MediaWiki:Common.css: Difference between revisions
Appearance
Content deleted Content added
No edit summary |
No edit summary Tag: Reverted |
||
| Line 1: | Line 1: | ||
/* Any JavaScript here will be loaded for all users on every page load. */ |
|||
/* ================================================================= |
|||
/** |
|||
Common.css — Global styles for all skins |
|||
* Keep code in MediaWiki:Common.js to a minimum as it is unconditionally |
|||
Applies read-only mode, branding, navigation, and AI assistant. |
|||
* loaded for all users on every wiki page. If possible create a gadget that is |
|||
Logged-in overrides live in MediaWiki:Group-user.css |
|||
* enabled by default instead of adding it here (since gadgets are fully |
|||
MANAGED WHOLESALE: replace the entire page from the canonical file |
|||
* optimized ResourceLoader modules with possibility to add dependencies etc.) |
|||
(temp/design/common_css_clean.css) — no incremental block pastes. |
|||
* |
|||
Color/typography authority: SECTION 12 owns all heading, link, |
|||
* Since Common.js isn't a gadget, there is no place to declare its |
|||
footer, table and AI-panel colors; earlier sections are structure. |
|||
* dependencies, so we have to lazy load them with mw.loader.using on demand and |
|||
================================================================= */ |
|||
* then execute the rest in the callback. In most cases these dependencies will |
|||
* be loaded (or loading) already and the callback will not be delayed. In case a |
|||
* dependency hasn't arrived yet it'll make sure those are loaded before this. |
|||
*/ |
|||
/* global mw, $ */ |
|||
/* jshint strict:false, browser:true */ |
|||
mw.loader.using( [ 'mediawiki.util' ] ).done( function () { |
|||
/* ================================================================= |
|||
/* Begin of mw.loader.using callback */ |
|||
1. BASE MEDIAWIKI OVERRIDES (Fonts, Quotes, Math, References) |
|||
================================================================= */ |
|||
/** |
|||
cite, dfn { font-style: inherit; } |
|||
* Map addPortletLink to mw.util |
|||
q { quotes: '"' '"' "'" "'"; } |
|||
* @deprecated: Use mw.util.addPortletLink instead. |
|||
*/ |
|||
mw.log.deprecate( window, 'addPortletLink', mw.util.addPortletLink, 'Use mw.util.addPortletLink instead' ); |
|||
/** |
|||
blockquote { |
|||
* @source https://www.mediawiki.org/wiki/Snippets/Load_JS_and_CSS_by_URL |
|||
overflow: hidden; |
|||
* @rev 6 |
|||
margin: 1em 0; |
|||
*/ |
|||
padding: 0 40px; |
|||
var extraCSS = mw.util.getParamValue( 'withCSS' ), |
|||
} |
|||
extraJS = mw.util.getParamValue( 'withJS' ); |
|||
if ( extraCSS ) { |
|||
small { font-size: 85%; } |
|||
if ( extraCSS.match( /^MediaWiki:[^&<>=%#]*\.css$/ ) ) { |
|||
.mw-body-content sub, .mw-body-content sup { font-size: 80%; } |
|||
mw.loader.load( '/w/index.php?title=' + extraCSS + '&action=raw&ctype=text/css', 'text/css' ); |
|||
.ns-talk .mw-body-content dd { margin-top: 0.4em; margin-bottom: 0.4em; } |
|||
} else { |
|||
mw.notify( 'Only pages from the MediaWiki namespace are allowed.', { title: 'Invalid withCSS value' } ); |
|||
} |
|||
} |
|||
if ( extraJS ) { |
|||
/* --- Collapsible elements --- */ |
|||
if ( extraJS.match( /^MediaWiki:[^&<>=%#]*\.js$/ ) ) { |
|||
.client-js .collapsible:not(.mw-made-collapsible).collapsed > tbody > tr:not(:first-child), |
|||
mw.loader.load( '/w/index.php?title=' + extraJS + '&action=raw&ctype=text/javascript' ); |
|||
.client-js .outercollapse .innercollapse.mw-collapsible:not(.mw-made-collapsible) > p, |
|||
} else { |
|||
.client-js .outercollapse .innercollapse.mw-collapsible:not(.mw-made-collapsible) > table, |
|||
mw.notify( 'Only pages from the MediaWiki namespace are allowed.', { title: 'Invalid withJS value' } ); |
|||
.client-js .outercollapse .innercollapse.mw-collapsible:not(.mw-made-collapsible) > thead + tbody, |
|||
} |
|||
.client-js .outercollapse .innercollapse.mw-collapsible:not(.mw-made-collapsible) tr:not(:first-child), |
|||
} |
|||
.client-js .outercollapse .innercollapse.mw-collapsible:not(.mw-made-collapsible) .mw-collapsible-content, |
|||
#editpage-specialchars { |
|||
display: none; |
|||
} |
|||
/** |
|||
.references { margin-bottom: 0.5em; } |
|||
* Collapsible tables; reimplemented with mw-collapsible |
|||
* Styling is also in place to avoid FOUC |
|||
* |
|||
* Allows tables to be collapsed, showing only the header. See [[Help:Collapsing]]. |
|||
* @version 3.0.0 (2018-05-20) |
|||
* @source https://www.mediawiki.org/wiki/MediaWiki:Gadget-collapsibleTables.js |
|||
* @author [[User:R. Koot]] |
|||
* @author [[User:Krinkle]] |
|||
* @author [[User:TheDJ]] |
|||
* @deprecated Since MediaWiki 1.20: Use class="mw-collapsible" instead which |
|||
* is supported in MediaWiki core. Shimmable since MediaWiki 1.32 |
|||
* |
|||
* @param {jQuery} $content |
|||
*/ |
|||
function makeCollapsibleMwCollapsible( $content ) { |
|||
var $tables = $content |
|||
.find( 'table.collapsible:not(.mw-collapsible)' ) |
|||
.addClass( 'mw-collapsible' ); |
|||
$.each( $tables, function ( index, table ) { |
|||
/* --- Cite link styling --- */ |
|||
// mw.log.warn( 'This page is using the deprecated class collapsible. Please replace it with mw-collapsible.'); |
|||
span[rel="mw:referencedBy"] { counter-reset: mw-ref-linkback 0; } |
|||
if ( $( table ).hasClass( 'collapsed' ) ) { |
|||
span[rel="mw:referencedBy"] > a::before { |
|||
$( table ).addClass( 'mw-collapsed' ); |
|||
content: counter(mw-ref-linkback, lower-alpha); |
|||
// mw.log.warn( 'This page is using the deprecated class collapsed. Please replace it with mw-collapsed.'); |
|||
font-size: 80%; font-weight: bold; font-style: italic; |
|||
} |
} |
||
} ); |
|||
a[rel="mw:referencedBy"]::before { font-weight: bold; content: "^"; } |
|||
if ( $tables.length > 0 ) { |
|||
span[rel="mw:referencedBy"]::before { content: "^ "; } |
|||
mw.loader.using( 'jquery.makeCollapsible' ).then( function () { |
|||
$tables.makeCollapsible(); |
|||
} ); |
|||
} |
|||
} |
|||
mw.hook( 'wikipage.content' ).add( makeCollapsibleMwCollapsible ); |
|||
/** |
|||
.mw-parser-output .mw-collapsible-toggle:not(.mw-ui-button) { |
|||
* Add support to mw-collapsible for autocollapse, innercollapse and outercollapse |
|||
font-weight: normal; padding-right: 0.2em; padding-left: 0.2em; |
|||
* |
|||
} |
|||
* Maintainers: TheDJ |
|||
.mw-collapsible-leftside-toggle .mw-collapsible-toggle { float: left; } |
|||
*/ |
|||
function mwCollapsibleSetup( $collapsibleContent ) { |
|||
var $element, |
|||
$toggle, |
|||
autoCollapseThreshold = 2; |
|||
$.each( $collapsibleContent, function ( index, element ) { |
|||
$element = $( element ); |
|||
if ( $element.hasClass( 'collapsible' ) ) { |
|||
$element.find( 'tr:first > th:first' ).prepend( $element.find( 'tr:first > * > .mw-collapsible-toggle' ) ); |
|||
} |
|||
if ( $collapsibleContent.length >= autoCollapseThreshold && $element.hasClass( 'autocollapse' ) ) { |
|||
$element.data( 'mw-collapsible' ).collapse(); |
|||
} else if ( $element.hasClass( 'innercollapse' ) ) { |
|||
if ( $element.parents( '.outercollapse' ).length > 0 ) { |
|||
$element.data( 'mw-collapsible' ).collapse(); |
|||
} |
|||
} |
|||
// because of colored backgrounds, style the link in the text color |
|||
// to ensure accessible contrast |
|||
$toggle = $element.find( '.mw-collapsible-toggle' ); |
|||
if ( $toggle.length ) { |
|||
// Make the toggle inherit text color (Updated for T333357 2023-04-29) |
|||
if ( $toggle.parent()[ 0 ].style.color ) { |
|||
$toggle.css( 'color', 'inherit' ); |
|||
$toggle.find( '.mw-collapsible-text' ).css( 'color', 'inherit' ); |
|||
} |
|||
} |
|||
} ); |
|||
} |
|||
mw.hook( 'wikipage.collapsibleContent' ).add( mwCollapsibleSetup ); |
|||
/* --- PDF icons --- */ |
|||
.mw-parser-output a[href$=".pdf"].external, |
|||
.mw-parser-output a[href*=".pdf?"].external, |
|||
.mw-parser-output a[href*=".pdf#"].external, |
|||
.mw-parser-output a[href$=".PDF"].external, |
|||
.mw-parser-output a[href*=".PDF?"].external, |
|||
.mw-parser-output a[href*=".PDF#"].external { |
|||
background: url("//upload.wikimedia.org/wikipedia/commons/4/4d/Icon_pdf_file.png") no-repeat right; |
|||
padding: 8px 18px 8px 0; |
|||
} |
|||
/* End of mw.loader.using callback */ |
|||
/* --- Warnings and notices --- */ |
|||
} ); |
|||
.mw-warning-with-logexcerpt.mw-warning-with-logexcerpt.mw-warning-with-logexcerpt, |
|||
div.mw-lag-warn-high, div.mw-cascadeprotectedwarning, div#mw-protect-cascadeon { |
|||
clear: both; margin: 0.2em 0; border: 1px solid #bb7070; |
|||
background-color: var(--background-color-error-subtle, #ffdbdb); |
|||
padding: 0.25em 0.9em; box-sizing: border-box; |
|||
} |
|||
.mw-contributions-blocked-notice-partial .mw-warning-with-logexcerpt.mw-warning-with-logexcerpt { |
|||
border-color: #fc3; background-color: var(--background-color-warning-subtle, #fef6e7); |
|||
} |
|||
// CapSach — Sticky TOC overlay (UNRESTRICTED: Works on iPad/Desktop/Mobile) |
|||
@media (min-width: 640px) { |
|||
(function () { |
|||
figure[typeof~="mw:File/Thumb"], figure[typeof~="mw:File/Frame"], .thumbinner { min-width: 100px; } |
|||
} |
|||
// 1. REMOVED the "min-width: 768px" check. Now runs everywhere. |
|||
#mw-subcategories, #mw-pages, #mw-category-media, #filehistory, #wikiPreview, #wikiDiff { clear: both; } |
|||
// Only run on pages where it makes sense (Articles/MainPage) |
|||
/* --- Permission groups (hidden by default) --- */ |
|||
if (window.mw && mw.config && mw.config.get) { |
|||
.checkuser-show, .sysop-show, .abusefilter-show, .abusefilter-helper-show, |
|||
var isAllowed = mw.config.get('wgIsArticle') || mw.config.get('wgIsMainPage'); |
|||
.patroller-show, .templateeditor-show, .extendedmover-show, .extendedconfirmed-show, |
|||
if (!isAllowed) return; |
|||
.autoconfirmed-show, .user-show { display: none; } |
|||
} |
|||
// Find the content root; MobileFrontend restructures DOM, so be flexible |
|||
.ve-ui-mwNoticesPopupTool-item .editnotice-redlink, |
|||
var root = |
|||
.ve-ui-mwNoticesPopupTool-item .mbox-image, |
|||
document.querySelector('#mw-content-text .mw-parser-output') || |
|||
.ve-ui-mwNoticesPopupTool-item .mbox-imageright { display: none !important; } |
|||
document.querySelector('.mw-parser-output') || |
|||
document.getElementById('mw-content-text') || |
|||
document.querySelector('#content') || |
|||
document.body; |
|||
// Collect headings (H2–H6). Prefer spans with .mw-headline (stable anchor ids) |
|||
ul.permissions-errors { margin: 0; } |
|||
var items = []; |
|||
ul.permissions-errors > li { list-style: none; } |
|||
var headings = root.querySelectorAll('h2, h3, h4, h5, h6'); |
|||
headings.forEach(function (h) { |
|||
var level = parseInt(h.tagName.slice(1), 10); |
|||
if (level < 2 || level > 6) return; |
|||
var headline = h.querySelector('.mw-headline') || h; |
|||
var id = headline.id || h.id; |
|||
var text = (headline.textContent || h.textContent || '').trim(); |
|||
if (!id || !text) return; |
|||
items.push({ id: id, text: text, level: level }); |
|||
}); |
|||
// Show only if there are enough headings to be useful |
|||
/* --- Math rendering --- */ |
|||
// CHANGED: Lowered requirement to 1 heading so it always shows if there is any structure |
|||
span.mwe-math-mathml-inline { font-size: 118%; } |
|||
if (items.length < 1) return; |
|||
.mwe-math-fallback-image-display, .mwe-math-mathml-display { |
|||
margin-left: 1.6em !important; margin-top: 0.6em; margin-bottom: 0.6em; |
|||
} |
|||
.mwe-math-mathml-display math { display: inline; } |
|||
// Create trigger button (bottom-left; avoids “Back to top” on bottom-right) |
|||
@media screen { |
|||
var btn = document.createElement('button'); |
|||
body:not(.ns-0):not(.ns-2):not(.ns-100) .gallerybox .thumb img { |
|||
btn.id = 'cps-open-toc'; |
|||
background: #fff url(//upload.wikimedia.org/wikipedia/commons/5/5d/Checker-16x16.png) repeat; |
|||
btn.type = 'button'; |
|||
} |
|||
btn.setAttribute('aria-label', 'Open table of contents'); |
|||
#siteSub { display: block; } |
|||
btn.innerHTML = '<span class="icon" aria-hidden="true">≡</span><span class="label">TOC</span>'; |
|||
.references { font-size: 90%; } |
|||
document.body.appendChild(btn); |
|||
} |
|||
// Overlay + panel |
|||
.flaggedrevs_draft_synced, .flaggedrevs_stable_synced, #t-upload, |
|||
var overlay = document.createElement('div'); |
|||
.mw-special-Book #coll-downloadbox { display: none; } |
|||
overlay.id = 'cps-toc-overlay'; |
|||
overlay.setAttribute('aria-hidden', 'true'); |
|||
var panel = document.createElement('div'); |
|||
/* --- Infoboxes (structure only — width/border/background/font owned |
|||
panel.id = 'cps-toc-panel'; |
|||
by section 12) --- */ |
|||
panel.setAttribute('role', 'dialog'); |
|||
.infobox { |
|||
panel.setAttribute('aria-modal', 'true'); |
|||
color: black; padding: 0.2em; |
|||
panel.setAttribute('aria-label', 'Table of contents'); |
|||
line-height: 1.5em; border-spacing: 3px; |
|||
} |
|||
@media (max-width: 640px) { .infobox .nowrap { white-space: normal; } } |
|||
@media (min-width: 640px) { |
|||
.infobox { margin: 0.5em 0 0.5em 1em; float: right; clear: right; } |
|||
} |
|||
.infobox-header, .infobox-label, .infobox-above, .infobox-full-data, .infobox-data, |
|||
.infobox-below, .infobox-subheader, .infobox-image, .infobox-navbar, |
|||
.infobox th, .infobox td { vertical-align: top; } |
|||
.infobox-label, .infobox-data, .infobox th, .infobox td { text-align: left; } |
|||
.infobox .infobox-above, .infobox .infobox-title, .infobox caption { |
|||
font-size: 125%; font-weight: bold; text-align: center; padding: 0.2em; |
|||
} |
|||
.infobox .infobox-header, .infobox .infobox-subheader, .infobox .infobox-image, |
|||
.infobox .infobox-full-data, .infobox .infobox-below { text-align: center; } |
|||
.infobox .infobox-navbar { text-align: right; } |
|||
var header = document.createElement('div'); |
|||
/* --- Text utilities --- */ |
|||
header.id = 'cps-toc-header'; |
|||
.nounderlines a, .IPA a:link, .IPA a:visited { text-decoration: none !important; } |
|||
header.innerHTML = |
|||
.nowrap, .nowraplinks a { white-space: nowrap; } |
|||
'<h2 id="cps-toc-title">Contents</h2>' + |
|||
.wrap, .wraplinks a { white-space: normal; } |
|||
'<button id="cps-toc-close" type="button" aria-label="Close">×</button>'; |
|||
var list = document.createElement('ul'); |
|||
span.texhtml { |
|||
list.id = 'cps-toc-list'; |
|||
font-family: "Nimbus Roman No9 L", "Times New Roman", Times, serif; |
|||
font-size: 118%; line-height: 1; |
|||
font-variant-numeric: lining-nums tabular-nums; font-kerning: none; |
|||
} |
|||
span.texhtml span.texhtml { font-size: 100%; } |
|||
@media (min-width: 640px) { span.texhtml { white-space: nowrap; } } |
|||
@media (max-width: 640px) { |
|||
.flagicon a > img, .flagicon noscript > img { max-width: none !important; } |
|||
} |
|||
@media screen { .nochecker .gallerybox .thumb img { background-image: none; } } |
|||
items.forEach(function (it) { |
|||
/* --- YouTube embeds --- */ |
|||
var li = document.createElement('li'); |
|||
.mw-parser-output iframe[src*="youtube.com"], |
|||
li.setAttribute('data-level', String(it.level)); |
|||
.mw-parser-output iframe[src*="youtube-nocookie.com"] { |
|||
var a = document.createElement('a'); |
|||
width: 100% !important; max-width: 320px; height: auto !important; |
|||
a.href = '#' + it.id; |
|||
aspect-ratio: 16 / 9; display: block; margin: 0 auto; |
|||
a.textContent = it.text; |
|||
} |
|||
li.appendChild(a); |
|||
list.appendChild(li); |
|||
}); |
|||
panel.appendChild(header); |
|||
panel.appendChild(list); |
|||
overlay.appendChild(panel); |
|||
document.body.appendChild(overlay); |
|||
// Focus handling |
|||
/* ================================================================= |
|||
var lastFocus = null; |
|||
2. LAYOUT & SPACING |
|||
function openOverlay() { |
|||
================================================================= */ |
|||
lastFocus = document.activeElement; |
|||
overlay.classList.add('is-open'); |
|||
overlay.setAttribute('aria-hidden', 'false'); |
|||
document.body.style.overflow = 'hidden'; |
|||
// Focus first link for accessibility |
|||
var firstLink = list.querySelector('a'); |
|||
if (firstLink) firstLink.focus({ preventScroll: true }); |
|||
} |
|||
function closeOverlay() { |
|||
overlay.classList.remove('is-open'); |
|||
overlay.setAttribute('aria-hidden', 'true'); |
|||
document.body.style.overflow = ''; |
|||
if (lastFocus && lastFocus.focus) lastFocus.focus({ preventScroll: true }); |
|||
} |
|||
// Force button display immediately |
|||
/* --- Content width & readability --- */ |
|||
btn.style.display = 'flex'; |
|||
#content { |
|||
btn.addEventListener('click', openOverlay); |
|||
max-width: 900px; |
|||
margin: 0 auto; |
|||
line-height: 1.6; |
|||
} |
|||
overlay.addEventListener('click', function (e) { |
|||
/* --- Header reset (invisible fixed container for floating buttons) --- */ |
|||
// Click outside the bottom sheet closes |
|||
.header-container.header-chrome { |
|||
if (e.target === overlay) closeOverlay(); |
|||
position: fixed !important; |
|||
}); |
|||
top: 0 !important; left: 0 !important; right: 0 !important; |
|||
overlay.querySelector('#cps-toc-close').addEventListener('click', closeOverlay); |
|||
height: 60px !important; |
|||
z-index: 1000 !important; |
|||
pointer-events: none !important; |
|||
background: transparent !important; |
|||
border: none !important; |
|||
box-shadow: none !important; |
|||
} |
|||
.minerva-header { |
|||
background: transparent !important; |
|||
border: none !important; |
|||
box-shadow: none !important; |
|||
} |
|||
overlay.addEventListener('keydown', function (e) { |
|||
.header-container .navigation-drawer { display: none !important; } |
|||
if (e.key === 'Escape') closeOverlay(); |
|||
}); |
|||
// Navigate and try to ensure mobile-collapsed sections are visible |
|||
/* --- Top margin resets (remove white gap) --- */ |
|||
// Navigate and try to ensure mobile-collapsed sections are visible |
|||
body.skin-minerva { padding-top: 0 !important; } |
|||
list.addEventListener('click', function (e) { |
|||
var a = e.target.closest('a'); |
|||
if (!a) return; |
|||
e.preventDefault(); |
|||
var targetId = a.getAttribute('href').slice(1); |
|||
#content, |
|||
#content.mw-body, |
|||
.mw-body { |
|||
margin-top: 0 !important; |
|||
padding-top: 0 !important; |
|||
} |
|||
// === NEW LOGIC START: Scroll to Top for "Contents" === |
|||
.banner-container, |
|||
// If the user clicks the "Contents" header (id="mw-toc-heading"), scroll to top (0,0) |
|||
#siteNotice { |
|||
// === FIXED CODE === |
|||
padding: 0 !important; |
|||
if (targetId === 'mw-toc-heading') { |
|||
margin: 0 !important; |
|||
closeOverlay(); |
|||
// Delay scroll to let iOS Safari process the overflow change |
|||
setTimeout(function() { |
|||
try { |
|||
window.scrollTo({ top: 0, behavior: 'smooth' }); |
|||
} catch (e) { |
|||
window.scrollTo(0, 0); |
|||
} |
|||
// Fallback for older iOS Safari |
|||
document.documentElement.scrollTop = 0; |
|||
document.body.scrollTop = 0; |
|||
}, 100); |
|||
if (history.replaceState) { |
|||
history.replaceState(null, '', window.location.pathname + window.location.search); |
|||
} |
|||
return; |
|||
} |
} |
||
// === NEW LOGIC END === |
|||
var target = document.getElementById(targetId); |
|||
.pre-content, |
|||
closeOverlay(); |
|||
.page-heading, |
|||
.firstHeading { |
|||
margin-top: 0 !important; |
|||
padding-top: 0 !important; |
|||
} |
|||
if (target) { |
|||
/* Push title down so it clears the invisible header */ |
|||
try { |
|||
.pre-content.heading-holder { |
|||
target.scrollIntoView({ behavior: 'smooth', block: 'start' }); |
|||
padding-top: 70px !important; /* 60px header + 10px visual space */ |
|||
} catch (_) { |
|||
display: block !important; |
|||
target.scrollIntoView(true); |
|||
} |
|||
} |
|||
// Update URL hash after a tick (so browser back works) |
|||
@media (prefers-reduced-motion: reduce) { |
|||
setTimeout(function () { |
|||
if (history && history.replaceState) { |
|||
} |
|||
history.replaceState(null, '', '#' + targetId); |
|||
} else { |
|||
location.hash = targetId; |
|||
} |
|||
}, 200); |
|||
// MobileFrontend: headings may be inside collapsed sections. |
|||
// Heuristic: click the nearest toggle if present. |
|||
var maybeToggle = target.closest('.collapsible-block, .mf-section') || |
|||
target.closest('section'); |
|||
if (maybeToggle && maybeToggle.classList.contains('collapsed')) { |
|||
// Try to open; fallback by clicking the first heading inside |
|||
var headingToggle = maybeToggle.querySelector('.section-heading, h2, h3, h4, h5, h6'); |
|||
if (headingToggle) headingToggle.click(); |
|||
} |
|||
} |
|||
}); |
|||
// 2. REMOVED the "resize" event listener that was hiding the button. |
|||
/* ================================================================= |
|||
// The button now persists on all screen sizes. |
|||
3. BRANDING (Logo, Tagline — Desktop Header & Mobile Footer) |
|||
})(); |
|||
================================================================= */ |
|||
/* Script for Inline Expandable Template */ |
|||
/* --- Desktop: hide logo wordmark, inject tagline --- */ |
|||
$(function() { |
|||
.mw-logo-container { display: none !important; } |
|||
$('.inline-expand-trigger').on('click', function() { |
|||
.mw-logo-wordmark { |
|||
// 1. Toggle the content visibility |
|||
display: none !important; |
|||
$(this).next('.inline-expand-content').toggle(); |
|||
visibility: hidden !important; |
|||
width: 0 !important; |
|||
} |
|||
// 2. Toggle the arrow icon |
|||
.mw-logo:hover, |
|||
const currentText = $(this).text(); |
|||
.mw-logo:active, |
|||
$(this).text( |
|||
.mw-logo:focus { text-decoration: none !important; } |
|||
currentText.includes('▸') ? currentText.replace('▸', '◂') : currentText.replace('◂', '▸') |
|||
); |
|||
}); |
|||
}); |
|||
$(document).ready(function() { |
|||
.mw-logo::after { |
|||
// Check if the button already exists to prevent duplicates |
|||
content: "Unleashing \A intelligence"; |
|||
if ($('#custom-email-btn').length === 0) { |
|||
font-size: 0.875em; |
|||
font-weight: 700; |
|||
line-height: 1.4; |
|||
color: #202122 !important; |
|||
text-decoration: none !important; |
|||
cursor: pointer; |
|||
display: block; |
|||
white-space: pre; |
|||
margin-left: 3px; |
|||
text-align: left; |
|||
position: relative; |
|||
top: 3px; |
|||
} |
|||
// Create the email button element |
|||
@media screen and (max-width: 900px) { |
|||
var emailBtn = $('<a>', { |
|||
.mw-logo::after { display: none !important; } |
|||
id: 'custom-email-btn', |
|||
} |
|||
href: 'mailto:bananabot@axabrain.com', |
|||
// Simple accessible title |
|||
title: 'Contact AXA BRAIN Services' |
|||
}); |
|||
// Add it to the body of the page |
|||
/* --- Mobile footer: logo image + tagline --- */ |
|||
$('body').append(emailBtn); |
|||
.minerva-footer-logo { |
|||
} |
|||
font-size: 0 !important; |
|||
}); |
|||
color: transparent !important; |
|||
display: block !important; |
|||
text-align: left !important; |
|||
margin-bottom: 20px !important; |
|||
} |
|||
/* Open AXA BRAIN AI Assistant when clicking the logo */ |
|||
.minerva-footer-logo::before { |
|||
$(document).ready(function() { |
|||
content: "" !important; |
|||
$('.fullscreen-logo').css('cursor', 'pointer').click(function(e) { |
|||
display: block !important; |
|||
e.preventDefault(); |
|||
background-image: url("https://pro-wiki.s3.eu-central-1.amazonaws.com/2776118/Logo.png"); |
|||
width: 160px; |
|||
height: 50px; |
|||
background-repeat: no-repeat !important; |
|||
background-size: contain !important; |
|||
background-position: left center !important; |
|||
margin-bottom: 6px !important; |
|||
} |
|||
// Method 1: Click the AI Assistant floating icon |
|||
.minerva-footer-logo::after { |
|||
var $aiButton = $('img[src*="ai-icon.png"]').closest('div, button, a'); |
|||
content: "Unleashing intelligence" !important; |
|||
if ($aiButton.length > 0) { |
|||
font-size: 0.875rem !important; |
|||
$aiButton.trigger('click'); |
|||
font-weight: 700 !important; |
|||
return; |
|||
} |
|||
color: #202122 !important; |
|||
display: block !important; |
|||
white-space: pre-wrap !important; |
|||
} |
|||
// Method 2: Try the extension's trigger class |
|||
/* Force hidden Minerva footer links to appear */ |
|||
var $trigger = $('.ext-aiassistant-trigger, .ext-aiassistant'); |
|||
body.skin-minerva #footer-places-about, |
|||
if ($trigger.length > 0) { |
|||
body.skin-minerva #footer-places-disclaimers { |
|||
$trigger.first().trigger('click'); |
|||
display: inline-block !important; |
|||
return; |
|||
} |
|||
} |
|||
console.log("AXA BRAIN Assistant button not found on this page."); |
|||
/* --- Fullscreen logo (fits content width) --- */ |
|||
}); |
|||
.fullscreen-logo { |
|||
}); |
|||
width: 100% !important; |
|||
padding: 0 !important; |
|||
margin: 0 auto !important; |
|||
max-width: 900px !important; |
|||
} |
|||
/* Inline footnotes ({{footnote}}). We render the note OURSELVES, appended to |
|||
.fullscreen-logo figure, |
|||
<body> (the ROOT stacking context), so a table's sticky column can never |
|||
.fullscreen-logo .mw-default-size, |
|||
cover it and it behaves identically across browsers. The native title="" |
|||
.fullscreen-logo .mw-halign-center { |
|||
tooltip is unreliable + unstyled, so we move it to data-fn (the bot still |
|||
max-width: 100% !important; |
|||
reads the hidden .ed-fn-body span) and show: |
|||
width: 100% !important; |
|||
- PHONE (no hover): tap a cue -> full-width banner at the top; tap to dismiss. |
|||
margin: 0 !important; |
|||
- DESKTOP (hover): hover a cue -> a small popover beside the cue. |
|||
padding: 0 !important; |
|||
If this script never runs, the title="" stays and the native tooltip is the |
|||
} |
|||
graceful fallback. */ |
|||
(function () { |
|||
var cues = document.querySelectorAll('.ed-fn'); |
|||
if (!cues.length) { return; } |
|||
// Suppress the native tooltip; keep the note text in data-fn. |
|||
.fullscreen-logo figure > span { |
|||
Array.prototype.forEach.call(cues, function (el) { |
|||
display: block !important; |
|||
if (el.hasAttribute('title')) { |
|||
width: 100% !important; |
|||
el.setAttribute('data-fn', el.getAttribute('title')); |
|||
} |
|||
el.removeAttribute('title'); |
|||
.fullscreen-logo img.mw-file-element { |
|||
display: block !important; |
|||
width: 100% !important; |
|||
max-width: 100% !important; |
|||
height: auto !important; |
|||
min-width: 0 !important; |
|||
} |
|||
/* ================================================================= |
|||
4. CAPSACH MOBILE TOC OVERLAY |
|||
================================================================= */ |
|||
/* --- Base state (JS toggles visibility) --- */ |
|||
#cps-open-toc { |
|||
position: fixed; |
|||
display: none; |
|||
} |
|||
/* --- Full-screen scrim --- */ |
|||
#cps-toc-overlay { |
|||
position: fixed; inset: 0; |
|||
background: rgba(0,0,0,0.4); |
|||
display: none; |
|||
z-index: 1004; |
|||
} |
|||
#cps-toc-overlay.is-open { display: block; } |
|||
/* --- Dropdown panel --- */ |
|||
#cps-toc-panel { |
|||
position: fixed; |
|||
top: 0 !important; |
|||
left: 0 !important; |
|||
right: 0 !important; |
|||
margin: 0 auto !important; |
|||
bottom: auto !important; |
|||
width: 100% !important; |
|||
max-width: 900px !important; |
|||
max-height: calc(100vh - 60px) !important; |
|||
border-radius: 0 !important; |
|||
background: #ffffff !important; |
|||
color: #202122 !important; |
|||
box-shadow: 0 10px 30px rgba(0,0,0,0.15) !important; |
|||
padding: 15px !important; |
|||
box-sizing: border-box !important; |
|||
overflow-y: auto !important; |
|||
-webkit-overflow-scrolling: touch; |
|||
z-index: 1005 !important; |
|||
display: none; |
|||
} |
|||
.is-open #cps-toc-panel, |
|||
#cps-toc-overlay.is-open + #cps-toc-panel, |
|||
#cps-toc-panel[style*="display: block"] { |
|||
display: block !important; |
|||
} |
|||
/* --- Panel header reset --- */ |
|||
#cps-toc-header { |
|||
background: transparent !important; |
|||
padding: 0 !important; |
|||
margin: 0 !important; |
|||
border: none !important; |
|||
min-height: 0 !important; |
|||
} |
|||
/* --- Title bar (grey block) --- */ |
|||
#cps-toc-panel > h2, |
|||
#cps-toc-title { |
|||
background-color: #F8F9FA !important; |
|||
margin: -15px -15px 15px !important; |
|||
padding: 20px 0 !important; |
|||
border-bottom: 1px solid #eaecf0 !important; |
|||
display: block !important; |
|||
width: auto !important; |
|||
text-align: center !important; |
|||
color: #202122 !important; |
|||
font-size: 18px !important; |
|||
font-family: sans-serif !important; |
|||
font-weight: bold !important; |
|||
} |
|||
/* Hide close button and duplicate headings */ |
|||
#cps-toc-close, |
|||
#cps-toc-panel .toctitle, |
|||
#cps-toc-panel #mw-toc-heading, |
|||
#cps-toc-panel h2 { |
|||
display: none !important; |
|||
} |
|||
/* --- TOC list --- */ |
|||
#cps-toc-list { list-style: none; margin: 0; padding: 0; } |
|||
#cps-toc-list li { margin: 0; } |
|||
#cps-toc-list a { |
|||
display: block; padding: 12px 10px; |
|||
border-bottom: 1px solid #f8f8f8; |
|||
text-decoration: none; |
|||
color: #202122; |
|||
font-size: 15px; |
|||
line-height: 1.4; |
|||
} |
|||
#cps-toc-list a:active { |
|||
background: #f0f0f0; |
|||
color: #3366cc; |
|||
} |
|||
/* Indentation levels */ |
|||
#cps-toc-list li[data-level="3"] { padding-left: 15px; } |
|||
#cps-toc-list li[data-level="4"] { padding-left: 30px; } |
|||
#cps-toc-list li[data-level="5"] { padding-left: 45px; } |
|||
/* "Contents" header link — bold, orange, dark border */ |
|||
#cps-toc-list a[href="#mw-toc-heading"] { |
|||
font-weight: bold !important; |
|||
color: #f07662 !important; |
|||
border-bottom: 1px solid #202122 !important; |
|||
} |
|||
/* Arrow prefix (▸) for level 2 and 3 items */ |
|||
#cps-toc-list li[data-level="2"] a::before, |
|||
#cps-toc-list li[data-level="3"] a::before { |
|||
content: "▸" !important; |
|||
color: #202122 !important; |
|||
margin-right: 8px; |
|||
display: inline-block; |
|||
} |
|||
/* Remove arrow from "Contents" header (technically level 2) */ |
|||
#cps-toc-list li[data-level="2"] a[href="#mw-toc-heading"]::before { |
|||
display: none !important; |
|||
content: "" !important; |
|||
} |
|||
/* Hide default in-article TOC */ |
|||
.toc, |
|||
#toc, |
|||
.mw-parser-output #toc, |
|||
.client-js .mw-content-ltr .toc { |
|||
display: none !important; |
|||
} |
|||
/* ================================================================= |
|||
5. FLOATING BOTTOM BUTTONS (Search, Home, ToC, Email) |
|||
================================================================= */ |
|||
/* --- Shared styles (all 4 buttons + search input) --- */ |
|||
.branding-box, |
|||
#searchIcon, |
|||
#cps-open-toc, |
|||
#custom-email-btn, |
|||
body.mw-mf-search-mode .minerva-header .search-box input { |
|||
background-color: rgba(0, 0, 0, 0.2) !important; |
|||
opacity: 1 !important; |
|||
border-radius: 50% !important; |
|||
border: none !important; |
|||
box-shadow: none !important; |
|||
backdrop-filter: none !important; |
|||
pointer-events: auto !important; |
|||
box-sizing: border-box !important; |
|||
width: 44px !important; |
|||
height: 44px !important; |
|||
min-width: 44px !important; |
|||
max-width: 44px !important; |
|||
padding: 0 !important; |
|||
margin: 0 !important; |
|||
position: fixed !important; |
|||
top: auto !important; |
|||
bottom: calc(15px + env(safe-area-inset-bottom)) !important; |
|||
transform: translateZ(0); |
|||
will-change: transform; |
|||
left: 50% !important; |
|||
right: auto !important; |
|||
display: flex !important; |
|||
align-items: center; |
|||
justify-content: center; |
|||
z-index: 1002 !important; |
|||
} |
|||
/* --- Individual positions --- */ |
|||
/* Search (far left, offset -150px) */ |
|||
#searchIcon { |
|||
margin-left: -150px !important; |
|||
z-index: 1003 !important; |
|||
} |
|||
#searchIcon .minerva-icon { |
|||
font-size: 24px !important; |
|||
color: #fff !important; |
|||
fill: #fff !important; |
|||
filter: brightness(0) invert(1); |
|||
} |
|||
/* Home (left of center, offset -86px) */ |
|||
.branding-box { |
|||
margin-left: -86px !important; |
|||
flex: 0 0 44px !important; |
|||
} |
|||
.branding-box::after { |
|||
content: "⌂"; |
|||
font-size: 30px !important; |
|||
color: #fff !important; |
|||
-webkit-text-stroke: 0.5px #fff !important; |
|||
margin-top: -6px !important; |
|||
line-height: 1 !important; |
|||
} |
|||
.branding-box a { opacity: 0 !important; position: absolute; inset: 0; } |
|||
/* ToC (center, offset -22px) */ |
|||
#cps-open-toc { margin-left: -22px !important; } |
|||
#cps-open-toc .icon { |
|||
font-size: 30px !important; |
|||
line-height: 1 !important; |
|||
margin-bottom: 3px !important; |
|||
color: #fff !important; |
|||
} |
|||
#cps-open-toc .label { display: none !important; } |
|||
/* Email (right of center, offset +42px) */ |
|||
#custom-email-btn { margin-left: 42px !important; } |
|||
#custom-email-btn::after { |
|||
content: "\2709\FE0E"; /* Text-mode envelope glyph */ |
|||
font-size: 26px !important; |
|||
line-height: 1 !important; |
|||
margin-top: -2px !important; |
|||
color: transparent !important; |
|||
text-shadow: 0 0 0 #fff !important; |
|||
} |
|||
/* --- Search input (expanded state) --- */ |
|||
body:not(.mw-mf-search-mode) .minerva-header .search-box { |
|||
display: none !important; |
|||
} |
|||
body.mw-mf-search-mode .minerva-header .search-box { |
|||
display: block !important; |
|||
position: fixed !important; |
|||
top: 8px !important; |
|||
height: 44px !important; |
|||
z-index: 1001 !important; |
|||
left: 10px !important; |
|||
right: 10px !important; |
|||
width: auto !important; |
|||
padding: 0 !important; margin: 0 !important; |
|||
background: transparent !important; |
|||
border-radius: 0 !important; |
|||
} |
|||
body.mw-mf-search-mode .minerva-header .search-box input { |
|||
width: 100% !important; |
|||
font-size: 16px !important; |
|||
color: #fff !important; |
|||
-webkit-text-fill-color: #fff !important; |
|||
padding-left: 55px !important; |
|||
padding-right: 55px !important; |
|||
position: static !important; |
|||
margin: 0 !important; |
|||
} |
|||
.minerva-header .search-box .search-box-icon-overlay { display: none !important; } |
|||
body.mw-mf-search-mode .minerva-header .search-box input::placeholder { |
|||
color: rgba(255, 255, 255, 0.7) !important; |
|||
-webkit-text-fill-color: rgba(255, 255, 255, 0.7) !important; |
|||
} |
|||
.search-box .search-box-cancel { |
|||
display: block !important; |
|||
position: absolute !important; |
|||
top: 0 !important; right: 0 !important; |
|||
width: 44px !important; height: 44px !important; |
|||
line-height: 44px !important; |
|||
text-align: center !important; |
|||
color: #fff !important; |
|||
z-index: 1004 !important; |
|||
} |
|||
/* ================================================================= |
|||
6. GLOBAL HIDE (Read-Only Mode) |
|||
Hidden for everyone; un-hidden in MediaWiki:Group-user.css |
|||
================================================================= */ |
|||
/* --- User links (includes Vector 2022 sticky header IDs) --- */ |
|||
#vector-user-links, |
|||
#p-personal, |
|||
#pt-login, |
|||
#pt-login-2, |
|||
#pt-createaccount, |
|||
#pt-createaccount-2, |
|||
#pt-userpage, |
|||
#pt-mytalk, |
|||
#pt-preferences, |
|||
#pt-watchlist, |
|||
#pt-mycontris, |
|||
#pt-logout { |
|||
display: none !important; |
|||
} |
|||
/* --- Tools (sidebar, dropdowns, tabs) --- */ |
|||
#p-tb, |
|||
#vector-page-tools, |
|||
#vector-page-tools-dropdown, |
|||
.vector-p-tb, |
|||
#ca-viewsource, |
|||
#ca-history, |
|||
#ca-talk { |
|||
display: none !important; |
|||
} |
|||
/* --- Categories --- */ |
|||
#catlinks, |
|||
.catlinks, |
|||
.mw-normal-catlinks { |
|||
display: none !important; |
|||
} |
|||
/* --- Page actions (Language, Watch, Edit, etc.) --- */ |
|||
#p-views, |
|||
.page-actions-menu__list, |
|||
.page-actions-menu { |
|||
display: none !important; |
|||
} |
|||
/* --- Vector 2022 page toolbar & pre-content --- */ |
|||
.vector-page-toolbar { display: none !important; } |
|||
.vector-body-before-content { display: none !important; } |
|||
/* --- Language selector & main menu --- */ |
|||
#p-vector-user-menu-preferences { display: none !important; } |
|||
.vector-main-menu-landmark { display: none !important; } |
|||
/* --- Mobile: history bar --- */ |
|||
.last-modified-bar, |
|||
a.last-modified-bar { |
|||
display: none !important; |
|||
visibility: hidden !important; |
|||
} |
|||
.last-modified-bar__text, |
|||
.modified-enhancement, |
|||
.minerva-icon--modified-history { |
|||
display: none !important; |
|||
} |
|||
/* --- Mobile: user/login menu --- */ |
|||
.minerva-user-menu { display: none !important; } |
|||
.toggle-list__toggle#minerva-user-menu-toggle { display: none !important; } |
|||
.minerva-icon--userAvatarOutline { display: none !important; } |
|||
/* --- Mobile: sidebar items --- */ |
|||
#mw-mf-page-left a[href*="Special:RecentChanges"], |
|||
#mw-mf-page-left a[data-event-name="recentchanges"], |
|||
#mw-mf-page-left a[href*="Special:SpecialPages"], |
|||
#mw-mf-page-left a[href*="Community_portal"] { |
|||
display: none !important; |
|||
} |
|||
/* ================================================================= |
|||
7. CHROME EXTRAS |
|||
(Heading, link, and footer COLORS are owned by section 12 — |
|||
this section keeps only structural chrome fixes.) |
|||
================================================================= */ |
|||
/* Remove Vector 2022 default title underline */ |
|||
.vector-page-titlebar::after { |
|||
background-color: transparent !important; |
|||
display: none !important; |
|||
height: 0 !important; |
|||
} |
|||
#footer-icons { display: none !important; } |
|||
.minerva-footer .footer-content, |
|||
.minerva-footer .branding-box, |
|||
.minerva-footer-logo, |
|||
#footer-info, |
|||
#footer-places { |
|||
border: none !important; |
|||
} |
|||
/* Mobile section expand icon */ |
|||
.skin-minerva .section-heading .mw-ui-icon-wikimedia-expand-small { |
|||
filter: grayscale(1) brightness(0.2); |
|||
} |
|||
/* --- Navigation menu paragraphs --- */ |
|||
.navigation-menu .infobox-data p { |
|||
font-size: 1em !important; |
|||
margin: 0 !important; |
|||
padding: 0 !important; |
|||
} |
|||
/* --- Main page menu --- */ |
|||
.main-page-menu { |
|||
line-height: 1.8; |
|||
margin-bottom: 0; |
|||
font-size: 1em; |
|||
} |
|||
/* --- Read pill (inline badge) --- */ |
|||
.read-pill { |
|||
display: inline; |
|||
white-space: nowrap; |
|||
padding: 1px 0.4em; |
|||
position: relative; |
|||
top: -1px; |
|||
border-radius: 4px; |
|||
margin: 0 0.2em 0 0; |
|||
font-size: 0.85em; |
|||
font-weight: 500; |
|||
color: #202122 !important; |
|||
-webkit-box-decoration-break: clone; |
|||
box-decoration-break: clone; |
|||
} |
|||
.read-pill a, |
|||
.read-pill a:visited { |
|||
color: #202122 !important; |
|||
text-decoration: none !important; |
|||
} |
|||
.read-pill a.new { |
|||
color: red !important; |
|||
padding: 0 4px; |
|||
border-radius: 3px; |
|||
} |
|||
/* ================================================================= |
|||
8. AI ASSISTANT PANEL — STRUCTURE |
|||
(Panel colors — borders, bubbles, send button, citations — are |
|||
owned by section 12's theme block.) |
|||
================================================================= */ |
|||
/* --- Z-index: sits behind floating buttons (z-index 1002) --- */ |
|||
.ext-aiassistant, |
|||
.ext-aiassistant-panel { |
|||
z-index: 1001 !important; |
|||
} |
|||
.ext-aiassistant-panel { box-shadow: none !important; } |
|||
/* --- Header --- */ |
|||
.ext-aiassistant-header { |
|||
margin-left: 0 !important; |
|||
margin-right: 0 !important; |
|||
padding-left: 12px !important; |
|||
padding-right: 12px !important; |
|||
} |
|||
/* --- Message area --- */ |
|||
.ext-aiassistant-body { |
|||
padding-left: 20px !important; |
|||
padding-right: 20px !important; |
|||
box-sizing: border-box !important; |
|||
} |
|||
.ext-aiassistant-message { |
|||
margin-left: 0 !important; |
|||
margin-right: 0 !important; |
|||
} |
|||
.ext-aiassistant-message + .ext-aiassistant-message { |
|||
margin-top: 0 !important; |
|||
} |
|||
/* --- User bubble --- */ |
|||
.ext-aiassistant-message-user { |
|||
margin-left: 100px !important; |
|||
margin-top: 0 !important; |
|||
margin-bottom: 0 !important; |
|||
} |
|||
.ext-aiassistant-message-user .ext-aiassistant-message__content { |
|||
color: white !important; |
|||
border-radius: 18px !important; |
|||
border: none !important; |
|||
padding: 6px 12px !important; |
|||
} |
|||
.ext-aiassistant-message-user .ext-aiassistant-message__content p { |
|||
color: white !important; |
|||
margin: 0 !important; |
|||
} |
|||
/* --- Assistant typography (family/color set by section 12) --- */ |
|||
.ext-aiassistant-message-assistant { |
|||
font-size: 1em !important; |
|||
overflow-wrap: break-word !important; |
|||
white-space: normal !important; |
|||
max-width: 100% !important; |
|||
} |
|||
.ext-aiassistant-message-assistant p { |
|||
margin: 0 0 0.6em !important; |
|||
} |
|||
.ext-aiassistant-message-assistant p, |
|||
.ext-aiassistant-message-assistant li, |
|||
.ext-aiassistant-message-assistant ul, |
|||
.ext-aiassistant-message-assistant ol { |
|||
line-height: 1.6 !important; |
|||
} |
|||
.ext-aiassistant-message-assistant ul, |
|||
.ext-aiassistant-message-assistant ol { |
|||
margin: 0.3em 0 0.6em !important; |
|||
margin-left: 0 !important; |
|||
padding-top: 0 !important; |
|||
} |
|||
.ext-aiassistant-message-assistant ul { |
|||
list-style-type: disc !important; |
|||
padding-left: 1.2em !important; |
|||
} |
|||
.ext-aiassistant-message-assistant ul ul { |
|||
list-style-type: disc !important; |
|||
padding-left: 1.5em !important; |
|||
} |
|||
.ext-aiassistant-message-assistant li { |
|||
margin-bottom: 0.2em !important; |
|||
white-space: normal !important; |
|||
} |
|||
.ext-aiassistant-message-assistant pre, |
|||
.ext-aiassistant-message-assistant code { |
|||
white-space: pre-wrap !important; |
|||
word-wrap: break-word !important; |
|||
font-family: inherit !important; |
|||
background: transparent !important; |
|||
border: none !important; |
|||
padding: 0 !important; |
|||
margin: 0 !important; |
|||
} |
|||
/* --- Action buttons (copy, source) --- */ |
|||
.ext-aiassistant-message-assistant .ext-aiassistant-actions { |
|||
display: flex !important; |
|||
flex-direction: row-reverse !important; |
|||
} |
|||
.ext-aiassistant-message-user .ext-aiassistant-actions { |
|||
display: flex !important; |
|||
justify-content: flex-end !important; |
|||
} |
|||
/* --- Citations (color set by section 12) --- */ |
|||
.ext-aiassistant-cite { |
|||
line-height: 1 !important; |
|||
font-size: 80% !important; |
|||
vertical-align: super !important; |
|||
} |
|||
/* --- Sources --- */ |
|||
.ext-aiassistant-sources { |
|||
background: transparent !important; |
|||
border: none !important; |
|||
box-shadow: none !important; |
|||
padding: 0 !important; |
|||
margin-bottom: 12px !important; |
|||
} |
|||
/* --- "New Chat" label (color set by section 12) --- */ |
|||
.ext-aiassistant-panel .cdx-button--weight-quiet:not(.cdx-button--icon-only) { |
|||
font-size: 0 !important; |
|||
} |
|||
.ext-aiassistant-panel .cdx-button--weight-quiet:not(.cdx-button--icon-only)::before { |
|||
content: "New" !important; |
|||
font-size: 0.875rem !important; |
|||
font-weight: bold !important; |
|||
visibility: visible !important; |
|||
} |
|||
/* --- Footer + Composer --- */ |
|||
.ext-aiassistant-footer { |
|||
display: flex !important; |
|||
align-items: center !important; |
|||
justify-content: center !important; |
|||
padding: 0 !important; |
|||
box-sizing: border-box !important; |
|||
} |
|||
.ext-aiassistant-prompt-composer { |
|||
margin: 0 !important; |
|||
width: 100% !important; |
|||
background-color: #fff !important; |
|||
padding: 10px 20px !important; |
|||
border: none !important; |
|||
border-radius: 0 !important; |
|||
} |
|||
.ext-aiassistant-prompt-composer__toolbar { |
|||
display: flex !important; |
|||
align-items: center !important; |
|||
} |
|||
/* --- Send button (shape; colors set by section 12) --- */ |
|||
.ext-aiassistant-prompt-composer__send { |
|||
border-radius: 50% !important; |
|||
width: 32px !important; |
|||
height: 32px !important; |
|||
min-width: 0 !important; |
|||
padding: 0 !important; |
|||
display: flex !important; |
|||
align-items: center !important; |
|||
justify-content: center !important; |
|||
margin-left: 4px !important; |
|||
} |
|||
.ext-aiassistant-prompt-composer__send:disabled .cdx-icon svg { |
|||
fill: #72777d !important; |
|||
} |
|||
/* ================================================================= |
|||
9. RESPONSIVE OVERRIDES |
|||
================================================================= */ |
|||
/* --- Mobile (max-width: 768px) --- */ |
|||
@media screen and (max-width: 768px) { |
|||
/* AI assistant: fullscreen mode */ |
|||
.ext-aiassistant-panel { |
|||
position: fixed !important; |
|||
box-sizing: border-box !important; |
|||
width: 100% !important; |
|||
height: 100% !important; |
|||
max-width: none !important; |
|||
max-height: none !important; |
|||
top: 0 !important; |
|||
left: 0 !important; |
|||
right: 0 !important; |
|||
bottom: 0 !important; |
|||
border-radius: 0 !important; |
|||
margin: 0 !important; |
|||
} |
|||
.ext-aiassistant-body { |
|||
height: auto !important; |
|||
flex-grow: 1 !important; |
|||
} |
|||
/* Push input above sticky buttons */ |
|||
.ext-aiassistant-footer { |
|||
padding-bottom: calc(70px + env(safe-area-inset-bottom)) !important; |
|||
} |
} |
||
}); |
|||
var box = null, activeCue = null; |
|||
/* Prevent iOS zoom on AI input */ |
|||
function noteOf(el) { return el.getAttribute('data-fn') || ''; } |
|||
.ext-aiassistant-panel input, |
|||
function cueOf(e) { |
|||
.ext-aiassistant-panel textarea, |
|||
var t = e.target; |
|||
.ext-aiassistant-panel .cdx-text-input__input { |
|||
return (t && t.closest) ? t.closest('.ed-fn') : null; |
|||
font-size: 16px !important; |
|||
} |
|||
function close() { |
|||
if (box) { box.remove(); box = null; } |
|||
activeCue = null; |
|||
document.removeEventListener('click', onAway, true); |
|||
} |
|||
function onAway(e) { |
|||
if (!cueOf(e)) { close(); } |
|||
} |
|||
var touch = window.matchMedia && window.matchMedia('(hover: none)').matches; |
|||
/* Prevent horizontal scroll */ |
|||
html, body { |
|||
overflow-x: hidden !important; |
|||
width: 100% !important; |
|||
position: relative; |
|||
} |
|||
if (touch) { |
|||
/* Hide AI shortcut hint */ |
|||
// Phone: full-width banner pinned to the top; the next tap anywhere dismisses. |
|||
.ext-aiassistant-shortcut-hint { display: none !important; } |
|||
document.addEventListener('click', function (e) { |
|||
} |
|||
var cue = cueOf(e); |
|||
if (!cue) { return; } |
|||
e.preventDefault(); |
|||
var txt = noteOf(cue); |
|||
if (!txt) { return; } |
|||
e.stopPropagation(); |
|||
close(); |
|||
box = document.createElement('div'); |
|||
box.className = 'ed-fn-banner'; |
|||
box.textContent = txt; |
|||
document.body.appendChild(box); |
|||
setTimeout(function () { |
|||
document.addEventListener('click', onAway, true); |
|||
}, 0); |
|||
}, false); |
|||
} else { |
|||
// Desktop: a styled popover beside the cue while hovering it. |
|||
document.addEventListener('mouseover', function (e) { |
|||
var cue = cueOf(e); |
|||
if (!cue || cue === activeCue) { return; } |
|||
var txt = noteOf(cue); |
|||
if (!txt) { return; } |
|||
close(); |
|||
activeCue = cue; |
|||
box = document.createElement('div'); |
|||
box.className = 'ed-fn-popover'; |
|||
box.textContent = txt; |
|||
document.body.appendChild(box); |
|||
var r = cue.getBoundingClientRect(); |
|||
var left = Math.max(8, Math.min(r.left, window.innerWidth - box.offsetWidth - 8)); |
|||
var top = r.top - box.offsetHeight - 8; // above the cue... |
|||
if (top < 8) { top = r.bottom + 8; } // ...or below if no room |
|||
box.style.left = left + 'px'; |
|||
box.style.top = top + 'px'; |
|||
}); |
|||
document.addEventListener('mouseout', function (e) { |
|||
if (!activeCue) { return; } |
|||
var to = e.relatedTarget; |
|||
if (to && to.closest && to.closest('.ed-fn') === activeCue) { return; } |
|||
close(); |
|||
}); |
|||
window.addEventListener('scroll', function () { if (box) { close(); } }, true); |
|||
} |
|||
})(); |
|||
/* ── Datacheck confirm/correct gadget ─────────────────────────────────────── |
|||
/* --- Tablet (min-width: 768px) --- */ |
|||
On a Datacheck: page (namespace 3006), turn each Module:ReportedTable row's |
|||
@media screen and (min-width: 768px) { |
|||
.rt-confirm control into Confirm (toggle) + Reject/Correct (enter a number), |
|||
/* Keep ToC button visible above panel overlays */ |
|||
writing the verdict straight into the underlying Data:<...>.json page under the |
|||
#cps-open-toc { |
|||
REVIEWER'S OWN session (no bot creds). DOM order of .rt-confirm == records[] |
|||
visibility: visible !important; |
|||
order (the module emits exactly one per record); the exact Data title comes |
|||
z-index: 9999 !important; |
|||
from the hidden .rt-data-title marker. Verdicts survive a re-publish via |
|||
} |
|||
wiki_extract.merge_verdicts (value-gated). Anonymous users see read-only marks. */ |
|||
} |
|||
$(function () { |
|||
if (!(window.mw && mw.config) || mw.config.get('wgNamespaceNumber') !== 3006) { return; } |
|||
var marker = document.querySelector('.rt-data-title'); |
|||
var spans = document.querySelectorAll('.rt-confirm'); |
|||
if (!marker || !spans.length || !mw.config.get('wgUserName')) { return; } |
|||
var dataTitle = (marker.textContent || '').trim(); |
|||
if (!dataTitle) { return; } |
|||
mw.loader.using(['mediawiki.api', 'mediawiki.notify']).done(function () { |
|||
/* --- Desktop (min-width: 1000px) --- */ |
|||
var api = new mw.Api(), data = null, baseRevId = null; |
|||
@media screen and (min-width: 1000px) { |
|||
/* Wider content column */ |
|||
#content { max-width: 1200px !important; } |
|||
function fetchAndRender() { |
|||
/* Match logo to wider content */ |
|||
api.get({ action: 'query', prop: 'revisions', rvprop: 'content|ids', |
|||
.fullscreen-logo { max-width: 100% !important; } |
|||
rvslots: 'main', titles: dataTitle, formatversion: 2 }).done(function (res) { |
|||
.fullscreen-logo img.mw-file-element { |
|||
var page = res.query && res.query.pages && res.query.pages[0]; |
|||
max-width: min(100%, 1200px) !important; |
|||
var rev = page && page.revisions && page.revisions[0]; |
|||
margin: 0 auto !important; |
|||
if (!rev) { mw.notify('Datacheck: data page not found — ' + dataTitle); return; } |
|||
baseRevId = rev.revid; |
|||
var content = rev.slots ? rev.slots.main.content : rev.content; |
|||
try { data = JSON.parse(content); } |
|||
catch (e) { mw.notify('Datacheck: bad JSON in ' + dataTitle); return; } |
|||
render(); |
|||
}).fail(function (code) { mw.notify('Datacheck: load failed — ' + code); }); |
|||
} |
} |
||
function save(okMsg) { |
|||
/* Hide ToC button on desktop Vector 2022 (full sidebar available) */ |
|||
api.postWithEditToken({ |
|||
body.skin-vector-2022 #cps-open-toc { display: none !important; } |
|||
action: 'edit', title: dataTitle, contentmodel: 'json', |
|||
} |
|||
text: JSON.stringify(data, null, 2), |
|||
summary: 'Datacheck: human verdict via confirm gadget', baserevid: baseRevId |
|||
}).done(function (res) { |
|||
/* ================================================================= |
|||
if (res.edit && res.edit.newrevid) { baseRevId = res.edit.newrevid; } |
|||
10. PRINT STYLES |
|||
render(); |
|||
================================================================= */ |
|||
mw.notify(okMsg || 'Datacheck: saved.'); |
|||
}).fail(function (code) { |
|||
@media print { |
|||
if (code === 'editconflict') { mw.notify('Datacheck: edit conflict — reloading.'); fetchAndRender(); } |
|||
else { mw.notify('Datacheck: save failed — ' + code); } |
|||
/* --- Hide floating buttons, overlays, and AI assistant --- */ |
|||
}); |
|||
.branding-box, |
|||
#cps-open-toc, |
|||
#custom-email-btn, |
|||
#cps-toc-panel, |
|||
#cps-toc-overlay, |
|||
.minerva-header .search-box, |
|||
.ext-aiassistant, |
|||
.ext-aiassistant-panel, |
|||
.ext-aiassistant-trigger { |
|||
display: none !important; |
|||
} |
} |
||
// Clear every verdict field (keeps the JSON clean like the Python serializer), then set one. |
|||
/* --- Hide standard MediaWiki UI elements to free up space --- */ |
|||
function setStatus(rec, status, extra) { |
|||
#mw-navigation, |
|||
delete rec.human_status; delete rec.confirmed_rev; delete rec.corrected_rev; |
|||
#footer, |
|||
delete rec.override_reason; delete rec.alt_source; |
|||
.printfooter, |
|||
if (status) { rec.human_status = status; for (var k in extra) { rec[k] = extra[k]; } } |
|||
.mw-editsection { |
|||
display: none !important; |
|||
} |
} |
||
function toggleConfirm(rec) { |
|||
/* --- Font consistency for lists --- */ |
|||
if (rec.human_status === 'confirmed') { setStatus(rec, null); } |
|||
.mw-parser-output ul, |
|||
else { setStatus(rec, 'confirmed', { confirmed_rev: data.source_revision || null }); } |
|||
.mw-parser-output ol, |
|||
save(); |
|||
.mw-parser-output li { |
|||
font-family: inherit !important; |
|||
} |
} |
||
function correctRow(rec) { |
|||
/* --- Remove underlines specifically from internal links in print --- */ |
|||
var hint = 'measure=' + rec.measure + ', scale=' + (rec.scale || 1) + |
|||
.mw-parser-output a:not(.external), |
|||
(rec.currency ? ', ' + rec.currency : ''); |
|||
.mw-parser-output a:not(.external):visited { |
|||
var entered = window.prompt( |
|||
text-decoration: none !important; |
|||
'Correct value for "' + rec.label + '" [' + (rec.business_line || 'Total') + '/' + |
|||
(rec.business_unit || 'Group') + ']\n(' + hint + ' — enter the stored value):', String(rec.value)); |
|||
if (entered === null) { return; } |
|||
var num = parseFloat(String(entered).replace(/[,\s]/g, '')); |
|||
if (isNaN(num)) { mw.notify('Datacheck: not a number — ' + entered); return; } |
|||
var reason = window.prompt('Reason (optional):', rec.override_reason || 'manual correction') || 'manual correction'; |
|||
setStatus(rec, 'override', { value: num, corrected_rev: data.source_revision || null, override_reason: reason }); |
|||
save('Datacheck: override saved (' + num + ').'); |
|||
} |
} |
||
} |
|||
function render() { |
|||
if (!data || !data.records) { return; } |
|||
/* ============================================================================ |
|||
if (spans.length !== data.records.length) { |
|||
SECTION 11 — WIKITABLES: table TYPES |
|||
mw.notify('Datacheck: table out of sync with the data page — reload the page.'); return; |
|||
- .wikitable = NEUTRAL default: themed (frame, caption, header |
|||
} |
|||
tint, hairlines, hover) but free-form — columns |
|||
Array.prototype.forEach.call(spans, function (span, i) { |
|||
flex, labels wrap, nothing frozen. |
|||
var rec = data.records[i], status = rec.human_status || null; |
|||
- .wikitable.fintable = FINANCIAL bundle: frozen nowrap first column + |
|||
span.innerHTML = ''; |
|||
data-column width floors. The bot emits the class |
|||
var ok = document.createElement('a'); |
|||
automatically on numeric-dense tables; add it by |
|||
ok.href = '#'; ok.textContent = (status === 'confirmed') ? '✓' : '○'; |
|||
hand to get the same behavior on a manual table. |
|||
ok.title = (status === 'confirmed') ? 'Confirmed — click to un-confirm' : 'Click to confirm'; |
|||
- Future table types = one new class, one new bundle below. |
|||
ok.style.cssText = 'text-decoration:none;font-weight:bold;margin-right:8px;color:' + |
|||
- .wt-freeze-2 = add-on modifier: freeze columns 1+2 (mark column 1 |
|||
(status === 'confirmed' ? '#137333' : '#999'); |
|||
ok.onclick = function (e) { e.preventDefault(); toggleConfirm(rec); }; |
|||
============================================================================ */ |
|||
span.appendChild(ok); |
|||
:root { |
|||
var fix = document.createElement('a'); |
|||
/* column size scale — markers map to these; an UNMARKED column flexes */ |
|||
fix.href = '#'; fix.textContent = (status === 'override') ? ('✎ ' + rec.value) : '✎'; |
|||
--wt-xs: 3em; |
|||
fix.title = 'Reject + enter the correct number'; |
|||
--wt-s: 6em; |
|||
fix.style.cssText = 'text-decoration:none;color:' + (status === 'override' ? '#b06000' : '#999'); |
|||
--wt-m: 9em; |
|||
fix.onclick = function (e) { e.preventDefault(); correctRow(rec); }; |
|||
--wt-l: 15em; |
|||
span.appendChild(fix); |
|||
--wt-xl: 24em; |
|||
if (status === 'corrected') { |
|||
--wt-xxl: 39em; |
|||
var c = document.createElement('span'); c.textContent = ' (corrected)'; |
|||
/* palette (section 12 re-points these onto the warm ramp) */ |
|||
c.style.color = '#137333'; span.appendChild(c); |
|||
--wt-border: #eceef1; |
|||
} |
|||
--wt-rule: #72777d; |
|||
}); |
|||
--wt-edge: #dadde1; |
|||
--wt-th-bg: #f6f7f9; |
|||
--wt-th-text: #54595d; |
|||
--wt-pad-y: 0.5em; |
|||
} |
|||
/* ── Theme: EVERY wikitable, any type ── */ |
|||
.wikitable { width: 100% !important; } |
|||
table.wikitable { |
|||
font-size: 0.85em; |
|||
background-color: #fff; |
|||
border: 1px solid var(--wt-border); |
|||
font-variant-numeric: tabular-nums; |
|||
margin-top: 0.3em; |
|||
margin-bottom: 2em; |
|||
} |
|||
table.wikitable td { background-color: #fff; } |
|||
table.wikitable caption { |
|||
text-align: left; |
|||
font-weight: bold; |
|||
background-color: #fff; |
|||
padding-bottom: 0.45em; |
|||
} |
|||
table.wikitable > tr > th, |
|||
table.wikitable > tr > td, |
|||
table.wikitable > * > tr > th, |
|||
table.wikitable > * > tr > td { |
|||
border: 1px solid var(--wt-border); |
|||
padding: var(--wt-pad-y) 0.6em; |
|||
} |
|||
table.wikitable > * > tr > th { |
|||
background-color: var(--wt-th-bg); |
|||
color: var(--wt-th-text); |
|||
} |
|||
table.wikitable > * > tr:first-child > th, |
|||
table.wikitable > * > tr:first-child > td { border-top: 1px solid var(--wt-rule); } |
|||
table.wikitable > * > tr:has(> th):has(+ tr > td) > th { border-bottom: 1px solid var(--wt-rule); } |
|||
table.wikitable > * > tr:last-child > td, |
|||
table.wikitable > * > tr:last-child > th { border-bottom: 1px solid var(--wt-rule); } |
|||
table.wikitable > tbody > tr:hover > td { background-color: #f8f9fa; } |
|||
table.wikitable td p { font-size: inherit !important; } |
|||
/* ── Column size scale: usable on ANY table type ── */ |
|||
.wikitable th.col-xs, .wikitable td.col-xs { width: var(--wt-xs); min-width: var(--wt-xs); } |
|||
.wikitable th.col-s, .wikitable td.col-s { width: var(--wt-s); min-width: var(--wt-s); } |
|||
.wikitable th.col-m, .wikitable td.col-m { width: var(--wt-m); min-width: var(--wt-m); } |
|||
.wikitable th.col-l, .wikitable td.col-l { width: var(--wt-l); min-width: var(--wt-l); } |
|||
.wikitable th.col-xl, .wikitable td.col-xl { width: var(--wt-xl); min-width: var(--wt-xl); } |
|||
.wikitable th.col-xxl, .wikitable td.col-xxl { width: var(--wt-xxl); min-width: var(--wt-xxl); } |
|||
/* legacy marker names on published pages = aliases of s / m */ |
|||
.wikitable th.col, .wikitable td.col { width: var(--wt-s); min-width: var(--wt-s); } |
|||
.wikitable th.col-wide, .wikitable td.col-wide { width: var(--wt-m); min-width: var(--wt-m); } |
|||
/* ── FINTABLE bundle — THE definition of "financial table" on this wiki. |
|||
Applies to .fintable (emitter-typed numeric-dense tables) and, via |
|||
:has(), to every already-published bot table — they all carry the |
|||
legacy col/col-wide markers, so the back catalogue upgrades with NO |
|||
re-publishing. The bridge is scoped to the LEGACY marker names only: |
|||
col-s/col-m on a neutral hand table does NOT trigger financial |
|||
behavior. Repeat this selector group verbatim wherever fintable |
|||
scoping is needed (section 12 uses it too). ── */ |
|||
/* data-column floor (legacy pages can have unmarked data columns) */ |
|||
table.wikitable.fintable th:not(:first-child), |
|||
table.wikitable.fintable td:not(:first-child), |
|||
table.wikitable:has(.col, .col-wide) th:not(:first-child), |
|||
table.wikitable:has(.col, .col-wide) td:not(:first-child) { min-width: var(--wt-s); } |
|||
/* frozen row-label column. white-space:normal (NOT nowrap) with a max-width |
|||
cap: a normal label keeps to one line as long as it fits (auto table layout |
|||
sizes the column to its content), but a runaway label — e.g. a long note |
|||
that ends up in the cell — WRAPS at ~2/3 of the table instead of forcing a |
|||
giant one-line column that pushes the data off-screen. overflow-wrap breaks |
|||
an unbreakable token. min-width keeps it from collapsing too narrow. */ |
|||
table.wikitable.fintable th:first-child, |
|||
table.wikitable.fintable td:first-child, |
|||
table.wikitable:has(.col, .col-wide) th:first-child, |
|||
table.wikitable:has(.col, .col-wide) td:first-child { |
|||
white-space: normal; |
|||
max-width: 66%; /* hard cap: never hog more than ~2/3 */ |
|||
overflow-wrap: anywhere; |
|||
min-width: 16em; |
|||
position: sticky; |
|||
left: 0; |
|||
z-index: 1; |
|||
box-shadow: 1px 0 0 var(--wt-edge); |
|||
} |
|||
table.wikitable.fintable td:first-child, |
|||
table.wikitable:has(.col, .col-wide) td:first-child { background-color: #fff; } |
|||
table.wikitable.fintable th:first-child, |
|||
table.wikitable:has(.col, .col-wide) th:first-child { background-color: var(--wt-th-bg); } |
|||
/* ── wt-freeze-2 add-on: freeze columns 1+2. Mark column 1 col-xs — column |
|||
2 sticks exactly one xs step in. Comes AFTER the fintable bundle so |
|||
its column-1 width exception wins the tie. ── */ |
|||
table.wikitable.wt-freeze-2 th:first-child, |
|||
table.wikitable.wt-freeze-2 td:first-child { |
|||
min-width: var(--wt-xs); /* overrides the fintable 16em label column */ |
|||
white-space: normal; |
|||
position: sticky; |
|||
left: 0; |
|||
z-index: 1; |
|||
} |
|||
table.wikitable.wt-freeze-2 th:nth-child(2), |
|||
table.wikitable.wt-freeze-2 td:nth-child(2) { |
|||
position: sticky; |
|||
left: var(--wt-xs); |
|||
z-index: 1; |
|||
box-shadow: 1px 0 0 var(--wt-edge); |
|||
background-color: #fff; |
|||
} |
|||
table.wikitable.wt-freeze-2 th:nth-child(2) { background-color: var(--wt-th-bg); } |
|||
table.wikitable.wt-freeze-2 td:first-child { background-color: #fff; } |
|||
table.wikitable.wt-freeze-2 th:first-child { background-color: var(--wt-th-bg); } |
|||
@media screen and (max-width: 719px) { |
|||
table.wikitable { border: none !important; } |
|||
table.wikitable > tr > th, |
|||
table.wikitable > tr > td, |
|||
table.wikitable > tbody > tr > th, |
|||
table.wikitable > tbody > tr > td { |
|||
border: 1px solid var(--wt-border); |
|||
} |
} |
||
} |
|||
fetchAndRender(); |
|||
/* ================================================================= |
|||
}); |
|||
12. EDITORIAL DESIGN SYSTEM v11 ("paper & ink") |
|||
}); |
|||
Appended LAST deliberately: later rules of equal specificity win, |
|||
so this section restyles typography / color / spacing WITHOUT |
|||
editing sections 1-11 (it even re-points section 11's --wt-* |
|||
color variables from here — a later :root wins). Delete the whole |
|||
section to revert. |
|||
v11: full-sheet cleanup — sections 7/8 stripped to structure (this |
|||
section is the single color authority); TOC block consolidated |
|||
(numbers in a fixed right-aligned gutter, "0." on Beginning, |
|||
inline chevron, no rails). |
|||
================================================================= */ |
|||
/* ── Webfont: Source Serif 4 (variable; ONE file covers 400-600). |
|||
@font-face is safe anywhere in ResourceLoader output — never use |
|||
@import here (gadget CSS is concatenated BEFORE Common.css and |
|||
breaks it, per T165040). If the font fails to load, Georgia |
|||
takes over seamlessly. Production hardening: copy the two woff2 |
|||
files to the S3 bucket and swap the URLs. ── */ |
|||
@font-face { |
|||
font-family: "Source Serif 4"; |
|||
font-style: normal; |
|||
font-weight: 400 600; |
|||
font-display: swap; |
|||
src: url(https://fonts.gstatic.com/s/sourceserif4/v14/vEFF2_tTDB4M7-auWDN0ahZJW3IX2ih5nk3AucvUHf6kDXr4.woff2) format("woff2"); |
|||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; |
|||
} |
|||
@font-face { |
|||
font-family: "Source Serif 4"; |
|||
font-style: italic; |
|||
font-weight: 400 600; |
|||
font-display: swap; |
|||
src: url(https://fonts.gstatic.com/s/sourceserif4/v14/vEF02_tTDB4M7-auWDN0ahZJW1ge6NmXpVAHV83Bfb_US2D2QYxoUKIkn98pRl9tDMQC.woff2) format("woff2"); |
|||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; |
|||
} |
|||
/* ── Design knobs. |
|||
ONE gray ramp (3 grays + 2 hairlines), ONE small size, ONE sans. |
|||
The --wt-* lines re-point section 11's table palette onto the |
|||
same warm ramp (this :root is later, so it wins the tie). ── */ |
|||
:root { |
|||
--ed-serif: "Source Serif 4", Georgia, "Times New Roman", serif; |
|||
--ed-sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, |
|||
"Inter", Helvetica, Arial, sans-serif; /* = Vector/Codex chrome stack */ |
|||
--ed-ink: #2b2926; /* text, headings, strong rules */ |
|||
--ed-secondary: #66605c; /* labels, standfirst, TOC, footer links */ |
|||
--ed-faint: #807973; /* page refs, list markers, footer body */ |
|||
--ed-hairline: #e7e2db; /* light warm line (infobox frame) */ |
|||
--ed-hairline-strong: #d6d0c8; /* stronger warm line (panel frame) */ |
|||
--ed-link: #0d7680; /* interactive teal: links, focus, send */ |
|||
--ed-underline: #ccc1b7; /* resting link underline tint */ |
|||
--ed-accent: #f07662; /* house coral — hover underline, sparing */ |
|||
--ed-paper: #fbfaf7; /* page canvas (set #fff to disable the tint) */ |
|||
--ed-infobox-w: 18.5rem; /* infobox total width (border-box) */ |
|||
--ed-measure: calc((100% - var(--ed-infobox-w)) * 0.9); /* prose stops ~10% short of |
|||
the infobox — tighter readable line + a gutter before the card */ |
|||
--ed-body: 1rem; /* body size (16px — the "90% zoom" preference) */ |
|||
--ed-small: 0.8125rem; /* THE small size: tables, infobox, TOC, footer */ |
|||
--ed-title-gap: 2.1rem; /* CALIBRATION: moves the title rule DOWN */ |
|||
--ed-heading-gap: 4rem; /* space BEFORE h2 AND h3 — the SAME for both (rem, not em, |
|||
so the two gaps stay equal in px despite different heading |
|||
sizes); ~2x the old h3 space (was 1.8em ≈ 32px) */ |
|||
--ed-list-indent: var(--ed-body); /* per-level indent = marker-to-text step, tied to the |
|||
BODY size (1em = 16px) — a clean typographic ratio that the |
|||
table's first-column labels also align to (see section 12). |
|||
Still rem-based (via --ed-body), NOT em — an em offset would |
|||
resolve against each marker's own font-size. */ |
|||
/* section 11's table palette, warmed onto the same ramp. |
|||
--wt-rule is the table FRAME: deliberately lighter than the ink |
|||
h2 rules so tables sit below section structure in the hierarchy */ |
|||
--wt-border: #ece8e1; |
|||
--wt-rule: #b3aca3; |
|||
--wt-edge: var(--wt-border); /* ONE hairline tone for interior edges */ |
|||
--wt-th-bg: #f3efe8; |
|||
--wt-th-text: var(--ed-secondary); |
|||
} |
|||
/* ── Canvas: warm paper everywhere — page, the header band Vector |
|||
paints white on its own, the TOC column, and the TOC's |
|||
scroll-fade overlay ── */ |
|||
body, .mw-page-container { background-color: var(--ed-paper) !important; } |
|||
.vector-header-container .mw-header, |
|||
.vector-header-container .vector-sticky-header { |
|||
background-color: var(--ed-paper) !important; |
|||
} |
|||
#vector-toc, .vector-toc, .vector-pinned-container { |
|||
background-color: transparent !important; |
|||
} |
|||
/* Minerva (mobile skin) paints its own white wrappers over body */ |
|||
#mw-mf-page-center, .mw-body { background-color: var(--ed-paper) !important; } |
|||
.vector-sticky-pinned-container::after { |
|||
background: linear-gradient(transparent, var(--ed-paper)) !important; |
|||
} |
|||
@media print { body, .mw-page-container { background-color: #fff !important; } } |
|||
/* ── Visitor chrome: Appearance UI hidden for EVERYONE here, re-shown |
|||
for logged-in users in MediaWiki:Group-user.css (the wiki's |
|||
read-only-mode architecture — Group-user.css only loads when |
|||
logged in, so no body-class dependency) ── */ |
|||
.vector-appearance-landmark, |
|||
#vector-appearance-dropdown, |
|||
#vector-appearance-pinned-container, |
|||
#vector-appearance, |
|||
.vector-column-end { display: none !important; } |
|||
/* ── Mobile (Minerva) keeps ONE light line tone in tables — every |
|||
structural table line consumes --wt-rule, so one override |
|||
simplifies frame, header rule, and side rails at once ── */ |
|||
.skin-minerva { --wt-rule: var(--wt-border); } |
|||
/* ── ONE sans: the whole interface (header, search, tagline, buttons, |
|||
footer) and all data share the Codex stack; prose re-asserts the |
|||
serif below ── */ |
|||
body { font-family: var(--ed-sans); } |
|||
/* ── Logo on the title axis: push it right by the TOC column + grid |
|||
gap at Vector's own grid breakpoints, so the logo + tagline sit |
|||
exactly above the page title. Below 1120px the TOC column does |
|||
not exist, so no offset. ── */ |
|||
@media (min-width: 1120px) { .mw-logo { margin-left: calc(12.25rem + 24px); } } |
|||
@media (min-width: 1680px) { .mw-logo { margin-left: calc(15.5rem + 24px); } } |
|||
/* ── Prose voice: serif, warm ink (Minerva has no .mw-body-content — |
|||
its wrapper is #bodyContent.content) ── */ |
|||
.mw-body-content, |
|||
.skin-minerva #bodyContent.content { |
|||
font-family: var(--ed-serif); |
|||
font-size: var(--ed-body); |
|||
line-height: 1.6; |
|||
color: var(--ed-ink); |
|||
font-variant-numeric: lining-nums; |
|||
} |
|||
/* readable measure for prose; data/tables stay full width */ |
|||
.mw-parser-output > p, |
|||
.mw-parser-output > ul, |
|||
.mw-parser-output > ol, |
|||
.mw-parser-output > dl { max-width: var(--ed-measure); } |
|||
/* nested paragraphs too (hand-written page structures); table cells released */ |
|||
.mw-parser-output p { max-width: var(--ed-measure); } |
|||
.mw-parser-output table p { max-width: none; } |
|||
/* guards: the data voice stays sans at the ONE small size — otherwise the |
|||
serif body size would silently scale section 11's 0.85em tables (and |
|||
every em-based column width) */ |
|||
table.wikitable, .infobox { |
|||
font-family: var(--ed-sans); |
|||
font-size: var(--ed-small); |
|||
} |
|||
/* ── The table BLOCK ── |
|||
1. Printed ON the paper (not white cards): surfaces transparent; |
|||
in a FINTABLE only the sticky first column stays opaque (it |
|||
must cover scrolling content) in the paper color; hover warms. |
|||
2. Full frame in --wt-rule. Sides: the RIGHT rail is a plain |
|||
border on the last-column cells. On a NEUTRAL table the LEFT |
|||
rail is a plain table border (nothing is sticky); on a |
|||
FINTABLE it must be a box-shadow on the sticky first-column |
|||
cells — with border-collapse, borders on sticky cells do not |
|||
move when the cell sticks (they vanish on horizontal scroll), |
|||
but shadows travel with the cell — and the table's own left |
|||
border is disabled so the rail is the only line there. |
|||
The fintable selector group below is section 11's definition |
|||
of "financial table", repeated verbatim. |
|||
3. The table's outer margins move to the scroll WRAPPER so the |
|||
horizontal scrollbar hugs the bottom rule, and the scrollbar |
|||
itself goes thin + warm. ── */ |
|||
table.wikitable, |
|||
table.wikitable td, |
|||
table.wikitable caption { background-color: transparent; } |
|||
table.wikitable > tbody > tr:hover > td { background-color: #f2ede5; } |
|||
/* the frozen first column carries its own paper bg (below) at higher |
|||
specificity, so it needs its OWN hover rule to warm with the row */ |
|||
table.wikitable.fintable > tbody > tr:hover > td:first-child, |
|||
table.wikitable:has(.col, .col-wide) > tbody > tr:hover > td:first-child { |
|||
background-color: #f2ede5; |
|||
} |
|||
table.wikitable.fintable td:first-child, |
|||
table.wikitable:has(.col, .col-wide) td:first-child { |
|||
background-color: var(--ed-paper); |
|||
} |
|||
table.wikitable.fintable th:first-child, |
|||
table.wikitable.fintable td:first-child, |
|||
table.wikitable:has(.col, .col-wide) th:first-child, |
|||
table.wikitable:has(.col, .col-wide) td:first-child { |
|||
border-left: none; |
|||
box-shadow: inset 1px 0 0 var(--wt-rule), /* left rail — sticks with the cell */ |
|||
1px 0 0 var(--wt-edge); /* right edge of the frozen column */ |
|||
} |
|||
/* LEFT + RIGHT frame edges drawn on the CELLS in --wt-rule, matching the |
|||
top/bottom edges (section 11). The left edge MUST be on the first cell, not |
|||
only the table: with border-collapse a cell border outranks the table border, |
|||
so the first column's --wt-border (light) cell border would otherwise win the |
|||
left edge and render it lighter than the other three sides. Fintable overrides |
|||
first-child border-left → none + box-shadow rail (higher specificity, above). */ |
|||
.wikitable th:first-child, |
|||
.wikitable td:first-child { border-left: 1px solid var(--wt-rule); } |
|||
.wikitable th:last-child, |
|||
.wikitable td:last-child { border-right: 1px solid var(--wt-rule); } |
|||
/* row labels MEET the bullets: the first column's text starts at the SAME indent |
|||
as list text (both = --ed-list-indent), so table row-labels and bullet text read |
|||
on ONE axis. The table frame + the bullet dots already share x=0, so this lands |
|||
the second axis too. Tied to the same variable → they can never drift apart. */ |
|||
.wikitable th:first-child, |
|||
.wikitable td:first-child { padding-left: var(--ed-list-indent); } |
|||
table.wikitable { margin: 0; border-left: 1px solid var(--wt-rule); } |
|||
table.wikitable.fintable, |
|||
table.wikitable:has(.col, .col-wide) { border-left: none; } |
|||
/* the table's outer margins live on the scroll WRAPPER (the emitter wraps |
|||
every table in <div style="overflow-x:auto">): top margin gives air |
|||
before the eyebrow caption + separates consecutive tables; the scrollbar |
|||
goes thin and quiet in the header-row tint */ |
|||
.mw-parser-output div[style*="overflow-x"], |
|||
.copy-table-scroll { |
|||
margin: 1.8em 0 2em; |
|||
scrollbar-width: thin; |
|||
scrollbar-color: var(--wt-th-bg) transparent; |
|||
} |
|||
/* caption = the table's TITLE as a quiet EYEBROW (the shared kicker |
|||
treatment — breadcrumb / infobox header): uppercase sans, letter-spaced, |
|||
secondary ink, with air below before the grid. No glyph. */ |
|||
table.wikitable caption { |
|||
font-family: var(--ed-sans); |
|||
font-size: 0.75rem; |
|||
font-weight: 600; |
|||
letter-spacing: 0.08em; |
|||
text-transform: uppercase; |
|||
color: var(--ed-secondary); |
|||
text-align: left; |
|||
padding-bottom: 0.7em; |
|||
} |
|||
/* standfirst — the italic intro sentence (FT: sans, calm). Anchored to the |
|||
generated infobox-then-intro pattern so hand-written pages keep real italics */ |
|||
.mw-parser-output > .infobox ~ p:first-of-type > i, |
|||
.mw-parser-output > table.infobox + p > i { |
|||
font-family: var(--ed-sans); |
|||
font-style: normal; |
|||
font-size: 0.97em; |
|||
line-height: 1.55; |
|||
color: var(--ed-secondary); |
|||
} |
|||
/* ── List geometry — ONE definition for both skins: text hangs at |
|||
--ed-list-indent per level; the markers are positioned EXACTLY |
|||
below (see the ::before block). !important + the Minerva-qualified |
|||
selectors beat section 7's mobile rules and the skin defaults; |
|||
table-cell lists keep section 11's own rule (higher specificity). ── */ |
|||
.mw-parser-output ul, |
|||
.mw-parser-output ol, |
|||
body.skin-minerva .mw-parser-output ul, |
|||
body.skin-minerva .collapsible-block ul { |
|||
margin-left: 0 !important; |
|||
padding-left: var(--ed-list-indent) !important; |
|||
} |
|||
.mw-parser-output ol { padding-left: 1.4em !important; } /* numbers need more room */ |
|||
/* list rhythm: air between points, predictable nesting */ |
|||
.mw-parser-output ul { margin-top: 0.4em; } |
|||
.mw-parser-output li { margin-bottom: 0.45em; } |
|||
.mw-parser-output li li { margin-top: 0.3em; margin-bottom: 0.3em; } |
|||
.mw-parser-output li > ul { margin-top: 0.3em; } |
|||
/* per-level markers drawn as ::before at EXACT positions: each marker's |
|||
LEFT edge sits on its parent's text axis (level 1 on the heading |
|||
axis), because left: -indent lands on the container edge, which IS |
|||
the parent text x. Shapes: bullet / house triangle (drivers, echoes |
|||
the TOC prefix) / hairline en dash; per-level font-size + |
|||
line-height keep the three optically equal and vertically centered */ |
|||
.mw-parser-output ul { list-style: none !important; } |
|||
.mw-parser-output ul > li { position: relative; } |
|||
.mw-parser-output ul > li::before { |
|||
content: "\2022"; |
|||
position: absolute; |
|||
left: calc(-1 * var(--ed-list-indent)); |
|||
color: var(--ed-faint); |
|||
font-family: var(--ed-sans); |
|||
font-size: 0.95em; |
|||
line-height: 1.68; |
|||
} |
|||
.mw-parser-output ul ul > li::before { content: "\25B8"; font-size: 0.7em; line-height: 2.29; } |
|||
.mw-parser-output ul ul ul > li::before { content: "\2013"; font-size: 0.95em; line-height: 1.68; } |
|||
/* page-reference superscripts — present everywhere, must whisper. |
|||
line-height:0 stops them inflating the line box */ |
|||
.mw-body-content sup, |
|||
.skin-minerva .content sup { |
|||
font-size: 68%; |
|||
line-height: 0; |
|||
font-family: var(--ed-sans); |
|||
color: var(--ed-faint); |
|||
} |
|||
/* ── Title block: serif display, REGULAR weight, large; the title-gap |
|||
knob lands its rule on the CONTENTS rule's line ── */ |
|||
h1#firstHeading, .mw-first-heading { |
|||
font-family: var(--ed-serif); |
|||
font-size: 2.4rem; |
|||
line-height: 1.15; |
|||
font-weight: 400; |
|||
letter-spacing: -0.01em; |
|||
color: var(--ed-ink) !important; |
|||
border-bottom: 2px solid var(--ed-ink) !important; |
|||
margin-top: var(--ed-title-gap) !important; |
|||
padding-bottom: 0.3em; |
|||
margin-bottom: 0.35em; |
|||
} |
|||
/* breadcrumb under the title rule — the shared eyebrow treatment */ |
|||
#contentSub .subpages { |
|||
font-family: var(--ed-sans); |
|||
font-size: 0.75rem; |
|||
font-weight: 600; |
|||
letter-spacing: 0.08em; |
|||
text-transform: uppercase; |
|||
color: var(--ed-secondary); |
|||
margin-bottom: 1.4em; |
|||
} |
|||
#contentSub .subpages a, |
|||
#contentSub .subpages a:visited { color: var(--ed-secondary) !important; } |
|||
/* ── Section headings: sans semibold on the house rules. Scoped to |
|||
.mw-body-content — Vector's own typography rules are |
|||
class-qualified (0,1,1), so bare h2/h3 selectors would LOSE. |
|||
Minerva's content wrapper is .content. ── */ |
|||
.mw-body-content h2, .mw-body-content .mw-heading2, .section-heading, |
|||
.skin-minerva .content h2 { |
|||
font-family: var(--ed-sans); |
|||
font-size: 1.875rem; /* 30px */ |
|||
line-height: 1.25; |
|||
font-weight: 600; |
|||
letter-spacing: -0.005em; |
|||
color: var(--ed-ink) !important; |
|||
border-bottom: 1px solid var(--ed-ink) !important; |
|||
margin-top: var(--ed-heading-gap); /* same space before h2 and h3 */ |
|||
margin-bottom: 0.7em; |
|||
padding-bottom: 0.3em; |
|||
} |
|||
.mw-body-content h3, |
|||
.skin-minerva .content h3 { |
|||
font-family: var(--ed-sans); |
|||
font-size: 1.5rem; /* 24px */ |
|||
font-weight: 600; |
|||
color: var(--ed-ink) !important; |
|||
/* a FULL-WIDTH rule like h2 — but in the TABLE-FRAME tone (--wt-rule) rather |
|||
than h2's ink, so it reads one level down and rhymes with the table borders */ |
|||
border-bottom: 1px solid var(--wt-rule); |
|||
margin-top: var(--ed-heading-gap); /* doubled vs the old 1.8em; same as h2 */ |
|||
margin-bottom: 0.6em; |
|||
padding-bottom: 0.25em; |
|||
} |
|||
.mw-body-content h4, .mw-body-content h5, .mw-body-content h6 { |
|||
font-family: var(--ed-sans); |
|||
font-size: 1rem; |
|||
font-weight: 600; |
|||
color: var(--ed-ink) !important; |
|||
} |
|||
/* the inner spans are pinned #202122 !important by old skin CSS — make |
|||
them follow their heading's ink instead */ |
|||
.mw-headline, .mw-page-title-main { color: inherit !important; } |
|||
/* ── Links: FT teal; content links carry a resting tint underline that |
|||
warms to the house coral on hover ── */ |
|||
a, a:visited, |
|||
.mw-parser-output a, .mw-parser-output a:visited, |
|||
.mw-body-content a.external, .mw-body-content a.external:visited, |
|||
.mw-collapsible-toggle-default .mw-collapsible-text { |
|||
color: var(--ed-link) !important; |
|||
} |
|||
.mw-parser-output a { |
|||
text-decoration: underline; |
|||
text-decoration-color: var(--ed-underline); |
|||
text-decoration-thickness: 1px; |
|||
text-underline-offset: 0.18em; |
|||
} |
|||
.mw-parser-output a:hover { |
|||
text-decoration-color: var(--ed-accent); |
|||
text-decoration-thickness: 2px; |
|||
} |
|||
/* exceptions re-stated AFTER the generic rules so they keep winning */ |
|||
a.new, a.new:visited { color: #d73333 !important; } |
|||
a.mw-ui-button, a.mw-ui-button:visited { color: #fff !important; } |
|||
.mw-editsection, .mw-editsection a, .mw-editsection a:visited { |
|||
color: var(--ed-secondary) !important; |
|||
text-decoration: none; |
|||
opacity: 0.7; |
|||
} |
|||
/* ── Focus/active states join the interactive teal — Codex paints them |
|||
in its own progressive blue (#36c) otherwise. The generic |
|||
.cdx-text-input rule covers the header search box; the AI chat |
|||
input is exempted further below (its ring sits on the composer). ── */ |
|||
.cdx-text-input__input:focus, |
|||
.cdx-text-input__input:enabled:focus { |
|||
border-color: var(--ed-link) !important; |
|||
box-shadow: inset 0 0 0 1px var(--ed-link) !important; |
|||
} |
|||
.cdx-button:enabled:focus, |
|||
.cdx-button--fake-button:focus { |
|||
box-shadow: inset 0 0 0 2px var(--ed-link) !important; |
|||
} |
|||
:focus-visible { outline-color: var(--ed-link); } |
|||
/* ── TOC sidebar — flat left-aligned design. |
|||
Every entry, ANY level, starts on ONE left axis: the section |
|||
number is INLINE (Vector ships it display:none; we re-show it) |
|||
flowing straight into the title as a single text run, so "2.1. |
|||
Press release" reads as one string. Depth is carried by the |
|||
number itself plus a lighter ink on child rows — NO indentation, |
|||
NO number gutter, NO absolute positioning (the old gutter geometry |
|||
is gone). The ONE structural rule is a hanging indent on every li |
|||
(--toc-hang): the first line outdents to the axis, wrapped lines |
|||
align under the TITLE. Nested <ul>s are pulled back by the same |
|||
--toc-hang so level-2+ numbers land on the level-1 axis (flat, no |
|||
staircase). "Beginning" (the one entry MediaWiki leaves unnumbered) |
|||
gets a generated inline "0.". Expand/collapse is the house triangle |
|||
▸/▾ INLINE after the heading. The CONTENTS header left-aligns with |
|||
the number axis. |
|||
CALIBRATION: --toc-hang is the wrap-indent / number budget — size |
|||
it to the title-start of the entries that actually wrap (level-2, |
|||
~"2.2. "); the 0.22rem row rhythm is unchanged. ── */ |
|||
.vector-toc { |
|||
font-family: var(--ed-sans); |
|||
--toc-header-inset: 0; /* CONTENTS label sits on the number axis */ |
|||
} |
|||
/* CONTENTS header: label + 1px ink rule on the title rule's line |
|||
(padding-top moves the label and rule together; padding-bottom the |
|||
rule only), inset onto the number axis */ |
|||
.vector-toc .vector-pinnable-header { |
|||
border-bottom: 1px solid var(--ed-ink) !important; |
|||
padding-top: 0.35rem; |
|||
padding-bottom: 0.95rem; |
|||
margin-bottom: 0.9rem; |
|||
padding-left: 0 !important; |
|||
margin-left: var(--toc-header-inset) !important; |
|||
} |
|||
.vector-toc .vector-pinnable-header-label { |
|||
font-size: 0.75rem; |
|||
font-weight: 600; |
|||
letter-spacing: 0.08em; |
|||
text-transform: uppercase; |
|||
color: var(--ed-secondary) !important; |
|||
margin-left: 0; |
|||
} |
|||
/* entries: TOP-LEVEL rows in full body ink so the section spine reads as |
|||
strongly as the article; CHILD rows (level 2+) drop to the faint ink — the |
|||
parent↔child contrast is now ink↔faint (the widest gap on the ramp), so |
|||
subsections clearly recede and group under their parent WITHOUT any indent. |
|||
Hover + active go to ink: a child darkens, a top-level row is already ink so |
|||
its "current" cue is the weight bump on active. |
|||
CASCADE: the base is a (0,2,0) non-visited + (0,3,0) :visited PAIR; the child |
|||
rules carry their own :visited arm so they reach (0,4,0) and win for visited |
|||
child links regardless of order; hover/active are (0,3,0) !important and sit |
|||
AFTER the child block so source order hands them the tie for a hovered/active |
|||
child. Keep this order: base → children → hover → active. */ |
|||
.vector-toc .vector-toc-link, |
|||
.vector-toc .vector-toc-link:visited { |
|||
color: var(--ed-ink) !important; |
|||
font-size: var(--ed-small); |
|||
text-decoration: none; |
|||
} |
|||
.vector-toc .vector-toc-level-2 > .vector-toc-link, |
|||
.vector-toc .vector-toc-level-2 > .vector-toc-link:visited, |
|||
.vector-toc .vector-toc-level-3 > .vector-toc-link, |
|||
.vector-toc .vector-toc-level-3 > .vector-toc-link:visited, |
|||
.vector-toc .vector-toc-level-4 > .vector-toc-link, |
|||
.vector-toc .vector-toc-level-4 > .vector-toc-link:visited { |
|||
color: var(--ed-faint) !important; |
|||
} |
|||
.vector-toc .vector-toc-link:hover { color: var(--ed-ink) !important; } |
|||
.vector-toc .vector-toc-list-item-active > .vector-toc-link { |
|||
color: var(--ed-ink) !important; |
|||
font-weight: 500 !important; /* the "current" cue (top-level is already ink) */ |
|||
} |
|||
/* lists flush on the component edge; hanging indent carried on every li */ |
|||
.vector-toc .vector-toc-contents, |
|||
.vector-toc .vector-toc-list { |
|||
margin: 0; |
|||
padding: 0; |
|||
list-style: none; |
|||
} |
|||
.vector-toc .vector-toc-list-item { |
|||
/* ROW RHYTHM: vertical spacing lives on padding-TOP (one gap per row). The li |
|||
is a flex ROW so the chevron toggle sits in-flow right after the title; |
|||
the sublist wraps onto its own row below (flex-basis:100%). */ |
|||
display: flex; |
|||
flex-wrap: wrap; |
|||
align-items: baseline; |
|||
padding: 0.44em 0 0 0 !important; |
|||
margin: 0 !important; |
|||
font-size: var(--ed-small); |
|||
line-height: 1.5; /* = the infobox / wikitable line-height */ |
|||
} |
|||
/* level-2+ sits flush under level-1 (numbers aligned on one axis); flex-basis |
|||
100% drops the sublist onto its own row below the parent's title + chevron */ |
|||
.vector-toc .vector-toc-list-item > .vector-toc-list { |
|||
flex: 0 0 100%; |
|||
margin: 0 !important; |
|||
} |
|||
/* HANG-UNDER-TITLE: the number and the title share a flex row, so the title is |
|||
a wrapping block whose 2nd+ lines align under the TITLE (after the number). |
|||
Because the number is its own flex item, this holds for any number width |
|||
("3." vs "12."), which a fixed text-indent could not. The link is a flex item |
|||
of the row; grow:0 so a short title doesn't stretch (the chevron stays right |
|||
after it), shrink:1 + min-width:0 so a long title wraps. */ |
|||
.vector-toc .vector-toc-link { flex: 1 1 auto; min-width: 0; } |
|||
.vector-toc .vector-toc-list-item:has(> .vector-toc-toggle) > .vector-toc-link { |
|||
max-width: calc(100% - 1.5em); |
|||
} |
|||
.vector-toc .vector-toc-text { |
|||
display: flex; |
|||
align-items: baseline; |
|||
} |
|||
.vector-toc .vector-toc-numb { |
|||
flex: 0 0 auto; /* the number column = its own width */ |
|||
display: inline; /* defeat Vector's display:none */ |
|||
margin-right: 0.4em; |
|||
white-space: nowrap; |
|||
font-variant-numeric: tabular-nums; |
|||
} |
|||
.vector-toc .vector-toc-numb::after { content: "."; } |
|||
/* the title span is unclassed in Vector's DOM; it is the wrapping block */ |
|||
.vector-toc .vector-toc-text > span:not(.vector-toc-numb) { |
|||
flex: 1 1 auto; |
|||
min-width: 0; /* allow the title to wrap inside the row */ |
|||
} |
|||
/* "0." for Beginning — it has no numb span, so generate it as the FIRST flex |
|||
item of its text row; same number voice, ink + medium when active */ |
|||
.vector-toc #toc-mw-content-text .vector-toc-text::before { |
|||
content: "0."; |
|||
flex: 0 0 auto; |
|||
margin-right: 0.4em; |
|||
white-space: nowrap; |
|||
font-variant-numeric: tabular-nums; |
|||
color: var(--ed-ink); |
|||
} |
|||
.vector-toc #toc-mw-content-text.vector-toc-list-item-active .vector-toc-text::before { |
|||
font-weight: 500; |
|||
} |
|||
/* chevron: an in-flow disclosure triangle right AFTER the title — a flex item of |
|||
the row, baseline-aligned to the first line. The Codex icon is replaced by a |
|||
::before glyph switched on the expanded state; font-size:0 hides the |
|||
screen-reader span without removing it. All button chrome (background, border, |
|||
focus ring) is stripped so only the bare ▸/▾ glyph ever shows. */ |
|||
.vector-toc .vector-toc-toggle { |
|||
position: static !important; /* ← ADD THIS */ |
|||
flex: 0 0 auto; |
|||
margin: 0 0 0 0.35em !important; |
|||
min-width: 0 !important; |
|||
min-height: 0 !important; |
|||
width: auto !important; |
|||
height: auto !important; |
|||
padding: 0 !important; |
|||
border: none !important; |
|||
background: none !important; |
|||
box-shadow: none !important; /* kill Codex's teal focus ring (the "blue rectangle") */ |
|||
outline: none !important; |
|||
/* NB: do NOT put font-size:0 on the button — as a baseline-aligned flex item |
|||
that collapses its baseline to the top and floats the glyph ABOVE the line. |
|||
Keep the inherited font-size; hide the inner spans instead (below). */ |
|||
} |
|||
/* Codex re-applies the ring / background on every interaction state — neutralise |
|||
them all so only the bare ▸/▾ glyph ever shows (these come AFTER the section's |
|||
.cdx-button:focus rule, so they win the tie). */ |
|||
.vector-toc .vector-toc-toggle:hover, |
|||
.vector-toc .vector-toc-toggle:focus, |
|||
.vector-toc .vector-toc-toggle:focus-visible, |
|||
.vector-toc .vector-toc-toggle:active { |
|||
background: none !important; |
|||
border: none !important; |
|||
box-shadow: none !important; |
|||
outline: none !important; |
|||
} |
|||
/* hide the Codex icon span and zero the screen-reader label span (font-size:0, |
|||
not display:none, so assistive tech keeps it); the ::before glyph below is the |
|||
only visible chevron */ |
|||
.vector-toc .vector-toc-toggle .vector-icon { display: none; } |
|||
.vector-toc .vector-toc-toggle > span { font-size: 0; } |
|||
.vector-toc .vector-toc-toggle::before { |
|||
content: "▸"; /* collapsed — the house triangle */ |
|||
font-size: 0.65rem; |
|||
color: var(--ed-faint); |
|||
} |
|||
.vector-toc .vector-toc-list-item-expanded > .vector-toc-toggle::before { |
|||
content: "▾"; /* expanded */ |
|||
} |
|||
.vector-toc .vector-toc-toggle:hover::before { color: var(--ed-ink); } |
|||
/* ── Infobox: the page's ONE white card, in the data voice; its width |
|||
is the SAME token the prose measure subtracts, ENFORCED with |
|||
!important so inline widths cannot break the axis — and pinned |
|||
class-generically so ANY infobox markup (table or div) obeys. ── */ |
|||
.mw-parser-output .infobox { /* class-generic: any infobox markup */ |
|||
width: var(--ed-infobox-w) !important; |
|||
box-sizing: border-box; |
|||
} |
|||
.mw-parser-output table.infobox { |
|||
font-family: var(--ed-sans); |
|||
font-size: var(--ed-small); |
|||
background-color: #fff !important; |
|||
border: 1px solid var(--ed-hairline) !important; |
|||
padding: 0.55em 0.9em 0.75em; |
|||
line-height: 1.5; |
|||
} |
|||
.infobox .infobox-above { |
|||
background-color: #fff !important; /* beats the template's inline #cee0f2 */ |
|||
color: var(--ed-secondary) !important; /* beats inline color:inherit */ |
|||
text-align: left !important; |
|||
font-size: 0.75rem; /* the shared eyebrow size */ |
|||
font-weight: 600; |
|||
letter-spacing: 0.08em; |
|||
text-transform: uppercase; |
|||
border-bottom: 1px solid var(--ed-ink); |
|||
padding: 0.2em 0.2em 0.55em; |
|||
} |
|||
.infobox .infobox-label { |
|||
color: var(--ed-secondary); |
|||
font-weight: 400; |
|||
padding: 0.22em 0.8em 0.22em 0.2em; |
|||
} |
|||
.infobox .infobox-data { color: var(--ed-ink); padding: 0.22em 0.2em; } |
|||
/* ── Blockquotes: coral bar, serif italic (future-proofing — the emitter |
|||
currently renders quotes as "> ..." list items) ── */ |
|||
.mw-parser-output blockquote { |
|||
border-left: 3px solid var(--ed-accent); |
|||
padding: 0.2em 0 0.2em 1.2em; |
|||
margin: 1.2em 0; |
|||
margin-left: 2px !important; /* sit the coral bar on the bullet axis. Two jobs: |
|||
(1) override MediaWiki/Parsoid core content |
|||
styles that otherwise indent the blockquote; |
|||
(2) +2px optical nudge so the straight 3px bar's |
|||
left edge lines up with the round bullet's visual |
|||
left edge (a bar and a dot share no geometric |
|||
edge). Dial to 1px if it ever overshoots */ |
|||
color: var(--ed-secondary); |
|||
font-style: italic; |
|||
} |
|||
/* ── Footer + page-bottom cleanup. Vector ships `.mw-footer li |
|||
{ font-size: 0.75em }`, which COMPOUNDS with any footer size — |
|||
the rem on the li kills the compounding; footer now matches |
|||
the TOC exactly ── */ |
|||
@media screen { |
|||
.printfooter { display: none; } /* "Retrieved from ..." clutter; stays in print */ |
|||
} |
|||
#footer, .mw-footer, .minerva-footer { |
|||
font-family: var(--ed-sans); |
|||
color: var(--ed-faint); |
|||
border-top: 1px solid var(--ed-ink) !important; |
|||
} |
|||
#footer li, .mw-footer li { font-size: var(--ed-small); } |
|||
#footer a, #footer a:visited, |
|||
.mw-footer a, .mw-footer a:visited { color: var(--ed-secondary) !important; } |
|||
/* ── AI assistant panel on the theme: warm card, serif answers, |
|||
teal send button (later !important wins the ties vs section 8) ── */ |
|||
.ext-aiassistant-panel { border: 1px solid var(--ed-hairline-strong) !important; } |
|||
/* ONE sans for the whole panel UI (the extension ships its own stack); |
|||
the assistant-message serif rule below this still wins for answers */ |
|||
.ext-aiassistant-panel, |
|||
.ext-aiassistant-panel input, |
|||
.ext-aiassistant-panel textarea, |
|||
.ext-aiassistant-panel button { font-family: var(--ed-sans) !important; } |
|||
.ext-aiassistant-header { border-bottom: 1px solid var(--ed-hairline) !important; } |
|||
.ext-aiassistant-message-user .ext-aiassistant-message__content { |
|||
background-color: var(--ed-ink) !important; |
|||
} |
|||
.ext-aiassistant-message-assistant { |
|||
font-family: var(--ed-serif) !important; |
|||
color: var(--ed-ink) !important; |
|||
} |
|||
.ext-aiassistant-footer { |
|||
border-top: 1px solid var(--ed-hairline) !important; |
|||
background-color: var(--ed-paper) !important; |
|||
} |
|||
/* ONE focus ring around the whole composer (input + send button); the |
|||
text field itself stays borderless — the panel's input is exempted |
|||
from the generic Codex focus rule above */ |
|||
.ext-aiassistant-panel .cdx-text-input__input, |
|||
.ext-aiassistant-panel .cdx-text-input__input:focus, |
|||
.ext-aiassistant-prompt-composer__input, |
|||
.ext-aiassistant-prompt-composer__input:focus { |
|||
border-color: transparent !important; |
|||
box-shadow: none !important; |
|||
outline: none !important; |
|||
} |
|||
.ext-aiassistant-prompt-composer { box-shadow: none !important; } |
|||
.ext-aiassistant-prompt-composer:focus-within { |
|||
outline: 1px solid var(--ed-link) !important; |
|||
outline-offset: -1px; |
|||
box-shadow: none !important; |
|||
} |
|||
.ext-aiassistant-prompt-composer__send:not(:disabled) { |
|||
background-color: var(--ed-link) !important; |
|||
border-color: var(--ed-link) !important; |
|||
} |
|||
.ext-aiassistant-prompt-composer__send:disabled { |
|||
background-color: var(--ed-hairline) !important; |
|||
border-color: var(--ed-hairline) !important; |
|||
} |
|||
.ext-aiassistant-panel .cdx-button--weight-quiet:not(.cdx-button--icon-only)::before { |
|||
color: var(--ed-link) !important; |
|||
} |
|||
/* citation chips in the theme's interactive teal, like article links */ |
|||
.ext-aiassistant-cite, |
|||
.ext-aiassistant-cite a { color: var(--ed-link) !important; } |
|||
/* ── Inline footnotes ({{footnote}} → <span class="ed-fn" title="…">). |
|||
A small dotted-underline "note" chip after the term. The note lives |
|||
in the title="" attribute, so on DESKTOP the browser's NATIVE tooltip |
|||
shows it on hover — and a native tooltip is rendered above the whole |
|||
page, so it can never be covered by the frozen table column or clipped |
|||
by the table's scroll (the bug an in-page card kept hitting). On TOUCH |
|||
devices (no hover) a CSS bubble is synthesised from attr(title) on |
|||
tap/focus. NO JavaScript. The note is ALSO kept in a hidden |
|||
"(footnote: …)" span so the bot reads it from the DOM (Docling ignores |
|||
title attributes) — readers and RAG see different things from one |
|||
markup. ── */ |
|||
.ed-fn { cursor: help; } |
|||
.ed-fn-chip::after { |
|||
content: "note"; |
|||
font-family: var(--ed-sans); |
|||
font-size: 0.7em; |
|||
vertical-align: super; |
|||
color: var(--ed-faint); |
|||
text-decoration: underline dotted; |
|||
text-underline-offset: 2px; |
|||
white-space: nowrap; |
|||
} |
|||
.ed-fn:hover .ed-fn-chip::after { color: var(--ed-link); } |
|||
/* in the DOM for the bot; never shown to readers as inline text */ |
|||
.ed-fn-body { display: none; } |
|||
/* The touch note banner. Created by MediaWiki:Common.js and appended to |
|||
<body> — so it lives in the ROOT stacking context and NO table sticky column |
|||
(or any overlay) can ever cover it, which a CSS ::after on the in-table cue |
|||
could not guarantee. Full-width, pinned to the top, white on near-black. The |
|||
z-index is belt-and-suspenders; being a child of <body> is what truly wins. |
|||
Desktop keeps the browser's native title tooltip (the cue still carries |
|||
title=""); this banner only appears on touch. */ |
|||
.ed-fn-banner { |
|||
position: fixed; |
|||
top: 0; |
|||
left: 0; |
|||
right: 0; |
|||
z-index: 2147483647; |
|||
box-sizing: border-box; |
|||
padding: calc(0.9em + env(safe-area-inset-top)) 1.2em 0.9em; |
|||
background: rgba(20, 18, 16, 0.92); /* near-black, slightly transparent */ |
|||
color: #fff; |
|||
font-family: var(--ed-sans); |
|||
font-size: 0.95rem; |
|||
line-height: 1.5; |
|||
text-align: left; |
|||
/* pre-line: collapse runs of spaces but KEEP newlines, so a multi-point |
|||
footnote ("• a • b") shows each bullet on its own line. */ |
|||
white-space: pre-line; |
|||
} |
|||
/* The desktop hover popover (also created in Common.js, appended to <body>). |
|||
A small light card beside the cue — white, coral left rule, serif — in the |
|||
editorial voice. pointer-events:none so it never steals the hover it reports. */ |
|||
.ed-fn-popover { |
|||
position: fixed; |
|||
z-index: 2147483647; |
|||
max-width: min(28rem, 90vw); |
|||
box-sizing: border-box; |
|||
padding: 0.6em 0.8em; |
|||
background: #fff; |
|||
color: var(--ed-ink); |
|||
border: 1px solid var(--ed-hairline-strong); |
|||
border-left: 3px solid var(--ed-accent); |
|||
border-radius: 4px; |
|||
box-shadow: 0 4px 16px rgba(43, 41, 38, 0.18); |
|||
font-family: var(--ed-serif); |
|||
font-size: 0.9rem; |
|||
line-height: 1.45; |
|||
text-align: left; |
|||
/* pre-line: keep newlines so a multi-point footnote ("• a • b") shows |
|||
each bullet on its own line (matches .ed-fn-banner on mobile). */ |
|||
white-space: pre-line; |
|||
pointer-events: none; |
|||
} |
|||
/* ── Mobile ── */ |
|||
@media screen and (max-width: 768px) { |
|||
:root { --ed-measure: 100%; } /* infobox is full-width on mobile */ |
|||
.mw-parser-output .infobox { width: 100% !important; } |
|||
h1#firstHeading, .mw-first-heading { font-size: 1.7rem; } |
|||
.mw-body-content h2, .mw-body-content .mw-heading2 { font-size: 1.22rem; } |
|||
.ext-aiassistant-prompt-composer { border-bottom: 1px solid var(--ed-hairline) !important; } |
|||
} |
|||
Revision as of 19:07, 22 June 2026
/* Any JavaScript here will be loaded for all users on every page load. */
/**
* Keep code in MediaWiki:Common.js to a minimum as it is unconditionally
* loaded for all users on every wiki page. If possible create a gadget that is
* enabled by default instead of adding it here (since gadgets are fully
* optimized ResourceLoader modules with possibility to add dependencies etc.)
*
* Since Common.js isn't a gadget, there is no place to declare its
* dependencies, so we have to lazy load them with mw.loader.using on demand and
* then execute the rest in the callback. In most cases these dependencies will
* be loaded (or loading) already and the callback will not be delayed. In case a
* dependency hasn't arrived yet it'll make sure those are loaded before this.
*/
/* global mw, $ */
/* jshint strict:false, browser:true */
mw.loader.using( [ 'mediawiki.util' ] ).done( function () {
/* Begin of mw.loader.using callback */
/**
* Map addPortletLink to mw.util
* @deprecated: Use mw.util.addPortletLink instead.
*/
mw.log.deprecate( window, 'addPortletLink', mw.util.addPortletLink, 'Use mw.util.addPortletLink instead' );
/**
* @source https://www.mediawiki.org/wiki/Snippets/Load_JS_and_CSS_by_URL
* @rev 6
*/
var extraCSS = mw.util.getParamValue( 'withCSS' ),
extraJS = mw.util.getParamValue( 'withJS' );
if ( extraCSS ) {
if ( extraCSS.match( /^MediaWiki:[^&<>=%#]*\.css$/ ) ) {
mw.loader.load( '/w/index.php?title=' + extraCSS + '&action=raw&ctype=text/css', 'text/css' );
} else {
mw.notify( 'Only pages from the MediaWiki namespace are allowed.', { title: 'Invalid withCSS value' } );
}
}
if ( extraJS ) {
if ( extraJS.match( /^MediaWiki:[^&<>=%#]*\.js$/ ) ) {
mw.loader.load( '/w/index.php?title=' + extraJS + '&action=raw&ctype=text/javascript' );
} else {
mw.notify( 'Only pages from the MediaWiki namespace are allowed.', { title: 'Invalid withJS value' } );
}
}
/**
* Collapsible tables; reimplemented with mw-collapsible
* Styling is also in place to avoid FOUC
*
* Allows tables to be collapsed, showing only the header. See [[Help:Collapsing]].
* @version 3.0.0 (2018-05-20)
* @source https://www.mediawiki.org/wiki/MediaWiki:Gadget-collapsibleTables.js
* @author [[User:R. Koot]]
* @author [[User:Krinkle]]
* @author [[User:TheDJ]]
* @deprecated Since MediaWiki 1.20: Use class="mw-collapsible" instead which
* is supported in MediaWiki core. Shimmable since MediaWiki 1.32
*
* @param {jQuery} $content
*/
function makeCollapsibleMwCollapsible( $content ) {
var $tables = $content
.find( 'table.collapsible:not(.mw-collapsible)' )
.addClass( 'mw-collapsible' );
$.each( $tables, function ( index, table ) {
// mw.log.warn( 'This page is using the deprecated class collapsible. Please replace it with mw-collapsible.');
if ( $( table ).hasClass( 'collapsed' ) ) {
$( table ).addClass( 'mw-collapsed' );
// mw.log.warn( 'This page is using the deprecated class collapsed. Please replace it with mw-collapsed.');
}
} );
if ( $tables.length > 0 ) {
mw.loader.using( 'jquery.makeCollapsible' ).then( function () {
$tables.makeCollapsible();
} );
}
}
mw.hook( 'wikipage.content' ).add( makeCollapsibleMwCollapsible );
/**
* Add support to mw-collapsible for autocollapse, innercollapse and outercollapse
*
* Maintainers: TheDJ
*/
function mwCollapsibleSetup( $collapsibleContent ) {
var $element,
$toggle,
autoCollapseThreshold = 2;
$.each( $collapsibleContent, function ( index, element ) {
$element = $( element );
if ( $element.hasClass( 'collapsible' ) ) {
$element.find( 'tr:first > th:first' ).prepend( $element.find( 'tr:first > * > .mw-collapsible-toggle' ) );
}
if ( $collapsibleContent.length >= autoCollapseThreshold && $element.hasClass( 'autocollapse' ) ) {
$element.data( 'mw-collapsible' ).collapse();
} else if ( $element.hasClass( 'innercollapse' ) ) {
if ( $element.parents( '.outercollapse' ).length > 0 ) {
$element.data( 'mw-collapsible' ).collapse();
}
}
// because of colored backgrounds, style the link in the text color
// to ensure accessible contrast
$toggle = $element.find( '.mw-collapsible-toggle' );
if ( $toggle.length ) {
// Make the toggle inherit text color (Updated for T333357 2023-04-29)
if ( $toggle.parent()[ 0 ].style.color ) {
$toggle.css( 'color', 'inherit' );
$toggle.find( '.mw-collapsible-text' ).css( 'color', 'inherit' );
}
}
} );
}
mw.hook( 'wikipage.collapsibleContent' ).add( mwCollapsibleSetup );
/* End of mw.loader.using callback */
} );
// CapSach — Sticky TOC overlay (UNRESTRICTED: Works on iPad/Desktop/Mobile)
(function () {
// 1. REMOVED the "min-width: 768px" check. Now runs everywhere.
// Only run on pages where it makes sense (Articles/MainPage)
if (window.mw && mw.config && mw.config.get) {
var isAllowed = mw.config.get('wgIsArticle') || mw.config.get('wgIsMainPage');
if (!isAllowed) return;
}
// Find the content root; MobileFrontend restructures DOM, so be flexible
var root =
document.querySelector('#mw-content-text .mw-parser-output') ||
document.querySelector('.mw-parser-output') ||
document.getElementById('mw-content-text') ||
document.querySelector('#content') ||
document.body;
// Collect headings (H2–H6). Prefer spans with .mw-headline (stable anchor ids)
var items = [];
var headings = root.querySelectorAll('h2, h3, h4, h5, h6');
headings.forEach(function (h) {
var level = parseInt(h.tagName.slice(1), 10);
if (level < 2 || level > 6) return;
var headline = h.querySelector('.mw-headline') || h;
var id = headline.id || h.id;
var text = (headline.textContent || h.textContent || '').trim();
if (!id || !text) return;
items.push({ id: id, text: text, level: level });
});
// Show only if there are enough headings to be useful
// CHANGED: Lowered requirement to 1 heading so it always shows if there is any structure
if (items.length < 1) return;
// Create trigger button (bottom-left; avoids “Back to top” on bottom-right)
var btn = document.createElement('button');
btn.id = 'cps-open-toc';
btn.type = 'button';
btn.setAttribute('aria-label', 'Open table of contents');
btn.innerHTML = '<span class="icon" aria-hidden="true">≡</span><span class="label">TOC</span>';
document.body.appendChild(btn);
// Overlay + panel
var overlay = document.createElement('div');
overlay.id = 'cps-toc-overlay';
overlay.setAttribute('aria-hidden', 'true');
var panel = document.createElement('div');
panel.id = 'cps-toc-panel';
panel.setAttribute('role', 'dialog');
panel.setAttribute('aria-modal', 'true');
panel.setAttribute('aria-label', 'Table of contents');
var header = document.createElement('div');
header.id = 'cps-toc-header';
header.innerHTML =
'<h2 id="cps-toc-title">Contents</h2>' +
'<button id="cps-toc-close" type="button" aria-label="Close">×</button>';
var list = document.createElement('ul');
list.id = 'cps-toc-list';
items.forEach(function (it) {
var li = document.createElement('li');
li.setAttribute('data-level', String(it.level));
var a = document.createElement('a');
a.href = '#' + it.id;
a.textContent = it.text;
li.appendChild(a);
list.appendChild(li);
});
panel.appendChild(header);
panel.appendChild(list);
overlay.appendChild(panel);
document.body.appendChild(overlay);
// Focus handling
var lastFocus = null;
function openOverlay() {
lastFocus = document.activeElement;
overlay.classList.add('is-open');
overlay.setAttribute('aria-hidden', 'false');
document.body.style.overflow = 'hidden';
// Focus first link for accessibility
var firstLink = list.querySelector('a');
if (firstLink) firstLink.focus({ preventScroll: true });
}
function closeOverlay() {
overlay.classList.remove('is-open');
overlay.setAttribute('aria-hidden', 'true');
document.body.style.overflow = '';
if (lastFocus && lastFocus.focus) lastFocus.focus({ preventScroll: true });
}
// Force button display immediately
btn.style.display = 'flex';
btn.addEventListener('click', openOverlay);
overlay.addEventListener('click', function (e) {
// Click outside the bottom sheet closes
if (e.target === overlay) closeOverlay();
});
overlay.querySelector('#cps-toc-close').addEventListener('click', closeOverlay);
overlay.addEventListener('keydown', function (e) {
if (e.key === 'Escape') closeOverlay();
});
// Navigate and try to ensure mobile-collapsed sections are visible
// Navigate and try to ensure mobile-collapsed sections are visible
list.addEventListener('click', function (e) {
var a = e.target.closest('a');
if (!a) return;
e.preventDefault();
var targetId = a.getAttribute('href').slice(1);
// === NEW LOGIC START: Scroll to Top for "Contents" ===
// If the user clicks the "Contents" header (id="mw-toc-heading"), scroll to top (0,0)
// === FIXED CODE ===
if (targetId === 'mw-toc-heading') {
closeOverlay();
// Delay scroll to let iOS Safari process the overflow change
setTimeout(function() {
try {
window.scrollTo({ top: 0, behavior: 'smooth' });
} catch (e) {
window.scrollTo(0, 0);
}
// Fallback for older iOS Safari
document.documentElement.scrollTop = 0;
document.body.scrollTop = 0;
}, 100);
if (history.replaceState) {
history.replaceState(null, '', window.location.pathname + window.location.search);
}
return;
}
// === NEW LOGIC END ===
var target = document.getElementById(targetId);
closeOverlay();
if (target) {
try {
target.scrollIntoView({ behavior: 'smooth', block: 'start' });
} catch (_) {
target.scrollIntoView(true);
}
// Update URL hash after a tick (so browser back works)
setTimeout(function () {
if (history && history.replaceState) {
history.replaceState(null, '', '#' + targetId);
} else {
location.hash = targetId;
}
}, 200);
// MobileFrontend: headings may be inside collapsed sections.
// Heuristic: click the nearest toggle if present.
var maybeToggle = target.closest('.collapsible-block, .mf-section') ||
target.closest('section');
if (maybeToggle && maybeToggle.classList.contains('collapsed')) {
// Try to open; fallback by clicking the first heading inside
var headingToggle = maybeToggle.querySelector('.section-heading, h2, h3, h4, h5, h6');
if (headingToggle) headingToggle.click();
}
}
});
// 2. REMOVED the "resize" event listener that was hiding the button.
// The button now persists on all screen sizes.
})();
/* Script for Inline Expandable Template */
$(function() {
$('.inline-expand-trigger').on('click', function() {
// 1. Toggle the content visibility
$(this).next('.inline-expand-content').toggle();
// 2. Toggle the arrow icon
const currentText = $(this).text();
$(this).text(
currentText.includes('▸') ? currentText.replace('▸', '◂') : currentText.replace('◂', '▸')
);
});
});
$(document).ready(function() {
// Check if the button already exists to prevent duplicates
if ($('#custom-email-btn').length === 0) {
// Create the email button element
var emailBtn = $('<a>', {
id: 'custom-email-btn',
href: 'mailto:bananabot@axabrain.com',
// Simple accessible title
title: 'Contact AXA BRAIN Services'
});
// Add it to the body of the page
$('body').append(emailBtn);
}
});
/* Open AXA BRAIN AI Assistant when clicking the logo */
$(document).ready(function() {
$('.fullscreen-logo').css('cursor', 'pointer').click(function(e) {
e.preventDefault();
// Method 1: Click the AI Assistant floating icon
var $aiButton = $('img[src*="ai-icon.png"]').closest('div, button, a');
if ($aiButton.length > 0) {
$aiButton.trigger('click');
return;
}
// Method 2: Try the extension's trigger class
var $trigger = $('.ext-aiassistant-trigger, .ext-aiassistant');
if ($trigger.length > 0) {
$trigger.first().trigger('click');
return;
}
console.log("AXA BRAIN Assistant button not found on this page.");
});
});
/* Inline footnotes ({{footnote}}). We render the note OURSELVES, appended to
<body> (the ROOT stacking context), so a table's sticky column can never
cover it and it behaves identically across browsers. The native title=""
tooltip is unreliable + unstyled, so we move it to data-fn (the bot still
reads the hidden .ed-fn-body span) and show:
- PHONE (no hover): tap a cue -> full-width banner at the top; tap to dismiss.
- DESKTOP (hover): hover a cue -> a small popover beside the cue.
If this script never runs, the title="" stays and the native tooltip is the
graceful fallback. */
(function () {
var cues = document.querySelectorAll('.ed-fn');
if (!cues.length) { return; }
// Suppress the native tooltip; keep the note text in data-fn.
Array.prototype.forEach.call(cues, function (el) {
if (el.hasAttribute('title')) {
el.setAttribute('data-fn', el.getAttribute('title'));
el.removeAttribute('title');
}
});
var box = null, activeCue = null;
function noteOf(el) { return el.getAttribute('data-fn') || ''; }
function cueOf(e) {
var t = e.target;
return (t && t.closest) ? t.closest('.ed-fn') : null;
}
function close() {
if (box) { box.remove(); box = null; }
activeCue = null;
document.removeEventListener('click', onAway, true);
}
function onAway(e) {
if (!cueOf(e)) { close(); }
}
var touch = window.matchMedia && window.matchMedia('(hover: none)').matches;
if (touch) {
// Phone: full-width banner pinned to the top; the next tap anywhere dismisses.
document.addEventListener('click', function (e) {
var cue = cueOf(e);
if (!cue) { return; }
e.preventDefault();
var txt = noteOf(cue);
if (!txt) { return; }
e.stopPropagation();
close();
box = document.createElement('div');
box.className = 'ed-fn-banner';
box.textContent = txt;
document.body.appendChild(box);
setTimeout(function () {
document.addEventListener('click', onAway, true);
}, 0);
}, false);
} else {
// Desktop: a styled popover beside the cue while hovering it.
document.addEventListener('mouseover', function (e) {
var cue = cueOf(e);
if (!cue || cue === activeCue) { return; }
var txt = noteOf(cue);
if (!txt) { return; }
close();
activeCue = cue;
box = document.createElement('div');
box.className = 'ed-fn-popover';
box.textContent = txt;
document.body.appendChild(box);
var r = cue.getBoundingClientRect();
var left = Math.max(8, Math.min(r.left, window.innerWidth - box.offsetWidth - 8));
var top = r.top - box.offsetHeight - 8; // above the cue...
if (top < 8) { top = r.bottom + 8; } // ...or below if no room
box.style.left = left + 'px';
box.style.top = top + 'px';
});
document.addEventListener('mouseout', function (e) {
if (!activeCue) { return; }
var to = e.relatedTarget;
if (to && to.closest && to.closest('.ed-fn') === activeCue) { return; }
close();
});
window.addEventListener('scroll', function () { if (box) { close(); } }, true);
}
})();
/* ── Datacheck confirm/correct gadget ───────────────────────────────────────
On a Datacheck: page (namespace 3006), turn each Module:ReportedTable row's
.rt-confirm control into Confirm (toggle) + Reject/Correct (enter a number),
writing the verdict straight into the underlying Data:<...>.json page under the
REVIEWER'S OWN session (no bot creds). DOM order of .rt-confirm == records[]
order (the module emits exactly one per record); the exact Data title comes
from the hidden .rt-data-title marker. Verdicts survive a re-publish via
wiki_extract.merge_verdicts (value-gated). Anonymous users see read-only marks. */
$(function () {
if (!(window.mw && mw.config) || mw.config.get('wgNamespaceNumber') !== 3006) { return; }
var marker = document.querySelector('.rt-data-title');
var spans = document.querySelectorAll('.rt-confirm');
if (!marker || !spans.length || !mw.config.get('wgUserName')) { return; }
var dataTitle = (marker.textContent || '').trim();
if (!dataTitle) { return; }
mw.loader.using(['mediawiki.api', 'mediawiki.notify']).done(function () {
var api = new mw.Api(), data = null, baseRevId = null;
function fetchAndRender() {
api.get({ action: 'query', prop: 'revisions', rvprop: 'content|ids',
rvslots: 'main', titles: dataTitle, formatversion: 2 }).done(function (res) {
var page = res.query && res.query.pages && res.query.pages[0];
var rev = page && page.revisions && page.revisions[0];
if (!rev) { mw.notify('Datacheck: data page not found — ' + dataTitle); return; }
baseRevId = rev.revid;
var content = rev.slots ? rev.slots.main.content : rev.content;
try { data = JSON.parse(content); }
catch (e) { mw.notify('Datacheck: bad JSON in ' + dataTitle); return; }
render();
}).fail(function (code) { mw.notify('Datacheck: load failed — ' + code); });
}
function save(okMsg) {
api.postWithEditToken({
action: 'edit', title: dataTitle, contentmodel: 'json',
text: JSON.stringify(data, null, 2),
summary: 'Datacheck: human verdict via confirm gadget', baserevid: baseRevId
}).done(function (res) {
if (res.edit && res.edit.newrevid) { baseRevId = res.edit.newrevid; }
render();
mw.notify(okMsg || 'Datacheck: saved.');
}).fail(function (code) {
if (code === 'editconflict') { mw.notify('Datacheck: edit conflict — reloading.'); fetchAndRender(); }
else { mw.notify('Datacheck: save failed — ' + code); }
});
}
// Clear every verdict field (keeps the JSON clean like the Python serializer), then set one.
function setStatus(rec, status, extra) {
delete rec.human_status; delete rec.confirmed_rev; delete rec.corrected_rev;
delete rec.override_reason; delete rec.alt_source;
if (status) { rec.human_status = status; for (var k in extra) { rec[k] = extra[k]; } }
}
function toggleConfirm(rec) {
if (rec.human_status === 'confirmed') { setStatus(rec, null); }
else { setStatus(rec, 'confirmed', { confirmed_rev: data.source_revision || null }); }
save();
}
function correctRow(rec) {
var hint = 'measure=' + rec.measure + ', scale=' + (rec.scale || 1) +
(rec.currency ? ', ' + rec.currency : '');
var entered = window.prompt(
'Correct value for "' + rec.label + '" [' + (rec.business_line || 'Total') + '/' +
(rec.business_unit || 'Group') + ']\n(' + hint + ' — enter the stored value):', String(rec.value));
if (entered === null) { return; }
var num = parseFloat(String(entered).replace(/[,\s]/g, ''));
if (isNaN(num)) { mw.notify('Datacheck: not a number — ' + entered); return; }
var reason = window.prompt('Reason (optional):', rec.override_reason || 'manual correction') || 'manual correction';
setStatus(rec, 'override', { value: num, corrected_rev: data.source_revision || null, override_reason: reason });
save('Datacheck: override saved (' + num + ').');
}
function render() {
if (!data || !data.records) { return; }
if (spans.length !== data.records.length) {
mw.notify('Datacheck: table out of sync with the data page — reload the page.'); return;
}
Array.prototype.forEach.call(spans, function (span, i) {
var rec = data.records[i], status = rec.human_status || null;
span.innerHTML = '';
var ok = document.createElement('a');
ok.href = '#'; ok.textContent = (status === 'confirmed') ? '✓' : '○';
ok.title = (status === 'confirmed') ? 'Confirmed — click to un-confirm' : 'Click to confirm';
ok.style.cssText = 'text-decoration:none;font-weight:bold;margin-right:8px;color:' +
(status === 'confirmed' ? '#137333' : '#999');
ok.onclick = function (e) { e.preventDefault(); toggleConfirm(rec); };
span.appendChild(ok);
var fix = document.createElement('a');
fix.href = '#'; fix.textContent = (status === 'override') ? ('✎ ' + rec.value) : '✎';
fix.title = 'Reject + enter the correct number';
fix.style.cssText = 'text-decoration:none;color:' + (status === 'override' ? '#b06000' : '#999');
fix.onclick = function (e) { e.preventDefault(); correctRow(rec); };
span.appendChild(fix);
if (status === 'corrected') {
var c = document.createElement('span'); c.textContent = ' (corrected)';
c.style.color = '#137333'; span.appendChild(c);
}
});
}
fetchAndRender();
});
});