Rule34 - Reskin

Rule34 - Dark Masonry Reskin

2025-05-24 يوللانغان نەشرى. ئەڭ يېڭى نەشرىنى كۆرۈش.

// ==UserScript==
// @name         Rule34 - Reskin
// @namespace    ko-fi.com/awesome97076
// @version      1
// @description  Rule34 - Dark Masonry Reskin
// @author       Awesome
// @match        https://rule34.xxx/*
// @license      MIT
// @icon         https://www.google.com/s2/favicons?sz=64&domain=rule34.xxx
// @grant        none
// @run-at       document-start
// ==/UserScript==

(function () {
  "use strict";

  const style = document.createElement("style");
  style.innerHTML = `
:root {
  /* Dark theme color palette */
  --bg-color: #121212;
  --bg-secondary: #1e1e1e;
  --bg-tertiary: #2d2d2d;
  --accent-color: #9c64a6;
  --accent-secondary: #ae81ff;
  --text-primary: #e0e0e0;
  --text-secondary: #b0b0b0;
  --text-muted: #707070;
  --border-color: rgba(255, 255, 255, 0.1);
  --success-color: #50fa7b;
  --warning-color: #ffb86c;
  --error-color: #ff5555;

  /* Tag type colors - vibrant but fitting dark theme */
  --tag-artist: #ff79c6;
  --tag-character: #50fa7b;
  --tag-copyright: #bd93f9;
  --tag-metadata: #f1fa8c;

  /* Layout - Responsive defaults */
  --container-width: 100%;
  --container-max-width: 100%;
  --column-count: 3; /* Start with max columns for large screens */
  --column-gap: 3px;
  --content-padding: 8px;
  --border-radius: 6px;
  --box-shadow: 0 4px 6px rgba(0, 0, 0, 0.3);

  /* Thumbnails */
  --thumbnail-padding: 0;
  --thumbnail-border-width: 2px;
  --thumbnail-border-radius: 8px;
  --thumbnail-hover-scale: 1.08;
  --thumbnail-transition: all 0.25s cubic-bezier(0.25, 0.46, 0.45, 0.94);
  --video-border-color: #8e44ad;

  /* Typography - Responsive base */
  --font-primary: 'Inter', 'Segoe UI', Roboto, -apple-system, BlinkMacSystemFont, sans-serif;
  --font-secondary: 'Poppins', 'Segoe UI', Roboto, sans-serif;
  --font-code: 'Fira Code', 'Cascadia Code', Consolas, monospace;
  --font-size-base: clamp(14px, 2.5vw, 16px); /* Responsive font size */
  --line-height: 1.6;

  /* UI Elements */
  --button-padding: 8px 16px;
  --input-padding: 8px 12px;
  --nav-height: 60px;
}

/* Basic resets and body styling */
html, body {
  margin: 0;
  padding: 0;
  font-family: var(--font-primary);
  font-size: var(--font-size-base);
  line-height: var(--line-height);
  background-color: var(--bg-color);
  color: var(--text-primary);
  min-width: 320px; /* Minimum supported width */
  overflow-x: hidden; /* Prevent horizontal scroll */
}

body, div, h1, h2, h3, h4, h5, h6, p, ul, li, dd, dt {
  font-family: var(--font-primary);
}

/* Apply border-box sizing to all elements for consistent sizing */
*, *::before, *::after {
  box-sizing: border-box;
}

/* Content container - Fully responsive */
div#content {
  width: 100%;
  max-width: 100%;
  margin: 0 auto;
  padding: var(--content-padding);
  box-sizing: border-box;
}

/* Header area modernization - Mobile first */
div#header {
  background: var(--bg-secondary);
  padding: 0;
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.2);
  position: sticky;
  top: 0;
  z-index: 1000;
  margin-bottom: clamp(16px, 3vw, 24px);
}

div#header #site-title {
  background-image: none;
  padding: clamp(10px, 2vw, 15px) clamp(15px, 3vw, 20px);
}

div#header #site-title a {
  color: var(--accent-color);
  font-size: clamp(20px, 4vw, 24px);
  font-weight: bold;
  font-family: var(--font-secondary);
  word-wrap: break-word;
}

.tag-count {
  color: var(--text-secondary);
  font-size: clamp(12px, 2vw, 14px);
}

/* Navigation styling - Responsive */
div#header ul#navbar,
div#header ul#subnavbar {
  background: var(--bg-secondary);
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  list-style: none;
  padding: 0 clamp(10px, 2vw, 20px);
  margin: 0;
  border-bottom: 1px solid var(--border-color);
  gap: 0;
  overflow-x: auto; /* Allow horizontal scroll on very small screens */
  -webkit-overflow-scrolling: touch; /* Smooth scrolling on iOS */
}

div#header ul#navbar li,
div#header ul#subnavbar li {
  margin: 0;
  padding: 0;
  flex-shrink: 0;
}

div#header ul#navbar li a,
div#header ul#subnavbar li a {
  display: block;
  padding: clamp(10px, 2vw, 15px);
  color: var(--text-secondary);
  transition: color 0.2s ease;
  text-decoration: none;
  white-space: nowrap;
  font-size: clamp(13px, 2.5vw, 15px);
}

div#header ul#navbar li a:hover,
div#header ul#subnavbar li a:hover {
  color: var(--accent-color);
}

div#header ul#navbar li.current-page,
div#header ul#subnavbar li.current-page {
  background: transparent;
}

div#header ul#navbar li.current-page a,
div#header ul#subnavbar li.current-page a {
  color: var(--accent-color);
  font-weight: bold;
}

/* Links styling */
a:link, a:visited {
  color: var(--accent-color);
  text-decoration: none;
  transition: color 0.2s, text-decoration 0.2s;
}

a:hover, a:active {
  color: var(--accent-secondary);
  text-decoration: underline;
}

/* Search form styling - Responsive */
div.tag-search {
  background: var(--bg-tertiary);
  padding: clamp(10px, 2vw, 15px);
  border-radius: var(--border-radius);
  margin-bottom: clamp(15px, 3vw, 20px);
  width: 100%;
  max-width: 100%;
}

div.tag-search input[type="text"] {
  width: 100%;
  padding: var(--input-padding);
  background: var(--bg-color);
  border: 1px solid var(--border-color);
  border-radius: var(--border-radius);
  color: var(--text-primary);
  font-family: var(--font-primary);
  font-size: clamp(14px, 2.5vw, 16px);
  margin-bottom: 10px;
  box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.1);
}

div.tag-search input[type="submit"] {
  padding: var(--button-padding);
  background: var(--accent-color);
  color: white;
  border: none;
  border-radius: var(--border-radius);
  cursor: pointer;
  font-weight: bold;
  font-size: clamp(14px, 2.5vw, 16px);
  transition: background 0.2s;
  width: 100%;
  max-width: 200px;
}

div.tag-search input[type="submit"]:hover {
  background: var(--accent-secondary);
}

/* Tag styling */
.tag-type-artist a, .tag-type-artist {
  color: var(--tag-artist) !important;
}

.tag-type-character a, .tag-type-character {
  color: var(--tag-character) !important;
}

.tag-type-copyright a, .tag-type-copyright {
  color: var(--tag-copyright) !important;
}

.tag-type-metadata a, .tag-type-metadata {
  color: var(--tag-metadata) !important;
}

/* Masonry layout for the image grid - Fully responsive */
div.image-list {
  display: block !important;
  column-count: var(--column-count);
  column-gap: var(--column-gap);
  width: 100%;
  max-width: 100%;
  margin: 0 auto;
  padding: 0;
}

/* Thumbnail container */
.thumb {
  width: 100% !important;
  height: auto !important;
  display: inline-block !important;
  break-inside: avoid;
  margin-bottom: var(--column-gap);
  padding: var(--thumbnail-padding);
  box-sizing: border-box;
  page-break-inside: avoid;
}

/* Thumbnail links */
.thumb a {
  display: block !important;
  position: relative;
  overflow: hidden;
  border-radius: var(--thumbnail-border-radius);
  background: var(--bg-tertiary);
  box-shadow: var(--box-shadow);
  transition: var(--thumbnail-transition);
  max-height: 100%;
  height: 100%;
  width: auto;
}

.thumb a:hover {
  transform: scale(var(--thumbnail-hover-scale));
  transition: var(--thumbnail-transition);
  box-shadow: 0 6px 12px rgba(0, 0, 0, 0.4);
  z-index: 9999;
}

/* Images within thumbnails */
.thumb img, .thumb video {
  width: 100% !important;
  height: auto !important;
  max-height: 100% !important;
  max-width: 100% !important;
  display: block !important;
  transition: var(--thumbnail-transition);
  object-fit: contain;
}

/* Special styling for video thumbnails */
.webm-thumb {
  border: var(--thumbnail-border-width) solid var(--video-border-color) !important;
  border-radius: var(--thumbnail-border-radius) !important;
  box-sizing: border-box !important;
}

/* Hover effect for video thumbnails */
.thumb a:hover .webm-thumb {
  opacity: 0.9;
}

/* Enhanced responsive breakpoints for any screen size */
/* Ultra-wide screens (4K+) */
@media (min-width: 2560px) {
  :root {
    --column-count: 6;
    --column-gap: 20px;
    --content-padding: 30px;
    --font-size-base: 17px;
  }
}

/* Very large screens */
@media (max-width: 2559px) and (min-width: 1920px) {
  :root {
    --column-count: 4;
    --column-gap: 18px;
  }
}

/* Large screens */
@media (max-width: 1919px) and (min-width: 1600px) {
  :root {
    --column-count: 4;
    --column-gap: 16px;
  }
}

/* Medium-large screens */
@media (max-width: 1599px) and (min-width: 1200px) {
  :root {
    --column-count: 3;
    --column-gap: 14px;
  }
}

/* Medium screens */
@media (max-width: 1199px) and (min-width: 992px) {
  :root {
    --column-count: 3;
    --column-gap: 12px;
  }
}

/* Small tablets */
@media (max-width: 991px) and (min-width: 768px) {
  :root {
    --column-count: 3;
    --column-gap: 10px;
    --content-padding: 15px;
  }
}

/* Large phones / small tablets */
@media (max-width: 767px) and (min-width: 576px) {
  :root {
    --column-count: 2;
    --column-gap: 8px;
    --content-padding: 12px;
  }
}

/* Mobile phones */
@media (max-width: 575px) {
  :root {
    --column-count: 1;
    --column-gap: 10px;
    --content-padding: 10px;
    --nav-height: 50px;
  }

  /* Stack navigation vertically on very small screens */
  div#header ul#navbar,
  div#header ul#subnavbar {
    justify-content: center;
  }

  /* Make buttons full width on mobile */
  button, input[type="submit"] {
    width: 100%;
  }
}

/* Ultra-small screens (older phones) */
@media (max-width: 359px) {
  :root {
    --content-padding: 8px;
    --column-gap: 8px;
    --thumbnail-padding: 4px;
  }

  div#header ul#navbar li a,
  div#header ul#subnavbar li a {
    padding: 8px;
  }
}

/* Paginator styling - Responsive */
div#paginator {
  display: flex;
  justify-content: center;
  align-items: center;
  margin: clamp(20px, 4vw, 30px) 0;
  flex-wrap: wrap;
  gap: 4px;
}

div#paginator a,
div#paginator b {
  display: inline-block;
  padding: clamp(6px, 1.5vw, 8px) clamp(10px, 2vw, 14px);
  margin: 2px;
  border-radius: var(--border-radius);
  background: var(--bg-tertiary);
  color: var(--text-secondary);
  text-decoration: none;
  transition: all 0.2s;
  font-size: clamp(13px, 2.5vw, 15px);
}

div#paginator a:hover {
  background: var(--accent-color);
  color: white;
  text-decoration: none;
}

div#paginator b {
  background: var(--accent-color);
  color: white;
  font-weight: bold;
}

/* Manual page chooser styling - Responsive */
.manual-page-chooser {
  display: inline-flex;
  align-items: center;
  margin: 10px 0;
  width: 100%;
  max-width: 200px;
}

.manual-page-chooser input[type="text"] {
  width: 100%;
  padding: clamp(6px, 1.5vw, 8px);
  background: var(--bg-tertiary);
  border: 1px solid var(--border-color);
  border-radius: var(--border-radius) 0 0 var(--border-radius);
  color: var(--text-primary);
  font-size: clamp(13px, 2.5vw, 15px);
}

.manual-page-chooser input[type="submit"] {
  padding: clamp(6px, 1.5vw, 8px) clamp(10px, 2vw, 12px);
  background: var(--accent-color);
  color: white;
  border: none;
  border-radius: 0 var(--border-radius) var(--border-radius) 0;
  cursor: pointer;
  font-size: clamp(13px, 2.5vw, 15px);
  white-space: nowrap;
}

/* Tables styling - Responsive */
table {
  width: 100%;
  border-collapse: collapse;
  margin-bottom: clamp(15px, 3vw, 20px);
  background: var(--bg-secondary);
  border-radius: var(--border-radius);
  overflow: hidden;
  display: block;
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}

table th {
  background: var(--bg-tertiary);
  color: var(--text-primary);
  padding: clamp(8px, 1.5vw, 12px);
  text-align: left;
  font-weight: bold;
  font-size: clamp(13px, 2.5vw, 15px);
  white-space: nowrap;
}

table td {
  padding: clamp(8px, 1.5vw, 12px);
  border-top: 1px solid var(--border-color);
  color: var(--text-secondary);
  font-size: clamp(13px, 2.5vw, 15px);
}

table tr:hover td {
  background: rgba(255, 255, 255, 0.03);
}

/* Form controls - Responsive */
input, textarea, select {
  background: var(--bg-tertiary);
  color: var(--text-primary);
  border: 1px solid var(--border-color);
  border-radius: var(--border-radius);
  padding: var(--input-padding);
  font-family: var(--font-primary);
  font-size: clamp(14px, 2.5vw, 16px);
  max-width: 100%;
}

/* Auto-expanding text input fields */
textarea, input[type="text"] {
  word-wrap: break-word;
  word-break: normal;
  white-space: pre-wrap;
  overflow-wrap: break-word;
  min-height: 2.5em;
  line-height: 1.5;
  vertical-align: top;
  resize: vertical;
  width: 100%;
}

/* Convert single-line text inputs to auto-expanding */
input[type="text"] {
  height: auto !important;
  min-height: calc(1.5em + var(--input-padding) * 2);
}

/* Ensure inputs can expand on user input with JavaScript support */
textarea {
  overflow: hidden;
  transition: height 0.2s ease;
}

input:focus, textarea:focus, select:focus {
  outline: none;
  border-color: var(--accent-color);
  box-shadow: 0 0 0 2px rgba(156, 100, 166, 0.2);
}

button, input[type="submit"] {
  background: var(--accent-color);
  color: white;
  border: none;
  border-radius: var(--border-radius);
  padding: var(--button-padding);
  cursor: pointer;
  font-weight: bold;
  transition: background 0.2s;
  font-size: clamp(14px, 2.5vw, 16px);
  touch-action: manipulation; /* Improve touch responsiveness */
}

button:hover, input[type="submit"]:hover {
  background: var(--accent-secondary);
}

/* Additional modernizations */

/* Notice styling - Responsive */
div.notice, div.status-notice {
  background: var(--bg-secondary);
  border-left: 4px solid var(--accent-color);
  color: var(--text-primary);
  padding: clamp(10px, 2vw, 15px);
  margin: clamp(10px, 2vw, 15px) 0;
  border-radius: 0 var(--border-radius) var(--border-radius) 0;
  font-size: clamp(13px, 2.5vw, 15px);
}

/* Quote blocks - Responsive */
div.quote {
  background: var(--bg-tertiary);
  border-left: 4px solid var(--accent-secondary);
  padding: clamp(10px, 2vw, 15px);
  margin: clamp(10px, 2vw, 15px) 0;
  font-style: italic;
  font-size: clamp(13px, 2.5vw, 15px);
  border-radius: 0 var(--border-radius) var(--border-radius) 0;
}

/* Footer styling - Responsive */
div#footer {
  margin-top: clamp(30px, 5vw, 40px);
  padding: clamp(15px, 3vw, 20px) 0;
  text-align: center;
  color: var(--text-muted);
  border-top: 1px solid var(--border-color);
  font-size: clamp(12px, 2vw, 14px);
}

/* Hide or modernize ads */
[data-nosnippet], .gdprcontainer {
  display: none !important;
}

/* Special effects for links in masonry grid */
.thumb a::before {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background: linear-gradient(to bottom, rgba(0,0,0,0) 70%, rgba(0,0,0,0.8) 100%);
  opacity: 0;
  transition: opacity 0.3s ease;
  z-index: 1;
  border-radius: var(--thumbnail-border-radius);
}

/* Disable hover effects on touch devices */
@media (hover: hover) {
  .thumb a:hover::before {
    opacity: 1;
  }
}

img {
  border: none;
  vertical-align: middle;
  max-height: 90vh;
  width: auto;
}

/* ===== SIDEBAR STYLES ===== */
div.sidebar {
  background: var(--bg-secondary);
  border-radius: 12px;
  box-shadow: var(--box-shadow);
  padding: 0;
  margin-right: clamp(10px, 2vw, 20px);
  margin-bottom: clamp(15px, 3vw, 25px);
  max-width: 280px;
  min-width: 260px;
  border: 1px solid var(--border-color);
  overflow: hidden;
  transition: all 0.3s ease;
}

/* Hover effect for entire sidebar */
div.sidebar:hover {
  box-shadow: 0 8px 25px rgba(0, 0, 0, 0.4);
  border-color: rgba(156, 100, 166, 0.3);
}

/* Search section - Enhanced modern design */
div.tag-search {
  background: linear-gradient(135deg, var(--bg-tertiary) 0%, rgba(45, 45, 45, 0.8) 100%);
  padding: clamp(15px, 3vw, 20px);
  margin-bottom: 0;
  border-radius: 0;
  border-bottom: 1px solid var(--border-color);
  position: relative;
}

div.tag-search::before {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 2px;
  background: linear-gradient(90deg, var(--accent-color), var(--accent-secondary));
  opacity: 0.8;
}

div.tag-search h5 {
  color: var(--text-primary);
  font-family: var(--font-secondary);
  font-weight: 600;
  font-size: clamp(16px, 3vw, 18px);
  margin: 0 0 12px 0;
  display: flex;
  align-items: center;
  gap: 8px;
}

div.tag-search h5::before {
  content: "🔍";
  font-size: 16px;
  opacity: 0.8;
}

/* Enhanced search input */
div.tag-search input[type="text"] {
  width: 100%;
  padding: 12px 16px;
  background: var(--bg-color);
  border: 2px solid rgba(255, 255, 255, 0.1);
  border-radius: 8px;
  color: var(--text-primary);
  font-family: var(--font-primary);
  font-size: 14px;
  margin-bottom: 12px;
  transition: all 0.3s ease;
  box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.1);
}

div.tag-search input[type="text"]:focus {
  border-color: var(--accent-color);
  box-shadow:
    inset 0 2px 4px rgba(0, 0, 0, 0.1),
    0 0 0 3px rgba(156, 100, 166, 0.15);
  transform: translateY(-1px);
}

div.tag-search input[type="text"]::placeholder {
  color: var(--text-muted);
}

/* Modern search button */
div.tag-search input[type="submit"] {
  width: 100%;
  padding: 12px 20px;
  background: linear-gradient(135deg, var(--accent-color) 0%, var(--accent-secondary) 100%);
  color: white;
  border: none;
  border-radius: 8px;
  cursor: pointer;
  font-weight: 600;
  font-size: 14px;
  transition: all 0.3s ease;
  position: relative;
  overflow: hidden;
}

div.tag-search input[type="submit"]:hover {
  transform: translateY(-2px);
  box-shadow: 0 6px 20px rgba(156, 100, 166, 0.4);
}

div.tag-search input[type="submit"]:active {
  transform: translateY(0);
}

/* Ripple effect for search button */
div.tag-search input[type="submit"]::after {
  content: '';
  position: absolute;
  top: 50%;
  left: 50%;
  width: 0;
  height: 0;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.3);
  transition: width 0.3s, height 0.3s, top 0.3s, left 0.3s;
  transform: translate(-50%, -50%);
}

/* Search hint styling */
div.tag-search small {
  color: var(--text-muted);
  font-size: 12px;
  display: block;
  margin-top: 8px;
  font-style: italic;
}

/* Display options section */
ul#displayOptions {
  background: var(--bg-tertiary);
  margin: 0;
  padding: 15px 20px;
  list-style: none;
  border-bottom: 1px solid var(--border-color);
}

ul#displayOptions li {
  margin: 0;
  padding: 8px 0;
}

ul#displayOptions label {
  display: flex;
  align-items: center;
  justify-content: space-between;
  color: var(--text-secondary);
  font-size: 14px;
  font-weight: 500;
  cursor: pointer;
  transition: color 0.2s ease;
}

ul#displayOptions label:hover {
  color: var(--text-primary);
}

/* Modern toggle switch styling */
.switch {
  position: relative;
  display: inline-block;
  width: 48px;
  height: 24px;
  margin-left: 10px;
}

.switch input {
  opacity: 0;
  width: 0;
  height: 0;
}

.slider {
  position: absolute;
  cursor: pointer;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background: rgba(255, 255, 255, 0.1);
  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
  border-radius: 24px;
  border: 1px solid rgba(255, 255, 255, 0.1);
}

.slider:before {
  position: absolute;
  content: "";
  height: 18px;
  width: 18px;
  left: 3px;
  bottom: 2px;
  background: var(--text-muted);
  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
  border-radius: 50%;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
}

input:checked + .slider {
  background: linear-gradient(135deg, var(--accent-color), var(--accent-secondary));
  border-color: var(--accent-color);
}

input:checked + .slider:before {
  transform: translateX(24px);
  background: white;
  box-shadow: 0 3px 8px rgba(0, 0, 0, 0.3);
}

.slider:hover {
  box-shadow: 0 0 0 8px rgba(156, 100, 166, 0.1);
}

/* Tags section - Modern card design */
#tag-sidebar {
  margin: 0;
  padding: 0;
  list-style: none;
  max-height: 60vh;
  overflow-y: auto;
  scrollbar-width: thin;
  scrollbar-color: var(--accent-color) var(--bg-tertiary);
}

/* Custom scrollbar for tag section */
#tag-sidebar::-webkit-scrollbar {
  width: 6px;
}

#tag-sidebar::-webkit-scrollbar-track {
  background: var(--bg-tertiary);
}

#tag-sidebar::-webkit-scrollbar-thumb {
  background: var(--accent-color);
  border-radius: 3px;
}

#tag-sidebar::-webkit-scrollbar-thumb:hover {
  background: var(--accent-secondary);
}

/* Tag category headers with collapsible functionality */
#tag-sidebar h6 {
  background: linear-gradient(135deg, var(--bg-tertiary) 0%, rgba(45, 45, 45, 0.8) 100%);
  color: var(--text-primary);
  margin: 0;
  padding: 12px 20px;
  font-family: var(--font-secondary);
  font-weight: 600;
  font-size: 13px;
  text-transform: uppercase;
  letter-spacing: 1px;
  border-bottom: 1px solid var(--border-color);
  position: sticky;
  top: 0;
  z-index: 10;
  cursor: pointer;
  user-select: none;
  transition: all 0.3s ease;
  display: flex;
  align-items: center;
  justify-content: space-between;
}

#tag-sidebar h6:hover {
  background: linear-gradient(135deg, rgba(156, 100, 166, 0.2) 0%, rgba(174, 129, 255, 0.15) 100%);
  color: var(--accent-color);
}

/* Equilateral arrowhead indicator */
#tag-sidebar h6::after {
  content: '';
  width: 0;
  height: 0;
  border-left: 6px solid transparent;
  border-right: 6px solid transparent;
  border-top: 8px solid currentColor;
  transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);
  opacity: 0.7;
  margin-left: 8px;
}

/* Collapsed state arrow */
#tag-sidebar h6.collapsed::after {
  transform: rotate(-90deg);
}

/* Tag section container for collapsing */
.tag-section {
  overflow: hidden;
  transition: max-height 0.4s cubic-bezier(0.4, 0, 0.2, 1), opacity 0.3s ease;
  max-height: 1000px; /* Large enough for any tag list */
  opacity: 1;
}

.tag-section.collapsed {
  max-height: 0;
  opacity: 0;
}

/* Smooth animation for tag items when collapsing */
.tag-section.collapsing {
  transition: max-height 0.4s cubic-bezier(0.4, 0, 0.2, 1), opacity 0.3s ease;
}

/* Tag list items - Updated selector to work with all tag items */
#tag-sidebar li {
  padding: 0;
  margin: 0;
  border-bottom: 1px solid rgba(255, 255, 255, 0.05);
  transition: background 0.2s ease;
}

/* Only apply hover to non-header items */
#tag-sidebar li:not(:has(h6)):hover,
#tag-sidebar li.tag-type-general:hover,
#tag-sidebar li.tag-type-artist:hover,
#tag-sidebar li.tag-type-character:hover,
#tag-sidebar li.tag-type-copyright:hover,
#tag-sidebar li.tag-type-metadata:hover {
  background: rgba(255, 255, 255, 0.03);
}

#tag-sidebar li:last-child {
  border-bottom: none;
}

/* Ensure header items don't get tag item styling */
#tag-sidebar li:has(h6) {
  padding: 0;
  border-bottom: none;
  background: none;
}

/* Tag links and controls */
#tag-sidebar li a {
  display: inline-block;
  padding: 8px 12px;
  color: var(--text-secondary);
  text-decoration: none;
  font-size: 13px;
  transition: all 0.2s ease;
  border-radius: 4px;
}

#tag-sidebar li a:hover {
  color: var(--text-primary);
  background: rgba(255, 255, 255, 0.05);
}

/* Tag type specific colors with modern styling - Updated for all tag types */
.tag-type-general a, .tag-type-general {
  color: var(--text-secondary) !important;
}

.tag-type-artist a, .tag-type-artist {
  color: var(--tag-artist) !important;
}

.tag-type-character a, .tag-type-character {
  color: var(--tag-character) !important;
}

.tag-type-copyright a, .tag-type-copyright {
  color: var(--tag-copyright) !important;
}

.tag-type-metadata a, .tag-type-metadata {
  color: var(--tag-metadata) !important;
}

/* Tag control buttons (?, +, -) */
#tag-sidebar li a[href*="wiki"],
#tag-sidebar li a[onclick*="+"]:not([href*="tags="]),
#tag-sidebar li a[onclick*="-"]:not([href*="tags="]) {
  width: 26px;
  height: 26px;
  padding: 0;
  margin: 0 2px;
  text-align: center;
  line-height: 26px;
  font-size: 13px;
  font-weight: bold;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.1);
  color: var(--text-muted);
  transition: all 0.2s ease;
}

#tag-sidebar li a[href*="wiki"]:hover {
  background: var(--accent-color);
  color: white;
}

#tag-sidebar li a[onclick*="+"]:not([href*="tags="]):hover {
  background: var(--success-color);
  color: white;
}

#tag-sidebar li a[onclick*="-"]:not([href*="tags="]):hover {
  background: var(--error-color);
  color: white;
}

/* Tag count styling */
.tag-count {
  color: var(--text-muted);
  font-size: 11px;
  font-weight: 500;
  background: rgba(255, 255, 255, 0.05);
  padding: 2px 6px;
  border-radius: 10px;
  margin-left: auto;
  display: inline-block;
  min-width: 20px;
  text-align: center;
}

/* Tag item layout - flexbox for better control */
#tag-sidebar li.tag-type-general,
#tag-sidebar li.tag-type-artist,
#tag-sidebar li.tag-type-character,
#tag-sidebar li.tag-type-copyright,
#tag-sidebar li.tag-type-metadata {
  display: flex;
  align-items: center;
  padding: 6px 12px;
  gap: 4px;
  flex-wrap: wrap;
}

/* Ensure header items display normally */
#tag-sidebar li:has(h6) {
  display: block;
}

/* Main tag link takes remaining space */
#tag-sidebar li a[href*="tags="]:not([onclick]) {
  flex: 1;
  padding: 4px 8px;
  margin: 0;
  word-break: break-word;
}

/* Hidden blacklist section styling */
#blacklisted-sidebar {
  background: var(--bg-tertiary);
  padding: 15px 20px;
  border-bottom: 1px solid var(--border-color);
}

#blacklisted-sidebar h5 {
  margin: 0;
  color: var(--text-secondary);
  font-size: 14px;
  font-weight: 600;
}

#blacklisted-sidebar a {
  color: var(--warning-color);
  text-decoration: none;
}

#blacklisted-sidebar a:hover {
  color: var(--error-color);
}

/* Sidebar footer - cute mascot area */
div.sidebar img[src*="r34chibi"] {
  display: block;
  margin: 15px auto;
  opacity: 0.6;
  transition: opacity 0.3s ease;
  filter: brightness(1.2) contrast(1.1);
}

div.sidebar img[src*="r34chibi"]:hover {
  opacity: 1;
}

/* Responsive sidebar adjustments */
@media (max-width: 1199px) {
  div.sidebar {
    max-width: 240px;
    min-width: 220px;
  }
}

@media (max-width: 575px) {
  div.sidebar {
    border-radius: 8px;
    margin-bottom: 15px;
  }

  div.tag-search {
    padding: 12px 15px;
  }

  #tag-sidebar {
    max-height: 35vh;
  }

  #tag-sidebar li:not(:has(h6)) {
    padding: 8px 15px;
  }
}

/* Loading animation for tag section */
@keyframes tagLoad {
  0% { opacity: 0; transform: translateY(10px); }
  100% { opacity: 1; transform: translateY(0); }
}

#tag-sidebar li {
  animation: tagLoad 0.3s ease forwards;
}

/* Add stagger effect for tag items */
#tag-sidebar li:nth-child(even) {
  animation-delay: 0.05s;
}

#tag-sidebar li:nth-child(3n) {
  animation-delay: 0.1s;
}

/* Dark mode specific enhancements */
@media (prefers-color-scheme: dark) {
  div.sidebar {
    box-shadow: 0 4px 20px rgba(0, 0, 0, 0.6);
  }
}

/* High contrast mode support */
@media (prefers-contrast: high) {
  div.sidebar {
    border: 2px solid var(--accent-color);
  }

  .tag-count {
    background: var(--accent-color);
    color: var(--bg-color);
  }
}
  `;
  document.head.appendChild(style);

function setColumnCount(count) {
  document.documentElement.style.setProperty('--column-count', count);
}

function addColumnControlPanel() {
  // Avoid duplicate panel
  if (document.getElementById('columnSlider')) return;

  // Create the panel
  const controlPanel = document.createElement('div');
  controlPanel.innerHTML = `
    <div style="margin-bottom: 18px; background: #1a1a1a; padding: 10px; border-radius: 8px; border: 1px solid #2a2a2a; display: flex; align-items: center; gap: 10px;">
      <label style="color: #e0e0e0;">Columns:</label>
      <input type="range" id="columnSlider" min="1" max="8" value="4" style="width: 100px;">
      <span id="columnCount" style="color: #e0e0e0;">4</span>
    </div>
  `;

  // Insert above .image-list
  const imageList = document.querySelector('.image-list');
  if (imageList && imageList.parentNode) {
    imageList.parentNode.insertBefore(controlPanel, imageList);
  } else {
    // fallback: append to body if .image-list not found
    document.body.appendChild(controlPanel);
  }

  const slider = document.getElementById('columnSlider');
  const countDisplay = document.getElementById('columnCount');

  slider.addEventListener('input', function() {
    const count = this.value;
    countDisplay.textContent = count;
    setColumnCount(count);
    localStorage.setItem('galleryColumns', count);
  });

  // Load saved preference
  const savedColumns = localStorage.getItem('galleryColumns');
  if (savedColumns) {
    slider.value = savedColumns;
    countDisplay.textContent = savedColumns;
    setColumnCount(savedColumns);
  }
}

  const processedImages = new Set();
  const apiCache = new Map();

  function extractHashFromThumbnail(thumbnailUrl) {
    // Extract hash from: https://wimg.rule34.xxx/thumbnails/5046/thumbnail_fffef5df32fbff452a0be69302ca8e8b.jpg?5747620
    const match = thumbnailUrl.match(/thumbnail_([a-f0-9]+)/);
    return match ? match[1] : null;
  }

  function extractDirectoryFromThumbnail(thumbnailUrl) {
    // Extract directory from: https://wimg.rule34.xxx/thumbnails/5046/thumbnail_...
    const match = thumbnailUrl.match(/thumbnails\/(\d+)\//);
    return match ? match[1] : null;
  }

  function createJPGUrl(thumbnailUrl) {
    const hash = extractHashFromThumbnail(thumbnailUrl);
    const directory = extractDirectoryFromThumbnail(thumbnailUrl);

    if (!hash || !directory) return null;

    // Convert: thumbnails/5046/thumbnail_hash.jpg → samples/5046/sample_hash.jpg
    return `https://rule34.xxx/images/${directory}/${hash}.jpg`;
  }
  function createJPEGUrl(thumbnailUrl) {
    const hash = extractHashFromThumbnail(thumbnailUrl);
    const directory = extractDirectoryFromThumbnail(thumbnailUrl);

    if (!hash || !directory) return null;

    // Convert: thumbnails/5046/thumbnail_hash.jpg → samples/5046/sample_hash.jpg
    return `https://rule34.xxx/images/${directory}/${hash}.jpeg`;
  }
  function createPNGUrl(thumbnailUrl) {
    const hash = extractHashFromThumbnail(thumbnailUrl);
    const directory = extractDirectoryFromThumbnail(thumbnailUrl);

    if (!hash || !directory) return null;

    // Convert: thumbnails/5046/thumbnail_hash.jpg → samples/5046/sample_hash.jpg
    return `https://rule34.xxx/images/${directory}/${hash}.gif`;
  }

  function getCurrentPageTags() {
    // Extract tags from current URL: tags=rating%3Asafe+sort%3Ascore%3Adesc&pid=126
    const urlParams = new URLSearchParams(window.location.search);
    const tags = urlParams.get("tags") || "";

    // Clean up the tags - decode and keep only the filter tags, remove sort
    let cleanTags = decodeURIComponent(tags);
    // Remove sorting parameters but keep filter tags
    cleanTags = cleanTags.replace(/\s*sort:[^\s]+/g, "").trim();

    console.log(`Current page tags: "${cleanTags}"`);
    return cleanTags;
  }

  function extractIdFromThumbnail(thumbnailUrl) {
    // Extract ID from: https://wimg.rule34.xxx/thumbnails/5046/thumbnail_fffef5df32fbff452a0be69302ca8e8b.jpg?5747620
    const match = thumbnailUrl.match(/\?(\d+)$/);
    return match ? match[1] : null;
  }

  async function fallbackToAPI(thumbnailUrl, img) {
    const postId = extractIdFromThumbnail(thumbnailUrl);
    if (!postId) {
      console.log(`Could not extract post ID from ${thumbnailUrl}`);
      return;
    }

    // Check if we already have this specific post cached
    if (apiCache.has(postId)) {
      const cachedPost = apiCache.get(postId);
      replaceWithApiData(cachedPost, img);
      return;
    }

    // Make API call for this specific post ID
    const apiUrl = `https://api.rule34.xxx/index.php?page=dapi&s=post&q=index&json=1&limit=1000&id=${postId}`;

    console.log(`Making API call for post ${postId}: ${apiUrl}`);

    try {
      const response = await fetch(apiUrl);
      if (!response.ok) {
        console.log(`API request failed: ${response.status}`);
        return;
      }

      const data = await response.json();
      console.log(`API returned data for post ${postId}:`, data);

      // Handle response format - could be array or single object
      let post = null;
      if (Array.isArray(data) && data.length > 0) {
        post = data[0];
      } else if (data.id) {
        post = data;
      }

      if (post) {
        // Cache the post data
        apiCache.set(postId, post);

        // Replace the image
        replaceWithApiData(post, img);
      } else {
        console.log(`No post data found for ID ${postId}`);
      }
    } catch (error) {
      console.error(`API call failed for post ${postId}:`, error);
    }
  }

  function replaceWithApiData(post, img) {
    // Use sample_url if available, otherwise file_url
    let betterUrl;
    if (post.file_url.endsWith(".mp4") || post.file_url.endsWith(".webm")) {
      betterUrl = post.sample_url;
    } else {
      betterUrl = post.file_url;
    }

    if (betterUrl) {
      console.log(`Found API replacement for post ${post.id}: ${betterUrl}`);

      // Test the image before replacing
      const testImg = new Image();
      testImg.onload = function () {
        img.src = betterUrl;
        img.dataset.replacedViaApi = "true";
        img.dataset.replaced = "api";
        console.log(`✅ Successfully replaced post ${post.id} via API`);

        // Visual feedback - different color for API replacements
        img.style.transition = "box-shadow 0.3s ease";
        img.style.boxShadow = "0 0 8px #0099ff";
        setTimeout(() => {
          img.style.boxShadow = "";
        }, 800);
      };
      testImg.onerror = function () {
        console.log(
          `❌ API replacement failed to load for post ${post.id}: ${betterUrl}`
        );
      };
      testImg.src = betterUrl;
    } else {
      console.log(`No suitable URL found for post ${post.id} in API response`);
    }
  }

  async function replaceThumbnailWithSample(img) {
    const originalSrc = img.src;

    // Skip if already processed
    if (processedImages.has(originalSrc) || img.dataset.replaced) {
      return;
    }

    // Only process thumbnail images
    if (!originalSrc.includes("/thumbnails/")) {
      return;
    }

    processedImages.add(originalSrc);
    img.dataset.processing = "true";

    console.log(`Processing thumbnail: ${originalSrc}`);

    // Try all sample URL creators in order
    const urlCreators = [createJPGUrl, createJPEGUrl, createPNGUrl];

    let replaced = false;
    for (const createUrl of urlCreators) {
      const sampleUrl = createUrl(originalSrc);
      if (!sampleUrl) continue;

      console.log(`Trying sample URL: ${sampleUrl}`);

      // eslint-disable-next-line no-await-in-loop
      const success = await testImageUrl(sampleUrl);
      if (success) {
        img.src = sampleUrl;
        img.dataset.replaced = "sample";
        img.dataset.processing = "false";
        console.log(`✅ Successfully replaced with sample: ${sampleUrl}`);

        // Visual feedback
        img.style.transition = "box-shadow 0.3s ease";
        img.style.boxShadow = "0 0 8px #00ff00";
        setTimeout(() => {
          img.style.boxShadow = "";
        }, 800);

        replaced = true;
        break;
      }
    }

    if (!replaced) {
      fallbackToAPI(originalSrc, img);
    }
  }

  // Helper to test if an image URL loads
  function testImageUrl(url) {
    return new Promise((resolve) => {
      const testImg = new Image();
      testImg.onload = () => resolve(true);
      testImg.onerror = () => resolve(false);
      testImg.src = url;
    });
  }

  function processAllThumbnails() {
    const thumbnails = Array.from(
      document.querySelectorAll('img[src*="/thumbnails/"]')
    );
    console.log(`Found ${thumbnails.length} thumbnail images to process`);

    thumbnails.forEach((img, index) => {
      // Add small delay to avoid overwhelming the browser
      setTimeout(() => {
        replaceThumbnailWithSample(img);
      }, index * 50);
    });
  }

  function processVisibleThumbnails() {
    const thumbnails = Array.from(
      document.querySelectorAll('img[src*="/thumbnails/"]')
    ).filter((img) => {
      if (img.dataset.replaced || img.dataset.processing) return false;

      const rect = img.getBoundingClientRect();
      const windowHeight = window.innerHeight;
      return rect.top < windowHeight + 300 && rect.bottom > -300;
    });

    if (thumbnails.length > 0) {
      console.log(`Processing ${thumbnails.length} visible thumbnails`);
      thumbnails.forEach(replaceThumbnailWithSample);
    }
  }

  // Debug functions
  function showStats() {
    const total = document.querySelectorAll('img[src*="/thumbnails/"]').length;
    const sampleReplaced = document.querySelectorAll(
      'img[data-replaced="sample"]'
    ).length;
    const apiReplaced = document.querySelectorAll(
      'img[data-replaced="api"]'
    ).length;
    const processing = document.querySelectorAll(
      'img[data-processing="true"]'
    ).length;

    console.log(
      `Stats: ${sampleReplaced} sample, ${apiReplaced} API, ${processing} processing, ${total} total`
    );
    console.log(`API cache: ${apiCache.size} entries`);

    return {
      total,
      sampleReplaced,
      apiReplaced,
      processing,
      cached: apiCache.size,
    };
  }

  function clearCacheAndReprocess() {
    processedImages.clear();
    apiCache.clear();

    // Reset all images
    document
      .querySelectorAll("img[data-replaced], img[data-processing]")
      .forEach((img) => {
        delete img.dataset.replaced;
        delete img.dataset.processing;
        delete img.dataset.replacedViaApi;
      });

    console.log("Cache cleared, reprocessing...");
    setTimeout(processAllThumbnails, 100);
  }

  // Make functions globally available
  window.processAllThumbnails = processAllThumbnails;
  window.showStats = showStats;
  window.clearCacheAndReprocess = clearCacheAndReprocess;

  // Initialize
  function initialize() {
    console.log("Rule34 Simple Reskin initialized");

    // Process images after page loads
    setTimeout(processAllThumbnails, 500);
	document.head.appendChild(style);
	addColumnControlPanel();
  }

  // Start when ready
  if (document.readyState === "loading") {
    document.addEventListener("DOMContentLoaded", initialize);
  } else {
    initialize();
  }

  // Process visible images on scroll
  let scrollTimeout;
  window.addEventListener("scroll", () => {
    clearTimeout(scrollTimeout);
    scrollTimeout = setTimeout(processVisibleThumbnails, 200);
  });

  // Process new images when they're dynamically added
  const observer = new MutationObserver((mutations) => {
    let hasNewThumbnails = false;
    mutations.forEach((mutation) => {
      mutation.addedNodes.forEach((node) => {
        if (node.nodeType === Node.ELEMENT_NODE) {
          if (node.tagName === "IMG" && node.src.includes("/thumbnails/")) {
            hasNewThumbnails = true;
          } else if (
            node.querySelector &&
            node.querySelector('img[src*="/thumbnails/"]')
          ) {
            hasNewThumbnails = true;
          }
        }
      });
    });

    if (hasNewThumbnails) {
      setTimeout(processVisibleThumbnails, 200);
    }
  });

// ===== COLLAPSIBLE SIDEBAR FUNCTIONALITY =====

function initializeCollapsibleSidebar() {
  const tagSidebar = document.getElementById('tag-sidebar');
  if (!tagSidebar) return;

  // Get saved collapsed states from localStorage
  const savedStates = JSON.parse(localStorage.getItem('sidebarCollapsedStates') || '{}');

  // Find all h6 headers and wrap subsequent tag items
  const headers = tagSidebar.querySelectorAll('h6');

  headers.forEach((header, index) => {
    const categoryName = header.textContent.toLowerCase().trim();

    // Create wrapper for tag items in this category
    const tagSection = document.createElement('div');
    tagSection.className = 'tag-section';
    tagSection.dataset.category = categoryName;

    // Find all tag items until the next h6 or end of list
    let currentElement = header.parentElement.nextElementSibling;
    const tagItems = [];

    while (currentElement && !currentElement.querySelector('h6')) {
      tagItems.push(currentElement);
      currentElement = currentElement.nextElementSibling;
    }

    // Move tag items into the wrapper
    tagItems.forEach(item => {
      tagSection.appendChild(item);
    });

    // Insert wrapper after header
    header.parentElement.parentNode.insertBefore(tagSection, header.parentElement.nextElementSibling);

    // Apply saved collapsed state
    if (savedStates[categoryName]) {
      header.classList.add('collapsed');
      tagSection.classList.add('collapsed');
    }

    // Add click handler
    header.addEventListener('click', function(e) {
      e.preventDefault();
      e.stopPropagation();
      toggleSection(header, tagSection, categoryName);
    });

    // Add keyboard support
    header.addEventListener('keydown', function(e) {
      if (e.key === 'Enter' || e.key === ' ') {
        e.preventDefault();
        toggleSection(header, tagSection, categoryName);
      }
    });

    // Make headers focusable
    header.setAttribute('tabindex', '0');
    header.setAttribute('role', 'button');
    header.setAttribute('aria-expanded', !savedStates[categoryName]);
    header.setAttribute('aria-controls', `tag-section-${categoryName}`);

    tagSection.setAttribute('id', `tag-section-${categoryName}`);
  });
}

function toggleSection(header, section, categoryName) {
  const isCollapsed = header.classList.contains('collapsed');

  // Update visual state
  header.classList.toggle('collapsed');
  header.setAttribute('aria-expanded', isCollapsed);

  if (isCollapsed) {
    // Expanding
    section.classList.remove('collapsed');
    section.style.maxHeight = section.scrollHeight + 'px';

    // Reset max-height after animation
    setTimeout(() => {
      if (!section.classList.contains('collapsed')) {
        section.style.maxHeight = '1000px';
      }
    }, 400);
  } else {
    // Collapsing
    section.style.maxHeight = section.scrollHeight + 'px';
    section.classList.add('collapsing');

    // Force reflow
    section.offsetHeight;

    section.style.maxHeight = '0px';

    setTimeout(() => {
      section.classList.add('collapsed');
      section.classList.remove('collapsing');
    }, 400);
  }

  // Save state to localStorage
  saveCollapsedStates();
}

function saveCollapsedStates() {
  const states = {};
  const headers = document.querySelectorAll('#tag-sidebar h6');

  headers.forEach(header => {
    const categoryName = header.textContent.toLowerCase().trim();
    states[categoryName] = header.classList.contains('collapsed');
  });

  localStorage.setItem('sidebarCollapsedStates', JSON.stringify(states));
}

// Utility functions for manual control
function expandAllSections() {
  const headers = document.querySelectorAll('#tag-sidebar h6.collapsed');
  headers.forEach(header => {
    const categoryName = header.textContent.toLowerCase().trim();
    const section = document.getElementById(`tag-section-${categoryName}`);
    if (section) {
      toggleSection(header, section, categoryName);
    }
  });
}

function collapseAllSections() {
  const headers = document.querySelectorAll('#tag-sidebar h6:not(.collapsed)');
  headers.forEach(header => {
    const categoryName = header.textContent.toLowerCase().trim();
    const section = document.getElementById(`tag-section-${categoryName}`);
    if (section) {
      toggleSection(header, section, categoryName);
    }
  });
}

// Reset all collapsed states
function resetSidebarStates() {
  localStorage.removeItem('sidebarCollapsedStates');
  location.reload();
}

// Make functions globally available for debugging
window.expandAllSections = expandAllSections;
window.collapseAllSections = collapseAllSections;
window.resetSidebarStates = resetSidebarStates;

// Initialize when DOM is ready
function initSidebarWhenReady() {
  if (document.getElementById('tag-sidebar')) {
    setTimeout(initializeCollapsibleSidebar, 100);
  } else {
    // Retry after a short delay if sidebar isn't ready yet
    setTimeout(initSidebarWhenReady, 500);
  }
}

// Call initialization
initSidebarWhenReady();

// Re-initialize if new content is loaded dynamically
const sidebarObserver = new MutationObserver((mutations) => {
  mutations.forEach((mutation) => {
    if (mutation.addedNodes.length > 0) {
      const addedSidebar = Array.from(mutation.addedNodes).find(node =>
        node.id === 'tag-sidebar' || (node.querySelector && node.querySelector('#tag-sidebar'))
      );
      if (addedSidebar) {
        setTimeout(initializeCollapsibleSidebar, 100);
      }
    }
  });
});

if (document.body) {
  sidebarObserver.observe(document.body, {
    childList: true,
    subtree: true
  });
}
})();