MediaWiki:Common.css: Difference between revisions

Current answers. Practical procedures. Reliable reference.
Jump to navigation Jump to search
Add logo spacing above sidebar Discord invite button
Make Frontier news panel images uniform
Tag: Blanking
Line 1: Line 1:
/* ==========================================================================
  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).
  2026-08-07 SECOND PASS: the first redesign pass was judged too close to
  stock MediaWiki with a colour change -- this pass changes the actual
  visual composition (centred workspace instead of a huge dead gutter,
  a two-tier header, a real masthead, a tile-grid TOC, a restructured
  status module, larger deliberate type scale, depth via surface
  elevation instead of borders-around-everything) while reusing every
  working mechanism from the first pass rather than throwing it away --
  the tab/:visited fix, the external-link specificity fix, the mobile
  reorder fix, and focus-visible/reduced-motion are all still here,
  unchanged in mechanism.
  ========================================================================== */
/* ==========================================================================
  1. DESIGN TOKENS
  ========================================================================== */
:root {
/* Depth system: site (outermost, visible in the sidebar/header/gutters)
  -> article surface -> component surfaces, each a deliberate step
  brighter so the page reads as having actual depth rather than "one
  background colour with slightly lighter boxes everywhere". */
--edfm-bg-deep: #07090b;
--edfm-bg-page: #0a0e11;
--edfm-surface-1: #10171b;
--edfm-surface-2: #161f24;
--edfm-surface-3: #1c272d;
--edfm-surface-4: #233037;
--edfm-border: #26333b;
--edfm-border-soft: rgba( 255, 255, 255, 0.06 );
--edfm-text: #edf0f2;
--edfm-text-muted: #98a5ad;
--edfm-text-dim: #6c7a82;
/* 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 */
--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 );
--edfm-status-positive-bg: rgba( 66, 199, 217, 0.12 );
--edfm-status-attention-bg: rgba( 255, 138, 0, 0.12 );
--edfm-status-neutral-bg: rgba( 108, 122, 130, 0.12 );
/* Typography -- explicit desktop scale (2026-08-07 pass 2). Sized in
  rem against the root's real 16px (Vector legacy's own
  @font-size-root is 100%, i.e. browser default -- confirmed by
  reading skins.vector.styles.legacy/variables.less, not assumed)
  rather than nested em, specifically so component sizes can't
  compound smaller than intended inside whatever ambient size an
  ancestor happens to set. */
--edfm-fs-title: clamp( 1.9rem, 1.4rem + 2vw, 2.25rem ); /* ~30-36px */
--edfm-fs-h2: 1.35rem; /* ~21.6px */
--edfm-fs-h3: 1.15rem; /* ~18.4px */
--edfm-fs-body: 1rem; /* 16px */
--edfm-fs-resource-name: 1.1rem; /* ~17.6px */
--edfm-fs-meta: 0.8rem; /* ~12.8px */
--edfm-fs-sidebar: 0.9375rem; /* 15px -- polish pass: +1px for readability */
--edfm-fs-utility: 0.72rem; /* ~11.5px */
--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 );
/* Geometry / layout */
--edfm-corner: 10px;
/* Polish-pass bump from 1280px -- article read as slightly too narrow
  on large desktop displays, and future reference tables (engineering,
  ship stats, colonisation data) will want the room. Still centred
  within the workspace via --edfm-gutter below, not stretched
  edge-to-edge. */
--edfm-content-max: 1320px;
/* RuneScape.wiki-style integrated rail: wide enough for readable labels,
  but joined directly to the page plane. Width and clear match so the
  article starts beside the sidebar shadow instead of after a dead gutter. */
--edfm-sidebar-width: 12.75rem;
--edfm-sidebar-clear: 12.75rem;
/* The gutter is whatever's left of the workspace (viewport minus the
  sidebar) after the capped content width, split evenly, never
  negative. On a screen too narrow to fit sidebar+content-max, this
  collapses to 0 and content just fills the workspace edge-to-edge --
  see "GLOBAL LAYOUT" below for the full explanation. */
--edfm-gutter: max( 0px, calc( ( 100vw - var( --edfm-sidebar-clear ) - var( --edfm-content-max ) ) / 2 ) );
}
/* ==========================================================================
  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 );
font-size: var( --edfm-fs-body );
}
/* Background treatment: a faint technical grid plus a very soft radial
  glow centred behind the (now centred) content column, so the composition
  still has quiet visual interest in the gutters on ultrawide screens
  instead of just flat colour -- both stay under ~3% opacity, this is
  texture, not a HUD. Not image assets; pure CSS gradients. */
body {
background-image:
radial-gradient( ellipse 1400px 900px at 50% 0%, rgba( 66, 199, 217, 0.05 ), transparent 60% ),
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: auto, 48px 48px, 48px 48px;
background-repeat: no-repeat, repeat, repeat;
background-attachment: fixed, scroll, scroll;
}
/* Full-height sidebar rail: mirrors the RuneScape.wiki behavior where the
  left rail has no visible bottom edge. The real #mw-panel only carries the
  navigation content; this fixed layer paints the uninterrupted surface,
  border, and shadow down the whole viewport. */
body::before {
content: '';
position: fixed;
top: 0;
left: 0;
bottom: 0;
width: var( --edfm-sidebar-width );
background: linear-gradient( 180deg, var( --edfm-surface-1 ) 0%, var( --edfm-bg-deep ) 100% );
border-right: 1px solid var( --edfm-border );
box-shadow: 10px 0 22px rgba( 0, 0, 0, 0.32 );
pointer-events: none;
z-index: 1;
}
@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: 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;
}
/* Small reusable angular motif: a corner-cut bracket, used sparingly (see
  the redesign notes in docs/content-style-guide.md for exactly where) --
  deliberately not applied everywhere. */
.edfm-corner-cut {
clip-path: polygon( 0 0, calc( 100% - var( --edfm-corner ) ) 0, 100% var( --edfm-corner ), 100% 100%, 0 100% );
}
/* ==========================================================================
  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: var( --edfm-fs-title );
font-weight: 700;
margin-top: 0.15em;
}
/* Section headings (h2): "// " prefix in orange, bright heading text, a
  short orange accent segment over the dim full-width divider core
  already draws. Substantially more vertical space than a wiki section
  normally gets, per the "sections feel packed together" fix -- 3.25rem
  (~52px) above, ~1.1rem gap to the first content component below. If a
  heading opts into explicit numbering via {{Section number}}, the
  automatic "// " is suppressed so the two treatments don't double up. */
.mw-body h2 {
position: relative;
padding-bottom: 0.4em;
margin-top: 3.25rem;
margin-bottom: 1.1rem;
font-size: var( --edfm-fs-h2 );
}
.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 );
font-size: var( --edfm-fs-h3 );
}
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.7;
font-size: var( --edfm-fs-body );
}
.mw-body p {
margin: 0 0 1.1em 0;
max-width: 46em; /* comfortable reading measure, not the full column */
}
.mw-body ul,
.mw-body ol {
line-height: 1.7;
margin-bottom: 1.1em;
}
/* MW 1.46 wraps headings in a `.mw-heading2`/`.mw-heading3` div, so the
  sibling that immediately follows is that wrapper, not the `h2`/`h3`
  itself -- matching both forms since a page could still have a bare
  heading in edge cases (e.g. content generated without the wrapper). */
.mw-heading2 + p, .mw-body h2 + p,
.mw-heading3 + p, .mw-body h3 + p,
.mw-heading2 + div, .mw-body h2 + div,
.mw-heading3 + div, .mw-body h3 + div {
margin-top: 0;
}
hr {
background-color: var( --edfm-border );
border-color: var( --edfm-border );
}
/* Quiet, discoverable section-edit controls (logged-in editors only --
  MediaWiki only renders these for users who can edit). Keeping the
  functionality/keyboard access intact while making sure they don't
  compete visually with the heading they're attached to: low opacity at
  rest, full opacity on hover/focus of the heading OR the control itself,
  brackets hidden (the opacity+letter-spacing treatment already reads as
  a distinct control without them). */
.mw-editsection {
margin-left: 1em;
font-family: var( --edfm-mono );
font-size: var( --edfm-fs-utility ) !important;
font-weight: 700;
letter-spacing: 0.05em;
text-transform: uppercase;
opacity: 0.45;
transition: opacity 0.15s ease;
}
.mw-heading:hover .mw-editsection,
.mw-heading:focus-within .mw-editsection,
.mw-editsection:hover,
.mw-editsection:focus-within {
opacity: 1;
}
.mw-editsection a {
color: var( --edfm-text-dim );
}
.mw-editsection a:hover,
.mw-editsection a:focus-visible {
color: var( --edfm-cyan );
}
.mw-editsection-bracket {
display: none;
}
.mw-editsection-divider {
color: var( --edfm-text-dim );
margin: 0 0.3em;
}
/* ==========================================================================
  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. GLOBAL LAYOUT -- centred workspace
  ========================================================================== */
