MediaWiki:Common.css: Difference between revisions

Current answers. Practical procedures. Reliable reference.
Jump to navigation Jump to search
Fix external links rendering core blue instead of theme orange (core .mw-parser-output a.external rule outranked our plain a.external rule)
Redesign: technical field-manual theme -- design tokens, capped content width, rebalanced link colours (blue/cyan links, orange reserved for nav/emphasis), TOC/footer/table/metadata restyle, focus-visible, reduced-motion, faint grid bg
Line 1: Line 1:
/* EDFM site-wide styling.
/* ==========================================================================
* Original CSS written for this project no code or assets copied from
  EDFM site-wide styling -- "Elite Dangerous technical field manual" theme.
* runescape.wiki, Elite Dangerous, or any other site/game. Visual
  Original CSS written for this project -- no code or assets copied from
* direction (classic always-visible left sidebar, bordered header,
  runescape.wiki, Elite Dangerous, or any other site/game, and no Frontier
* right-floated infoboxes, permanent dark theme, orange/cyan "high-tech
  logo/branding/proprietary fonts/copied HUD elements. Restrained visual
* instrument panel" accents) is inspired by that genre, per operator
  influence only: dark industrial surfaces, subtle angular geometry,
* request, but implemented from scratch: no copied HUD elements, no
  orange/cyan accents used sparingly, information hierarchy first. This is
* Frontier logo/branding, no proprietary fonts (the monospace stack
  a reference site, not a HUD -- no glow, no neon, no glassmorphism, no
* below lists common system/open fonts with a generic `monospace`
  constant animation.
* fallback — no font files are shipped or embedded), no glow/scanline
* animation effects, no fake cockpit widgets.
*
* SKIN NOTE (2026-08-07): the site uses Vector "legacy" (2011), not
* Vector 2022 — see the "Why Vector legacy" note in
* docs/content-style-guide.md (Vector 2022 hard-restricts its pinned
* sidebar to logged-in users; legacy has no such restriction).
*
* COLOUR NOTE (2026-08-07): permanent dark theme with an Elite-Dangerous-
* evoking orange-on-near-black palette, cyan as a secondary/status
* accent. Vector legacy has no light/dark toggle at all, so this is the
* site's one and only colour scheme, not a preference.
*
* Keep this file simple. If it grows much further, split it into
* per-purpose TemplateStyles sheets instead of one large Common.css.
*/


/* --- Fonts: a "technical readout" monospace stack for UI chrome (nav,
  SKIN NOTE: the site uses Vector "legacy" (2011), not Vector 2022 -- see
   headings, table/infobox headers) -- common system/open fonts only,
   the "Why Vector legacy" note in docs/content-style-guide.md (Vector 2022
   nothing shipped or embedded, generic monospace as the final fallback.
  hard-restricts its pinned sidebar to logged-in users; legacy has no such
   Body/article paragraph text stays in a normal readable sans-serif on
  restriction). Several rules below exist specifically to beat core Vector
   purpose (see .mw-body below) -- long-form reading in monospace would
  legacy/mediawiki.skinning selectors that are *more specific* than a naive
   hurt readability, which stays a hard requirement even with a more
  override would be (documented inline at each occurrence) -- this isn't
   technical visual language elsewhere. */
   guesswork, each one was found by reading the actual core .less source and
   confirmed with a real rendered screenshot, not just computed-style checks
   (:visited colours in particular are invisible to getComputedStyle by
  design -- see the tab-bar note below).
 
  File organised to mirror the 2026-08-07 redesign brief's own section
  numbers, so both stay easy to cross-reference.
   ========================================================================== */
 
/* ==========================================================================
   1. DESIGN TOKENS
  ========================================================================== */
:root {
:root {
/* Surfaces -- darkest to lightest */
--edfm-bg-deep: #090d0f;
--edfm-bg-page: #0d1215;
--edfm-surface-1: #12181c;
--edfm-surface-2: #171f24;
--edfm-surface-3: #1c252b;
/* Borders */
--edfm-border: #273239;
--edfm-border-soft: rgba( 255, 255, 255, 0.07 );
/* Text */
--edfm-text: #e7eaec;
--edfm-text-muted: #8e9aa1;
--edfm-text-dim: #68757c;
/* Accents -- orange is reserved for navigation/selection/emphasis/
  section numbering; cyan/blue are for links, verification info, and
  secondary interface elements. See "Links" and "Colour system" in
  docs/content-style-guide.md for the reasoning. */
--edfm-orange: #ff8a00;
--edfm-orange-bright: #ffa21a;
--edfm-cyan: #42c7d9;
--edfm-blue: #4f9fe8;
/* Derived link colours (not part of the operator's token list verbatim,
  but named separately so link handling reads as its own concern) */
--edfm-link: var( --edfm-blue );
--edfm-link-visited: #3f7bb3;
--edfm-link-hover: #8cc4f7;
--edfm-link-external: var( --edfm-cyan );
--edfm-link-external-visited: #2f8f9c;
--edfm-link-external-hover: #7fe0ec;
--edfm-link-new: #e07a7a;
/* Status semantics (article metadata module) -- text label always
  present too, never colour-only. */
--edfm-status-positive: var( --edfm-cyan );
--edfm-status-attention: var( --edfm-orange );
--edfm-status-neutral: var( --edfm-text-dim );
/* Typography */
--edfm-mono: 'JetBrains Mono', 'Fira Code', Consolas, 'SF Mono', Menlo, 'Courier New', monospace;
--edfm-mono: 'JetBrains Mono', 'Fira Code', Consolas, 'SF Mono', Menlo, 'Courier New', monospace;
--edfm-orange: #ff8c1a;
--edfm-sans: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
--edfm-orange-hover: #ffab5c;
 
--edfm-orange-active: #ffc98f;
/* Legacy aliases: earlier revisions of this stylesheet used these names
--edfm-cyan: #3ecbd6;
  directly and some inline template output/older docs may still refer
--color-progressive: #ff8c1a;
  to them; keep pointing at the current tokens rather than duplicate
--color-progressive--hover: #ffab5c;
  values that could drift out of sync. */
--color-progressive--active: #ffc98f;
--edfm-orange-hover: var( --edfm-orange-bright );
--color-progressive--focus: #ff8c1a;
--edfm-orange-active: var( --edfm-orange-bright );
--background-color-progressive: #ff8c1a;
--color-progressive: var( --edfm-orange );
--background-color-progressive--hover: #ffab5c;
--color-progressive--hover: var( --edfm-orange-bright );
--background-color-progressive--active: #ffc98f;
--color-progressive--active: var( --edfm-orange-bright );
--border-color-progressive: #ff8c1a;
--color-progressive--focus: var( --edfm-orange );
--border-color-progressive--hover: #ffab5c;
--background-color-progressive: var( --edfm-orange );
--border-color-progressive--active: #ffc98f;
--background-color-progressive--hover: var( --edfm-orange-bright );
--background-color-progressive--active: var( --edfm-orange-bright );
--border-color-progressive: var( --edfm-orange );
--border-color-progressive--hover: var( --edfm-orange-bright );
--border-color-progressive--active: var( --edfm-orange-bright );
 
/* Shared geometry: a small clipped corner reads as "technical panel"
  without a giant border-radius anywhere on the site. */
--edfm-corner: 10px;
--edfm-content-max: 1200px;
}
}


/* --- Base page colours ------------------------------------------------ */
/* ==========================================================================
  2. BASE / RESET-ADJACENT
  ========================================================================== */
html, body {
html, body {
background-color: #0d0f11;
background-color: var( --edfm-bg-page );
color: #d7dade;
color: var( --edfm-text );
}
}
body.mediawiki {
body.mediawiki {
color: #d7dade;
color: var( --edfm-text );
font-family: var( --edfm-sans );
}
/* Very faint (~2.5%) technical grid across the page background. Only
  visible where an opaque panel (sidebar, article surface, tables) isn't
  already covering it -- the header strip, the sidebar, and the margin
  outside the width-capped article column on wide screens. Not an image
  asset; pure CSS gradients. */
body {
background-image:
linear-gradient( rgba( 255, 255, 255, 0.025 ) 1px, transparent 1px ),
linear-gradient( 90deg, rgba( 255, 255, 255, 0.025 ) 1px, transparent 1px );
background-size: 48px 48px;
}
@media ( prefers-reduced-motion: reduce ) {
*, *::before, *::after {
animation-duration: 0.001ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.001ms !important;
scroll-behavior: auto !important;
}
}
/* Focus visibility: the pre-redesign stylesheet had no explicit focus
  styling at all (relying entirely on browser defaults, which vary and can
  be hard to see against a dark theme). Applies to every interactive
  element, not just links. */
a:focus-visible,
button:focus-visible,
input:focus-visible,
textarea:focus-visible,
select:focus-visible,
[tabindex]:focus-visible {
outline: 2px solid var( --edfm-cyan );
outline-offset: 2px;
}
}
/* ==========================================================================
  3. TYPOGRAPHY
  ========================================================================== */
