Toggle menu
Toggle preferences menu
Toggle personal menu
Not logged in
Your IP address will be publicly visible if you make any edits.

MediaWiki:Common.js: Difference between revisions

MediaWiki interface page
No edit summary
Rewrite: dynamic menu from Mf-navigation config, inline search in ribbon, icon collapse on narrow screens
Line 1: Line 1:
/* Menhirs Fate Wiki - Custom Header */
/* Menhirs Fate Wiki - Custom Header
* Menu items are loaded from MediaWiki:Mf-navigation
* Edit that page to change nav links, dropdowns, and ordering.
*/
( function () {
( function () {
     "use strict";
     "use strict";


     /* ── Google Fonts ──────────────────────────────────────────────────────────────── */
     /* ── Google Fonts ─────────────────────────────────────────────────── */
     var link = document.createElement( "link" );
     var link = document.createElement( "link" );
     link.rel = "stylesheet";
     link.rel = "stylesheet";
Line 9: Line 12:
     document.head.appendChild( link );
     document.head.appendChild( link );


     /* ── Custom Header ─────────────────────────────────────────────────────────────── */
     /* ── Build header shell ───────────────────────────────────────────── */
     var header = document.createElement( "div" );
     var header = document.createElement( "div" );
     header.id = "mf-header";
     header.id = "mf-header";
     header.innerHTML =
     header.innerHTML =
         '<div id="mf-header-top"><a href="https://www.menhirsfate.com/" id="mf-logo-link"><img src="https://www.menhirsfate.com/wp-content/uploads/2024/08/white-logo-scaled-120x65.png" alt="Menhirs Fate" id="mf-logo" /></a></div>' +
         '<div id="mf-header-top">' +
        '<nav id="mf-ribbon"><div id="mf-ribbon-inner">' +
            '<a href="https://www.menhirsfate.com/" id="mf-logo-link">' +
             '<a href="https://www.menhirsfate.com/" class="mf-nav-item mf-nav-back">&larr; MenhirsFate.com</a>' +
                '<img src="https://www.menhirsfate.com/wp-content/uploads/2024/08/white-logo-scaled-120x65.png" alt="Menhirs Fate" id="mf-logo" />' +
            '<a href="/wiki/Main_Page" class="mf-nav-item">Home</a>' +
             '</a>' +
            '<div class="mf-has-dropdown"><span class="mf-nav-label">Nations <span class="mf-caret">&#9662;</span></span><div class="mf-dropdown">' +
        '</div>' +
                '<a href="/wiki/The_Crownlands/Avereaux">Avereaux</a>' +
        '<nav id="mf-ribbon">' +
                '<a href="/wiki/The_Wonder">The Wonder</a>' +
             '<div id="mf-ribbon-inner">' +
                '<a href="/wiki/Valdraeth">Valdraeth</a>' +
                 '<span id="mf-nav-loading" style="color:#844725;font-style:italic;padding:0 17px;line-height:50px;">Loading…</span>' +
                '<a href="/wiki/The_Urdrevan_People">The Urdrevan People</a>' +
             '</div>' +
                '<a href="/wiki/The_Republic_of_Portavas">The Republic of Portavas</a>' +
         '</nav>';
                '<a href="/wiki/The_Hammerstadt_Charter">The Hammerstadt Charter</a>' +
                '<a href="/wiki/Kairos">Kairos</a>' +
                '<a href="/wiki/Syradonia">Syradonia</a>' +
                '<a href="/wiki/Morvalis">Morvalis</a>' +
             '</div></div>' +
            '<div class="mf-has-dropdown"><span class="mf-nav-label">Gameplay <span class="mf-caret">&#9662;</span></span><div class="mf-dropdown">' +
                '<a href="/wiki/Look_and_Feel">Look and Feel</a>' +
                '<a href="/wiki/Basic_Skills">Basic Skills</a>' +
                 '<a href="/wiki/Magical_Skills">Magical Skills</a>' +
                '<a href="/wiki/Monstering">Monstering</a>' +
                '<a href="/wiki/Accessibility">Accessibility</a>' +
            '</div></div>' +
            '<div class="mf-has-dropdown"><span class="mf-nav-label">Resources <span class="mf-caret">&#9662;</span></span><div class="mf-dropdown">' +
                '<a href="/wiki/Funded_Builds">Funded Builds</a>' +
                '<a href="/wiki/Camping_Information">Camping Information</a>' +
                '<a href="/wiki/Special:Categories">Browse by Category</a>' +
             '</div></div>' +
         '</div></nav>' +
        '<div id="mf-search-bar"><div id="mf-search-inner"><form action="/wiki/Special:Search" id="mf-search-form"><input type="text" name="search" id="mf-search-input" placeholder="Search the wiki..." autocomplete="off" /><button type="submit" id="mf-search-btn" aria-label="Search"><svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg></button></form><div id="mf-search-suggestions"></div></div></div>';
     document.body.insertBefore( header, document.body.firstChild );
     document.body.insertBefore( header, document.body.firstChild );


     /* ── Mobile hamburger ────────────────────────────────────────────────────────────── */
     /* ── Hamburger button ─────────────────────────────────────────────── */
    var ribbon = document.getElementById( "mf-ribbon-inner" );
     var burger = document.createElement( "button" );
     var burger = document.createElement( "button" );
     burger.id = "mf-burger";
     burger.id = "mf-burger";
Line 51: Line 34:
     burger.innerHTML = "<span></span><span></span><span></span>";
     burger.innerHTML = "<span></span><span></span><span></span>";
     document.getElementById( "mf-header-top" ).appendChild( burger );
     document.getElementById( "mf-header-top" ).appendChild( burger );
    var ribbon = document.getElementById( "mf-ribbon-inner" );


     burger.addEventListener( "click", function () {
     burger.addEventListener( "click", function () {
Line 57: Line 42:
     } );
     } );


     ribbon.addEventListener( "click", function ( e ) {
     /* ── Parse navigation config ──────────────────────────────────────── */
         if ( e.target.tagName === "A" ) {
    function parseNavConfig( text ) {
            ribbon.classList.remove( "mf-open" );
        var items = [];
             burger.classList.remove( "mf-open" );
        var lines = text.split( "\n" );
         }
        var current = null;
 
        lines.forEach( function ( line ) {
            /* skip blanks and comments */
            if ( /^\s*$/.test( line ) || /^\s*<!--/.test( line ) || /^\s*-->/.test( line ) ) return;
            if ( line.indexOf( "<!--" ) !== -1 ) return;
 
            var subMatch = line.match( /^\s*\*\*\s+(.+?)\s*\|\s*(.+?)\s*$/ );
            if ( subMatch && current ) {
                current.children.push( { label: subMatch[1], url: subMatch[2].trim() } );
                return;
            }
 
            var dropMatch = line.match( /^\s*\*\s+(.+?)\s*>\s*$/ );
            if ( dropMatch ) {
                current = { label: dropMatch[1].trim(), children: [] };
                items.push( current );
                return;
            }
 
            var linkMatch = line.match( /^\s*\*\s+(.+?)\s*\|\s*(.+?)\s*$/ );
            if ( linkMatch ) {
                var parts = linkMatch[2].split( "|" ).map( function(s){ return s.trim(); } );
                var url = parts[0];
                var flags = parts.slice(1);
                current = null;
                items.push( { label: linkMatch[1].trim(), url: url, flags: flags } );
            }
        } );
 
        return items;
    }
 
    /* ── Build nav HTML from parsed items ─────────────────────────────── */
    function buildNav( items ) {
        var html = "";
         var dropdownCount = 0;
 
        items.forEach( function ( item ) {
            if ( item.children ) {
                /* dropdown */
                html += '<div class="mf-has-dropdown">' +
                    '<span class="mf-nav-label">' + item.label + ' <span class="mf-caret">&#9662;</span></span>' +
                    '<div class="mf-dropdown">';
                item.children.forEach( function ( child ) {
                    html += '<a href="' + child.url + '">' + child.label + '</a>';
                } );
                html += '</div></div>';
                dropdownCount++;
            } else {
                /* simple link */
                var cls = "mf-nav-item";
                if ( item.flags && item.flags.indexOf( "back" ) !== -1 ) {
                    cls += " mf-nav-back";
                }
                html += '<a href="' + item.url + '" class="' + cls + '">' + item.label + '</a>';
            }
        } );
 
        /* Search — inline input for desktop, icon-only for narrow screens */
        html += '<div id="mf-search-wrap">' +
            '<form action="/wiki/Special:Search" id="mf-search-form">' +
                '<input type="text" name="search" id="mf-search-input" placeholder="Search…" autocomplete="off" />' +
                '<button type="submit" id="mf-search-btn" aria-label="Search">' +
                    '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>' +
                '</button>' +
            '</form>' +
             '<button type="button" id="mf-search-icon" aria-label="Search">' +
                '<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>' +
            '</button>' +
            '<div id="mf-search-suggestions"></div>' +
        '</div>';
 
        /* Update grid columns: back-link(auto) + N nav items(1fr each) + search(auto) */
        var navItemCount = 0;
        items.forEach( function(i) { if ( !i.flags || i.flags.indexOf("back") === -1 ) navItemCount++; } );
 
        return { html: html, navItemCount: navItemCount };
    }
 
    /* ── Fetch config and render ──────────────────────────────────────── */
    new mw.Api().get( {
        action: "query",
        titles: "MediaWiki:Mf-navigation",
        prop: "revisions",
        rvprop: "content",
        rvslots: "main",
         format: "json"
    } ).then( function ( data ) {
        var pages = data.query.pages;
        var page = pages[ Object.keys( pages )[0] ];
        if ( !page.revisions ) return;
 
        var raw = page.revisions[0].slots.main["*"];
        var items = parseNavConfig( raw );
        var result = buildNav( items );
 
        ribbon.innerHTML = result.html;
 
        /* Set grid columns dynamically */
        var cols = "auto repeat(" + result.navItemCount + ", 1fr) auto";
        ribbon.style.gridTemplateColumns = cols;
 
        initDropdowns();
        initSearch();
     } );
     } );


     /* ── Dropdown toggles ────────────────────────────────────────────────────────────── */
     /* ── Dropdown toggle logic ────────────────────────────────────────── */
     var labels = document.querySelectorAll( ".mf-has-dropdown > .mf-nav-label" );
     function initDropdowns() {
    Array.prototype.forEach.call( labels, function ( label ) {
        var labels = document.querySelectorAll( ".mf-has-dropdown > .mf-nav-label" );
        label.addEventListener( "click", function ( e ) {
        Array.prototype.forEach.call( labels, function ( label ) {
            e.stopPropagation();
            label.addEventListener( "click", function ( e ) {
            var parent = this.parentNode;
                e.stopPropagation();
            var open = document.querySelectorAll( ".mf-has-dropdown.mf-dropdown-open" );
                var parent = this.parentNode;
            Array.prototype.forEach.call( open, function ( s ) {
                var open = document.querySelectorAll( ".mf-has-dropdown.mf-dropdown-open" );
                if ( s !== parent ) { s.classList.remove( "mf-dropdown-open" ); }
                Array.prototype.forEach.call( open, function ( s ) {
                    if ( s !== parent ) s.classList.remove( "mf-dropdown-open" );
                } );
                parent.classList.toggle( "mf-dropdown-open" );
             } );
             } );
            parent.classList.toggle( "mf-dropdown-open" );
         } );
         } );
    } );


    document.addEventListener( "click", function () {
        document.addEventListener( "click", function ( e ) {
        var open = document.querySelectorAll( ".mf-has-dropdown.mf-dropdown-open" );
            if ( !e.target.closest( ".mf-has-dropdown" ) ) {
        Array.prototype.forEach.call( open, function ( el ) {
                var open = document.querySelectorAll( ".mf-has-dropdown.mf-dropdown-open" );
            el.classList.remove( "mf-dropdown-open" );
                Array.prototype.forEach.call( open, function ( el ) {
                    el.classList.remove( "mf-dropdown-open" );
                } );
            }
        } );
 
        /* Close mobile menu on link click */
        ribbon.addEventListener( "click", function ( e ) {
            if ( e.target.tagName === "A" ) {
                ribbon.classList.remove( "mf-open" );
                burger.classList.remove( "mf-open" );
            }
         } );
         } );
     } );
     }


    /* ── Search with suggestions ──────────────────────────────────────── */
    function initSearch() {
        var input = document.getElementById( "mf-search-input" );
        var sugBox = document.getElementById( "mf-search-suggestions" );
        var iconBtn = document.getElementById( "mf-search-icon" );
        var debounce = null;


        if ( !input || !sugBox ) return;


    /* ── Search bar suggestions ──────────────────────────────────────────────── */
        /* Icon button (shown on narrow screens) opens Citizen search overlay */
    var searchInput = document.getElementById( "mf-search-input" );
        if ( iconBtn ) {
    var suggestionsBox = document.getElementById( "mf-search-suggestions" );
            iconBtn.addEventListener( "click", function () {
    var searchDebounce = null;
                var details = document.getElementById( "citizen-search-details" );
                if ( details ) {
                    details.open = true;
                    var citizenInput = details.querySelector( "input[type=\"search\"]" );
                    if ( citizenInput ) citizenInput.focus();
                }
            } );
        }


    if ( searchInput && suggestionsBox ) {
        /* Autocomplete suggestions */
         searchInput.addEventListener( "input", function () {
         input.addEventListener( "input", function () {
             var query = searchInput.value.trim();
             var q = input.value.trim();
             clearTimeout( searchDebounce );
             clearTimeout( debounce );
             if ( query.length < 2 ) {
             if ( q.length < 2 ) {
                 suggestionsBox.style.display = "none";
                 sugBox.style.display = "none";
                 suggestionsBox.innerHTML = "";
                 sugBox.innerHTML = "";
                 return;
                 return;
             }
             }
             searchDebounce = setTimeout( function () {
             debounce = setTimeout( function () {
                 new mw.Api().get( {
                 new mw.Api().get( {
                     action: "opensearch",
                     action: "opensearch",
                     search: query,
                     search: q,
                     limit: 8,
                     limit: 6,
                     namespace: 0
                     namespace: 0
                 } ).then( function ( data ) {
                 } ).then( function ( data ) {
                     var titles = data[ 1 ] || [];
                     var titles = data[1] || [];
                     if ( titles.length === 0 ) {
                     if ( !titles.length ) {
                         suggestionsBox.style.display = "none";
                         sugBox.style.display = "none";
                         suggestionsBox.innerHTML = "";
                         sugBox.innerHTML = "";
                         return;
                         return;
                     }
                     }
                     suggestionsBox.innerHTML = "";
                     sugBox.innerHTML = "";
                     titles.forEach( function ( title ) {
                     titles.forEach( function ( t ) {
                         var a = document.createElement( "a" );
                         var a = document.createElement( "a" );
                         a.href = mw.util.getUrl( title );
                         a.href = mw.util.getUrl( t );
                         a.textContent = title;
                         a.textContent = t;
                         a.className = "mf-suggestion";
                         a.className = "mf-suggestion";
                         suggestionsBox.appendChild( a );
                         sugBox.appendChild( a );
                     } );
                     } );
                     suggestionsBox.style.display = "block";
                     sugBox.style.display = "block";
                 } );
                 } );
             }, 200 );
             }, 200 );
         } );
         } );


         searchInput.addEventListener( "focus", function () {
         input.addEventListener( "focus", function () {
             if ( suggestionsBox.children.length > 0 ) {
             if ( sugBox.children.length ) sugBox.style.display = "block";
                suggestionsBox.style.display = "block";
            }
         } );
         } );


         document.addEventListener( "click", function ( e ) {
         document.addEventListener( "click", function ( e ) {
             if ( !e.target.closest( "#mf-search-bar" ) ) {
             if ( !e.target.closest( "#mf-search-wrap" ) ) {
                 suggestionsBox.style.display = "none";
                 sugBox.style.display = "none";
             }
             }
         } );
         } );
     }
     }
    /* ── Fix sitename typo wherever it appears ────────────────────────── */
    document.querySelectorAll( ".citizen-footer__sitetitle, .citizen-footer a, .mw-logo-wordmark" ).forEach( function ( el ) {
        if ( el.textContent.indexOf( "Mehirs" ) !== -1 ) {
            el.textContent = el.textContent.replace( /Mehirs/g, "Menhirs" );
        }
    } );
    /* ── Citizen header z-index ───────────────────────────────────────── */
    /* Handled in Common.css */
}() );
}() );