/* THE fix for "enormous unused region on the right side of wide displays".
  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 with no max-width at all -- the first redesign
  pass added a max-width but left the column pinned to the sidebar's left
  edge, which is *why* it still read as "a column stuck on the left with
  dead space on the right" rather than a composed layout.
  Fix: instead of a fixed `margin-left: 11em`, compute how much space is
  left over in the workspace (viewport minus the sidebar) once the
  content has its max-width, and split that leftover evenly between the
  left and right margins (via the --edfm-gutter token above) -- so the
  article is centred *within the workspace to the right of the sidebar*,
  not centred in the full viewport (which would ignore the sidebar and
  look off-centre) and not pinned to its left edge either. On a screen
  too narrow for sidebar + max-width content, --edfm-gutter naturally
  evaluates to 0 and this degrades to the old "fill the workspace"
  behaviour -- no separate narrow-screen override needed.
  The header/tab bar's own float/absolute-position box (#mw-head) is left
  at its native full width deliberately -- rewriting *that* mechanism is
  a different, much higher-risk change (it took several rounds to get
  right originally) -- but its *contents* (search box, personal tools,
  namespace/view tabs) get their own right/left offsets pulled in by the
  same --edfm-gutter below, so they still visually line up with the
  centred column beneath them instead of hugging the browser edge. */
.mw-body,
#mw-data-after-content,
.mw-footer {
position: relative;
z-index: 2;
margin-left: var( --edfm-sidebar-clear );
margin-right: var( --edfm-gutter );
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 {
/* Keep real table layout so header cells and body cells share one column grid.
  The earlier display:block + tbody display:table overflow hack made sortable
  headers size independently from body columns, which visibly misaligned the
  Engineer directory after portrait chips were added. */
display: table;
width: 100%;
table-layout: auto;
}
.mw-body table.wikitable th,
.mw-body table.wikitable td,
.mw-body table.mw-datatable th,
.mw-body table.mw-datatable td {
vertical-align: middle;
}
.mw-body img {
max-width: 100%;
height: auto;
}
/* ==========================================================================
  4. ARTICLE MASTHEAD (eyebrow / title / deck)
  ========================================================================== */
/* Eyebrow line is authored as ordinary wikitext (see Template:Article
  header) and, purely as a placement detail, a small script
  (MediaWiki:Common.js) moves it directly above #firstHeading on 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).
  If JS is unavailable the eyebrow still renders, just directly under the
  title instead of above it.
  The eyebrow/title/deck aren't wrapped in one literal bounding box (they
  live at two different DOM depths -- eyebrow is a sibling of #firstHeading,
  deck is inside the article body further down -- wrapping them in one
  real container would need heavier JS than is justified here), so the
  "designed masthead" read comes from a matching top rule above the
  eyebrow and bottom rule below the deck, a small angular marker, and the
  larger title/subtitle type scale, rather than one drawn box. */
.edfm-eyebrow {
display: flex;
align-items: center;
gap: 0.55em;
margin: 0 0 0.5em 0;
padding-top: 1.1em;
border-top: 1px solid var( --edfm-border );
font-family: var( --edfm-mono );
font-size: var( --edfm-fs-meta );
font-weight: 700;
letter-spacing: 0.12em;
text-transform: uppercase;
color: var( --edfm-text-dim );
}
.edfm-eyebrow::before {
content: '';
width: 8px;
height: 8px;
flex-shrink: 0;
background: var( --edfm-orange );
clip-path: polygon( 0 0, 100% 0, 100% 65%, 65% 100%, 0 100% );
}
.edfm-eyebrow .edfm-orange-mark {
color: var( --edfm-orange );
}
.edfm-deck {
color: var( --edfm-text-muted );
font-size: 1.1rem;
line-height: 1.55;
max-width: 42em;
margin: 0.5em 0 1.7em 0;
padding-bottom: 1.6em;
border-bottom: 1px solid var( --edfm-border );
}
/* ==========================================================================
  1. SIDEBAR
  ========================================================================== */
#mw-panel {
background: transparent;
box-sizing: border-box;
width: var( --edfm-sidebar-width );
padding: 0 0.65rem 1.35rem 0.65rem;
border-right: 0;
box-shadow: none;
z-index: 3;
}
/* Logo anchors the sidebar visually. Do not draw a divider on or near
  #p-logo: Vector legacy fixes the logo box at 155px high and the EDFM hex
  mark reaches that edge, so any horizontal rule in this box cuts through
  the lower point of the logo. Navigation spacing below provides the break. */
#p-logo {
box-sizing: border-box;
width: auto;
margin: 0 -0.65rem 1.25rem -0.65rem;
padding: 0.95rem 0.55rem 1.05rem 0.55rem;
border-bottom: 0 !important;
background: radial-gradient( circle at 50% 25%, rgba( 255, 138, 0, 0.08 ), transparent 58% );
}
/* Each nav group gets real breathing room from the one before it instead
  of being packed together like a stock wiki sidebar. */
/* Sidebar Discord invite CTA: injected by MediaWiki:Common.js directly below
  the logo and above the first generated Vector portlet, matching the compact
  community-button placement shown in the reference screenshot. */
.edfm-discord-cta {
display: inline-flex;
align-items: center;
justify-content: center;
gap: 0.42rem;
box-sizing: border-box;
width: calc( 100% - 1.35rem );
min-height: 1.78rem;
margin: 0.35rem 0.675rem 1.05rem 0.675rem;
padding: 0.36rem 0.56rem;
border-radius: 4px;
background: #5865f2;
color: #fff !important;
font-size: 0.76rem;
font-weight: 700;
line-height: 1.1;
text-align: center;
text-decoration: none !important;
box-shadow: 0 2px 5px rgba( 0, 0, 0, 0.35 );
transition: background-color 120ms ease, box-shadow 120ms ease, transform 120ms ease;
}
.edfm-discord-cta:hover,
.edfm-discord-cta:focus {
background: #4752c4;
color: #fff !important;
text-decoration: none !important;
box-shadow: 0 3px 8px rgba( 0, 0, 0, 0.42 );
transform: translateY( -1px );
}
.edfm-discord-cta-icon {
display: inline-flex;
width: 1rem;
height: 1rem;
flex: 0 0 auto;
}
.edfm-discord-cta-icon svg {
display: block;
width: 100%;
height: 100%;
fill: currentColor;
}
#mw-panel .portal,
#mw-panel .vector-menu-portal {
box-sizing: border-box;
width: auto;
max-width: none;
margin-top: 1.45rem;
}
#mw-panel .portal:first-of-type,
#mw-panel .vector-menu-portal:first-of-type {
margin-top: 0;
}
#mw-panel .portal .body,
#mw-panel .portal ul,
#mw-panel .vector-menu-content,
#mw-panel .vector-menu-content-list {
box-sizing: border-box;
width: auto;
max-width: none;
margin-left: 0;
margin-right: 0;
padding-left: 0;
border-color: var( --edfm-border-soft );
}
#mw-panel .portal a {
color: var( --edfm-text-muted );
display: block;
font-size: var( --edfm-fs-sidebar );
line-height: 1.35;
padding: 0.42em 0.55em;
margin: 0.08em -0.35em;
border-left: 2px solid transparent;
border-radius: 2px;
}
#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). */
.edfm-nav-current > a {
color: var( --edfm-orange ) !important;
font-weight: 700;
border-left-color: var( --edfm-orange );
border-left-width: 3px;
background: var( --edfm-surface-2 );
box-shadow: inset 0 0 0 1px rgba( 255, 138, 0, 0.08 );
}
.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: var( --edfm-fs-utility );
border-left: 2px solid var( --edfm-orange );
padding-left: 0.5em;
margin-left: -0.5em;
margin-bottom: 0.4em;
}
/* ==========================================================================
  3. TOP BAR -- two-tier chrome
  ========================================================================== */
/* Vector legacy's #mw-head naturally has ~2.5em of empty space above the
  tabs row (core: `#left-navigation/#right-navigation { margin-top:2.5em }`),
  originally reserved just for #p-personal to float in. Painting that same
  box with a background gradient that stays transparent for that top
  band and then switches to a surface colour for the tabs band creates a
  real two-tier read -- "primary chrome" (personal tools/search, over the
  page's own background) above "wiki authoring controls" (the tabs, on
  their own distinct strip) below -- without touching #mw-head's own
  position/width mechanics, which is the same fragile absolute-position
  system the very first pass of this project had to debug carefully to
  get the persistent sidebar working at all. Not worth re-risking that
  for a background change. */
#mw-head {
background-image: linear-gradient(
to bottom,
transparent 0,
transparent 2.35em,
var( --edfm-surface-2 ) 2.35em,
var( --edfm-surface-2 ) 100%
);
border-bottom: 1px solid var( --edfm-border );
}
#mw-page-base {
background-color: var( --edfm-bg-deep );
background-image: none;
}
#mw-head-base {
background-color: var( --edfm-bg-deep );
/* Polish pass: thinned from 2px -- at 2px this competed visually with
  the masthead's own orange marker/rule directly below it; a single
  thinner accent line still reads as "site identity colour" without
  the repetition. */
border-bottom: 1px solid var( --edfm-orange );
}
/* Personal tools (login/logout) and the search box are the "primary
  chrome" tier -- pulled in by the same gutter used to centre the article,
  so on wide screens they visually line up with the centred column
  instead of hugging the browser edge, and given noticeably more visual
  weight than the tabs below them. */