h1, h2, h3, h4, h5, h6 {
h1, h2, h3, h4, h5, h6 {
color: #f2f4f6;
color: var( --edfm-text );
border-color: #2b2f33;
border-color: var( --edfm-border );
}
}
/* !important justified here: MediaWiki core's mediawiki.skinning module
/* !important justified here: MediaWiki core's mediawiki.skinning module
   sets heading colour with equal-specificity plain-tag selectors and
   sets heading colour with equal-specificity plain-tag selectors and kept
   kept winning in testing despite this stylesheet loading later --
   winning in testing despite this stylesheet loading later -- rather than
   rather than keep chasing exact cascade/bundling order, force it. This
   keep chasing exact cascade/bundling order, force it. This is a
   is a correctness/contrast fix, not decorative. */
   correctness/contrast fix, not decoration. */
.mw-body h1, .mw-body h2, .mw-body h3, .mw-body h4, .mw-body h5, .mw-body h6,
.mw-body h1, .mw-body h2, .mw-body h3, .mw-body h4, .mw-body h5, .mw-body h6,
.mw-heading1, .mw-heading2, .mw-heading3, .mw-heading4, .mw-heading5, .mw-heading6,
.mw-heading1, .mw-heading2, .mw-heading3, .mw-heading4, .mw-heading5, .mw-heading6,
h1, h2, h3, h4, h5, h6 {
h1, h2, h3, h4, h5, h6 {
color: #f2f4f6 !important;
color: var( --edfm-text ) !important;
border-color: #2b2f33 !important;
border-color: var( --edfm-border ) !important;
font-family: var( --edfm-mono );
font-family: var( --edfm-mono );
letter-spacing: 0.01em;
letter-spacing: 0.01em;
line-height: 1.3;
}
#firstHeading {
color: var( --edfm-text ) !important;
font-family: var( --edfm-mono );
font-size: 1.9em;
}
/* Restrained "instrument label" bracket treatment on major section
  headings (h2): a plain "// " prefix via ::before (no image, no glow, no
  animation) plus a short orange accent segment layered over the
  otherwise-dim divider line core already draws under h2. If a heading
  opts into explicit numbering via {{Section number}} (see
  .edfm-section-number below), the automatic "// " is suppressed so the
  two treatments don't double up. */
.mw-body h2 {
position: relative;
padding-bottom: 0.3em;
margin-top: 1.6em;
}
}
/* A restrained "instrument label" bracket treatment on major section
  headings only (h2) -- plain characters via ::before/::after, no
  images, no glow, no animation. */
.mw-body h2::before {
.mw-body h2::before {
content: '// ';
content: '// ';
Line 83: Line 183:
font-weight: 400;
font-weight: 400;
}
}
#firstHeading {
.mw-body h2:has( .edfm-section-number )::before {
color: #f2f4f6 !important;
content: none;
font-family: var( --edfm-mono );
}
.mw-body h2::after {
content: '';
position: absolute;
left: 0;
bottom: -1px;
width: 3em;
max-width: 100%;
height: 2px;
background: var( --edfm-orange );
}
.edfm-section-number {
color: var( --edfm-orange );
font-weight: 700;
}
.edfm-section-sep {
color: var( --edfm-orange );
margin-right: 0.15em;
}
h3, h4 {
color: var( --edfm-text );
}
h3::before {
content: '/ ';
color: var( --edfm-text-dim );
font-weight: 400;
}
 
/* Body text: readable sans-serif, deliberately NOT monospace -- long-form
  reading in monospace hurts readability, which stays a hard requirement
  even with a more technical visual language elsewhere. */
.mw-body p,
.mw-body li,
.mw-body dd {
line-height: 1.65;
}
.mw-body p {
margin: 0 0 1em 0;
max-width: 74em; /* comfortable measure even inside the wider content column */
}
.mw-body ul,
.mw-body ol {
line-height: 1.65;
margin-bottom: 1em;
}
.mw-body h2 + p,
.mw-body h3 + p {
margin-top: 0.6em;
}
}
hr {
hr {
background-color: #2b2f33;
background-color: var( --edfm-border );
border-color: #2b2f33;
border-color: var( --edfm-border );
}
}
a { color: var( --edfm-orange ); transition: color 0.1s ease; }
 
a:visited { color: #d9974f; }
/* ==========================================================================
a:hover { color: var( --edfm-orange-hover ); }
  8. LINKS
a.new, .new a { color: #e07a7a; }
  ========================================================================== */
a.external { color: var( --edfm-orange ); }
a { color: var( --edfm-link ); transition: color 0.1s ease; }
/* Core MediaWiki ships `.mw-parser-output a.external`/`a.extiw` (and
a:visited { color: var( --edfm-link-visited ); }
   their :visited states) at higher specificity than a plain `a.external`
a:hover { color: var( --edfm-link-hover ); }
  rule, so the line above never actually wins for real article links --
a.new, .new a { color: var( --edfm-link-new ); }
   same underlying gotcha as the tab :visited bug. Matching the same
a.external { color: var( --edfm-link-external ); }
  selector shape here (loaded after core skin styles) is what actually
/* Core MediaWiki ships `.mw-parser-output a.external`/`a.extiw` (and their
   applies our colour to external links in article content. */
   :visited/:hover states) at higher specificity (two classes + a tag) than
  a plain `a.external` rule (one class + a tag), so the line above never
  actually wins for real article links on its own -- the same underlying
   "core selector outranks a naive theme override" gotcha as the tab
  :visited fix further down. Matching the same selector shape here (this
  stylesheet loads after core skin styles) is what actually applies our
   colour to external links in article content. */
.mw-parser-output a.external,
.mw-parser-output a.external,
.mw-parser-output a.extiw {
.mw-parser-output a.extiw {
color: var( --edfm-orange );
color: var( --edfm-link-external );
}
}
.mw-parser-output a.external:visited,
.mw-parser-output a.external:visited,
.mw-parser-output a.extiw:visited {
.mw-parser-output a.extiw:visited {
color: #d9974f;
color: var( --edfm-link-external-visited );
}
}
.mw-parser-output a.external:hover,
.mw-parser-output a.external:hover,
.mw-parser-output a.extiw:hover {
.mw-parser-output a.extiw:hover {
color: var( --edfm-orange-hover );
color: var( --edfm-link-external-hover );
}
.mw-footer a {
color: var( --edfm-link );
}
.mw-footer a:hover {
color: var( --edfm-link-hover );
}
}


/* --- Content/body panel ------------------------------------------------ */
/* ==========================================================================
  1 + 4. GLOBAL LAYOUT / ARTICLE HEADER
  ========================================================================== */
/* Vector legacy's core layout (skins.vector.styles.legacy/layouts/screen.less)
  gives `.mw-body` (#content) a left margin to clear the fixed-width
  sidebar and otherwise lets it run edge-to-edge to the browser's right
  side -- there is no max-width at all, which is why content stretched
  excessively on large displays. Capping width here only affects the
  article/footer column; the full-width header/tab bar above it is left
  alone deliberately (its own float/absolute-position math is exactly what
  an earlier round of this project had to carefully debug to get the
  persistent sidebar working at all -- touching it again for a purely
  cosmetic width cap isn't worth the regression risk). A full-bleed
  toolbar above a capped content column is also just a normal, accepted
  pattern on technical documentation sites. */
.mw-body,
.mw-body,
.parsoid-body {
#mw-data-after-content,
background-color: #131619;
.mw-footer {
color: #d7dade;
max-width: var( --edfm-content-max );
border-color: #2b2f33;
box-sizing: border-box;
font-family: sans-serif; /* readable body text -- not monospace */
}
/* Tables, code blocks, and preformatted content are still allowed to be
  wider than a comfortable reading measure (technical data often needs
  it) -- they scroll horizontally inside the capped column instead of
  being force-shrunk or breaking the layout. Ordinary images/galleries
  already respect the column via max-width:100% below. */
.mw-body table,
.mw-body pre,
.mw-body .mw-code {
max-width: 100%;
overflow-x: auto;
}
.mw-body table.wikitable,
.mw-body table.mw-datatable {
display: block;
overflow-x: auto;
}
.mw-body table.wikitable tbody,
.mw-body table.mw-datatable tbody {
display: table;
width: 100%;
}
.mw-body img {
max-width: 100%;
height: auto;
}
 
/* Eyebrow / deck (see Template:Article header). The eyebrow line is
  authored as ordinary wikitext and, purely as a placement detail, a small
  script (MediaWiki:Common.js) moves it directly above #firstHeading on
  page load -- see the comment there for why that needs JS rather than
  CSS/a template (the title is rendered by the skin before the article
  body in the DOM, so nothing living inside the article body can appear
  earlier than it without either moving it in the DOM or abandoning the
  real semantic H1, and the brief is explicit the H1 must stay the real
  H1). If JS is unavailable the eyebrow still renders, just directly under
  the title instead of above it -- nothing breaks, it's a placement
  nicety, not functionality. */
.edfm-eyebrow {
margin: 0 0 0.3em 0;
font-family: var( --edfm-mono );
font-size: 0.75em;
font-weight: 700;
letter-spacing: 0.08em;
text-transform: uppercase;
color: var( --edfm-text-dim );
}
.edfm-eyebrow .edfm-orange-mark {
color: var( --edfm-orange );
}
.edfm-deck {
color: var( --edfm-text-muted );
font-size: 1.05em;
max-width: 60em;
margin: 0.3em 0 1.2em 0;
}
 
/* ==========================================================================
  1. SIDEBAR
  ========================================================================== */
#mw-panel {
background-color: var( --edfm-bg-deep );
}
#mw-panel .portal .body,
#mw-panel .portal ul {
border-color: var( --edfm-border-soft );
}
#mw-panel .portal a {
color: var( --edfm-text-muted );
display: block;
padding: 0.15em 0.4em;
margin: 0 -0.4em;
border-left: 2px solid transparent;
border-radius: 0;
}
#mw-panel .portal a:hover {
color: var( --edfm-cyan );
background: var( --edfm-surface-1 );
}
/* "You are here" -- MediaWiki's sidebar has no built-in current-page
  indication; MediaWiki:Common.js adds the .edfm-nav-current class to the
  matching list item by comparing hrefs to the current URL. Orange is
  reserved for exactly this kind of "important navigation / selected
  state" per the colour system, which is why the rest of the sidebar is
  deliberately muted rather than orange throughout (an all-orange sidebar
  would both fight this indicator and read as visually dominant, which the
  brief specifically calls out to avoid). */
