OldRedditPlus

Old RedditのUIカスタマイズ、画面左側に登録サブレ一覧のサイドバーを追加します

You will need to install an extension such as Tampermonkey, Greasemonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Userscripts to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install a user script manager extension to install this script.

(I already have a user script manager, let me install it!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(I already have a user style manager, let me install it!)

// ==UserScript==
// @version      1.1.1
// @name         OldRedditPlus
// @name:en      OldRedditPlus
// @namespace    https://codeberg.org/Merlinsencho/oldredditplus
// @description  Old RedditのUIカスタマイズ、画面左側に登録サブレ一覧のサイドバーを追加します
// @description:en Old Reddit customization with overlay sidebar on the left of the screen and dark mode
// @author       Merlinsencho
// @match        https://www.reddit.com/*
// @match        https://reddit.com/*
// @match        https://old.reddit.com/*
// @grant        GM_addStyle
// @run-at       document-end
// @noframes
// @copyright    2025, Merlinsencho
// @license      MIT
// ==/UserScript==

(function() {
    'use strict';
    
    // CSS注入
    GM_addStyle(`
/* ===================================
   New Old Reddit Style - Overlay MVP
   =================================== */

:root {
    --bg-primary: #1a1a1b;
    --bg-secondary: #272729;
    --text-primary: #d7dadc;
    --text-secondary: #818384;
    --border-color: #343536;
    --link-color: #4fbcff;
    --hover-bg: #272729;
}

/* bodyへの干渉を最小化 - ダークモード時のみ背景色/文字色を適用 */
body.dark-mode {
    background: var(--bg-secondary) !important;
    color: var(--text-primary) !important;
}

/* #headerへの干渉を削除 - サブレディット独自レイアウトを尊重 */

/* LEFTサイドバー - オーバーレイ */
#sr-header-area {
    position: fixed !important;
    left: -260px;
    top: 60px;  /* フォールバック値:JavaScriptで動的に更新 */
    width: 250px;
    height: calc(100vh - 60px);  /* フォールバック値:JavaScriptで動的に更新 */
    overflow-y: scroll !important;
    background: var(--bg-primary, #1a1a1b);
    border-right: 1px solid var(--border-color, #343536);
    z-index: 999;
    padding-top: 0;
    display: flex !important;
    flex-direction: column !important;
    transition: left 0.3s ease-in-out;
    box-shadow: 2px 0 8px rgba(0, 0, 0, 0.3);
}

body.show-left #sr-header-area {
    left: 0;
}

body.show-left::before {
    content: '';
    position: fixed;
    top: 0;
    left: 250px;  /* SUBSの幅分だけ右にずらして、SUBSエリアには背景を適用しない */
    right: 0;
    bottom: 0;
    background: rgba(0, 0, 0, 0.5);
    z-index: 998;
    animation: fadeIn 0.3s ease-in-out;
    pointer-events: none;  /* 背景オーバーレイはクリック不可に(視覚効果のみ) */
}

/* 設定パネル表示時は半透明背景を無効化 */
#orp-settings-overlay.show ~ body.show-left::before,
body.show-left.settings-open::before {
    display: none;
}

@keyframes fadeIn {
    from { opacity: 0; }
    to { opacity: 1; }
}

/* #header-bottom-left/right削除 - サブレディット依存要素への干渉回避 */

#sr-header-area .width-clip {
    width: 100%;
    height: 100%;
    display: flex;
    flex-direction: column;
}

#sr-header-area .sr-list {
    background: var(--bg-primary, #1a1a1b);
    padding: 0;
    margin: 0;
    height: 100%;
    display: flex;
    flex-direction: column;
    flex: 1;
    overflow-y: auto;
}

#sr-header-area .sr-bar {
    display: flex !important;
    flex-direction: column !important;
    padding: 0;
    list-style: none;
    margin: 0;
    order: 1;
    flex: 1;
}

#sr-header-area .sr-bar li {
    display: block;
    margin: 0;
    padding: 0;
}

#sr-header-area .sr-bar a {
    display: block !important;
    padding: 10px 15px !important;
    color: var(--text-primary, #d7dadc) !important;
    text-decoration: none !important;
    transition: background 0.2s;
    border-bottom: 1px solid var(--border-color, #343536);
    font-size: 14px;
}

#sr-header-area .sr-bar a:hover {
    background: var(--hover-bg, #272729) !important;
}

#sr-header-area .separator,
#sr-header-area .dropdown,
#sr-header-area .srdrop {
    display: none !important;
}

#sr-header-area #sr-more-link {
    display: block;
    padding: 10px 15px;
    color: var(--link-color, #4fbcff);
    text-decoration: none;
    font-size: 12px;
    text-align: center;
    border-top: 1px solid var(--border-color, #343536);
    order: 3;
    margin-top: auto;
}

/* スペーサー(区切り線) */
#sr-header-area .orp-separator {
    height: 1px;
    background: var(--border-color, #343536);
    margin: 8px 0;
    pointer-events: none;
}

/* .contentへの干渉を削除 - サブレディット独自レイアウトを尊重 */

/* .thingをダークモード限定に - サブレディット独自デザインを尊重 */
body.dark-mode .thing {
    background: var(--bg-primary, #1a1a1b);
    border: 1px solid var(--border-color, #343536);
    border-radius: 4px;
    margin-bottom: 10px;
}

body.dark-mode .thing .title a {
    color: var(--text-primary, #d7dadc) !important;
}

body.dark-mode .thing .title a:visited {
    color: var(--text-secondary, #818384) !important;
}

/* ===================================
   コメントページ(アーティクル)用ダークモード
   =================================== */

/* コメントエリア全般 */
body.dark-mode .commentarea {
    background: var(--bg-primary) !important;
    color: var(--text-primary) !important;
}

/* コメント本体 */
body.dark-mode .comment {
    background: transparent !important;
    border-left: 1px solid var(--border-color) !important;
}

body.dark-mode .comment .entry {
    color: var(--text-primary) !important;
}

/* タグライン(投稿者情報) */
body.dark-mode .tagline,
body.dark-mode .comment .tagline {
    color: var(--text-secondary) !important;
}

body.dark-mode .tagline .author,
body.dark-mode .comment .tagline .author {
    color: var(--link-color) !important;
}

/* コメント本文のテキスト */
body.dark-mode .usertext-body,
body.dark-mode .usertext-body .md,
body.dark-mode .comment .usertext-body,
body.dark-mode .comment .md {
    background: transparent !important;
    color: var(--text-primary) !important;
}

body.dark-mode .usertext-body .md p,
body.dark-mode .comment .md p {
    color: var(--text-primary) !important;
}

/* コメント内のリンク */
body.dark-mode .usertext-body a,
body.dark-mode .comment .md a {
    color: var(--link-color) !important;
}

body.dark-mode .usertext-body a:visited,
body.dark-mode .comment .md a:visited {
    color: var(--text-secondary) !important;
}

body.dark-mode .usertext-body a:hover,
body.dark-mode .comment .md a:hover {
    color: var(--text-primary) !important;
}

/* コメント投稿フォーム */
body.dark-mode .usertext-edit {
    background: var(--bg-secondary) !important;
    border-color: var(--border-color) !important;
}

body.dark-mode .usertext-edit textarea {
    background: var(--bg-primary) !important;
    color: var(--text-primary) !important;
    border-color: var(--border-color) !important;
}

body.dark-mode .usertext-edit textarea:focus {
    background: var(--bg-secondary) !important;
    border-color: var(--link-color) !important;
}

/* フォーム下部エリア */
body.dark-mode .usertext-edit .bottom-area {
    background: var(--bg-secondary) !important;
    border-top-color: var(--border-color) !important;
}

body.dark-mode .usertext-edit .bottom-area a,
body.dark-mode .help-toggle a {
    color: var(--link-color) !important;
}

/* ボタン */
body.dark-mode .usertext-buttons button {
    background: var(--link-color) !important;
    color: #ffffff !important;
    border: none !important;
}

body.dark-mode .usertext-buttons button:hover {
    background: #3a9dd9 !important;
}

body.dark-mode .usertext-buttons .cancel {
    background: var(--bg-secondary) !important;
    color: var(--text-primary) !important;
    border: 1px solid var(--border-color) !important;
}

body.dark-mode .usertext-buttons .cancel:hover {
    background: var(--hover-bg) !important;
}

/* フラットリストのボタン */
body.dark-mode .flat-list.buttons li a {
    color: var(--text-secondary) !important;
}

body.dark-mode .flat-list.buttons li a:hover {
    color: var(--link-color) !important;
}

/* エクスパンド領域 */
body.dark-mode .expando {
    background: transparent !important;
}

/* メニューエリア */
body.dark-mode .menuarea {
    background: var(--bg-secondary) !important;
    color: var(--text-primary) !important;
}

/* ドロップダウン */
body.dark-mode .dropdown {
    background: var(--bg-secondary) !important;
    color: var(--text-primary) !important;
    border-color: var(--border-color) !important;
}

body.dark-mode .drop-choices {
    background: var(--bg-secondary) !important;
    border-color: var(--border-color) !important;
}

body.dark-mode .drop-choices a {
    color: var(--text-primary) !important;
    background: var(--bg-secondary) !important;
}

body.dark-mode .drop-choices a:hover {
    background: var(--hover-bg) !important;
}

/* マークダウンヘルプ */
body.dark-mode .markhelp {
    background: var(--bg-secondary) !important;
    border-color: var(--border-color) !important;
}

body.dark-mode .markhelp td {
    color: var(--text-primary) !important;
    border-color: var(--border-color) !important;
}

/* パネルスタックタイトル */
body.dark-mode .panestack-title {
    background: var(--bg-secondary) !important;
    color: var(--text-primary) !important;
}

body.dark-mode .panestack-title .title {
    color: var(--text-primary) !important;
}

/* siteTable */
body.dark-mode .sitetable {
    background: transparent !important;
}

/* エントリー */
body.dark-mode .entry {
    color: var(--text-primary) !important;
}

body.dark-mode .entry .title {
    color: var(--text-primary) !important;
}

/* ドメイン */
body.dark-mode .domain a {
    color: var(--text-secondary) !important;
}

/* スコア */
body.dark-mode .score {
    color: var(--text-primary) !important;
}

/* エラーメッセージ */
body.dark-mode .error {
    color: #ff6b6b !important;
}

/* ステータスメッセージ */
body.dark-mode .status {
    color: var(--text-primary) !important;
}

/* ===================================
   RIGHT側サイドバー用ダークモード(オプション)
   最小限の適用でサブレディット共通で使える安全策
   =================================== */

/* RIGHTサイドバー - 背景と基本テキスト色のみ(最小限) */
body.dark-mode.dark-mode-right .side {
    background: var(--bg-primary) !important;
    color: var(--text-primary) !important;
}

/* サイドバーの基本リンク色 */
body.dark-mode.dark-mode-right .side a {
    color: var(--link-color) !important;
}

/* 検索ボックス - 最小限の調整 */
body.dark-mode.dark-mode-right .side .search input[type="text"] {
    background: var(--bg-primary) !important;
    color: var(--text-primary) !important;
    border-color: var(--border-color) !important;
}

body.dark-mode.dark-mode-right .side .search input[type="text"]:focus {
    border-color: var(--link-color) !important;
}

/* ===================================
   RIGHT側フルダークモード(警告:問題が起こりやすい)
   =================================== */

/* サイドボックス(各ウィジェット) */
body.dark-mode.dark-mode-right.dark-mode-right-full .side .spacer {
    background: var(--bg-secondary) !important;
    border: 1px solid var(--border-color) !important;
}

body.dark-mode.dark-mode-right.dark-mode-right-full .side .spacer .titlebox {
    background: var(--bg-secondary) !important;
}

/* サイドバーのタイトル */
body.dark-mode.dark-mode-right.dark-mode-right-full .side h1,
body.dark-mode.dark-mode-right.dark-mode-right-full .side h2,
body.dark-mode.dark-mode-right.dark-mode-right-full .side h3,
body.dark-mode.dark-mode-right.dark-mode-right-full .side h4,
body.dark-mode.dark-mode-right.dark-mode-right-full .side h5,
body.dark-mode.dark-mode-right.dark-mode-right-full .side h6 {
    color: var(--text-primary) !important;
}

/* サイドバーのテキスト */
body.dark-mode.dark-mode-right.dark-mode-right-full .side .usertext-body,
body.dark-mode.dark-mode-right.dark-mode-right-full .side .md {
    color: var(--text-primary) !important;
}

/* リンクホバー */
body.dark-mode.dark-mode-right.dark-mode-right-full .side a:hover {
    color: var(--text-primary) !important;
}

/* スポンサードリンク */
body.dark-mode.dark-mode-right.dark-mode-right-full .side .sidecontentbox {
    background: var(--bg-secondary) !important;
    border-color: var(--border-color) !important;
}

body.dark-mode.dark-mode-right.dark-mode-right-full .side .sidecontentbox .title h1 {
    background: var(--bg-secondary) !important;
    color: var(--text-primary) !important;
}

body.dark-mode.dark-mode-right.dark-mode-right-full .side .sidecontentbox .content {
    background: var(--bg-primary) !important;
}

/* 検索ボックス(フル版) */
body.dark-mode.dark-mode-right.dark-mode-right-full .side .search input[type="text"]:focus {
    background: var(--bg-secondary) !important;
}

/* ログインフォーム */
body.dark-mode.dark-mode-right.dark-mode-right-full .side .login-form-side {
    background: var(--bg-secondary) !important;
    border-color: var(--border-color) !important;
}

body.dark-mode.dark-mode-right.dark-mode-right-full .side .login-form-side input[type="text"],
body.dark-mode.dark-mode-right.dark-mode-right-full .side .login-form-side input[type="password"] {
    background: var(--bg-primary) !important;
    color: var(--text-primary) !important;
    border-color: var(--border-color) !important;
}

/* モデレーターリスト */
body.dark-mode.dark-mode-right.dark-mode-right-full .side .sidecontentbox .morelink {
    background: var(--link-color) !important;
    border-color: var(--link-color) !important;
}

body.dark-mode.dark-mode-right.dark-mode-right-full .side .sidecontentbox .morelink:hover {
    background: #3a9dd9 !important;
}

body.dark-mode.dark-mode-right.dark-mode-right-full .side .sidecontentbox .morelink a {
    color: #ffffff !important;
}

/* 購読ボタン */
body.dark-mode.dark-mode-right.dark-mode-right-full .side .fancy-toggle-button {
    background: var(--bg-secondary) !important;
    border-color: var(--border-color) !important;
}

body.dark-mode.dark-mode-right.dark-mode-right-full .side .fancy-toggle-button .active {
    background: var(--link-color) !important;
}

/* サイドバーの投稿作成ボタン */
body.dark-mode.dark-mode-right.dark-mode-right-full .side .sidebox.submit {
    background: var(--bg-secondary) !important;
}

body.dark-mode.dark-mode-right.dark-mode-right-full .side .morelink {
    background: var(--link-color) !important;
    border: none !important;
}

body.dark-mode.dark-mode-right.dark-mode-right-full .side .morelink:hover {
    background: #3a9dd9 !important;
}

body.dark-mode.dark-mode-right.dark-mode-right-full .side .morelink a {
    color: #ffffff !important;
}

/* フレアセレクター */
body.dark-mode.dark-mode-right.dark-mode-right-full .side .flairselector {
    background: var(--bg-primary) !important;
    border-color: var(--border-color) !important;
}

body.dark-mode.dark-mode-right.dark-mode-right-full .side .flairselector li {
    background: var(--bg-secondary) !important;
    border-color: var(--border-color) !important;
}

body.dark-mode.dark-mode-right.dark-mode-right-full .side .flairselector li:hover {
    background: var(--hover-bg) !important;
}

/* モデレーター情報 */
body.dark-mode.dark-mode-right.dark-mode-right-full .side .icon-menu a {
    background: var(--bg-secondary) !important;
    color: var(--text-primary) !important;
}

body.dark-mode.dark-mode-right.dark-mode-right-full .side .icon-menu a:hover {
    background: var(--hover-bg) !important;
}

/* ===================================
   投稿フォーム用ダークモードスタイル
   =================================== */

/* 投稿ページ全体 */
body.dark-mode.submit-page {
    background: var(--bg-primary) !important;
}

/* 投稿フォームのコンテナ */
body.dark-mode .content[role="main"] {
    background: var(--bg-primary);
}

/* roundfield(入力フィールドのコンテナ) */
body.dark-mode .roundfield {
    background: var(--bg-secondary);
    border-color: var(--border-color);
}

body.dark-mode .roundfield-content {
    background: var(--bg-secondary);
}

/* spacer要素 */
body.dark-mode .spacer {
    background: transparent;
}

/* タイトルラベル */
body.dark-mode .roundfield .title {
    color: var(--text-primary);
}

/* 必須フィールドマーク */
body.dark-mode .required-roundfield {
    color: var(--text-primary);
}

/* 小さい説明文 */
body.dark-mode .little,
body.dark-mode .roundfield-description {
    color: var(--text-secondary);
}

/* テキストエリア・インプット */
body.dark-mode textarea,
body.dark-mode input[type="text"],
body.dark-mode input[type="url"] {
    background: var(--bg-primary) !important;
    color: var(--text-primary) !important;
    border-color: var(--border-color) !important;
}

body.dark-mode textarea:focus,
body.dark-mode input[type="text"]:focus,
body.dark-mode input[type="url"]:focus {
    background: var(--bg-secondary) !important;
    border-color: var(--link-color) !important;
}

/* ユーザーテキスト編集エリア */
body.dark-mode .usertext-edit {
    background: var(--bg-secondary);
    border-color: var(--border-color);
}

body.dark-mode .usertext-edit .md {
    background: var(--bg-primary);
}

/* マークダウンヘルプエリア */
body.dark-mode .usertext-edit .bottom-area {
    background: var(--bg-secondary);
    border-top-color: var(--border-color);
}

/* ヘルプトグル */
body.dark-mode .help-toggle a,
body.dark-mode .bottom-area a {
    color: var(--link-color);
}

body.dark-mode .help-toggle a:hover,
body.dark-mode .bottom-area a:hover {
    color: var(--text-primary);
}

/* マークダウンヘルプテーブル */
body.dark-mode .markhelp {
    background: var(--bg-secondary);
    border-color: var(--border-color);
}

body.dark-mode .markhelp td {
    color: var(--text-primary);
    border-color: var(--border-color);
}

/* 情報バー */
body.dark-mode .infobar {
    background: var(--bg-secondary);
    color: var(--text-primary);
    border-color: var(--border-color);
}

/* フォームタブ */
body.dark-mode .tabmenu.formtab {
    background: var(--bg-secondary);
}

body.dark-mode .tabmenu.formtab li a {
    background: var(--bg-secondary);
    color: var(--text-secondary);
    border-color: var(--border-color);
}

body.dark-mode .tabmenu.formtab li.selected a,
body.dark-mode .tabmenu.formtab li a:hover {
    background: var(--bg-primary);
    color: var(--text-primary);
}

/* フォームタブコンテンツ */
body.dark-mode .formtabs-content {
    background: var(--bg-primary);
}

/* ボタン類 */
body.dark-mode button,
body.dark-mode .c-btn {
    background: var(--bg-secondary);
    color: var(--text-primary);
    border-color: var(--border-color);
}

body.dark-mode button:hover,
body.dark-mode .c-btn:hover {
    background: var(--hover-bg);
}

body.dark-mode .c-btn-primary {
    background: var(--link-color);
    color: #ffffff;
}

body.dark-mode .c-btn-primary:hover {
    background: #3a9dd9;
}

/* サブレディット提案リスト */
body.dark-mode .sr-suggestion {
    color: var(--link-color);
}

body.dark-mode .sr-suggestion:hover {
    background: var(--hover-bg);
    color: var(--text-primary);
}

/* フレアプレビュー */
body.dark-mode .flair-preview {
    background: var(--bg-secondary);
    color: var(--text-primary);
    border-color: var(--border-color);
}

/* コレクションプロモ */
body.dark-mode .roundfield--with-padding {
    background: var(--bg-secondary);
}

body.dark-mode .roundfield--with-padding .usertext {
    color: var(--text-primary);
}

/* 送信テキスト */
body.dark-mode .submit_text h1 {
    color: var(--text-primary);
}

body.dark-mode .submit_text .content {
    color: var(--text-primary);
}

/* 左サイドバートグル - 左側の縦バー */
#orp-left-sidebar-toggle {
    position: fixed !important;
    left: 0 !important;
    top: 50% !important;
    transform: translateY(-50%) !important;
    z-index: 1001 !important;
    background: var(--bg-secondary, #272729) !important;
    border: 1px solid var(--border-color, #343536) !important;
    border-left: none !important;
    border-radius: 0 8px 8px 0 !important;
    padding: 15px 6px !important;
    cursor: pointer !important;
    font-size: 20px !important;
    color: var(--text-primary, #d7dadc) !important;
    transition: all 0.2s !important;
    writing-mode: vertical-rl !important;
    text-orientation: mixed !important;
    box-shadow: 2px 0 8px rgba(0, 0, 0, 0.3) !important;
    width: auto !important;
    max-width: 50px !important;
    height: auto !important;
    min-width: unset !important;
    min-height: unset !important;
    box-sizing: border-box !important;
}

#orp-left-sidebar-toggle:hover {
    background: var(--hover-bg, #343536) !important;
    padding-left: 10px !important;
}

/* 設定ボタン - 左サイドバー下部 */
#orp-settings-button {
    display: block;
    padding: 15px 15px;
    background: var(--link-color, #4fbcff);
    color: #ffffff;
    text-decoration: none;
    font-size: 14px;
    font-weight: bold;
    text-align: center;
    border-top: 2px solid var(--border-color, #343536);
    cursor: pointer;
    transition: background 0.2s;
    order: 4;
    margin-top: 0;
}

#orp-settings-button:hover {
    background: #3a9dd9;
}

/* 設定画面オーバーレイ */
#orp-settings-overlay {
    display: none;
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    background: transparent;
    z-index: 10000;
    overflow-y: auto;
}

#orp-settings-overlay.show {
    display: flex;
    align-items: center;
    justify-content: center;
}

#orp-settings-panel {
    background: var(--bg-primary, #1a1a1b);
    border: 2px solid var(--border-color, #343536);
    border-radius: 8px;
    max-width: 600px;
    width: 90%;
    max-height: 80vh;
    overflow-y: auto;
    box-shadow: 0 4px 20px rgba(0, 0, 0, 0.5);
}

#orp-settings-header {
    background: var(--bg-secondary, #272729);
    padding: 20px;
    border-bottom: 2px solid var(--border-color, #343536);
    display: flex;
    justify-content: space-between;
    align-items: center;
}

#orp-settings-header h2 {
    margin: 0;
    color: var(--text-primary, #d7dadc);
    font-size: 20px;
}

#orp-settings-close {
    background: transparent;
    border: none;
    color: var(--text-primary, #d7dadc);
    font-size: 24px;
    cursor: pointer;
    padding: 0;
    width: 30px;
    height: 30px;
    line-height: 30px;
    text-align: center;
}

#orp-settings-close:hover {
    color: var(--link-color, #4fbcff);
}

#orp-settings-content {
    padding: 20px;
}

/* タブUI */
.orp-tabs {
    display: flex;
    border-bottom: 2px solid var(--border-color, #343536);
    background: var(--bg-secondary, #272729);
    margin: 0;
    padding: 0;
}

.orp-tab {
    flex: 1;
    padding: 15px 20px;
    background: transparent;
    border: none;
    color: var(--text-secondary, #818384);
    font-size: 14px;
    font-weight: bold;
    cursor: pointer;
    transition: all 0.2s;
    border-bottom: 3px solid transparent;
}

.orp-tab:hover {
    background: var(--hover-bg, #343536);
    color: var(--text-primary, #d7dadc);
}

.orp-tab.active {
    color: var(--link-color, #4fbcff);
    border-bottom-color: var(--link-color, #4fbcff);
}

.orp-tab-content {
    display: none;
    padding: 20px;
}

.orp-tab-content.active {
    display: block;
}

/* メニュータブのレイアウト */
#tab-menu {
    display: none;
    padding: 0;
}

#tab-menu.active {
    display: flex;
    gap: 20px;
}

.orp-menu-settings {
    flex: 1;
    padding: 20px;
    overflow-y: auto;
}

.orp-menu-preview {
    width: 250px;
    background: var(--bg-primary, #1a1a1b);
    border-left: 2px solid var(--border-color, #343536);
    padding: 20px 0;
    position: sticky;
    top: 0;
    align-self: flex-start;
    max-height: calc(80vh - 120px);
    overflow-y: auto;
}

.orp-preview-title {
    color: var(--text-secondary, #818384);
    font-size: 12px;
    font-weight: bold;
    padding: 0 15px 10px;
    border-bottom: 1px solid var(--border-color, #343536);
}

.orp-preview-list {
    list-style: none;
    padding: 0;
    margin: 0;
}

.orp-preview-item {
    display: block;
    padding: 10px 15px;
    color: var(--text-primary, #d7dadc);
    border-bottom: 1px solid var(--border-color, #343536);
    font-size: 14px;
}

.orp-preview-item:hover {
    background: var(--hover-bg, #272729);
}

#tab-sort {
    display: none;
}

#tab-sort.active {
    display: flex;
    flex-direction: column;
}

/* ソートタブコントロール */
#orp-sort-controls {
    display: flex;
    justify-content: flex-end;
    gap: 10px;
    padding: 15px 20px;
    border-bottom: 2px solid var(--border-color, #343536);
    background: var(--bg-secondary, #272729);
    position: sticky;
    top: 0;
    z-index: 10;
}

#orp-sort-save,
#orp-sort-cancel {
    padding: 8px 16px;
    border: 1px solid var(--border-color, #343536);
    border-radius: 4px;
    cursor: pointer;
    font-size: 14px;
    font-weight: bold;
}

#orp-sort-save {
    background: var(--link-color, #4fbcff);
    color: #ffffff;
}

#orp-sort-save:hover {
    background: #3a9dd9;
}

#orp-sort-cancel {
    background: var(--bg-secondary, #272729);
    color: var(--text-primary, #d7dadc);
}

#orp-sort-cancel:hover {
    background: var(--hover-bg, #343536);
}

#orp-sort-list {
    flex: 1;
    overflow-y: auto;
    padding: 0;
}

.orp-sort-item {
    display: grid;
    grid-template-columns: 40px 35px 35px 35px 35px 1fr;
    align-items: center;
    padding: 10px 15px;
    border-bottom: 1px solid var(--border-color, #343536);
    gap: 5px;
}

.orp-sort-item:hover {
    background: var(--hover-bg, #272729);
}

.orp-sort-number {
    text-align: center;
    font-weight: bold;
    color: var(--text-secondary, #818384);
    font-size: 13px;
}

.orp-sort-btn {
    background: var(--bg-secondary, #272729);
    color: var(--text-primary, #d7dadc);
    border: 1px solid var(--border-color, #343536);
    padding: 5px 8px;
    cursor: pointer;
    font-size: 14px;
    border-radius: 3px;
    text-align: center;
    transition: background 0.2s;
    width: 100%;
}

.orp-sort-btn:hover:not(:disabled) {
    background: var(--hover-bg, #343536);
}

.orp-sort-btn:disabled {
    opacity: 0;
    cursor: default;
    visibility: hidden;
}

.orp-sort-name {
    font-size: 14px;
    color: var(--text-primary, #d7dadc);
}

.orp-setting-item {
    margin-bottom: 25px;
    padding-bottom: 25px;
    border-bottom: 1px solid var(--border-color, #343536);
}

.orp-setting-item:last-child {
    border-bottom: none;
}

.orp-setting-label {
    display: block;
    color: var(--text-primary, #d7dadc);
    font-weight: bold;
    margin-bottom: 10px;
    font-size: 16px;
}

.orp-setting-description {
    color: var(--text-secondary, #818384);
    font-size: 13px;
    margin-bottom: 10px;
}

.orp-toggle-switch {
    display: inline-block;
    width: 50px;
    height: 26px;
    background: var(--text-secondary, #818384);
    border-radius: 13px;
    position: relative;
    cursor: pointer;
    transition: background 0.3s;
}

.orp-toggle-switch.active {
    background: var(--link-color, #4fbcff);
}

.orp-toggle-switch::after {
    content: '';
    position: absolute;
    top: 3px;
    left: 3px;
    width: 20px;
    height: 20px;
    background: white;
    border-radius: 50%;
    transition: left 0.3s;
}

.orp-toggle-switch.active::after {
    left: 27px;
}

.orp-rgb-control {
    display: flex;
    align-items: center;
    gap: 10px;
    margin-bottom: 10px;
}

.orp-rgb-label {
    width: 30px;
    font-weight: bold;
    color: var(--text-primary, #d7dadc);
}

.orp-rgb-spinner {
    display: flex;
    align-items: center;
    gap: 5px;
}

.orp-spinner-btn {
    background: var(--bg-secondary, #272729);
    border: 1px solid var(--border-color, #343536);
    color: var(--text-primary, #d7dadc);
    width: 30px;
    height: 30px;
    cursor: pointer;
    font-size: 16px;
    border-radius: 4px;
    transition: background 0.2s;
}

.orp-spinner-btn:hover {
    background: var(--hover-bg, #343536);
}

.orp-spinner-value {
    width: 50px;
    text-align: center;
    padding: 5px;
    background: var(--bg-secondary, #272729);
    border: 1px solid var(--border-color, #343536);
    border-radius: 4px;
    color: var(--text-primary, #d7dadc);
}

.orp-rgb-preview {
    width: 100px;
    height: 40px;
    border: 2px solid var(--border-color, #343536);
    border-radius: 4px;
    margin-top: 10px;
}

body.dark-mode {
    --bg-primary: #1a1a1b;
    --bg-secondary: #272729;
    --text-primary: #d7dadc;
    --text-secondary: #818384;
    --border-color: #343536;
}

body:not(.dark-mode) {
    --bg-primary: #ffffff;
    --bg-secondary: #f6f7f8;
    --text-primary: #1c1c1c;
    --text-secondary: #7c7c7c;
    --border-color: #ccc;
    --hover-bg: #e8e8e8;
}

#sr-header-area::-webkit-scrollbar {
    width: 12px;
}

#sr-header-area::-webkit-scrollbar-track {
    background: var(--bg-secondary, #272729);
}

#sr-header-area::-webkit-scrollbar-thumb {
    background: var(--text-secondary, #818384);
    border-radius: 6px;
    border: 2px solid var(--bg-primary, #1a1a1b);
}

#sr-header-area::-webkit-scrollbar-thumb:hover {
    background: var(--text-primary, #d7dadc);
}

#sr-header-area {
    scrollbar-width: thin;
    scrollbar-color: var(--text-secondary, #818384) var(--bg-secondary, #272729);
}
`);
    
    // JavaScript機能
    
    // ===================================
    // セキュリティユーティリティ関数
    // ===================================
    
    /**
     * HTMLエスケープ: XSS攻撃対策
     * @param {string} str - エスケープする文字列
     * @returns {string} エスケープ済み文字列
     */
    function sanitizeHTML(str) {
        if (typeof str !== 'string') return '';
        const escapeMap = {
            '<': '&lt;',
            '>': '&gt;',
            '&': '&amp;',
            '"': '&quot;',
            "'": '&#x27;'
        };
        return str.replace(/[<>&"']/g, char => escapeMap[char]);
    }
    
    /**
     * スクリプトタグ除去: XSS攻撃対策
     * @param {string} str - 処理する文字列
     * @returns {string} スクリプトタグを除去した文字列
     */
    function removeScriptTags(str) {
        if (typeof str !== 'string') return '';
        return str
            .replace(/<script[^>]*>.*?<\/script>/gi, '')
            .replace(/<iframe[^>]*>.*?<\/iframe>/gi, '')
            .replace(/on\w+\s*=\s*["'][^"']*["']/gi, '')
            .replace(/on\w+\s*=\s*[^\s>]*/gi, '')
            .replace(/javascript:/gi, '')
            .replace(/data:text\/html/gi, '');
    }
    
    /**
     * CSSサニタイズ: CSSインジェクション対策
     * @param {string} str - 処理する文字列
     * @returns {string} 危険なCSS構文を除去した文字列
     */
    function sanitizeCSS(str) {
        if (typeof str !== 'string') return '';
        return str
            .replace(/url\s*\(\s*["']?javascript:/gi, 'url(about:blank')
            .replace(/url\s*\(\s*["']?data:/gi, 'url(about:blank')
            .replace(/expression\s*\(/gi, 'invalid(')
            .replace(/@import/gi, '@invalid')
            .replace(/behavior\s*:/gi, 'invalid:')
            .replace(/binding\s*:/gi, 'invalid:')
            .replace(/-moz-binding/gi, 'invalid')
            .replace(/vbscript:/gi, 'invalid:');
    }
    
    /**
     * 数値検証: 範囲チェックとNaN対策
     * @param {any} value - 検証する値
     * @param {number} min - 最小値
     * @param {number} max - 最大値
     * @param {number} defaultValue - デフォルト値
     * @param {string} key - 設定キー名(警告用)
     * @returns {number} 検証済みの数値
     */
    function sanitizeNumericValue(value, min, max, defaultValue, key = '') {
        const parsed = parseInt(value, 10);
        
        if (isNaN(parsed)) {
            if (key && value !== null && value !== undefined && value !== '') {
                console.warn(`[NOR Security] NaN値を検出: ${key}="${value}" → デフォルト値${defaultValue}を使用`);
            }
            return defaultValue;
        }
        
        if (parsed < min || parsed > max) {
            if (key) {
                console.warn(`[NOR Security] 範囲外の値を検出: ${key}=${parsed} (範囲: ${min}-${max}) → ${Math.max(min, Math.min(max, parsed))}に修正`);
            }
            return Math.max(min, Math.min(max, parsed));
        }
        
        return parsed;
    }
    
    /**
     * 文字列サニタイズチェーン: HTML/Script/CSSの全サニタイズを適用
     * @param {string} str - 処理する文字列
     * @returns {string} サニタイズ済み文字列
     */
    function sanitizeString(str) {
        if (typeof str !== 'string') return '';
        let sanitized = sanitizeHTML(str);
        sanitized = removeScriptTags(sanitized);
        sanitized = sanitizeCSS(sanitized);
        return sanitized;
    }
    
    // ===================================
    // localStorage安全アクセス
    // ===================================
    
    const storage = {
        get(key, defaultValue = null) {
            try {
                const value = localStorage.getItem(key);
                if (value === null) return defaultValue;
                
                // Boolean値の場合
                if (defaultValue === true || defaultValue === false) {
                    return value === 'true';
                }
                
                // 文字列の場合はサニタイズ適用(二重防御)
                if (typeof defaultValue === 'string') {
                    const sanitized = sanitizeString(value);
                    if (sanitized !== value && sanitized.length < value.length) {
                        console.warn(`[NOR Security] 不正な値を検出してサニタイズ: ${key}`);
                    }
                    return sanitized;
                }
                
                // その他(数値検証は呼び出し側で実施)
                return value;
            } catch (error) {
                console.warn('[NOR] localStorage read failed:', error);
                return defaultValue;
            }
        },
        
        set(key, value, isJSON = false) {
            try {
                let sanitizedValue = String(value);
                
                // JSONの場合はサニタイズをスキップ
                if (isJSON) {
                    // JSONの場合はサイズチェックのみ実施
                    if (sanitizedValue.length > 50000) {
                        console.warn(`[NOR Security] JSON値が大きすぎます(${sanitizedValue.length}文字): ${key} → 50000文字に切り捨て`);               sanitizedValue = sanitizedValue.substring(0, 50000);
                    }
                    localStorage.setItem(key, sanitizedValue);
                    return;
                }
                
                // サイズチェック
                if (sanitizedValue.length > 10000) {
                    console.warn(`[NOR Security] 値が大きすぎます(${sanitizedValue.length}文字): ${key} → 10000文字に切り捨て`);
                    sanitizedValue = sanitizedValue.substring(0, 10000);
                }
                
                // Boolean以外の文字列の場合はサニタイズ
                if (value !== true && value !== false && value !== 'true' && value !== 'false') {
                    const originalLength = sanitizedValue.length;
                    sanitizedValue = sanitizeString(sanitizedValue);
                    if (sanitizedValue.length < originalLength) {
                        console.warn(`[NOR Security] 不正な内容を除去して保存: ${key}`);
                    }
                    
                    // サニタイズで空になった場合
                    if (sanitizedValue.trim() === '' && originalLength > 0) {
                        console.warn(`[NOR Security] サニタイズ後に空文字列になったため保存をスキップ: ${key}`);
                        return;
                    }
                }
                
                localStorage.setItem(key, sanitizedValue);
            } catch (error) {
                console.warn('[NOR] localStorage write failed:', error);
            }
        }
    };
    
    function createToggleButtons() {
        // 左サイドバートグルボタン(画面左側の縦バー)
        const leftToggleBtn = document.createElement('button');
        leftToggleBtn.id = 'orp-left-sidebar-toggle';
        leftToggleBtn.textContent = '☰';
        leftToggleBtn.title = t('buttons.leftToggle');
        leftToggleBtn.setAttribute('type', 'button');
        document.body.appendChild(leftToggleBtn);
        
        // 左サイドバーに設定ボタンを追加
        const sidebar = document.querySelector('#sr-header-area');
        if (sidebar) {
            const settingsBtn = document.createElement('button');
            settingsBtn.id = 'orp-settings-button';
            settingsBtn.textContent = t('buttons.settingsText');
            settingsBtn.title = t('buttons.settingsTitle');
            settingsBtn.setAttribute('type', 'button');
            
            const widthClip = sidebar.querySelector('.width-clip');
            if (widthClip) {
                widthClip.appendChild(settingsBtn);
            }
        }
        
        return { leftToggleBtn };
    }
    
    function createSettingsPanel() {
        const overlay = document.createElement('div');
        overlay.id = 'orp-settings-overlay';
        overlay.innerHTML = `
            <div id="orp-settings-panel">
                <div id="orp-settings-header">
                    <h2 data-i18n="settings.title">${t('settings.title')}</h2>
                    <button id="orp-settings-close" type="button">×</button>
                </div>
                <div style="padding: 15px 20px; border-bottom: 2px solid var(--border-color, #343536); background: var(--bg-secondary, #272729);">
                    <label style="display: flex; align-items: center; gap: 10px;">
                        <span data-i18n="language.label" style="color: var(--text-primary, #d7dadc); font-weight: bold;">${t('language.label')}:</span>
                        <select id="orp-language-select" style="padding: 5px 10px; background: var(--bg-primary, #1a1a1b); color: var(--text-primary, #d7dadc); border: 1px solid var(--border-color, #343536); border-radius: 4px; cursor: pointer;">
                            <option value="en">English</option>
                            <option value="ja">日本語</option>
                        </select>
                    </label>
                </div>
                <div class="orp-tabs">
                    <button class="orp-tab active" data-tab="menu-button" data-i18n="tabs.menuButton">${t('tabs.menuButton')}</button>
                    <button class="orp-tab" data-tab="menu" data-i18n="tabs.menu">${t('tabs.menu')}</button>
                    <button class="orp-tab" data-tab="sort" data-i18n="tabs.sort">${t('tabs.sort')}</button>
                </div>
                <div id="tab-menu-button" class="orp-tab-content active">
                    <div class="orp-setting-item">
                        <label class="orp-setting-label" data-i18n="darkMode.label">${t('darkMode.label')}</label>
                        <div class="orp-setting-description" data-i18n="darkMode.description">${t('darkMode.description')}</div>
                        <div id="orp-darkmode-toggle" class="orp-toggle-switch"></div>
                    </div>
                    <div class="orp-setting-item">
                        <label class="orp-setting-label" data-i18n="darkModeRight.label">${t('darkModeRight.label')}</label>
                        <div class="orp-setting-description" data-i18n="darkModeRight.description">${t('darkModeRight.description')}</div>
                        <div id="orp-darkmode-right-toggle" class="orp-toggle-switch"></div>
                    </div>
                    <div class="orp-setting-item" id="orp-darkmode-right-full-container" style="display: none;">
                        <label class="orp-setting-label" data-i18n="darkModeRightFull.label">${t('darkModeRightFull.label')}</label>
                        <div class="orp-setting-description" data-i18n="darkModeRightFull.description" style="color: #ff6b6b;">${t('darkModeRightFull.description')}</div>
                        <div id="orp-darkmode-right-full-toggle" class="orp-toggle-switch"></div>
                    </div>
                    <div class="orp-setting-item">
                        <label class="orp-setting-label" data-i18n="menuColor.label">${t('menuColor.label')}</label>
                        <div class="orp-setting-description" data-i18n="menuColor.description">${t('menuColor.description')}</div>
                        <div class="orp-rgb-control">
                            <span class="orp-rgb-label" style="color: #ff0000;">R:</span>
                            <div class="orp-rgb-spinner">
                                <button class="orp-spinner-btn" id="orp-r-minus" type="button">−</button>
                                <span class="orp-spinner-value" id="orp-r-value">0</span>
                                <button class="orp-spinner-btn" id="orp-r-plus" type="button">+</button>
                            </div>
                        </div>
                        <div class="orp-rgb-control">
                            <span class="orp-rgb-label" style="color: #00ff00;">G:</span>
                            <div class="orp-rgb-spinner">
                                <button class="orp-spinner-btn" id="orp-g-minus" type="button">−</button>
                                <span class="orp-spinner-value" id="orp-g-value">0</span>
                                <button class="orp-spinner-btn" id="orp-g-plus" type="button">+</button>
                            </div>
                        </div>
                        <div class="orp-rgb-control">
                            <span class="orp-rgb-label" style="color: #0088ff;">B:</span>
                            <div class="orp-rgb-spinner">
                                <button class="orp-spinner-btn" id="orp-b-minus" type="button">−</button>
                                <span class="orp-spinner-value" id="orp-b-value">0</span>
                                <button class="orp-spinner-btn" id="orp-b-plus" type="button">+</button>
                            </div>
                        </div>
                        <div class="orp-rgb-control">
                            <span class="orp-rgb-label" style="color: #ffffff;">A:</span>
                            <div class="orp-rgb-spinner">
                                <button class="orp-spinner-btn" id="orp-a-minus" type="button">−</button>
                                <span class="orp-spinner-value" id="orp-a-value">100</span>
                                <button class="orp-spinner-btn" id="orp-a-plus" type="button">+</button>
                            </div>
                            <span style="color: var(--text-secondary); font-size: 12px; margin-left: 5px;">%</span>
                        </div>
                        <div class="orp-setting-description" data-i18n="menuColor.preview">${t('menuColor.preview')}</div>
                        <div id="orp-rgb-preview" class="orp-rgb-preview"></div>
                    </div>
                    <div class="orp-setting-item">
                        <label class="orp-setting-label" data-i18n="menuSize.label">${t('menuSize.label')}</label>
                        <div class="orp-setting-description" data-i18n="menuSize.description">${t('menuSize.description')}</div>
                        <div class="orp-rgb-control">
                            <span class="orp-rgb-label" data-i18n="menuSize.width">${t('menuSize.width')}</span>
                            <div class="orp-rgb-spinner">
                                <button class="orp-spinner-btn" id="orp-width-minus" type="button">−</button>
                                <span class="orp-spinner-value" id="orp-width-value">50</span>
                                <button class="orp-spinner-btn" id="orp-width-plus" type="button">+</button>
                            </div>
                            <span style="color: var(--text-secondary); font-size: 12px; margin-left: 5px;">px</span>
                        </div>
                        <div class="orp-rgb-control">
                            <span class="orp-rgb-label" data-i18n="menuSize.height">${t('menuSize.height')}</span>
                            <div class="orp-rgb-spinner">
                                <button class="orp-spinner-btn" id="orp-height-minus" type="button">−</button>
                                <span class="orp-spinner-value" id="orp-height-value">200</span>
                                <button class="orp-spinner-btn" id="orp-height-plus" type="button">+</button>
                            </div>
                            <span style="color: var(--text-secondary); font-size: 12px; margin-left: 5px;">px</span>
                        </div>
                        <button id="orp-size-reset" class="orp-spinner-btn" type="button" data-i18n="menuSize.reset" style="margin-top: 10px; width: auto; padding: 5px 15px;">${t('menuSize.reset')}</button>
                    </div>
                    <div class="orp-setting-item">
                        <label class="orp-setting-label" data-i18n="menuOffset.label">${t('menuOffset.label')}</label>
                        <div class="orp-setting-description" data-i18n="menuOffset.description">${t('menuOffset.description')}</div>
                        <div class="orp-rgb-control">
                            <span class="orp-rgb-label" data-i18n="menuOffset.position">${t('menuOffset.position')}</span>
                            <div class="orp-rgb-spinner">
                                <button class="orp-spinner-btn" id="orp-offset-minus" type="button">−</button>
                                <span class="orp-spinner-value" id="orp-offset-value">0</span>
                                <button class="orp-spinner-btn" id="orp-offset-plus" type="button">+</button>
                            </div>
                            <span style="color: var(--text-secondary); font-size: 12px; margin-left: 5px;">px</span>
                        </div>
                        <button id="orp-offset-reset" class="orp-spinner-btn" type="button" data-i18n="menuOffset.reset" style="margin-top: 10px; width: auto; padding: 5px 15px;">${t('menuOffset.reset')}</button>
                    </div>
                </div>
                <div id="tab-menu" class="orp-tab-content">
                    <div class="orp-menu-settings">
                        <div class="orp-setting-item">
                            <label class="orp-setting-label" data-i18n="subsSettings.fontSize.label">${t('subsSettings.fontSize.label')}</label>
                            <div class="orp-setting-description" data-i18n="subsSettings.fontSize.description">${t('subsSettings.fontSize.description')}</div>
                            <div class="orp-rgb-control">
                                <span class="orp-rgb-label" data-i18n="subsSettings.fontSize.size">${t('subsSettings.fontSize.size')}</span>
                                <div class="orp-rgb-spinner">
                                    <button class="orp-spinner-btn" id="orp-subs-font-size-minus" type="button">−</button>
                                    <span class="orp-spinner-value" id="orp-subs-font-size-value">14</span>
                                    <button class="orp-spinner-btn" id="orp-subs-font-size-plus" type="button">+</button>
                                </div>
                                <span style="color: var(--text-secondary); font-size: 12px; margin-left: 5px;">px</span>
                                <button id="orp-subs-font-size-reset" class="orp-spinner-btn" type="button" data-i18n="subsSettings.fontSize.reset" style="width: auto; padding: 5px 15px; margin-left: 10px;">${t('subsSettings.fontSize.reset')}</button>
                            </div>
                        </div>
                        <div class="orp-setting-item">
                            <label class="orp-setting-label" data-i18n="subsSettings.margin.label">${t('subsSettings.margin.label')}</label>
                            <div class="orp-setting-description" data-i18n="subsSettings.margin.description">${t('subsSettings.margin.description')}</div>
                            <div class="orp-rgb-control">
                                <span class="orp-rgb-label" data-i18n="subsSettings.margin.margin">${t('subsSettings.margin.margin')}</span>
                                <div class="orp-rgb-spinner">
                                    <button class="orp-spinner-btn" id="orp-subs-margin-minus" type="button">−</button>
                                    <span class="orp-spinner-value" id="orp-subs-margin-value">10</span>
                                    <button class="orp-spinner-btn" id="orp-subs-margin-plus" type="button">+</button>
                                </div>
                                <span style="color: var(--text-secondary); font-size: 12px; margin-left: 5px;">px</span>
                                <button id="orp-subs-margin-reset" class="orp-spinner-btn" type="button" data-i18n="subsSettings.margin.reset" style="width: auto; padding: 5px 15px; margin-left: 10px;">${t('subsSettings.margin.reset')}</button>
                            </div>
                        </div>
                        <div class="orp-setting-item">
                            <label class="orp-setting-label" data-i18n="subsSettings.topOffset.label">${t('subsSettings.topOffset.label')}</label>
                            <div class="orp-setting-description" data-i18n="subsSettings.topOffset.description">${t('subsSettings.topOffset.description')}</div>
                            <div class="orp-rgb-control">
                                <span class="orp-rgb-label" data-i18n="subsSettings.topOffset.offset">${t('subsSettings.topOffset.offset')}</span>
                                <div class="orp-rgb-spinner">
                                    <button class="orp-spinner-btn" id="orp-subs-top-offset-minus" type="button">−</button>
                                    <span class="orp-spinner-value" id="orp-subs-top-offset-value">0</span>
                                    <button class="orp-spinner-btn" id="orp-subs-top-offset-plus" type="button">+</button>
                                </div>
                                <span style="color: var(--text-secondary); font-size: 12px; margin-left: 5px;">px</span>
                                <button id="orp-subs-top-offset-reset" class="orp-spinner-btn" type="button" data-i18n="subsSettings.topOffset.reset" style="width: auto; padding: 5px 15px; margin-left: 10px;">${t('subsSettings.topOffset.reset')}</button>
                            </div>
                        </div>
                        <div class="orp-setting-item">
                            <label class="orp-setting-label" data-i18n="subsSettings.lrOffset.label">${t('subsSettings.lrOffset.label')}</label>
                            <div class="orp-setting-description" data-i18n="subsSettings.lrOffset.description">${t('subsSettings.lrOffset.description')}</div>
                            <div class="orp-rgb-control">
                                <span class="orp-rgb-label" data-i18n="subsSettings.lrOffset.offset">${t('subsSettings.lrOffset.offset')}</span>
                                <div class="orp-rgb-spinner">
                                    <button class="orp-spinner-btn" id="orp-subs-lr-offset-minus" type="button">−</button>
                                    <span class="orp-spinner-value" id="orp-subs-lr-offset-value">0</span>
                                    <button class="orp-spinner-btn" id="orp-subs-lr-offset-plus" type="button">+</button>
                                </div>
                                <span style="color: var(--text-secondary); font-size: 12px; margin-left: 5px;">px</span>
                                <button id="orp-subs-lr-offset-reset" class="orp-spinner-btn" type="button" data-i18n="subsSettings.lrOffset.reset" style="width: auto; padding: 5px 15px; margin-left: 10px;">${t('subsSettings.lrOffset.reset')}</button>
                            </div>
                        </div>
                    </div>
                    <div class="orp-menu-preview">
                        <div class="orp-preview-title" data-i18n="preview.title">${t('preview.title')}</div>
                        <ul class="orp-preview-list" id="orp-preview-list">
                            <li class="orp-preview-item">TEST1</li>
                            <li class="orp-preview-item">TEST2</li>
                            <li class="orp-preview-item">TEST3</li>
                            <li class="orp-preview-item">TEST4</li>
                            <li class="orp-preview-item">TEST5</li>
                        </ul>
                    </div>
                </div>
                <div id="tab-sort" class="orp-tab-content">
                    <div id="orp-sort-controls">
                        <button id="orp-sort-save" type="button" data-i18n="sort.save">${t('sort.save')}</button>
                        <button id="orp-sort-cancel" type="button" data-i18n="sort.cancel">${t('sort.cancel')}</button>
                    </div>
                    <div id="orp-sort-list"></div>
                </div>
            </div>
        `;
        document.body.appendChild(overlay);
        return overlay;
    }
    
    function initSettingsPanel() {
        const overlay = createSettingsPanel();
        const closeBtn = document.getElementById('orp-settings-close');
        const settingsBtn = document.getElementById('orp-settings-button');
        const darkModeToggle = document.getElementById('orp-darkmode-toggle');
        
        // ソート機能の初期化
        initSortFeature();
        
        // 言語選択の初期化
        const languageSelect = document.getElementById('orp-language-select');
        if (languageSelect) {
            languageSelect.value = currentLang;
            languageSelect.addEventListener('change', function() {
                updateLanguage(this.value);
            });
        }
        
        // タブ切り替え機能
        const tabs = document.querySelectorAll('.orp-tab');
        const tabContents = document.querySelectorAll('.orp-tab-content');
        
        tabs.forEach(tab => {
            tab.addEventListener('click', function() {
                const targetTab = this.dataset.tab;
                
                // すべてのタブとコンテンツから active クラスを削除
                tabs.forEach(t => t.classList.remove('active'));
                tabContents.forEach(tc => tc.classList.remove('active'));
                
                // クリックされたタブとそのコンテンツに active クラスを追加
                this.classList.add('active');
                document.getElementById(`tab-${targetTab}`).classList.add('active');
                
                // ソートタブが開かれたらリストを描画
                if (targetTab === 'sort') {
                    renderSortList();
                }
            });
        });
        
        // ダークモードの初期状態を反映
        const isDarkMode = storage.get('darkMode') === 'true';
        if (isDarkMode) {
            darkModeToggle.classList.add('active');
        }
        
        // RIGHT側ダークモードの初期化
        const darkModeRightToggle = document.getElementById('orp-darkmode-right-toggle');
        const darkModeRightFullToggle = document.getElementById('orp-darkmode-right-full-toggle');
        const darkModeRightFullContainer = document.getElementById('orp-darkmode-right-full-container');
        
        const isDarkModeRight = storage.get('darkModeRight') === 'true';
        if (isDarkModeRight) {
            darkModeRightToggle.classList.add('active');
            document.body.classList.add('dark-mode-right');
            // RIGHT側ダークモードがONの場合、フルダークモード設定を表示
            darkModeRightFullContainer.style.display = '';
        }
        
        // RIGHT側フルダークモードの初期化
        const isDarkModeRightFull = storage.get('darkModeRightFull') === 'true';
        if (isDarkModeRightFull && isDarkModeRight) {
            darkModeRightFullToggle.classList.add('active');
            document.body.classList.add('dark-mode-right-full');
        }
        
        // 設定ボタンクリックで表示
        if (settingsBtn) {
            settingsBtn.addEventListener('click', function(e) {
                e.stopPropagation();
                overlay.classList.add('show');
                document.body.classList.add('settings-open');
                // 左サイドバーを閉じる
                document.body.classList.remove('show-left');
                storage.set('leftSidebarVisible', false);
                const leftToggle = document.getElementById('orp-left-sidebar-toggle');
                if (leftToggle) leftToggle.style.display = '';
            });
        }
        
        // 閉じるボタン
        closeBtn.addEventListener('click', function() {
            overlay.classList.remove('show');
            document.body.classList.remove('settings-open');
            // SUBSを閉じる
            document.body.classList.remove('show-left');
        });
        
        // オーバーレイの外側クリックで閉じる
        overlay.addEventListener('click', function(e) {
            if (e.target === overlay) {
                overlay.classList.remove('show');
                document.body.classList.remove('settings-open');
                // SUBSを閉じる
                document.body.classList.remove('show-left');
            }
        });
        
        // ダークモードトグル
        darkModeToggle.addEventListener('click', function() {
            darkModeToggle.classList.toggle('active');
            const isNowDark = darkModeToggle.classList.contains('active');
            document.body.classList.toggle('dark-mode', isNowDark);
            storage.set('darkMode', isNowDark);
        });
        
        // RIGHT側ダークモードトグル
        darkModeRightToggle.addEventListener('click', function() {
            darkModeRightToggle.classList.toggle('active');
            const isNowDarkRight = darkModeRightToggle.classList.contains('active');
            document.body.classList.toggle('dark-mode-right', isNowDarkRight);
            storage.set('darkModeRight', isNowDarkRight);
            
            // フルダークモード設定の表示/非表示を切り替え
            if (isNowDarkRight) {
                darkModeRightFullContainer.style.display = '';
            } else {
                darkModeRightFullContainer.style.display = 'none';
                // RIGHT側ダークモードをOFFにした場合、フルダークモードも自動的にOFF
                if (darkModeRightFullToggle.classList.contains('active')) {
                    darkModeRightFullToggle.classList.remove('active');
                    document.body.classList.remove('dark-mode-right-full');
                    storage.set('darkModeRightFull', false);
                }
            }
        });
        
        // RIGHT側フルダークモードトグル
        darkModeRightFullToggle.addEventListener('click', function() {
            darkModeRightFullToggle.classList.toggle('active');
            const isNowDarkRightFull = darkModeRightFullToggle.classList.contains('active');
            document.body.classList.toggle('dark-mode-right-full', isNowDarkRightFull);
            storage.set('darkModeRightFull', isNowDarkRightFull);
        });
        
        // RGB設定の初期化
        initRGBSettings();
        
        // メニュー設定の初期化
        initMenuSettings();
    }
    
    function initRGBSettings() {
        const leftToggleBtn = document.getElementById('orp-left-sidebar-toggle');
        
        // RGB値を0-255の範囲で、5刻みで管理(セキュリティ検証付き)
        let rValue = sanitizeNumericValue(storage.get('menuColorR', '39'), 0, 255, 39, 'menuColorR');
        let gValue = sanitizeNumericValue(storage.get('menuColorG', '39'), 0, 255, 39, 'menuColorG');
        let bValue = sanitizeNumericValue(storage.get('menuColorB', '41'), 0, 255, 41, 'menuColorB');
        // アルファ値は10-100の範囲で、5刻みで管理(%表記)
        let aValue = sanitizeNumericValue(storage.get('menuColorA', '100'), 10, 100, 100, 'menuColorA');
        
        // サイズとオフセット設定(セキュリティ検証付き)
        let widthValue = sanitizeNumericValue(storage.get('menuWidth', '50'), 5, 100, 50, 'menuWidth');
        let heightValue = sanitizeNumericValue(storage.get('menuHeight', '200'), 5, 5000, 200, 'menuHeight');
        let offsetValue = sanitizeNumericValue(storage.get('menuOffset', '0'), -10000, 10000, 0, 'menuOffset');
        
        const rValueEl = document.getElementById('orp-r-value');
        const gValueEl = document.getElementById('orp-g-value');
        const bValueEl = document.getElementById('orp-b-value');
        const aValueEl = document.getElementById('orp-a-value');
        const widthValueEl = document.getElementById('orp-width-value');
        const heightValueEl = document.getElementById('orp-height-value');
        const offsetValueEl = document.getElementById('orp-offset-value');
        const previewEl = document.getElementById('orp-rgb-preview');
        
        const updateRGBA = () => {
            // 値を表示
            rValueEl.textContent = rValue;
            gValueEl.textContent = gValue;
            bValueEl.textContent = bValue;
            aValueEl.textContent = aValue;
            
            // アルファ値を0-1の範囲に変換
            const alpha = aValue / 100;
            
            // プレビュー更新(強制的に再描画)
            const color = `rgba(${rValue}, ${gValue}, ${bValue}, ${alpha})`;
            previewEl.style.background = '';
            setTimeout(() => {
                previewEl.style.background = color;
            }, 0);
            
            // メニューボタンに適用
            if (leftToggleBtn) {
                leftToggleBtn.style.setProperty('background', color, 'important');
            }
            
            // 保存
            storage.set('menuColorR', String(rValue));
            storage.set('menuColorG', String(gValue));
            storage.set('menuColorB', String(bValue));
            storage.set('menuColorA', String(aValue));
            
            console.log('[NOR] Color updated:', color);
        };
        
        const updateSize = () => {
            // 値を表示
            widthValueEl.textContent = widthValue;
            heightValueEl.textContent = heightValue;
            
            // メニューボタンに適用
            if (leftToggleBtn) {
                leftToggleBtn.style.setProperty('max-width', `${widthValue}px`, 'important');
                leftToggleBtn.style.setProperty('width', `${widthValue}px`, 'important');
                leftToggleBtn.style.setProperty('height', `${heightValue}px`, 'important');
            }
            
            // 保存
            storage.set('menuWidth', String(widthValue));
            storage.set('menuHeight', String(heightValue));
            
            console.log('[NOR] Size updated:', widthValue, heightValue);
        };
        
        const updateOffset = () => {
            // 値を表示
            offsetValueEl.textContent = offsetValue;
            
            // メニューボタンに適用
            if (leftToggleBtn) {
                const transform = `translateY(calc(-50% + ${offsetValue}px))`;
                leftToggleBtn.style.setProperty('transform', transform, 'important');
            }
            
            // 保存
            storage.set('menuOffset', String(offsetValue));
            
            console.log('[NOR] Offset updated:', offsetValue);
        };
        
        // 初期表示
        updateRGBA();
        updateSize();
        updateOffset();
        
        // RGB値更新のヘルパー関数
        const createHandler = (getValue, setValue, updateFunc, min = 0, max = 255, step = 5) => {
            return {
                increment: () => {
                    setValue(Math.min(max, getValue() + step));
                    updateFunc();
                },
                decrement: () => {
                    setValue(Math.max(min, getValue() - step));
                    updateFunc();
                }
            };
        };
        
        // R, G, B, Aのハンドラーを設定
        const colorHandlers = {
            r: createHandler(() => rValue, (v) => rValue = v, updateRGBA, 0, 255, 5),
            g: createHandler(() => gValue, (v) => gValue = v, updateRGBA, 0, 255, 5),
            b: createHandler(() => bValue, (v) => bValue = v, updateRGBA, 0, 255, 5),
            a: createHandler(() => aValue, (v) => aValue = v, updateRGBA, 10, 100, 5)
        };
        
        // サイズハンドラー
        const sizeHandlers = {
            width: createHandler(() => widthValue, (v) => widthValue = v, updateSize, 5, 100, 5),
            height: createHandler(() => heightValue, (v) => heightValue = v, updateSize, 5, 5000, 10)
        };
        
        // オフセットハンドラー
        const offsetHandlers = {
            offset: createHandler(() => offsetValue, (v) => offsetValue = v, updateOffset, -10000, 10000, 10)
        };
        
        // イベントリスナーを登録
        ['r', 'g', 'b', 'a'].forEach(color => {
            document.getElementById(`orp-${color}-minus`).addEventListener('click', colorHandlers[color].decrement);
            document.getElementById(`orp-${color}-plus`).addEventListener('click', colorHandlers[color].increment);
        });
        
        // サイズのイベントリスナー
        document.getElementById('orp-width-minus').addEventListener('click', sizeHandlers.width.decrement);
        document.getElementById('orp-width-plus').addEventListener('click', sizeHandlers.width.increment);
        document.getElementById('orp-height-minus').addEventListener('click', sizeHandlers.height.decrement);
        document.getElementById('orp-height-plus').addEventListener('click', sizeHandlers.height.increment);
        
        // オフセットのイベントリスナー
        document.getElementById('orp-offset-minus').addEventListener('click', offsetHandlers.offset.decrement);
        document.getElementById('orp-offset-plus').addEventListener('click', offsetHandlers.offset.increment);
        
        // リセットボタン
        document.getElementById('orp-size-reset').addEventListener('click', () => {
            widthValue = 50;
            heightValue = 200;
            updateSize();
        });
        
        document.getElementById('orp-offset-reset').addEventListener('click', () => {
            offsetValue = 0;
            updateOffset();
        });
    }
    
    function initMenuSettings() {
        // SUBS設定の初期化(セキュリティ検証付き)
        const subsSettings = {
            fontSize: {
                value: sanitizeNumericValue(storage.get('subsFontSize', '14'), 5, 50, 14, 'subsFontSize'),
                default: 14,
                min: 5,
                max: 50,
                step: 1
            },
            margin: {
                value: sanitizeNumericValue(storage.get('subsMargin', '10'), 0, 100, 10, 'subsMargin'),
                default: 10,
                min: 0,
                max: 100,
                step: 1
            },
            topOffset: {
                value: sanitizeNumericValue(storage.get('subsTopOffset', '0'), 0, 1000, 0, 'subsTopOffset'),
                default: 0,
                min: 0,
                max: 1000,
                step: 1
            },
            lrOffset: {
                value: sanitizeNumericValue(storage.get('subsLROffset', '0'), 0, 1000, 0, 'subsLROffset'),
                default: 0,
                min: 0,
                max: 1000,
                step: 1
            }
        };
        
        const updateSubsStyles = () => {
            const styleId = 'orp-subs-custom-style';
            let styleEl = document.getElementById(styleId);
            if (!styleEl) {
                styleEl = document.createElement('style');
                styleEl.id = styleId;
                document.head.appendChild(styleEl);
            }
            
            // CSSインジェクション対策: 値の再検証(多層防御)
            const fontSize = sanitizeNumericValue(subsSettings.fontSize.value, 5, 50, 14);
            const margin = sanitizeNumericValue(subsSettings.margin.value, 0, 100, 10);
            const topOffset = sanitizeNumericValue(subsSettings.topOffset.value, 0, 1000, 0);
            const lrOffset = sanitizeNumericValue(subsSettings.lrOffset.value, 0, 1000, 0);
            
            // 型チェック(数値であることを保証)
            if (typeof fontSize !== 'number' || typeof margin !== 'number' || 
                typeof topOffset !== 'number' || typeof lrOffset !== 'number') {
                console.error('[NOR Security] CSS値の型が不正です。スタイル更新をスキップします。');
                return;
            }
            
            styleEl.textContent = `
                #sr-header-area .sr-bar a {
                    font-size: ${fontSize}px !important;
                    padding-top: ${margin}px !important;
                    padding-bottom: ${margin}px !important;
                    padding-left: ${15 + lrOffset}px !important;
                    padding-right: ${15 + lrOffset}px !important;
                }
                #sr-header-area .sr-bar {
                    padding-top: ${topOffset}px !important;
                }
                /* プレビュー用 */
                .orp-preview-item {
                    font-size: ${fontSize}px !important;
                    padding-top: ${margin}px !important;
                    padding-bottom: ${margin}px !important;
                    padding-left: ${15 + lrOffset}px !important;
                    padding-right: ${15 + lrOffset}px !important;
                }
                .orp-preview-list {
                    padding-top: ${topOffset}px !important;
                }
            `;
        };
        
        // 各設定の更新関数
        const updateSetting = (key) => {
            const setting = subsSettings[key];
            const valueEl = document.getElementById(`orp-subs-${key.replace(/([A-Z])/g, '-$1').toLowerCase()}-value`);
            valueEl.textContent = setting.value;
            
            const storageKey = 'subs' + key.charAt(0).toUpperCase() + key.slice(1);
            storage.set(storageKey, String(setting.value));
            
            updateSubsStyles();
        };
        
        // 初期表示
        Object.keys(subsSettings).forEach(key => {
            const setting = subsSettings[key];
            const kebabKey = key.replace(/([A-Z])/g, '-$1').toLowerCase();
            const valueEl = document.getElementById(`orp-subs-${kebabKey}-value`);
            valueEl.textContent = setting.value;
        });
        updateSubsStyles();
        
        // イベントリスナー
        Object.keys(subsSettings).forEach(key => {
            const setting = subsSettings[key];
            const kebabKey = key.replace(/([A-Z])/g, '-$1').toLowerCase();
            
            // +ボタン
            document.getElementById(`orp-subs-${kebabKey}-plus`).addEventListener('click', () => {
                setting.value = Math.min(setting.max, setting.value + setting.step);
                updateSetting(key);
            });
            
            // -ボタン
            document.getElementById(`orp-subs-${kebabKey}-minus`).addEventListener('click', () => {
                setting.value = Math.max(setting.min, setting.value - setting.step);
                updateSetting(key);
            });
            
            // リセットボタン
            document.getElementById(`orp-subs-${kebabKey}-reset`).addEventListener('click', () => {
                setting.value = setting.default;
                updateSetting(key);
            });
        });
    }
    
    // ===================================
    // ソート機能
    // ===================================
    let currentSortOrder = [];
    let originalSortOrder = [];
    
    function getSortableItems() {
        // 2つの.sr-barが存在する:[0]はシステムメニュー、[1]は登録サブレディット
        const srBars = document.querySelectorAll('#sr-header-area .sr-bar');
        const srBar = srBars[1]; // 2つ目(登録サブレディット)を使用
        
        if (!srBar) {
            console.warn('[ORP Sort] Second .sr-bar (user subreddits) not found');
            return [];
        }
        
        const items = Array.from(srBar.querySelectorAll('li'));
        console.log('[ORP Sort] Total subreddit items found:', items.length);
        
        // 各li要素から情報を抽出(separatorを除外)
        return items.map(item => {
            const link = item.querySelector('a.choice');
            if (!link) return null;
            
            return {
                href: link.getAttribute('href') || '',
                name: link.textContent?.trim() || ''
            };
        }).filter(item => item && item.href && item.name);
    }
    
    function renderSortList() {
        console.log('[ORP Sort] renderSortList called');
        const listContainer = document.getElementById('orp-sort-list');
        if (!listContainer) {
            console.warn('[ORP Sort] List container not found');
            return;
        }
        
        const items = getSortableItems();
        currentSortOrder = [...items];
        originalSortOrder = [...items];
        
        listContainer.innerHTML = '';
        
        if (items.length === 0) {
            console.warn('[ORP Sort] No sortable subreddits found');
            listContainer.innerHTML = `<div style="padding: 20px; text-align: center; color: var(--text-secondary);">
                登録されたサブレディットが見つかりませんでした
            </div>`;
            return;
        }
        
        console.log('[ORP Sort] Rendering', items.length, 'subreddits');
        
        currentSortOrder.forEach((item, index) => {
            const row = document.createElement('div');
            row.className = 'orp-sort-item';
            
            // 連番
            const numberEl = document.createElement('div');
            numberEl.className = 'orp-sort-number';
            numberEl.textContent = (index + 1).toString();
            
            // ↑↑ボタン(最上位に移動、最初の項目は作成しない)
            let upUpBtn;
            if (index > 0) {
                upUpBtn = document.createElement('button');
                upUpBtn.className = 'orp-sort-btn';
                upUpBtn.textContent = '↑↑';
                upUpBtn.type = 'button';
                upUpBtn.addEventListener('click', () => {
                    const movedItem = currentSortOrder.splice(index, 1)[0];
                    currentSortOrder.unshift(movedItem);
                    updateSortList();
                });
            }
            
            // ↑ボタン(1つ上に移動、最初の項目は作成しない)
            let upBtn;
            if (index > 0) {
                upBtn = document.createElement('button');
                upBtn.className = 'orp-sort-btn';
                upBtn.textContent = '↑';
                upBtn.type = 'button';
                upBtn.addEventListener('click', () => {
                    [currentSortOrder[index - 1], currentSortOrder[index]] = [currentSortOrder[index], currentSortOrder[index - 1]];
                    updateSortList();
                });
            }
            
            // ↓ボタン(1つ下に移動、最下段の項目は作成しない)
            let downBtn;
            if (index < currentSortOrder.length - 1) {
                downBtn = document.createElement('button');
                downBtn.className = 'orp-sort-btn';
                downBtn.textContent = '↓';
                downBtn.type = 'button';
                downBtn.addEventListener('click', () => {
                    [currentSortOrder[index], currentSortOrder[index + 1]] = [currentSortOrder[index + 1], currentSortOrder[index]];
                    updateSortList();
                });
            }
            
            // ↓↓ボタン(最下位に移動、最下段の項目は作成しない)
            let downDownBtn;
            if (index < currentSortOrder.length - 1) {
                downDownBtn = document.createElement('button');
                downDownBtn.className = 'orp-sort-btn';
                downDownBtn.textContent = '↓↓';
                downDownBtn.type = 'button';
                downDownBtn.addEventListener('click', () => {
                    const movedItem = currentSortOrder.splice(index, 1)[0];
                    currentSortOrder.push(movedItem);
                    updateSortList();
                });
            }
            
            // サブレディット名
            const nameEl = document.createElement('div');
            nameEl.className = 'orp-sort-name';
            nameEl.textContent = item.name;
            
            row.appendChild(numberEl);
            if (upUpBtn) row.appendChild(upUpBtn);
            else row.appendChild(document.createElement('div'));
            if (upBtn) row.appendChild(upBtn);
            else row.appendChild(document.createElement('div'));
            if (downBtn) row.appendChild(downBtn);
            else row.appendChild(document.createElement('div'));
            if (downDownBtn) row.appendChild(downDownBtn);
            else row.appendChild(document.createElement('div'));
            row.appendChild(nameEl);
            
            listContainer.appendChild(row);
        });
    }
    
    function updateSortList() {
        const listContainer = document.getElementById('orp-sort-list');
        if (!listContainer) return;
        
        listContainer.innerHTML = '';
        
        currentSortOrder.forEach((item, index) => {
            const row = document.createElement('div');
            row.className = 'orp-sort-item';
            
            const numberEl = document.createElement('div');
            numberEl.className = 'orp-sort-number';
            numberEl.textContent = (index + 1).toString();
            
            // ↑↑ボタン(最上位に移動)
            let upUpBtn;
            if (index > 0) {
                upUpBtn = document.createElement('button');
                upUpBtn.className = 'orp-sort-btn';
                upUpBtn.textContent = '↑↑';
                upUpBtn.type = 'button';
                upUpBtn.addEventListener('click', () => {
                    const movedItem = currentSortOrder.splice(index, 1)[0];
                    currentSortOrder.unshift(movedItem);
                    updateSortList();
                });
            }
            
            // ↑ボタン(1つ上に移動)
            let upBtn;
            if (index > 0) {
                upBtn = document.createElement('button');
                upBtn.className = 'orp-sort-btn';
                upBtn.textContent = '↑';
                upBtn.type = 'button';
                upBtn.addEventListener('click', () => {
                    [currentSortOrder[index - 1], currentSortOrder[index]] = [currentSortOrder[index], currentSortOrder[index - 1]];
                    updateSortList();
                });
            }
            
            // ↓ボタン(1つ下に移動)
            let downBtn;
            if (index < currentSortOrder.length - 1) {
                downBtn = document.createElement('button');
                downBtn.className = 'orp-sort-btn';
                downBtn.textContent = '↓';
                downBtn.type = 'button';
                downBtn.addEventListener('click', () => {
                    [currentSortOrder[index], currentSortOrder[index + 1]] = [currentSortOrder[index + 1], currentSortOrder[index]];
                    updateSortList();
                });
            }
            
            // ↓↓ボタン(最下位に移動)
            let downDownBtn;
            if (index < currentSortOrder.length - 1) {
                downDownBtn = document.createElement('button');
                downDownBtn.className = 'orp-sort-btn';
                downDownBtn.textContent = '↓↓';
                downDownBtn.type = 'button';
                downDownBtn.addEventListener('click', () => {
                    const movedItem = currentSortOrder.splice(index, 1)[0];
                    currentSortOrder.push(movedItem);
                    updateSortList();
                });
            }
            
            const nameEl = document.createElement('div');
            nameEl.className = 'orp-sort-name';
            nameEl.textContent = item.name;
            
            row.appendChild(numberEl);
            if (upUpBtn) row.appendChild(upUpBtn);
            else row.appendChild(document.createElement('div'));
            if (upBtn) row.appendChild(upBtn);
            else row.appendChild(document.createElement('div'));
            if (downBtn) row.appendChild(downBtn);
            else row.appendChild(document.createElement('div'));
            if (downDownBtn) row.appendChild(downDownBtn);
            else row.appendChild(document.createElement('div'));
            row.appendChild(nameEl);
            
            listContainer.appendChild(row);
        });
    }
    
    function saveSortOrder() {
        const orderMap = {};
        currentSortOrder.forEach((item, index) => {
            orderMap[item.href] = index;
        });
        
        const jsonString = JSON.stringify(orderMap);
        console.log('[ORP] Saving sort order:', jsonString.substring(0, 100) + '...');
        storage.set('subredditOrder', jsonString, true); // isJSON=trueでサニタイズをスキップ
        
        // 保存後に確認
        const saved = localStorage.getItem('subredditOrder');
        console.log('[ORP] Verification - saved value:', saved?.substring(0, 100) + '...');
        
        // 実際のDOMにも反映(2つ目の.sr-bar = 登録サブレディット)
        const srBars = document.querySelectorAll('#sr-header-area .sr-bar');
        const srBar = srBars[1];
        if (!srBar) return;
        
        const items = Array.from(srBar.querySelectorAll('li'));
        
        // スペーサーを保持
        const separator = srBar.querySelector('.orp-separator');
        
        // 現在のソート順でDOMを並び替え
        currentSortOrder.forEach(sortItem => {
            const li = items.find(i => i.querySelector('a')?.getAttribute('href') === sortItem.href);
            if (li) srBar.appendChild(li);
        });
        
        // スペーサーを先頭に戻す
        if (separator && srBar.firstChild !== separator) {
            srBar.insertBefore(separator, srBar.firstChild);
        }
        
        originalSortOrder = [...currentSortOrder];
        console.log('[ORP] ✅ Sort order saved successfully');
    }
    
    // ローディング表示を追加
    function showSortLoading() {
        const srBars = document.querySelectorAll('#sr-header-area .sr-bar');
        const srBar = srBars[1];
        if (!srBar) return;
        
        // 既存のローディング表示があれば削除
        const existing = srBar.querySelector('.orp-sort-loading');
        if (existing) existing.remove();
        
        const loadingLi = document.createElement('li');
        loadingLi.className = 'orp-sort-loading';
        loadingLi.style.cssText = 'color: #888; font-style: italic; pointer-events: none;';
        const lang = document.documentElement.lang;
        loadingLi.textContent = lang === 'ja' ? 'サブレ順読み込み中...' : 'Loading subreddit order...';
        srBar.insertBefore(loadingLi, srBar.firstChild);
    }
    
    // ローディング表示を削除
    function hideSortLoading() {
        const loadingElements = document.querySelectorAll('.orp-sort-loading');
        loadingElements.forEach(el => el.remove());
    }
    
    // 再読み込みボタンを表示(設定ボタンの下)
    function showSortReloadButton() {
        const sidebar = document.querySelector('#sr-header-area');
        if (!sidebar) return;
        
        const widthClip = sidebar.querySelector('.width-clip');
        if (!widthClip) return;
        
        // 既存のボタンがあれば削除
        const existing = document.getElementById('orp-sort-reload-button');
        if (existing) existing.remove();
        
        const reloadBtn = document.createElement('button');
        reloadBtn.id = 'orp-sort-reload-button';
        reloadBtn.setAttribute('type', 'button');
        reloadBtn.style.cssText = `
            position: absolute;
            bottom: 10px;
            right: 10px;
            padding: 8px 12px;
            background: #ff4500;
            color: white;
            border: none;
            border-radius: 4px;
            cursor: pointer;
            font-size: 12px;
            font-weight: bold;
            z-index: 100;
        `;
        const lang = document.documentElement.lang;
        reloadBtn.textContent = lang === 'ja' ? '🔄 ソート順を再読み込み' : '🔄 Reload sort order';
        reloadBtn.addEventListener('click', (e) => {
            e.preventDefault();
            reloadBtn.remove();
            loadSortOrderWithRetry();
        });
        widthClip.appendChild(reloadBtn);
    }
    
    // ソート順を読み込む(実際の処理)
    function loadSortOrder() {
        console.log('[ORP] loadSortOrder() called');
        const savedOrder = storage.get('subredditOrder');
        if (!savedOrder) {
            console.log('[ORP] No saved sort order found in storage');
            return false;
        }
        
        console.log('[ORP] Saved order found:', savedOrder.substring(0, 100) + '...');
        
        try {
            const orderMap = JSON.parse(savedOrder);
            console.log('[ORP] Parsed order map:', Object.keys(orderMap).length, 'items');
            
            // 2つ目の.sr-bar(登録サブレディット)を取得
            const srBars = document.querySelectorAll('#sr-header-area .sr-bar');
            console.log('[ORP] Found .sr-bar elements:', srBars.length);
            
            const srBar = srBars[1];
            if (!srBar) {
                console.warn('[ORP] Subreddit bar not found (srBar[1] is undefined)');
                console.warn('[ORP] Available srBars:', srBars.length);
                return false;
            }
            
            const items = Array.from(srBar.querySelectorAll('li'));
            console.log('[ORP] Found <li> items in srBar[1]:', items.length);
            
            if (items.length === 0) {
                console.warn('[ORP] No subreddit items found in the bar');
                return false;
            }
            
            // 2つ目の.sr-barにはすべて登録サブレディットが入っているので、固定項目は不要
            // スペーサーもソート対象から除外
            const sortableItems = items.filter(item => 
                !item.classList.contains('orp-sort-loading') && 
                !item.classList.contains('orp-sort-reload') &&
                !item.classList.contains('orp-separator')
            );
            console.log('[ORP] Sortable items:', sortableItems.length);
            
            // ソート前の順序をログ出力
            console.log('[ORP] Before sort:', sortableItems.slice(0, 5).map(i => i.querySelector('a')?.textContent));
            
            sortableItems.sort((a, b) => {
                const aHref = a.querySelector('a')?.getAttribute('href') || '';
                const bHref = b.querySelector('a')?.getAttribute('href') || '';
                const aIndex = orderMap[aHref] !== undefined ? orderMap[aHref] : 999;
                const bIndex = orderMap[bHref] !== undefined ? orderMap[bHref] : 999;
                return aIndex - bIndex;
            });
            
            // ソート後の順序をログ出力
            console.log('[ORP] After sort:', sortableItems.slice(0, 5).map(i => i.querySelector('a')?.textContent));
            
            // スペーサーを保持
            const separator = srBar.querySelector('.orp-separator');
            
            // ソート済みアイテムをDOMに反映
            sortableItems.forEach(item => srBar.appendChild(item));
            
            // スペーサーを先頭に戻す
            if (separator && srBar.firstChild !== separator) {
                srBar.insertBefore(separator, srBar.firstChild);
            }
            
            console.log('[ORP] ✅ Sort order loaded and applied successfully');
            return true;
        } catch (e) {
            console.error('[ORP] ❌ Failed to load sort order:', e);
            return false;
        }
    }
    
    // リトライ機能付きでソート順を読み込む
    function loadSortOrderWithRetry(attempt = 0, maxAttempts = 3, delay = 150) {
        if (attempt === 0) {
            showSortLoading();
        }
        
        const success = loadSortOrder();
        
        if (success) {
            hideSortLoading();
            return;
        }
        
        if (attempt < maxAttempts - 1) {
            console.log(`[ORP] Retrying to load sort order (${attempt + 1}/${maxAttempts})...`);
            setTimeout(() => {
                loadSortOrderWithRetry(attempt + 1, maxAttempts, delay);
            }, delay);
        } else {
            console.warn('[ORP] Failed to load sort order after all retries');
            hideSortLoading();
            showSortReloadButton();
        }
    }
    
    function initSortFeature() {
        const saveBtn = document.getElementById('orp-sort-save');
        const cancelBtn = document.getElementById('orp-sort-cancel');
        
        if (saveBtn) {
            saveBtn.addEventListener('click', () => {
                saveSortOrder();
                const overlay = document.getElementById('orp-settings-overlay');
                if (overlay) {
                    overlay.classList.remove('show');
                    document.body.classList.remove('settings-open');
                }
            });
        }
        
        if (cancelBtn) {
            cancelBtn.addEventListener('click', () => {
                currentSortOrder = [...originalSortOrder];
                updateSortList();
            });
        }
        
        // loadSortOrder()の呼び出しは削除(init()から遅延実行される)
    }
    
    function initDarkMode() {
        const isDarkMode = storage.get('darkMode') === 'true';
        if (isDarkMode) {
            document.body.classList.add('dark-mode');
        }
        
        const isDarkModeRight = storage.get('darkModeRight') === 'true';
        if (isDarkModeRight) {
            document.body.classList.add('dark-mode-right');
            
            // RIGHT側フルダークモード(RIGHT側ダークモードがONの場合のみ)
            const isDarkModeRightFull = storage.get('darkModeRightFull') === 'true';
            if (isDarkModeRightFull) {
                document.body.classList.add('dark-mode-right-full');
            }
        }
    }
    
    function insertSeparator() {
        const srBars = document.querySelectorAll('#sr-header-area .sr-bar');
        const userSubsBar = srBars[1]; // 登録サブレディット
        
        if (!userSubsBar) {
            console.warn('[ORP] User subreddits bar not found, separator not inserted');
            return;
        }
        
        // すでにスペーサーが存在する場合は追加しない
        if (userSubsBar.querySelector('.orp-separator')) {
            return;
        }
        
        // スペーサーを作成
        const separator = document.createElement('li');
        separator.className = 'orp-separator';
        
        // 登録サブレディットバーの最初に挿入
        if (userSubsBar.firstChild) {
            userSubsBar.insertBefore(separator, userSubsBar.firstChild);
        } else {
            userSubsBar.appendChild(separator);
        }
        
        console.log('[ORP] Separator inserted successfully');
    }
    
    function initLeftSidebar(button) {
        // スペーサー(区切り線)を挿入
        insertSeparator();
        
        // ページロード時は常にSUBSを閉じた状態で開始(ページ遷移時の暗転を防ぐ)
        document.body.classList.remove('show-left');
        storage.set('leftSidebarVisible', false);
        button.style.display = '';
        
        button.addEventListener('click', function(e) {
            e.stopPropagation();
            document.body.classList.toggle('show-left');
            const isNowVisible = document.body.classList.contains('show-left');
            storage.set('leftSidebarVisible', isNowVisible);
            
            // SUBS表示時はフロートボタンを非表示
            if (isNowVisible) {
                button.style.display = 'none';
            }
        });
        
        document.addEventListener('click', function(e) {
            const sidebar = document.getElementById('sr-header-area');
            const isOpen = document.body.classList.contains('show-left');
            
            if (isOpen && sidebar && !sidebar.contains(e.target) && e.target !== button) {
                document.body.classList.remove('show-left');
                storage.set('leftSidebarVisible', false);
                // SUBSがひっこんだらフロートボタンを表示
                button.style.display = '';
            }
        });
        
        const sidebar = document.getElementById('sr-header-area');
        if (sidebar) {
            sidebar.addEventListener('click', function(e) {
                e.stopPropagation();
                
                // SUBSメニュー内のリンククリック時に即座にメニューを閉じる
                if (e.target.tagName === 'A') {
                    document.body.classList.remove('show-left');
                    storage.set('leftSidebarVisible', false);
                    // フロートボタンを表示
                    button.style.display = '';
                }
            });
        }
    }
    
    function updateSubsPosition() {
        // ヘッダーの実際の高さを取得してSUBSの位置を動的に調整
        const header = document.getElementById('header');
        const subs = document.getElementById('sr-header-area');
        
        if (header && subs) {
            const headerHeight = header.offsetHeight || 0;
            subs.style.top = `${headerHeight}px`;
            subs.style.height = `calc(100vh - ${headerHeight}px)`;
            console.log('[NOR] SUBS position updated: headerHeight =', headerHeight);
        }
    }
    
    // ===================================
    // 言語リソース(多言語対応)
    // ===================================
    const i18n = {
        en: {
            language: {
                label: 'Language'
            },
            buttons: {
                leftToggle: 'Toggle LEFT sidebar',
                settingsText: '⚙️ Settings',
                settingsTitle: 'Open settings panel'
            },
            settings: {
                title: 'OldRedditPlus Settings',
                close: '×'
            },
            tabs: {
                menuButton: 'Menu Button',
                menu: 'Menu',
                sort: 'Sort'
            },
            sort: {
                save: 'Save',
                cancel: 'Cancel'
            },
            darkMode: {
                label: 'Dark Mode',
                description: 'Toggle dark mode on/off (RIGHT side is excluded as much as possible)'
            },
            darkModeRight: {
                label: 'RIGHT Side Dark Mode',
                description: 'Apply minimal dark mode to the RIGHT sidebar (safe common styles only)'
            },
            darkModeRightFull: {
                label: '⚠️ Apply Full Dark Mode',
                description: 'WARNING: May break subreddit-specific designs'
            },
            menuColor: {
                label: 'Menu Button Color Settings',
                description: 'Set the background color of the left sidebar toggle button (adjust in 5-step increments)',
                preview: 'Preview:'
            },
            menuSize: {
                label: 'Menu Button Size Settings',
                description: 'Set the width and height of the left sidebar toggle button',
                width: 'Width:',
                height: 'Height:',
                reset: 'Reset to Default'
            },
            menuOffset: {
                label: 'Vertical Offset Settings',
                description: 'Adjust the vertical position of the menu button (negative = up, positive = down)',
                position: 'Position:',
                reset: 'Reset to Default'
            },
            subsSettings: {
                fontSize: {
                    label: 'SUBS Font Size',
                    description: 'Set the font size of subreddit names',
                    size: 'Size:',
                    reset: 'Default'
                },
                margin: {
                    label: 'SUBS Row Vertical Margin',
                    description: 'Set the vertical margin of subreddit rows',
                    margin: 'Margin:',
                    reset: 'Default'
                },
                topOffset: {
                    label: 'SUBS Top Offset',
                    description: 'Adjust the top position of the subreddit list',
                    offset: 'Offset:',
                    reset: 'Default'
                },
                lrOffset: {
                    label: 'SUBS Horizontal Offset',
                    description: 'Adjust the horizontal position of subreddit names',
                    offset: 'Offset:',
                    reset: 'Default'
                }
            },
            preview: {
                title: 'Preview'
            }
        },
        ja: {
            language: {
                label: '言語'
            },
            buttons: {
                leftToggle: 'LEFTサイドバーの表示/非表示',
                settingsText: '⚙️ 設定',
                settingsTitle: '設定画面を開く'
            },
            settings: {
                title: 'Oldredditplus設定画面',
                close: '×'
            },
            tabs: {
                menuButton: 'メニューボタン',
                menu: 'メニュー',
                sort: 'ソート'
            },
            sort: {
                save: '保存',
                cancel: 'キャンセル'
            },
            darkMode: {
                label: 'ダークモード',
                description: 'ダークモードのオン/オフを切り替えます(RIGHT側はなるべく除外)'
            },
            darkModeRight: {
                label: 'RIGHT側ダークモード',
                description: 'RIGHT側サイドバーにも最小限のダークモードを適用します(サブレディット共通で安全な範囲のみ)'
            },
            darkModeRightFull: {
                label: '⚠️ フルダークモードを適用',
                description: '問題が起こりやすいです:サブレディット固有のデザインが崩れる可能性があります'
            },
            menuColor: {
                label: 'メニューボタンの色設定',
                description: '左サイドバートグルボタンの背景色を設定します(5段階で調整)',
                preview: 'プレビュー:'
            },
            menuSize: {
                label: 'メニューボタンのサイズ設定',
                description: '左サイドバートグルボタンの幅と高さを設定します',
                width: '幅:',
                height: '高さ:',
                reset: '規定値にリセット'
            },
            menuOffset: {
                label: '上下オフセット設定',
                description: 'メニューボタンの上下位置を調整します(マイナスで上、プラスで下)',
                position: '位置:',
                reset: '規定値にリセット'
            },
            subsSettings: {
                fontSize: {
                    label: 'SUBS文字サイズ',
                    description: 'サブレディット名の文字サイズを設定します',
                    size: 'サイズ:',
                    reset: '規定値'
                },
                margin: {
                    label: 'SUBS行の上下マージン',
                    description: 'サブレディット行の上下マージンを設定します',
                    margin: 'マージン:',
                    reset: '規定値'
                },
                topOffset: {
                    label: 'SUBS上端オフセット',
                    description: 'サブレディットリストの上端位置を調整します',
                    offset: 'オフセット:',
                    reset: '規定値'
                },
                lrOffset: {
                    label: 'SUBS文字列の左右オフセット',
                    description: 'サブレディット名の左右位置を調整します',
                    offset: 'オフセット:',
                    reset: '規定値'
                }
            },
            preview: {
                title: 'プレビュー'
            }
        }
    };
    
    // 現在の言語を保持(デフォルトは英語)
    let currentLang = storage.get('language', 'en');
    if (currentLang !== 'en' && currentLang !== 'ja') {
        currentLang = 'en';
    }
    
    // 言語リソースを取得するヘルパー関数
    function t(path) {
        const keys = path.split('.');
        let result = i18n[currentLang];
        for (const key of keys) {
            result = result[key];
            if (!result) {
                console.warn(`[NOR] Missing translation: ${path} (${currentLang})`);
                return path;
            }
        }
        return result;
    }
    
    // 言語を変更してUIを更新
    function updateLanguage(lang) {
        if (lang !== 'en' && lang !== 'ja') {
            console.warn(`[NOR] Invalid language: ${lang}`);
            return;
        }
        currentLang = lang;
        storage.set('language', lang);
        
        // ボタンのテキストを更新
        const leftToggleBtn = document.getElementById('orp-left-sidebar-toggle');
        if (leftToggleBtn) {
            leftToggleBtn.title = t('buttons.leftToggle');
        }
        
        const settingsBtn = document.getElementById('orp-settings-button');
        if (settingsBtn) {
            settingsBtn.textContent = t('buttons.settingsText');
            settingsBtn.title = t('buttons.settingsTitle');
        }
        
        // 設定パネルが存在する場合は更新
        updateSettingsPanelLanguage();
    }
    
    // 設定パネルの言語を更新
    function updateSettingsPanelLanguage() {
        const panel = document.getElementById('orp-settings-panel');
        if (!panel) return;
        
        // タイトル
        const title = panel.querySelector('#orp-settings-header h2');
        if (title) title.textContent = t('settings.title');
        
        // タブ
        const tabMenuButton = panel.querySelector('[data-tab="menu-button"]');
        if (tabMenuButton) tabMenuButton.textContent = t('tabs.menuButton');
        
        const tabMenu = panel.querySelector('[data-tab="menu"]');
        if (tabMenu) tabMenu.textContent = t('tabs.menu');
        
        const tabSort = panel.querySelector('[data-tab="sort"]');
        if (tabSort) tabSort.textContent = t('tabs.sort');
        
        // ソートボタン
        const sortSaveBtn = document.getElementById('orp-sort-save');
        if (sortSaveBtn) sortSaveBtn.textContent = t('sort.save');
        
        const sortCancelBtn = document.getElementById('orp-sort-cancel');
        if (sortCancelBtn) sortCancelBtn.textContent = t('sort.cancel');
        
        // 各設定項目
        const updates = [
            { selector: '[data-i18n="language.label"]', text: t('language.label') },
            { selector: '[data-i18n="darkMode.label"]', text: t('darkMode.label') },
            { selector: '[data-i18n="darkMode.description"]', text: t('darkMode.description') },
            { selector: '[data-i18n="darkModeRight.label"]', text: t('darkModeRight.label') },
            { selector: '[data-i18n="darkModeRight.description"]', text: t('darkModeRight.description') },
            { selector: '[data-i18n="darkModeRightFull.label"]', text: t('darkModeRightFull.label') },
            { selector: '[data-i18n="darkModeRightFull.description"]', text: t('darkModeRightFull.description') },
            { selector: '[data-i18n="menuColor.label"]', text: t('menuColor.label') },
            { selector: '[data-i18n="menuColor.description"]', text: t('menuColor.description') },
            { selector: '[data-i18n="menuColor.preview"]', text: t('menuColor.preview') },
            { selector: '[data-i18n="menuSize.label"]', text: t('menuSize.label') },
            { selector: '[data-i18n="menuSize.description"]', text: t('menuSize.description') },
            { selector: '[data-i18n="menuSize.width"]', text: t('menuSize.width') },
            { selector: '[data-i18n="menuSize.height"]', text: t('menuSize.height') },
            { selector: '[data-i18n="menuSize.reset"]', text: t('menuSize.reset') },
            { selector: '[data-i18n="menuOffset.label"]', text: t('menuOffset.label') },
            { selector: '[data-i18n="menuOffset.description"]', text: t('menuOffset.description') },
            { selector: '[data-i18n="menuOffset.position"]', text: t('menuOffset.position') },
            { selector: '[data-i18n="menuOffset.reset"]', text: t('menuOffset.reset') },
            { selector: '[data-i18n="subsSettings.fontSize.label"]', text: t('subsSettings.fontSize.label') },
            { selector: '[data-i18n="subsSettings.fontSize.description"]', text: t('subsSettings.fontSize.description') },
            { selector: '[data-i18n="subsSettings.fontSize.size"]', text: t('subsSettings.fontSize.size') },
            { selector: '[data-i18n="subsSettings.fontSize.reset"]', text: t('subsSettings.fontSize.reset') },
            { selector: '[data-i18n="subsSettings.margin.label"]', text: t('subsSettings.margin.label') },
            { selector: '[data-i18n="subsSettings.margin.description"]', text: t('subsSettings.margin.description') },
            { selector: '[data-i18n="subsSettings.margin.margin"]', text: t('subsSettings.margin.margin') },
            { selector: '[data-i18n="subsSettings.margin.reset"]', text: t('subsSettings.margin.reset') },
            { selector: '[data-i18n="subsSettings.topOffset.label"]', text: t('subsSettings.topOffset.label') },
            { selector: '[data-i18n="subsSettings.topOffset.description"]', text: t('subsSettings.topOffset.description') },
            { selector: '[data-i18n="subsSettings.topOffset.offset"]', text: t('subsSettings.topOffset.offset') },
            { selector: '[data-i18n="subsSettings.topOffset.reset"]', text: t('subsSettings.topOffset.reset') },
            { selector: '[data-i18n="subsSettings.lrOffset.label"]', text: t('subsSettings.lrOffset.label') },
            { selector: '[data-i18n="subsSettings.lrOffset.description"]', text: t('subsSettings.lrOffset.description') },
            { selector: '[data-i18n="subsSettings.lrOffset.offset"]', text: t('subsSettings.lrOffset.offset') },
            { selector: '[data-i18n="subsSettings.lrOffset.reset"]', text: t('subsSettings.lrOffset.reset') },
            { selector: '[data-i18n="preview.title"]', text: t('preview.title') }
        ];
        
        updates.forEach(({ selector, text }) => {
            const el = panel.querySelector(selector);
            if (el) el.textContent = text;
        });
    }
    
    function init() {
        if (document.readyState === 'loading') {
            document.addEventListener('DOMContentLoaded', init);
            return;
        }
        
        const buttons = createToggleButtons();
        if (buttons) {
            initDarkMode();
            initLeftSidebar(buttons.leftToggleBtn);
            initSettingsPanel();
            
            // SUBS位置の初期設定と動的更新
            updateSubsPosition();
            // ウィンドウリサイズ時に再計算
            window.addEventListener('resize', updateSubsPosition);
            // ヘッダー変更を監視(MutationObserver)
            const header = document.getElementById('header');
            if (header) {
                const observer = new MutationObserver(updateSubsPosition);
                observer.observe(header, { attributes: true, childList: true, subtree: true });
            }
            
            // ソート順を遅延読み込み(Reddit側のDOM生成を待つ)
            setTimeout(() => {
                loadSortOrderWithRetry();
            }, 100);
            
            console.log('[NOR] Overlay MVP with Settings Panel initialized');
        }
    }
    
    init();
})();