Aller au contenu

« MediaWiki:Vector-2022.js » : différence entre les versions

De Wikidébats, l'encyclopédie des débats et des arguments « pour » et « contre »
Aucun résumé des modifications
Aucun résumé des modifications
Ligne 3 173 : Ligne 3 173 :
W.breadcrumbMenu = breadcrumbMenu;
W.breadcrumbMenu = breadcrumbMenu;
W.breadcrumbGeneration = W.breadcrumbGeneration;
W.breadcrumbGeneration = W.breadcrumbGeneration;
// --- Mode lecture (exposé) ---
W.WK_READING = WK_READING;
W.wkOpenReadingModeFromTitleEl = wkOpenReadingModeFromTitleEl;
W.wkOpenReadingModeFromPageTitle = wkOpenReadingModeFromPageTitle;
W.wkCloseReadingMode = wkCloseReadingMode;


}() );
}() );

Version du 6 février 2026 à 15:10

/* ============================================
	Wikidébats — Vector 2022 + i18n centralisée (MW 1.43)
	============================================ */

( function () {
	'use strict';

	/* =========================
		Singletons DOM/jQuery (micro-opt)
	   ========================= */

	var D = document;
	var W = window;
	var $D = $( D );
	var $W = $( W );
	var $B = $( D.body );

	/* =========================
		Constantes de concat (micro-opt)
	   ========================= */

	var WK_OPEN = '{{';
	var WK_CLOSE = '}}';
	var WK_SEP = '|';
	var WK_EQ = '=';

	/* =========================
		I18N loader + helpers
	   ========================= */

	function wkLoadI18n() {
		var lang = ( mw.config.get( 'wgUserLanguage' ) || 'fr' ).toLowerCase();
		var base = 'MediaWiki:Wikidebats.i18n.';
		var fallback = 'fr';

		function load( l ) {
			var url = mw.util.wikiScript( 'index' ) +
				'?title=' + encodeURIComponent( base + l + '.js' ) +
				'&action=raw&ctype=text/javascript';

			return new Promise( function ( resolve, reject ) {
				mw.loader.getScript( url )
					.done( resolve )
					.fail( reject );
			} );
		}

		return load( lang ).catch( function () {
			return load( fallback );
		} );
	}

	function wkMsg( key /*, ...params */ ) {
		var params = Array.prototype.slice.call( arguments, 1 );

		try {
			if ( mw && mw.message && mw.message( key ).exists() ) {
				return mw.msg.apply( mw, [ key ].concat( params ) );
			}
		} catch ( e ) {}

		return key;
	}

	function wkMsgD( key, def /*, ...params */ ) {
		var params = Array.prototype.slice.call( arguments, 2 );
		var v = wkMsg.apply( null, [ key ].concat( params ) );
		return ( v === key ) ? def : v;
	}

	function wkTpl( key, def /*, ...params */ ) {
		var params = Array.prototype.slice.call( arguments, 2 );
		return wkMsgD.apply( null, [ key, def ].concat( params ) );
	}

	function wkParam( key, def ) {
		return wkMsgD( key, def );
	}

	function wkForm( key, def ) {
		return wkMsgD( key, def );
	}

	/* =========================
		I18N fast cache
	   ========================= */

	var wkMsgFastCache = Object.create( null );

	function wkHasCache( obj, k ) {
		return Object.prototype.hasOwnProperty.call( obj, k );
	}

	function wkParamFast( key, def ) {
		var k = 'p|' + key + '|' + def;
		if ( wkHasCache( wkMsgFastCache, k ) ) return wkMsgFastCache[ k ];
		wkMsgFastCache[ k ] = wkParam( key, def );
		return wkMsgFastCache[ k ];
	}

	function wkTplFast( key, def ) {
		var k = 't|' + key + '|' + def;
		if ( wkHasCache( wkMsgFastCache, k ) ) return wkMsgFastCache[ k ];
		wkMsgFastCache[ k ] = wkTpl( key, def );
		return wkMsgFastCache[ k ];
	}

	function wkFormFast( key, def ) {
		var k = 'f|' + key + '|' + def;
		if ( wkHasCache( wkMsgFastCache, k ) ) return wkMsgFastCache[ k ];
		wkMsgFastCache[ k ] = wkForm( key, def );
		return wkMsgFastCache[ k ];
	}

	/* =========================
		I18N “pré-caches” (safe) : évite les recalculs en handlers
	   ========================= */

	var WK_P = {
		page: null,
		argument: null,
		type: null,
		level: null,
		root: null,
		path: null,
		warnings: null
	};

	var WK_T = {
		breadcrumbMenu: null,
		more: null,
		latest: null,
		hover: null
	};

	var WK_F = {
		summary: null,
		citations: null,
		references: null
	};

	function wkWarmI18nCaches() {
		if ( WK_P.page !== null ) return;

		WK_P.page = wkParamFast( 'wk-param-page', 'page' );
		WK_P.argument = wkParamFast( 'wk-param-argument', 'argument' );
		WK_P.type = wkParamFast( 'wk-param-type', 'type' );
		WK_P.level = wkParamFast( 'wk-param-level', 'niveau' );
		WK_P.root = wkParamFast( 'wk-param-root', 'racine' );
		WK_P.path = wkParamFast( 'wk-param-path', 'chemin' );
		WK_P.warnings = wkParamFast( 'wk-param-warnings', 'avertissements' );

		WK_T.breadcrumbMenu = wkTplFast( 'wk-tpl-breadcrumb-menu', "Fil d'Ariane (menu)" );
		WK_T.more = wkTplFast( 'wk-tpl-more-content', 'Contenu supplémentaire' );
		WK_T.hoverMap = wkTplFast( 'wk-tpl-hover-map', 'Survol de carte des arguments' );
		WK_T.hoverWP = wkTplFast( 'wk-tpl-hover-wikipedia', 'Survol de lien Wikipédia' );
		WK_T.latest = wkTplFast( 'wk-tpl-latest-changes', 'Dernières contributions' );

		/* Hover : template dépend du HTML (dataset), donc ici on “warm” seulement les strings génériques */
		WK_T.hover = null;

		WK_F.summary = wkFormFast( 'wk-form-summary', 'Résumé' );
		WK_F.citations = wkFormFast( 'wk-form-citations', 'Citations' );
		WK_F.references = wkFormFast( 'wk-form-references', 'Références' );
	}

	/* ========================
		Helpers contexte + once
	   ======================== */

	function wkIsNs( ns ) {
		try { return mw.config.get( 'wgNamespaceNumber' ) === ns; } catch ( e ) { return false; }
	}

	function wkIsView() {
		return D.body && D.body.classList.contains( 'action-view' );
	}

	function wkIsFormEdit() {
		return !!D.querySelector( '.mw-special-FormEdit, .mw-editable.action-formedit' );
	}

	function wkOnce( key ) {
		try {
			if ( D.documentElement.dataset[ key ] === '1' ) return false;
			D.documentElement.dataset[ key ] = '1';
			return true;
		} catch ( e ) { return true; }
	}

	function wkIdle( fn ) {
		if ( W.requestIdleCallback ) {
			requestIdleCallback( fn, { timeout: 500 } );
		} else {
			setTimeout( fn, 0 );
		}
	}

	function wkRafThrottle( fn ) {
		var raf = 0;
		return function () {
			if ( raf ) return;
			raf = requestAnimationFrame( function () {
				raf = 0;
				fn();
			} );
		};
	}

	function wkRootNode( root ) {
		if ( !root ) return D;
		if ( root.jquery && root.length ) return root[ 0 ];
		if ( root.nodeType ) return root;
		return D;
	}

	/* =========================
		HTML replace helper (fragment)
	   ========================= */

	function wkReplaceHtml( $target, html ) {
		if ( !$target || !$target.length ) return;

		var tmp = D.createElement( 'div' );
		tmp.innerHTML = html;

		var frag = D.createDocumentFragment();
		while ( tmp.firstChild ) frag.appendChild( tmp.firstChild );

		$target[ 0 ].replaceWith( frag );
	}

	function wkGetWikiTitleFromHrefRaw( href ) {
		if ( !href ) return '';
		var m = href.match( /\/wiki\/([^#?]+)/ );
		return ( m && m[ 1 ] ) ? m[ 1 ] : '';
	}

	function hrefToPageTitle( href ) {
		if ( !href ) return '';

		var page = href.replace( /^.*\/wiki\//, '' );
		page = decodeURIComponent( page );
		page = page.replace( /_/g, ' ' );

		return page;
	}

	/* =========================
		API Parse — pool + dédup + caches (LRU) + fail cache
		+ priorité de queue (hover > bc > latest/more > arg > def)
		+ annulation des jobs en file
	   ========================= */

	var wkApi = null;

	var WK_PARSE_CONCURRENCY = 2;

	var WK_PARSE_CACHE_MAX = {
		bc: 80,
		arg: 160,
		hover: 120,
		latest: 0,
		more: 0,
		def: 80
	};

	var wkParseCacheBC = new Map();
	var wkParseCacheArg = new Map();
	var wkParseCacheHover = new Map();
	var wkParseCacheLatest = new Map();
	var wkParseCacheMore = new Map();
	var wkParseCacheDef = new Map();
	var wkArgEmbedCache = new Map();

	var wkParseInFlight = new Map();
	var wkParseQueue = [];
	var wkParseActive = 0;

	var WK_PARSE_FAIL_TTL_MS = 15000;
	var wkParseFailUntil = new Map();

	var WK_PARSE_PRIORITY = {
		hover: 0,
		bc: 1,
		latest: 2,
		more: 2,
		arg: 3,
		def: 4
	};

	function wkGetApi() {
		if ( wkApi ) return wkApi;
		wkApi = new mw.Api();
		return wkApi;
	}

	function wkGetBucketCache( bucket ) {
		if ( bucket === 'bc' ) return wkParseCacheBC;
		if ( bucket === 'arg' ) return wkParseCacheArg;
		if ( bucket === 'hover' ) return wkParseCacheHover;
		if ( bucket === 'latest' ) return wkParseCacheLatest;
		if ( bucket === 'more' ) return wkParseCacheMore;
		return wkParseCacheDef;
	}

	function wkCacheGetLRU( cache, key ) {
		if ( !cache || !cache.has || !cache.size ) return null;
		if ( !cache.has( key ) ) return null;
		var v = cache.get( key );
		cache.delete( key );
		cache.set( key, v );
		return v;
	}

	function wkCacheSetLRU( cache, max, key, value ) {
		if ( !cache || typeof max !== 'number' || max <= 0 ) return;

		if ( cache.has( key ) ) cache.delete( key );
		cache.set( key, value );

		while ( cache.size > max ) {
			var firstKey = cache.keys().next().value;
			if ( typeof firstKey === 'undefined' ) break;
			cache.delete( firstKey );
		}
	}

	function wkFailIsHot( bucket, keyLocal ) {
		var k = bucket + '|' + keyLocal;
		var until = wkParseFailUntil.get( k ) || 0;
		if ( until > Date.now() ) return true;
		if ( until ) wkParseFailUntil.delete( k );
		return false;
	}

	function wkFailTouch( bucket, keyLocal ) {
		var k = bucket + '|' + keyLocal;
		wkParseFailUntil.set( k, Date.now() + WK_PARSE_FAIL_TTL_MS );
	}

	function wkParseCancel( bucket, wikitext ) {
		var keyLocal = String( wikitext || '' );
		var inFlightKey = String( bucket || 'def' ) + '|' + keyLocal;

		for ( var i = wkParseQueue.length - 1; i >= 0; i-- ) {
			if ( wkParseQueue[ i ] && wkParseQueue[ i ].inFlightKey === inFlightKey ) {
				var job = wkParseQueue.splice( i, 1 )[ 0 ];

				if ( wkParseInFlight.has( inFlightKey ) ) wkParseInFlight.delete( inFlightKey );

				try { job.reject( new Error( 'wkParse:cancelled' ) ); } catch ( e ) {}
				break;
			}
		}
	}

	function wkParseWikitext( wikitext, bucket ) {
		bucket = bucket || 'def';

		var cache = wkGetBucketCache( bucket );
		var keyLocal = String( wikitext || '' );
		var inFlightKey = bucket + '|' + keyLocal;

		var cached = wkCacheGetLRU( cache, keyLocal );
		if ( cached !== null ) return Promise.resolve( cached );

		if ( wkFailIsHot( bucket, keyLocal ) ) return Promise.reject( new Error( 'wkParse:fail-cached' ) );

		if ( wkParseInFlight.has( inFlightKey ) ) return wkParseInFlight.get( inFlightKey );

		var p = new Promise( function ( resolve, reject ) {
			wkParseQueue.push( {
				inFlightKey: inFlightKey,
				keyLocal: keyLocal,
				bucket: bucket,
				wikitext: wikitext,
				resolve: resolve,
				reject: reject
			} );
			wkParsePump();
		} );

		wkParseInFlight.set( inFlightKey, p );

		p.finally( function () {
			wkParseInFlight.delete( inFlightKey );
		} );

		return p;
	}

	function wkParseQueuePickNext() {
		if ( !wkParseQueue.length ) return null;

		var bestIdx = -1;
		var bestPri = 999;

		for ( var i = 0; i < wkParseQueue.length; i++ ) {
			var job = wkParseQueue[ i ];
			if ( !job ) continue;

			var b = job.bucket || 'def';
			var pri = ( typeof WK_PARSE_PRIORITY[ b ] === 'number' ) ? WK_PARSE_PRIORITY[ b ] : WK_PARSE_PRIORITY.def;

			if ( pri < bestPri ) {
				bestPri = pri;
				bestIdx = i;
				if ( bestPri === 0 ) break;
			}
		}

		if ( bestIdx < 0 ) return null;

		return wkParseQueue.splice( bestIdx, 1 )[ 0 ];
	}

	function wkParsePump() {
		while ( wkParseActive < WK_PARSE_CONCURRENCY && wkParseQueue.length ) {
			var job = wkParseQueuePickNext();
			if ( !job ) return;

			wkParseActive++;

			wkGetApi().post( {
				action: 'parse',
				contentmodel: 'wikitext',
				text: job.wikitext,
				formatversion: 2,
				disablelimitreport: 1,
				disableeditsection: 1,
				disabletoc: 1,
				redirects: 1
			} ).done( function ( data ) {
				var html = data && data.parse && data.parse.text
					? ( typeof data.parse.text === 'string' ? data.parse.text : ( data.parse.text[ '*' ] || '' ) )
					: '';

				if ( html ) html = html.replace( /<!--[\S\s]*?-->/gm, '' );

				var cache2 = wkGetBucketCache( job.bucket );
				var max = WK_PARSE_CACHE_MAX[ job.bucket ];
				if ( typeof max !== 'number' ) max = WK_PARSE_CACHE_MAX.def;

				wkCacheSetLRU( cache2, max, job.keyLocal, html );

				job.resolve( html );
			} ).fail( function ( err ) {
				wkFailTouch( job.bucket, job.keyLocal );
				job.reject( err );
			} ).always( function () {
				wkParseActive--;
				wkParsePump();
			} );
		}
	}

	/* ==========================================================
		fr-collapsible — bind idempotent (root-scoped)
	   ========================================================== */

	function bindFrCollapsible( $root ) {
		$root.find( '.fr-collapsible' ).each( function () {
			var $box = $( this );
			if ( $box.data( 'fr-collapsible-bound' ) ) return;
			$box.data( 'fr-collapsible-bound', true );

			var $toggle = $box.children( '.fr-collapsible-toggle' ).first();
			var $content = $box.children( '.fr-collapsible-content' ).first();
			if ( !$toggle.length || !$content.length ) return;

			$toggle.attr( { role: 'button', tabindex: 0 } );
			$content.removeAttr( 'hidden' )[ 0 ].style.display = 'block';

			var reduce = W.matchMedia && W.matchMedia( '(prefers-reduced-motion: reduce)' ).matches;

			function openPanel( instant ) {
				$box.removeClass( 'fr-collapsed' ).addClass( 'fr-expanded' );
				$toggle.attr( 'aria-expanded', 'true' )
					.removeClass( 'fr-collapsible-toggle-collapsed' )
					.addClass( 'fr-collapsible-toggle-expanded' );
				$content.attr( 'aria-hidden', 'false' );

				if ( instant || reduce ) {
					$content.stop( true, true );
					$content[ 0 ].style.transition = 'none';
					$content[ 0 ].style.height = 'auto';
					$content[ 0 ].style.opacity = '1';
					void $content[ 0 ].offsetHeight;
					$content[ 0 ].style.transition = '';
					return;
				}

				$content.stop( true, true );
				$content[ 0 ].style.display = 'block';
				$content[ 0 ].style.height = '0px';
				$content[ 0 ].style.opacity = '0';

				requestAnimationFrame( function () {
					var h = $content[ 0 ].scrollHeight;
					$content[ 0 ].style.height = h + 'px';
					$content[ 0 ].style.opacity = '1';
				} );

				$content.one( 'transitionend', function ( e ) {
					if ( e.target !== $content[ 0 ] ) return;
					$content[ 0 ].style.height = 'auto';
				} );
			}

			function closePanel( instant ) {
				$box.removeClass( 'fr-expanded' ).addClass( 'fr-collapsed' );
				$toggle.attr( 'aria-expanded', 'false' )
					.removeClass( 'fr-collapsible-toggle-expanded' )
					.addClass( 'fr-collapsible-toggle-collapsed' );
				$content.attr( 'aria-hidden', 'true' );

				if ( instant || reduce ) {
					$content.stop( true, true );
					$content[ 0 ].style.transition = 'none';
					$content[ 0 ].style.height = '0px';
					$content[ 0 ].style.opacity = '0';
					void $content[ 0 ].offsetHeight;
					$content[ 0 ].style.transition = '';
					return;
				}

				$content.stop( true, true );
				$content[ 0 ].style.display = 'block';
				$content[ 0 ].style.height = $content[ 0 ].scrollHeight + 'px';
				$content[ 0 ].style.opacity = '1';

				requestAnimationFrame( function () {
					$content[ 0 ].style.height = '0px';
					$content[ 0 ].style.opacity = '0';
				} );
			}

			function setState( expanded, instant ) {
				if ( expanded ) openPanel( instant );
				else closePanel( instant );
			}

			$toggle.on( 'click', function ( e ) {
				if ( $( e.target ).closest( 'a,button,input,select,textarea,label' ).length ) return;
				e.preventDefault();
				setState( $box.hasClass( 'fr-collapsed' ), false );
			} );

			$toggle.on( 'keydown', function ( e ) {
				if ( e.key === 'Enter' || e.key === ' ' || e.keyCode === 13 || e.keyCode === 32 ) {
					e.preventDefault();
					setState( $box.hasClass( 'fr-collapsed' ), false );
				}
			} );

			setState( !$box.hasClass( 'fr-collapsed' ), true );
		} );
	}

	/* ==========================================================
		Autogrow — PF events + scan initial + batching idle
	   ========================================================== */

	var wkAutoGrowIdleScheduled = 0;
	var wkAutoGrowPendingRoot = null;

	function wkAutoGrowTextareasScan( $root ) {
		$root.find( '#pfForm textarea.autoGrow' ).each( function () {
			if ( this.dataset && this.dataset.wkAutogrow === '1' ) return;
			if ( this.dataset ) this.dataset.wkAutogrow = '1';

			this.rows = 1;
			this.style.height = 'auto';
			this.style.height = this.scrollHeight + 'px';
		} );
	}

	function wkAutoGrowSchedule( root ) {
		wkAutoGrowPendingRoot = root || wkAutoGrowPendingRoot || D;

		if ( wkAutoGrowIdleScheduled ) return;
		wkAutoGrowIdleScheduled = 1;

		wkIdle( function () {
			wkAutoGrowIdleScheduled = 0;
			var r = wkAutoGrowPendingRoot || D;
			wkAutoGrowPendingRoot = null;
			wkAutoGrowTextareasScan( $( r ) );
		} );
	}

	function wkBindAutoGrow() {
		if ( !wkOnce( 'wkAutogrowInit' ) ) return;

		$D.on( 'pfaddinstance pfafterrebuild pfcreateinput', function ( e ) {
			var root = e && e.target ? e.target : D;
			wkAutoGrowSchedule( root );
		} );
	}

	/* ==========================================================
		Espace insécable avant " ?"
	   ========================================================== */

	function wkFixTitleSpace() {
		if ( !wkOnce( 'wkTitleSpaceInit' ) ) return;

		function fixTitleSpace() {
			var el = D.querySelector( '#firstHeading .mw-page-title-main' ) || D.querySelector( '#firstHeading' );
			if ( !el ) return;

			var walker = D.createTreeWalker( el, NodeFilter.SHOW_TEXT );
			var t, last = null;
			while ( ( t = walker.nextNode() ) ) last = t;
			if ( !last ) return;

			var s = last.nodeValue;
			if ( /\u00A0\?$/.test( s ) || /\u202F\?$/.test( s ) ) return;

			var r = s.replace( / (?=\?$)/, '\u00A0' );
			if ( r !== s ) last.nodeValue = r;
		}

		mw.hook( 'wikipage.ready' ).add( fixTitleSpace );

		var h = D.getElementById( 'firstHeading' );
		if ( h && W.MutationObserver ) {
			new MutationObserver( fixTitleSpace ).observe( h, { childList: true, subtree: true, characterData: true } );
		}
	}

	/* ==========================================================
		Onglet externe
	   ========================================================== */

	$( document ).on( 'click', '.onglet-externe a', function () {
		var a = this;

		if ( a.getAttribute( 'target' ) !== '_blank' ) {
			a.setAttribute( 'target', '_blank' );
		}

		if ( a.relList && a.relList.add ) {
			a.relList.add( 'noopener' );
		} else {
			var rel = ( a.getAttribute( 'rel' ) || '' );
			if ( !/\bnoopener\b/.test( rel ) ) {
				a.setAttribute( 'rel', ( rel ? rel + ' ' : '' ) + 'noopener' );
			}
		}
	} );

	/* ==========================================================
		DÉPLACEMENTS BOUTONS — NS0 uniquement
	   ========================================================== */

	function wkMoveRenameButton() {
		if ( !wkIsNs( 0 ) || !wkIsView() ) return;

		var span = D.getElementById( 'bouton-renommer' );
		if ( !span ) return;

		var heading = D.querySelector( '.firstHeading' ) || D.getElementById( 'firstHeading' );
		if ( !heading ) return;

		span.style.display = 'inline';
		if ( span.parentNode !== heading ) heading.appendChild( span );

		var a = span.querySelector( 'a' );
		if ( a ) a.textContent = '';
	}

	function wkMoveTopicButton() {
		if ( !wkIsNs( 0 ) || !wkIsView() ) return;

		var bouton = D.getElementById( 'bouton-modifier-sujet' );
		var contentSub = D.getElementById( 'contentSub' );
		if ( bouton && contentSub ) {
			if ( bouton.parentNode !== contentSub ) contentSub.appendChild( bouton );
			contentSub.style.display = 'flex';
			bouton.style.display = 'flex';
		}
	}

	function wkMoveCategoriesButton() {
		if ( !wkIsNs( 0 ) || !wkIsView() ) return;

		var bouton = D.getElementById( 'bouton-modifier-categories' );
		var categories = D.getElementById( 'mw-normal-catlinks' );
		if ( !bouton || !categories ) return;

		var ul = categories.querySelector( 'ul' );
		if ( !ul ) return;

		var lastLi = ul.querySelector( 'li:last-child' );
		if ( !lastLi ) return;

		if ( bouton.parentElement !== lastLi ) lastLi.appendChild( bouton );
		bouton.style.display = 'inline';
	}

	function wkMoveInterlanguageButton() {
		if ( !wkIsNs( 0 ) || !wkIsView() ) return;

		var MARKER_SELECTOR = '#bouton-modifier-interlangue';
		var PORTLET_SELECTOR = '#p-lang-btn .vector-dropdown-content';
		var NEW_ID = 'modifier-langues-lien';

		var marker = D.querySelector( MARKER_SELECTOR );
		if ( !marker ) return;

		var container = D.querySelector( PORTLET_SELECTOR );
		if ( !container ) return;

		if ( D.getElementById( NEW_ID ) ) return;

		var sourceLink = marker.querySelector( 'a' );
		if ( !sourceLink || !sourceLink.href ) return;

		var wantedTooltip = ( marker.getAttribute( 'data-wk-tooltip' ) || '' ).trim();

		var newLink = D.createElement( 'a' );
		newLink.id = NEW_ID;
		newLink.href = sourceLink.href;

		newLink.textContent = ( sourceLink.textContent || '' ).trim() || 'Modifier';
		newLink.className = ( ( sourceLink.getAttribute( 'class' ) || '' ).trim() + ' interlanguage-edit-link' ).trim();
		newLink.setAttribute( 'rel', 'nofollow' );

		if ( wantedTooltip ) {
			newLink.setAttribute( 'title', wantedTooltip );
			newLink.setAttribute( 'data-tooltip', wantedTooltip );
			newLink.setAttribute( 'aria-label', wantedTooltip );
		}

		var wrap = D.createElement( 'div' );
		wrap.className = 'modifier-langues';
		wrap.appendChild( newLink );

		container.appendChild( wrap );
		marker.remove();
	}

	function wkInitHeaderButtons() {
		if ( !wkIsNs( 0 ) || !wkIsView() ) return;

		wkMoveRenameButton();
		wkMoveTopicButton();
		wkMoveCategoriesButton();
		wkMoveInterlanguageButton();
	}

	/* ==========================================================
		TOOLTIPS formulaires + renommer (root-scoped)
	   ========================================================== */

	function wkFixAddDataAndRenameTooltipsOn( root ) {
		var el = wkRootNode( root );
		if ( !el || !el.querySelectorAll ) return;

		var nodes = el.querySelectorAll( 'span.wk-adddata-link[data-wk-tooltip]' );
		for ( var i = 0; i < nodes.length; i++ ) {
			var wrap = nodes[ i ];
			var tt = wrap.getAttribute( 'data-wk-tooltip' );
			if ( !tt ) continue;

			var a = wrap.querySelector( 'a' );
			if ( !a ) continue;

			if ( a.getAttribute( 'title' ) !== tt ) a.setAttribute( 'title', tt );
			if ( a.getAttribute( 'data-tooltip' ) !== tt ) a.setAttribute( 'data-tooltip', tt );
			if ( wrap.hasAttribute( 'title' ) ) wrap.removeAttribute( 'title' );
		}

		var a2 = D.querySelector( '#bouton-renommer a' );
		if ( a2 ) {
			var RENAME_KEY = 'wk-rename-page';
			var tt2 = ( typeof wkMsg === 'function' ) ? wkMsg( RENAME_KEY ) : RENAME_KEY;

			if ( a2.getAttribute( 'title' ) !== tt2 ) a2.setAttribute( 'title', tt2 );
			if ( a2.getAttribute( 'data-tooltip' ) !== tt2 ) a2.setAttribute( 'data-tooltip', tt2 );
			if ( a2.getAttribute( 'aria-label' ) !== tt2 ) a2.setAttribute( 'aria-label', tt2 );
		}
	}

	/* ==========================================================
		More / Latest — via wkParseWikitext (pool + dédup + priorité)
	   ========================================================== */

	function moreContentCall() {
		if ( !wkOnce( 'wkMoreInit' ) ) return;

		$D.on( 'click.wkMore', '.more-content-button', function () {
			$( this ).hide();

			wkWarmI18nCaches();

			var ds = this.dataset || null;
			var page = ds && ds.page ? ds.page : $( this ).data( 'page' );

			var $wrapper = $( this ).parent().find( '.more-content-wrapper' );

			var query = WK_OPEN + WK_T.more + WK_SEP + WK_P.page + ' = ' + page + WK_CLOSE;

			wkParseWikitext( query, 'more' ).then( function ( html ) {
				wkReplaceHtml( $wrapper, '<div class="more-content-wrapper"><div class="more-content-drop show"></div>' + html + '</div>' );
			} ).catch( function () {} );
		} );
	}

	function latestChangesCall() {
		if ( !wkOnce( 'wkLatestInit' ) ) return;

		$D.on( 'click.wkLatest', '.ns-0 .latest-changes-button.mw-ui-button', function () {
			$( this ).hide();

			wkWarmI18nCaches();

			var ds = this.dataset || null;
			var page = ds && ds.page ? ds.page : $( this ).data( 'page' );

			var $wrapper = $( this ).parent().find( '.latest-changes-wrapper' );

			var query = WK_OPEN + WK_T.latest + WK_SEP + WK_P.page + ' = ' + page + WK_CLOSE;

			wkParseWikitext( query, 'latest' ).then( function ( html ) {
				wkReplaceHtml( $wrapper, '<div class="latest-changes-wrapper"><div class="latest-changes-drop show"></div>' + html + '</div>' );
			} ).catch( function () {} );
		} );
	}

	/* ==========================================================
		Hover — WeakMap cache + skip hidden + annulation queue
	   ========================================================== */

	var wkHoverTip = null;
	var wkHoverTipContent = null;
	var wkHoverCurrent = null;
	var wkHoverTimer = 0;
	var wkHoverToken = 0;

	var wkHoverStore = ( typeof WeakMap !== 'undefined' ) ? new WeakMap() : null;

	/* “global scroll/resize hub” (safe) */
	var wkGlobalScrollHubBound = false;
	var wkGlobalScrollHub = null;
	var wkHoverNeedsReposition = false;

	function wkEnsureGlobalScrollHub() {
		if ( wkGlobalScrollHubBound ) return;
		wkGlobalScrollHubBound = true;

		wkGlobalScrollHub = wkRafThrottle( function () {
			/* Hover reposition si tooltip visible */
			if ( wkHoverNeedsReposition && wkHoverCurrent && wkHoverCurrent.length && wkHoverTip && wkHoverTip.is( ':visible' ) ) {
				var el = wkHoverCurrent[ 0 ];
				var ds = el && el.dataset ? el.dataset : null;
				var pos = ( ds && ds.position ) ? ds.position : ( wkHoverCurrent.data( 'position' ) || 'bottom' );
				wkPositionHoverTooltip( wkHoverCurrent, pos );
			}
		} );

		W.addEventListener( 'scroll', wkGlobalScrollHub, { passive: true } );
		W.addEventListener( 'resize', wkGlobalScrollHub, { passive: true } );

		if ( W.visualViewport ) {
			visualViewport.addEventListener( 'resize', wkGlobalScrollHub, { passive: true } );
			visualViewport.addEventListener( 'scroll', wkGlobalScrollHub, { passive: true } );
		}
	}

	function wkEnsureHoverTooltip() {
		if ( wkHoverTip ) return;

		wkHoverTip = $( '<div class="wk-hover-tooltip" aria-hidden="true">\n' +
			'\t<div class="wk-hover-tooltip__content"></div>\n' +
		'</div>' ).appendTo( $B ).hide();

		wkHoverTipContent = wkHoverTip.find( '.wk-hover-tooltip__content' );

		wkHoverTip.on( 'click', function ( e ) {
			e.stopPropagation();
		} );

		wkHoverNeedsReposition = true;
		wkEnsureGlobalScrollHub();
	}

	function wkPositionHoverTooltip( $anchor, position ) {
		if ( !$anchor || !$anchor.length || !wkHoverTip ) return;

		var rect = $anchor[ 0 ].getBoundingClientRect();
		var winW = W.innerWidth || D.documentElement.clientWidth || 0;
		var scrollX = W.pageXOffset || D.documentElement.scrollLeft || 0;
		var scrollY = W.pageYOffset || D.documentElement.scrollTop || 0;

		wkHoverTip.removeClass( 'pos-left pos-right pos-top pos-bottom' );
		if ( position ) wkHoverTip.addClass( 'pos-' + position );

		wkHoverTip.css( { left: -9999, top: -9999, right: '' } ).show();

		var tipW = wkHoverTip.outerWidth();
		var tipH = wkHoverTip.outerHeight();
		var margin = 10;

		var top = rect.bottom + scrollY + margin;
		if ( position === 'top' ) top = rect.top + scrollY - tipH - margin;

		var left = rect.left + scrollX + ( rect.width / 2 ) - ( tipW / 2 );
		left = Math.max( scrollX + 6, Math.min( scrollX + winW - tipW - 6, left ) );

		wkHoverTip.css( { left: Math.round( left ), top: Math.round( top ) } );
	}

	function wkHideHoverTooltip() {
		if ( wkHoverTip ) wkHoverTip.hide().attr( 'aria-hidden', 'true' );
		if ( wkHoverTipContent ) wkHoverTipContent.empty();
		wkHoverCurrent = null;
	}

	function wkSetLocalHoverWrapper( $el, html, position ) {
		var $w = $el.find( '.hover-wrapper' ).first();
		if ( !$w.length ) {
			$el.append( '<div class="hover-wrapper"></div>' );
			$w = $el.find( '.hover-wrapper' ).first();
		}

		var pos = ( position || '' ).trim();
		var cls = 'hover-wrapper show' + ( pos ? ( ' ' + pos ) : '' );

		$w.replaceWith( '<div class="' + cls + '">' + html + '</div>' );
	}

	function wkClearLocalHoverWrapper( $el ) {
		var $w = $el.find( '.hover-wrapper' ).first();
		if ( $w.length ) {
			$w.replaceWith( '<div class="hover-wrapper"></div>' );
		}
	}

	function wkHoverQueryKey( el, $el ) {
		var ds = el && el.dataset ? el.dataset : null;

		var template = ( ds && ds.template ) ? ds.template : $el.data( 'template' );
		var p1 = ( ds && ds.parameter1 ) ? ds.parameter1 : $el.data( 'parameter1' );
		var p2 = ( ds && ds.parameter2 ) ? ds.parameter2 : $el.data( 'parameter2' );
		var p3 = ( ds && ds.parameter3 ) ? ds.parameter3 : $el.data( 'parameter3' );
		var pos = ( ds && ds.position ) ? ds.position : ( $el.data( 'position' ) || 'bottom' );

		return String( template || '' ) + '|' + String( p1 || '' ) + '|' + String( p2 || '' ) + '|' + String( p3 || '' ) + '|' + String( pos || '' );
	}

	function hoverContentCall() {
		if ( !wkOnce( 'wkHoverInit' ) ) return;

		function wkGetHoverTypeAndTpl( $wrap ) {
			if ( $wrap.hasClass( 'hover-map' ) ) {
				return { type: 'map', template: WK_T.hoverMap };
			}
			if ( $wrap.hasClass( 'hover-wikipedia' ) ) {
				return { type: 'wikipedia', template: WK_T.hoverWP };
			}
			return null;
		}

		function wkEnsureLocalHoverWrapper( $wrap ) {
			var $w = $wrap.find( '.hover-wrapper' );
			if ( !$w.length ) {
				$w = $( '<div class="hover-wrapper" aria-hidden="true"></div>' );
				$wrap.append( $w );
			}
			return $w;
		}

		function wkGetLinkNode( $wrap ) {
			var $a = $wrap.find( 'a' ).first();
			return $a.length ? $a : null;
		}

		function wkDecodeWikiTitleFromHref( href ) {
			if ( !href ) return '';
			try {
				var m = href.match( /\/wiki\/([^#?]+)/ );
				if ( !m || !m[ 1 ] ) return '';
				var t = m[ 1 ].replace( /_/g, ' ' );
				return decodeURIComponent( t );
			} catch ( e ) {}
			return '';
		}

		function wkGetParamForMap( $a ) {
			var t = ( $a.attr( 'title' ) || '' ).trim();
			if ( t ) return t;

			var href = $a.attr( 'href' ) || '';
			return wkDecodeWikiTitleFromHref( href );
		}

		function wkGetParamForWikipedia( $a ) {
			var href = $a.attr( 'href' ) || '';
			if ( !href ) return '';

			try {
				var m = href.match( /\/\/[^/]+\/wiki\/([^#?]+)/ );
				if ( m && m[ 1 ] ) {
					var t = m[ 1 ].replace( /_/g, ' ' );
					return decodeURIComponent( t );
				}
			} catch ( e ) {}

			return ( $a.text() || '' ).replace( /\s+/g, ' ' ).trim();
		}

		function wkBuildHoverQuery( info, el, $wrap, $a ) {
			//	Retourne { query, key } ou null
			if ( !info || !info.template ) return null;

			var ds = ( el && el.dataset ) ? el.dataset : null;

			if ( info.type === 'wikipedia' ) {
				var p1 = wkGetParamForWikipedia( $a );
				if ( !p1 ) return null;

				return {
					query: WK_OPEN + info.template + WK_SEP + p1 + WK_SEP + WK_SEP + WK_CLOSE,
					key: 'wikipedia|' + p1
				};
			}

			//	map
			var p1m = wkGetParamForMap( $a );
			if ( !p1m ) return null;

			var p2 = '';
			var p3 = '';

			//	Priorité : data-debate
			if ( ds && ds.debate ) {
				p2 = ds.debate;
				p3 = 'debate';
			} else if ( ds && ds.argument ) {
				p2 = ds.argument;
			}

			return {
				query: WK_OPEN + info.template + WK_SEP + p1m + WK_SEP + ( p2 || '' ) + WK_SEP + ( p3 || '' ) + WK_CLOSE,
				key: 'map|' + p1m + '|' + ( p2 || '' ) + '|' + ( p3 || '' )
			};
		}

		$D.on( 'mouseenter.wkHover', '.hover-map, .hover-wikipedia', function () {
			var el = this;
			var $wrap = $( el );

			wkHoverCurrent = $wrap;

			if ( wkHoverTimer ) clearTimeout( wkHoverTimer );

			var myToken = ++wkHoverToken;

			wkHoverTimer = setTimeout( function () {
				wkHoverTimer = 0;

				if ( myToken !== wkHoverToken ) return;
				if ( !wkHoverCurrent || wkHoverCurrent[ 0 ] !== el ) return;

				if ( $wrap.is( ':hidden' ) ) return;
				if ( el && el.offsetParent === null ) return;

				try {
					var r = el.getBoundingClientRect();
					var vh = W.innerHeight || D.documentElement.clientHeight || 0;
					if ( r.bottom < 0 || r.top > vh ) return;
				} catch ( e ) {}

				var info = wkGetHoverTypeAndTpl( $wrap );
				if ( !info || !info.template ) return;

				var $a = wkGetLinkNode( $wrap );
				if ( !$a ) return;

				var built = wkBuildHoverQuery( info, el, $wrap, $a );
				if ( !built || !built.query || !built.key ) return;

				var $local = wkEnsureLocalHoverWrapper( $wrap );
				$local.attr( 'aria-hidden', 'false' ).show();

				//	Cache
				var stored = wkHoverStore ? wkHoverStore.get( el ) : null;
				if ( stored && stored.key === built.key && stored.html ) {
					$local.html( stored.html );
					return;
				}

				//	Pas de texte d’attente
				$local.empty();

				wkParseWikitext( built.query, 'hover' ).then( function ( html ) {
					if ( myToken !== wkHoverToken ) return;
					if ( !wkHoverCurrent || wkHoverCurrent[ 0 ] !== el ) return;

					if ( wkHoverStore ) wkHoverStore.set( el, { key: built.key, html: html } );

					$local.html( html );
				} ).catch( function () {} );
			}, 140 );
		} );

		$D.on( 'mouseleave.wkHover', '.hover-map, .hover-wikipedia', function () {
			var el = this;
			var $wrap = $( el );

			if ( wkHoverTimer ) clearTimeout( wkHoverTimer );
			wkHoverTimer = 0;

			wkHoverToken++;

			try {
				var info = wkGetHoverTypeAndTpl( $wrap );
				var $a = wkGetLinkNode( $wrap );

				if ( info && $a && info.template ) {
					var built = wkBuildHoverQuery( info, el, $wrap, $a );
					if ( built && built.query ) {
						wkParseCancel( 'hover', built.query );
					}
				}
			} catch ( e ) {}

			var $local = $wrap.find( '.hover-wrapper' );
			if ( $local.length ) {
				$local.attr( 'aria-hidden', 'true' ).hide().empty();
			}
		} );
	}

	/* ==========================================================
		FIL D'ARIANE — observer robuste + fallback scroll si pas IO
	   ========================================================== */

	var filArianeObserver = null;
	var filArianeLock = false;
	var wkObservedSentinel = null;

	var wkObserverRaf = 0;
	var wkFallbackBound = false;
	var wkFallbackRecompute = null;

	function installOrUpdateObserver() {
		var sentinel = getOrCreateLeftNavSentinel();
		if ( !sentinel ) return;

		var needReinstall = false;
		if ( wkObservedSentinel !== sentinel ) needReinstall = true;

		wkObservedSentinel = sentinel;

		if ( !( 'IntersectionObserver' in W ) ) {
			wkBindFallbackObserverOnce();
			applyFilArianeVisibilityNow( 0, sentinel );
			return;
		}

		if ( filArianeObserver && !needReinstall ) {
			applyFilArianeVisibilityNow( 0, sentinel );
			return;
		}

		if ( filArianeObserver ) {
			try { filArianeObserver.disconnect(); } catch ( e ) {}
		}

		filArianeObserver = new IntersectionObserver( function ( entries ) {
			var entry = entries[ 0 ];
			if ( entry && entry.isIntersecting ) hideFilAriane();
			else showFilAriane();
		}, {
			root: null,
			rootMargin: '0px 0px 0px 0px',
			threshold: 0
		} );

		filArianeObserver.observe( sentinel );
		applyFilArianeVisibilityNow( 0, sentinel );
	}

	var installOrUpdateObserverRaf = wkRafThrottle( installOrUpdateObserver );

	function pauseFilArianeObserver() {
		if ( filArianeObserver ) {
			try { filArianeObserver.disconnect(); } catch ( e ) {}
		}
		filArianeObserver = null;
		wkObservedSentinel = null;
	}

	function resumeFilArianeObserver() {
		installOrUpdateObserver();
	}

	function showFilAriane() {
		if ( filArianeLock ) return;
		var fil = D.getElementById( 'fil-ariane' );
		if ( !fil ) return;
		fil.classList.add( 'is-visible' );
		fil.classList.remove( 'is-hidden' );
		fil.setAttribute( 'aria-hidden', 'false' );
	}

	function hideFilAriane() {
		if ( filArianeLock ) return;
		var fil = D.getElementById( 'fil-ariane' );
		if ( !fil ) return;
		fil.classList.add( 'is-hidden' );
		fil.classList.remove( 'is-visible' );
		fil.setAttribute( 'aria-hidden', 'true' );
	}

	function measureFilArianeHeight() {
		var fil = D.getElementById( 'fil-ariane' );
		if ( !fil ) return 0;

		if ( fil.classList.contains( 'is-visible' ) ) return fil.offsetHeight || 0;

		var hadVisible = fil.classList.contains( 'is-visible' );
		var hadHidden = fil.classList.contains( 'is-hidden' );

		fil.classList.add( 'is-visible' );
		fil.classList.remove( 'is-hidden' );

		var h = fil.offsetHeight || 0;

		if ( !hadVisible ) fil.classList.remove( 'is-visible' );
		if ( hadHidden ) fil.classList.add( 'is-hidden' );

		return h;
	}

	function getOrCreateLeftNavSentinel() {
		var leftNav = D.querySelector( '#left-navigation' );
		if ( !leftNav ) return null;

		var next = leftNav.nextElementSibling;
		if ( next && next.id === 'fil-ariane-sentinel' ) return next;

		var sent = D.createElement( 'div' );
		sent.id = 'fil-ariane-sentinel';
		sent.setAttribute( 'aria-hidden', 'true' );
		sent.style.cssText = 'position:relative;height:1px;pointer-events:none;';
		leftNav.parentNode.insertBefore( sent, leftNav.nextSibling );
		return sent;
	}

	function applyFilArianeVisibilityNow( headerOffset, sentinel ) {
		if ( !sentinel ) return;
		var rect = sentinel.getBoundingClientRect();
		if ( rect.top >= headerOffset ) hideFilAriane();
		else showFilAriane();
	}

	function wkBindFallbackObserverOnce() {
		if ( wkFallbackBound ) return;
		wkFallbackBound = true;

		wkFallbackRecompute = wkRafThrottle( function () {
			var sentinel = D.getElementById( 'fil-ariane-sentinel' ) || getOrCreateLeftNavSentinel();
			if ( !sentinel ) return;
			applyFilArianeVisibilityNow( 0, sentinel );
		} );

		W.addEventListener( 'scroll', wkFallbackRecompute, { passive: true } );
		W.addEventListener( 'resize', wkFallbackRecompute, { passive: true } );

		if ( W.visualViewport ) {
			visualViewport.addEventListener( 'resize', wkFallbackRecompute, { passive: true } );
			visualViewport.addEventListener( 'scroll', wkFallbackRecompute, { passive: true } );
		}
	}

	function wkHtmlSig( html ) {
		var s = String( html || '' );
		var len = s.length;

		var c0 = len ? s.charCodeAt( 0 ) : 0;
		var c1 = len ? s.charCodeAt( len - 1 ) : 0;
		var c2 = len ? s.charCodeAt( ( len / 2 ) | 0 ) : 0;
		var c3 = len ? s.charCodeAt( ( len / 4 ) | 0 ) : 0;
		var c4 = len ? s.charCodeAt( ( ( len * 3 ) / 4 ) | 0 ) : 0;

		var limit = Math.min( 200, len );
		var h = 2166136261;
		for ( var i = 0; i < limit; i++ ) {
			h ^= s.charCodeAt( i );
			h = ( h + ( h << 1 ) + ( h << 4 ) + ( h << 7 ) + ( h << 8 ) + ( h << 24 ) ) >>> 0;
		}

		return len + '|' + c0 + '|' + c1 + '|' + c2 + '|' + c3 + '|' + c4 + '|' + h;
	}

	function wkGetOrCreateBreadcrumbNav() {
		var fil = D.getElementById( 'fil-ariane' );
		if ( fil ) return fil;

		var nav = D.createElement( 'nav' );
		nav.id = 'fil-ariane';
		nav.className = 'zone-ariane fil-ariane--sticky is-hidden';
		nav.setAttribute( 'role', 'navigation' );
		nav.setAttribute( 'aria-label', wkMsg( 'wk-breadcrumb-aria-label' ) );
		nav.setAttribute( 'aria-hidden', 'true' );

		var main = D.querySelector( 'main#content.mw-body' ) || D.querySelector( '#content, .mw-body' );
		if ( !main ) return null;

		var anchor = main.querySelector( '.mw-body-header.vector-page-titlebar' );
		if ( anchor && anchor.parentNode ) {
			anchor.parentNode.insertBefore( nav, anchor );
		} else {
			main.insertBefore( nav, main.firstChild );
		}

		return nav;
	}

	function wkSetNavInnerHtml( nav, html ) {
		if ( !nav ) return;

		var prevVisible = nav.classList.contains( 'is-visible' );
		var prevHidden = nav.classList.contains( 'is-hidden' );
		var prevNoAnim = nav.classList.contains( 'no-anim' );
		var prevAria = nav.getAttribute( 'aria-hidden' );

		var tmp = D.createElement( 'div' );
		tmp.innerHTML = html;

		while ( nav.firstChild ) nav.removeChild( nav.firstChild );
		while ( tmp.firstChild ) nav.appendChild( tmp.firstChild );

		if ( prevVisible ) nav.classList.add( 'is-visible' ); else nav.classList.remove( 'is-visible' );
		if ( prevHidden ) nav.classList.add( 'is-hidden' ); else nav.classList.remove( 'is-hidden' );
		if ( prevNoAnim ) nav.classList.add( 'no-anim' ); else nav.classList.remove( 'no-anim' );
		if ( prevAria !== null ) nav.setAttribute( 'aria-hidden', prevAria );
	}

	function injectFilAriane( html, meta ) {
		var nav = wkGetOrCreateBreadcrumbNav();
		if ( !nav ) return;

		if ( meta && meta.currentKey ) nav.setAttribute( 'data-current-key', meta.currentKey );
		if ( meta && meta.currentPath ) nav.setAttribute( 'data-current-path', meta.currentPath );
		if ( meta && meta.currentPage ) nav.setAttribute( 'data-current-page', meta.currentPage );

		var lastSig = nav.getAttribute( 'data-wk-html-sig' ) || '';
		var sig = wkHtmlSig( html );

		if ( lastSig !== sig ) {
			nav.setAttribute( 'data-wk-html-sig', sig );
			wkSetNavInnerHtml( nav, html );
		}

		installOrUpdateObserverRaf();
	}

	( function () {
		var _pendingKey = null;

		function normalizePath( path ) {
			if ( typeof path !== 'string' ) return '';
			var s = path.replace( /\+/g, ' ' );
			try { s = decodeURIComponent( s ); } catch ( e ) {}
			return s.replace( /\s+/g, ' ' ).trim().toLowerCase();
		}

		W.breadcrumbGeneration = function breadcrumbGeneration( titleElement ) {
			if ( typeof titleElement === 'undefined' || !titleElement ) return;
			if ( titleElement.jquery && titleElement.length ) titleElement = titleElement[ 0 ];

			wkWarmI18nCaches();

			var wrap = titleElement.nextElementSibling;
			if ( !wrap || !wrap.classList || !wrap.classList.contains( 'argument-wrapper' ) ) {
					// si jamais le wrapper n'existe pas encore, on laisse tomber proprement
					return;
			}

			var ds = wrap.dataset || null;

			var rawPath = ( ds && ds.path ) ? ds.path : '';
			var page = ( ds && ds.page ) ? ds.page : '';

			if ( !rawPath ) {
				var fil = D.getElementById( 'fil-ariane' );
				if ( fil && fil.parentNode ) fil.parentNode.removeChild( fil );
				return;
			}

			var normPath = normalizePath( String( rawPath ) );
			var normPage = String( page || '' );
			var newKey = normPath + '||' + normPage;

			var filNow = D.getElementById( 'fil-ariane' );
			var currentKey = filNow ? ( filNow.getAttribute( 'data-current-key' ) || '' ) : '';

			if ( currentKey === newKey ) return;

			_pendingKey = newKey;

			var query = WK_OPEN + WK_T.breadcrumbMenu +
				WK_SEP + WK_P.path + ' = ' + rawPath +
				WK_SEP + WK_P.page + ' = ' + page +
			WK_CLOSE;

			wkParseWikitext( query, 'bc' ).then( function ( html ) {
				if ( _pendingKey !== newKey ) return;

				injectFilAriane( html, {
					currentKey: newKey,
					currentPath: normPath,
					currentPage: normPage
				} );
			} ).catch( function () {} );
		};
	} )();

	var wkBreadcrumbScrollTimer = 0;

	function breadcrumbMenu( titleElement, opts ) {
		opts = opts || {};
		if ( typeof titleElement === 'undefined' || !titleElement ) return;
		if ( titleElement.jquery && titleElement.length ) titleElement = titleElement[ 0 ];

		if ( typeof W.breadcrumbGeneration === 'function' ) {
			W.breadcrumbGeneration( titleElement );
		}

		var recompute = wkRafThrottle( function () {
			installOrUpdateObserverRaf();
		} );

		function scrollToTitle() {
			var $el = $( titleElement );
			if ( !$el.length ) return;

			var fil = D.getElementById( 'fil-ariane' );
			if ( !fil ) { setTimeout( scrollToTitle, 100 ); return; }

			var headerOffset = 0;
			var safeGap = 12;
			var forceShow = !!opts.fromMapClick;

			if ( forceShow ) showFilAriane();

			var sentinel = D.querySelector( '#fil-ariane-sentinel' ) || getOrCreateLeftNavSentinel();
			var willShowFil = true;

			if ( sentinel ) {
				var rect = sentinel.getBoundingClientRect();
				willShowFil = ( rect.top <= headerOffset );
			}

			var filH = willShowFil ? ( measureFilArianeHeight() || 0 ) : 0;
			if ( forceShow ) { willShowFil = true; filH = measureFilArianeHeight() || 0; }

			var offset = headerOffset + filH + safeGap;
			var targetY = $el.offset().top - offset;
			targetY = Math.max( 0, targetY );

			filArianeLock = true;
			pauseFilArianeObserver();
			fil.classList.add( 'no-anim' );

			$( 'html, body' ).stop( true, false ).animate( { scrollTop: targetY }, 120, function () {
				fil.classList.remove( 'no-anim' );
				filArianeLock = false;

				requestAnimationFrame( function () {
					resumeFilArianeObserver();
				} );
			} );
		}

		if ( wkOnce( 'wkBreadcrumbListeners' ) ) {
			W.addEventListener( 'resize', recompute, { passive: true } );

			if ( W.visualViewport ) {
				visualViewport.addEventListener( 'resize', recompute, { passive: true } );
				visualViewport.addEventListener( 'scroll', recompute, { passive: true } );
			}
		}

		recompute();

		if ( wkBreadcrumbScrollTimer ) clearTimeout( wkBreadcrumbScrollTimer );
		wkBreadcrumbScrollTimer = setTimeout( function () {
			wkBreadcrumbScrollTimer = 0;
			scrollToTitle();
		}, 150 );
	}

	/* ==========================================================
		Handlers Fil d’Ariane + TOC en GLOBAL (document)
	   ========================================================== */

	function wkIsVectorStickyEnabled() {
		var root = D.documentElement;
		return !!( root && root.classList && root.classList.contains( 'vector-sticky-header-enabled' ) );
	}

	function wkHideVectorStickyHeader() {
		if ( !wkIsVectorStickyEnabled() ) return;
		D.documentElement.classList.add( 'wk-hide-vector-sticky' );
	}

	function wkShowVectorStickyHeader() {
		D.documentElement.classList.remove( 'wk-hide-vector-sticky' );
	}

	function wkBindBreadcrumbHandlers() {
		if ( !wkOnce( 'wkBreadcrumbHandlersInit' ) ) return;

		$D.on( 'click.wkBreadcrumbLink', '#fil-ariane .lien-ariane', function () {
			var ds = this.dataset || null;
			var titleId = ( ds && ds.anchor ) ? ds.anchor : $( this ).data( 'anchor' );
			var targetEl = titleId ? D.getElementById( titleId ) : null;
			if ( !targetEl ) return;

			var level = ( ds && ds.level ) ? parseInt( ds.level, 10 ) : parseInt( $( this ).data( 'level' ), 10 );
			level = isNaN( level ) ? 0 : level;

			//	Fermer tous les arguments enfants ouverts sous cet argument
			var wrap = targetEl.nextElementSibling;
			if ( wrap && wrap.classList && wrap.classList.contains( 'argument-wrapper' ) ) {
				var opened = wrap.querySelectorAll( '.argument-title.is-expanded' );
				for ( var i = 0; i < opened.length; i++ ) {
					wkCollapseTitleEl( opened[ i ] );
				}
			}

			var parentElement = $( targetEl ).closest( '.argument' );
			var inlineElement = parentElement.find( '.colonnes.inline' );
			inlineElement.removeClass( 'inline' );
			if ( !parentElement.length ) $( '.colonnes' ).removeClass( 'inline' );

			breadcrumbMenu( targetEl );
		} );

		$D.on( 'click.wkBreadcrumbDelete', '.supprimer-ariane', function ( e ) {
			e.preventDefault();

			var fil = D.getElementById( 'fil-ariane' );
			if ( fil && fil.parentNode ) fil.parentNode.removeChild( fil );

			wkShowVectorStickyHeader();
		} );
	}

	function wkBindTocRemoveBreadcrumb() {
		if ( !wkOnce( 'wkTocRemoveBreadcrumbInit' ) ) return;

		$D.on( 'click.wkTocRemoveBreadcrumb', '#mw-panel-toc .vector-toc-list-item', function () {
			var fil = D.getElementById( 'fil-ariane' );
			if ( fil && fil.parentNode ) fil.parentNode.removeChild( fil );
		} );
	}

	/* ==========================================================
		ARGUMENTS — Set des éléments expanded (évite gros scans)
		+ TokenMap + Abort (schéma Minerva) — SAFE
	   ========================================================== */

	var wkExpandedSet = ( typeof Set !== 'undefined' ) ? new Set() : null;

	function wkExpandedAdd( el ) {
		if ( !wkExpandedSet || !el ) return;
		wkExpandedSet.add( el );
	}

	function wkExpandedDel( el ) {
		if ( !wkExpandedSet || !el ) return;
		wkExpandedSet.delete( el );
	}

	function wkExpandedForEach( fn ) {
		if ( !wkExpandedSet ) return;

		wkExpandedSet.forEach( function ( el ) {
			if ( !el || !D.documentElement.contains( el ) ) {
				wkExpandedSet.delete( el );
				return;
			}
			fn( el );
		} );
	}

	/* Token/abort par wrapper (comme Minerva) */
	var wkArgTokenByWrapper = new WeakMap();
	var wkArgXhrByWrapper = new WeakMap();

	/* Meta calculée (params modèle) par titre d’argument */
	var wkArgMetaStore = ( typeof WeakMap !== 'undefined' ) ? new WeakMap() : null;

	function wkAbortWrapperXhr( wrapperEl, xhrMap ) {
		if ( !wrapperEl || !xhrMap ) return;
		var prev = xhrMap.get( wrapperEl );
		if ( prev && typeof prev.abort === 'function' ) {
			try { prev.abort(); } catch ( e ) {}
		}
		xhrMap.delete( wrapperEl );
	}

	function wkBumpWrapperToken( wrapperEl, tokenMap, xhrMap ) {
		if ( !wrapperEl || !tokenMap ) return 0;

		var tok = ( tokenMap.get( wrapperEl ) || 0 ) + 1;
		tokenMap.set( wrapperEl, tok );

		if ( xhrMap ) wkAbortWrapperXhr( wrapperEl, xhrMap );

		return tok;
	}

	function wkParseWikitextAbortable( wikitext, bucket, wrapperEl, tokenMap, xhrMap ) {
		var myTok = 0;

		if ( wrapperEl && tokenMap ) {
			myTok = wkBumpWrapperToken( wrapperEl, tokenMap, xhrMap );
		}

		var p = wkParseWikitext( wikitext, bucket );

		/* NOTE: mw.Api().post retourne jqXHR, mais ici on est dans un pool -> pas d’abort natif
			=> “safe”: tokenMap suffit pour ignorer les réponses tardives.
			(Si tu veux abort réel, il faut une branche “direct xhr” comme Minerva.)
		*/

		return { token: myTok, promise: p };
	}

	function wkCollapseTitleEl( el ) {
		if ( !el ) return;

		var $t = $( el );
		$t.removeClass( 'is-expanded' ).addClass( 'visited' );

		var $w = $t.next( '.argument-wrapper' );
		if ( $w.length ) {
			var wEl = $w.get( 0 );
			wkBumpWrapperToken( wEl, wkArgTokenByWrapper, wkArgXhrByWrapper );
			$w.empty();
		}

		wkExpandedDel( el );
	}

	function wkDsGetAny( el, key, $el ) {
		if ( el && el.dataset && typeof el.dataset[ key ] !== 'undefined' && el.dataset[ key ] !== '' ) {
			return el.dataset[ key ];
		}
		if ( $el && $el.length ) {
			var v = $el.data( key );
			if ( typeof v !== 'undefined' && v !== null && String( v ) !== '' ) return v;
		}
		return '';
	}

	function wkEncodePlus( s ) {
		if ( !s ) return '';
		try {
			return encodeURIComponent( s ).replace( /%20/g, '+' );
		} catch ( e ) {}
		return '';
	}

	function wkGetDebateTitleFromHeading() {
		var el = D.querySelector( '#firstHeading .mw-page-title-main' ) || D.querySelector( '#firstHeading' );
		if ( !el ) return '';
		return ( el.textContent || '' ).replace( /\s+/g, ' ' ).trim();
	}

	function wkGetDebateBaseForPath() {
		var t = wkGetDebateTitleFromHeading();
		if ( !t ) {
			try { t = mw.config.get( 'wgTitle' ) || ''; } catch ( e ) { t = ''; }
		}
		return wkEncodePlus( t );
	}

	function wkGetArgumentTitleFromNode( titleEl ) {
		if ( !titleEl ) return '';

		var a = titleEl.querySelector( 'a' );
		if ( !a ) return '';

		return ( a.textContent || '' )
			.replace( /\s+/g, ' ' )
			.trim();
	}

	function wkEnsureArgWrapperAfterTitle( titleEl ) {
		if ( !titleEl ) return null;

		var next = titleEl.nextElementSibling;
		if ( next && next.classList && next.classList.contains( 'argument-wrapper' ) ) return next;

		var w = D.createElement( 'div' );
		w.className = 'argument-wrapper';
		titleEl.insertAdjacentElement( 'afterend', w );
		return w;
	}

	$D.on( 'click.wkArgTitleLink', '.argument-title > a', function ( e ) {
			//	Laisser passer les intentions de navigation (nouvel onglet, etc.)
			if ( e.ctrlKey || e.metaKey || e.shiftKey || e.altKey || e.button === 1 ) return;

			//	Empêche la navigation, mais laisse le clic remonter vers .argument-title (ouverture)
			e.preventDefault();
	} );

	/* ==========================================================
		MODE LECTURE — pile sticky + contenu injecté dans #bodyContent
	   ========================================================== */

	var WK_READING = {
		enabled: true,
		state: {
			chain: []	// [{ page, title, type }]
		}
	};

	var WK_READING_UI = {
		rootId: 'wk-reading-mode',
		stackId: 'wk-reading-stack',
		contentId: 'wk-reading-content',
		closeId: 'wk-reading-close'
	};

	function wkReadingEnsureCss() {
		if ( D.getElementById( 'wk-reading-css' ) ) return;

		var css = [
			'#' + WK_READING_UI.rootId + '{',
			'	box-sizing:border-box;',
			'	max-width:100%;',
			'	margin:0 0 12px 0;',
			'}',
			'#' + WK_READING_UI.stackId + '{',
			'	position:relative;',
			'	margin:0 0 10px 0;',
			'}',
			'.wk-reading__item{',
			'	position:sticky;',
			'	z-index:6;',
			'	margin:0 0 8px 0;',
			'	max-width:100%;',
			'	box-sizing:border-box;',
			'}',
			'.wk-reading__inner{',
			'	background:#fff;',
			'	border:1px solid #c8ccd1;',
			'	border-radius:10px;',
			'	box-shadow:0 2px 10px rgba(0,0,0,.10);',
			'	padding:10px 12px;',
			'	box-sizing:border-box;',
			'	max-width:100%;',
			'}',
			'.wk-reading__item.is-pro .wk-reading__inner{',
			'	border-left:4px solid #14866d;',
			'}',
			'.wk-reading__item.is-con .wk-reading__inner{',
			'	border-left:4px solid #b32424;',
			'}',
			'.wk-reading__meta{',
			'	font-size:12px;',
			'	color:#54595d;',
			'	margin:0 0 4px 0;',
			'}',
			'.wk-reading__title{',
			'	font-weight:600;',
			'	line-height:1.35;',
			'	word-break:break-word;',
			'}',
			'#' + WK_READING_UI.closeId + '{',
			'	display:inline-block;',
			'	margin:0 0 8px 0;',
			'	cursor:pointer;',
			'	color:#3366cc;',
			'}',
			'#' + WK_READING_UI.contentId + '{',
			'	box-sizing:border-box;',
			'	max-width:100%;',
			'}'
		].join( '\n' );

		var style = D.createElement( 'style' );
		style.id = 'wk-reading-css';
		style.textContent = css;
		D.head.appendChild( style );
	}

	function wkReadingEnsureUi() {
		wkReadingEnsureCss();

		var body = D.querySelector( '#bodyContent' );
		if ( !body ) return null;

		var root = D.getElementById( WK_READING_UI.rootId );
		if ( root ) {
			return {
				root: root,
				stack: D.getElementById( WK_READING_UI.stackId ),
				content: D.getElementById( WK_READING_UI.contentId )
			};
		}

		root = D.createElement( 'div' );
		root.id = WK_READING_UI.rootId;

		var close = D.createElement( 'div' );
		close.id = WK_READING_UI.closeId;
		close.textContent = '← ' + wkMsg( 'wk-reading-back' );

		var stack = D.createElement( 'div' );
		stack.id = WK_READING_UI.stackId;

		var content = D.createElement( 'div' );
		content.id = WK_READING_UI.contentId;

		root.appendChild( close );
		root.appendChild( stack );
		root.appendChild( content );

		body.insertBefore( root, body.firstChild );

		return { root: root, stack: stack, content: content };
	}

	function wkReadingIsClickInsideReading( target ) {
		if ( !target ) return false;
		var root = D.getElementById( WK_READING_UI.rootId );
		return !!( root && root.contains( target ) );
	}

	function wkReadingGetTypeFromTitleEl( titleEl ) {
		var ul = titleEl ? titleEl.closest( 'ul.argument-list' ) : null;
		if ( !ul ) return '';
		return ul.classList.contains( 'is-con' ) ? 'contre' : 'pour';
	}

	function wkReadingBuildChainFromDom( titleEl ) {
		//	Chaîne basée sur les wrappers réellement présents (donc uniquement la descendance ouverte)
		var chain = [];
		var curTitle = titleEl;

		while ( curTitle ) {
			var page = wkReadingGetArgPageFromTitleEl( curTitle );
			var title = wkGetArgumentTitleFromNode( curTitle ) || ( curTitle.textContent || '' ).trim();
			var type = wkReadingGetTypeFromTitleEl( curTitle );

			chain.push( { page: page, title: title, type: type } );

			var parentWrap = null;

			//	parent = wrapper qui contient la UL courante
			var ul = curTitle.closest( 'ul.argument-list' );
			parentWrap = ul ? ul.closest( '.argument-wrapper' ) : null;

			//	parent title = previousElementSibling du wrapper parent (si présent)
			if ( parentWrap ) {
				var prev = parentWrap.previousElementSibling;
				if ( prev && prev.classList && prev.classList.contains( 'argument-title' ) ) {
					curTitle = prev;
					continue;
				}
			}

			break;
		}

		chain.reverse();
		return chain;
	}

	function wkReadingGetArgPageFromTitleEl( titleEl ) {
		var a = titleEl ? titleEl.querySelector( 'a[href]' ) : null;
		if ( !a ) return '';

		var href = a.getAttribute( 'href' ) || '';
		if ( !href ) return '';

		return hrefToPageTitle( href );
	}

	function wkReadingRenderStack( ui, chain ) {
		ui.stack.textContent = '';

		for ( var i = 0; i < chain.length; i++ ) {
			var it = chain[ i ];

			var item = D.createElement( 'div' );
			item.className = 'wk-reading__item';

			if ( it.type === 'contre' ) item.classList.add( 'is-con' );
			else item.classList.add( 'is-pro' );

			item.dataset.page = it.page || '';

			var inner = D.createElement( 'div' );
			inner.className = 'wk-reading__inner';

			var meta = D.createElement( 'div' );
			meta.className = 'wk-reading__meta';
			meta.textContent = 'Niveau ' + ( i + 1 );

			var title = D.createElement( 'div' );
			title.className = 'wk-reading__title';
			title.textContent = it.title || '';

			inner.appendChild( meta );
			inner.appendChild( title );
			item.appendChild( inner );

			//	Clic sur une carte => ouvrir ce niveau (recharge contenu)
			( function ( page ) {
				item.addEventListener( 'click', function () {
					if ( !page ) return;
					wkOpenReadingModeFromPageTitle( page, chain.slice( 0, i + 1 ) );
				} );
			} )( it.page );

			ui.stack.appendChild( item );
		}

		wkReadingUpdateStickyOffsets( ui );
	}

	function wkReadingUpdateStickyOffsets( ui ) {
		var top = 0;
		var gap = 8;
		var items = ui.stack.querySelectorAll( '.wk-reading__item' );

		for ( var i = 0; i < items.length; i++ ) {
			items[ i ].style.top = top + 'px';
			top += ( items[ i ].offsetHeight || 0 ) + gap;
		}
	}

	function wkReadingExtractFragment( html ) {
		//	Réutilise ton extraction Summary → Parent_debates
		function wkFindHeadingStartById( html2, id ) {
			var key = 'id="' + id + '"';
			var p = html2.indexOf( key );
			if ( p === -1 ) return -1;
			return html2.lastIndexOf( '<h2', p );
		}

		function wkExtractBetweenHeadingIds( html2, startId, endId ) {
			var a = wkFindHeadingStartById( html2, startId );
			if ( a === -1 ) return '';

			var key = 'id="' + endId + '"';
			var p = html2.indexOf( key, a + 1 );
			if ( p === -1 ) return '';

			var b = html2.lastIndexOf( '<h2', p );
			if ( b === -1 ) b = html2.lastIndexOf( '<div', p );
			if ( b === -1 || b <= a ) return '';

			return html2.slice( a, b );
		}

		return wkExtractBetweenHeadingIds( html, 'Summary', 'Parent_debates' );
	}

	function wkOpenReadingModeFromPageTitle( argPage, chainOpt ) {
		if ( !WK_READING.enabled ) return;

		var ui = wkReadingEnsureUi();
		if ( !ui ) return;

		//	Remplacer la chaîne (si fournie)
		if ( chainOpt && chainOpt.length ) {
			WK_READING.state.chain = chainOpt.slice();
		}

		wkReadingRenderStack( ui, WK_READING.state.chain );

		//	Cacher le fil d’ariane “linéaire” si présent (optionnel)
		var fil = D.getElementById( 'fil-ariane' );
		if ( fil ) fil.style.display = 'none';

		ui.content.innerHTML = '<p>' + wkMsg( 'wk-loading' ) + '</p>';

		//	Cache fragment (celui que tu as déjà)
		if ( wkArgEmbedCache.has( argPage ) ) {
			var cached = wkArgEmbedCache.get( argPage ) || '';
			if ( cached ) {
				ui.content.innerHTML = cached;
				wkOnContent( ui.content );
				wkReadingUpdateStickyOffsets( ui );
			}
			return;
		}

		wkGetApi().get( {
			action: 'parse',
			formatversion: 2,
			page: argPage,
			prop: 'text',
			disableeditsection: 1,
			redirects: 1
		} ).then( function ( data ) {
			var html = ( data && data.parse && data.parse.text ) ? data.parse.text : '';
			if ( !html ) return;

			var fragment = wkReadingExtractFragment( html );
			if ( !fragment ) return;

			wkArgEmbedCache.set( argPage, fragment );

			ui.content.innerHTML = fragment;
			wkOnContent( ui.content );
			wkReadingUpdateStickyOffsets( ui );
		} ).catch( function () {} );
	}

	function wkOpenReadingModeFromTitleEl( titleEl ) {
		if ( !titleEl ) return;

		var argPage = wkReadingGetArgPageFromTitleEl( titleEl );
		if ( !argPage ) return;

		//	Si clic depuis le contenu mode lecture : on append au chain courant
		if ( wkReadingIsClickInsideReading( titleEl ) && WK_READING.state.chain.length ) {
			var next = {
				page: argPage,
				title: wkGetArgumentTitleFromNode( titleEl ) || ( titleEl.textContent || '' ).trim(),
				type: wkReadingGetTypeFromTitleEl( titleEl )
			};
			var chain2 = WK_READING.state.chain.slice();
			chain2.push( next );

			WK_READING.state.chain = chain2;
			wkOpenReadingModeFromPageTitle( argPage, chain2 );
			return;
		}

		//	Sinon : on reconstruit depuis le DOM ouvert (descendance réelle)
		var chain = wkReadingBuildChainFromDom( titleEl );
		WK_READING.state.chain = chain;

		wkOpenReadingModeFromPageTitle( argPage, chain );
	}

	function wkCloseReadingMode() {
		var root = D.getElementById( WK_READING_UI.rootId );
		if ( root ) root.parentNode.removeChild( root );

		//	Réafficher fil ariane si tu l’avais masqué
		var fil = D.getElementById( 'fil-ariane' );
		if ( fil ) fil.style.display = '';
	}

	function argumentContentCall() {
		if ( !wkOnce( 'wkArgOpenInit' ) ) return;

		$D.on( 'click.wkArgOpen', '.argument-title:not(.is-expanded)', function () {
			wkHideVectorStickyHeader();
			wkWarmI18nCaches();

			var $clicked = $( this );
			var clickedElement = this;

			//	Fermer les arguments ouverts au même niveau (sans data-level)
			var ul = clickedElement.closest( 'ul.argument-list' );
			var scope = ul ? ul.closest( '.argument-wrapper' ) : null;

			if ( scope ) {
				//	Niveau > 1 : fermer les siblings (pro + con) du même parent
				var opened = scope.querySelectorAll( 'ul.argument-list > li.argument > .argument-title.is-expanded' );

				for ( var i = 0; i < opened.length; i++ ) {
					if ( opened[ i ] !== clickedElement ) {
						wkCollapseTitleEl( opened[ i ] );
					}
				}
			} else {
				//	Niveau 1 : fermer les autres niveau 1 (évite closest() en boucle)
				var openedTop = D.querySelectorAll( 'li.argument.level-1 > .argument-title.is-expanded' );

				for ( var j = 0; j < openedTop.length; j++ ) {
					if ( openedTop[ j ] !== clickedElement ) {
						wkCollapseTitleEl( openedTop[ j ] );
					}
				}
			}

			wkOpenReadingModeFromTitleEl( clickedElement );

			var col = clickedElement.closest( '.colonnes' );
			if ( col ) col.classList.add( 'inline' );
		} );

		$D.on( 'click.wkArgStop', '.ns-0 a.modifier-argument-lien', function ( event ) {
			event.stopPropagation();
		} );
	}

	function wkApplyArgMetaFromTitleToWrapper( titleEl, $title, wrapperEl ) {
		if ( titleEl && titleEl.jquery && titleEl.length ) titleEl = titleEl[ 0 ];
		if ( !titleEl || !wrapperEl ) return;

		//	Type (pour/contre) via la liste courante
		var ul = titleEl.closest( 'ul.argument-list' );
		if ( !ul ) return;

		var argType = ul.classList.contains( 'is-con' ) ? 'contre' : 'pour';

		//	Titre “propre”
		var argTitle = wkGetArgumentTitleFromNode( titleEl );
		if ( !argTitle ) return;

		//	Parent wrapper = wrapper qui contient cette UL (niveau parent)
		var parentWrap = ul.closest( '.argument-wrapper' );

		var level = 1;
		var path = '';

		if ( parentWrap && parentWrap.dataset && parentWrap.dataset.path ) {
			var parentLevel = parseInt( parentWrap.dataset.level, 10 );
			parentLevel = isNaN( parentLevel ) ? 0 : parentLevel;

			level = parentLevel + 1;

			var typeParent = parentWrap.classList.contains( 'is-pro' ) ? 'pour' : 'contre';
			var argIcon = ( argType === typeParent ) ? 'pour' : 'contre';

			path = parentWrap.dataset.path + '⟭' + argIcon + '⟬' + argTitle;
		} else {
			path = wkGetDebateBaseForPath() + '⟭' + argType + '⟬' + argTitle;
		}

		wrapperEl.classList.remove( 'is-pro', 'is-con' );
		wrapperEl.classList.add( argType === 'contre' ? 'is-con' : 'is-pro' );

		wrapperEl.dataset.level = String( level );
		wrapperEl.dataset.path = String( path );
	}

	function loadContentFromTitle( $title ) {
		//	Mode lecture : on n’injecte plus jamais sous le titre
		if ( W.WK_READING && W.WK_READING.enabled && typeof W.wkOpenReadingModeFromTitleEl === 'function' ) {
			var el = $title && $title.length ? $title[ 0 ] : null;
			if ( el ) W.wkOpenReadingModeFromTitleEl( el );
			return;
		}

		wkWarmI18nCaches();

		$title.addClass( 'is-expanded' ).removeClass( 'visited' );
		var el = $title[ 0 ];

		wkExpandedAdd( el );

		var wrapperEl = wkEnsureArgWrapperAfterTitle( el );
		if ( !wrapperEl ) return;

		//	Vider vite (plus rapide que $wrapper.empty() ici)
		wrapperEl.textContent = '';

		wkApplyArgMetaFromTitleToWrapper( el, $title, wrapperEl );

		//	Lien => argPage
		var a = el.querySelector( 'a[href]' );
		if ( !a ) return;

		var href = a.getAttribute( 'href' ) || '';
		if ( !href ) return;

		var argPage = hrefToPageTitle( href );
		if ( !argPage ) return;

		//	Helper local : injection ultra rapide via fragment
		function appendFragment( html ) {
			if ( !html ) return;
			wrapperEl.insertAdjacentHTML( 'beforeend', html );
		}

		//	Retourne l’index du début du bloc heading (mw-heading ou h2) pour un id donné
		function wkFindHeadingStartById( html, id ) {
			var key = 'id="' + id + '"';
			var p = html.indexOf( key );
			if ( p === -1 ) return -1;
			return html.lastIndexOf( '<h2', p );
		}

		//	Extraction start inclus / end exclu (ultra rapide)
		function wkExtractBetweenHeadingIds( html, startId, endId ) {
			var a = wkFindHeadingStartById( html, startId );
			if ( a === -1 ) return '';

			var key = 'id="' + endId + '"';
			var p = html.indexOf( key, a + 1 );
			if ( p === -1 ) return '';

			var b = html.lastIndexOf( '<h2', p );
			if ( b === -1 ) {
				b = html.lastIndexOf( '<div', p );
			}
			if ( b === -1 || b <= a ) return '';

			return html.slice( a, b );
		}

		//	✅ Cache HIT (has() = robuste même si valeur falsy)
		if ( wkArgEmbedCache.has( argPage ) ) {
			var cachedFrag = wkArgEmbedCache.get( argPage ) || '';
			if ( cachedFrag ) {
				appendFragment( cachedFrag );
				wkOnContent( wrapperEl );
			}
			return;
		}

		//	Token anti-réponse tardive
		var token = wkBumpWrapperToken(
			wrapperEl,
			wkArgTokenByWrapper,
			wkArgXhrByWrapper
		);

		//	❌ Cache MISS → parse(page)
		wkGetApi().get( {
			action: 'parse',
			formatversion: 2,
			page: argPage,
			prop: 'text',
			disableeditsection: 1,
			redirects: 1
		} ).then( function ( data ) {

			//	Ignore si un autre chargement a été lancé depuis
			if ( wrapperEl && wkArgTokenByWrapper.get( wrapperEl ) !== token ) return;

			var html = ( data && data.parse && data.parse.text ) ? data.parse.text : '';
			if ( !html ) return;

			//	Optionnel : virer les commentaires HTML (parfois petit gain)
			//	html = html.replace( /<!--[\S\s]*?-->/gm, '' );

			//	Extraction ultra rapide : #Summary inclus → #Parent_debates non inclus
			var fragment = wkExtractBetweenHeadingIds( html, 'Summary', 'Parent_debates' );
			if ( !fragment ) return;

			//	🧠 Cache (fragment HTML)
			wkArgEmbedCache.set( argPage, fragment );

			//	Injection via DocumentFragment
			appendFragment( fragment );
			wkOnContent( wrapperEl );

		} ).catch( function () {} );
	}

	function argumentContentDrop() {
		if ( !wkOnce( 'wkArgDropInit' ) ) return;

		$D.on( 'click.wkArgDrop', '.argument-title.is-expanded', function ( e ) {
			if ( $( e.target ).closest( '.modifier-dropdown' ).length ) return;
			wkCollapseTitleEl( this );
		} );
	}

	function closeArgument( level, clickedElement ) {
		clickedElement = clickedElement || null;

		if ( wkExpandedSet ) {
			wkExpandedForEach( function ( el ) {
				if ( clickedElement && el === clickedElement ) return;

				var lvlRaw = wkDsGetAny( el, 'level', $( el ) );
				var lvl = parseInt( lvlRaw, 10 );
				lvl = isNaN( lvl ) ? 1 : lvl;

				if ( lvl === level ) wkCollapseTitleEl( el );
			} );
			return;
		}

		$( '.argument-title.is-expanded' ).each( function () {
			var lvl2Raw = wkDsGetAny( this, 'level', $( this ) );
			var lvl2 = parseInt( lvl2Raw, 10 );
			lvl2 = isNaN( lvl2 ) ? 1 : lvl2;

			if ( lvl2 === level && ( !clickedElement || this !== clickedElement ) ) {
				wkCollapseTitleEl( this );
			}
		} );
	}

	/* ==========================================================
		Carte des arguments en tête de débat
	   ========================================================== */

	function argumentMapContentCall() {
		if ( !wkOnce( 'wkMapOpenInit' ) ) return;

		$D.on( 'click.wkMapOpen', '.ns-0 #Argument_map .argument-title--map', function () {
			wkHideVectorStickyHeader();
			wkWarmI18nCaches();

			closeArgument( 1 );

			var id = $( this ).attr( 'id' );
			id = id ? id.slice( 0, -4 ) : '';
			if ( !id ) return;

			var raw = D.getElementById( id );
			if ( !raw ) return;

			var titleEl = null;

			if ( raw.classList && raw.classList.contains( 'argument-title' ) ) {
				titleEl = raw;
			} else {
				titleEl = raw.querySelector( '.argument-title' ) || raw.querySelector( 'div.argument-title' );
			}

			if ( !titleEl || !titleEl.id ) return;

			var $title = $( '#' + CSS.escape( titleEl.id ) );

			wkEnsureModifierArgumentButton( $title );

			if ( !$title.hasClass( 'is-expanded' ) ) {
				loadContentFromTitle( $title );
			}

			breadcrumbMenu( $title[ 0 ], { fromMapClick: true } );

			$( this ).addClass( 'visited' );
		} );
	}

	function argumentMapColor() {
		if ( !wkOnce( 'wkMapColorInit' ) ) return;

		$D.on( 'click.wkMapColor', '.ns-0 .argument.level-1:not(.is-expanded)', function () {
			var id = this.getAttribute( 'id' ) || '';
			if ( !id ) return;

			$( '#' + CSS.escape( id ) + '_map' ).addClass( 'visited' );
		} );
	}

	/* ==========================================================
		Lazy-bind NS0 view
	   ========================================================== */

	function wkLazyBindForArgumentsView( root ) {
		if ( !( wkIsNs( 0 ) || wkIsNs( 3100 ) ) || !wkIsView() ) return;

		var el = wkRootNode( root );
		if ( !el || !el.querySelector ) return;

		if ( el.querySelector( '.argument-title' ) ) {
			argumentContentCall();
			argumentContentDrop();
			wkBindBreadcrumbHandlers();
			wkBindTocRemoveBreadcrumb();
		}

		if ( el.querySelector( '#Argument_map .argument-title--map, #Argument_map' ) ) {
			argumentMapContentCall();
			argumentMapColor();
		}
	}

	/* ==========================================================
		RESTE (FormEdit / SMW / Tooltips / Dropdown etc.)
	   ========================================================== */

	function wkHideTitlebarOnAutoEval() {
		if ( !wkIsNs( -1 ) ) return;
		if ( !D.body.classList.contains( 'mw-special-FormEdit' ) ) return;
		if ( !D.body.classList.contains( 'action-view' ) ) return;

		if ( !D.querySelector( '#accepte-autoevaluation' ) ) return;

		var titlebar = D.querySelector( '.mw-body-header.vector-page-titlebar' );
		if ( titlebar ) titlebar.style.display = 'none';
	}

	function wkGetPfScope() {
		var pf = D.getElementById( 'pfForm' );
		return pf ? $( pf ) : $D;
	}

	function fillEditSummary( message ) {
		if ( typeof message === 'undefined' || message === null ) return;

		var $input = $( 'input[name=wpSummary]' );
		if ( !$input.length ) return;

		var summary = $input.val() || '';

		if ( summary ) {
			var condition = summary.substr( -3 );
			if ( condition === '*/ ' ) summary += message;
			else summary += ' + ' + message;
		} else {
			summary = message;
		}

		$input.val( summary );
	}

	function fillEditSummaryForCheckbox( $object, addingMessage, removingMessage ) {
		if ( !$object || !$object.length ) return;

		var $input = $( 'input[name=wpSummary]' );
		if ( !$input.length ) return;

		var checked = $object.prop( 'checked' );
		var bannerName = $object.parent();
		bannerName = $( bannerName ).next();
		bannerName = $( bannerName ).text() + ' »';

		var actionDone = checked ? ( addingMessage + ' «' ) : ( removingMessage + ' «' );
		var message = actionDone + bannerName;

		fillEditSummary( message );
	}

	function wkInitEditSummaries() {
		if ( !wkIsFormEdit() ) return;
		if ( !wkOnce( 'wkEditSummariesInit' ) ) return;

		var $scope = wkGetPfScope();

		if ( $( '.mw-special-FormEdit' ).length > 0 ) {

			( function () {
				var sectionValue = $( '#formName' ).data( 'section' );
				var $summaryField = $( 'input[name="wpSummary"]' );
				if ( $summaryField.length && ( $summaryField.val() || '' ).trim() === '' && sectionValue ) {
					$summaryField.val( '/* ' + sectionValue + ' */ ' );
				}
			} )();

			( function () {

				var zones = [
					{ selector: '.zone-arguments-pour', labelReorgKey: 'wk-summary-reorg-arguments', labelRenomKey: 'wk-summary-rename-argument', labelSuppKey: 'wk-summary-delete-argument', labelAjoutKey: 'wk-summary-add-argument-existing' },
					{ selector: '.zone-arguments-contre', labelReorgKey: 'wk-summary-reorg-arguments', labelRenomKey: 'wk-summary-rename-argument', labelSuppKey: 'wk-summary-delete-argument', labelAjoutKey: 'wk-summary-add-argument-existing' },
					{ selector: '.zone-justifications', labelReorgKey: 'wk-summary-reorg-arguments', labelRenomKey: 'wk-summary-rename-argument', labelSuppKey: 'wk-summary-delete-argument', labelAjoutKey: 'wk-summary-add-argument-existing' },
					{ selector: '.zone-objections', labelReorgKey: 'wk-summary-reorg-arguments', labelRenomKey: 'wk-summary-rename-objection', labelSuppKey: 'wk-summary-delete-objection', labelAjoutKey: 'wk-summary-add-argument-existing' },
					{ selector: '.zone-introduction', labelReorgKey: 'wk-summary-reorg-sections', labelRenomKey: 'wk-summary-rename-section', labelSuppKey: 'wk-summary-delete-section', labelSuppBisKey: 'wk-summary-delete-section-untitled', labelAjoutKey: 'wk-summary-add-section' },
					{ selector: '.zone-voir-Wikipedia', labelReorgKey: 'wk-summary-reorg-articles', labelRenomKey: 'wk-summary-rename-article', labelSuppKey: 'wk-summary-delete-article', labelAjoutKey: 'wk-summary-add-wikipedia-article' },
					{ selector: '.zone-debats-connexes', labelReorgKey: 'wk-summary-reorg-debats', labelRenomKey: 'wk-summary-rename-debat', labelSuppKey: 'wk-summary-delete-debat', labelAjoutKey: 'wk-summary-add-debat' },
					{ selector: '.zone-interlangue', labelReorgKey: 'wk-summary-reorg-interlang', labelSuppKey: 'wk-summary-delete-interlang', labelAjoutKey: 'wk-summary-add-interlang' },
					{ selector: '.zone-citations', labelReorgKey: 'wk-summary-reorg-citations', labelSuppKey: 'wk-summary-delete-citation', labelSuppBisKey: 'wk-summary-delete-citation-generic', labelAjoutKey: 'wk-summary-add-citation' },
					{ selector: '.zone-references', labelReorgKey: 'wk-summary-reorg-references', labelSuppKey: 'wk-summary-delete-reference', labelSuppBisKey: 'wk-summary-delete-reference-generic', labelAjoutKey: 'wk-summary-add-reference' }
				];

				W.ajoutInstance = false;
				W.ajoutInstanceZone = null;

				function wkBindZoneSummaryHandlers( root ) {
					var scope = root && root.nodeType ? root : D;
					var pfRoot = scope.querySelector( '#pfForm' ) || scope;

					zones.forEach( function ( zone ) {

						var selRemove = zone.selector + ' .instanceRemove a';
						var selAdd = zone.selector + ' .instanceAddAbove a, ' + zone.selector + ' .multipleTemplateAdder';
						var selRename = zone.selector + ' .parametre-important';

						var removeNodes = pfRoot.querySelectorAll( selRemove );
						for ( var i = 0; i < removeNodes.length; i++ ) {
							var element = removeNodes[ i ];
							if ( element.dataset.wkSumRemoveBound === '1' ) continue;
							element.dataset.wkSumRemoveBound = '1';

							element.addEventListener( 'click', function ( e ) {
								e.preventDefault();

								var row = this.closest( 'tr' );
								var titreInput = row ? row.querySelector( '.parametre-important' ) : null;
								var isBis = false;

								if ( !titreInput ) {
									titreInput = row ? row.querySelector( '.parametre-important-bis' ) : null;
									isBis = !!titreInput;
								}

								var titre = ( titreInput && titreInput.value ) ? titreInput.value : null;
								var key;

								if ( titre ) {
									key = isBis ? ( zone.labelSuppBisKey || zone.labelSuppKey ) : zone.labelSuppKey;
									fillEditSummary( wkMsg( key, titre ) );
								} else {
									key = zone.labelSuppBisKey || zone.labelSuppKey;
									fillEditSummary( wkMsg( key ) );
								}
							} );
						}

						var addNodes = pfRoot.querySelectorAll( selAdd );
						for ( var j = 0; j < addNodes.length; j++ ) {
							var elementAdd = addNodes[ j ];
							if ( elementAdd.dataset.wkSumAddBound === '1' ) continue;
							elementAdd.dataset.wkSumAddBound = '1';

							elementAdd.addEventListener( 'click', function ( e ) {
								e.preventDefault();

								if (
									zone.selector === '.zone-introduction' ||
									zone.selector === '.zone-citations' ||
									zone.selector === '.zone-references'
								) {
									fillEditSummary( wkMsg( zone.labelAjoutKey ) );
								} else {
									W.ajoutInstance = true;
									W.ajoutInstanceZone = zone.selector;
								}
							} );
						}

						var renameNodes = pfRoot.querySelectorAll( selRename );
						for ( var k = 0; k < renameNodes.length; k++ ) {
							var input = renameNodes[ k ];
							if ( input.dataset.wkSumRenameBound === '1' ) continue;
							input.dataset.wkSumRenameBound = '1';

							input.addEventListener( 'blur', function ( e ) {
								var value = e && e.target ? e.target.value : '';
								if ( value && value.trim() !== '' ) {
									fillEditSummary( wkMsg( zone.labelRenomKey, value ) );
								}
							} );
						}

					} );
				}

				W.ajoutInstance = false;
				W.ajoutInstanceZone = null;

				wkBindZoneSummaryHandlers( D );

				$D.on( 'pfaddinstance pfafterrebuild pfcreateinput', function ( e ) {
					wkBindZoneSummaryHandlers( ( e && e.target ) ? e.target : D );
				} );

				$scope.on( 'select2:select.wkSumSelect2', 'select', function ( e ) {
					var match = ( e && e.params && e.params.data && e.params.data.text ) ? ( e.params.data.text || '' ).trim() : '';

					try {
						var selectedId = e.params.data && e.params.data._resultId;
						var $option = selectedId ? $( D.getElementById( selectedId ) ) : null;
						if ( $option && $option.length && $option.find( '.select2-match-entire' ).length ) {
							match = $option.find( '.select2-match-entire' ).text().trim();
						}
					} catch ( err ) {}

					var message;
					if ( W.ajoutInstance && W.ajoutInstanceZone ) {
						var matchedZone = zones.find( function ( z ) { return z.selector === W.ajoutInstanceZone; } );
						if ( matchedZone ) message = wkMsg( matchedZone.labelAjoutKey, match );
						else message = wkMsg( 'wk-summary-add-generic', match );

						W.ajoutInstance = false;
						W.ajoutInstanceZone = null;
					} else {
						message = wkMsg( 'wk-summary-add-generic', match );
					}

					fillEditSummary( message );
				} );

			} )();

			$scope.on( 'click.wkWarnCb', '.checkboxesSpan .oo-ui-inputWidget-input', function () {
				if ( $( this ).closest( '.zone-rubriques' ).length === 0 ) {
					fillEditSummaryForCheckbox( $( this ), wkMsg( 'wk-summary-warning-add' ), wkMsg( 'wk-summary-warning-remove' ) );
				}
			} );

			$scope.on( 'click.wkRubCb', '.zone-rubriques .oo-ui-inputWidget-input', function () {
				fillEditSummaryForCheckbox( $( this ), wkMsg( 'wk-summary-rubrique-add' ), wkMsg( 'wk-summary-rubrique-remove' ) );
			} );

			$scope.on( 'change.wkProgress', '.mw-special-FormEdit .zone-bandeaux .mandatoryField', function () {
				var bannerName = $( '.zone-bandeaux select.mandatoryField option:selected' ).val();
				fillEditSummary( wkMsg( 'wk-summary-progress-change', bannerName ) );
			} );

			$scope.on( 'click.wkKeywordRemove', '.select2-selection__choice__remove', function () {
				var $li = $( this ).closest( '.select2-selection__choice' );
				var keyword = $li.find( '.select2-match-entire' ).text();
				fillEditSummary( wkMsg( 'wk-summary-keyword-remove', keyword ) );
			} );

			( function () {
				var $summary = $( 'input[name=wpSummary]' );
				var sujetCompletInitial = $( '.zone-sujet-complet' ).val() || '';

				$scope.on( 'change.wkSubjectFull1', '.zone-sujet-complet', function () {
					var sujetCompletActuel = $( this ).val() || '';
					var ajoutOuModification = '';

					if ( sujetCompletInitial === '' && sujetCompletActuel !== '' ) {
						ajoutOuModification = wkMsg( 'wk-summary-subject-add', sujetCompletActuel );
					} else if ( sujetCompletInitial !== '' && sujetCompletActuel !== '' && sujetCompletInitial !== sujetCompletActuel ) {
						ajoutOuModification = wkMsg( 'wk-summary-subject-mod', sujetCompletActuel );
					}

					if ( ajoutOuModification ) {
						$summary.val( '/* Sujet du débat */ ' + ajoutOuModification );
					}
				} );
			} )();

			$scope.on( 'click.wkResumeOps', '.resume-modifications', function () {
				var $summary = $( 'input[name=wpSummary]' );
				if ( !$summary.length ) return;

				var summary = $summary.val() || '';
				var newSummary = ( $( this ).text() || '' ).trim();

				if ( summary ) {
					var condition = summary.substr( -3 );
					if ( condition === '*/ ' ) summary += newSummary;
					else summary += ' + ' + newSummary;
				} else {
					summary = newSummary;
				}
				$summary.val( summary );
			} );
		}
	}

	function wkReinitSMWTooltips() {
		if ( !wkOnce( 'wkSmwTooltipInit' ) ) return;

		mw.loader.using( 'ext.smw.tooltip' ).then( function () {
			function reinitSMWTooltips( $root ) {
				try {
					if ( W.smw && smw.tooltip && smw.tooltip.init ) smw.tooltip.init( $root || $D );
				} catch ( e ) {}
			}

			reinitSMWTooltips( $D );

			$D.on( 'pfaddinstance pfafterrebuild pfcreateinput', function ( e ) {
				reinitSMWTooltips( $( e && e.target ? e.target : D ) );
			} );
		} );
	}

	function wkRemoveSomeTooltipsOn( root ) {
		var el = wkRootNode( root );
		if ( !el || !el.querySelectorAll ) return;

		var nodes = el.querySelectorAll( '.masquer-infobulle a[title]' );
		for ( var i = 0; i < nodes.length; i++ ) {
			nodes[ i ].removeAttribute( 'title' );
		}
	}

	function wkRemoveSomeTooltips() {
		if ( !wkOnce( 'wkRemoveSomeTooltipsInit' ) ) return;

		$D.on( 'mouseenter.wkRmTip', '.hover-wikipedia a[title], .hover-map a[title]', function () {
			this.removeAttribute( 'title' );
		} );
	}

	function wkRefTooltips() {
		( function ( mwLocal, $ ) {
			'use strict';

			if ( !wkOnce( 'wkRefTooltipInit' ) ) return;

			var $tooltip = null;
			var $content = null;
			var currentTrigger = null;

			function ensureTooltip() {
				if ( $tooltip ) return;

				$tooltip = $( '<div class="wk-ref-tooltip" role="dialog" aria-hidden="true">\n' +
					'\t<div class="wk-ref-tooltip__content"></div>\n' +
				'</div>' ).appendTo( $B ).hide();

				$tooltip.css( { position: 'absolute', top: -9999, left: -9999 } );

				$content = $tooltip.find( '.wk-ref-tooltip__content' );

				$tooltip.on( 'click', function ( e ) {
					e.stopPropagation();
				} );
			}

			function getNoteHtmlFromLink( $a ) {
				var href = $a.attr( 'href' );
				if ( !href || href.charAt( 0 ) !== '#' ) return '';

				var id = href.slice( 1 );
				var $note = $( '#' + $.escapeSelector( id ) );
				if ( !$note.length ) return '';

				var $clone = $note.clone();
				$clone.find( '.mw-cite-backlink' ).remove();

				return $clone.html() || '';
			}

			function positionTooltip( $trigger ) {
				if ( !$trigger || !$trigger.length ) return;

				var rect = $trigger[ 0 ].getBoundingClientRect();

				$tooltip.css( { top: -9999, left: -9999, right: '' } ).show();

				var tipW = $tooltip.outerWidth();
				var tipH = $tooltip.outerHeight();
				var scrollX = $W.scrollLeft();
				var scrollY = $W.scrollTop();
				var margin = 8;

				var top = rect.top + scrollY - tipH - margin;
				var below = false;

				if ( top < scrollY ) {
					top = rect.bottom + scrollY + margin;
					below = true;
				}

				var left = rect.left + scrollX + ( rect.width / 2 ) - ( tipW / 2 );
				var minLeft = scrollX + 4;
				var maxLeft = scrollX + $W.width() - tipW - 4;

				left = Math.max( minLeft, Math.min( maxLeft, left ) );

				$tooltip
					.toggleClass( 'wk-ref-tooltip--below', below )
					.css( { top: Math.round( top ), left: Math.round( left ) } );
			}

			function hideNow() {
				if ( !$tooltip ) return;

				$tooltip.hide().attr( 'aria-hidden', 'true' );
				$content.empty();
				currentTrigger = null;

				$W.off( 'scroll.refhover resize.refhover keydown.refhover' );
				$B.off( 'click.refhover' );
			}

			function showFor( $a ) {
				ensureTooltip();

				var html = getNoteHtmlFromLink( $a );
				if ( !html ) return;

				$content.html( html );
				$tooltip.attr( 'aria-hidden', 'false' ).show();
				positionTooltip( $a );

				currentTrigger = $a;

				$W.on( 'scroll.refhover resize.refhover', function () {
					if ( currentTrigger ) positionTooltip( currentTrigger );
				} ).on( 'keydown.refhover', function ( e ) {
					if ( e.key === 'Escape' || e.key === 'Esc' ) hideNow();
				} );

				$B.on( 'click.refhover', function () {
					hideNow();
				} );
			}

			function toggleFor( $a ) {
				if ( currentTrigger && currentTrigger[ 0 ] === $a[ 0 ] ) hideNow();
				else showFor( $a );
			}

			function bindOn( $root ) {
				var $ctx = $root && $root.jquery ? $root : $( $root || D );

				if ( $ctx.data( 'wk-ref-tooltip-delegated' ) === 1 ) return;
				$ctx.data( 'wk-ref-tooltip-delegated', 1 );

				$ctx.on( 'click.refhover', 'sup.reference[id^="cite_ref"] > a, a[href^="#cite_note-"]', function ( e ) {
					e.preventDefault();
					e.stopPropagation();
					e.stopImmediatePropagation();
					toggleFor( $( this ) );
				} );

				$ctx.on( 'keydown.refhover', 'sup.reference[id^="cite_ref"] > a, a[href^="#cite_note-"]', function ( e ) {
					if ( e.key === 'Enter' || e.key === ' ' || e.code === 'Space' ) {
						e.preventDefault();
						e.stopPropagation();
						e.stopImmediatePropagation();
						toggleFor( $( this ) );
					}
				} );
			}

			W.wkBindRefTooltipsOn = function ( root ) {
				bindOn( $( root || D ) );
			};

			bindOn( $D );

		} )( mediaWiki, jQuery );
	}

	/* ==========================================================
		Bouton “modifier-argument” — insertion centralisée
	   ========================================================== */

	function wkEnsureModifierArgumentButton( $argumentTitle ) {
		if ( !$argumentTitle || !$argumentTitle.length ) return;

		if ( $argumentTitle.find( '.modifier-argument' ).length ) return;

		$argumentTitle.append(
			'<span class="modifier-argument">' +
				'<a href="#" class="modifier-argument-lien" title="' + wkMsg( 'wk-edit-argument-title' ) + '">' +
					wkMsg( 'wk-edit' ) +
				'</a>' +
			'</span>'
		);
	}

	/* ---- Dropdown “modifier argument” ---- */
	function wkInitArgumentDropdown() {
		if ( !wkIsNs( 0 ) ) return;

		$( document ).on( 'click.wkDropAddBtn', '.ns-0 div.argument-title:not(.is-expanded)', function () {
			wkEnsureModifierArgumentButton( $( this ) );
		} );

		if ( !wkOnce( 'wkArgumentDropdownInit' ) ) return;

		$D.on( 'click.wkDropToggle', '.ns-0 a.modifier-argument-lien', function ( e ) {
			e.preventDefault();

			wkWarmI18nCaches();

			var $argumentTitle = $( this ).closest( '.argument-title' );
			if ( !$argumentTitle.length ) return;

			var $a = $argumentTitle.find( 'a' ).first();
			var hrefArg = $a.attr( 'href' ) || '';
			var identifiant = wkGetWikiTitleFromHrefRaw( hrefArg );
			if ( !identifiant ) return;

			var $modifierArgument = $argumentTitle.find( '.modifier-argument' );
			var $dropdown = $argumentTitle.find( '.modifier-dropdown' );
			if ( $dropdown.length ) {
				$dropdown.toggle();
				return;
			}

			var $menu = $( '<div class="modifier-dropdown"></div>' )
				.attr( 'data-parent', $argumentTitle.attr( 'id' ) || '' );
			$modifierArgument.append( $menu );

			var lienModifierTitre = '#';
			var ancestor = $argumentTitle.closest( '.NavFramex' );

			if ( ancestor.length ) {
				var navHead = ancestor.find( '.NavHead' ).first();
				if ( navHead.length ) {
					var modifierSection = navHead.find( '.modifier-section' ).first();
					if ( modifierSection.length ) {
						var lienHref = modifierSection.find( 'a' ).attr( 'href' );
						if ( lienHref ) lienModifierTitre = lienHref;
					}
				}
			} else {
				var ulListe = $argumentTitle.closest( 'ul.argument-list' );
				var precedent = ulListe.prev();
				while ( precedent.length && precedent.prop( 'tagName' ) !== 'H2' ) {
					precedent = precedent.prev();
				}

				if ( precedent.length ) {
					var modifierSectionLink = precedent.find( '.modifier-section a' ).first();
					if ( modifierSectionLink.length ) {
						lienModifierTitre = modifierSectionLink.attr( 'href' );
					}
				}
			}

			var $lienTitre = $( '<span><a></a></span>' );
			var $iconeTitre = $( '<img>' )
				.attr( 'src', '/w/images/fr/b/ba/Modifier.svg' )
				.attr( 'alt', '' )
				.attr( 'class', 'picto-dropdown' );

			var $wrapTitre = $( '<span class="picto-dropdown-wrap"></span>' )
				.append( $iconeTitre );

			$lienTitre.find( 'a' )
				.attr( 'href', lienModifierTitre )
				.attr( 'target', '_self' )
				.append( $wrapTitre )
				.append( wkMsg( 'wk-dropdown-edit-display-title' ) );

			$menu.append( $lienTitre );

			var formulaireTexte = [
				{
					formulaire: WK_F.summary,
					texte: wkMsg( 'wk-dropdown-edit-summary' ),
					icone: '/w/images/fr/c/c6/Contributions.svg'
				},
				{
					formulaire: WK_F.citations,
					texte: wkMsg( 'wk-dropdown-edit-citations' ),
					icone: '/w/images/fr/6/6e/Citation.svg'
				},
				{
					formulaire: WK_F.references,
					texte: wkMsg( 'wk-dropdown-edit-references' ),
					icone: '/w/images/fr/9/9e/Bibliographie.svg'
				}
			];

			$.each( formulaireTexte, function ( index, item ) {
				var $lien = $( '<span><a></a></span>' );
				var $icone = $( '<img>' )
					.attr( 'src', item.icone )
					.attr( 'class', 'picto-dropdown' )
					.attr( 'alt', '' );

				var $wrap = $( '<span class="picto-dropdown-wrap"></span>' )
					.append( $icone );

				$lien.find( 'a' )
					.attr( 'href', '/wiki/Special:AddData/' + item.formulaire + '/' + identifiant )
					.attr( 'target', '_self' )
					.append( $wrap )
					.append( item.texte );

				$menu.append( $lien );
			} );

			var $lienExterne = $( '<span class="onglet-externe"><a></a></span>' );
			var $iconeExterne = $( '<img>' )
				.attr( 'src', '/w/images/fr/7/74/Loupe-noire.svg' )
				.attr( 'alt', '' )
				.attr( 'class', 'picto-dropdown' );

			var $wrapExterne = $( '<span class="picto-dropdown-wrap"></span>' )
				.append( $iconeExterne );

			$lienExterne.find( 'a' )
				.attr( 'href', '/wiki/' + identifiant )
				.attr( 'target', '_self' )
				.append( $wrapExterne )
				.append( wkMsg( 'wk-dropdown-view-detail' ) );

			$menu.append( $lienExterne );

			$menu.show();
		} );

		$D.on( 'click.wkDropClose', '.ns-0', function ( e ) {
			if ( !$( e.target ).closest( '.modifier-dropdown, .modifier-argument' ).length ) {
				$( '.modifier-dropdown' ).hide();
			}
		} );
	}

	/* ---- NS-3100 scroll top ---- */

	function wkBindNs3100ScrollHandlers() {
		if ( !wkOnce( 'wkNs3100ScrollInit' ) ) return;

		$D.on( 'click.wkEvalTop', '.ns-3100 .bouton-argument-suivant', function () {
			$( 'html, body' ).animate( { scrollTop: 0 }, 'slow' );
		} );

		$D.on( 'click.wkAutoEvalTop', '.ns-3100 .remonter-autoevaluation, .ns-3100 .titre-ariane', function ( event ) {
			event.preventDefault();
			$( '.colonnes' ).removeClass( 'inline' );
			$( 'html, body' ).animate( { scrollTop: 0 }, 'slow' );
			closeArgument( 2 );
		} );
	}

	/* ---- Fil d’Ariane extras ---- */

	function wkBindBreadcrumbExtras() {
		if ( !wkOnce( 'wkBreadcrumbExtrasInit' ) ) return;

		( function ( mwLocal, $ ) {

			$D.on( 'click.wkBackToTop', '.remonter-fil, .remonter-carte, .remonter-haut, .titre-ariane', function ( e ) {
				e.preventDefault();

				// 1) Cacher / supprimer le fil d'Ariane
				var fil = D.getElementById( 'fil-ariane' );
				if ( fil && fil.parentNode ) {
					fil.parentNode.removeChild( fil );
				}

				// (optionnel) réafficher le header sticky Vector si tu l'avais masqué
				if ( typeof wkShowVectorStickyHeader === 'function' ) {
					wkShowVectorStickyHeader();
				}

				// 2) Fermer les arguments
				if ( typeof W.closeArgument === 'function' ) {
					W.closeArgument( 1 );
				}

				// 3) Remonter en haut
				$( 'html, body' ).stop( true ).animate( { scrollTop: 0 }, 120 );

			} );

		} )( mw, jQuery );
	}

	/* ==========================================================
		SCAN DOM + BOOT — pré-checks pour limiter les rescans
		(optim “safe”: getElementsByClassName quand possible)
	   ========================================================== */

	function wkHasClassIn( el, cls ) {
		try {
			return !!( el && el.getElementsByClassName && el.getElementsByClassName( cls ).length );
		} catch ( e ) {}
		return false;
	}

	function wkOnContent( root ) {
		var el = wkRootNode( root );
		if ( !el ) return;

		var $root = root && root.jquery ? root : $( el );

		/* Collapsibles */
		if ( wkHasClassIn( el, 'fr-collapsible' ) ) bindFrCollapsible( $root );

		/* Tooltips à retirer */
		if ( el.querySelector && el.querySelector( '.masquer-infobulle a[title]' ) ) wkRemoveSomeTooltipsOn( el );

		/* Tooltips AddData + renommer */
		if ( ( el.querySelector && el.querySelector( 'span.wk-adddata-link[data-wk-tooltip]' ) ) || D.querySelector( '#bouton-renommer a' ) ) {
			wkFixAddDataAndRenameTooltipsOn( el );
		}

		/* Ref tooltips */
		if ( typeof W.wkBindRefTooltipsOn === 'function' && ( ( el.querySelector && el.querySelector( 'sup.reference > a, a[href^="#cite_note-"]' ) ) || el === D ) ) {
			W.wkBindRefTooltipsOn( el );
		}

		/* NS0 + NS3100 view : arguments */
		if ( wkIsView() && ( wkIsNs( 0 ) || wkIsNs( 3100 ) ) ) {
			if ( el.querySelector && el.querySelector( '.argument-title' ) ) {
				wkLazyBindForArgumentsView( el );
			}

			/* Déplacements boutons : NS0 uniquement */
			if ( wkIsNs( 0 ) ) {
				wkIdle( function () {
					wkInitHeaderButtons();
				} );
			}
		}

		/* PF autogrow */
		if ( el.querySelector && ( el.querySelector( '#pfForm textarea.autoGrow' ) || el.querySelector( '#pfForm' ) ) ) {
			wkAutoGrowSchedule( el );
		}
	}

	/* ==========================================================
		Boot global — regroupement safe
		(“safe”: certaines init en idle)
	   ========================================================== */

	function wkBindGlobalDelegations() {
		wkRemoveSomeTooltips();
		wkRefTooltips();

		moreContentCall();
		latestChangesCall();
		hoverContentCall();

		wkBindBreadcrumbHandlers();
		wkBindTocRemoveBreadcrumb();

		wkInitArgumentDropdown();
		wkBindNs3100ScrollHandlers();
		wkBindBreadcrumbExtras();

		$D.on( 'click.wkReadingClose', '#' + WK_READING_UI.closeId, function ( e ) {
			e.preventDefault();
			wkCloseReadingMode();
		} );
	}

	function wkGlobalBindAll() {
		/* i18n warm-up immédiat (safe) */
		wkWarmI18nCaches();

		/* Les trucs “non-urgents” en idle */
		wkIdle( function () {
			wkFixTitleSpace();
			wkBindAutoGrow();
			wkReinitSMWTooltips();
		} );

		wkInitEditSummaries();
		wkHideTitlebarOnAutoEval();

		wkBindGlobalDelegations();
	}

	function boot() {
		if ( !wkOnce( 'wkBooted' ) ) return;

		wkLoadI18n().catch( function () {} ).finally( function () {
			wkGlobalBindAll();
			wkOnContent( D );
		} );
	}

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

	mw.hook( 'wikipage.content' ).add( function ( $content ) {
		wkOnContent( $content && $content[ 0 ] ? $content[ 0 ] : D );
	} );

	/* ==========================================================
		Expose (si besoin ailleurs)
	   ========================================================== */

	W.wkLoadI18n = wkLoadI18n;
	W.wkMsg = wkMsg;
	W.wkMsgD = wkMsgD;
	W.wkTpl = wkTpl;
	W.wkParam = wkParam;
	W.wkForm = wkForm;

	W.wkParamFast = wkParamFast;
	W.wkTplFast = wkTplFast;
	W.wkFormFast = wkFormFast;

	W.wkGetApi = wkGetApi;
	W.wkParseWikitext = wkParseWikitext;
	W.wkParseCancel = wkParseCancel;

	W.loadContentFromTitle = loadContentFromTitle;
	W.closeArgument = closeArgument;

	W.breadcrumbMenu = breadcrumbMenu;
	W.breadcrumbGeneration = W.breadcrumbGeneration;

	// --- Mode lecture (exposé) ---
	W.WK_READING = WK_READING;
	W.wkOpenReadingModeFromTitleEl = wkOpenReadingModeFromTitleEl;
	W.wkOpenReadingModeFromPageTitle = wkOpenReadingModeFromPageTitle;
	W.wkCloseReadingMode = wkCloseReadingMode;

}() );

mw.hook( 'wikipage.content' ).add( function ( $content ) {
		if ( typeof wkIsNs === 'function' && !wkIsNs( 0 ) ) return;

		$content.on( 'click', 'a.wk-js-nav', function ( e ) {
				e.preventDefault();

				var url = this.getAttribute( 'data-href' );
				if ( !url ) return;

				window.location.assign( url );
		} );
} );

(function () {
		'use strict';

		if ( typeof wkIsNs === 'function' && !wkIsNs( 0 ) ) return;
		if ( !document.querySelector( '.wk-auto-id' ) ) return;

		function pad2(n) { return (n < 10 ? "0" : "") + n; }

		function makeId() {
				const d = new Date();
				return (
						d.getFullYear().toString() +
						pad2(d.getMonth() + 1) +
						pad2(d.getDate()) +
						pad2(d.getHours()) +
						pad2(d.getMinutes()) +
						pad2(d.getSeconds())
				);
		}

		function hasPlaceholder(href) {
				return href && (href.indexOf("(ID)") !== -1 || href.indexOf("%28ID%29") !== -1);
		}

		function replacePlaceholder(href, id) {
				// (ID) non encodé
				href = href.replace("(ID)", "(" + id + ")");
				// (ID) encodé : %28ID%29
				href = href.replace("%28ID%29", "%28" + id + "%29");
				return href;
		}

		// Capture = on passe avant la navigation et avant d'autres handlers
		document.addEventListener("click", function (e) {
				const wrap = e.target.closest(".wk-auto-id");
				if (!wrap) return;

				// On prend le premier lien à l’intérieur du bouton
				const a = wrap.querySelector("a[href]");
				if (!a) return;

				// getAttribute peut contenir &amp; etc, a.href donne l'URL résolue
				const rawHref = a.getAttribute("href") || "";
				const resolvedHref = a.href || rawHref;

				const hrefToCheck = rawHref || resolvedHref;
				if (!hasPlaceholder(hrefToCheck)) return;

				e.preventDefault();
				e.stopPropagation();

				const id = makeId();

				// On remplace sur la version "raw" si possible, sinon sur la résolue
				const newHref = replacePlaceholder(rawHref || resolvedHref, id);

				// Mettre à jour le lien + naviguer (clic sur div ou sur lien : les 2 marchent)
				a.setAttribute("href", newHref);
				try { a.href = newHref; } catch (err) {}

				//	Respecter target=_blank et les gestes "nouvel onglet"
				const wantsNewTab =
								(a.target && a.target.toLowerCase() === "_blank") ||
								e.ctrlKey || e.metaKey || e.button === 1;

				if (wantsNewTab) {
								window.open(a.href, "_blank", "noopener");
				} else {
								window.location.href = a.href;
				}
		}, true);
})();