diff --git a/src/acore-wp-plugin/src/Hooks/Various/DarkMode.php b/src/acore-wp-plugin/src/Hooks/Various/DarkMode.php
new file mode 100644
index 000000000..2cebc0915
--- /dev/null
+++ b/src/acore-wp-plugin/src/Hooks/Various/DarkMode.php
@@ -0,0 +1,149 @@
+add_node([
+ 'id' => 'acore-dark-mode',
+ 'parent' => 'top-secondary',
+ 'title' => '' . ($is_dark ? '☀' : '☾') . '',
+ 'href' => '#',
+ 'meta' => ['title' => $is_dark ? 'Switch to light mode' : 'Switch to dark mode'],
+ ]);
+}
+
+add_filter('admin_body_class', __NAMESPACE__ . '\acore_dark_mode_body_class');
+
+function acore_dark_mode_body_class($classes) {
+ if (get_user_meta(get_current_user_id(), 'acore_dark_mode', true) === '1') {
+ $classes .= ' acore-dark-mode';
+ }
+ return $classes;
+}
+
+add_action('admin_enqueue_scripts', __NAMESPACE__ . '\acore_dark_mode_enqueue');
+
+function acore_dark_mode_enqueue() {
+ wp_enqueue_style('acore-css', ACORE_URL_PLG . 'web/assets/css/main.css', [], '3.0');
+ wp_enqueue_style('acore-dark-mode', ACORE_URL_PLG . 'web/assets/css/dark-mode.css', ['acore-css'], '3.7');
+ // Central light/dark theme layer (edit colours here). Loaded last so it wins.
+ wp_enqueue_style('acore-theme', ACORE_URL_PLG . 'web/assets/css/theme.css', ['acore-dark-mode'], '3.7');
+
+ $nonce = wp_create_nonce('acore_dark_mode');
+ wp_add_inline_script('jquery-core', acore_dark_mode_js($nonce));
+}
+
+/*
+ * Late inline
+
+
+ $new === '1']);
+}
+
+function acore_dark_mode_js(string $nonce): string {
+ return << a', function(e){
+ e.preventDefault();
+ $.post(ajaxurl, { action: 'acore_toggle_dark_mode', nonce: nonce }, function(res){
+ if (!res.success) return;
+ var dark = res.data.dark;
+ $('body').toggleClass('acore-dark-mode', dark);
+ $('#acore-dm-icon').html(dark ? '☀' : '☾');
+ $('#wp-admin-bar-acore-dark-mode > a').attr('title', dark ? 'Switch to light mode' : 'Switch to dark mode');
+ });
+ });
+})(jQuery);
+JS;
+}
+
+/*
+ * The WP 2FA setup wizard (profile.php?page=wp-2fa-setup) renders a sealed
+ * full-page template that only prints its own stylesheets. It exposes
+ * `wp_2fa_setup_page_scripts` inside its ; we use it to inject theme.css
+ * (whose body.wp2fa-setup rules are dark) only when the user has dark mode on.
+ */
+add_action('wp_2fa_setup_page_scripts', __NAMESPACE__ . '\acore_dark_mode_wizard_css');
+
+function acore_dark_mode_wizard_css() {
+ if (get_user_meta(get_current_user_id(), 'acore_dark_mode', true) !== '1') {
+ return;
+ }
+ echo '' . "\n";
+}
diff --git a/src/acore-wp-plugin/src/Utils/AcoreCharColors.php b/src/acore-wp-plugin/src/Utils/AcoreCharColors.php
new file mode 100644
index 000000000..13620f841
--- /dev/null
+++ b/src/acore-wp-plugin/src/Utils/AcoreCharColors.php
@@ -0,0 +1,109 @@
+ 'Warrior',
+ 2 => 'Paladin',
+ 3 => 'Hunter',
+ 4 => 'Rogue',
+ 5 => 'Priest',
+ 6 => 'Death Knight',
+ 7 => 'Shaman',
+ 8 => 'Mage',
+ 9 => 'Warlock',
+ 11 => 'Druid',
+ ];
+
+ const CLASS_COLORS = [
+ 1 => ['light' => '#C69B6D', 'dark' => '#C69B6D'], // Warrior
+ 2 => ['light' => '#F48CBA', 'dark' => '#F48CBA'], // Paladin
+ 3 => ['light' => '#AAD372', 'dark' => '#AAD372'], // Hunter
+ 4 => ['light' => '#C8A800', 'dark' => '#FFF468'], // Rogue (yellow → darkened for light bg)
+ 5 => ['light' => '#909090', 'dark' => '#E0E0E0'], // Priest (white → grey for light bg)
+ 6 => ['light' => '#C41E3A', 'dark' => '#FF3355'], // Death Knight
+ 7 => ['light' => '#0070DD', 'dark' => '#3399FF'], // Shaman
+ 8 => ['light' => '#3FC7EB', 'dark' => '#3FC7EB'], // Mage
+ 9 => ['light' => '#8788EE', 'dark' => '#9A9BFF'], // Warlock
+ 11 => ['light' => '#FF7C0A', 'dark' => '#FF7C0A'], // Druid
+ ];
+
+ const FALLBACK_LIGHT = '#646970';
+ const FALLBACK_DARK = '#8b949e';
+
+ const RACE_NAMES = [
+ 1 => 'Human',
+ 2 => 'Orc',
+ 3 => 'Dwarf',
+ 4 => 'Night Elf',
+ 5 => 'Undead',
+ 6 => 'Tauren',
+ 7 => 'Gnome',
+ 8 => 'Troll',
+ 10 => 'Blood Elf',
+ 11 => 'Draenei',
+ ];
+
+ /** Maps race ID → faction. */
+ const RACE_FACTION = [
+ 1 => 'alliance', // Human
+ 2 => 'horde', // Orc
+ 3 => 'alliance', // Dwarf
+ 4 => 'alliance', // Night Elf
+ 5 => 'horde', // Undead
+ 6 => 'horde', // Tauren
+ 7 => 'alliance', // Gnome
+ 8 => 'horde', // Troll
+ 10 => 'horde', // Blood Elf
+ 11 => 'alliance', // Draenei
+ ];
+
+ public static function getClassName(int $classId): string {
+ return self::CLASS_NAMES[$classId] ?? 'Unknown';
+ }
+
+ public static function getRaceName(int $raceId): string {
+ return self::RACE_NAMES[$raceId] ?? 'Unknown';
+ }
+
+ public static function getFaction(int $raceId): string {
+ return self::RACE_FACTION[$raceId] ?? 'unknown';
+ }
+
+ /**
+ * Returns inline style string for a character row.
+ * Uses CSS custom properties so dark-mode.css can override via color-mix.
+ */
+ public static function rowStyle(int $classId, int $raceId): string {
+ $cls = self::CLASS_COLORS[$classId] ?? ['light' => self::FALLBACK_LIGHT, 'dark' => self::FALLBACK_DARK];
+ $faction = self::RACE_FACTION[$raceId] ?? 'unknown';
+ $fLight = $faction === 'alliance' ? '#3FACF4' : '#FF653D';
+ $fDark = $faction === 'alliance' ? '#3FACF4' : '#FF653D';
+ return sprintf(
+ '--cls-light:%s; --cls-dark:%s; --faction-color:%s; border-top:2px solid %s; border-right:2px solid %s; border-bottom:2px solid %s; border-left:4px solid %s;',
+ $cls['light'], $cls['dark'], $fLight,
+ $fLight, $fLight, $fLight, $cls['light']
+ );
+ }
+
+ /** Returns the expansion slug for a level, used as data-exp attribute. */
+ public static function expansionSlug(int $level): string {
+ if ($level <= 60) return 'vanilla';
+ if ($level <= 70) return 'tbc';
+ return 'wrath';
+ }
+
+ /** Returns the expansion label for a level, used as title attribute. */
+ public static function expansionLabel(int $level): string {
+ if ($level <= 60) return 'Classic';
+ if ($level <= 70) return 'The Burning Crusade';
+ return 'Wrath of the Lich King';
+ }
+}
diff --git a/src/acore-wp-plugin/src/boot.php b/src/acore-wp-plugin/src/boot.php
index 7a280f60a..a7b832cf3 100644
--- a/src/acore-wp-plugin/src/boot.php
+++ b/src/acore-wp-plugin/src/boot.php
@@ -3,6 +3,7 @@
define('FS_METHOD', 'direct');
require_once ACORE_PATH_PLG . 'src/Utils/AcoreUtils.php';
+require_once ACORE_PATH_PLG . 'src/Utils/AcoreCharColors.php';
require_once ACORE_PATH_PLG . 'src/Deps/class-tgm-plugin-activation.php';
@@ -18,6 +19,7 @@
require_once ACORE_PATH_PLG . 'src/Hooks/Subscriptions/sync_subscription.php';
require_once ACORE_PATH_PLG . 'src/Hooks/Various/tgmplugin_activator.php';
+require_once ACORE_PATH_PLG . 'src/Hooks/Various/DarkMode.php';
require_once ACORE_PATH_PLG . 'src/Hooks/User/Include.php';
diff --git a/src/acore-wp-plugin/web/assets/css/dark-mode.css b/src/acore-wp-plugin/web/assets/css/dark-mode.css
new file mode 100644
index 000000000..ebc10dfe0
--- /dev/null
+++ b/src/acore-wp-plugin/web/assets/css/dark-mode.css
@@ -0,0 +1,706 @@
+/*
+Acore dark mode overrides
+*/
+
+/* ============================================================
+ Profile page & sub-tabs — dark mode appearance overrides only
+ (layout/spacing lives in main.css and loads for all modes)
+ ============================================================ */
+
+body.acore-dark-mode.profile-php #wpbody-content h2,
+body.acore-dark-mode.profile-php #wpbody-content h3 {
+ border-bottom-color: #30363d;
+}
+
+/* dark mode tweaks for security page */
+body.acore-dark-mode #acore-security-page .postbox {
+ box-shadow: 0 1px 4px rgba(0, 0, 0, 0.3);
+}
+
+/* Fix hardcoded dark thead in item restoration — let dark mode handle it */
+body.acore-dark-mode #acore-item-restoration-page .table thead {
+ background: #1d2327;
+ color: #fff;
+}
+
+/* --- Item Restoration dark mode --- */
+body.acore-dark-mode #acore-item-restoration-page .table {
+ color: #c9d1d9;
+ border-color: #30363d;
+ --bs-table-bg: transparent;
+ --bs-table-striped-bg: transparent;
+ --bs-table-border-color: #30363d;
+}
+
+body.acore-dark-mode #acore-item-restoration-page .table > :not(caption) > * > * {
+ background-color: #161b22 !important;
+ border-bottom-color: #30363d !important;
+ color: #c9d1d9 !important;
+ --bs-table-bg: #161b22;
+ --bs-table-color: #c9d1d9;
+}
+
+body.acore-dark-mode #acore-item-restoration-page .table thead tr th {
+ background: #21262d !important;
+ color: #e6edf3 !important;
+ border-color: #30363d !important;
+}
+
+body.acore-dark-mode #acore-item-restoration-page .table tbody td,
+body.acore-dark-mode #acore-item-restoration-page .table tbody th {
+ background: #161b22 !important;
+ color: #c9d1d9 !important;
+ border-color: #30363d !important;
+}
+
+/* alert-info (no items / info messages) */
+body.acore-dark-mode #acore-item-restoration-page .alert-info {
+ background-color: #1a2f1a !important;
+ border-color: #2d6a2d !important;
+ color: #56d364 !important;
+}
+
+/* active character row */
+body.acore-dark-mode #acore-characters-item-restore .acore-char-row.active {
+ background: #21262d !important;
+ border-top-color: var(--faction-color, #58a6ff) !important;
+ border-right-color: var(--faction-color, #58a6ff) !important;
+ border-bottom-color: var(--faction-color, #58a6ff) !important;
+ border-top-width: 3px !important;
+ border-right-width: 3px !important;
+ border-bottom-width: 3px !important;
+}
+
+/* ============================================================ */
+
+/* --- expansion selector (profile page) --- */
+.acore-expansion-wrapper {
+ position: relative;
+ padding-top: 14px;
+ margin-bottom: 8px;
+}
+
+.acore-expansion-arrow {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 0;
+ height: 0;
+ border-left: 8px solid transparent;
+ border-right: 8px solid transparent;
+ border-top: 10px solid #646970;
+ transform: translateX(-50%);
+ transition: left 0.15s ease;
+}
+
+.acore-expansion-selector {
+ display: flex;
+ gap: 8px;
+ flex-wrap: wrap;
+}
+
+.acore-expansion-option {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ padding: 7px 14px 7px 10px;
+ background: #fff;
+ border: 1px solid #dcdcde;
+ border-left: 4px solid var(--exp-color, #646970);
+ border-radius: 2px;
+ cursor: pointer;
+}
+
+.acore-expansion-option input[type="radio"] {
+ position: absolute;
+ width: 1px;
+ height: 1px;
+ margin: -1px;
+ padding: 0;
+ border: 0;
+ overflow: hidden;
+ clip-path: inset(50%);
+ white-space: nowrap;
+}
+
+.acore-expansion-option .acore-expansion-label {
+ font-weight: 600;
+ font-size: 13px;
+ color: var(--exp-color, #646970);
+}
+
+.acore-expansion-option.is-selected {
+ box-shadow: 0 0 0 2px var(--exp-color, #646970);
+}
+
+.acore-expansion-option:hover {
+ background: #f6f7f7;
+}
+
+.acore-expansion-warning {
+ color: #8a6d3b;
+ background: #fcf8e3;
+ border-left: 4px solid #f0ad4e;
+ border-radius: 2px;
+ padding: 8px 12px;
+ margin: 0;
+ font-size: 12px;
+ max-width: 520px;
+}
+
+/* dark mode */
+body.acore-dark-mode .acore-expansion-option {
+ background: #1c2128 !important;
+ border-top-color: #30363d !important;
+ border-right-color: #30363d !important;
+ border-bottom-color: #30363d !important;
+ border-left-color: var(--exp-color, #8b949e) !important;
+}
+
+body.acore-dark-mode .acore-expansion-option:hover {
+ background: #262d36 !important;
+}
+
+body.acore-dark-mode .acore-expansion-option.is-selected {
+ box-shadow: 0 0 0 2px var(--exp-color, #8b949e) !important;
+}
+
+body.acore-dark-mode .acore-expansion-warning {
+ background: #2d2208 !important;
+ border-left-color: #f0ad4e !important;
+ color: #d4a843 !important;
+}
+
+/* --- admin bar toggle icon --- */
+#wp-admin-bar-acore-dark-mode > .ab-item {
+ padding: 0 8px !important;
+ cursor: pointer;
+ display: flex !important;
+ align-items: center;
+ height: 32px;
+}
+
+#wp-admin-bar-acore-dark-mode > .ab-item #acore-dm-icon {
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ width: 28px;
+ height: 28px;
+ font-size: 18px;
+ line-height: 1;
+ border: 1px solid rgba(255, 255, 255, 0.35);
+ border-radius: 5px;
+ padding: 2px;
+}
+
+/* --- Bootstrap 5 CSS variable overrides (must come before class rules) --- */
+body.acore-dark-mode {
+ --bs-body-bg: #0d1117;
+ --bs-body-color: #c9d1d9;
+ --bs-card-bg: #161b22;
+ --bs-card-border-color: #30363d;
+ --bs-card-cap-bg: #0d1117;
+ --bs-border-color: #30363d;
+ --bs-secondary-color: #8b949e;
+ --bs-link-color: #58a6ff;
+ --bs-link-hover-color: #79c0ff;
+ --bs-list-group-bg: #161b22;
+ --bs-list-group-border-color: #30363d;
+ --bs-list-group-color: #c9d1d9;
+}
+
+/* --- base --- */
+body.acore-dark-mode,
+body.acore-dark-mode #wpwrap {
+ background: #0d1117;
+ color: #c9d1d9;
+}
+
+body.acore-dark-mode #wpcontent,
+body.acore-dark-mode #wpfooter {
+ background: #0d1117;
+}
+
+body.acore-dark-mode #wpbody-content {
+ background: #0d1117;
+}
+
+/* --- headings & text --- */
+body.acore-dark-mode h1,
+body.acore-dark-mode h2,
+body.acore-dark-mode h3,
+body.acore-dark-mode h4,
+body.acore-dark-mode h5,
+body.acore-dark-mode p,
+body.acore-dark-mode label,
+body.acore-dark-mode span,
+body.acore-dark-mode li {
+ color: #c9d1d9;
+}
+
+body.acore-dark-mode .description,
+body.acore-dark-mode .text-muted {
+ color: #8b949e !important;
+}
+
+body.acore-dark-mode hr {
+ border-color: #30363d;
+}
+
+/* --- postboxes (WP core) --- */
+body.acore-dark-mode .postbox,
+body.acore-dark-mode #poststuff .postbox {
+ background: #161b22;
+ border-color: #30363d;
+}
+
+body.acore-dark-mode .postbox-header {
+ background: #161b22;
+ border-bottom-color: #30363d;
+}
+
+body.acore-dark-mode .postbox-header h2,
+body.acore-dark-mode .postbox-header .hndle {
+ color: #c9d1d9;
+}
+
+body.acore-dark-mode .postbox .inside {
+ color: #c9d1d9;
+}
+
+/* --- Bootstrap card --- */
+body.acore-dark-mode .card {
+ background-color: #161b22 !important;
+ border-color: #30363d !important;
+ color: #c9d1d9 !important;
+}
+
+body.acore-dark-mode .card-body {
+ background-color: #161b22 !important;
+ color: #c9d1d9 !important;
+}
+
+body.acore-dark-mode .card-header {
+ background-color: #0d1117 !important;
+ border-bottom-color: #30363d !important;
+ color: #c9d1d9 !important;
+}
+
+body.acore-dark-mode .card-title {
+ color: #c9d1d9 !important;
+}
+
+/* --- Character list rows --- */
+body.acore-dark-mode .acore-char-row {
+ background: #1c2128 !important;
+ /* faction color for top/right/bottom, dimmed for dark mode */
+ border-top-color: color-mix(in srgb, var(--faction-color, #30363d) 55%, #0d1117) !important;
+ border-right-color: color-mix(in srgb, var(--faction-color, #30363d) 55%, #0d1117) !important;
+ border-bottom-color: color-mix(in srgb, var(--faction-color, #30363d) 55%, #0d1117) !important;
+ border-left-color: var(--cls-dark, #8b949e) !important;
+}
+
+body.acore-dark-mode .acore-char-pos {
+ color: #e6edf3 !important;
+ background: rgba(255, 255, 255, 0.12) !important;
+}
+
+body.acore-dark-mode .acore-char-name {
+ color: #c9d1d9 !important;
+}
+
+body.acore-dark-mode .acore-char-meta {
+ color: #8b949e !important;
+}
+
+body.acore-dark-mode .acore-char-row:hover {
+ background: #262d36 !important;
+}
+
+body.acore-dark-mode #acore-characters-mail .acore-char-row.active {
+ background: #21262d !important;
+ border-top-color: var(--faction-color, #58a6ff) !important;
+ border-right-color: var(--faction-color, #58a6ff) !important;
+ border-bottom-color: var(--faction-color, #58a6ff) !important;
+ border-top-width: 3px !important;
+ border-right-width: 3px !important;
+ border-bottom-width: 3px !important;
+}
+
+/* --- Bootstrap form-select --- */
+body.acore-dark-mode .form-select {
+ background-color: #0d1117 !important;
+ border-color: #30363d !important;
+ color: #c9d1d9 !important;
+}
+
+body.acore-dark-mode .form-select:focus {
+ border-color: #58a6ff !important;
+ box-shadow: 0 0 0 0.2rem rgba(88, 166, 255, 0.25) !important;
+}
+
+/* --- form elements --- */
+body.acore-dark-mode input[type="text"],
+body.acore-dark-mode input[type="password"],
+body.acore-dark-mode input[type="email"],
+body.acore-dark-mode input[type="number"],
+body.acore-dark-mode input[type="search"],
+body.acore-dark-mode input[type="url"],
+body.acore-dark-mode select,
+body.acore-dark-mode textarea {
+ background-color: #0d1117;
+ border-color: #30363d;
+ color: #c9d1d9;
+ box-shadow: none;
+}
+
+body.acore-dark-mode input[type="text"]:focus,
+body.acore-dark-mode input[type="password"]:focus,
+body.acore-dark-mode select:focus,
+body.acore-dark-mode textarea:focus {
+ border-color: #58a6ff;
+ box-shadow: 0 0 0 1px #58a6ff;
+ outline: none;
+}
+
+body.acore-dark-mode .form-table th {
+ color: #8b949e;
+}
+
+body.acore-dark-mode .form-table td {
+ color: #c9d1d9;
+}
+
+/* --- mail entries — border color comes from JS inline (faction/class), only override bg --- */
+body.acore-dark-mode .mail-entry {
+ background: #161b22 !important;
+ color: #c9d1d9 !important;
+}
+
+body.acore-dark-mode .mail-recipient,
+body.acore-dark-mode .mail-items {
+ background: #0d1117 !important;
+ color: #c9d1d9 !important;
+}
+
+body.acore-dark-mode .mail-header,
+body.acore-dark-mode .mail-meta,
+body.acore-dark-mode .mail-subject,
+body.acore-dark-mode .mail-money,
+body.acore-dark-mode .recipient-name {
+ color: #c9d1d9 !important;
+}
+
+/* --- tables --- */
+body.acore-dark-mode .widefat,
+body.acore-dark-mode .wp-list-table {
+ background: #161b22;
+ border-color: #30363d;
+ color: #c9d1d9;
+}
+
+body.acore-dark-mode .widefat thead th,
+body.acore-dark-mode .widefat tfoot th,
+body.acore-dark-mode .wp-list-table thead th {
+ background: #0d1117;
+ color: #8b949e;
+ border-bottom-color: #30363d;
+}
+
+body.acore-dark-mode .widefat td,
+body.acore-dark-mode .widefat th,
+body.acore-dark-mode .wp-list-table td {
+ color: #c9d1d9;
+ border-bottom-color: #21262d;
+}
+
+body.acore-dark-mode .striped > tbody > :nth-child(odd) > td,
+body.acore-dark-mode .striped > tbody > :nth-child(odd) > th,
+body.acore-dark-mode .alternate {
+ background: #1c2128;
+}
+
+/* --- buttons --- */
+body.acore-dark-mode .button,
+body.acore-dark-mode .button-secondary {
+ background: #21262d;
+ border-color: #30363d;
+ color: #c9d1d9;
+ text-shadow: none;
+ box-shadow: none;
+}
+
+body.acore-dark-mode .button:hover,
+body.acore-dark-mode .button-secondary:hover {
+ background: #30363d;
+ border-color: #8b949e;
+ color: #f0f6fc;
+}
+
+body.acore-dark-mode .button-primary {
+ background: #1f6feb;
+ border-color: #1f6feb;
+ color: #fff;
+ text-shadow: none;
+ box-shadow: none;
+}
+
+body.acore-dark-mode .button-primary:hover {
+ background: #388bfd;
+ border-color: #388bfd;
+}
+
+body.acore-dark-mode .button-primary:disabled,
+body.acore-dark-mode .button-primary[disabled] {
+ background: #1f6feb;
+ opacity: 0.5;
+}
+
+/* --- Bootstrap buttons --- */
+body.acore-dark-mode .btn-primary {
+ background-color: #1f6feb !important;
+ border-color: #1f6feb !important;
+}
+
+body.acore-dark-mode .btn-primary:hover {
+ background-color: #388bfd !important;
+ border-color: #388bfd !important;
+}
+
+body.acore-dark-mode .btn-outline-secondary,
+body.acore-dark-mode .btn-secondary {
+ background-color: #21262d !important;
+ border-color: #30363d !important;
+ color: #c9d1d9 !important;
+}
+
+/* --- notices --- */
+body.acore-dark-mode .notice,
+body.acore-dark-mode div.updated,
+body.acore-dark-mode div.error {
+ background: #161b22;
+ border-color: #30363d;
+ color: #c9d1d9;
+}
+
+body.acore-dark-mode .notice-success,
+body.acore-dark-mode .updated {
+ border-left-color: #3fb950;
+}
+
+body.acore-dark-mode .notice-error,
+body.acore-dark-mode div.error {
+ border-left-color: #f85149;
+}
+
+body.acore-dark-mode .notice-warning {
+ border-left-color: #d29922;
+}
+
+body.acore-dark-mode .notice p,
+body.acore-dark-mode div.updated p,
+body.acore-dark-mode div.error p {
+ color: #c9d1d9;
+}
+
+/* --- links --- */
+body.acore-dark-mode a {
+ color: #58a6ff;
+}
+
+body.acore-dark-mode a:hover {
+ color: #79c0ff;
+}
+
+/* --- footer --- */
+body.acore-dark-mode #wpfooter {
+ border-top-color: #30363d;
+ color: #8b949e;
+}
+
+body.acore-dark-mode #wpfooter a {
+ color: #58a6ff;
+}
+
+/* --- myCred widgets --- */
+body.acore-dark-mode [id^="mycred"],
+body.acore-dark-mode [class^="mycred"],
+body.acore-dark-mode .mycred-wrap,
+body.acore-dark-mode .mycred-widget {
+ background: #161b22 !important;
+ border-color: #30363d !important;
+ color: #c9d1d9 !important;
+}
+
+body.acore-dark-mode .mycred-history,
+body.acore-dark-mode .mycred-history *,
+body.acore-dark-mode #mycred-log-wrap,
+body.acore-dark-mode #mycred-log-wrap * {
+ background: #161b22 !important;
+ color: #c9d1d9 !important;
+ border-color: #30363d !important;
+}
+
+/* WP profile page balance box */
+body.acore-dark-mode #mycred-user-balance,
+body.acore-dark-mode .user-profile-mycred,
+body.acore-dark-mode td.mycred-field,
+body.acore-dark-mode th.mycred-field {
+ color: #c9d1d9 !important;
+}
+
+/* --- Scroll of Resurrection page --- */
+body.acore-dark-mode .acore-rscroll .card {
+ background: #161b22;
+ border-color: #30363d;
+ color: #c9d1d9;
+}
+
+body.acore-dark-mode .acore-rscroll .card-body {
+ color: #c9d1d9;
+}
+
+body.acore-dark-mode .acore-rscroll h5 {
+ color: #e6edf3;
+}
+
+body.acore-dark-mode .acore-rscroll hr {
+ border-color: #30363d;
+ opacity: 1;
+}
+
+body.acore-dark-mode .acore-rscroll .table {
+ color: #c9d1d9;
+ border-color: #30363d;
+ --bs-table-bg: transparent;
+ --bs-table-striped-bg: transparent;
+ --bs-table-border-color: #30363d;
+}
+
+body.acore-dark-mode .acore-rscroll .table > :not(caption) > * > * {
+ background-color: transparent;
+ border-bottom-color: #30363d;
+ color: #ffffff;
+}
+
+/* Row label column (th inside tbody) */
+body.acore-dark-mode .acore-rscroll .table tbody th {
+ background: #21262d !important;
+ color: #e6edf3 !important;
+ font-weight: 600;
+ border-color: #30363d !important;
+}
+
+body.acore-dark-mode .acore-rscroll .table tbody td {
+ background: #161b22 !important;
+ color: #ffffff !important;
+ border-color: #30363d !important;
+}
+
+/* thead row (Player Commands table) */
+body.acore-dark-mode .acore-rscroll .table thead tr th,
+body.acore-dark-mode .acore-rscroll .table-light thead tr th {
+ background: #21262d !important;
+ color: #e6edf3 !important;
+ border-color: #30363d !important;
+}
+
+body.acore-dark-mode .acore-rscroll code {
+ background: #0d1117;
+ color: #f85149;
+ border: 1px solid #30363d;
+ padding: 1px 5px;
+ border-radius: 3px;
+}
+
+body.acore-dark-mode .acore-rscroll .text-muted {
+ color: #8b949e !important;
+}
+
+body.acore-dark-mode .acore-rscroll strong {
+ color: #818cf8;
+}
+
+body.acore-dark-mode .acore-rscroll ol,
+body.acore-dark-mode .acore-rscroll p,
+body.acore-dark-mode .acore-rscroll li {
+ color: #ffffff;
+}
+
+body.acore-dark-mode .acore-rscroll .text-muted {
+ color: #b0b8c4 !important;
+}
+
+/* Force white text on all badges */
+body.acore-dark-mode .acore-rscroll .badge {
+ color: #ffffff !important;
+}
+
+/* Warning badge: yellow is unreadable with white text — shift to solid orange */
+body.acore-dark-mode .acore-rscroll .badge.bg-warning {
+ background-color: #c27400 !important;
+}
+
+/* --- Expansion level badge — dark mode --- */
+body.acore-dark-mode .acore-level { color: #8b949e; }
+body.acore-dark-mode .acore-level[data-exp="vanilla"] { background: rgba(195, 147, 97, 0.18); border-color: #C39361; color: #c9d1d9; }
+body.acore-dark-mode .acore-level[data-exp="tbc"] { background: rgba(98, 201, 7, 0.18); border-color: #62C907; color: #c9d1d9; }
+body.acore-dark-mode .acore-level[data-exp="wrath"] { background: rgba(93, 172, 235, 0.18); border-color: #5DACEB; color: #c9d1d9; }
+
+/* --- Mail Return dark mode --- */
+body.acore-dark-mode #mail-return-heading {
+ color: #e6edf3 !important;
+}
+
+body.acore-dark-mode #mail-return-items .mail-entry {
+ background: #161b22;
+ border-color: #30363d;
+}
+
+body.acore-dark-mode #mail-return-items .mail-header {
+ background: #0d1117;
+ border-bottom-color: #30363d;
+}
+
+body.acore-dark-mode #mail-return-items .mail-recipient,
+body.acore-dark-mode #mail-return-items .mail-subject,
+body.acore-dark-mode #mail-return-items .mail-meta {
+ color: #c9d1d9;
+}
+
+body.acore-dark-mode #mail-return-items .mail-to-label,
+body.acore-dark-mode #mail-return-items .mail-subject-label {
+ color: #8b949e;
+}
+
+body.acore-dark-mode #mail-return-items .mail-items-grid {
+ background: #0d1117;
+ border-top-color: #30363d;
+}
+
+body.acore-dark-mode #mail-return-items .mail-item-slot {
+ background: #161b22;
+}
+
+body.acore-dark-mode #mail-return-items .mail-item-slot a {
+ color: #c9d1d9;
+}
+
+body.acore-dark-mode #mail-return-items .mail-cod-label {
+ color: #8b949e;
+}
+
+body.acore-dark-mode .mail-return-button {
+ background: #21262d !important;
+ border-color: #30363d !important;
+ color: #c9d1d9 !important;
+}
+
+body.acore-dark-mode .mail-return-button:hover {
+ background: #30363d !important;
+ color: #e6edf3 !important;
+}
+
+body.acore-dark-mode #mail-return-empty {
+ color: #8b949e;
+}
diff --git a/src/acore-wp-plugin/web/assets/css/main.css b/src/acore-wp-plugin/web/assets/css/main.css
index f36f2ab4e..f12f03ed6 100644
--- a/src/acore-wp-plugin/web/assets/css/main.css
+++ b/src/acore-wp-plugin/web/assets/css/main.css
@@ -17,62 +17,187 @@ body {
background-color: var(--bs-teal) !important;
}
-/* start char-order */
-#acore-characters-order .menu-item-handle {
+/* start acore-char-list — shared character row layout */
+.acore-char-list {
+ list-style: none;
+ padding: 0;
+ margin: 0;
}
-#acore-characters-order .item-type {
- padding: 0px;
- margin-top: 5px;
+.acore-char-list li {
+ margin-bottom: 4px;
}
-#acore-characters-order .item-type img {
- display: inline-block;
- vertical-align: middle;
- height: 32px;
- transform: translateZ(0); /* prevent blurry image on chrome */
+.acore-char-list input[type="hidden"],
+.acore-char-list input[name="characterorder[]"] {
+ display: none;
}
-#acore-characters-order input {
- display: none;
+button.acore-char-row {
+ font: inherit;
+ color: inherit;
+ text-align: left;
+ cursor: pointer;
+ -webkit-appearance: none;
+ appearance: none;
}
-/* end char order */
+/* Clicking a card/button shouldn't select its text (name, number, label). */
+button.acore-char-row,
+button.acore-char-row *,
+.item-restore-card,
+.item-restore-card * {
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+}
-/* start char-unstuck */
-#acore-characters-unstuck .menu-item-handle {
- cursor: default;
+/* Tools setting labels: informational only (no control activation), help cursor. */
+.acore-help-label {
+ cursor: help;
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
}
-.unstuck-button {
- background-size: cover;
- border: none;
- color: transparent;
- cursor: pointer;
+.acore-char-row {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ width: 100%;
+ min-height: 46px;
+ padding: 6px 12px;
+ box-sizing: border-box;
+ background: #fff;
+ /* top/right/bottom use faction color; left uses class color */
+ border-top: 2px solid var(--faction-color, #dcdcde);
+ border-right: 2px solid var(--faction-color, #dcdcde);
+ border-bottom: 2px solid var(--faction-color, #dcdcde);
+ border-left: 4px solid var(--cls-light, #646970);
+ border-radius: 2px;
}
-.unstuck-button:disabled {
- opacity: 0.5; /* Adjust the opacity for disabled state */
- cursor: not-allowed;
+.acore-char-pos {
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ min-width: 22px;
+ height: 22px;
+ font-size: 11px;
+ font-weight: 700;
+ color: #3c434a;
+ background: rgba(0, 0, 0, 0.10);
+ border-radius: 4px;
+ margin-right: 8px;
+ flex-shrink: 0;
}
-#acore-characters-unstuck .item-type {
- padding: 0px;
- margin-top: 5px;
+.acore-char-name {
+ flex: 1;
+ font-weight: 500;
}
-#acore-characters-unstuck .item-type img {
+.acore-char-meta {
+ display: flex;
+ align-items: center;
+ gap: 6px;
+ color: #646970;
+}
+
+.acore-level {
+ display: inline-block;
+ text-transform: uppercase;
+ font-size: 11px;
+ font-weight: 600;
+ letter-spacing: 0.04em;
+ min-width: 52px;
+ text-align: center;
+ /* badge shape */
+ padding: 2px 6px;
+ border-radius: 3px;
+ border: 1.5px solid currentcolor;
+ color: #50575e;
+}
+
+/* Expansion badge: filled background + matching border */
+.acore-level[data-exp="vanilla"] {
+ background: rgba(195, 147, 97, 0.12);
+ border-color: #C39361;
+ color: #50575e;
+}
+.acore-level[data-exp="tbc"] {
+ background: rgba(98, 201, 7, 0.12);
+ border-color: #62C907;
+ color: #50575e;
+}
+.acore-level[data-exp="wrath"] {
+ background: rgba(93, 172, 235, 0.12);
+ border-color: #5DACEB;
+ color: #50575e;
+}
+
+.acore-char-meta img {
display: inline-block;
vertical-align: middle;
height: 32px;
+ width: 32px;
transform: translateZ(0); /* prevent blurry image on chrome */
+ border: 3px solid rgba(0, 0, 0, 0.12);
+ border-radius: 4px;
}
-#acore-characters-unstuck input {
- display: none;
+/* Race icon: faction color border */
+.acore-char-meta img.race-icon {
+ border-color: var(--faction-color, rgba(0, 0, 0, 0.12));
+}
+
+/* Class icon: class color border */
+.acore-char-meta img.class-icon {
+ border-color: var(--cls-light, rgba(0, 0, 0, 0.12));
+}
+
+/* sortable drag cursor on order list */
+#acore-characters-order .acore-char-row {
+ cursor: grab;
+}
+
+#acore-characters-order .acore-char-row:active {
+ cursor: grabbing;
}
-/* end char unstuck */
+/* click cursor on mail return */
+#acore-characters-mail .acore-char-row {
+ cursor: pointer;
+}
+
+#acore-characters-mail .acore-char-row.active {
+ background: #f0f4f8;
+ /* thicken faction borders to signal selection; border-left (class color) unchanged */
+ border-top-width: 3px;
+ border-right-width: 3px;
+ border-bottom-width: 3px;
+}
+/* end acore-char-list */
+
+/* start unstuck button */
+.unstuck-button {
+ border: none;
+ color: transparent;
+ cursor: pointer;
+ background-color: transparent;
+ background-repeat: no-repeat;
+ background-position: center;
+ background-size: cover;
+ padding: 0;
+}
+
+.unstuck-button:disabled {
+ opacity: 0.5;
+ cursor: not-allowed;
+}
+/* end unstuck button */
/* start raf progress view */
@@ -206,66 +331,198 @@ body {
/* end raf progress view */
+/* start mail-return layout */
+#acore-mail-return-page {
+ max-width: 100%;
+}
+
+#mail-return-layout {
+ display: grid;
+ grid-template-columns: 460px 1fr 1fr;
+ gap: 16px;
+ align-items: start;
+}
+
+/* col 1 — always the same width */
+#mail-return-sidebar {
+ grid-column: 1;
+}
+
+/* cols 2–3 — hidden until mails exist */
+#mail-return-content {
+ display: none;
+ grid-column: 2 / 4;
+}
+
+/* "Unread Sent Mails" heading — inside card-header */
+#mail-return-heading {
+ font-size: 14px;
+ font-weight: 600;
+}
+
+/* mail entries fill cols 2–3 as a 2-column inner grid */
+#mail-return-items {
+ display: grid;
+ grid-template-columns: 1fr 1fr;
+ gap: 12px;
+}
+
+@media (max-width: 800px) {
+ #mail-return-layout {
+ grid-template-columns: 1fr;
+ }
+ #mail-return-content {
+ grid-column: 1;
+ }
+ #mail-return-items {
+ grid-template-columns: 1fr;
+ }
+}
+/* end mail-return layout */
+
/* start mail-return */
#mail-return-items .mail-entry {
background: #fff;
- border: 1px solid #ccd0d4;
+ /* JS overrides colors per-mail; thickness mirrors character selector rows */
+ border-top: 2px solid #ccd0d4;
+ border-right: 2px solid #ccd0d4;
+ border-bottom: 2px solid #ccd0d4;
+ border-left: 4px solid #646970;
border-radius: 4px;
padding: 12px;
- margin-bottom: 10px;
}
+/* Row 1: recipient left, return button right — class-colored border-left */
#mail-return-items .mail-header {
display: flex;
align-items: center;
justify-content: space-between;
-}
-
-#mail-return-items .mail-subject {
- font-weight: 600;
- font-size: 14px;
+ gap: 8px;
+ margin-bottom: 8px;
+ /* avoid border shorthand so JS inline border-left-color wins */
+ border-top: 1px solid #dcdcde;
+ border-right: 1px solid #dcdcde;
+ border-bottom: 1px solid #dcdcde;
+ border-left: 4px solid #646970; /* JS overrides color per card */
+ border-radius: 2px;
+ padding: 7px 10px;
+ background: #f9f9f9;
}
#mail-return-items .mail-recipient {
display: flex;
align-items: center;
gap: 6px;
- margin-top: 8px;
- padding: 6px 10px;
- background: #f6f7f7;
- border-radius: 4px;
+ flex-wrap: wrap;
+ background: none;
+ padding: 0;
+ margin: 0;
}
-#mail-return-items .mail-recipient img {
+#mail-return-items .mail-recipient-icon {
display: inline-block;
- vertical-align: middle;
- height: 24px;
- width: 24px;
+ height: 28px;
+ width: 28px;
transform: translateZ(0);
+ border: 3px solid rgba(0, 0, 0, 0.18);
+ border-radius: 4px;
}
-#mail-return-items .mail-recipient .recipient-name {
- font-weight: 500;
+#mail-return-items .mail-to-label {
+ font-size: 12px;
+ color: #646970;
+ text-transform: uppercase;
+ font-weight: 600;
+ letter-spacing: 0.04em;
+}
+
+#mail-return-items .recipient-name {
+ font-weight: 600;
+ font-size: 14px;
}
-#mail-return-items .mail-meta {
+#mail-return-items .recipient-level {
+ font-size: 11px;
color: #646970;
- font-size: 12px;
- margin-top: 6px;
+ text-transform: uppercase;
+ font-weight: 600;
+ letter-spacing: 0.04em;
}
-#mail-return-items .mail-items {
- margin-top: 8px;
- padding: 6px 10px;
- background: #f6f7f7;
- border-radius: 4px;
+/* Row 2: subject */
+#mail-return-items .mail-subject {
font-size: 13px;
+ color: #50575e;
+ margin-bottom: 8px;
+}
+#mail-return-items .mail-subject-label {
+ font-size: 11px;
+ font-weight: 600;
+ text-transform: uppercase;
+ letter-spacing: 0.04em;
+ color: #8b949e;
+ margin-right: 3px;
+}
+
+.mail-cod-label {
+ font-size: 12px;
+ color: #a00;
+}
+
+/* Row 3: item icon grid — centered in card */
+.mail-items-grid {
+ display: grid;
+ grid-template-columns: repeat(6, 56px);
+ gap: 6px;
+ justify-content: center;
}
-#mail-return-items .mail-money {
- margin-top: 6px;
+@media (max-width: 480px) {
+ .mail-items-grid {
+ grid-template-columns: repeat(4, 56px);
+ }
+}
+
+.mail-item-slot {
+ position: relative;
+ width: 56px;
+ height: 56px;
+ background: #1c1c1c;
+ border: 3px solid rgba(255, 255, 255, 0.22);
+ border-radius: 3px;
+ overflow: hidden;
+}
+
+.mail-item-slot > a {
+ position: absolute;
+ inset: 0;
+ display: block;
+ font-size: 0;
+ line-height: 0;
+ color: transparent !important;
+ overflow: hidden;
+ /* WowHead sets background-image inline on the — override size/position */
+ background-size: cover !important;
+ background-position: center !important;
+ background-repeat: no-repeat !important;
+}
+
+/* Quantity — bottom strip with semi-transparent overlay */
+.mail-item-qty {
+ position: absolute;
+ bottom: 0;
+ left: 0;
+ right: 0;
+ background: rgba(0, 0, 0, 0.55);
+ color: #fff;
font-size: 13px;
- color: #646970;
+ font-weight: 700;
+ text-align: center;
+ padding: 2px 0 1px;
+ line-height: 1.3;
+ letter-spacing: 0.02em;
+ pointer-events: none;
+ z-index: 2;
}
#mail-return-items .mail-return-button {
@@ -277,6 +534,7 @@ body {
cursor: pointer;
white-space: nowrap;
font-size: 13px;
+ flex-shrink: 0;
}
#mail-return-items .mail-return-button:hover {
@@ -289,3 +547,233 @@ body {
cursor: not-allowed;
}
/* end mail-return */
+
+/* ============================================================
+ Profile page & sub-tabs layout (applies to both light + dark)
+ ============================================================ */
+
+body.profile-php #wpbody-content > .wrap {
+ max-width: 900px;
+}
+
+body.profile-php .form-table th {
+ width: 180px;
+ padding: 12px 10px 12px 0;
+ vertical-align: top;
+ font-size: 13px;
+}
+
+body.profile-php .form-table td {
+ padding: 10px 0;
+}
+
+/* --- Security sub-page --- */
+#acore-security-page {
+ max-width: 760px;
+}
+
+#acore-security-page > h1 {
+ margin-bottom: 4px;
+ padding-bottom: 0;
+ border-bottom: none;
+}
+
+#acore-security-page .postbox {
+ border-radius: 3px;
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.07);
+ margin-top: 16px;
+ margin-bottom: 0;
+}
+
+#acore-security-page .postbox .inside {
+ padding: 16px 20px;
+}
+
+/* Postbox header — padding, cursor, typography */
+#acore-security-page .postbox-header {
+ cursor: default;
+ border-bottom: 1px solid #dcdcde;
+}
+
+#acore-security-page .postbox-header h2,
+#acore-security-page .postbox-header .hndle {
+ cursor: default;
+ font-size: 13px;
+ font-weight: 600;
+ padding: 10px 16px;
+ margin: 0;
+ border: none;
+}
+
+#acore-security-page .form-table th {
+ width: 180px;
+ padding: 10px 10px 10px 0;
+}
+
+#acore-security-page .form-table td {
+ padding: 8px 0;
+}
+
+/* --- RAF sub-page --- */
+#acore-raf-page {
+ max-width: 860px;
+}
+
+#acore-raf-page > h1 {
+ margin-bottom: 6px;
+}
+
+.acore-raf-intro {
+ color: #646970;
+ margin-bottom: 12px;
+}
+
+.acore-raf-notice {
+ max-width: 700px;
+ margin-bottom: 16px !important;
+}
+
+.acore-raf-row {
+ margin-top: 4px;
+}
+
+#acore-raf-page .card {
+ margin-bottom: 16px;
+}
+
+/* --- Item Restoration sub-page --- */
+#acore-item-restoration-page {
+ max-width: 100%;
+}
+
+#acore-item-restoration-page > h1 {
+ margin-bottom: 16px;
+}
+
+/* Layout: sidebar + content (mirrors mail-return) */
+#item-restore-layout {
+ display: grid;
+ grid-template-columns: 460px 1fr;
+ gap: 16px;
+ align-items: start;
+}
+
+#item-restore-sidebar {
+ grid-column: 1;
+}
+
+#item-restore-content {
+ grid-column: 2;
+}
+
+@media (max-width: 800px) {
+ #item-restore-layout {
+ grid-template-columns: 1fr;
+ }
+ #item-restore-content {
+ grid-column: 1;
+ }
+}
+
+/* click cursor + active state (mirrors mail return) */
+#acore-characters-item-restore .acore-char-row {
+ cursor: pointer;
+}
+
+#acore-characters-item-restore .acore-char-row.active {
+ background: #f0f4f8;
+ border-top-width: 3px;
+ border-right-width: 3px;
+ border-bottom-width: 3px;
+}
+
+/* Item restore: 4-column card grid */
+.item-restore-grid {
+ display: grid;
+ grid-template-columns: repeat(4, 1fr);
+ gap: 12px;
+}
+
+/* Card: white bg, quality-coloured border (set by JS after wowhead loads) */
+.item-restore-card {
+ position: relative;
+ background: #fff;
+ border: 3px solid #9d9d9d;
+ border-radius: 4px;
+ padding: 20px 12px 12px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ gap: 10px;
+}
+
+/* Number badge — top-left corner */
+.item-restore-num {
+ position: absolute;
+ top: 6px;
+ left: 8px;
+ font-size: 11px;
+ font-weight: 600;
+ color: #646970;
+ line-height: 1;
+}
+
+/* Icon container */
+.item-restore-icon {
+ position: relative;
+ width: 80px;
+ height: 80px;
+ background: #1c1c1c;
+ border-radius: 3px;
+ overflow: hidden;
+ flex-shrink: 0;
+}
+
+/* WowHead puts icon as background-image on the .
+ font-size/color hide the item-name text wowhead injects. */
+.item-restore-icon > a {
+ position: absolute !important;
+ inset: 0 !important;
+ display: block !important;
+ width: 100% !important;
+ height: 100% !important;
+ font-size: 0 !important;
+ line-height: 0 !important;
+ color: transparent !important;
+ text-indent: -9999px !important;
+ overflow: hidden !important;
+ background-size: cover !important;
+ background-position: center !important;
+ background-repeat: no-repeat !important;
+ padding: 0 !important;
+}
+
+/* Deleted date */
+.item-restore-date {
+ font-size: 11px;
+ color: #646970;
+ text-align: center;
+ line-height: 1.3;
+}
+
+.item-restore-btn {
+ background: #2271b1;
+ color: #fff;
+ border: 1px solid #2271b1;
+ border-radius: 3px;
+ padding: 5px 0;
+ cursor: pointer;
+ font-size: 13px;
+ width: 100%;
+ text-align: center;
+}
+
+.item-restore-btn:hover {
+ background: #135e96;
+ border-color: #135e96;
+}
+
+.item-restore-btn:disabled {
+ opacity: 0.6;
+ cursor: not-allowed;
+}
diff --git a/src/acore-wp-plugin/web/assets/css/theme.css b/src/acore-wp-plugin/web/assets/css/theme.css
new file mode 100644
index 000000000..0a1570d88
--- /dev/null
+++ b/src/acore-wp-plugin/web/assets/css/theme.css
@@ -0,0 +1,616 @@
+/* =====================================================================
+ * acore-theme.css
+ * Single place to edit light/dark theming for the AzerothCore plugin.
+ *
+ * Colours are driven by CSS custom properties. Edit the values in the
+ * two blocks below (":root" = light, "body.acore-dark-mode" = dark) and
+ * every rule further down updates automatically.
+ *
+ * Loaded after main.css and dark-mode.css, so rules here win.
+ * ===================================================================== */
+
+:root {
+ --acore-bg: #ffffff;
+ --acore-surface: #ffffff;
+ --acore-surface-2: #f3f4f5;
+ --acore-text: #1d2327;
+ --acore-muted: #646970;
+ --acore-border: #c3c4c7;
+ --acore-border-strong: #8c8f94;
+ --acore-accent: #2271b1;
+ --acore-danger: #d63638;
+ --acore-danger-bg: #fbeaea;
+ --acore-danger-text: #b32d2e;
+
+ /* WoW item-quality colours (shared by both themes) */
+ --q0: #9d9d9d; --q1: #ffffff; --q2: #1eff00; --q3: #0070dd;
+ --q4: #a335ee; --q5: #ff8000; --q6: #e6cc80; --q7: #e6cc80;
+}
+
+body.acore-dark-mode {
+ --acore-bg: #0d1117;
+ --acore-surface: #161b22;
+ --acore-surface-2: #21262d;
+ --acore-text: #c9d1d9;
+ --acore-muted: #9aa4af;
+ --acore-border: #30363d;
+ --acore-border-strong: #484f58;
+ --acore-accent: #58a6ff;
+ --acore-danger: #d63638;
+ --acore-danger-bg: transparent;
+ --acore-danger-text: #ea5a5c;
+
+ --q1: #c0c0c0; /* pure white reads poorly on dark; soften common quality */
+}
+
+/* ── Danger buttons (Reset Order, Remove, Reset, …) ─────────────────── */
+body.acore-dark-mode .acore-btn-danger .dashicons {
+ color: var(--acore-danger-text) !important;
+}
+.acore-btn-danger {
+ border: 1px solid var(--acore-danger) !important;
+ color: var(--acore-danger-text) !important;
+ background: var(--acore-danger-bg) !important;
+ transition: background .12s ease, color .12s ease;
+}
+.acore-btn-danger:hover,
+.acore-btn-danger:focus {
+ background: var(--acore-danger) !important;
+ color: #ffffff !important;
+}
+.acore-btn-danger .dashicons { margin-top: 3px; }
+
+/* ── Item Restoration: cards ────────────────────────────────────────── */
+/* Outer card: neutral border + theme surface (works light & dark). */
+.item-restore-card {
+ background: var(--acore-surface) !important;
+ border: 1px solid var(--acore-border) !important;
+ color: var(--acore-text) !important;
+ border-radius: 6px;
+}
+.item-restore-card .item-restore-date { color: var(--acore-muted) !important; }
+.item-restore-card .item-restore-num { color: var(--acore-muted) !important; }
+/* Inner icon shows the item quality as its border. wowhead adds q0..q7 */
+/* to the icon link; we colour the icon frame from that. */
+.item-restore-icon a {
+ display: block;
+ border: 2px solid var(--acore-border-strong);
+ border-radius: 4px;
+ box-sizing: border-box;
+}
+.item-restore-icon a.q0 { border-color: var(--q0) !important; }
+.item-restore-icon a.q1 { border-color: var(--q1) !important; }
+.item-restore-icon a.q2 { border-color: var(--q2) !important; }
+.item-restore-icon a.q3 { border-color: var(--q3) !important; }
+.item-restore-icon a.q4 { border-color: var(--q4) !important; }
+.item-restore-icon a.q5 { border-color: var(--q5) !important; }
+.item-restore-icon a.q6 { border-color: var(--q6) !important; }
+.item-restore-icon a.q7 { border-color: var(--q7) !important; }
+
+/* ── Security page: readability in dark mode ────────────────────────── */
+/* Inline muted greys (#646970) are too dark on a dark surface. */
+body.acore-dark-mode #acore-security-page [style*="646970"],
+body.acore-dark-mode #acore-security-page [style*="#646970"],
+body.acore-dark-mode #acore-security-page .description,
+body.acore-dark-mode #acore-security-page .text-muted {
+ color: var(--acore-muted) !important;
+}
+body.acore-dark-mode #acore-security-page,
+body.acore-dark-mode #acore-security-page p,
+body.acore-dark-mode #acore-security-page li,
+body.acore-dark-mode #acore-security-page h3 { color: var(--acore-text); }
+body.acore-dark-mode #acore-security-page code {
+ background: var(--acore-surface-2) !important;
+ color: var(--acore-text) !important;
+ border: 1px solid var(--acore-border);
+ border-radius: 3px;
+ padding: 1px 5px;
+}
+/* Recent Connections table - stripe rows at the level so WP's light
+ .striped odd-row background doesn't show through transparent cells. */
+body.acore-dark-mode #acore-security-page .wp-list-table {
+ background: var(--acore-surface) !important;
+ border-color: var(--acore-border) !important;
+}
+body.acore-dark-mode #acore-security-page .wp-list-table > thead > tr,
+body.acore-dark-mode #acore-security-page .wp-list-table > tbody > tr:nth-child(odd) {
+ background: var(--acore-surface-2) !important;
+}
+body.acore-dark-mode #acore-security-page .wp-list-table > tbody > tr:nth-child(even) {
+ background: var(--acore-surface) !important;
+}
+body.acore-dark-mode #acore-security-page .wp-list-table th,
+body.acore-dark-mode #acore-security-page .wp-list-table td {
+ color: var(--acore-text) !important;
+ border-color: var(--acore-border) !important;
+ background: transparent !important;
+}
+
+/* ── Mail Return surfaces ───────────────────────────────────────────── */
+body.acore-dark-mode #acore-mail-return-page .mail-entry { background: var(--acore-surface) !important; }
+body.acore-dark-mode #acore-mail-return-page .mail-recipient,
+body.acore-dark-mode #acore-mail-return-page .mail-items { background: var(--acore-bg) !important; }
+body.acore-dark-mode #acore-mail-return-page .mail-entry *,
+body.acore-dark-mode #acore-mail-return-page .mail-meta { color: var(--acore-text) !important; }
+body.acore-dark-mode #acore-mail-return-page .text-muted { color: var(--acore-muted) !important; }
+
+/* ── WP 2FA plugin UI (embedded on the Security page) ───────────────── */
+body.acore-dark-mode #acore-security-page [class*="wp2fa"],
+body.acore-dark-mode #acore-security-page [class*="wp-2fa"] { color: var(--acore-text) !important; }
+body.acore-dark-mode #acore-security-page [class*="wp2fa"] input,
+body.acore-dark-mode #acore-security-page [class*="wp2fa"] select,
+body.acore-dark-mode #acore-security-page [class*="wp2fa"] textarea {
+ background: var(--acore-surface-2) !important;
+ color: var(--acore-text) !important;
+ border: 1px solid var(--acore-border) !important;
+}
+body.acore-dark-mode #acore-security-page [class*="wp2fa"] code,
+body.acore-dark-mode #acore-security-page [class*="wp2fa"] pre {
+ background: var(--acore-surface-2) !important;
+ color: var(--acore-text) !important;
+}
+
+/* ── myCRED points / history page (profile.php?page=mycred_default-history) ── */
+body.acore-dark-mode.mycred-log-page #wpbody-content { color: var(--acore-text); }
+
+/* Filter tabs (All / Today / This Week …) */
+body.acore-dark-mode.mycred-log-page .subsubsub,
+body.acore-dark-mode.mycred-log-page .subsubsub a { color: var(--acore-muted) !important; }
+body.acore-dark-mode.mycred-log-page .subsubsub a.current,
+body.acore-dark-mode.mycred-log-page .subsubsub a:hover { color: var(--acore-accent) !important; }
+
+/* Search box + pagination chrome */
+body.acore-dark-mode.mycred-log-page .search-box input,
+body.acore-dark-mode.mycred-log-page .tablenav input,
+body.acore-dark-mode.mycred-log-page .tablenav select {
+ background: var(--acore-surface-2) !important;
+ color: var(--acore-text) !important;
+ border: 1px solid var(--acore-border) !important;
+}
+body.acore-dark-mode.mycred-log-page .tablenav,
+body.acore-dark-mode.mycred-log-page .tablenav * { color: var(--acore-text) !important; }
+body.acore-dark-mode.mycred-log-page .tablenav .tablenav-pages a,
+body.acore-dark-mode.mycred-log-page .tablenav .tablenav-pages span.tablenav-pages-navspan {
+ background: var(--acore-surface-2) !important;
+ border-color: var(--acore-border) !important;
+ color: var(--acore-text) !important;
+}
+
+/* The points-history list table */
+body.acore-dark-mode.mycred-log-page .wp-list-table {
+ background: var(--acore-surface) !important;
+ border-color: var(--acore-border) !important;
+ color: var(--acore-text) !important;
+}
+body.acore-dark-mode.mycred-log-page .wp-list-table thead th,
+body.acore-dark-mode.mycred-log-page .wp-list-table tfoot th,
+body.acore-dark-mode.mycred-log-page .wp-list-table thead th a,
+body.acore-dark-mode.mycred-log-page .wp-list-table thead th span {
+ background: var(--acore-surface-2) !important;
+ color: var(--acore-text) !important;
+ border-color: var(--acore-border) !important;
+}
+body.acore-dark-mode.mycred-log-page .wp-list-table td,
+body.acore-dark-mode.mycred-log-page .wp-list-table th {
+ color: var(--acore-text) !important;
+ border-color: var(--acore-border) !important;
+ background: transparent !important;
+}
+body.acore-dark-mode.mycred-log-page .wp-list-table > tbody > tr:nth-child(odd) {
+ background: var(--acore-surface-2) !important;
+}
+body.acore-dark-mode.mycred-log-page .wp-list-table a { color: var(--acore-accent) !important; }
+
+/* Export button row */
+body.acore-dark-mode.mycred-log-page #export-log-history,
+body.acore-dark-mode.mycred-log-page #export-log-history * { color: var(--acore-text) !important; }
+
+/* Generic myCRED widgets elsewhere (points balance boxes, etc.) */
+body.acore-dark-mode [class*="mycred"] th,
+body.acore-dark-mode [class*="mycred"] td { color: var(--acore-text) !important; border-color: var(--acore-border) !important; }
+body.acore-dark-mode [class*="mycred"] a { color: var(--acore-accent) !important; }
+
+/* myCRED page outer wrapper (#myCRED-wrap is white) -> blend into dark admin bg */
+body.acore-dark-mode.mycred-log-page #myCRED-wrap {
+ background: transparent !important;
+}
+body.acore-dark-mode.mycred-log-page #myCRED-wrap,
+body.acore-dark-mode.mycred-log-page #myCRED-wrap h1,
+body.acore-dark-mode.mycred-log-page #myCRED-wrap h2,
+body.acore-dark-mode.mycred-log-page #myCRED-wrap p {
+ color: var(--acore-text) !important;
+}
+
+/* ── WP 2FA standalone setup wizard (profile.php?page=wp-2fa-setup) ──────
+ * The wizard renders its own with no admin/dark
+ * class, and only prints its own stylesheets. We inject theme.css into its
+ * via the `wp_2fa_setup_page_scripts` hook ONLY when dark mode is on
+ * (see DarkMode.php), so these body.wp2fa-setup rules are dark-only by load.
+ * The dark palette is redeclared here because .acore-dark-mode isn't present. */
+body.wp2fa-setup {
+ --acore-bg: #0d1117;
+ --acore-surface: #161b22;
+ --acore-surface-2: #21262d;
+ --acore-text: #c9d1d9;
+ --acore-muted: #9aa4af;
+ --acore-border: #30363d;
+ --acore-accent: #58a6ff;
+
+ background: var(--acore-bg) !important;
+ color: var(--acore-text) !important;
+}
+body.wp2fa-setup .setup-wizard-wrapper,
+body.wp2fa-setup .wp2fa-setup-content,
+body.wp2fa-setup .modal__container {
+ background: var(--acore-surface) !important;
+ color: var(--acore-text) !important;
+ border-color: var(--acore-border) !important;
+}
+body.wp2fa-setup h1, body.wp2fa-setup h2, body.wp2fa-setup h3,
+body.wp2fa-setup h4, body.wp2fa-setup p, body.wp2fa-setup label,
+body.wp2fa-setup li, body.wp2fa-setup span, body.wp2fa-setup strong {
+ color: var(--acore-text) !important;
+}
+body.wp2fa-setup .description,
+body.wp2fa-setup .wp2fa-setup-footer a { color: var(--acore-muted) !important; }
+body.wp2fa-setup input[type="text"],
+body.wp2fa-setup input[type="email"],
+body.wp2fa-setup input[type="number"],
+body.wp2fa-setup input[type="password"],
+body.wp2fa-setup select,
+body.wp2fa-setup textarea,
+body.wp2fa-setup .select2-selection {
+ background: var(--acore-surface-2) !important;
+ color: var(--acore-text) !important;
+ border: 1px solid var(--acore-border) !important;
+}
+body.wp2fa-setup .steps li { color: var(--acore-muted) !important; }
+body.wp2fa-setup .steps li.is-active { color: var(--acore-accent) !important; font-weight: 600; }
+body.wp2fa-setup .button-secondary,
+body.wp2fa-setup .wp-2fa-button-secondary {
+ background: var(--acore-surface-2) !important;
+ color: var(--acore-text) !important;
+ border-color: var(--acore-border) !important;
+}
+body.wp2fa-setup code,
+body.wp2fa-setup pre {
+ background: var(--acore-surface-2) !important;
+ color: var(--acore-text) !important;
+ border: 1px solid var(--acore-border);
+}
+body.wp2fa-setup .modal__overlay { background: rgba(0,0,0,0.6) !important; }
+
+/* ── WP 2FA micromodal on normal admin pages (Security page "Configure 2FA") ──
+ * The modal is appended at level (outside #acore-security-page), so it is
+ * scoped by the body dark class instead. */
+body.acore-dark-mode .wp2fa-modal .modal__container {
+ background: var(--acore-surface) !important;
+ color: var(--acore-text) !important;
+}
+body.acore-dark-mode .wp2fa-modal .modal__content,
+body.acore-dark-mode .wp2fa-modal .modal__content h1,
+body.acore-dark-mode .wp2fa-modal .modal__content h2,
+body.acore-dark-mode .wp2fa-modal .modal__content h3,
+body.acore-dark-mode .wp2fa-modal .modal__content h4,
+body.acore-dark-mode .wp2fa-modal .modal__content p,
+body.acore-dark-mode .wp2fa-modal .modal__content label,
+body.acore-dark-mode .wp2fa-modal .modal__content span,
+body.acore-dark-mode .wp2fa-modal .modal__content li,
+body.acore-dark-mode .wp2fa-modal .modal__content strong {
+ color: var(--acore-text) !important;
+}
+body.acore-dark-mode .wp2fa-modal .description { color: var(--acore-muted) !important; }
+body.acore-dark-mode .wp2fa-modal .option-pill,
+body.acore-dark-mode .wp2fa-modal .radio-cells .option-pill {
+ background: var(--acore-surface-2) !important;
+ border-color: var(--acore-border) !important;
+ color: var(--acore-text) !important;
+}
+body.acore-dark-mode .wp2fa-modal .option-pill.selected,
+body.acore-dark-mode .wp2fa-modal .option-pill:hover {
+ border-color: var(--acore-accent) !important;
+}
+body.acore-dark-mode .wp2fa-modal input,
+body.acore-dark-mode .wp2fa-modal select,
+body.acore-dark-mode .wp2fa-modal textarea {
+ background: var(--acore-surface-2) !important;
+ color: var(--acore-text) !important;
+ border: 1px solid var(--acore-border) !important;
+}
+body.acore-dark-mode .wp2fa-modal .modal__close { color: var(--acore-text) !important; }
+body.acore-dark-mode .wp2fa-modal code,
+body.acore-dark-mode .wp2fa-modal pre {
+ background: var(--acore-surface-2) !important;
+ color: var(--acore-text) !important;
+ border: 1px solid var(--acore-border);
+}
+
+/* WP 2FA TOTP secret-key box (shown in both the modal and the wizard) */
+body.acore-dark-mode .wp2fa-modal .app-key-wrapper,
+body.wp2fa-setup .app-key-wrapper {
+ background: var(--acore-surface-2) !important;
+ border-color: var(--acore-border) !important;
+}
+body.acore-dark-mode .wp2fa-modal .app-key-wrapper .app-key,
+body.acore-dark-mode .wp2fa-modal .app-key-wrapper input,
+body.wp2fa-setup .app-key-wrapper .app-key,
+body.wp2fa-setup .app-key-wrapper input {
+ color: var(--acore-text) !important;
+}
+
+
+/* ── "Disabled" sections (e.g. In-game 2FA before Website 2FA is set up) ──
+ * A greyed background box signals "disabled" while text stays fully legible
+ * (no opacity wash-out). Works in both light and dark themes. */
+.acore-2fa-disabled {
+ position: relative;
+ pointer-events: none;
+ user-select: none;
+ background: var(--acore-surface-2);
+ border: 1px solid var(--acore-border);
+ border-radius: 6px;
+ padding: 10px 16px 12px;
+ margin-top: 8px;
+}
+/* Light theme: keep the intro + steps at readable contrast on the grey box */
+.acore-2fa-disabled p,
+.acore-2fa-disabled li { color: #3c434a !important; }
+.acore-2fa-disabled p:first-child { color: #50575e !important; }
+/* Dark theme */
+body.acore-dark-mode .acore-2fa-disabled,
+body.acore-dark-mode .acore-2fa-disabled p,
+body.acore-dark-mode .acore-2fa-disabled li,
+body.acore-dark-mode .acore-2fa-disabled span { color: var(--acore-text) !important; }
+body.acore-dark-mode .acore-2fa-disabled p:first-child { color: var(--acore-muted) !important; }
+
+/* ── "Website 2FA required" callout (bright & visible in both themes) ── */
+.acore-2fa-required-note {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ margin: 10px 0 0;
+ padding: 8px 12px;
+ font-size: 13px;
+ font-weight: 600;
+ line-height: 1.4;
+ border-radius: 6px;
+ color: #9a5b00;
+ background: #fff4e0;
+ border: 1px solid #f0b429;
+}
+.acore-2fa-required-note .dashicons { color: #d98300; flex: 0 0 auto; }
+body.acore-dark-mode .acore-2fa-required-note {
+ color: #f5c451 !important;
+ background: rgba(240, 180, 41, 0.12) !important;
+ border-color: #8a6d1f !important;
+}
+body.acore-dark-mode .acore-2fa-required-note .dashicons { color: #f5c451 !important; }
+
+/* ── Highlight the connection row matching the viewer's current IP ── */
+#acore-security-page .wp-list-table > tbody > tr.acore-conn-current > td {
+ background: #fff3cd !important;
+ border-color: #f0d488 !important;
+}
+#acore-security-page .wp-list-table > tbody > tr.acore-conn-current > td:first-child {
+ box-shadow: inset 3px 0 0 0 #e0a800;
+ font-weight: 600;
+}
+body.acore-dark-mode #acore-security-page .wp-list-table > tbody > tr.acore-conn-current > td {
+ background: rgba(240, 180, 41, 0.16) !important;
+ color: #f5d98a !important;
+ border-color: #6e5a1e !important;
+}
+body.acore-dark-mode #acore-security-page .wp-list-table > tbody > tr.acore-conn-current > td:first-child {
+ box-shadow: inset 3px 0 0 0 #f0b429;
+}
+
+/* ── Shared connection tables (Security page + Profile page) ── */
+body.acore-dark-mode .acore-conn-table {
+ background: var(--acore-surface) !important;
+ border-color: var(--acore-border) !important;
+}
+body.acore-dark-mode .acore-conn-table > thead > tr,
+body.acore-dark-mode .acore-conn-table > tbody > tr:nth-child(odd) {
+ background: var(--acore-surface-2) !important;
+}
+body.acore-dark-mode .acore-conn-table > tbody > tr:nth-child(even) {
+ background: var(--acore-surface) !important;
+}
+body.acore-dark-mode .acore-conn-table th,
+body.acore-dark-mode .acore-conn-table td {
+ color: var(--acore-text) !important;
+ border-color: var(--acore-border) !important;
+ background: transparent !important;
+}
+.acore-conn-table > tbody > tr.acore-conn-current > td {
+ background: #fff3cd !important;
+ border-color: #f0d488 !important;
+}
+.acore-conn-table > tbody > tr.acore-conn-current > td:first-child {
+ box-shadow: inset 3px 0 0 0 #e0a800;
+ font-weight: 600;
+}
+body.acore-dark-mode .acore-conn-table > tbody > tr.acore-conn-current > td {
+ background: rgba(240, 180, 41, 0.16) !important;
+ color: #f5d98a !important;
+ border-color: #6e5a1e !important;
+}
+body.acore-dark-mode .acore-conn-table > tbody > tr.acore-conn-current > td:first-child {
+ box-shadow: inset 3px 0 0 0 #f0b429;
+}
+
+/* "Your IPv4:" label (right-aligned) + connection notes - readable both themes */
+.acore-conn-heading {
+ display: flex;
+ justify-content: space-between;
+ align-items: baseline;
+ gap: 8px;
+ max-width: 860px;
+ flex-wrap: wrap;
+}
+.acore-conn-myip {
+ font-size: 13px;
+ font-weight: 400;
+ white-space: nowrap;
+ color: #50575e;
+}
+body.acore-dark-mode .acore-conn-myip { color: #c9d1d9; }
+.acore-conn-note { color: #50575e; font-size: 13px; }
+body.acore-dark-mode .acore-conn-note { color: #9aa4af !important; }
+
+/* ── Dark-mode toggle in the admin bar (visible in both themes) ────────── */
+#wp-admin-bar-acore-dark-mode > .ab-item {
+ background: rgba(255, 255, 255, 0.08);
+ border-radius: 4px;
+}
+#wp-admin-bar-acore-dark-mode:hover > .ab-item {
+ background: rgba(255, 255, 255, 0.18) !important;
+}
+#acore-dm-icon {
+ font-size: 18px !important;
+ line-height: 1 !important;
+ color: #ffc83d !important;
+ vertical-align: middle;
+}
+
+/* ── Native