.edfm-nav-current > a {
color: var( --edfm-orange ) !important;
font-weight: 700;
border-left-color: var( --edfm-orange );
background: var( --edfm-surface-1 );
}
}
#content {
.vector-menu-heading {
background-color: #131619;
color: var( --edfm-text-dim );
font-weight: 700;
font-family: var( --edfm-mono );
letter-spacing: 0.08em;
text-transform: uppercase;
font-size: 0.75em;
border-left: 2px solid var( --edfm-orange );
padding-left: 0.5em;
margin-left: -0.5em;
}
}


/* --- Header / masthead -------------------------------------------------- */
/* ==========================================================================
  4/9. HEADER / MASTHEAD / MEDIAWIKI TABS
  ========================================================================== */
#mw-page-base {
#mw-page-base {
background-color: #0d0f11;
background-color: var( --edfm-bg-deep );
background-image: none;
background-image: none;
}
}
#mw-head-base {
#mw-head-base {
background-color: #0d0f11;
background-color: var( --edfm-bg-deep );
}
}
#p-personal,
#p-personal,
.vector-header-container {
.vector-header-container {
border-bottom: 3px solid var( --edfm-orange );
border-bottom: 2px solid var( --edfm-orange );
}
}
#mw-head-base {
#mw-head-base {
border-bottom: 3px solid var( --edfm-orange );
border-bottom: 2px solid var( --edfm-orange );
}
}
/* Personal tools (login/logout) -- a real action, kept orange-adjacent but
  quiet until interacted with, matching "utility control" treatment. */
#p-personal a {
#p-personal a {
color: var( --edfm-text-muted );
font-family: var( --edfm-mono );
}
#p-personal a:hover {
color: var( --edfm-orange );
color: var( --edfm-orange );
font-family: var( --edfm-mono );
}
}
/* Namespace tabs (Main Page / Discussion, left) and view tabs
/* Namespace tabs (Main Page / Discussion, left) and view tabs
Line 150: Line 429:
   .vector-menu-tabs-legacy markup. Core skin CSS paints every tab `li`
   .vector-menu-tabs-legacy markup. Core skin CSS paints every tab `li`
   with a gradient fading to white and forces the selected tab to pure
   with a gradient fading to white and forces the selected tab to pure
   white -- neither is touched by recolouring the link text alone, which
   white -- neither is touched by recolouring the link text alone, which is
   is why these stayed light after the rest of the theme went dark.
   why these stayed light before this stylesheet covered the `li`
   Core also has an `a:visited` rule (higher specificity than a plain
   background too. Core also has an `a:visited` rule (higher specificity
  `a` rule, since a pseudo-class counts the same as a class) that
  than a plain `a` rule, since a pseudo-class counts the same as a class)
   reasserts a near-black "visited" colour meant for a white background;
   that reasserts a near-black "visited" colour meant for a white
  every one of these tabs is a link you're almost always going to have
  background; since these tabs point at pages you've almost always
   visited, so without an explicit `:visited` override here the text
   already visited, without an explicit `:visited` override here the text
   goes dark-on-dark. Note this can't be caught by reading
   goes dark-on-dark. This can't be caught by reading getComputedStyle() in
  getComputedStyle() in an automated check -- browsers deliberately
  an automated check -- browsers deliberately report the *unvisited*
  report the *unvisited* color from JS for privacy reasons, so it only
  colour to JS for privacy reasons, so it only shows up on an actual
  shows up on an actual screen. */
  screen; verified with real rendered screenshots, including after
  genuinely visiting the linked pages first.
 
  Per the redesign brief, tabs are "important navigation" (namespace
  identity) rather than "utility controls" (the view/actions tabs, see
  below) -- selected state stays orange; unselected rests at a slightly
  dimmer neutral than article body text so the *selected* tab still reads
  as the clear focal point. */
.vector-menu-tabs-legacy li {
.vector-menu-tabs-legacy li {
background-image: none;
background-image: none;
background-color: #16191c;
background-color: var( --edfm-surface-2 );
}
}
.vector-menu-tabs-legacy li.selected {
.vector-menu-tabs-legacy li.selected {
background-image: none;
background-image: none;
background-color: #131619;
background-color: var( --edfm-surface-1 );
}
}
.vector-menu-tabs-legacy li a,
.vector-menu-tabs-legacy li a,
.vector-menu-tabs-legacy li a:visited {
.vector-menu-tabs-legacy li a:visited {
background-color: transparent;
background-color: transparent;
color: #d7dade;
color: var( --edfm-text-dim );
font-family: var( --edfm-mono );
font-family: var( --edfm-mono );
letter-spacing: 0.01em;
letter-spacing: 0.01em;
}
.vector-menu-tabs-legacy li a:hover,
.vector-menu-tabs-legacy li a:visited:hover {
color: var( --edfm-text );
}
}
.vector-menu-tabs-legacy li.selected a,
.vector-menu-tabs-legacy li.selected a,
Line 182: Line 472:
.vector-menu-tabs-legacy li.new a,
.vector-menu-tabs-legacy li.new a,
.vector-menu-tabs-legacy li.new a:visited {
.vector-menu-tabs-legacy li.new a:visited {
color: #ff6b6b;
color: var( --edfm-link-new );
}
}
/* "More" actions dropdown (#p-cactions) sits in the same tab row;
/* "More" actions dropdown (#p-cactions) sits in the same tab row; same
   same :visited gotcha applies to its menu items. */
   :visited gotcha applies to its menu items. Kept deliberately quiet --
  this is the clearest case of "utility control, not primary nav". */
.vector-menu-dropdown .vector-menu-heading {
.vector-menu-dropdown .vector-menu-heading {
color: #9aa0a6;
color: var( --edfm-text-dim );
font-family: var( --edfm-mono );
font-family: var( --edfm-mono );
border-left: none;
padding-left: 8px;
margin-left: 0;
text-transform: none;
letter-spacing: normal;
font-size: 1em;
font-weight: normal;
}
}
.vector-menu-dropdown .vector-menu-heading:hover,
.vector-menu-dropdown .vector-menu-heading:hover,
Line 195: Line 493:
}
}
.vector-menu-dropdown .vector-menu-content {
.vector-menu-dropdown .vector-menu-content {
background-color: #16191c;
background-color: var( --edfm-surface-2 );
border-color: #33383e;
border-color: var( --edfm-border );
}
}
.vector-menu-dropdown .vector-menu-content a,
.vector-menu-dropdown .vector-menu-content a,
.vector-menu-dropdown .vector-menu-content a:visited {
.vector-menu-dropdown .vector-menu-content a:visited {
color: #d7dade;
color: var( --edfm-text-muted );
}
}
.vector-menu-dropdown .vector-menu-content li.selected a,
.vector-menu-dropdown .vector-menu-content li.selected a,
Line 207: Line 505:
}
}
.vector-menu-dropdown .vector-menu-content li:hover {
.vector-menu-dropdown .vector-menu-content li:hover {
background-color: #1c2024;
background-color: var( --edfm-surface-3 );
}
}
.vector-search-box-inner input,
.vector-search-box-inner input,
#searchInput {
#searchInput {
background-color: #16191c;
background-color: var( --edfm-surface-2 );
color: #eef1f4;
color: var( --edfm-text );
border: 1px solid #33383e;
border: 1px solid var( --edfm-border );
font-family: var( --edfm-mono );
font-family: var( --edfm-mono );
}
}
#searchInput::placeholder {
#searchInput::placeholder {
color: #767c84;
color: var( --edfm-text-dim );
}
}


/* --- Sidebar ------------------------------------------------------------ */
/* ==========================================================================
#mw-panel {
  CONTENT / ARTICLE SURFACE
background-color: #0d0f11;
  ========================================================================== */
.mw-body,
.parsoid-body {
background-color: var( --edfm-surface-1 );
color: var( --edfm-text );
border-color: var( --edfm-border );
font-family: var( --edfm-sans );
}
#content {
background-color: var( --edfm-surface-1 );
}
}
#mw-panel .portal .body,
 
#mw-panel .portal ul {
/* ==========================================================================
border-color: #23272b;
  10. TABLE OF CONTENTS
  ========================================================================== */