Revision as of 19:38, 12 March 2026

/* Menhirs Fate Wiki - Custom Header
 * Menu items are loaded from MediaWiki:Mf-navigation
 * Edit that page to change nav links, dropdowns, and ordering.
 */
( function () {
    "use strict";

    /* ── Google Fonts ─────────────────────────────────────────────────── */
    var link = document.createElement( "link" );
    link.rel = "stylesheet";
    link.href = "https://fonts.googleapis.com/css2?family=Crimson+Text:ital,wght@0,400;0,600;0,700;1,400&display=swap";
    document.head.appendChild( link );

    /* ── Build header shell ───────────────────────────────────────────── */
    var header = document.createElement( "div" );
    header.id = "mf-header";
    header.innerHTML =
        '<div id="mf-header-top">' +
            '<a href="https://www.menhirsfate.com/" id="mf-logo-link">' +
                '<img src="https://www.menhirsfate.com/wp-content/uploads/2024/08/white-logo-scaled-120x65.png" alt="Menhirs Fate" id="mf-logo" />' +
            '</a>' +
        '</div>' +
        '<nav id="mf-ribbon">' +
            '<div id="mf-ribbon-inner">' +
                '<span id="mf-nav-loading" style="color:#844725;font-style:italic;padding:0 17px;line-height:50px;">Loading…</span>' +
            '</div>' +
        '</nav>';
    document.body.insertBefore( header, document.body.firstChild );

    /* ── Hamburger button ─────────────────────────────────────────────── */
    var burger = document.createElement( "button" );
    burger.id = "mf-burger";
    burger.setAttribute( "aria-label", "Toggle menu" );
    burger.innerHTML = "<span></span><span></span><span></span>";
    document.getElementById( "mf-header-top" ).appendChild( burger );

    var ribbon = document.getElementById( "mf-ribbon-inner" );

    burger.addEventListener( "click", function () {
        ribbon.classList.toggle( "mf-open" );
        burger.classList.toggle( "mf-open" );
    } );

    /* ── Parse navigation config ──────────────────────────────────────── */
    function parseNavConfig( text ) {
        var items = [];
        var lines = text.split( "\n" );
        var current = null;

        lines.forEach( function ( line ) {
            /* skip blanks and comments */
            if ( /^\s*$/.test( line ) || /^\s*<!--/.test( line ) || /^\s*-->/.test( line ) ) return;
            if ( line.indexOf( "<!--" ) !== -1 ) return;

            var subMatch = line.match( /^\s*\*\*\s+(.+?)\s*\|\s*(.+?)\s*$/ );
            if ( subMatch && current ) {
                current.children.push( { label: subMatch[1], url: subMatch[2].trim() } );
                return;
            }

            var dropMatch = line.match( /^\s*\*\s+(.+?)\s*>\s*$/ );
            if ( dropMatch ) {
                current = { label: dropMatch[1].trim(), children: [] };
                items.push( current );
                return;
            }

            var linkMatch = line.match( /^\s*\*\s+(.+?)\s*\|\s*(.+?)\s*$/ );
            if ( linkMatch ) {
                var parts = linkMatch[2].split( "|" ).map( function(s){ return s.trim(); } );
                var url = parts[0];
                var flags = parts.slice(1);
                current = null;
                items.push( { label: linkMatch[1].trim(), url: url, flags: flags } );
            }
        } );

        return items;
    }

    /* ── Build nav HTML from parsed items ─────────────────────────────── */
    function buildNav( items ) {
        var html = "";
        var dropdownCount = 0;

        items.forEach( function ( item ) {
            if ( item.children ) {
                /* dropdown */
                html += '<div class="mf-has-dropdown">' +
                    '<span class="mf-nav-label">' + item.label + ' <span class="mf-caret">&#9662;</span></span>' +
                    '<div class="mf-dropdown">';
                item.children.forEach( function ( child ) {
                    html += '<a href="' + child.url + '">' + child.label + '</a>';
                } );
                html += '</div></div>';
                dropdownCount++;
            } else {
                /* simple link */
                var cls = "mf-nav-item";
                if ( item.flags && item.flags.indexOf( "back" ) !== -1 ) {
                    cls += " mf-nav-back";
                }
                html += '<a href="' + item.url + '" class="' + cls + '">' + item.label + '</a>';
            }
        } );

        /* Search — inline input for desktop, icon-only for narrow screens */
        html += '<div id="mf-search-wrap">' +
            '<form action="/wiki/Special:Search" id="mf-search-form">' +
                '<input type="text" name="search" id="mf-search-input" placeholder="Search…" autocomplete="off" />' +
                '<button type="submit" id="mf-search-btn" aria-label="Search">' +
                    '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>' +
                '</button>' +
            '</form>' +
            '<button type="button" id="mf-search-icon" aria-label="Search">' +
                '<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>' +
            '</button>' +
            '<div id="mf-search-suggestions"></div>' +
        '</div>';

        /* Update grid columns: back-link(auto) + N nav items(1fr each) + search(auto) */
        var navItemCount = 0;
        items.forEach( function(i) { if ( !i.flags || i.flags.indexOf("back") === -1 ) navItemCount++; } );

        return { html: html, navItemCount: navItemCount };
    }

    /* ── Fetch config and render ──────────────────────────────────────── */
    new mw.Api().get( {
        action: "query",
        titles: "MediaWiki:Mf-navigation",
        prop: "revisions",
        rvprop: "content",
        rvslots: "main",
        format: "json"
    } ).then( function ( data ) {
        var pages = data.query.pages;
        var page = pages[ Object.keys( pages )[0] ];
        if ( !page.revisions ) return;

        var raw = page.revisions[0].slots.main["*"];
        var items = parseNavConfig( raw );
        var result = buildNav( items );

        ribbon.innerHTML = result.html;

        /* Set grid columns dynamically */
        var cols = "auto repeat(" + result.navItemCount + ", 1fr) auto";
        ribbon.style.gridTemplateColumns = cols;

        initDropdowns();
        initSearch();
    } );

    /* ── Dropdown toggle logic ────────────────────────────────────────── */
    function initDropdowns() {
        var labels = document.querySelectorAll( ".mf-has-dropdown > .mf-nav-label" );
        Array.prototype.forEach.call( labels, function ( label ) {
            label.addEventListener( "click", function ( e ) {
                e.stopPropagation();
                var parent = this.parentNode;
                var open = document.querySelectorAll( ".mf-has-dropdown.mf-dropdown-open" );
                Array.prototype.forEach.call( open, function ( s ) {
                    if ( s !== parent ) s.classList.remove( "mf-dropdown-open" );
                } );
                parent.classList.toggle( "mf-dropdown-open" );
            } );
        } );

        document.addEventListener( "click", function ( e ) {
            if ( !e.target.closest( ".mf-has-dropdown" ) ) {
                var open = document.querySelectorAll( ".mf-has-dropdown.mf-dropdown-open" );
                Array.prototype.forEach.call( open, function ( el ) {
                    el.classList.remove( "mf-dropdown-open" );
                } );
            }
        } );

        /* Close mobile menu on link click */
        ribbon.addEventListener( "click", function ( e ) {
            if ( e.target.tagName === "A" ) {
                ribbon.classList.remove( "mf-open" );
                burger.classList.remove( "mf-open" );
            }
        } );
    }

    /* ── Search with suggestions ──────────────────────────────────────── */
    function initSearch() {
        var input = document.getElementById( "mf-search-input" );
        var sugBox = document.getElementById( "mf-search-suggestions" );
        var iconBtn = document.getElementById( "mf-search-icon" );
        var debounce = null;

        if ( !input || !sugBox ) return;

        /* Icon button (shown on narrow screens) opens Citizen search overlay */
        if ( iconBtn ) {
            iconBtn.addEventListener( "click", function () {
                var details = document.getElementById( "citizen-search-details" );
                if ( details ) {
                    details.open = true;
                    var citizenInput = details.querySelector( "input[type=\"search\"]" );
                    if ( citizenInput ) citizenInput.focus();
                }
            } );
        }

        /* Autocomplete suggestions */
        input.addEventListener( "input", function () {
            var q = input.value.trim();
            clearTimeout( debounce );
            if ( q.length < 2 ) {
                sugBox.style.display = "none";
                sugBox.innerHTML = "";
                return;
            }
            debounce = setTimeout( function () {
                new mw.Api().get( {
                    action: "opensearch",
                    search: q,
                    limit: 6,
                    namespace: 0
                } ).then( function ( data ) {
                    var titles = data[1] || [];
                    if ( !titles.length ) {
                        sugBox.style.display = "none";
                        sugBox.innerHTML = "";
                        return;
                    }
                    sugBox.innerHTML = "";
                    titles.forEach( function ( t ) {
                        var a = document.createElement( "a" );
                        a.href = mw.util.getUrl( t );
                        a.textContent = t;
                        a.className = "mf-suggestion";
                        sugBox.appendChild( a );
                    } );
                    sugBox.style.display = "block";
                } );
            }, 200 );
        } );

        input.addEventListener( "focus", function () {
            if ( sugBox.children.length ) sugBox.style.display = "block";
        } );

        document.addEventListener( "click", function ( e ) {
            if ( !e.target.closest( "#mf-search-wrap" ) ) {
                sugBox.style.display = "none";
            }
        } );
    }

    /* ── Fix sitename typo wherever it appears ────────────────────────── */
    document.querySelectorAll( ".citizen-footer__sitetitle, .citizen-footer a, .mw-logo-wordmark" ).forEach( function ( el ) {
        if ( el.textContent.indexOf( "Mehirs" ) !== -1 ) {
            el.textContent = el.textContent.replace( /Mehirs/g, "Menhirs" );
        }
    } );

    /* ── Citizen header z-index ───────────────────────────────────────── */
    /* Handled in Common.css */

}() );