#p-personal {
right: calc( 0.75em + var( --edfm-gutter ) );
display: flex;
align-items: center;
gap: 0.75rem;
}
#p-personal ul {
display: flex;
align-items: center;
gap: 0.55rem;
}
#p-personal li {
margin-left: 0;
}
#p-personal a {
color: var( --edfm-text-muted );
font-family: var( --edfm-mono );
font-size: var( --edfm-fs-sidebar );
padding: 0.3em 0.2em;
}
#p-personal a:hover {
color: var( --edfm-orange );
}
.edfm-topbar-clocks {
display: inline-flex;
align-items: center;
gap: 0.5rem;
font-family: var( --edfm-mono );
font-size: var( --edfm-fs-sidebar );
line-height: 1;
white-space: nowrap;
}
.edfm-topbar-clock {
display: inline-flex;
align-items: center;
gap: 0.3em;
padding: 0.3em 0.55em;
background: rgba( 66, 199, 217, 0.08 );
border: 1px solid var( --edfm-border-soft );
border-left: 2px solid var( --edfm-cyan );
color: var( --edfm-text );
}
.edfm-topbar-clock-label {
color: var( --edfm-text-dim );
font-size: var( --edfm-fs-utility );
letter-spacing: 0.08em;
text-transform: uppercase;
}
.edfm-topbar-clock time {
color: var( --edfm-cyan );
font-weight: 700;
}
.edfm-topbar-clock-local {
background: rgba( 255, 138, 0, 0.06 );
border-left-color: var( --edfm-orange );
}
.edfm-topbar-clock-local time {
color: var( --edfm-orange-bright );
}
#right-navigation {
margin-right: var( --edfm-gutter );
}
#left-navigation {
margin-left: var( --edfm-sidebar-clear );
}
/* Polish pass: core caps this at `width:20vw; max-width:20em`, which read
  as cramped next to the rest of the (now larger-scale) interface --
  given more room on desktop, still capped so it can't dominate the bar. */
.vector-search-box-inner {
width: 22vw;
max-width: 24em;
}
.vector-search-box-inner input,
#searchInput {
background-color: var( --edfm-surface-3 );
color: var( --edfm-text );
border: 1px solid var( --edfm-border );
font-family: var( --edfm-mono );
font-size: var( --edfm-fs-sidebar );
padding: 0.5em 0.7em;
transition: border-color 0.15s ease, box-shadow 0.15s ease;
}
#searchInput:focus {
border-color: var( --edfm-cyan );
box-shadow: 0 0 0 2px rgba( 66, 199, 217, 0.22 );
outline: none;
}
#searchInput::placeholder {
color: var( --edfm-text-dim );
}
/* 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.
  These are the "wiki authoring controls" utility tier -- deliberately
  smaller (--edfm-fs-utility) and quieter than personal-tools/search
  above them, sitting on their own background strip (see #mw-head above).
  Selected state stays orange (it's still real navigation, just
  secondary); unselected rests dim so the *selected* tab is the one that
  reads clearly. */
.vector-menu-tabs-legacy li {
background-image: none;
background-color: transparent;
}
.vector-menu-tabs-legacy li.selected {
background-image: none;
background-color: var( --edfm-surface-1 );
/* Polish pass: a small underline makes the selected tab unambiguous at
  a glance instead of relying on the text colour change alone. */
box-shadow: inset 0 -2px 0 var( --edfm-orange );
}
.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 );
font-size: var( --edfm-fs-utility );
letter-spacing: 0.03em;
text-transform: uppercase;
font-weight: 700;
}
.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. */
.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;
margin-bottom: 0;
text-transform: uppercase;
letter-spacing: 0.03em;
font-size: var( --edfm-fs-utility );
font-weight: 700;
}
.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-3 );
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 );
font-size: var( --edfm-fs-sidebar );
}
.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-4 );
}
/* ==========================================================================
  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 );
}
.mw-body {
border-right: 1px solid var( --edfm-border );
}
#content {
background-color: var( --edfm-surface-1 );
}
/* Site notice chrome. The global disclaimer was moved to its dedicated
  legal/disclaimer page, so an empty #siteNotice must not leave behind a
  phantom divider at the top of the article surface. */
#siteNotice:empty {
display: none;
}
#siteNotice:not( :empty ) {
font-size: var( --edfm-fs-meta );
line-height: 1.5;
color: var( --edfm-text-dim );
font-style: normal;
padding-bottom: 0.7em;
margin-bottom: 1.4rem;
border-bottom: 1px solid var( --edfm-border-soft );
}
#siteNotice:not( :empty ) em, #siteNotice:not( :empty ) i {
color: var( --edfm-text-muted );
font-style: italic;
}
#siteNotice:not( :empty ) a {
color: var( --edfm-link-external );
}
#siteNotice a:hover {
color: var( --edfm-link-external-hover );
}
/* ==========================================================================
  HOME PAGE DASHBOARD
  ========================================================================== */
.edfm-home-hero {
margin: 0.9rem 0 1.6rem;
padding: 1.35rem 1.55rem;
background:
linear-gradient( 135deg, rgba( 255, 138, 0, 0.16 ), transparent 34% ),
linear-gradient( 315deg, rgba( 66, 199, 217, 0.14 ), transparent 42% ),
var( --edfm-surface-2 );
border: 1px solid var( --edfm-border );
border-left: 4px solid var( --edfm-cyan );
clip-path: polygon( 0 0, calc( 100% - 12px ) 0, 100% 12px, 100% 100%, 0 100% );
}
.edfm-home-hero-kicker,
.edfm-home-card-kicker {
color: var( --edfm-text-dim );
font-family: var( --edfm-mono );
font-size: var( --edfm-fs-meta );
font-weight: 800;
letter-spacing: 0.1em;
text-transform: uppercase;
}
.edfm-home-hero-title {
margin-top: 0.25rem;
color: var( --edfm-text );
font-family: var( --edfm-mono );
font-size: clamp( 1.55rem, 1.1rem + 1.5vw, 2.2rem );
font-weight: 800;
line-height: 1.15;
}
.edfm-home-hero-text {
max-width: 52rem;
margin-top: 0.55rem;
color: var( --edfm-text-muted );
font-size: 1.05rem;
line-height: 1.55;
}
.edfm-home-grid {
display: grid;
gap: 1rem;
margin: 1.2rem 0 2rem;
}
.edfm-home-grid-four {
grid-template-columns: repeat( 4, minmax( 0, 1fr ) );
}
.edfm-home-grid-topics {
grid-template-columns: repeat( 2, minmax( 0, 1fr ) );
}
.edfm-home-grid-two {
grid-template-columns: repeat( 2, minmax( 0, 1fr ) );
}
.edfm-home-card {
background: var( --edfm-surface-2 );
border: 1px solid var( --edfm-border );
border-left: 3px solid var( --edfm-cyan );
padding: 1rem 1.1rem;
box-shadow: 0 12px 24px rgba( 0, 0, 0, 0.2 );
transition: transform 0.15s ease, border-color 0.15s ease, background-color 0.15s ease;
}
.edfm-home-card:hover {
transform: translateY( -2px );
background: var( --edfm-surface-3 );
border-left-color: var( --edfm-orange );
}
.edfm-home-card-primary {
border-left-color: var( --edfm-orange );
}
.edfm-home-card-warning {
border-left-color: var( --edfm-text-dim );
}
.edfm-home-card-title,
.edfm-home-card-title a {
margin-top: 0.35rem;
color: var( --edfm-text ) !important;
font-family: var( --edfm-mono );
font-size: 1.05rem;
font-weight: 800;
line-height: 1.3;
text-decoration: none;
}
.edfm-home-card-title a:hover {
color: var( --edfm-orange-bright ) !important;
}
.edfm-home-card-text,
.edfm-home-link-list {
margin-top: 0.65rem;
color: var( --edfm-text-muted );
line-height: 1.6;
}
.edfm-home-link-list a {
font-weight: 600;
}
@media ( max-width: 1100px ) {
.edfm-home-grid-four {
grid-template-columns: repeat( 2, minmax( 0, 1fr ) );
}
}
@media ( max-width: 760px ) {
.edfm-home-grid-four,
.edfm-home-grid-topics,
.edfm-home-grid-two {
grid-template-columns: 1fr;
}
}
/* ==========================================================================
  HOME PAGE NEWS MODULE
  ========================================================================== */