/* Restyled as an "EDFM navigation module" rather than a default wiki TOC,
  while leaving MediaWiki's actual TOC markup/anchors completely alone --
  this is presentation only. "Contents" is kept in the DOM for screen
  readers/no-JS/no-CSS fallback (more standard wording there anyway) and
  visually replaced with "Jump to" via ::before on the wrapper, with the
  real heading text hidden via font-size rather than display:none so it
  remains in the accessibility tree. */
#toc, .toc {
background-color: var( --edfm-surface-2 ) !important;
border: 1px solid var( --edfm-border ) !important;
color: var( --edfm-text );
padding: 0.8em 1em;
clip-path: polygon( 0 0, calc( 100% - var( --edfm-corner ) ) 0, 100% var( --edfm-corner ), 100% 100%, 0 100% );
}
}
#mw-panel .portal a {
.toctitle {
color: #d7dade;
position: relative;
margin-bottom: 0.4em;
}
}
#mw-panel .portal a:hover {
.toctitle::before {
content: 'Jump to';
font-family: var( --edfm-mono );
font-size: 0.75em;
font-weight: 700;
letter-spacing: 0.1em;
text-transform: uppercase;
color: var( --edfm-orange );
color: var( --edfm-orange );
}
}
.vector-menu-heading {
.toctitle h2 {
font-size: 0;
line-height: 0;
margin: 0;
border: none;
padding: 0;
display: inline;
}
.toctitle h2::before,
.toctitle h2::after {
content: none;
}
.toctogglelabel::before {
color: var( --edfm-text-dim );
}
/* Top-level entries as wrapped horizontal "chips" -- reads well for the
  short/medium pages this site mostly has, and simply wraps onto more
  rows for longer ones rather than needing a separate vertical mode. */
.toc > ul {
display: flex;
flex-wrap: wrap;
gap: 0.4em 1.2em;
list-style: none;
margin: 0;
padding: 0;
}
.toc ul ul {
flex-basis: 100%;
width: 100%;
list-style: none;
margin: 0.2em 0 0.2em 1.4em;
padding: 0;
display: block;
}
.toc li {
margin: 0;
}
.toc a {
display: inline-flex;
align-items: baseline;
gap: 0.35em;
color: var( --edfm-text-muted );
text-decoration: none;
font-size: 0.92em;
}
.toc a:hover {
color: var( --edfm-cyan );
}
.tocnumber {
color: var( --edfm-orange );
color: var( --edfm-orange );
font-family: var( --edfm-mono );
font-weight: 700;
font-weight: 700;
font-family: var( --edfm-mono );
min-width: 1.2em;
letter-spacing: 0.06em;
}
text-transform: uppercase;
.toctext {
font-size: 0.78em;
color: inherit;
}
}


/* --- Tables (wikitables, and Special: pages' tables) ------------------- */
/* ==========================================================================
  6. PANELS / CALLOUTS, and 11. ARTICLE METADATA / STATUS MODULE
  ========================================================================== */
/* Deliberately NOT defined here. .edfm-box / .edfm-panel* / .edfm-status* /
  .edfm-inline-flag are used exclusively by the editorial templates (see
  Template:Article status, Template:Draft warning, etc.), which already
  load Template:EDFM style/styles.css themselves via <templatestyles>.
  Defining the same class names in both this file and that one would
  leave their relative precedence dependent on unclear/unstable ordering
  between a ResourceLoader "site" stylesheet and a TemplateStyles-injected
  <style> tag -- rather than rely on that, there is exactly one definition
  of each, living in Template:EDFM style/styles.css. That file freely uses
  the --edfm-* custom properties defined above; custom properties resolve
  through the DOM regardless of which stylesheet declared vs references
  them, so this split costs nothing. */
 
/* ==========================================================================
  7. TABLES (wikitables, and Special: pages' tables)
  ========================================================================== */
table.wikitable,
table.wikitable,
table.mw-datatable {
table.mw-datatable {
background-color: #16191c;
background-color: var( --edfm-surface-2 );
color: #d7dade;
color: var( --edfm-text );
border-color: #33383e;
border-color: var( --edfm-border );
}
}
table.wikitable > tr > th,
table.wikitable > tr > th,
table.wikitable > * > tr > th {
table.wikitable > * > tr > th {
background-color: #1e2226;
background-color: var( --edfm-surface-3 );
color: #f2f4f6;
color: var( --edfm-text );
border-color: #33383e;
border-color: var( --edfm-border );
font-family: var( --edfm-mono );
font-family: var( --edfm-mono );
letter-spacing: 0.03em;
letter-spacing: 0.03em;
text-transform: uppercase;
text-transform: uppercase;
font-size: 0.85em;
font-size: 0.85em;
text-align: left;
}
}
table.wikitable > tr > td,
table.wikitable > tr > td,
table.wikitable > * > tr > td {
table.wikitable > * > tr > td {
border-color: #2b2f33;
border-color: var( --edfm-border-soft );
padding: 0.5em 0.7em;
}
/* Subtle alternating row treatment -- helps scanning wide/dense reference
  tables without turning them into cards. */
table.wikitable > tbody > tr:nth-child( even ),
table.wikitable > * > tr:nth-child( even ) {
background-color: var( --edfm-surface-1 );
}
}


/* --- Footer -------------------------------------------------------------- */
/* ==========================================================================
  13. FOOTER
  ========================================================================== */
.mw-footer {
margin-left: auto;
margin-right: auto;
border-top: 1px solid var( --edfm-border );
display: grid;
grid-template-columns: 1fr auto;
grid-template-areas: "info icons" "places icons";
align-items: center;
column-gap: 2em;
row-gap: 0.3em;
}
.mw-footer,
.mw-footer,
.mw-footer li,
.mw-footer li,
#footer-info,
#footer-info,
#footer-info li {
#footer-info li {
color: #9aa0a6 !important;
color: var( --edfm-text-dim );
border-color: #23272b;
border-color: var( --edfm-border-soft );
}
}
.mw-footer a {
#footer-info {
color: var( --edfm-orange ) !important;
grid-area: info;
margin: 0;
}
#footer-places {
grid-area: places;
margin: 0;
}
#footer-icons {
grid-area: icons;
align-self: center;
display: flex;
gap: 0.75em;
margin: 0;
}
}
#footer-icons img {
#footer-icons img {
background: #eef1f4;
background: var( --edfm-text );
border-radius: 2px;
border-radius: 2px;
}
@media ( max-width: 640px ) {
.mw-footer {
grid-template-columns: 1fr;
grid-template-areas: "info" "places" "icons";
}
#footer-icons {
margin-top: 0.5em;
}
}
}


/* --- Misc MediaWiki UI chrome that ships with light backgrounds by
/* ==========================================================================
  default: category box at the bottom of articles, image thumbnails,
  MISC MediaWiki UI chrome that ships with light backgrounds by default
   collapsible table-of-contents box. */
   ========================================================================== */
.catlinks,
.catlinks {
#toc,
background-color: var( --edfm-surface-2 ) !important;
.toc {
border-color: var( --edfm-border ) !important;
background-color: #16191c !important;
color: var( --edfm-text-muted );
border-color: #2b2f33 !important;
color: #d7dade;
}
}
div.thumbinner {
div.thumbinner {
background-color: #16191c;
background-color: var( --edfm-surface-2 );
border-color: #2b2f33;
border-color: var( --edfm-border );
}
}
.thumbimage {
.thumbimage {
background-color: #131619;
background-color: var( --edfm-surface-1 );
border-color: #2b2f33;
border-color: var( --edfm-border );
}
}


/* --- Code / preformatted text (syntaxhighlight uses its own Pygments
/* Code / preformatted text (syntaxhighlight uses its own Pygments theme,
   theme, set via $wgPygmentsStyle in LocalSettings.php; this covers
   set via $wgPygmentsStyle in LocalSettings.php; this covers plain
   plain <pre>/<code> that isn't Pygments-highlighted). */
   <pre>/<code> that isn't Pygments-highlighted). */
pre, code, .mw-code {
pre, code, .mw-code {
background-color: #16191c;
background-color: var( --edfm-surface-2 );
color: #d7dade;
color: var( --edfm-text );
border-color: #33383e;
border-color: var( --edfm-border );
font-family: var( --edfm-mono );
}
 
/* ==========================================================================
  GENERIC INFOBOX -- see Template:Infobox
  ========================================================================== */
.edfm-infobox {
float: right;
clear: right;
width: 300px;
margin: 0 0 1.2em 1.2em;
border: 1px solid var( --edfm-orange );
background: var( --edfm-surface-2 );
color: var( --edfm-text );
font-size: 0.9em;
}
.edfm-infobox-title {
background: var( --edfm-orange );
color: var( --edfm-bg-deep );
font-weight: 700;
font-family: var( --edfm-mono );
letter-spacing: 0.04em;
text-transform: uppercase;
text-align: center;
padding: 0.4em 0.6em;
clip-path: polygon( 0 0, calc( 100% - 14px ) 0, 100% 14px, 100% 100%, 0 100% );
}
.edfm-infobox-image {
text-align: center;
padding: 0.6em;
border-bottom: 1px solid var( --edfm-border );
}
.edfm-infobox-row {
display: flex;
border-bottom: 1px solid var( --edfm-border-soft );
padding: 0.35em 0.6em;
}
.edfm-infobox-row:last-child {
border-bottom: none;
}
.edfm-infobox-label {
font-weight: 700;
font-family: var( --edfm-mono );
font-family: var( --edfm-mono );
font-size: 0.85em;
width: 40%;
flex-shrink: 0;
color: var( --edfm-cyan );
}
.edfm-infobox-value {
width: 60%;
}
@media ( max-width: 640px ) {
.edfm-infobox {
float: none;
width: auto;
margin: 1em 0;
}
}
}


