Modern aesthetic redesign for gwasi.com with custom colors, persistent filters, smart parsing, native modal integration, and Reddit auto-opener via old.reddit.
// ==UserScript==
// @name GWA to direct audio link + & Gwasi Enhancer
// @namespace http://tampermonkey.net/
// @version 2.0
// @description Modern aesthetic redesign for gwasi.com with custom colors, persistent filters, smart parsing, native modal integration, and Reddit auto-opener via old.reddit.
// @author Ifrit Raen
// @license MIT
// @match https://gwasi.com/*
// @match https://old.reddit.com/*
// @match https://www.reddit.com/*
// @match https://reddit.com/*
// @grant GM_setClipboard
// @grant GM_getValue
// @grant GM_setValue
// @grant GM_openInTab
// ==/UserScript==
(function() {
'use strict';
const isReddit = window.location.hostname.includes('reddit.com');
if (isReddit) {
initRedditScript();
} else {
// Prevent native elements from flashing before modal logic attaches
const preStyle = document.createElement('style');
preStyle.textContent = `#help:not(.show), #advanced:not(.show) { display: none !important; }`;
document.head.appendChild(preStyle);
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', initGwasiScript);
} else {
initGwasiScript();
}
}
// ========== REDDIT SCRIPT ==========
function initRedditScript() {
const AUDIO_SITES = [
'soundgasm.net', 'hotaudio.net', 'whyp.it',
'erocast.me', 'audio.love', 'audiochan.com'
];
let openedLinks = new Set();
let hasRedirected = false;
function findAndOpenAudioLinks() {
const links = document.querySelectorAll('a[href]');
let newlyFound = [];
links.forEach(link => {
const href = link.href;
if (AUDIO_SITES.some(site => href.includes(site))) {
if (!openedLinks.has(href)) {
openedLinks.add(href);
newlyFound.push(href);
}
}
});
if (newlyFound.length > 0) {
if (!hasRedirected) {
hasRedirected = true;
console.log('Redirecting to primary audio link:', newlyFound[0]);
// Force redirect via simulated click (Bypasses New Reddit SPA routing blocks)
const a = document.createElement('a');
a.href = newlyFound[0];
a.rel = 'noopener noreferrer';
document.body.appendChild(a);
a.click();
}
// Open additional links in background tabs
for (let i = (hasRedirected ? 1 : 0); i < newlyFound.length; i++) {
if (typeof GM_openInTab !== 'undefined') {
GM_openInTab(newlyFound[i], { active: false, insert: true });
} else {
window.open(newlyFound[i], '_blank', 'noopener,noreferrer');
}
}
}
}
// New Reddit is a SPA. Poll the DOM continuously to catch links when they finally render.
const pollInterval = setInterval(findAndOpenAudioLinks, 500);
setTimeout(() => clearInterval(pollInterval), 15000); // Stop aggressive polling after 15s
}
// ========== GWASI SCRIPT ==========
function initGwasiScript() {
let settings = {
bgColor1: '#0f0f13',
bgColor2: '#18181d',
bgColor3: '#131318',
textColor: '#e0e0e0',
postTextColor: '#ffffff',
accentColor: '#ffffff'
};
loadSettings();
createSettingsModal();
setupModals();
applyStyles();
setupPersistentFilters();
observeAndEnhancePosts();
setupRedditLinkHandler();
function hexToRgb(hex) {
hex = hex.replace(/^#/, '');
if (hex.length === 3) hex = hex.split('').map(c => c + c).join('');
const int = parseInt(hex, 16);
return `${(int >> 16) & 255}, ${(int >> 8) & 255}, ${int & 255}`;
}
function loadSettings() {
const saved = GM_getValue('gwasiSettings');
if (saved) settings = { ...settings, ...JSON.parse(saved) };
}
function saveSettings() {
GM_setValue('gwasiSettings', JSON.stringify(settings));
updateColors();
}
function updateColors() {
const root = document.documentElement;
root.style.setProperty('--bg-color-1', settings.bgColor1);
root.style.setProperty('--bg-color-2', settings.bgColor2);
root.style.setProperty('--bg-color-3', settings.bgColor3);
root.style.setProperty('--text-color', settings.textColor);
root.style.setProperty('--post-text-color', settings.postTextColor);
root.style.setProperty('--accent-color', settings.accentColor);
root.style.setProperty('--accent-rgb', hexToRgb(settings.accentColor));
}
function setupModals() {
// Create Backdrop Overlay
const backdrop = document.createElement('div');
backdrop.id = 'gwasi-backdrop';
document.body.appendChild(backdrop);
// Relocate Native Modals to body to prevent z-index/overflow clipping
const helpEl = document.getElementById('help');
const advEl = document.getElementById('advanced');
const settingsModal = document.getElementById('gwasi-settings-modal');
if (helpEl) document.body.appendChild(helpEl);
if (advEl) document.body.appendChild(advEl);
// Apply shared modal styling class
[helpEl, advEl, settingsModal].forEach(el => {
if (el) el.classList.add('gwasi-modal');
});
// Universal Close Function
const closeAll = () => {
backdrop.classList.remove('show');
document.querySelectorAll('.gwasi-modal').forEach(el => el.classList.remove('show'));
// Uncheck the hijacked inputs so they can trigger again
const helpInput = document.getElementById('showhelp');
const advInput = document.getElementById('showadvanced');
if(helpInput) helpInput.checked = false;
if(advInput) advInput.checked = false;
};
backdrop.onclick = closeAll;
const openModal = (targetEl) => {
closeAll();
if (targetEl) {
backdrop.classList.add('show');
targetEl.classList.add('show');
}
};
// Hijack Native Inputs instead of floating buttons
const helpInput = document.getElementById('showhelp');
const advInput = document.getElementById('showadvanced'); // Labeled "Settings" natively
if (helpInput) {
helpInput.addEventListener('click', (e) => {
e.preventDefault();
helpInput.checked = true;
openModal(helpEl);
});
}
if (advInput) {
advInput.addEventListener('click', (e) => {
e.preventDefault();
advInput.checked = true;
openModal(advEl);
});
}
// Inject "UI Colors" button natively right next to the advanced/settings button
const advLabel = advInput ? advInput.closest('label.button') : null;
if (advLabel && advLabel.parentNode) {
const uiLabel = document.createElement('label');
uiLabel.className = 'button';
uiLabel.innerHTML = `<input type="button" style="display:none;"><span>UI Colors</span>`;
uiLabel.onclick = (e) => {
e.preventDefault();
openModal(settingsModal);
};
advLabel.parentNode.insertBefore(uiLabel, advLabel.nextSibling);
}
// Add close buttons to the inner native modals
[helpEl, advEl].forEach(el => {
if(el) {
const closeBtn = document.createElement('button');
closeBtn.innerHTML = '×';
closeBtn.className = 'modal-close-btn';
closeBtn.onclick = closeAll;
el.prepend(closeBtn);
}
});
}
function createSettingsModal() {
const modal = document.createElement('div');
modal.id = 'gwasi-settings-modal';
modal.innerHTML = `
<div class="settings-content">
<div class="settings-header">
<h3 style="color: var(--text-color); margin: 0;">UI Color Settings</h3>
<button class="modal-close-btn" id="close-settings-btn">×</button>
</div>
<div class="settings-section">
<label>Accent Color (Borders, Highlights)</label>
<input type="color" id="accentColor" value="${settings.accentColor}">
</div>
<div class="settings-section">
<label>General Text Color</label>
<input type="color" id="textColor" value="${settings.textColor}">
</div>
<div class="settings-section">
<label>Post Title Text Color</label>
<input type="color" id="postTextColor" value="${settings.postTextColor}">
</div>
<div class="settings-section">
<label>Background Top</label>
<input type="color" id="bgColor1" value="${settings.bgColor1}">
</div>
<div class="settings-section">
<label>Background Middle</label>
<input type="color" id="bgColor2" value="${settings.bgColor2}">
</div>
<div class="settings-section">
<label>Background Bottom</label>
<input type="color" id="bgColor3" value="${settings.bgColor3}">
</div>
<div class="settings-footer">
<button id="reset-settings">Reset Default</button>
<button id="save-settings">Save Config</button>
</div>
</div>
`;
document.body.appendChild(modal);
document.getElementById('close-settings-btn').onclick = () => {
document.getElementById('gwasi-backdrop').click();
};
document.getElementById('save-settings').onclick = () => {
settings.bgColor1 = document.getElementById('bgColor1').value;
settings.bgColor2 = document.getElementById('bgColor2').value;
settings.bgColor3 = document.getElementById('bgColor3').value;
settings.textColor = document.getElementById('textColor').value;
settings.postTextColor = document.getElementById('postTextColor').value;
settings.accentColor = document.getElementById('accentColor').value;
saveSettings();
document.getElementById('gwasi-backdrop').click();
showCopyFeedback('Colors saved!');
};
document.getElementById('reset-settings').onclick = () => {
settings = { bgColor1: '#0f0f13', bgColor2: '#18181d', bgColor3: '#131318', textColor: '#e0e0e0', postTextColor: '#ffffff', accentColor: '#ffffff' };
document.getElementById('bgColor1').value = settings.bgColor1;
document.getElementById('bgColor2').value = settings.bgColor2;
document.getElementById('bgColor3').value = settings.bgColor3;
document.getElementById('textColor').value = settings.textColor;
document.getElementById('postTextColor').value = settings.postTextColor;
document.getElementById('accentColor').value = settings.accentColor;
saveSettings();
showCopyFeedback('Reset to default!');
};
}
function setupPersistentFilters() {
const savedFilters = GM_getValue('gwasiFilters', '{}');
let filterState = {};
try { filterState = JSON.parse(savedFilters); } catch(e) {}
Object.entries(filterState).forEach(([key, val]) => {
// Ignore hijacked UI toggles
if (key === 'showhelp' || key === 'showadvanced') return;
const els = document.querySelectorAll(`[name="${key}"], [id="${key}"]`);
els.forEach(el => {
if (el.type === 'radio' || el.type === 'checkbox') {
if (el.value === val || (el.type === 'checkbox' && val === true)) el.checked = true;
} else {
el.value = val;
}
});
});
document.body.addEventListener('change', (e) => {
if (e.target.matches('input[type="radio"], input[type="checkbox"], select')) {
const key = e.target.name || e.target.id;
if (!key || key === 'showhelp' || key === 'showadvanced') return;
if (e.target.type === 'radio' && !e.target.checked) return;
filterState[key] = e.target.type === 'checkbox' ? e.target.checked : e.target.value;
GM_setValue('gwasiFilters', JSON.stringify(filterState));
}
});
document.body.addEventListener('input', (e) => {
if (e.target.matches('input[type="text"], input[type="textbox"], textarea')) {
const key = e.target.name || e.target.id;
if (key) {
filterState[key] = e.target.value;
GM_setValue('gwasiFilters', JSON.stringify(filterState));
}
}
});
}
function setupRedditLinkHandler() {
document.addEventListener('click', function(e) {
let target = e.target;
while (target && target.tagName !== 'A') target = target.parentElement;
if (target && target.tagName === 'A' && target.href.includes('reddit.com')) {
target.setAttribute('target', '_blank');
target.setAttribute('rel', 'noopener noreferrer');
}
}, true);
}
function copyToClipboard(text) {
if (typeof GM_setClipboard !== 'undefined') GM_setClipboard(text);
else navigator.clipboard.writeText(text);
showCopyFeedback();
}
function showCopyFeedback(msg = '✓ Copied!') {
const feedback = document.createElement('div');
feedback.textContent = msg;
feedback.style.cssText = `
position: fixed; top: 20px; right: 80px;
background: var(--bg-color-2); color: var(--text-color);
border: 1px solid var(--accent-color);
padding: 8px 16px; border-radius: 6px; z-index: 10000;
font-weight: 600; box-shadow: 0 4px 12px rgba(var(--accent-rgb), 0.2);
animation: slideIn 0.15s ease-out; font-size: 0.85em;
`;
document.body.appendChild(feedback);
setTimeout(() => {
feedback.style.animation = 'slideOut 0.15s ease-in';
setTimeout(() => feedback.remove(), 150);
}, 1500);
}
function enhancePost(listItem) {
if (listItem.dataset.enhanced) return;
listItem.dataset.enhanced = 'true';
const textContent = listItem.textContent;
const dateMatch = textContent.match(/(\d{4}-\d{2}-\d{2})/);
const sourceMatch = textContent.match(/\d{4}-\d{2}-\d{2}\s+(\S+\s+\d+)/);
const userLink = listItem.querySelector('a[href*="#q=u:"]');
const username = userLink ? userLink.textContent : null;
// Extract Raw Title (avoids fragmentation from Gwasi search <b> wrappers)
const parts = listItem.innerHTML.split(/<br\s*\/?>/i);
const rawTitleHtml = parts[parts.length - 1];
const tempDiv = document.createElement('div');
tempDiv.innerHTML = rawTitleHtml;
const fullTitle = tempDiv.textContent.trim();
const tags = fullTitle.match(/\[([^\]]+)\]/g) || [];
const tagTexts = tags.map(t => t.slice(1, -1));
// --- SMART PARSING LOGIC ---
// 1. Split string by bracket blocks and filter out empty whitespace.
const textSegments = fullTitle.split(/\[[^\]]+\]/).map(s => s.trim()).filter(s => s.length > 0);
let actualTitle = fullTitle;
if (textSegments.length === 1) {
// Scenario A: Only one non-bracket phrase exists in the entire string.
actualTitle = textSegments[0];
} else if (textSegments.length > 1) {
// Scenario B: Non-bracket text is fragmented by tags.
// Rule: Remove ONLY leading tags, keep everything from the first non-bracket word to the end.
actualTitle = fullTitle.replace(/^(\s*\[[^\]]+\]\s*)+/, '').trim();
}
// Begin rebuilding element
listItem.innerHTML = '';
const metaContainer = document.createElement('div');
metaContainer.className = 'post-meta';
if (dateMatch) {
const dateSpan = document.createElement('span');
dateSpan.className = 'post-date clickable-meta';
dateSpan.textContent = dateMatch[1];
dateSpan.title = 'Click to copy';
dateSpan.onclick = (e) => { e.preventDefault(); e.stopPropagation(); copyToClipboard(dateMatch[1]); };
metaContainer.appendChild(dateSpan);
}
if (sourceMatch) {
const sourceSpan = document.createElement('span');
sourceSpan.className = 'post-source clickable-meta';
sourceSpan.textContent = sourceMatch[1];
sourceSpan.title = 'Click to copy';
sourceSpan.onclick = (e) => { e.preventDefault(); e.stopPropagation(); copyToClipboard(sourceMatch[1]); };
metaContainer.appendChild(sourceSpan);
}
const scoreMatch = textContent.match(/\s+(\d+)\s+/);
if (scoreMatch) {
const scoreSpan = document.createElement('span');
scoreSpan.className = 'post-score clickable-meta';
scoreSpan.textContent = `↑ ${scoreMatch[1]}`;
scoreSpan.title = 'Click to copy';
scoreSpan.onclick = (e) => { e.preventDefault(); e.stopPropagation(); copyToClipboard(scoreMatch[1]); };
metaContainer.appendChild(scoreSpan);
}
if (username) {
const userSpan = document.createElement('span');
userSpan.className = 'post-user clickable-meta';
userSpan.textContent = username;
userSpan.title = 'Click to copy';
userSpan.onclick = (e) => { e.preventDefault(); e.stopPropagation(); copyToClipboard(username); };
metaContainer.appendChild(userSpan);
}
const flairSpans = listItem.parentElement.querySelectorAll('.flair');
flairSpans.forEach(flair => metaContainer.appendChild(flair.cloneNode(true)));
listItem.appendChild(metaContainer);
if (tagTexts.length > 0) {
const tagsContainer = document.createElement('div');
tagsContainer.className = 'post-tags';
tagTexts.forEach(tag => {
const tagBtn = document.createElement('button');
tagBtn.className = 'tag-button';
tagBtn.textContent = tag;
tagBtn.title = 'Click to copy';
tagBtn.onclick = (e) => { e.preventDefault(); e.stopPropagation(); copyToClipboard(`[${tag}]`); };
tagsContainer.appendChild(tagBtn);
});
listItem.appendChild(tagsContainer);
}
if (actualTitle) {
const titleContainer = document.createElement('div');
titleContainer.className = 'post-title-container';
titleContainer.title = 'Click to copy';
titleContainer.onclick = (e) => { e.preventDefault(); e.stopPropagation(); copyToClipboard(actualTitle); };
const titleDiv = document.createElement('div');
titleDiv.className = 'post-title';
titleDiv.textContent = actualTitle;
titleContainer.appendChild(titleDiv);
listItem.appendChild(titleContainer);
}
}
function observeAndEnhancePosts() {
document.querySelectorAll('ul > a > li').forEach(enhancePost);
const observer = new MutationObserver((mutations) => {
mutations.forEach((mutation) => {
mutation.addedNodes.forEach((node) => {
if (node.nodeType === 1) {
if (node.matches && node.matches('ul > a > li')) enhancePost(node);
node.querySelectorAll && node.querySelectorAll('ul > a > li').forEach(enhancePost);
}
});
});
});
observer.observe(document.body, { childList: true, subtree: true });
}
function applyStyles() {
updateColors();
const style = document.createElement('style');
style.textContent = `
* {
transition: background-color 0.1s ease-out, color 0.1s ease-out, border-color 0.1s ease-out, transform 0.1s ease-out, box-shadow 0.1s ease-out;
box-sizing: border-box;
}
body {
background: linear-gradient(135deg, var(--bg-color-1) 0%, var(--bg-color-2) 50%, var(--bg-color-3) 100%) !important;
background-attachment: fixed !important;
color: var(--text-color) !important;
font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif !important;
line-height: 1.3 !important;
padding: 12px !important;
max-width: 1200px !important;
margin: 0 auto !important;
}
/* --- Backdrop Modals --- */
#gwasi-backdrop {
display: none; position: fixed; top: 0; left: 0; width: 100%; height: 100%;
background: rgba(0, 0, 0, 0.7); z-index: 10000;
backdrop-filter: blur(4px);
}
#gwasi-backdrop.show { display: block; }
.gwasi-modal {
display: none !important;
position: fixed !important; top: 50% !important; left: 50% !important;
transform: translate(-50%, -50%) !important; z-index: 10001 !important;
background: var(--bg-color-2) !important;
border: 1px solid rgba(var(--accent-rgb), 0.4) !important;
border-radius: 12px !important; padding: 20px !important;
width: 90% !important; max-width: 500px !important;
max-height: 85vh !important; overflow-y: auto !important;
box-shadow: 0 10px 40px rgba(0,0,0,0.8) !important;
margin: 0 !important; color: var(--text-color) !important;
}
.gwasi-modal.show { display: block !important; }
.modal-close-btn {
position: absolute; top: 12px; right: 16px;
background: transparent; border: none; font-size: 24px;
color: var(--text-color); cursor: pointer; line-height: 1;
}
.modal-close-btn:hover { color: var(--accent-color); }
/* Settings Config Specifics */
.settings-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 16px; }
.settings-section { margin-bottom: 12px; }
.settings-section label { display: block; margin-bottom: 4px; font-size: 0.85em; font-weight: 600; color: var(--text-color); }
.settings-section input[type="color"] {
width: 100%; height: 32px; border: 1px solid rgba(var(--accent-rgb), 0.3);
border-radius: 6px; cursor: pointer; background: transparent; padding: 0;
}
.settings-footer { display: flex; gap: 8px; margin-top: 16px; }
.settings-footer button { flex: 1; padding: 8px; border: none; border-radius: 6px; font-weight: 600; cursor: pointer; }
#save-settings { background: rgba(var(--accent-rgb), 0.2); border: 1px solid var(--accent-color); color: var(--text-color); }
#reset-settings { background: rgba(255, 255, 255, 0.05); color: var(--text-color); border: 1px solid rgba(255,255,255,0.1); }
.settings-footer button:hover { background: rgba(var(--accent-rgb), 0.3); }
/* Header Elements */
header {
background: rgba(255, 255, 255, 0.03) !important;
padding: 10px 16px !important; border-radius: 8px !important;
margin-bottom: 12px !important; border: 1px solid rgba(255, 255, 255, 0.05) !important;
}
header h3 {
font-size: 1.2em !important; font-weight: 700 !important;
color: var(--text-color) !important;
display: inline-block !important; margin: 0 !important;
}
header a {
color: var(--text-color) !important;
background: rgba(255,255,255, 0.05) !important;
border: 1px solid rgba(var(--accent-rgb), 0.2) !important;
padding: 4px 10px !important; border-radius: 4px !important;
font-size: 0.85em !important; font-weight: 600 !important;
}
header a:hover {
background: rgba(var(--accent-rgb), 0.15) !important;
border-color: var(--accent-color) !important;
}
/* Native Gwasi Inputs & Controls inside Modals AND visible Filters */
input[type=textbox], input[type=text] {
background: rgba(255, 255, 255, 0.05) !important;
border: 1px solid rgba(var(--accent-rgb), 0.3) !important;
border-radius: 6px !important; padding: 8px 12px !important;
font-size: 0.9em !important; color: var(--text-color) !important;
width: 100% !important; margin-bottom: 12px !important;
}
input[type=textbox]:focus, input[type=text]:focus {
outline: none !important; border-color: var(--accent-color) !important;
}
div.buttons {
background: rgba(255, 255, 255, 0.02) !important;
padding: 8px !important; border-radius: 6px !important;
margin-bottom: 8px !important; border: 1px solid rgba(255, 255, 255, 0.05) !important;
display: flex !important; gap: 6px !important; flex-wrap: wrap !important;
}
label.button { margin: 0 !important; }
label.button span {
padding: 4px 12px !important; border-radius: 4px !important;
font-size: 0.85em !important; color: var(--text-color) !important;
border: 1px solid rgba(var(--accent-rgb), 0.3) !important;
background: rgba(255,255,255, 0.05) !important; cursor: pointer;
display: inline-block;
}
label.button span:hover {
background: rgba(var(--accent-rgb), 0.15) !important;
border-color: var(--accent-color) !important;
}
span.radio span {
padding: 4px 8px !important; border-radius: 4px !important;
font-size: 0.8em !important; color: var(--text-color) !important;
border: 1px solid transparent !important;
}
span.radio input:checked + span {
background: rgba(var(--accent-rgb), 0.15) !important;
border-color: var(--accent-color) !important;
color: var(--text-color) !important;
}
#filters {
background: rgba(255, 255, 255, 0.03) !important;
border: 1px solid rgba(var(--accent-rgb), 0.2) !important;
border-radius: 8px !important; padding: 12px !important;
margin-bottom: 12px !important; max-height: 150px !important;
overflow-y: auto !important;
}
/* Compact Post Items */
ul { display: grid !important; gap: 6px !important; padding: 0 !important; }
ul > a > li {
background: rgba(255, 255, 255, 0.02) !important;
border: 1px solid rgba(var(--accent-rgb), 0.15) !important;
border-radius: 6px !important; padding: 8px 12px !important;
text-align: center !important; list-style: none !important;
}
ul > a > li:hover {
background: rgba(255, 255, 255, 0.04) !important;
border-color: var(--accent-color) !important;
}
.post-meta { display: flex; flex-wrap: wrap; gap: 4px; justify-content: center; margin-bottom: 6px; }
.clickable-meta {
padding: 2px 6px; border-radius: 3px;
background: rgba(255, 255, 255, 0.04);
border: 1px solid rgba(var(--accent-rgb), 0.15);
font-size: 0.75em; color: var(--text-color); cursor: pointer; user-select: none;
}
.clickable-meta:hover { background: rgba(var(--accent-rgb), 0.1); border-color: var(--accent-color); }
.post-date { font-family: monospace; font-weight: 600; }
.post-source, .post-score, .post-user { font-weight: 600; }
.flair { display: inline-block; padding: 2px 6px; border-radius: 3px; font-size: 0.7em; font-weight: 600; }
.audio { background: rgba(var(--accent-rgb), 0.8); color: var(--bg-color-1); }
.script { background: #20c997; color: #fff; }
.post-tags { display: flex; flex-wrap: wrap; gap: 4px; margin: 6px 0; justify-content: center; }
.tag-button {
background: rgba(var(--accent-rgb), 0.08); border: 1px solid rgba(var(--accent-rgb), 0.15);
color: var(--text-color); padding: 2px 6px; border-radius: 3px;
font-size: 0.7em; font-weight: 500; cursor: pointer;
}
.tag-button:hover { background: rgba(var(--accent-rgb), 0.2); border-color: var(--accent-color); }
.post-title-container {
margin-top: 4px; padding: 6px 10px;
background: rgba(255,255,255,0.02);
border: 1px solid rgba(var(--accent-rgb), 0.15);
border-radius: 4px; cursor: pointer; text-align: center;
}
.post-title-container:hover {
background: rgba(var(--accent-rgb), 0.08); border-color: var(--accent-color);
}
.post-title { font-size: 1.05em; font-weight: 700; color: var(--post-text-color); }
/* Scrollbar */
::-webkit-scrollbar { width: 6px; }
::-webkit-scrollbar-track { background: rgba(255,255,255,0.05); border-radius: 10px; }
::-webkit-scrollbar-thumb { background: rgba(var(--accent-rgb), 0.5); border-radius: 10px; }
@keyframes slideIn { from { transform: translateX(100%); opacity: 0; } to { transform: translateX(0); opacity: 1; } }
@keyframes slideOut { from { transform: translateX(0); opacity: 1; } to { transform: translateX(100%); opacity: 0; } }
`;
document.head.appendChild(style);
}
}
})();