.edfm-home-news {
margin: 1.8rem 0 2.2rem;
}
.edfm-news-feature-grid {
display: grid;
grid-template-columns: repeat( 3, minmax( 0, 1fr ) );
gap: 1rem;
margin-bottom: 1rem;
}
.edfm-news-card,
.edfm-news-list {
background: var( --edfm-surface-2 );
border: 1px solid var( --edfm-border );
box-shadow: 0 14px 26px rgba( 0, 0, 0, 0.22 );
overflow: hidden;
}
.edfm-news-card {
display: flex;
flex-direction: column;
min-height: 100%;
transition: transform 0.15s ease, border-color 0.15s ease, background-color 0.15s ease;
}
.edfm-news-card:hover {
transform: translateY( -2px );
border-color: rgba( 255, 138, 0, 0.48 );
background: var( --edfm-surface-3 );
}
.edfm-news-card-art {
display: flex;
align-items: flex-end;
min-height: 7rem;
padding: 0.8rem 1rem;
box-sizing: border-box;
background:
linear-gradient( 135deg, rgba( 255, 138, 0, 0.28 ), transparent 42% ),
linear-gradient( 315deg, rgba( 66, 199, 217, 0.2 ), transparent 48% ),
linear-gradient( 180deg, var( --edfm-surface-4 ), var( --edfm-surface-1 ) );
border-bottom: 1px solid var( --edfm-border );
color: rgba( 237, 240, 242, 0.72 );
font-family: var( --edfm-mono );
font-size: 0.8rem;
font-weight: 800;
letter-spacing: 0.16em;
text-transform: uppercase;
}
.edfm-news-card-primary .edfm-news-card-art {
background:
linear-gradient( 135deg, rgba( 255, 138, 0, 0.38 ), transparent 46% ),
linear-gradient( 315deg, rgba( 79, 159, 232, 0.26 ), transparent 52% ),
var( --edfm-surface-4 );
}
.edfm-news-card-body {
padding: 1rem 1.15rem 1.15rem;
}
.edfm-news-meta {
color: var( --edfm-text-dim );
font-family: var( --edfm-mono );
font-size: var( --edfm-fs-meta );
letter-spacing: 0.04em;
text-transform: uppercase;
margin-bottom: 0.35rem;
}
.edfm-news-title,
.edfm-news-title a {
color: var( --edfm-text ) !important;
font-family: var( --edfm-mono );
font-size: 1.1rem;
font-weight: 800;
line-height: 1.25;
text-decoration: none;
}
.edfm-news-title a:hover {
color: var( --edfm-orange-bright ) !important;
}
.edfm-news-summary {
color: var( --edfm-text-muted );
line-height: 1.55;
margin-top: 0.65rem;
}
.edfm-news-list {
padding: 1.1rem 1.25rem 1.2rem;
border-left: 4px solid var( --edfm-orange );
}
.edfm-news-list-heading {
color: var( --edfm-text );
font-family: var( --edfm-mono );
font-size: 1.05rem;
font-weight: 800;
letter-spacing: 0.04em;
text-transform: uppercase;
margin-bottom: 0.75rem;
}
.edfm-news-list ul {
margin: 0;
}
.edfm-news-list li {
margin-bottom: 0.55rem;
color: var( --edfm-text-muted );
}
.edfm-news-more {
margin-top: 0.9rem;
padding-top: 0.85rem;
border-top: 1px solid var( --edfm-border-soft );
text-align: right;
font-family: var( --edfm-mono );
font-weight: 800;
letter-spacing: 0.03em;
text-transform: uppercase;
}
@media ( max-width: 900px ) {
.edfm-news-feature-grid {
grid-template-columns: 1fr;
}
}
/* ==========================================================================
  10. JUMP NAVIGATION (table of contents)
  ========================================================================== */
/* A compact navigation strip/tile-grid rather than a traditional TOC box
  of small text links -- real MediaWiki anchors/markup untouched, this is
  all presentation. "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 {
display: block;
width: 100%;
box-sizing: border-box;
background: none;
border: none;
color: var( --edfm-text );
padding: 0;
margin: 1.8rem 0;
}
.toctitle {
position: relative;
margin-bottom: 0.7em;
}
.toctitle::before {
content: 'Jump to';
font-family: var( --edfm-mono );
font-size: var( --edfm-fs-meta );
font-weight: 700;
letter-spacing: 0.12em;
text-transform: uppercase;
color: var( --edfm-orange );
}
/* Core ships `.toc h2 { font-size: 100%; ... }` (mediawiki.skinning/toc/
  screen.less) at the exact same specificity (one class + one tag) as a
  plain `.toctitle h2` rule -- same "tie that doesn't resolve the way
  naive source order would suggest" gotcha documented elsewhere in this
  file. #toc's own ID makes this one unambiguous instead of relying on
  cascade order. */
#toc .toctitle h2,
.toc .toctitle h2 {
font-size: 0 !important;
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 );
}
/* Desktop: a real grid of clickable tiles (3 columns suits this site's
  typical 5-8 top-level sections well: commonly 2-3 rows) instead of one
  long line of small text. Each tile has its own surface, a visible
  boundary via the accent rail (not a full border -- see "stop using a
  border around everything"), and an obvious hover state. */
.toc > ul {
display: grid;
grid-template-columns: repeat( 4, 1fr );
gap: 0.45rem;
list-style: none;
margin: 0;
padding: 0;
}
.toc li {
margin: 0;
}
/* 2026-08-08 density pass: reverted to side-by-side number/label (from the
  earlier "stacked number-above-label" polish pass) specifically to cut
  per-tile height -- with 12 sections on articles like The Dweller, the
  stacked layout meant the jump nav alone filled most of the first
  viewport. Row layout plus tighter padding/font-size gets noticeably
  more sections above the fold without dropping the numbering or shrinking
  tap targets below a comfortable size -- see the dedicated mobile padding
  bump further down for keeping touch targets safe on small screens
  specifically. Whole tile stays one real <a>, so it's still a single
  click/focus target and keyboard tab stop either way. */
.toc a {
display: flex;
flex-direction: row;
align-items: center;
gap: 0.5em;
height: 100%;
box-sizing: border-box;
padding: 0.5em 0.75em 0.5em 0.7em;
background: var( --edfm-surface-3 );
/* Left accent rail: matches the orange section numbers and gives each
  jump tile a stronger EDFM navigation affordance without boxing the
  entire card. */
border-left: 4px solid var( --edfm-orange );
box-shadow: inset 1px 0 0 rgba( 255, 162, 26, 0.35 );
color: var( --edfm-text-muted );
text-decoration: none;
transition: background-color 0.15s ease, border-color 0.15s ease, box-shadow 0.15s ease, color 0.15s ease, transform 0.15s ease;
}
.toc a:hover {
background: var( --edfm-surface-4 );
border-left-color: var( --edfm-cyan );
box-shadow: inset 1px 0 0 rgba( 66, 199, 217, 0.45 );
color: var( --edfm-text );
transform: translateY( -1px );
}
/* Nested sub-levels (rare on this site so far) drop back to a plain
  indented block list inside their parent tile's grid cell rather than
  trying to stay gridded themselves. */
.toc ul ul {
grid-column: unset;
list-style: none;
margin: 0.3em 0 0 1.2em;
padding: 0;
display: block;
}
.toc ul ul a {
flex-direction: row;
align-items: center;
background: none;
border-left-width: 1px;
padding: 0.3em 0.6em;
}
.toc ul ul .tocnumber {
font-size: 0.85em;
}
.toc ul ul .toctext {
font-size: 0.85em;
}
.tocnumber {
color: var( --edfm-orange );
font-family: var( --edfm-mono );
font-weight: 700;
font-size: 1.05rem;
line-height: 1;
}
.toctext {
color: inherit;
font-size: 0.85rem;
line-height: 1.3;
}
/* 2026-08-08: rebalanced for the 4-column desktop default above -- was
  >1150px = 3 cols -> <=1150px = 2 cols -> <=560px = 1 col. A page with
  12 sections (e.g. The Dweller) now gets 3 rows at desktop width instead
  of 4, so a new <=860px step was added rather than dropping straight
  from 3 to 2 columns at 1150px, which left the same "Star systems,
  navigation and exploration"-style long labels cramped in the 1024px
  range this breakpoint set was originally tuned for. Order stays widest
  condition first, narrowest last, so cascade order matches the max-width
  overlap correctly at every width. */
@media ( max-width: 1150px ) {
.toc > ul {
grid-template-columns: repeat( 3, 1fr );
}
}
@media ( max-width: 860px ) {
.toc > ul {
grid-template-columns: repeat( 2, 1fr );
}
}
@media ( max-width: 560px ) {
.toc > ul {
grid-template-columns: 1fr;
}
/* Single-column tiles are already full-width here, so there's no
  density pressure left -- restore closer to the pre-2026-08-08
  padding instead of the tighter desktop value, keeping tap targets
  comfortable rather than compacting mobile just because desktop
  compacted. */
.toc a {
padding: 0.7em 0.95em;
}
}
/* ==========================================================================
  6. PANELS / CALLOUTS, and 11. ARTICLE METADATA / STATUS MODULE
  ========================================================================== */
/* Deliberately NOT defined here. .edfm-box / .edfm-panel* / .edfm-status* /
  .edfm-inline-flag / .edfm-related* are used exclusively by the
  editorial templates (see Template:Article status, Template:Draft
  warning, Template:Related articles, 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 );
font-size: var( --edfm-fs-body );
}
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: var( --edfm-fs-meta );
text-align: left;
padding: 0.6em 0.8em;
}
table.wikitable > tr > td,
table.wikitable > * > tr > td {
border-color: var( --edfm-border-soft );
padding: 0.6em 0.8em;
}
/* 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 );
}
/* ==========================================================================
  15. FOOTER
  ========================================================================== */