/* --- Mobile: Vector legacy has NO built-in responsive breakpoint at all
/* ==========================================================================
   (unlike Vector 2022) -- its entire header region (#mw-head, tabs, search,
  14. MOBILE
   personal tools/login) is built with absolute positioning and floats that
  ========================================================================== */
   all assume a fixed-width sidebar reserving 10-11em on the left, AND the
/* Vector legacy has NO built-in responsive breakpoint at all (unlike
  page's actual DOM order is content-then-navigation-then-footer (the
   Vector 2022) -- its entire header region (#mw-head, tabs, search,
  absolute positioning was doing double duty: both moving the header
   personal tools/login) is built with absolute positioning and floats
   that all assume a fixed-width sidebar reserving 10-11em on the left,
  AND the page's actual DOM order is content-then-navigation-then-footer
  (the absolute positioning was doing double duty: both moving the header
   visually to the top AND compensating for that DOM order). Simply
   visually to the top AND compensating for that DOM order). Simply
   removing the positioning stacks things in DOM order, which reads oddly
   removing the positioning stacks things in DOM order, which reads oddly
   on a phone (article text, then the nav/sidebar, then the footer).
   on a phone (article text, then the nav/sidebar, then the footer).
   Confirmed the actual DOM structure directly (not guessed): <body>'s
   Confirmed the actual DOM structure directly (not guessed): <body>'s
   real children are #mw-page-base, #mw-head-base, #content, #mw-navigation
   real children are #mw-page-base, #mw-head-base, #content,
  (which itself contains #mw-head then #mw-panel, already in the right
  #mw-navigation (which itself contains #mw-head then #mw-panel, already
  relative order), #footer. Since all four major regions are direct
  in the right relative order), #footer. Since all four major regions are
   children of <body>, flexbox `order` on <body> can reorder them properly
   direct children of <body>, flexbox `order` on <body> can reorder them
   without needing to touch the DOM itself.
   properly without needing to touch the DOM itself.
   Result: header/search/tabs, then sidebar nav, then content, then
   Result: header/search/tabs, then sidebar nav, then content, then
   footer -- a plain stacked mobile layout, not a collapsible hamburger
   footer -- a plain stacked mobile layout, not a collapsible hamburger
Line 333: Line 827:
flex-direction: column;
flex-direction: column;
}
}
/* #mw-head-base ships with `margin-top: -5em` in Vector legacy's own CSS
/* #mw-head-base ships with `margin-top: -5em` in Vector legacy's own
  -- a trick to sit it behind the absolutely-positioned header. Now that
  CSS -- a trick to sit it behind the absolutely-positioned header.
  the header is a normal flex sibling, that negative margin drags
  Now that the header is a normal flex sibling, that negative margin
  everything after it upward. Neutralize both decorative strips. */
  drags everything after it upward. Neutralize both decorative
  strips. */
#mw-page-base,
#mw-page-base,
#mw-head-base {
#mw-head-base {
Line 393: Line 888:
padding: 0.5em 1em;
padding: 0.5em 1em;
float: none;
float: none;
border-top: 1px solid #2b2f33;
border-top: 1px solid var( --edfm-border );
border-bottom: 1px solid #2b2f33;
border-bottom: 1px solid var( --edfm-border );
}
}
.mw-body,
.mw-body,
Line 400: Line 895:
.mw-footer {
.mw-footer {
margin-left: 0;
margin-left: 0;
max-width: none;
}
}
.mw-body {
.mw-body {
Line 406: Line 902:
padding: 1em;
padding: 1em;
}
}
}
.edfm-status-details {
 
grid-template-columns: 1fr;
/* --- Generic infobox: a right-floated, bordered reference box, the kind of
}
  structural element most game-reference wikis use for at-a-glance specs.
.toc > ul {
  A clipped top-right corner + monospace title give it a restrained
gap: 0.3em 0.9em;
  "instrument panel" feel without glow, gradients, or game-specific
}
  chrome. See Template:Infobox for usage. */
#firstHeading {
.edfm-infobox {
font-size: 1.5em;
float: right;
clear: right;
width: 300px;
margin: 0 0 1.2em 1.2em;
border: 1px solid var( --edfm-orange );
background: #16191c;
color: #d7dade;
font-size: 0.9em;
}
.edfm-infobox-title {
background: var( --edfm-orange );
color: #14171a;
font-weight: 700;
font-family: var( --edfm-mono );
letter-spacing: 0.04em;
text-transform: uppercase;
text-align: center;
padding: 0.4em 0.6em;
clip-path: polygon( 0 0, calc( 100% - 14px ) 0, 100% 14px, 100% 100%, 0 100% );
}
.edfm-infobox-image {
text-align: center;
padding: 0.6em;
border-bottom: 1px solid #2b2f33;
}
.edfm-infobox-row {
display: flex;
border-bottom: 1px solid #23272b;
padding: 0.35em 0.6em;
}
.edfm-infobox-row:last-child {
border-bottom: none;
}
.edfm-infobox-label {
font-weight: 700;
font-family: var( --edfm-mono );
font-size: 0.85em;
width: 40%;
flex-shrink: 0;
color: var( --edfm-cyan );
}
.edfm-infobox-value {
width: 60%;
}
@media ( max-width: 640px ) {
.edfm-infobox {
float: none;
width: auto;
margin: 1em 0;
}
}
}
}

Revision as of 16:32, 7 August 2026

/* ==========================================================================
   EDFM site-wide styling -- "Elite Dangerous technical field manual" theme.
   Original CSS written for this project -- no code or assets copied from
   runescape.wiki, Elite Dangerous, or any other site/game, and no Frontier
   logo/branding/proprietary fonts/copied HUD elements. Restrained visual
   influence only: dark industrial surfaces, subtle angular geometry,
   orange/cyan accents used sparingly, information hierarchy first. This is
   a reference site, not a HUD -- no glow, no neon, no glassmorphism, no
   constant animation.

   SKIN NOTE: the site uses Vector "legacy" (2011), not Vector 2022 -- see
   the "Why Vector legacy" note in docs/content-style-guide.md (Vector 2022
   hard-restricts its pinned sidebar to logged-in users; legacy has no such
   restriction). Several rules below exist specifically to beat core Vector
   legacy/mediawiki.skinning selectors that are *more specific* than a naive
   override would be (documented inline at each occurrence) -- this isn't
   guesswork, each one was found by reading the actual core .less source and
   confirmed with a real rendered screenshot, not just computed-style checks
   (:visited colours in particular are invisible to getComputedStyle by
   design -- see the tab-bar note below).

   File organised to mirror the 2026-08-07 redesign brief's own section
   numbers, so both stay easy to cross-reference.
   ========================================================================== */

/* ==========================================================================
   1. DESIGN TOKENS
   ========================================================================== */
:root {
	/* Surfaces -- darkest to lightest */
	--edfm-bg-deep: #090d0f;
	--edfm-bg-page: #0d1215;
	--edfm-surface-1: #12181c;
	--edfm-surface-2: #171f24;
	--edfm-surface-3: #1c252b;

	/* Borders */
	--edfm-border: #273239;
	--edfm-border-soft: rgba( 255, 255, 255, 0.07 );

	/* Text */
	--edfm-text: #e7eaec;
	--edfm-text-muted: #8e9aa1;
	--edfm-text-dim: #68757c;

	/* Accents -- orange is reserved for navigation/selection/emphasis/
	   section numbering; cyan/blue are for links, verification info, and
	   secondary interface elements. See "Links" and "Colour system" in
	   docs/content-style-guide.md for the reasoning. */
	--edfm-orange: #ff8a00;
	--edfm-orange-bright: #ffa21a;
	--edfm-cyan: #42c7d9;
	--edfm-blue: #4f9fe8;

	/* Derived link colours (not part of the operator's token list verbatim,
	   but named separately so link handling reads as its own concern) */
	--edfm-link: var( --edfm-blue );
	--edfm-link-visited: #3f7bb3;
	--edfm-link-hover: #8cc4f7;
	--edfm-link-external: var( --edfm-cyan );
	--edfm-link-external-visited: #2f8f9c;
	--edfm-link-external-hover: #7fe0ec;
	--edfm-link-new: #e07a7a;

	/* Status semantics (article metadata module) -- text label always
	   present too, never colour-only. */
	--edfm-status-positive: var( --edfm-cyan );
	--edfm-status-attention: var( --edfm-orange );
	--edfm-status-neutral: var( --edfm-text-dim );

	/* Typography */
	--edfm-mono: 'JetBrains Mono', 'Fira Code', Consolas, 'SF Mono', Menlo, 'Courier New', monospace;
	--edfm-sans: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;

	/* Legacy aliases: earlier revisions of this stylesheet used these names
	   directly and some inline template output/older docs may still refer
	   to them; keep pointing at the current tokens rather than duplicate
	   values that could drift out of sync. */
	--edfm-orange-hover: var( --edfm-orange-bright );
	--edfm-orange-active: var( --edfm-orange-bright );
	--color-progressive: var( --edfm-orange );
	--color-progressive--hover: var( --edfm-orange-bright );
	--color-progressive--active: var( --edfm-orange-bright );
	--color-progressive--focus: var( --edfm-orange );
	--background-color-progressive: var( --edfm-orange );
	--background-color-progressive--hover: var( --edfm-orange-bright );
	--background-color-progressive--active: var( --edfm-orange-bright );
	--border-color-progressive: var( --edfm-orange );
	--border-color-progressive--hover: var( --edfm-orange-bright );
	--border-color-progressive--active: var( --edfm-orange-bright );

	/* Shared geometry: a small clipped corner reads as "technical panel"
	   without a giant border-radius anywhere on the site. */
	--edfm-corner: 10px;
	--edfm-content-max: 1200px;
}

