MediaWiki:Common.css: Difference between revisions
Apply westeros dark theme (automated) |
Apply westeros dark theme (automated) |
||
| Line 443: | Line 443: | ||
html body .vector-pinnable-header-pin-button { | html body .vector-pinnable-header-pin-button { | ||
display: none !important; | display: none !important; | ||
} | |||
/* ── Auto-published page infobox ───────────────────────────────────────── | |||
* Every TownyExtras-published page (towns/players/nations/houses/events/ | |||
* ravens) emits a {| class="te-infobox" |} table — this styles it as the | |||
* Wikipedia-style right-hand card: floated right, panel background, gold | |||
* centered title, compact label/value rows. Emitters: WikiMarkup.java. */ | |||
.te-infobox { | |||
float: right; | |||
clear: right; | |||
width: 300px; | |||
margin: 0.25rem 0 1.25rem 1.75rem; | |||
background: var(--wiki-panel) !important; | |||
border: 1px solid var(--wiki-rule) !important; | |||
border-radius: 8px; | |||
border-collapse: separate; | |||
border-spacing: 0; | |||
padding: 10px 14px 12px; | |||
font-size: 0.92em; | |||
line-height: 1.45; | |||
} | |||
.te-infobox th, | |||
.te-infobox td { | |||
background: transparent !important; | |||
border: none !important; | |||
padding: 3px 0; | |||
text-align: left; | |||
vertical-align: top; | |||
} | |||
.te-infobox th { | |||
color: var(--wiki-muted) !important; | |||
font-weight: bold; | |||
white-space: nowrap; | |||
padding-right: 14px; | |||
width: 1%; | |||
} | |||
.te-infobox th.te-infobox-title { | |||
width: auto; | |||
white-space: normal; | |||
text-align: center; | |||
color: var(--wiki-gold) !important; | |||
font-size: 1.25em; | |||
padding: 2px 0 6px; | |||
border-bottom: 1px solid var(--wiki-rule) !important; | |||
} | |||
.te-infobox td.te-infobox-sub { | |||
text-align: center; | |||
color: var(--wiki-muted) !important; | |||
padding: 4px 0 2px; | |||
} | |||
.te-infobox td.te-infobox-image { | |||
text-align: center; | |||
padding: 8px 0 10px; | |||
} | |||
.te-infobox td.te-infobox-image img { | |||
image-rendering: pixelated; | |||
height: auto; | |||
max-width: 100%; | |||
} | |||
/* On phones the floated card would squeeze the text to a sliver — let it | |||
* sit full-width above the lead instead. */ | |||
@media (max-width: 999px) { | |||
.te-infobox { | |||
float: none; | |||
width: 100%; | |||
margin: 0 0 1rem; | |||
box-sizing: border-box; | |||
} | |||
} | |||
/* ── Make content links visibly links ──────────────────────────────────── | |||
* Gold alone wasn't enough to distinguish links from headings/labels | |||
* (owner feedback 2026-07-21) — underline every link in the article body. | |||
* Nav/sidebar/tabs stay underline-free (they're outside .mw-body-content). */ | |||
.mw-body-content a { | |||
text-decoration: underline !important; | |||
text-underline-offset: 3px; | |||
text-decoration-thickness: 1px; | |||
} | |||
.mw-editsection a { | |||
text-decoration: none !important; | |||
} | |||
/* Links to pages that don't exist yet ("red links") — MediaWiki's default | |||
* red is unreadable on this dark palette; use a muted brick tone that still | |||
* clearly says "this page is missing" next to the gold of real links. */ | |||
.mw-body-content a.new { | |||
color: #cf7a66 !important; | |||
} | } | ||
Revision as of 19:18, 21 July 2026
/* Dark theme, inlined into every page's <head> via a BeforePageDisplay
* hook in LocalSettings.php (see ops/wiki/scripts/apply_wiki_skin.sh —
* MediaWiki:Common.css alone doesn't reliably apply on this install, a
* ResourceLoader quirk only caught by rendering with a real headless
* browser). Matches guide.westeros.live's Georgia serif / gold-parchment
* look. Palette source of truth: web/guide-site/index.html — keep both
* in sync if the guide site's colors ever change.
*
* All colors are CSS custom properties below — change a value here and
* re-dispatch {"action": "apply_skin"} to repaint the whole wiki. No need
* to touch any of the selector rules further down.
*/
:root {
color-scheme: dark;
--wiki-bg: #14110f; /* page background */
--wiki-panel: #1c1815; /* header/TOC/table/input chrome background */
--wiki-ink: #f5f0e6; /* body text — bright, for readability against --wiki-bg */
--wiki-muted: #c2b394; /* de-emphasized text (footer, edit-section links) */
--wiki-gold: #d4af5a; /* headings, links */
--wiki-gold-hover: #f5f0e6; /* link hover — swaps to --wiki-ink for contrast */
--wiki-rule: #4a3f33; /* borders/dividers */
}
body,
.skin-vector,
.mw-page-container {
background: var(--wiki-bg) !important;
color: var(--wiki-ink) !important;
font-family: Georgia, 'Times New Roman', serif !important;
}
#content,
.vector-body,
.mw-body,
.vector-menu-content,
.vector-page-toolbar,
.vector-sitenotice-container {
background: var(--wiki-bg) !important;
color: var(--wiki-ink) !important;
border-color: var(--wiki-rule) !important;
}
.mw-body {
border: 1px solid var(--wiki-rule) !important;
}
.vector-header-container,
.vector-header,
.vector-pinnable-header,
.vector-menu-heading,
#p-logo-text,
.vector-sticky-pinned-container {
background: var(--wiki-panel) !important;
color: var(--wiki-ink) !important;
}
h1, h2, h3, h4, h5, h6,
.mw-first-heading,
.vector-menu-heading-label {
color: var(--wiki-gold) !important;
border-color: var(--wiki-rule) !important;
}
a, a:visited {
color: var(--wiki-gold) !important;
}
a:hover {
color: var(--wiki-gold-hover) !important;
}
.mw-editsection a { color: var(--wiki-muted) !important; }
pre, code, .mw-code {
background: var(--wiki-panel) !important;
color: var(--wiki-ink) !important;
border: 1px solid var(--wiki-rule) !important;
}
table, .wikitable {
background: var(--wiki-panel) !important;
color: var(--wiki-ink) !important;
border-color: var(--wiki-rule) !important;
}
.wikitable > tr > th,
.wikitable > * > tr > th {
background: var(--wiki-panel) !important;
color: var(--wiki-gold) !important;
border-color: var(--wiki-rule) !important;
}
.wikitable > tr > td,
.wikitable > * > tr > td {
border-color: var(--wiki-rule) !important;
}
input, textarea, select, .cdx-text-input__input {
background: var(--wiki-panel) !important;
color: var(--wiki-ink) !important;
border-color: var(--wiki-rule) !important;
}
.vector-menu-tabs,
.vector-menu-dropdown,
.vector-dropdown-content {
background: var(--wiki-panel) !important;
color: var(--wiki-ink) !important;
}
.mw-footer, #footer {
background: var(--wiki-bg) !important;
color: var(--wiki-muted) !important;
border-color: var(--wiki-rule) !important;
}
/* The "Category: X" bar at the bottom of a page (#catlinks) is a
* separate element from the footer proper — missed in the first
* dark-theme pass, confirmed live rendering as a plain white box (a
* hardcoded light background in Vector's own CSS, same pattern as the
* footer text color miss above). */
#catlinks {
background: var(--wiki-panel) !important;
color: var(--wiki-ink) !important;
border-color: var(--wiki-rule) !important;
}
#catlinks a {
color: var(--wiki-gold) !important;
}
/* Vector's own footer CSS sets an explicit near-black color directly on
* #footer-info li / #footer-places li — more specific than our bare
* #footer rule above, so it was winning despite our !important
* (confirmed live: "This page was last edited on..." etc. rendered at
* contrast ~15 against our dark background, effectively invisible). */
#footer-info *, #footer-places *, #footer-icons a {
color: var(--wiki-muted) !important;
}
/* Hide the per-page auto-generated Table of Contents entirely, site-wide
* -- not just on Main_Page (the old __NOTOC__ fix), since the same "a
* sections box floats in the middle of the page" complaint applies to
* event pages and Category pages too, and the real persistent sidebar
* nav already covers site-wide navigation. Simpler and more robust than
* hunting down every page type that can generate one. */
#vector-toc-pinned-container,
.vector-toc-landmark,
#vector-toc {
display: none !important;
}
/* Hiding the TOC's own content isn't enough on its own — Vector's page
* grid (.mw-page-container-inner) reserves an entire grid COLUMN
* (.vector-column-start) for it, sized independently of whether
* anything's actually inside; with only the inner content hidden, that
* column stayed in the layout as a large empty gap between the sidebar
* and the real content box (confirmed live via getBoundingClientRect on
* a real event page — an empty .vector-column-start still ~412px tall).
* Collapsing the grid item itself and forcing the grid to a single
* content column removes the reservation entirely. */
.vector-column-start {
display: none !important;
}
.mw-page-container-inner {
grid-template-columns: minmax(0, 1fr) !important;
}
/* Table of contents (Vector 2022) + any other pinnable/Codex chrome —
* attribute-wildcard so new sub-elements in these components are covered
* without having to enumerate every exact class name. */
[class*="vector-toc"],
[class*="vector-pinnable"],
[class*="vector-pinned-container"],
[class*="vector-dropdown"] {
background: var(--wiki-panel) !important;
color: var(--wiki-ink) !important;
border-color: var(--wiki-rule) !important;
}
[class*="vector-toc"] a,
[class*="vector-pinnable"] a {
color: var(--wiki-ink) !important;
}
[class*="vector-toc"] a:hover,
[class*="vector-pinnable"] a:hover {
color: var(--wiki-gold) !important;
}
button, .cdx-button, .mw-ui-button, [class*="cdx-"] {
background: var(--wiki-panel) !important;
color: var(--wiki-ink) !important;
border-color: var(--wiki-rule) !important;
}
/* UI icons (hamburger, search, ellipsis "more", user/login, fullscreen,
* etc.) are served as background-image SVGs with a hardcoded fill="#000"
* baked into the image itself (confirmed by fetching the actual SVG from
* load.php) — a plain `color` override has zero effect on them, since
* that only works for mask-image-based icon techniques, not this one.
* Invert turns solid black (opaque) pixels white while leaving
* transparent regions transparent, which is exactly what these
* single-color glyphs need. Scoped to .vector-icon/.mw-ui-icon (Vector's
* own icon classes) — NOT any broader "icon" wildcard — so it can't
* accidentally invert something that's already correctly colored, like
* the real westeros.live site logo (.mw-logo-icon) or the plain <img>
* "Powered by MediaWiki" footer badge, neither of which carry these
* classes. */
.vector-icon,
.mw-ui-icon {
filter: invert(1) !important;
}
/* Higher-specificity re-declarations: some Codex/Vector component CSS is
* loaded after this stylesheet with equal specificity + !important, which
* wins on source order alone — `html body` prefixes beat that regardless
* of load order. */
html body button,
html body .cdx-button,
html body [class*="vector-toc"],
html body [class*="vector-pinnable"],
html body [class*="vector-pinned-container"] {
background: var(--wiki-panel) !important;
color: var(--wiki-ink) !important;
border-color: var(--wiki-rule) !important;
}
/* Kills fade/scroll-shadow pseudo-elements Vector draws around pinnable
* chrome (TOC, sticky sidebar) — some hardcode a white linear-gradient
* directly in their ::after, invisible to any class-name-based selector
* and only found by inspecting computed styles directly. */
[class*="vector-toc"]::before,
[class*="vector-toc"]::after,
[class*="vector-pinnable"]::before,
[class*="vector-pinnable"]::after,
[class*="vector-sticky"]::before,
[class*="vector-sticky"]::after {
background: none !important;
background-image: none !important;
}
.vector-sticky-pinned-container {
background: var(--wiki-panel) !important;
}
/* Always show the main menu (Explore: Events/Houses/Nations/Towns/Players)
* as a permanent left column for every visitor, instead of the collapsed
* hamburger dropdown Vector 2022 uses by default. Vector's own "move to
* sidebar" pin is a per-visitor, cookie/localStorage-based preference —
* unsuitable here since the user wants it on for everyone, always, with no
* dependency on a visitor's own browser state. This bypasses that pin
* mechanism entirely with plain CSS: the dropdown's content is always
* rendered, positioned as a fixed column, regardless of the checkbox/pin
* state underneath. */
@media (min-width: 1000px) {
#vector-main-menu-dropdown-checkbox {
display: none !important;
}
/* Gated on :not(.wiki-sidebar-hidden) — shown by default for every
* visitor, but the minimize toggle (sidebar-toggle.js) can opt a given
* visitor out for their session by adding that class to <html>. */
html:not(.wiki-sidebar-hidden) .vector-main-menu-dropdown .vector-dropdown-content {
display: block !important;
visibility: visible !important;
opacity: 1 !important;
position: fixed !important;
/* A small gutter from the viewport edge on all sides — flush against
* the raw browser edge (0/0) read as visually "slapped on," not an
* intentional panel; matching the content box's own bordered-card
* look (border on all sides, not just border-right) ties it together.
* !important on top/left/width is required here: Vector's own core
* CSS positions this dropdown via an ID-based selector
* (#vector-main-menu-dropdown .vector-dropdown-content), which beats
* a two-class selector on specificity alone regardless of source
* order — confirmed live these values were silently never applying
* (computed style kept showing Vector's own natural popup position,
* not ours) until marked !important, same as the other properties
* on this rule already are. */
/* Vector's header is 66px tall on this install (measured live via a
* headless-browser getBoundingClientRect(), not assumed) — a bare
* top:16px put the sidebar's own top 16-66px range directly under the
* header's DOM position but on top of it visually (this fixed element
* has no explicit z-index counterpart on the header, and z-index:100
* here beats the header's default auto stacking regardless of source
* order), covering the site logo/title. Start below the header instead. */
top: 82px !important;
/* left is independent of .mw-page-container's margin below — moving
* this only shifts the sidebar itself, never the content box. Measured
* live: the box's actual left edge sits at 272px regardless of this
* value, so 56px leaves a deliberate ~24px gap (not flush/touching)
* instead of the original 16px's ~56px gap. */
left: 56px !important;
width: 200px !important;
height: calc(100vh - 98px) !important;
overflow-y: auto;
padding: 1rem 0.75rem;
box-sizing: border-box;
background: var(--wiki-panel) !important;
border: 1px solid var(--wiki-rule) !important;
z-index: 100;
pointer-events: auto !important;
}
#vector-main-menu-unpinned-container {
display: block !important;
}
/* Only the "move to sidebar" pin button is hidden — the sidebar is
* always already shown, so that action is meaningless. The "hide"
* unpin button stays visible and doubles as the minimize control
* (wired up by sidebar-toggle.js) — shown by default, but the user
* gets an explicit way to collapse it. */
.vector-pinnable-header-pin-button {
display: none !important;
}
.vector-pinnable-header-unpin-button {
display: inline-block !important;
}
/* left gutter (16) + sidebar width (200) + a normal column-gap (24) —
* matching Vector's own --column-gap value elsewhere, instead of the
* much larger, purely incidental gap the first version of this left
* behind (sidebar margin-left plus leftover centering slack). */
html:not(.wiki-sidebar-hidden) .mw-page-container {
margin-left: 240px !important;
}
/* Explicit hidden state (html.wiki-sidebar-hidden, set by
* sidebar-toggle.js) — the :not() guards above already stop the
* always-on rules from applying, this just makes the intent visible
* as its own rule rather than relying purely on absence. */
html.wiki-sidebar-hidden .vector-main-menu-dropdown .vector-dropdown-content {
display: none !important;
}
/* Small reopen tab, shown only while the sidebar is minimized — sits
* flush at the same top offset the sidebar itself uses so it reads as
* "the sidebar collapsed to this," not an unrelated floating button. */
#wiki-sidebar-reopen-tab {
display: none;
position: fixed;
top: 82px;
left: 0;
z-index: 101;
background: var(--wiki-panel);
color: var(--wiki-ink);
border: 1px solid var(--wiki-rule);
border-left: none;
padding: 0.6rem 0.5rem;
cursor: pointer;
font-size: 1rem;
line-height: 1;
}
html.wiki-sidebar-hidden #wiki-sidebar-reopen-tab {
display: block;
}
/* Vector centers its fixed-width content column (.mw-body sets
* justify-content:center) in whatever space is left after the sidebar —
* with the sidebar taken out of grid flow above, that left Vector
* centering a large dead gap before the content box even starts, and
* what looked like the content's own internal padding was actually just
* leftover centering whitespace, not real padding — so it disappeared
* along with the gap. Left-align instead of centering, and give the
* content real, explicit padding so it doesn't depend on how much
* incidental whitespace centering happens to leave. */
.mw-body {
justify-content: flex-start !important;
/* #firstHeading lives in .vector-page-titlebar, a SIBLING of
* .mw-body-content — both children of this grid container — so
* padding has to go here, not on .mw-body-content alone, or the
* heading stays flush against the edge while only the body text
* gets breathing room (confirmed live: padding on .mw-body-content
* had zero effect on #firstHeading's position). */
padding: 0 2rem !important;
box-sizing: border-box !important;
}
}
/* Real mobile fix (confirmed live via Playwright at 375-414px and iPhone
* 12 emulation): Vector 2022 hardcodes .vector-header{min-width:500px} —
* a genuine desktop-only assumption unrelated to $wgVectorResponsive
* (that flag only affects the legacy Vector skin and the viewport meta
* tag; actual mobile-optimized layout normally comes from the separate
* MobileFrontend extension, not installed here). Below 500px viewport
* width this forces real horizontal page overflow and pushes the
* hamburger menu button off-screen entirely (confirmed: negative
* getBoundingClientRect().left). Overriding it directly is the practical
* fix without pulling in a whole extra extension. */
@media (max-width: 999px) {
.vector-header,
.mw-page-container,
.mw-page-container-inner,
body,
html {
min-width: 0 !important;
}
.vector-header {
width: 100% !important;
}
/* Same content-padding bug as the desktop layout had (fixed earlier by
* padding .mw-body, the shared grid parent of #firstHeading and
* .mw-body-content — see that rule's own comment for why it has to be
* .mw-body and not .mw-body-content alone) — this fix was scoped to
* the >=1000px media query only, so real mobile (confirmed live via a
* real device screenshot, not just emulation) never got it: heading
* and body text sat flush against the content box's own border. */
.mw-body {
padding: 0 1rem !important;
box-sizing: border-box !important;
}
}
/* Image thumbnails (banner images, etc) — Vector hardcodes a light
* background/border directly on the figure, the file element, AND the
* caption (all three, separately) via #f8f9fa — confirmed live as the
* visible white box wrapping the town banner on event pages. */
figure[typeof~='mw:File/Thumb'],
figure[typeof~='mw:File/Frame'] {
background-color: var(--wiki-panel) !important;
border-color: var(--wiki-rule) !important;
}
figure[typeof~='mw:File/Thumb'] > :not(figcaption) .mw-file-element,
figure[typeof~='mw:File/Frame'] > :not(figcaption) .mw-file-element {
background: var(--wiki-panel) !important;
border-color: var(--wiki-rule) !important;
}
figure[typeof~='mw:File/Thumb'] > figcaption,
figure[typeof~='mw:File/Frame'] > figcaption {
background-color: var(--wiki-panel) !important;
color: var(--wiki-muted) !important;
border-color: var(--wiki-rule) !important;
}
/* "Powered by MediaWiki" footer badge is a real raster image (its own
* baked-in white background, not stylable) — simplest fix is to just
* not show it rather than fight a PNG's own pixels. */
#footer-poweredbyico {
display: none !important;
}
/* Sidebar minimize toggle ("hide" button) still wasn't showing —
* Vector's own conditional selector
* (.client-js .vector-pinnable-header-pinned .vector-pinnable-header-unpin-button)
* only shows it when a real Vector "pinned" ancestor class is present,
* which we never set (we bypass Vector's real pin state entirely with
* our own always-on CSS) — so its unconditional base rule
* (.vector-pinnable-header-toggle-button{display:none}) was what
* actually applied instead. Confirmed live: the earlier single-class
* !important override still computed to display:none. `html body`
* prefix (already proven necessary elsewhere in this file for an
* identical Codex/Vector specificity fight) forces this to win
* regardless of which of Vector's own rules is really in play. */
html body .vector-pinnable-header-unpin-button {
display: inline-block !important;
}
html body .vector-pinnable-header-pin-button {
display: none !important;
}
/* ── Auto-published page infobox ─────────────────────────────────────────
* Every TownyExtras-published page (towns/players/nations/houses/events/
* ravens) emits a {| class="te-infobox" |} table — this styles it as the
* Wikipedia-style right-hand card: floated right, panel background, gold
* centered title, compact label/value rows. Emitters: WikiMarkup.java. */
.te-infobox {
float: right;
clear: right;
width: 300px;
margin: 0.25rem 0 1.25rem 1.75rem;
background: var(--wiki-panel) !important;
border: 1px solid var(--wiki-rule) !important;
border-radius: 8px;
border-collapse: separate;
border-spacing: 0;
padding: 10px 14px 12px;
font-size: 0.92em;
line-height: 1.45;
}
.te-infobox th,
.te-infobox td {
background: transparent !important;
border: none !important;
padding: 3px 0;
text-align: left;
vertical-align: top;
}
.te-infobox th {
color: var(--wiki-muted) !important;
font-weight: bold;
white-space: nowrap;
padding-right: 14px;
width: 1%;
}
.te-infobox th.te-infobox-title {
width: auto;
white-space: normal;
text-align: center;
color: var(--wiki-gold) !important;
font-size: 1.25em;
padding: 2px 0 6px;
border-bottom: 1px solid var(--wiki-rule) !important;
}
.te-infobox td.te-infobox-sub {
text-align: center;
color: var(--wiki-muted) !important;
padding: 4px 0 2px;
}
.te-infobox td.te-infobox-image {
text-align: center;
padding: 8px 0 10px;
}
.te-infobox td.te-infobox-image img {
image-rendering: pixelated;
height: auto;
max-width: 100%;
}
/* On phones the floated card would squeeze the text to a sliver — let it
* sit full-width above the lead instead. */
@media (max-width: 999px) {
.te-infobox {
float: none;
width: 100%;
margin: 0 0 1rem;
box-sizing: border-box;
}
}
/* ── Make content links visibly links ────────────────────────────────────
* Gold alone wasn't enough to distinguish links from headings/labels
* (owner feedback 2026-07-21) — underline every link in the article body.
* Nav/sidebar/tabs stay underline-free (they're outside .mw-body-content). */
.mw-body-content a {
text-decoration: underline !important;
text-underline-offset: 3px;
text-decoration-thickness: 1px;
}
.mw-editsection a {
text-decoration: none !important;
}
/* Links to pages that don't exist yet ("red links") — MediaWiki's default
* red is unreadable on this dark palette; use a muted brick tone that still
* clearly says "this page is missing" next to the gold of real links. */
.mw-body-content a.new {
color: #cf7a66 !important;
}