/* A real branded footer: a small wordmark line (pure CSS generated
  content -- decorative branding only, redundant with the sidebar logo
  already visible, so nothing load-bearing depends on it being
  selectable), a top rule with more separation from the article above it,
  and MediaWiki's real info/places/icon links laid out on a clean grid
  with the badges aligned as a group rather than floating alone. */
.mw-footer {
margin-left: var( --edfm-sidebar-clear );
margin-right: var( --edfm-gutter );
margin-top: 2.5rem;
padding-top: 1.6rem;
border-top: 1px solid var( --edfm-border );
display: grid;
grid-template-columns: 1fr auto;
grid-template-areas: "brand brand" "info icons" "places icons";
align-items: center;
column-gap: 2em;
row-gap: 0.4rem;
}
.mw-footer::before {
grid-area: brand;
content: 'EDFM // Elite Dangerous Field Manual';
font-family: var( --edfm-mono );
font-size: 0.85rem;
font-weight: 700;
letter-spacing: 0.06em;
text-transform: uppercase;
color: var( --edfm-text-muted );
margin-bottom: 0.5rem;
}
.mw-footer,
.mw-footer li,
#footer-info,
#footer-info li {
color: var( --edfm-text-dim );
border-color: var( --edfm-border-soft );
font-size: var( --edfm-fs-meta );
}
#footer-info {
grid-area: info;
margin: 0;
line-height: 1.6;
}
#footer-places {
grid-area: places;
margin: 0;
}
/* Same "small uppercase label" treatment used for tags/meta text
  elsewhere, so these read as deliberate EDFM navigation rather than
  default MediaWiki footer links. */
#footer-places li {
display: inline-block;
margin-right: 1.4em;
}
#footer-places a {
font-family: var( --edfm-mono );
font-weight: 700;
letter-spacing: 0.03em;
text-transform: uppercase;
font-size: 0.78rem;
}
/* A left rule ties the badges to the rest of the footer instead of
  letting them read as detached/floating in their own space. */
#footer-icons {
grid-area: icons;
align-self: center;
display: flex;
gap: 0.75em;
margin: 0;
padding-left: 1.6em;
border-left: 1px solid var( --edfm-border-soft );
}
#footer-icons img {
background: var( --edfm-text );
border-radius: 2px;
}
@media ( max-width: 640px ) {
.mw-footer {
grid-template-columns: 1fr;
grid-template-areas: "brand" "info" "places" "icons";
}
#footer-icons {
margin-top: 0.7em;
padding-left: 0;
border-left: none;
border-top: 1px solid var( --edfm-border-soft );
padding-top: 0.7em;
}
}
/* ==========================================================================
  MISC MediaWiki UI chrome that ships with light backgrounds by default
  ========================================================================== */
.catlinks {
background: none !important;
border: none !important;
border-top: 1px solid var( --edfm-border-soft ) !important;
color: var( --edfm-text-dim );
font-size: var( --edfm-fs-meta );
padding: 0.9em 0 0 0 !important;
margin-top: 1.8rem !important;
}
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: 310px;
margin: 0 0 1.2em 1.2em;
border: 1px solid var( --edfm-border );
border-top: 2px solid var( --edfm-orange );
background: var( --edfm-surface-2 );
color: var( --edfm-text );
font-size: 0.92rem;
}
.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.5em 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-image-placeholder {
display: flex;
align-items: center;
justify-content: center;
height: 160px;
border: 1px dashed var( --edfm-border );
background: var( --edfm-surface-1 );
color: var( --edfm-text-dim );
font-family: var( --edfm-mono );
font-size: var( --edfm-fs-utility );
text-transform: uppercase;
letter-spacing: 0.06em;
text-align: center;
padding: 0.5em;
}
/* Optional section label (Template:Infobox's |groupN=) splitting a long
  infobox into scannable groups, e.g. Engineer infoboxes into "ENGINEER"
  and "ACCESS" (2026-08-08, part of the Engineer article layout pass). A
  shaded band with a bottom rule rather than a full boxed sub-header --
  consistent with .edfm-infobox-row's own bottom-rule-only separator, not
  a new visual language. */
.edfm-infobox-group {
background: var( --edfm-surface-3 );
color: var( --edfm-text-dim );
font-family: var( --edfm-mono );
font-weight: 700;
font-size: var( --edfm-fs-utility );
letter-spacing: 0.08em;
text-transform: uppercase;
padding: 0.35em 0.7em;
border-bottom: 1px solid var( --edfm-border );
}
.edfm-infobox-row {
display: flex;
border-bottom: 1px solid var( --edfm-border-soft );
padding: 0.45em 0.7em;
}
.edfm-infobox-row:last-child {
border-bottom: none;
}
.edfm-infobox-label {
font-weight: 700;
font-family: var( --edfm-mono );
font-size: var( --edfm-fs-meta );
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::before {
display: none;
}
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;
background-image: none;
background-color: var( --edfm-surface-2 );
}
#left-navigation,
#right-navigation {
float: none;
margin: 0 !important;
width: auto;
clear: both;
}
#left-navigation {
margin-top: 0 !important;
}
/* Core Vector legacy floats each tab/dropdown portlet
  (.vector-menu-tabs-legacy for Page/Discussion and Read/View
  source/View history, .vector-menu-dropdown for the More menu) AND
  floats every <li> inside their <ul>, with no wrapping at all -- at
  narrow widths the labels just overflow and overlap each other
  (confirmed with a real screenshot: "View source" and "More"
  overlapped instead of wrapping to a new line). Switching the
  portlets to inline-block and their tab lists to flex-wrap lets them
  reflow onto as many rows as needed instead. */
#left-navigation .vector-menu-tabs-legacy,
#right-navigation .vector-menu-tabs-legacy,
#right-navigation .vector-menu-dropdown {
float: none;
display: inline-block;
vertical-align: top;
}
.vector-menu-tabs-legacy ul {
float: none;
display: flex;
flex-wrap: wrap;
}
.vector-menu-tabs-legacy li {
float: none;
}
#p-personal {
position: static;
text-align: right;
padding: 0.5em 1em;
margin: 0;
right: auto !important;
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;
background: var( --edfm-bg-deep );
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 !important;
margin-right: 0 !important;
max-width: none;
}
.mw-body {
margin-top: 0;
border-width: 0;
padding: 1em;
}
.edfm-status-details {
grid-template-columns: 1fr;
}
/* .toc > ul column count is NOT overridden here -- the dedicated
  1150px/560px breakpoints above already cover every width down to
  the smallest phones; duplicating a rule here previously fought
  those (same specificity, this position in the cascade would have
  won and wrongly forced 1 column as low as 561px). */
#firstHeading {
font-size: 1.6rem;
}
.mw-body h2 {
margin-top: 2.25rem;
}
.edfm-eyebrow {
padding-top: 0.9em;
}
}
/* ==========================================================================
  16. OOUI DIALOGS -- VisualEditor's save dialog, and any other OOUI
  dialog (delete/move/protect confirmations, special-page dialogs).
  These render via OOUI's own bundled WikimediaUI theme stylesheet,
  entirely outside the .edfm-* component system this file otherwise
  covers, so without this they show up starkly white against the rest of
  the dark-themed site regardless of any variable/token used elsewhere in
  this file. !important is justified the same way as the h1-h6 fix above:
  OOUI's own stylesheet loads with equal-or-higher effective specificity,
  and this is a correctness/contrast fix, not decoration.
  ========================================================================== */
.oo-ui-window-frame {
background: var( --edfm-surface-2 ) !important;
color: var( --edfm-text ) !important;
}
.oo-ui-processDialog {
background: rgba( 7, 9, 11, 0.75 ) !important;
}
.oo-ui-processDialog-navigation,
.oo-ui-window-head,
.oo-ui-window-foot {
background: var( --edfm-surface-3 ) !important;
border-color: var( --edfm-border ) !important;
}
.oo-ui-processDialog-title,
.oo-ui-labelElement-label,
.oo-ui-fieldLayout-header,
.oo-ui-fieldLayout .oo-ui-labelElement-label {
color: var( --edfm-text ) !important;
}
.oo-ui-inputWidget-input {
background: var( --edfm-surface-1 ) !important;
color: var( --edfm-text ) !important;
border-color: var( --edfm-border ) !important;
}
.ve-ui-mwSaveDialog-options,
.oo-ui-panelLayout,
.oo-ui-window-body {
background: var( --edfm-surface-2 ) !important;
color: var( --edfm-text ) !important;
}
.oo-ui-popupWidget-popup {
background: var( --edfm-surface-2 ) !important;
color: var( --edfm-text ) !important;
border-color: var( --edfm-border ) !important;
}
.oo-ui-buttonElement:not( .oo-ui-flaggedElement-primary ) > .oo-ui-buttonElement-button {
background: var( --edfm-surface-4 ) !important;
color: var( --edfm-text ) !important;
border-color: var( --edfm-border ) !important;
}
/* ==========================================================================
  17. OOUI TOOLBAR -- VisualEditor's persistent editing toolbar and its
  dropdown menus (Cite, Insert, paragraph style, etc.), and the equivalent
  toolbar/popups used when editing a single section. Same root cause as
  16. OOUI DIALOGS above (OOUI's own bundled theme, not touched by
  anything else in this file), found separately because it's a different
  set of OOUI classes (toolbar chrome, not dialog chrome). Icons are not
  overridden here and don't need to be -- they're currentColor-based, so
  they pick up the text colour set below automatically.
  ========================================================================== */