/* ==========================================================================
   2. BASE / RESET-ADJACENT
   ========================================================================== */
html, body {
	background-color: var( --edfm-bg-page );
	color: var( --edfm-text );
}
body.mediawiki {
	color: var( --edfm-text );
	font-family: var( --edfm-sans );
}
/* Very faint (~2.5%) technical grid across the page background. Only
   visible where an opaque panel (sidebar, article surface, tables) isn't
   already covering it -- the header strip, the sidebar, and the margin
   outside the width-capped article column on wide screens. Not an image
   asset; pure CSS gradients. */
body {
	background-image:
		linear-gradient( rgba( 255, 255, 255, 0.025 ) 1px, transparent 1px ),
		linear-gradient( 90deg, rgba( 255, 255, 255, 0.025 ) 1px, transparent 1px );
	background-size: 48px 48px;
}
@media ( prefers-reduced-motion: reduce ) {
	*, *::before, *::after {
		animation-duration: 0.001ms !important;
		animation-iteration-count: 1 !important;
		transition-duration: 0.001ms !important;
		scroll-behavior: auto !important;
	}
}
/* Focus visibility: the pre-redesign stylesheet had no explicit focus
   styling at all (relying entirely on browser defaults, which vary and can
   be hard to see against a dark theme). Applies to every interactive
   element, not just links. */
a:focus-visible,
button:focus-visible,
input:focus-visible,
textarea:focus-visible,
select:focus-visible,
[tabindex]:focus-visible {
	outline: 2px solid var( --edfm-cyan );
	outline-offset: 2px;
}

/* ==========================================================================
   3. TYPOGRAPHY
   ========================================================================== */
h1, h2, h3, h4, h5, h6 {
	color: var( --edfm-text );
	border-color: var( --edfm-border );
}
/* !important justified here: MediaWiki core's mediawiki.skinning module
   sets heading colour with equal-specificity plain-tag selectors and kept
   winning in testing despite this stylesheet loading later -- rather than
   keep chasing exact cascade/bundling order, force it. This is a
   correctness/contrast fix, not decoration. */
.mw-body h1, .mw-body h2, .mw-body h3, .mw-body h4, .mw-body h5, .mw-body h6,
.mw-heading1, .mw-heading2, .mw-heading3, .mw-heading4, .mw-heading5, .mw-heading6,
h1, h2, h3, h4, h5, h6 {
	color: var( --edfm-text ) !important;
	border-color: var( --edfm-border ) !important;
	font-family: var( --edfm-mono );
	letter-spacing: 0.01em;
	line-height: 1.3;
}
#firstHeading {
	color: var( --edfm-text ) !important;
	font-family: var( --edfm-mono );
	font-size: 1.9em;
}
/* Restrained "instrument label" bracket treatment on major section
   headings (h2): a plain "// " prefix via ::before (no image, no glow, no
   animation) plus a short orange accent segment layered over the
   otherwise-dim divider line core already draws under h2. If a heading
   opts into explicit numbering via {{Section number}} (see
   .edfm-section-number below), the automatic "// " is suppressed so the
   two treatments don't double up. */
.mw-body h2 {
	position: relative;
	padding-bottom: 0.3em;
	margin-top: 1.6em;
}
.mw-body h2::before {
	content: '// ';
	color: var( --edfm-orange );
	font-weight: 400;
}
.mw-body h2:has( .edfm-section-number )::before {
	content: none;
}
.mw-body h2::after {
	content: '';
	position: absolute;
	left: 0;
	bottom: -1px;
	width: 3em;
	max-width: 100%;
	height: 2px;
	background: var( --edfm-orange );
}
.edfm-section-number {
	color: var( --edfm-orange );
	font-weight: 700;
}
.edfm-section-sep {
	color: var( --edfm-orange );
	margin-right: 0.15em;
}
h3, h4 {
	color: var( --edfm-text );
}
h3::before {
	content: '/ ';
	color: var( --edfm-text-dim );
	font-weight: 400;
}

/* Body text: readable sans-serif, deliberately NOT monospace -- long-form
   reading in monospace hurts readability, which stays a hard requirement
   even with a more technical visual language elsewhere. */
.mw-body p,
.mw-body li,
.mw-body dd {
	line-height: 1.65;
}
.mw-body p {
	margin: 0 0 1em 0;
	max-width: 74em; /* comfortable measure even inside the wider content column */
}
.mw-body ul,
.mw-body ol {
	line-height: 1.65;
	margin-bottom: 1em;
}
.mw-body h2 + p,
.mw-body h3 + p {
	margin-top: 0.6em;
}
hr {
	background-color: var( --edfm-border );
	border-color: var( --edfm-border );
}

/* ==========================================================================
   8. LINKS
   ========================================================================== */
a { color: var( --edfm-link ); transition: color 0.1s ease; }
a:visited { color: var( --edfm-link-visited ); }
a:hover { color: var( --edfm-link-hover ); }
a.new, .new a { color: var( --edfm-link-new ); }
a.external { color: var( --edfm-link-external ); }
/* Core MediaWiki ships `.mw-parser-output a.external`/`a.extiw` (and their
   :visited/:hover states) at higher specificity (two classes + a tag) than
   a plain `a.external` rule (one class + a tag), so the line above never
   actually wins for real article links on its own -- the same underlying
   "core selector outranks a naive theme override" gotcha as the tab
   :visited fix further down. Matching the same selector shape here (this
   stylesheet loads after core skin styles) is what actually applies our
   colour to external links in article content. */
.mw-parser-output a.external,
.mw-parser-output a.extiw {
	color: var( --edfm-link-external );
}
.mw-parser-output a.external:visited,
.mw-parser-output a.extiw:visited {
	color: var( --edfm-link-external-visited );
}
.mw-parser-output a.external:hover,
.mw-parser-output a.extiw:hover {
	color: var( --edfm-link-external-hover );
}
.mw-footer a {
	color: var( --edfm-link );
}
.mw-footer a:hover {
	color: var( --edfm-link-hover );
}

/* ==========================================================================
   1 + 4. GLOBAL LAYOUT / ARTICLE HEADER
   ========================================================================== */
/* Vector legacy's core layout (skins.vector.styles.legacy/layouts/screen.less)
   gives `.mw-body` (#content) a left margin to clear the fixed-width
   sidebar and otherwise lets it run edge-to-edge to the browser's right
   side -- there is no max-width at all, which is why content stretched
   excessively on large displays. Capping width here only affects the
   article/footer column; the full-width header/tab bar above it is left
   alone deliberately (its own float/absolute-position math is exactly what
   an earlier round of this project had to carefully debug to get the
   persistent sidebar working at all -- touching it again for a purely
   cosmetic width cap isn't worth the regression risk). A full-bleed
   toolbar above a capped content column is also just a normal, accepted
   pattern on technical documentation sites. */
.mw-body,
#mw-data-after-content,
.mw-footer {
	max-width: var( --edfm-content-max );
	box-sizing: border-box;
}
/* Tables, code blocks, and preformatted content are still allowed to be
   wider than a comfortable reading measure (technical data often needs
   it) -- they scroll horizontally inside the capped column instead of
   being force-shrunk or breaking the layout. Ordinary images/galleries
   already respect the column via max-width:100% below. */
.mw-body table,
.mw-body pre,
.mw-body .mw-code {
	max-width: 100%;
	overflow-x: auto;
}
.mw-body table.wikitable,
.mw-body table.mw-datatable {
	display: block;
	overflow-x: auto;
}
.mw-body table.wikitable tbody,
.mw-body table.mw-datatable tbody {
	display: table;
	width: 100%;
}
.mw-body img {
	max-width: 100%;
	height: auto;
}

/* Eyebrow / deck (see Template:Article header). The eyebrow line is
   authored as ordinary wikitext and, purely as a placement detail, a small
   script (MediaWiki:Common.js) moves it directly above #firstHeading on
   page load -- see the comment there for why that needs JS rather than
   CSS/a template (the title is rendered by the skin before the article
   body in the DOM, so nothing living inside the article body can appear
   earlier than it without either moving it in the DOM or abandoning the
   real semantic H1, and the brief is explicit the H1 must stay the real
   H1). If JS is unavailable the eyebrow still renders, just directly under
   the title instead of above it -- nothing breaks, it's a placement
   nicety, not functionality. */
