diff --git a/src/view/frontend/web/css/toolbar/_footer.css b/src/view/frontend/web/css/toolbar/_footer.css
index 73fbb219..1b84e650 100644
--- a/src/view/frontend/web/css/toolbar/_footer.css
+++ b/src/view/frontend/web/css/toolbar/_footer.css
@@ -13,9 +13,9 @@
padding-top: 6px;
}
-/* ── Theme toggle ────────────────────────────────────────────────────────── */
+/* ── Footer toolbar row (credit + theme + export) ─────────────────────────── */
-.mageforge-footer-theme-row {
+.mageforge-footer-toolbar-row {
display: flex;
align-items: center;
justify-content: space-between;
@@ -23,7 +23,7 @@
gap: 8px;
}
-.mageforge-footer-theme-label {
+.mageforge-footer-toolbar-label {
font-family: var(--mageforge-font-family);
font-size: 10px;
font-weight: 500;
@@ -33,7 +33,7 @@
padding: 3px 6px 3px 8px;
}
-.mageforge-theme-toggle {
+.mageforge-segmented-toggle {
display: flex;
align-items: center;
gap: 2px;
@@ -42,7 +42,7 @@
padding: 2px;
}
-.mageforge-theme-btn {
+.mageforge-segmented-btn {
padding: 3px 8px;
border-radius: 4px;
border: none;
@@ -56,23 +56,23 @@
line-height: 1;
}
-.mageforge-theme-btn:hover {
+.mageforge-segmented-btn:hover {
color: var(--mageforge-color-white);
background: rgba(var(--mageforge-color-white-rgb), 0.08);
}
-.mageforge-theme-btn--active,
-.mageforge-theme-btn[aria-pressed="true"] {
+.mageforge-segmented-btn--active,
+.mageforge-segmented-btn[aria-pressed="true"] {
background: var(--mageforge-color-blue);
color: var(--mageforge-color-white);
}
-.mageforge-theme-btn:focus-visible {
+.mageforge-segmented-btn:focus-visible {
outline: 2px solid var(--mageforge-color-blue);
outline-offset: 1px;
}
-.mageforge-theme-btn:disabled {
+.mageforge-segmented-btn:disabled {
opacity: 0.35;
cursor: not-allowed;
pointer-events: none;
diff --git a/src/view/frontend/web/css/toolbar/_health.css b/src/view/frontend/web/css/toolbar/_health.css
index 2599fc25..ece52a25 100644
--- a/src/view/frontend/web/css/toolbar/_health.css
+++ b/src/view/frontend/web/css/toolbar/_health.css
@@ -127,3 +127,25 @@
text-align: center;
line-height: 1;
}
+
+/* ============================================================================
+ Dynamic score colours
+ ========================================================================== */
+
+.mageforge-score--low .mageforge-toolbar-health-score-number,
+.mageforge-score--low .mageforge-score-number,
+.mageforge-score--low.mageforge-dashboard-category-score {
+ color: var(--mageforge-color-red);
+}
+
+.mageforge-score--mid .mageforge-toolbar-health-score-number,
+.mageforge-score--mid .mageforge-score-number,
+.mageforge-score--mid.mageforge-dashboard-category-score {
+ color: var(--mageforge-color-amber);
+}
+
+.mageforge-score--high .mageforge-toolbar-health-score-number,
+.mageforge-score--high .mageforge-score-number,
+.mageforge-score--high.mageforge-dashboard-category-score {
+ color: var(--mageforge-color-green);
+}
diff --git a/src/view/frontend/web/css/toolbar/_menu.css b/src/view/frontend/web/css/toolbar/_menu.css
index 4526a7fd..3b2d62ad 100644
--- a/src/view/frontend/web/css/toolbar/_menu.css
+++ b/src/view/frontend/web/css/toolbar/_menu.css
@@ -122,6 +122,57 @@
outline-offset: 2px;
}
+/* ============================================================================
+ Menu Header Actions (theme toggle + close)
+ ========================================================================== */
+
+.mageforge-toolbar-menu-actions {
+ display: flex;
+ align-items: center;
+ gap: 6px;
+}
+
+.mageforge-theme-icon-group {
+ display: flex;
+ align-items: center;
+ gap: 2px;
+ background: rgba(var(--mageforge-color-white-rgb), 0.06);
+ border-radius: 6px;
+ padding: 2px;
+}
+
+.mageforge-theme-icon-btn {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ width: 24px;
+ height: 24px;
+ padding: 0;
+ border: none;
+ border-radius: 4px;
+ background: transparent;
+ color: var(--mageforge-color-slate-400);
+ cursor: pointer;
+ transition: all 0.15s ease;
+ line-height: 0;
+}
+
+.mageforge-theme-icon-btn:hover {
+ color: var(--mageforge-color-white);
+ background: rgba(var(--mageforge-color-white-rgb), 0.08);
+}
+
+.mageforge-theme-icon-btn--active,
+.mageforge-theme-icon-btn[aria-pressed="true"] {
+ background: var(--mageforge-color-blue);
+ color: var(--mageforge-color-white);
+}
+
+.mageforge-theme-icon-btn:focus-visible {
+ outline: 2px solid var(--mageforge-color-blue);
+ outline-offset: 2px;
+}
+
/* ============================================================================
Menu Items
========================================================================== */
diff --git a/src/view/frontend/web/css/toolbar/_themes.css b/src/view/frontend/web/css/toolbar/_themes.css
index ad099fd8..c3292e3b 100644
--- a/src/view/frontend/web/css/toolbar/_themes.css
+++ b/src/view/frontend/web/css/toolbar/_themes.css
@@ -59,11 +59,13 @@
}
/* Theme toggle pill: replace hardcoded white alpha with dark */
-.mageforge-toolbar[data-theme="light"] .mageforge-theme-toggle {
+.mageforge-toolbar[data-theme="light"] .mageforge-segmented-toggle,
+.mageforge-toolbar[data-theme="light"] .mageforge-theme-icon-group {
background: rgba(var(--mageforge-color-black-rgb), 0.06);
}
-.mageforge-toolbar[data-theme="light"] .mageforge-theme-btn:hover {
+.mageforge-toolbar[data-theme="light"] .mageforge-segmented-btn:hover,
+.mageforge-toolbar[data-theme="light"] .mageforge-theme-icon-btn:hover {
background: rgba(var(--mageforge-color-black-rgb), 0.08);
}
@@ -130,11 +132,13 @@
background: rgba(var(--mageforge-color-teal-rgb), 0.14);
}
- .mageforge-toolbar[data-theme="auto"] .mageforge-theme-toggle {
+ .mageforge-toolbar[data-theme="auto"] .mageforge-segmented-toggle,
+ .mageforge-toolbar[data-theme="auto"] .mageforge-theme-icon-group {
background: rgba(var(--mageforge-color-black-rgb), 0.06);
}
- .mageforge-toolbar[data-theme="auto"] .mageforge-theme-btn:hover {
+ .mageforge-toolbar[data-theme="auto"] .mageforge-segmented-btn:hover,
+ .mageforge-toolbar[data-theme="auto"] .mageforge-theme-icon-btn:hover {
background: rgba(var(--mageforge-color-black-rgb), 0.08);
}
diff --git a/src/view/frontend/web/js/toolbar/ui/build.js b/src/view/frontend/web/js/toolbar/ui/build.js
index 402434cf..923c602d 100644
--- a/src/view/frontend/web/js/toolbar/ui/build.js
+++ b/src/view/frontend/web/js/toolbar/ui/build.js
@@ -24,6 +24,9 @@ import {
createLogoSvg,
generateId,
ICON_HOME,
+ ICON_THEME_DARK,
+ ICON_THEME_LIGHT,
+ ICON_THEME_AUTO,
GROUP_ICONS,
GAUGE_ARC_LENGTH,
SCORE_RING_CIRCUMFERENCE,
@@ -93,7 +96,7 @@ export const buildMethods = {
},
/**
- * Sticky title bar: logo + name + close button.
+ * Sticky title bar: logo + name + theme toggle + close button.
*
* @returns {HTMLDivElement}
*/
@@ -105,15 +108,54 @@ export const buildMethods = {
${createLogoSvg("#E5622A")}
-
+
`;
- header.querySelector(".mageforge-toolbar-menu-close").onclick = (e) => {
+
+ const actions = header.querySelector(".mageforge-toolbar-menu-actions");
+
+ // Theme toggle
+ const themeGroup = document.createElement("div");
+ themeGroup.className = "mageforge-theme-icon-group";
+ themeGroup.setAttribute("role", "group");
+ themeGroup.setAttribute("aria-label", "Colour theme");
+ [
+ ["dark", ICON_THEME_DARK, "Dark theme"],
+ ["auto", ICON_THEME_AUTO, "Auto theme"],
+ ["light", ICON_THEME_LIGHT, "Light theme"],
+ ].forEach(([value, icon, label]) => {
+ const btn = document.createElement("button");
+ btn.type = "button";
+ btn.className = "mageforge-theme-icon-btn";
+ btn.dataset.themeValue = value;
+ btn.innerHTML = icon;
+ btn.setAttribute("aria-label", label);
+ btn.title = label;
+ btn.setAttribute("aria-pressed", "false");
+ btn.onclick = (e) => {
+ e.stopPropagation();
+ this.setTheme(/** @type {'dark'|'auto'|'light'} */ (value));
+ };
+ themeGroup.appendChild(btn);
+ });
+ actions.appendChild(themeGroup);
+ this._themeToggleGroup = themeGroup;
+
+ // Close button
+ const closeBtn = document.createElement("button");
+ closeBtn.type = "button";
+ closeBtn.className = "mageforge-toolbar-menu-close";
+ closeBtn.title = "Close & deactivate all";
+ closeBtn.setAttribute("aria-label", "Close & deactivate all");
+ closeBtn.innerHTML =
+ '';
+ closeBtn.onclick = (e) => {
e.stopPropagation();
this.deactivateAllAudits();
this.closeMenu();
};
+ actions.appendChild(closeBtn);
+
+ this._updateThemeToggle();
return header;
},
@@ -718,16 +760,26 @@ export const buildMethods = {
const footer = document.createElement("div");
footer.className = "mageforge-toolbar-menu-footer";
- // Export format row ──────────────────────────────────────────────────
- const exportRow = document.createElement("div");
- exportRow.className = "mageforge-footer-theme-row";
- this._exportBtnRow = exportRow;
- const exportGroup = document.createElement("div");
- exportGroup.className = "mageforge-theme-toggle";
+ // Footer toolbar row: credit + theme toggle + export formats
+ const footerRow = document.createElement("div");
+ footerRow.className = "mageforge-footer-toolbar-row";
+
+ // Credit line
+ const credit = document.createElement("div");
+ credit.className = "mageforge-toolbar-menu-credit";
+ credit.innerHTML =
+ 'Built with by ';
+ footerRow.appendChild(credit);
+
+ // Export format toggle
+ this._exportBtnRow = document.createElement("div");
+ this._exportBtnRow.className = "mageforge-segmented-toggle";
+ this._exportBtnRow.setAttribute("role", "group");
+ this._exportBtnRow.setAttribute("aria-label", "Export format");
const exportLabel = document.createElement("span");
- exportLabel.className = "mageforge-footer-theme-label";
+ exportLabel.className = "mageforge-footer-toolbar-label";
exportLabel.textContent = "Export";
- exportGroup.appendChild(exportLabel);
+ this._exportBtnRow.appendChild(exportLabel);
[
["json", "JSON"],
["md", "MD"],
@@ -735,7 +787,7 @@ export const buildMethods = {
].forEach(([fmt, label]) => {
const btn = document.createElement("button");
btn.type = "button";
- btn.className = "mageforge-theme-btn mageforge-export-btn--disabled";
+ btn.className = "mageforge-segmented-btn mageforge-export-btn--disabled";
btn.dataset.exportFormat = fmt;
btn.textContent = label;
btn.disabled = true;
@@ -745,17 +797,11 @@ export const buildMethods = {
e.stopPropagation();
this.exportFindings(fmt);
};
- exportGroup.appendChild(btn);
+ this._exportBtnRow.appendChild(btn);
});
- exportRow.appendChild(exportGroup);
- footer.appendChild(exportRow);
+ footerRow.appendChild(this._exportBtnRow);
- // Credit line (left side of export row) ─────────────────────────────
- const credit = document.createElement("div");
- credit.className = "mageforge-toolbar-menu-credit";
- credit.innerHTML =
- 'Built with by ';
- exportRow.insertBefore(credit, exportRow.firstChild);
+ footer.appendChild(footerRow);
// Populate nav action bar for the initially active tab (home).
// footerActionBar was already created in _buildTabNav().
diff --git a/src/view/frontend/web/js/toolbar/ui/constants.js b/src/view/frontend/web/js/toolbar/ui/constants.js
index c5f5bc87..3cb99971 100644
--- a/src/view/frontend/web/js/toolbar/ui/constants.js
+++ b/src/view/frontend/web/js/toolbar/ui/constants.js
@@ -6,6 +6,15 @@ export const LOGO_SVG_PATH =
export const ICON_HOME =
'';
+export const ICON_THEME_DARK =
+ '';
+
+export const ICON_THEME_LIGHT =
+ '';
+
+export const ICON_THEME_AUTO =
+ '';
+
export const GROUP_ICONS = {
wcag: '',
"html-quality":
diff --git a/src/view/frontend/web/js/toolbar/ui/controls.js b/src/view/frontend/web/js/toolbar/ui/controls.js
index 33838406..c26ff993 100644
--- a/src/view/frontend/web/js/toolbar/ui/controls.js
+++ b/src/view/frontend/web/js/toolbar/ui/controls.js
@@ -96,6 +96,7 @@ export const controls = {
this.runAllButton = null;
this.resetButton = null;
this._exportBtnRow = null;
+ this._themeToggleGroup = null;
this.menuOpen = false;
},
@@ -110,5 +111,20 @@ export const controls = {
localStorage.setItem("mageforge-theme", theme);
} catch (_) {}
if (this.container) this.container.setAttribute("data-theme", theme);
+ this._updateThemeToggle();
+ },
+
+ /**
+ * Reflect the current theme in the header icon toggle buttons.
+ */
+ _updateThemeToggle() {
+ if (!this._themeToggleGroup) return;
+ this._themeToggleGroup
+ .querySelectorAll(".mageforge-theme-icon-btn")
+ .forEach((btn) => {
+ const active = btn.dataset.themeValue === this.currentTheme;
+ btn.classList.toggle("mageforge-theme-icon-btn--active", active);
+ btn.setAttribute("aria-pressed", String(active));
+ });
},
};
diff --git a/src/view/frontend/web/js/toolbar/ui/score.js b/src/view/frontend/web/js/toolbar/ui/score.js
index b34ded85..da0f9c65 100644
--- a/src/view/frontend/web/js/toolbar/ui/score.js
+++ b/src/view/frontend/web/js/toolbar/ui/score.js
@@ -7,6 +7,30 @@
import { GAUGE_ARC_LENGTH, SCORE_RING_CIRCUMFERENCE } from "./constants.js";
export const scoreMethods = {
+ /**
+ * Apply a colour class to a score element based on its value.
+ * < 50 = low (red), 50–89 = mid (amber), >= 90 = high (green).
+ *
+ * @param {HTMLElement|null} el
+ * @param {number} score
+ */
+ _applyScoreColorClass(el, score) {
+ if (!el) return;
+ el.classList.remove(
+ "mageforge-score--low",
+ "mageforge-score--mid",
+ "mageforge-score--high",
+ );
+ if (score < 0) return;
+ if (score < 50) {
+ el.classList.add("mageforge-score--low");
+ } else if (score < 90) {
+ el.classList.add("mageforge-score--mid");
+ } else {
+ el.classList.add("mageforge-score--high");
+ }
+ },
+
/**
* Animate all score gauges and rings to the given score (0-100).
*
@@ -32,9 +56,13 @@ export const scoreMethods = {
needle.setAttribute("opacity", "1");
}
this.menu
- .querySelectorAll(".mageforge-toolbar-health-score-number")
+ .querySelectorAll(".mageforge-toolbar-health-score-value")
.forEach((el) => {
- el.textContent = score;
+ const number = el.querySelector(
+ ".mageforge-toolbar-health-score-number",
+ );
+ if (number) number.textContent = score;
+ this._applyScoreColorClass(el, score);
});
// Circular rings in audit panel headers
@@ -69,9 +97,13 @@ export const scoreMethods = {
);
}
const number = panel.querySelector(".mageforge-score-number");
+ const valueEl = panel.querySelector(".mageforge-score-value");
if (number) {
number.textContent = score;
}
+ if (valueEl) {
+ this._applyScoreColorClass(valueEl, score);
+ }
// Also update the dashboard category badge
const dashboardScore = this.menu.querySelector(
@@ -83,6 +115,7 @@ export const scoreMethods = {
"mageforge-dashboard-category-score--active",
score > 0,
);
+ this._applyScoreColorClass(dashboardScore, score);
}
},
@@ -111,6 +144,13 @@ export const scoreMethods = {
this.menu.querySelectorAll(".mageforge-score-number").forEach((el) => {
el.textContent = "--";
});
+ this.menu
+ .querySelectorAll(
+ ".mageforge-toolbar-health-score-value, .mageforge-score-value, .mageforge-dashboard-category-score",
+ )
+ .forEach((el) => {
+ this._applyScoreColorClass(el, -1);
+ });
// Reset dashboard category badges
this.menu.querySelectorAll("[data-dashboard-group-score]").forEach((el) => {