.oo-ui-toolbar-bar,
.oo-ui-toolGroup-tools,
.oo-ui-popupToolGroup-tools {
background: var( --edfm-surface-3 ) !important;
border-color: var( --edfm-border ) !important;
}
.oo-ui-tool-title,
.oo-ui-tool-link,
.oo-ui-toolGroup-tools .oo-ui-optionWidget,
.oo-ui-menuOptionWidget,
.oo-ui-labelElement-label {
color: var( --edfm-text ) !important;
}
.oo-ui-optionWidget.oo-ui-optionWidget-selected,
.oo-ui-optionWidget:hover,
.oo-ui-tool:hover .oo-ui-tool-link {
background: var( --edfm-surface-4 ) !important;
}
/* ==========================================================================
  18. OOUI GENERIC MENUS -- .oo-ui-menuSelectWidget is OOUI's general
  dropdown/autocomplete menu class (paragraph-style picker, citation-type
  picker, link/media search suggestions, etc.) -- a different class from
  the toolbar-specific popups in 17. above, confirmed separately via
  computed-style inspection to default to the same white OOUI theme
  background.
  ========================================================================== */
.oo-ui-menuSelectWidget {
background: var( --edfm-surface-3 ) !important;
border-color: var( --edfm-border ) !important;
}
.oo-ui-menuOptionWidget {
color: var( --edfm-text ) !important;
}
.oo-ui-menuOptionWidget.oo-ui-optionWidget-highlighted,
.oo-ui-menuOptionWidget:hover {
background: var( --edfm-surface-4 ) !important;
}
/* ==========================================================================
  19. OOUI ICONS -- the toolbar/menu icons themselves (Bold, link, list,
  Cite, undo/redo, etc.) are rendered as background-image SVGs with a
  colour baked into the SVG markup, not currentColor-based masks -- so
  16-18 above (which only recolour backgrounds/text) left them dark and
  low-contrast against the now-dark surfaces. OOUI ships its own fix for
  exactly this, gated behind a narrow accessibility media query
  (forced-colors + prefers-color-scheme: dark) that doesn't apply to this
  site's own always-on dark theme -- reusing that exact technique
  unconditionally rather than inventing a different one. `:not(
  .oo-ui-image-invert )` is OOUI's own exclusion for icons already meant
  to render light (e.g. on the orange primary-button background) --
  inverting those too would flip them back to dark.
  ========================================================================== */
.oo-ui-iconElement-icon:not( .oo-ui-image-invert ),
.oo-ui-indicatorElement-indicator:not( .oo-ui-image-invert ) {
filter: invert( 1 ) hue-rotate( 180deg );
}
/* ==========================================================================
  20. EDIT SOURCE FORM -- MediaWiki core + WikiEditor + CodeMirror
  The source editor is not covered by the article/component selectors above:
  `action=edit` loads core edit-form CSS, WikiEditor chrome, and sometimes
  CodeMirror with their own light neutral surfaces. Force the same EDFM dark
  surface stack here so the source page no longer flashes as a white island.
  ========================================================================== */
.mw-editform,
#editform,
#toolbar,
.editOptions,
.mw-editTools,
.mw-summary-preview,
.mw-datatable,
.wikiEditor-ui,
.wikiEditor-ui-view,
.wikiEditor-ui-text,
.wikiEditor-ui-toolbar,
.wikiEditor-ui-top,
.wikiEditor-ui-controls,
.wikiEditor-ui-tabs,
.wikiEditor-ui-buttons,
.CodeMirror,
.CodeMirror-scroll {
background: var( --edfm-surface-1 ) !important;
color: var( --edfm-text ) !important;
border-color: var( --edfm-border ) !important;
}
.mw-editform textarea,
#wpTextbox1,
#wpSummary,
#wpSummaryWidget input,
#editform input[type='text'],
#editform input[type='search'],
#editform textarea,
.wikiEditor-ui-text textarea,
.CodeMirror-code,
.CodeMirror-lines,
.CodeMirror pre {
background: var( --edfm-bg-deep ) !important;
color: var( --edfm-text ) !important;
border-color: var( --edfm-border ) !important;
caret-color: var( --edfm-orange-bright );
}
.wikiEditor-ui-toolbar,
.wikiEditor-ui-toolbar .group,
.wikiEditor-ui-toolbar .tabs,
.wikiEditor-ui-toolbar .page,
.wikiEditor-ui-toolbar .sections,
.wikiEditor-ui-toolbar .section,
.wikiEditor-ui-toolbar .options,
.wikiEditor-ui-toolbar .booklet,
.wikiEditor-ui-toolbar .pages,
.CodeMirror-gutters {
background: var( --edfm-surface-2 ) !important;
color: var( --edfm-text-muted ) !important;
border-color: var( --edfm-border ) !important;
}
.wikiEditor-ui-toolbar a,
.wikiEditor-ui-toolbar .label,
.wikiEditor-ui-toolbar .tab a,
.mw-editTools a,
.editOptions label,
.mw-editform label,
.CodeMirror-linenumber {
color: var( --edfm-text ) !important;
}
.wikiEditor-ui-toolbar .tab a:hover,
.wikiEditor-ui-toolbar .tool-button:hover,
.wikiEditor-ui-toolbar .tool-select:hover,
.wikiEditor-ui-toolbar .page-table th,
.wikiEditor-ui-toolbar .page-table td,
.CodeMirror-activeline-background {
background: var( --edfm-surface-3 ) !important;
color: var( --edfm-text ) !important;
}
.wikiEditor-ui-toolbar .tab.current a,
.wikiEditor-ui-toolbar .section-main,
.CodeMirror-selected {
background: var( --edfm-surface-4 ) !important;
}
.CodeMirror-cursor {
border-left-color: var( --edfm-orange-bright ) !important;
}
.CodeMirror-matchingbracket {
color: var( --edfm-orange-bright ) !important;
}
/* ==========================================================================
  21. FILE PAGE CHROME -- #filetoc (the File / File history / File usage /
  Metadata nav on File: description pages) is defined in MediaWiki core's
  mediawiki.action.view.filepage.less, entirely separate from both the
  .edfm-* system and the OOUI fixes in 16-19 above -- a different
  subsystem again, only loaded on File: pages, which is why it was never
  touched by anything else in this file. Link colour inside it already
  correctly inherits the site's normal link blue; only the light neutral
  background/border needed overriding.
  ========================================================================== */
#filetoc {
background: var( --edfm-surface-2 ) !important;
border-color: var( --edfm-border ) !important;
}
/* ==========================================================================
  22. FILE PAGE: METADATA TABLE + MEDIA VIEWER BUTTON -- #mw_metadata is
  the EXIF-style metadata table (separate from the File history table
  above -- that one already carries the .wikitable class and picked up
  dark styling from 7. TABLES automatically; this one doesn't have that
  class, so it never matched). The "Open in Media Viewer" button is a
  Codex component (MultimediaViewer extension) -- a third distinct
  styling subsystem from OOUI and MediaWiki core skinning, again never
  touched by anything else in this file.
  ========================================================================== */
#mw_metadata th,
#mw_metadata td {
background: var( --edfm-surface-2 ) !important;
color: var( --edfm-text ) !important;
border-color: var( --edfm-border ) !important;
}
.mw-mmv-view-expanded.cdx-button {
background: var( --edfm-surface-4 ) !important;
color: var( --edfm-text ) !important;
border-color: var( --edfm-border ) !important;
}
/* ===========================================================================
  23. RUNE-WIKI-INSPIRED MOBILE APP SHELL
  =========================================================================== */
/* Inspired by RuneScape.wiki's mobile ergonomics -- persistent top app bar,
  large touch targets, off-canvas navigation, search-forward layout, and
  single-column readable article flow -- while preserving EDFM's dark field
  manual identity and not copying RuneScape.wiki assets/CSS.
  The close button is injected into #mw-panel by Common.js, so it must be
  explicitly hidden by default; otherwise a tiny native white button appears
  in the desktop sidebar's top-left corner. */