.edfm-eyebrow {
	margin: 0 0 0.3em 0;
	font-family: var( --edfm-mono );
	font-size: 0.75em;
	font-weight: 700;
	letter-spacing: 0.08em;
	text-transform: uppercase;
	color: var( --edfm-text-dim );
}
.edfm-eyebrow .edfm-orange-mark {
	color: var( --edfm-orange );
}
.edfm-deck {
	color: var( --edfm-text-muted );
	font-size: 1.05em;
	max-width: 60em;
	margin: 0.3em 0 1.2em 0;
}

/* ==========================================================================
   1. SIDEBAR
   ========================================================================== */
#mw-panel {
	background-color: var( --edfm-bg-deep );
}
#mw-panel .portal .body,
#mw-panel .portal ul {
	border-color: var( --edfm-border-soft );
}
#mw-panel .portal a {
	color: var( --edfm-text-muted );
	display: block;
	padding: 0.15em 0.4em;
	margin: 0 -0.4em;
	border-left: 2px solid transparent;
	border-radius: 0;
}
#mw-panel .portal a:hover {
	color: var( --edfm-cyan );
	background: var( --edfm-surface-1 );
}
/* "You are here" -- MediaWiki's sidebar has no built-in current-page
   indication; MediaWiki:Common.js adds the .edfm-nav-current class to the
   matching list item by comparing hrefs to the current URL. Orange is
   reserved for exactly this kind of "important navigation / selected
   state" per the colour system, which is why the rest of the sidebar is
   deliberately muted rather than orange throughout (an all-orange sidebar
   would both fight this indicator and read as visually dominant, which the
   brief specifically calls out to avoid). */
.edfm-nav-current > a {
	color: var( --edfm-orange ) !important;
	font-weight: 700;
	border-left-color: var( --edfm-orange );
	background: var( --edfm-surface-1 );
}
.vector-menu-heading {
	color: var( --edfm-text-dim );
	font-weight: 700;
	font-family: var( --edfm-mono );
	letter-spacing: 0.08em;
	text-transform: uppercase;
	font-size: 0.75em;
	border-left: 2px solid var( --edfm-orange );
	padding-left: 0.5em;
	margin-left: -0.5em;
}

/* ==========================================================================
   4/9. HEADER / MASTHEAD / MEDIAWIKI TABS
   ========================================================================== */
#mw-page-base {
	background-color: var( --edfm-bg-deep );
	background-image: none;
}
#mw-head-base {
	background-color: var( --edfm-bg-deep );
}
#p-personal,
.vector-header-container {
	border-bottom: 2px solid var( --edfm-orange );
}
#mw-head-base {
	border-bottom: 2px solid var( --edfm-orange );
}
/* Personal tools (login/logout) -- a real action, kept orange-adjacent but
   quiet until interacted with, matching "utility control" treatment. */
#p-personal a {
	color: var( --edfm-text-muted );
	font-family: var( --edfm-mono );
}
#p-personal a:hover {
	color: var( --edfm-orange );
}
/* Namespace tabs (Main Page / Discussion, left) and view tabs
   (Read / Edit / View history, right) both use Vector legacy's
   .vector-menu-tabs-legacy markup. Core skin CSS paints every tab `li`
   with a gradient fading to white and forces the selected tab to pure
   white -- neither is touched by recolouring the link text alone, which is
   why these stayed light before this stylesheet covered the `li`
   background too. Core also has an `a:visited` rule (higher specificity
   than a plain `a` rule, since a pseudo-class counts the same as a class)
   that reasserts a near-black "visited" colour meant for a white
   background; since these tabs point at pages you've almost always
   already visited, without an explicit `:visited` override here the text
   goes dark-on-dark. This can't be caught by reading getComputedStyle() in
   an automated check -- browsers deliberately report the *unvisited*
   colour to JS for privacy reasons, so it only shows up on an actual
   screen; verified with real rendered screenshots, including after
   genuinely visiting the linked pages first.

   Per the redesign brief, tabs are "important navigation" (namespace
   identity) rather than "utility controls" (the view/actions tabs, see
   below) -- selected state stays orange; unselected rests at a slightly
   dimmer neutral than article body text so the *selected* tab still reads
   as the clear focal point. */
.vector-menu-tabs-legacy li {
	background-image: none;
	background-color: var( --edfm-surface-2 );
}
.vector-menu-tabs-legacy li.selected {
	background-image: none;
	background-color: var( --edfm-surface-1 );
}
.vector-menu-tabs-legacy li a,
.vector-menu-tabs-legacy li a:visited {
	background-color: transparent;
	color: var( --edfm-text-dim );
	font-family: var( --edfm-mono );
	letter-spacing: 0.01em;
}
.vector-menu-tabs-legacy li a:hover,
.vector-menu-tabs-legacy li a:visited:hover {
	color: var( --edfm-text );
}
.vector-menu-tabs-legacy li.selected a,
.vector-menu-tabs-legacy li.selected a:visited {
	color: var( --edfm-orange );
}
.vector-menu-tabs-legacy li.new a,
.vector-menu-tabs-legacy li.new a:visited {
	color: var( --edfm-link-new );
}
/* "More" actions dropdown (#p-cactions) sits in the same tab row; same
   :visited gotcha applies to its menu items. Kept deliberately quiet --
   this is the clearest case of "utility control, not primary nav". */
.vector-menu-dropdown .vector-menu-heading {
	color: var( --edfm-text-dim );
	font-family: var( --edfm-mono );
	border-left: none;
	padding-left: 8px;
	margin-left: 0;
	text-transform: none;
	letter-spacing: normal;
	font-size: 1em;
	font-weight: normal;
}
.vector-menu-dropdown .vector-menu-heading:hover,
.vector-menu-dropdown .vector-menu-heading:focus {
	color: var( --edfm-orange );
}
.vector-menu-dropdown .vector-menu-content {
	background-color: var( --edfm-surface-2 );
	border-color: var( --edfm-border );
}
.vector-menu-dropdown .vector-menu-content a,
.vector-menu-dropdown .vector-menu-content a:visited {
	color: var( --edfm-text-muted );
}
.vector-menu-dropdown .vector-menu-content li.selected a,
.vector-menu-dropdown .vector-menu-content li.selected a:visited {
	color: var( --edfm-orange );
}
.vector-menu-dropdown .vector-menu-content li:hover {
	background-color: var( --edfm-surface-3 );
}
.vector-search-box-inner input,
#searchInput {
	background-color: var( --edfm-surface-2 );
	color: var( --edfm-text );
	border: 1px solid var( --edfm-border );
	font-family: var( --edfm-mono );
}
#searchInput::placeholder {
	color: var( --edfm-text-dim );
}

/* ==========================================================================
   CONTENT / ARTICLE SURFACE
   ========================================================================== */
.mw-body,
.parsoid-body {
	background-color: var( --edfm-surface-1 );
	color: var( --edfm-text );
	border-color: var( --edfm-border );
	font-family: var( --edfm-sans );
}
#content {
	background-color: var( --edfm-surface-1 );
}

/* ==========================================================================
   10. TABLE OF CONTENTS
   ========================================================================== */
/* Restyled as an "EDFM navigation module" rather than a default wiki TOC,
   while leaving MediaWiki's actual TOC markup/anchors completely alone --
   this is presentation only. "Contents" is kept in the DOM for screen
   readers/no-JS/no-CSS fallback (more standard wording there anyway) and
   visually replaced with "Jump to" via ::before on the wrapper, with the
   real heading text hidden via font-size rather than display:none so it
   remains in the accessibility tree. */
#toc, .toc {
	background-color: var( --edfm-surface-2 ) !important;
	border: 1px solid var( --edfm-border ) !important;
	color: var( --edfm-text );
	padding: 0.8em 1em;
	clip-path: polygon( 0 0, calc( 100% - var( --edfm-corner ) ) 0, 100% var( --edfm-corner ), 100% 100%, 0 100% );
}
.toctitle {
	position: relative;
	margin-bottom: 0.4em;
}
.toctitle::before {
	content: 'Jump to';
	font-family: var( --edfm-mono );
	font-size: 0.75em;
	font-weight: 700;
	letter-spacing: 0.1em;
	text-transform: uppercase;
	color: var( --edfm-orange );
}
.toctitle h2 {
	font-size: 0;
	line-height: 0;
	margin: 0;
	border: none;
	padding: 0;
	display: inline;
}
.toctitle h2::before,
.toctitle h2::after {
	content: none;
}
.toctogglelabel::before {
	color: var( --edfm-text-dim );
}
/* Top-level entries as wrapped horizontal "chips" -- reads well for the
   short/medium pages this site mostly has, and simply wraps onto more
   rows for longer ones rather than needing a separate vertical mode. */
