// ==UserScript==
// @name Torn Wiki Dark
// @namespace https://github.com/skillerious
// @version 2.6
// @description Dark-gray + cyan skin for *all* pages on wiki.torn.com.
// • Static sidebar, centred content column
// • Cyan headings & links, darker logo tile
// • Cyan scrollbar, zero white leaks
// • 64 px progress-ring “Back to Top” button, perfectly centred, clickable & smooth-scrolling
// 2025-07-12 build 🔵⬆️🌑
// @author Robin Doak (Skillerious)
// @match https://wiki.torn.com/wiki/*
// @match https://wiki.torn.com/*
// @include /^https:\/\/wiki\.torn\.com\/.*$/
// @grant none
// @run-at document-end
// @license MIT
// ==/UserScript==
(() => {
/*───────────────────────────────────────────────────────────────
1. GLOBAL CSS THEME
───────────────────────────────────────────────────────────────*/
const css = `
/* ─── Colour palette & constants ───────────────────────────── */
:root {
--bg : #1b1b1b;
--surface : #242424;
--surface-2 : #2e2e2e;
--card : #282828;
--cyan : #55c3ff;
--cyan-light : #7ad0ff;
--border : #3d3d3d;
--text-main : #d5d7da;
--text-muted : #9ca2a8;
--radius : 6px;
--shadow : 0 3px 10px rgb(0 0 0 / 0.5);
--max-read : 950px;
}
/* ─── Base layout & typography ─────────────────────────────── */
body,
#content,
.container,
.row,
.content-area-wrapper,
.mw-parser-output,
.mw-body {
background: var(--bg) !important;
color: var(--text-main) !important;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
Arial, sans-serif;
}
.content-area-wrapper {
flex: 1 1 auto !important;
padding: 0 1rem;
}
#content {
max-width: var(--max-read);
margin: 0 auto;
}
h1, h2, h3, h4, h5, h6 {
color: var(--cyan) !important;
font-weight: 700;
line-height: 1.3;
margin: 1.2em 0 0.6em;
}
h1 { font-size: 2.15rem; border: none; }
h2 { font-size: 1.55rem; border-bottom: 1px solid var(--cyan); padding-bottom: 0.4rem; }
h3 { font-size: 1.25rem; }
h4, h5, h6 { font-size: 1.1rem; }
/* ─── Links ────────────────────────────────────────────────── */
a {
color: var(--cyan);
text-decoration: none;
transition: color 0.15s;
}
a:hover {
color: var(--cyan-light);
text-decoration: underline;
}
a[target="_blank"]::after {
content: "↗";
font-size: 0.75em;
margin-left: 2px;
vertical-align: super;
color: var(--text-muted);
}
/* ─── Sidebar & logo tile ─────────────────────────────────── */
.side-panel-wrapper {
background: var(--surface);
border-right: 1px solid var(--border);
}
.side-panel-wrapper .card {
background: var(--surface) !important;
border: none !important;
}
.card.torn-navigation-header {
background: var(--surface-2) !important;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 1.4rem 0 1rem;
}
.torn-title-text {
font-size: 2.35rem;
font-weight: 900;
line-height: 1;
color: var(--cyan) !important;
letter-spacing: 1px;
}
.torn-title-text span {
font-weight: 300;
margin-left: 0.25rem;
color: var(--cyan) !important;
}
.torn-title-text::after {
content: "";
display: block;
width: 80%;
height: 4px;
background: var(--cyan);
margin: 0.45rem auto 0;
border-radius: 2px;
}
.torn-back-button {
margin-top: 0.85rem;
font-weight: 600;
font-size: 0.85rem;
color: var(--text-main);
display: flex;
align-items: center;
gap: 4px;
text-decoration: none;
}
.torn-back-button svg path { fill: #b0b0b0; }
.torn-back-button:hover { color: var(--cyan); }
.torn-back-button:hover svg path { fill: var(--cyan); }
/* Navigation links inside sidebar */
.torn-navigation-panel nav a.nav-link {
color: var(--text-muted);
border-radius: var(--radius);
margin: 0.13rem 0;
padding: 0.32rem 0.8rem;
transition: background 0.15s, color 0.15s;
}
.torn-navigation-panel nav a.nav-link:hover,
.torn-navigation-panel nav a.nav-link.active {
background: var(--surface-2);
color: var(--text-main);
}
.torn-navigation-panel nav a.nav-link.disabled {
color: var(--cyan) !important;
font-weight: 700;
cursor: default;
}
/* ─── Table of Contents ────────────────────────────────────── */
#toc,
.toc {
background: var(--surface-2);
border: 1px solid var(--border);
border-radius: var(--radius);
padding: 0.9rem 1rem 1rem;
margin-bottom: 1.5rem;
}
#toc .toctitle h2 {
margin: 0 0 0.55rem;
font-size: 1.2rem;
color: var(--cyan);
border: none;
}
#toc ul,
.toc ul { padding-left: 1.25rem; margin: 0; }
#toc li,
.toc li { line-height: 1.5; }
/* ─── Tables ──────────────────────────────────────────────── */
table, th, td { border-color: var(--border) !important; }
table {
background: var(--surface) !important;
border-collapse: collapse !important;
}
th, td {
background: var(--card) !important;
color: var(--text-main) !important;
padding: 6px 8px !important;
}
th[style*="background"],
td[style*="background"] { background: var(--card) !important; }
tr:nth-child(even) td { background: var(--surface) !important; }
.mw-collapsible-toggle a { color: var(--cyan); font-weight: 600; }
/* ─── Info / alert boxes ─────────────────────────────────── */
.alert,
.ambox,
.mbox,
.infobox,
.new-infobox {
background: var(--surface);
border: 1px solid var(--border) !important;
color: var(--text-main) !important;
}
.alert-warning,
.alert.alert-warning {
background: var(--surface-2) !important;
color: var(--text-main) !important;
border: 1px solid var(--border) !important;
}
.infobox th,
.new-infobox-heading {
background: var(--surface-2) !important;
color: var(--text-main) !important;
}
/* ─── Code blocks ────────────────────────────────────────── */
pre,
code {
background: var(--surface-2) !important;
color: var(--text-main) !important;
border: 1px solid var(--border) !important;
border-radius: var(--radius);
}
pre { padding: 10px; overflow: auto; }
/* ─── Forms ──────────────────────────────────────────────── */
input,
textarea,
select {
background: var(--surface-2) !important;
color: var(--text-main) !important;
border: 1px solid var(--border) !important;
}
input::placeholder,
textarea::placeholder { color: var(--text-muted); }
/* ─── Footer & scrollbar ─────────────────────────────────── */
#footer,
#footer-info,
#footer-places {
background: var(--bg) !important;
color: var(--text-muted) !important;
}
#footer a { color: var(--cyan); }
::-webkit-scrollbar { width: 12px; height: 12px; }
::-webkit-scrollbar-track { background: var(--bg); }
::-webkit-scrollbar-thumb {
background: var(--cyan);
border-radius: 6px;
transition: background 0.2s;
}
::-webkit-scrollbar-thumb:hover { background: var(--cyan-light); }
html {
scrollbar-width: thin;
scrollbar-color: var(--cyan) var(--bg);
}
/* ─── Hide Torn’s built-in back-to-top ───────────────────── */
#torn-back-to-top { display: none !important; }
/* ─── Back-to-Top FAB animation (no overshoot) ───────────── */
@keyframes twPop {
0% { transform: scale(0.4); opacity: 0; }
100% { transform: scale(1); opacity: 0.95; }
}
/* ─── FAB container (64 × 64 px) ─────────────────────────── */
#tw-b2t {
position: fixed;
right: 1.4rem;
bottom: 1.4rem;
width: 64px;
height: 64px;
border-radius: 50%;
backdrop-filter: blur(8px);
background: rgba(85, 195, 255, 0.12);
box-shadow: var(--shadow);
cursor: pointer;
opacity: 0;
pointer-events: none;
transform: scale(0.4);
transition: box-shadow 0.25s;
z-index: 3000;
}
#tw-b2t.show {
animation: twPop 0.33s ease-out forwards;
pointer-events: auto; /* <— makes it clickable */
}
#tw-b2t:hover {
box-shadow: 0 0 14px var(--cyan-light), var(--shadow);
}
/* Progress ring */
#tw-b2t svg.ring {
position: absolute;
top: 0;
left: 0;
width: 64px;
height: 64px;
transform: rotate(-90deg);
}
#tw-ring-track {
stroke: rgba(255, 255, 255, 0.07);
stroke-width: 8;
fill: none;
}
#tw-ring-progress {
stroke: var(--cyan);
stroke-width: 8;
stroke-linecap: round;
fill: none;
transition: stroke-dashoffset 0.1s;
}
/* Arrow */
.tw-arrow {
position: absolute;
width: 26px;
height: 26px;
fill: var(--cyan);
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
transition: transform 0.25s;
}
#tw-b2t:hover .tw-arrow {
transform: translate(-50%, -55%);
}
`;
document.head.appendChild(document.createElement('style')).textContent = css;
/*───────────────────────────────────────────────────────────────
2. Make external links open in a new tab
───────────────────────────────────────────────────────────────*/
document.querySelectorAll('a[href]').forEach(link => {
const href = link.getAttribute('href') || '';
if (href.startsWith('#') || href.toLowerCase().startsWith('javascript')) return;
/* treat as external if hostname differs */
if (link.hostname && link.hostname !== location.hostname) {
link.target = '_blank';
link.rel = 'noopener';
}
});
/*───────────────────────────────────────────────────────────────
3. Build smaller (64 px) Back-to-Top FAB
───────────────────────────────────────────────────────────────*/
const SIZE = 64; // px
const STROKE = 8; // px
const RADIUS = 28; // (28 × 2) + 8 = 64
const CIRCUMFERENCE = 2 * Math.PI * RADIUS;
/* container */
const fab = document.createElement('div');
fab.id = 'tw-b2t';
/* inner SVG (ring) + arrow */
fab.innerHTML = `
<svg class="ring" viewBox="0 0 ${SIZE} ${SIZE}">
<circle
cx="${SIZE / 2}"
cy="${SIZE / 2}"
r="${RADIUS}"
stroke-width="${STROKE}"
fill="none"
stroke="rgba(255,255,255,0.07)"
></circle>
<circle
id="tw-ring-progress"
cx="${SIZE / 2}"
cy="${SIZE / 2}"
r="${RADIUS}"
stroke-width="${STROKE}"
fill="none"
stroke="var(--cyan)"
stroke-linecap="round"
stroke-dasharray="${CIRCUMFERENCE}"
stroke-dashoffset="${CIRCUMFERENCE}"
></circle>
</svg>
<svg class="tw-arrow" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
<path d="M12 6 6 12l-1.4-1.4L12 3.2l7.4 7.4L18 12z"></path>
</svg>
`;
document.body.appendChild(fab);
const ring = fab.querySelector('#tw-ring-progress');
/* smooth scroll behaviour */
fab.addEventListener('click', () => {
window.scrollTo({
top: 0,
behavior: 'smooth'
});
});
/* update ring offset + FAB visibility on scroll */
const updateFab = () => {
const max = document.documentElement.scrollHeight - window.innerHeight;
const pct = max ? Math.min(window.scrollY / max, 1) : 0;
ring.style.strokeDashoffset = CIRCUMFERENCE * (1 - pct);
fab.classList.toggle('show', window.scrollY > 150);
};
window.addEventListener('scroll', updateFab, { passive: true });
updateFab(); // run once on load
console.info('[Torn Wiki Dark-Gray] v2.6 loaded – FAB clickable & smaller');
})();