.edfm-mobile-appbar,
.edfm-mobile-scrim,
.edfm-mobile-close-button {
display: none;
}
@media ( max-width: 800px ) {
html {
-webkit-text-size-adjust: 100%;
}
body {
background: var( --edfm-bg-page );
overflow-x: hidden;
}
body.edfm-mobile-menu-open {
overflow: hidden;
}
.edfm-mobile-appbar {
display: grid;
grid-template-columns: 48px 1fr 48px;
align-items: center;
position: sticky;
top: 0;
z-index: 1200;
min-height: 56px;
padding: 0 0.35rem;
background:
linear-gradient( 90deg, rgba( 255, 138, 0, 0.18 ), transparent 38% ),
var( --edfm-surface-2 );
border-bottom: 1px solid var( --edfm-border );
box-shadow: 0 10px 24px rgba( 0, 0, 0, 0.35 );
}
.edfm-mobile-brand {
min-width: 0;
color: var( --edfm-text ) !important;
font-family: var( --edfm-mono );
font-weight: 800;
letter-spacing: 0.05em;
text-transform: uppercase;
text-decoration: none;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.edfm-mobile-brand::before {
content: 'EDFM // ';
color: var( --edfm-orange );
}
.edfm-mobile-menu-button,
.edfm-mobile-search-button,
.edfm-mobile-close-button {
appearance: none;
-webkit-appearance: none;
display: inline-flex;
align-items: center;
justify-content: center;
min-width: 44px;
min-height: 44px;
margin: 0;
border: 0;
border-radius: 0;
background: transparent;
color: var( --edfm-text );
font: 700 1.5rem/1 var( --edfm-mono );
cursor: pointer;
}
.edfm-mobile-menu-button:focus-visible,
.edfm-mobile-search-button:focus-visible,
.edfm-mobile-close-button:focus-visible {
outline: 2px solid var( --edfm-cyan );
outline-offset: -4px;
}
.edfm-mobile-menu-button::before {
content: '☰';
color: var( --edfm-orange );
}
.edfm-mobile-search-button::before {
content: '⌕';
font-size: 1.85rem;
color: var( --edfm-cyan );
}
.edfm-mobile-close-button::before {
content: '×';
color: var( --edfm-text );
}
.edfm-mobile-scrim {
display: block;
position: fixed;
inset: 0;
z-index: 1000;
background: rgba( 0, 0, 0, 0.58 );
opacity: 0;
pointer-events: none;
transition: opacity 0.18s ease;
}
body.edfm-mobile-menu-open .edfm-mobile-scrim {
opacity: 1;
pointer-events: auto;
}
#mw-navigation {
background: var( --edfm-surface-2 );
box-shadow: none;
}
#mw-head {
position: relative;
z-index: 1100;
border-bottom: 1px solid var( --edfm-border );
}
#mw-head .vector-search-box {
display: none;
margin: 0;
padding: 0.65rem;
background: var( --edfm-surface-2 );
border-top: 1px solid var( --edfm-border-soft );
}
body.edfm-mobile-search-open #mw-head .vector-search-box {
display: block;
}
#mw-head .vector-search-box-inner,
#mw-head #searchform {
width: 100%;
}
#mw-head #searchInput {
min-height: 44px;
box-sizing: border-box;
width: 100%;
font-size: 1rem;
}
#left-navigation,
#right-navigation {
padding: 0 0.45rem 0.35rem;
background: var( --edfm-surface-2 );
overflow-x: auto;
white-space: nowrap;
-webkit-overflow-scrolling: touch;
}
.vector-menu-tabs-legacy ul {
flex-wrap: nowrap;
}
.vector-menu-tabs-legacy li a,
.vector-menu-tabs-legacy li a:visited,
.vector-menu-dropdown .vector-menu-heading {
min-height: 36px;
display: inline-flex;
align-items: center;
}
#p-personal {
display: none;
}
#mw-panel {
position: fixed;
top: 0;
left: 0;
z-index: 1300;
width: min( 82vw, 22rem );
height: 100dvh;
box-sizing: border-box;
padding: 0;
background: var( --edfm-surface-1 );
border: 0;
border-right: 1px solid var( --edfm-border );
box-shadow: 18px 0 36px rgba( 0, 0, 0, 0.45 );
overflow-y: auto;
-webkit-overflow-scrolling: touch;
transform: translateX( -105% );
transition: transform 0.2s ease;
}
body.edfm-mobile-menu-open #mw-panel {
transform: translateX( 0 );
}
#mw-panel::before {
content: 'EDFM Navigation';
display: block;
position: sticky;
top: 0;
z-index: 1;
padding: 1rem 3.4rem 1rem 1rem;
background: var( --edfm-surface-2 );
border-bottom: 1px solid var( --edfm-border );
color: var( --edfm-orange );
font: 800 0.86rem/1.2 var( --edfm-mono );
letter-spacing: 0.08em;
text-transform: uppercase;
}
#mw-panel .edfm-mobile-close-button {
position: absolute;
top: 0.3rem;
right: 0.35rem;
z-index: 2;
}
#mw-panel .portal,
#mw-panel .vector-menu-portal {
margin: 0;
padding: 0.75rem 0;
border-bottom: 1px solid var( --edfm-border-soft );
}
#mw-panel .vector-menu-heading {
margin: 0.25rem 1rem 0.45rem;
}
#mw-panel .vector-menu-content-list li a,
#mw-panel .vector-menu-content-list li a:visited {
display: flex;
align-items: center;
min-height: 46px;
box-sizing: border-box;
padding: 0.55rem 1rem;
border-left: 3px solid transparent;
color: var( --edfm-text-muted );
font-size: 1rem;
text-decoration: none;
}
#mw-panel .vector-menu-content-list li a:hover,
#mw-panel .vector-menu-content-list li a:focus {
background: var( --edfm-surface-3 );
border-left-color: var( --edfm-cyan );
color: var( --edfm-text );
}
#mw-panel .edfm-nav-current > a,
#mw-panel .edfm-nav-current > a:visited {
background: rgba( 255, 138, 0, 0.12 );
border-left-color: var( --edfm-orange );
color: var( --edfm-orange ) !important;
}
.mw-body {
padding: clamp( 1rem, 4vw, 1.35rem );
font-size: 1rem;
line-height: 1.68;
}
#siteNotice {
margin-bottom: 1rem;
padding-bottom: 0.85rem;
}
#firstHeading {
font-size: clamp( 1.65rem, 8vw, 2.25rem );
line-height: 1.1;
letter-spacing: -0.015em;
}
.mw-body h2 {
font-size: 1.18rem;
line-height: 1.25;
}
.mw-body p,
.mw-body li {
max-width: none;
}
.mw-body img,
.mw-body .thumb,
.mw-body .thumbinner,
.mw-body .thumbimage {
max-width: 100% !important;
height: auto !important;
box-sizing: border-box;
}
.mw-body .thumb,
.mw-body .tright,
.mw-body .tleft {
float: none !important;
clear: both;
width: auto !important;
margin: 1rem 0 !important;
}
.mw-parser-output > table.wikitable,
.mw-parser-output > table.mw-datatable {
display: block;
width: 100% !important;
max-width: 100%;
overflow-x: auto;
-webkit-overflow-scrolling: touch;
white-space: nowrap;
}
.mw-parser-output > table.wikitable th,
.mw-parser-output > table.wikitable td,
.mw-parser-output > table.mw-datatable th,
.mw-parser-output > table.mw-datatable td {
white-space: normal;
min-width: 8rem;
}
.edfm-infobox {
font-size: 0.95rem;
}
.edfm-infobox-row {
display: grid;
grid-template-columns: minmax( 7.5rem, 40% ) 1fr;
gap: 0.5rem;
padding: 0.65rem 0.8rem;
}
.edfm-infobox-label,
.edfm-infobox-value {
width: auto;
}
body.page-Main_Page .mw-parser-output > table.wikitable:first-of-type,
body.page-Main_Page .mw-parser-output > table.wikitable:first-of-type tbody,
body.page-Main_Page .mw-parser-output > table.wikitable:first-of-type tr,
body.page-Main_Page .mw-parser-output > table.wikitable:first-of-type th,
body.page-Main_Page .mw-parser-output > table.wikitable:first-of-type td {
display: block;
width: 100% !important;
box-sizing: border-box;
}
body.page-Main_Page .mw-parser-output > table.wikitable:first-of-type {
overflow: visible;
white-space: normal;
background: transparent;
border: 0;
}
body.page-Main_Page .mw-parser-output > table.wikitable:first-of-type th {
margin-top: 0.75rem;
border-left: 3px solid var( --edfm-orange );
}
body.page-Main_Page .mw-parser-output > table.wikitable:first-of-type td {
margin-bottom: 0.75rem;
background: var( --edfm-surface-2 );
border-left: 3px solid var( --edfm-border );
}
.mw-footer {
padding: 1rem;
margin-top: 1.5rem;
}
}
@media ( max-width: 430px ) {
.edfm-mobile-brand::before {
content: 'EDFM';
margin-right: 0.45rem;
}
.edfm-mobile-brand {
font-size: 0.88rem;
}
.edfm-infobox-row {
grid-template-columns: 1fr;
gap: 0.2rem;
}
}
/* 22a. Mobile action tabs refinement: keep Vector's page/discussion/read/
  source/history controls available, but put them on one compact horizontal
  action rail so the first phone viewport feels like a real mobile app shell
  instead of two stacked desktop tab bars. */