.toc > ul {
	display: flex;
	flex-wrap: wrap;
	gap: 0.4em 1.2em;
	list-style: none;
	margin: 0;
	padding: 0;
}
.toc ul ul {
	flex-basis: 100%;
	width: 100%;
	list-style: none;
	margin: 0.2em 0 0.2em 1.4em;
	padding: 0;
	display: block;
}
.toc li {
	margin: 0;
}
.toc a {
	display: inline-flex;
	align-items: baseline;
	gap: 0.35em;
	color: var( --edfm-text-muted );
	text-decoration: none;
	font-size: 0.92em;
}
.toc a:hover {
	color: var( --edfm-cyan );
}
.tocnumber {
	color: var( --edfm-orange );
	font-family: var( --edfm-mono );
	font-weight: 700;
	min-width: 1.2em;
}
.toctext {
	color: inherit;
}

/* ==========================================================================
   6. PANELS / CALLOUTS, and 11. ARTICLE METADATA / STATUS MODULE
   ========================================================================== */
/* Deliberately NOT defined here. .edfm-box / .edfm-panel* / .edfm-status* /
   .edfm-inline-flag are used exclusively by the editorial templates (see
   Template:Article status, Template:Draft warning, etc.), which already
   load Template:EDFM style/styles.css themselves via <templatestyles>.
   Defining the same class names in both this file and that one would
   leave their relative precedence dependent on unclear/unstable ordering
   between a ResourceLoader "site" stylesheet and a TemplateStyles-injected
   <style> tag -- rather than rely on that, there is exactly one definition
   of each, living in Template:EDFM style/styles.css. That file freely uses
   the --edfm-* custom properties defined above; custom properties resolve
   through the DOM regardless of which stylesheet declared vs references
   them, so this split costs nothing. */

/* ==========================================================================
   7. TABLES (wikitables, and Special: pages' tables)
   ========================================================================== */
table.wikitable,
table.mw-datatable {
	background-color: var( --edfm-surface-2 );
	color: var( --edfm-text );
	border-color: var( --edfm-border );
}
table.wikitable > tr > th,
table.wikitable > * > tr > th {
	background-color: var( --edfm-surface-3 );
	color: var( --edfm-text );
	border-color: var( --edfm-border );
	font-family: var( --edfm-mono );
	letter-spacing: 0.03em;
	text-transform: uppercase;
	font-size: 0.85em;
	text-align: left;
}
table.wikitable > tr > td,
table.wikitable > * > tr > td {
	border-color: var( --edfm-border-soft );
	padding: 0.5em 0.7em;
}
/* Subtle alternating row treatment -- helps scanning wide/dense reference
   tables without turning them into cards. */
table.wikitable > tbody > tr:nth-child( even ),
table.wikitable > * > tr:nth-child( even ) {
	background-color: var( --edfm-surface-1 );
}

/* ==========================================================================
   13. FOOTER
   ========================================================================== */
.mw-footer {
	margin-left: auto;
	margin-right: auto;
	border-top: 1px solid var( --edfm-border );
	display: grid;
	grid-template-columns: 1fr auto;
	grid-template-areas: "info icons" "places icons";
	align-items: center;
	column-gap: 2em;
	row-gap: 0.3em;
}
.mw-footer,
.mw-footer li,
#footer-info,
#footer-info li {
	color: var( --edfm-text-dim );
	border-color: var( --edfm-border-soft );
}
#footer-info {
	grid-area: info;
	margin: 0;
}
#footer-places {
	grid-area: places;
	margin: 0;
}
#footer-icons {
	grid-area: icons;
	align-self: center;
	display: flex;
	gap: 0.75em;
	margin: 0;
}
#footer-icons img {
	background: var( --edfm-text );
	border-radius: 2px;
}
@media ( max-width: 640px ) {
	.mw-footer {
		grid-template-columns: 1fr;
		grid-template-areas: "info" "places" "icons";
	}
	#footer-icons {
		margin-top: 0.5em;
	}
}

/* ==========================================================================
   MISC MediaWiki UI chrome that ships with light backgrounds by default
   ========================================================================== */
.catlinks {
	background-color: var( --edfm-surface-2 ) !important;
	border-color: var( --edfm-border ) !important;
	color: var( --edfm-text-muted );
}
div.thumbinner {
	background-color: var( --edfm-surface-2 );
	border-color: var( --edfm-border );
}
.thumbimage {
	background-color: var( --edfm-surface-1 );
	border-color: var( --edfm-border );
}

/* Code / preformatted text (syntaxhighlight uses its own Pygments theme,
   set via $wgPygmentsStyle in LocalSettings.php; this covers plain
   <pre>/<code> that isn't Pygments-highlighted). */
pre, code, .mw-code {
	background-color: var( --edfm-surface-2 );
	color: var( --edfm-text );
	border-color: var( --edfm-border );
	font-family: var( --edfm-mono );
}

/* ==========================================================================
   GENERIC INFOBOX -- see Template:Infobox
   ========================================================================== */
.edfm-infobox {
	float: right;
	clear: right;
	width: 300px;
	margin: 0 0 1.2em 1.2em;
	border: 1px solid var( --edfm-orange );
	background: var( --edfm-surface-2 );
	color: var( --edfm-text );
	font-size: 0.9em;
}
.edfm-infobox-title {
	background: var( --edfm-orange );
	color: var( --edfm-bg-deep );
	font-weight: 700;
	font-family: var( --edfm-mono );
	letter-spacing: 0.04em;
	text-transform: uppercase;
	text-align: center;
	padding: 0.4em 0.6em;
	clip-path: polygon( 0 0, calc( 100% - 14px ) 0, 100% 14px, 100% 100%, 0 100% );
}
.edfm-infobox-image {
	text-align: center;
	padding: 0.6em;
	border-bottom: 1px solid var( --edfm-border );
}
.edfm-infobox-row {
	display: flex;
	border-bottom: 1px solid var( --edfm-border-soft );
	padding: 0.35em 0.6em;
}
.edfm-infobox-row:last-child {
	border-bottom: none;
}
.edfm-infobox-label {
	font-weight: 700;
	font-family: var( --edfm-mono );
	font-size: 0.85em;
	width: 40%;
	flex-shrink: 0;
	color: var( --edfm-cyan );
}
.edfm-infobox-value {
	width: 60%;
}
@media ( max-width: 640px ) {
	.edfm-infobox {
		float: none;
		width: auto;
		margin: 1em 0;
	}
}

/* ==========================================================================
   14. MOBILE
   ========================================================================== */
/* Vector legacy has NO built-in responsive breakpoint at all (unlike
   Vector 2022) -- its entire header region (#mw-head, tabs, search,
   personal tools/login) is built with absolute positioning and floats
   that all assume a fixed-width sidebar reserving 10-11em on the left,
   AND the page's actual DOM order is content-then-navigation-then-footer
   (the absolute positioning was doing double duty: both moving the header
   visually to the top AND compensating for that DOM order). Simply
   removing the positioning stacks things in DOM order, which reads oddly
   on a phone (article text, then the nav/sidebar, then the footer).
   Confirmed the actual DOM structure directly (not guessed): <body>'s
   real children are #mw-page-base, #mw-head-base, #content,
   #mw-navigation (which itself contains #mw-head then #mw-panel, already
   in the right relative order), #footer. Since all four major regions are
   direct children of <body>, flexbox `order` on <body> can reorder them
   properly without needing to touch the DOM itself.
   Result: header/search/tabs, then sidebar nav, then content, then
   footer -- a plain stacked mobile layout, not a collapsible hamburger
   menu, but a correct and readable order. */
@media ( max-width: 800px ) {
	body {
		display: flex;
		flex-direction: column;
	}
	/* #mw-head-base ships with `margin-top: -5em` in Vector legacy's own
	   CSS -- a trick to sit it behind the absolutely-positioned header.
	   Now that the header is a normal flex sibling, that negative margin
	   drags everything after it upward. Neutralize both decorative
	   strips. */
	#mw-page-base,
	#mw-head-base {
		order: 0;
		height: 0;
		margin: 0;
		min-height: 0;
	}
	#mw-navigation {
		order: 1;
	}
	#content {
		order: 2;
	}
	.mw-footer {
		order: 3;
	}

	#mw-head {
		position: static;
		width: auto;
	}
	#left-navigation,
	#right-navigation {
		float: none;
		margin: 0;
		width: auto;
		clear: both;
	}
	#left-navigation {
		margin-top: 0;
	}
	#p-personal {
		position: static;
		text-align: right;
		padding: 0.5em 1em;
		margin: 0;
		right: auto;
		top: auto;
	}
	#p-personal ul {
		padding-left: 0;
	}
	.vector-search-box {
		float: none;
		margin: 0.5em 1em;
		display: block;
	}
	.vector-search-box-inner {
		width: auto;
		max-width: none;
	}
	#mw-panel {
		position: static;
		width: auto;
		padding: 0.5em 1em;
		float: none;
		border-top: 1px solid var( --edfm-border );
		border-bottom: 1px solid var( --edfm-border );
	}
	.mw-body,
	#mw-data-after-content,
	.mw-footer {
		margin-left: 0;
		max-width: none;
	}
	.mw-body {
		margin-top: 0;
		border-width: 0;
		padding: 1em;
	}
	.edfm-status-details {
		grid-template-columns: 1fr;
	}
	.toc > ul {
		gap: 0.3em 0.9em;
	}
	#firstHeading {
		font-size: 1.5em;
	}
}