@media ( max-width: 800px ) {
body:not( .edfm-mobile-search-open ) #mw-head {
display: flex;
align-items: stretch;
gap: 0;
overflow-x: auto;
overflow-y: hidden;
-webkit-overflow-scrolling: touch;
scrollbar-width: thin;
}
body:not( .edfm-mobile-search-open ) #left-navigation,
body:not( .edfm-mobile-search-open ) #right-navigation {
flex: 0 0 auto;
clear: none !important;
float: none !important;
width: auto;
padding: 0 0.25rem;
margin: 0 !important;
border-right: 1px solid var( --edfm-border-soft );
}
body:not( .edfm-mobile-search-open ) .vector-menu-tabs-legacy,
body:not( .edfm-mobile-search-open ) .vector-menu-dropdown {
float: none !important;
display: inline-block;
}
body:not( .edfm-mobile-search-open ) .vector-menu-tabs-legacy li a,
body:not( .edfm-mobile-search-open ) .vector-menu-tabs-legacy li a:visited,
body:not( .edfm-mobile-search-open ) .vector-menu-dropdown .vector-menu-heading {
min-height: 40px;
padding-left: 0.55rem;
padding-right: 0.55rem;
font-size: 0.68rem;
}
body.edfm-mobile-search-open #mw-head {
display: block;
}
}
/* ===========================================================================
  24. HARD OVERRIDE: JUMP TILE LEFT RAIL
  The earlier border-left rail can be swallowed by ResourceLoader/cascade or
  visually read as part of the tile edge. Draw the rail as a high-specificity
  gradient on the actual top-level TOC anchors so it is unmistakable on the
  live jump grid.
  =========================================================================== */
#toc.toc > ul > li > a,
.mw-parser-output #toc > ul > li > a,
.mw-parser-output .toc > ul > li > a {
background-image: linear-gradient( 90deg, var( --edfm-orange ) 0, var( --edfm-orange ) 6px, transparent 6px ) !important;
border-left: 0 !important;
padding-left: 1rem !important;
}
#toc.toc > ul > li > a:hover,
#toc.toc > ul > li > a:focus-visible,
.mw-parser-output #toc > ul > li > a:hover,
.mw-parser-output #toc > ul > li > a:focus-visible,
.mw-parser-output .toc > ul > li > a:hover,
.mw-parser-output .toc > ul > li > a:focus-visible {
background-image: linear-gradient( 90deg, var( --edfm-cyan ) 0, var( --edfm-cyan ) 6px, transparent 6px ) !important;
}
/* ===========================================================================
  25. SOURCE EDIT CONFLICT / WIKITEXT DIFF THEME
  Source-edit conflict review uses MediaWiki's diff table classes, not the
  normal edit textarea/WikiEditor chrome. Without this, unchanged rows and
  inline change pills fall back to stark white/yellow/blue defaults. Keep the
  old/new meaning, but render it in EDFM's dark surfaces with restrained
  orange/cyan accents.
  =========================================================================== */
.mw-parser-output table.diff,
table.diff,
.diff {
background: var( --edfm-bg-deep ) !important;
color: var( --edfm-text ) !important;
border-collapse: separate !important;
border-spacing: 0 0.12rem !important;
}
.diff-title,
.diff-otitle,
.diff-ntitle,
#mw-diff-otitle1,
#mw-diff-ntitle1 {
background: var( --edfm-bg-deep ) !important;
color: var( --edfm-text ) !important;
font-family: var( --edfm-mono );
}
td.diff-lineno,
.diff-lineno {
background: transparent !important;
color: var( --edfm-text ) !important;
font-family: var( --edfm-mono );
font-weight: 700;
border: 0 !important;
padding: 0.35rem 0.5rem !important;
}
td.diff-marker,
.diff-marker {
background: transparent !important;
color: var( --edfm-text ) !important;
font-family: var( --edfm-mono );
font-weight: 700;
padding: 0.25rem 0.45rem !important;
text-align: center;
}
td.diff-context,
td.diff-addedline,
td.diff-deletedline,
.diff-context,
.diff-addedline,
.diff-deletedline,
.mw-diff-inline-context,
.mw-diff-inline-added,
.mw-diff-inline-deleted,
.mw-diff-inline-changed,
.mw-diff-inline-moved {
background: var( --edfm-surface-1 ) !important;
color: var( --edfm-text ) !important;
border-color: var( --edfm-border ) !important;
font-family: var( --edfm-mono );
box-shadow: none !important;
}
td.diff-context:empty,
td.diff-addedline:empty,
td.diff-deletedline:empty,
.diff-context:empty,
.diff-addedline:empty,
.diff-deletedline:empty {
/* Empty diff cells are alignment placeholders. Keep their card boundary so
  the two-column source-conflict diff does not look broken, but make them
  compact and neutral instead of tall blank blocks. */
background: var( --edfm-surface-1 ) !important;
border-color: var( --edfm-border ) !important;
box-shadow: none !important;
min-height: 0;
padding-top: 0.08rem !important;
padding-bottom: 0.08rem !important;
}
td.diff-deletedline,
.diff-deletedline,
.mw-diff-inline-deleted {
background: rgba( 255, 138, 0, 0.08 ) !important;
border-color: rgba( 255, 138, 0, 0.6 ) !important;
border-left-color: var( --edfm-orange ) !important;
}
td.diff-addedline,
.diff-addedline,
.mw-diff-inline-added {
background: rgba( 66, 199, 217, 0.08 ) !important;
border-color: rgba( 66, 199, 217, 0.6 ) !important;
border-left-color: var( --edfm-cyan ) !important;
}
.diffchange,
.diff-addedline .diffchange,
.diff-deletedline .diffchange,
.mw-diff-inline-added ins,
.mw-diff-inline-changed ins,
.mw-diff-inline-moved ins,
.mw-diff-inline-deleted del,
.mw-diff-inline-changed del,
.mw-diff-inline-moved del {
border-radius: 3px !important;
padding: 0.08rem 0.22rem !important;
font-weight: 700;
text-decoration: none !important;
color: var( --edfm-bg-deep ) !important;
}
.diff-deletedline .diffchange,
.mw-diff-inline-deleted del,
.mw-diff-inline-changed del,
.mw-diff-inline-moved del {
background: var( --edfm-orange-bright ) !important;
}
.diff-addedline .diffchange,
.mw-diff-inline-added ins,
.mw-diff-inline-changed ins,
.mw-diff-inline-moved ins {
background: var( --edfm-cyan ) !important;
}
.mw-explainconflict,
#wpTextbox2,
textarea#wpTextbox2,
textarea.mw-textarea-oldrev {
background: var( --edfm-surface-1 ) !important;
color: var( --edfm-text ) !important;
border-color: var( --edfm-border ) !important;
}
/* Engineer directory portrait chips -- intentionally quiet so table rows still
  read like data rows, not card/list hybrids. */
.edfm-engineer-entry {
display: inline-flex;
align-items: center;
gap: 0.45rem;
min-width: max-content;
}
.edfm-engineer-entry .mw-file-element {
width: 30px;
height: 30px;
object-fit: cover;
border-radius: 3px;
border: 1px solid var( --edfm-border );
background: var( --edfm-surface-0 );
box-shadow: none;
}
.edfm-engineer-entry__name {
line-height: 1.2;
}
/* Frontier official news feed image treatment */
.edfm-frontier-news .edfm-news-card-art-image {
display: block;
position: relative;
padding: 0;
min-height: 9.5rem;
background: var( --edfm-surface-4 );
overflow: hidden;
}
.edfm-frontier-news .edfm-news-card-primary .edfm-news-card-art-image {
min-height: 13.5rem;
}
.edfm-frontier-news .edfm-news-card-art-image > span,
.edfm-frontier-news .edfm-news-card-art-image .mw-default-size,
.edfm-frontier-news .edfm-news-card-art-image .mw-file-description {
display: block !important;
position: absolute;
inset: 0;
width: 100% !important;
height: 100% !important;
max-width: none !important;
margin: 0 !important;
}
.edfm-frontier-news .edfm-news-card-art-image .mw-file-element {
display: block !important;
width: 100% !important;
height: 100% !important;
max-width: none !important;
object-fit: cover;
transition: transform 0.2s ease, filter 0.2s ease;
}
.edfm-frontier-news .edfm-news-card:hover .edfm-news-card-art-image .mw-file-element {
filter: brightness( 1.08 ) contrast( 1.05 );
transform: scale( 1.035 );
}
.edfm-frontier-news .edfm-news-source-badge {
display: inline-flex !important;
align-items: center;
position: absolute !important;
left: 0.8rem !important;
right: auto !important;
bottom: 0.75rem !important;
z-index: 2;
max-width: calc( 100% - 1.6rem );
padding: 0.25rem 0.55rem;
background: rgba( 10, 13, 17, 0.82 );
border: 1px solid rgba( 255, 138, 0, 0.48 );
box-shadow: 0 8px 18px rgba( 0, 0, 0, 0.34 );
color: var( --edfm-text );
font-family: var( --edfm-mono );
font-size: 0.68rem;
font-weight: 800;
letter-spacing: 0.08em;
line-height: 1;
text-transform: uppercase;
white-space: nowrap;
pointer-events: none;
}
.edfm-news-attribution {
margin-top: 0.85rem;
padding-top: 0.75rem;
border-top: 1px solid var( --edfm-border-soft );
color: var( --edfm-text-dim );
font-family: var( --edfm-mono );
font-size: var( --edfm-fs-meta );
line-height: 1.45;
}

Revision as of 04:52, 10 August 2026