/* Copyright (C) 2025 Moko Consulting <hello@mokoconsulting.tech>

 This file is part of a Moko Consulting project.

 SPDX-License-Identifier: GPL-3.0-or-later
 */

(function (win, doc) {
	"use strict";

	// ========================================================================
	// THEME INITIALIZATION (Early theme application)
	// ========================================================================
	var storageKey = "theme";
	var mql = win.matchMedia("(prefers-color-scheme: dark)");
	var root = doc.documentElement;

	/**
	 * Apply theme to <html>, syncing both data-bs-theme and data-aria-theme.
	 * @param {"light"|"dark"} theme
	 */
	function applyTheme(theme) {
		root.setAttribute("data-bs-theme", theme);
		root.setAttribute("data-aria-theme", theme);
		try { localStorage.setItem(storageKey, theme); } catch (e) {}
	}

	/**
	 * Clear stored preference so system preference is followed.
	 */
	function clearStored() {
		try { localStorage.removeItem(storageKey); } catch (e) {}
	}

	/**
	 * Determine system theme.
	 */
	function systemTheme() {
		return mql.matches ? "dark" : "light";
	}

	/**
	 * Get stored theme preference.
	 */
	function getStored() {
		try { return localStorage.getItem(storageKey); } catch (e) { return null; }
	}

	// ========================================================================
	// FLOATING THEME TOGGLE (FAB)
	// ========================================================================
	function posClassFromBody() {
		var pos = (doc.body.getAttribute('data-theme-fab-pos') || 'br').toLowerCase();
		if (!/^(br|bl|tr|tl)$/.test(pos)) pos = 'br';
		return 'pos-' + pos;
	}

	function buildThemeToggle() {
		if (doc.getElementById('mokoThemeFab')) return;

		var wrap = doc.createElement('div');
		wrap.id = 'mokoThemeFab';
		wrap.className = posClassFromBody();

		// Sun/Moon toggle button
		var switchWrap = doc.createElement('button');
		switchWrap.id = 'mokoThemeSwitch';
		switchWrap.type = 'button';
		switchWrap.className = 'theme-icon-btn';
		switchWrap.setAttribute('aria-label', 'Toggle dark mode');

		var sunIcon = doc.createElement('i');
		sunIcon.className = 'fa-solid fa-sun';
		sunIcon.setAttribute('aria-hidden', 'true');

		var moonIcon = doc.createElement('i');
		moonIcon.className = 'fa-solid fa-moon';
		moonIcon.setAttribute('aria-hidden', 'true');

		switchWrap.appendChild(sunIcon);
		switchWrap.appendChild(moonIcon);

		function updateThemeIcon(theme) {
			if (theme === 'dark') {
				switchWrap.classList.add('is-dark');
				switchWrap.classList.remove('is-light');
			} else {
				switchWrap.classList.add('is-light');
				switchWrap.classList.remove('is-dark');
			}
		}

		// Auto toggle (on/off switch style)
		var autoWrap = doc.createElement('div');
		autoWrap.className = 'auto-toggle-wrap';

		var autoLabel = doc.createElement('span');
		autoLabel.className = 'auto-label';
		autoLabel.textContent = 'Auto';

		var auto = doc.createElement('button');
		auto.id = 'mokoThemeAuto';
		auto.type = 'button';
		auto.className = 'auto-switch';
		auto.setAttribute('role', 'switch');
		auto.setAttribute('aria-label', 'Automatic theme (follow system)');
		auto.setAttribute('aria-checked', getStored() ? 'false' : 'true');

		var autoTrack = doc.createElement('span');
		autoTrack.className = 'auto-track';
		var autoKnob = doc.createElement('span');
		autoKnob.className = 'auto-knob';
		autoTrack.appendChild(autoKnob);
		auto.appendChild(autoTrack);
		if (!getStored()) auto.classList.add('on');

		autoWrap.appendChild(autoLabel);
		autoWrap.appendChild(auto);

		// Divider before a11y slot
		var divider = doc.createElement('span');
		divider.className = 'fab-divider';

		// A11y slot — buildA11yToolbar will inject its toggle here
		var a11ySlot = doc.createElement('span');
		a11ySlot.id = 'mokoA11ySlot';

		// Behavior
		switchWrap.addEventListener('click', function () {
			var current = (root.getAttribute('data-bs-theme') || 'light').toLowerCase();
			var next = current === 'dark' ? 'light' : 'dark';
			applyTheme(next);
			updateThemeIcon(next);
			// Turn off auto when manually switching
			auto.classList.remove('on');
			auto.setAttribute('aria-checked', 'false');
			// Update meta theme color
			var meta = doc.querySelector('meta[name="theme-color"]');
			if (meta) {
				meta.setAttribute('content', next === 'dark' ? '#0f1115' : '#ffffff');
			}
		});

		auto.addEventListener('click', function () {
			var isAuto = auto.classList.toggle('on');
			auto.setAttribute('aria-checked', isAuto ? 'true' : 'false');
			if (isAuto) {
				clearStored();
				var sys = systemTheme();
				applyTheme(sys);
				updateThemeIcon(sys);
			}
		});

		// Respond to OS changes only when not user-forced
		var onMql = function () {
			if (!getStored()) {
				var sys = systemTheme();
				applyTheme(sys);
				updateThemeIcon(sys);
			}
		};
		if (typeof mql.addEventListener === 'function') mql.addEventListener('change', onMql);
		else if (typeof mql.addListener === 'function') mql.addListener(onMql);

		// Initial state
		var initial = getStored() || systemTheme();
		updateThemeIcon(initial);

		// Mount
		wrap.appendChild(switchWrap);
		wrap.appendChild(autoWrap);
		wrap.appendChild(divider);
		wrap.appendChild(a11ySlot);
		doc.body.appendChild(wrap);

		// Debug helper
		win.mokoThemeFabStatus = function () {
			var el = doc.getElementById('mokoThemeFab');
			if (!el) return { mounted: false };
			var r = el.getBoundingClientRect();
			return {
				mounted: true,
				rect: { top: r.top, left: r.left, width: r.width, height: r.height },
				zIndex: win.getComputedStyle(el).zIndex,
				posClass: el.className
			};
		};

		// Outline if invisible
		setTimeout(function () {
			var r = wrap.getBoundingClientRect();
			if (r.width < 10 || r.height < 10) {
				wrap.classList.add('debug-outline');
				console.warn('[moko] Theme FAB mounted but appears too small — check CSS collisions.');
			}
		}, 50);
	}

	// ========================================================================
	// ACCESSIBILITY TOOLBAR
	// ========================================================================
	var a11yStorageKey = "moko-a11y";
	var fontSizeSteps = [85, 90, 100, 110, 120, 130];
	var defaultStep = 2; // index of 100

	function getA11yPrefs() {
		try {
			var raw = localStorage.getItem(a11yStorageKey);
			if (raw) return JSON.parse(raw);
		} catch (e) {}
		return { fontStep: defaultStep, inverted: false, contrast: false, links: false, font: false, paused: false };
	}

	function saveA11yPrefs(prefs) {
		try { localStorage.setItem(a11yStorageKey, JSON.stringify(prefs)); } catch (e) {}
	}

	function applyFontSize(step) {
		root.style.fontSize = fontSizeSteps[step] + "%";
	}

	function applyInversion(on) {
		if (on) {
			root.classList.add("a11y-inverted");
		} else {
			root.classList.remove("a11y-inverted");
		}
	}

	function applyContrast(on) {
		root.classList.toggle("a11y-high-contrast", on);
		// Lazy-load the high-contrast stylesheet
		var hcId = "mokoA11yHcSheet";
		var existing = doc.getElementById(hcId);
		if (on && !existing) {
			var link = doc.createElement("link");
			link.id = hcId;
			link.rel = "stylesheet";
			link.href = (doc.querySelector('link[href*="mokoonyx/css/template"]') || {}).href
				? (doc.querySelector('link[href*="mokoonyx/css/template"]').href.replace(/\/css\/template[^/]*$/, "/css/a11y-high-contrast.css"))
				: "media/templates/site/mokoonyx/css/a11y-high-contrast.css";
			doc.head.appendChild(link);
		}
	}

	function applyLinks(on) {
		root.classList.toggle("a11y-highlight-links", on);
	}

	function applyFont(on) {
		root.classList.toggle("a11y-readable-font", on);
	}

	function applyPaused(on) {
		root.classList.toggle("a11y-pause-animations", on);
	}

	/** Create a Font Awesome icon element (safe DOM, no innerHTML). */
	function faIcon(classes) {
		var i = doc.createElement("i");
		i.className = classes;
		i.setAttribute("aria-hidden", "true");
		return i;
	}

	function buildA11yToolbar() {
		if (doc.getElementById("mokoA11yToolbar")) return;

		var body = doc.body;
		var showResize     = body.getAttribute("data-a11y-resize") === "1";
		var showInvert     = body.getAttribute("data-a11y-invert") === "1";
		var showContrast   = body.getAttribute("data-a11y-contrast") === "1";
		var showLinks      = body.getAttribute("data-a11y-links") === "1";
		var showFont       = body.getAttribute("data-a11y-font") === "1";
		var showAnimations = body.getAttribute("data-a11y-animations") === "1";
		var pos = (body.getAttribute("data-a11y-pos") || "tl").toLowerCase();
		if (!/^(br|bl|tr|tl)$/.test(pos)) pos = "tl";

		var prefs = getA11yPrefs();

		// Container
		var toolbar = doc.createElement("div");
		toolbar.id = "mokoA11yToolbar";
		toolbar.className = "a11y-pos-" + pos;
		toolbar.setAttribute("role", "toolbar");
		toolbar.setAttribute("aria-label", "Accessibility options");

		// Toggle button (accessibility icon)
		var toggle = doc.createElement("button");
		toggle.type = "button";
		toggle.id = "mokoA11yToggle";
		toggle.className = "a11y-toggle";
		toggle.setAttribute("aria-label", "Accessibility options");
		toggle.setAttribute("aria-expanded", "false");
		var a11yIcon = faIcon("fa-solid fa-universal-access");
		// Unicode fallback if FA7 glyph doesn't render (e.g. FA6/FA7 conflict)
		setTimeout(function () {
			var cs = win.getComputedStyle(a11yIcon, "::before");
			if (!cs.content || cs.content === "none" || cs.content === '""' || cs.content === '"" / ""') {
				a11yIcon.className = "";
				a11yIcon.textContent = "\u267F";
				a11yIcon.style.fontSize = "1.1rem";
			}
		}, 500);
		toggle.appendChild(a11yIcon);

		// Panel
		var panel = doc.createElement("div");
		panel.id = "mokoA11yPanel";
		panel.className = "a11y-panel";
		panel.hidden = true;

		// --- Text resize controls ---
		if (showResize) {
			var resizeGroup = doc.createElement("div");
			resizeGroup.className = "a11y-group";
			resizeGroup.setAttribute("role", "group");
			resizeGroup.setAttribute("aria-label", "Text size");

			var sizeLabel = doc.createElement("span");
			sizeLabel.className = "a11y-group-label";
			sizeLabel.textContent = "Text size";
			resizeGroup.appendChild(sizeLabel);

			var btnRow = doc.createElement("div");
			btnRow.className = "a11y-btn-row";

			var btnMinus = doc.createElement("button");
			btnMinus.type = "button";
			btnMinus.className = "a11y-btn";
			btnMinus.setAttribute("aria-label", "Decrease text size");
			btnMinus.appendChild(faIcon("fa-solid fa-minus"));

			var sizeDisplay = doc.createElement("span");
			sizeDisplay.className = "a11y-size-display";
			sizeDisplay.setAttribute("aria-live", "polite");
			sizeDisplay.textContent = fontSizeSteps[prefs.fontStep] + "%";

			var btnPlus = doc.createElement("button");
			btnPlus.type = "button";
			btnPlus.className = "a11y-btn";
			btnPlus.setAttribute("aria-label", "Increase text size");
			btnPlus.appendChild(faIcon("fa-solid fa-plus"));

			var btnReset = doc.createElement("button");
			btnReset.type = "button";
			btnReset.className = "a11y-btn a11y-btn-reset";
			btnReset.setAttribute("aria-label", "Reset text size");
			btnReset.appendChild(faIcon("fa-solid fa-rotate-left"));

			btnMinus.addEventListener("click", function () {
				if (prefs.fontStep > 0) {
					prefs.fontStep--;
					applyFontSize(prefs.fontStep);
					sizeDisplay.textContent = fontSizeSteps[prefs.fontStep] + "%";
					saveA11yPrefs(prefs);
				}
			});

			btnPlus.addEventListener("click", function () {
				if (prefs.fontStep < fontSizeSteps.length - 1) {
					prefs.fontStep++;
					applyFontSize(prefs.fontStep);
					sizeDisplay.textContent = fontSizeSteps[prefs.fontStep] + "%";
					saveA11yPrefs(prefs);
				}
			});

			btnReset.addEventListener("click", function () {
				prefs.fontStep = defaultStep;
				applyFontSize(prefs.fontStep);
				sizeDisplay.textContent = fontSizeSteps[prefs.fontStep] + "%";
				saveA11yPrefs(prefs);
			});

			btnRow.appendChild(btnMinus);
			btnRow.appendChild(sizeDisplay);
			btnRow.appendChild(btnPlus);
			btnRow.appendChild(btnReset);
			resizeGroup.appendChild(btnRow);
			panel.appendChild(resizeGroup);
		}

		// --- Helper: build a switch-style toggle button ---
		function addSwitchOption(show, prefKey, icon, label, applyFn) {
			if (!show) return;
			var group = doc.createElement("div");
			group.className = "a11y-group";

			var btn = doc.createElement("button");
			btn.type = "button";
			btn.className = "a11y-btn a11y-btn-wide";
			btn.setAttribute("role", "switch");
			btn.setAttribute("aria-checked", prefs[prefKey] ? "true" : "false");
			btn.setAttribute("aria-label", label);
			btn.appendChild(faIcon(icon));
			btn.appendChild(doc.createTextNode(" " + label));

			if (prefs[prefKey]) btn.classList.add("active");

			btn.addEventListener("click", function () {
				prefs[prefKey] = !prefs[prefKey];
				applyFn(prefs[prefKey]);
				btn.setAttribute("aria-checked", prefs[prefKey] ? "true" : "false");
				btn.classList.toggle("active", prefs[prefKey]);
				saveA11yPrefs(prefs);
			});

			group.appendChild(btn);
			panel.appendChild(group);
		}

		// --- Toggle options ---
		addSwitchOption(showInvert,     "inverted", "fa-solid fa-circle-half-stroke", "Invert colors",      applyInversion);
		addSwitchOption(showContrast,   "contrast", "fa-solid fa-adjust",             "High contrast",      applyContrast);
		addSwitchOption(showLinks,      "links",    "fa-solid fa-link",               "Highlight links",    applyLinks);
		addSwitchOption(showFont,       "font",     "fa-solid fa-font",               "Readable font",      applyFont);
		addSwitchOption(showAnimations, "paused",   "fa-solid fa-pause",              "Pause animations",   applyPaused);

		// Apply saved preferences on load
		if (prefs.fontStep !== defaultStep) applyFontSize(prefs.fontStep);
		if (prefs.inverted) applyInversion(true);
		if (prefs.contrast) applyContrast(true);
		if (prefs.links)    applyLinks(true);
		if (prefs.font)     applyFont(true);
		if (prefs.paused)   applyPaused(true);

		// If theme FAB is present, mount a11y toggle inside it; otherwise standalone
		var fabSlot = doc.getElementById("mokoA11ySlot");
		if (fabSlot) {
			toggle.className = "a11y-toggle a11y-toggle-inline";
			fabSlot.appendChild(toggle);
			toolbar.className = "a11y-toolbar-floating";
			toolbar.appendChild(panel);
			body.appendChild(toolbar);
			// Position panel near the FAB
			toggle.addEventListener("click", function () {
				var isOpen = !panel.hidden;
				panel.hidden = isOpen;
				toggle.setAttribute("aria-expanded", isOpen ? "false" : "true");
				toggle.classList.toggle("active", !isOpen);
				if (!isOpen) {
					var rect = toggle.getBoundingClientRect();
					toolbar.style.position = "fixed";
					toolbar.style.bottom = (win.innerHeight - rect.top + 8) + "px";
					toolbar.style.right = (win.innerWidth - rect.right) + "px";
					toolbar.style.zIndex = "1202";
				}
			});
			// Close on outside click for inline mode
			doc.addEventListener("click", function (e) {
				if (!toggle.contains(e.target) && !toolbar.contains(e.target) && !panel.hidden) {
					panel.hidden = true;
					toggle.setAttribute("aria-expanded", "false");
					toggle.classList.remove("active");
				}
			});
		} else {
			// Standalone mode — toggle and close handlers
			toggle.addEventListener("click", function () {
				var isOpen = !panel.hidden;
				panel.hidden = isOpen;
				toggle.setAttribute("aria-expanded", isOpen ? "false" : "true");
				toggle.classList.toggle("active", !isOpen);
			});
			doc.addEventListener("click", function (e) {
				if (!toolbar.contains(e.target) && !panel.hidden) {
					panel.hidden = true;
					toggle.setAttribute("aria-expanded", "false");
					toggle.classList.remove("active");
				}
			});
			toolbar.appendChild(toggle);
			toolbar.appendChild(panel);
			body.appendChild(toolbar);
		}
	}

	// ========================================================================
	// TEMPLATE UTILITIES
	// ========================================================================

	/**
	 * Utility: smooth scroll to top
	 */
	function backToTop() {
		win.scrollTo({ top: 0, behavior: "smooth" });
	}

	/**
	 * Utility: toggle body class on scroll for sticky header styling
	 */
	function handleScroll() {
		if (win.scrollY > 50) {
			doc.body.classList.add("scrolled");
		} else {
			doc.body.classList.remove("scrolled");
		}
	}

	/**
	 * Initialize offcanvas drawer buttons for left/right drawers.
	 * Bootstrap handles drawers automatically via data-bs-toggle="offcanvas"
	 * This function is kept for backwards compatibility but only runs if drawers exist.
	 */
	function initDrawers() {
		// Check if any drawer buttons exist before initializing
		var hasDrawers = doc.querySelector(".drawer-toggle-left") || doc.querySelector(".drawer-toggle-right");
		if (!hasDrawers) {
			return; // No drawers, skip initialization
		}

		// Bootstrap 5 handles offcanvas automatically via data-bs-toggle attribute
		// No manual initialization needed if Bootstrap is loaded correctly
		// The buttons already have data-bs-toggle="offcanvas" and data-bs-target="#drawer-*"
	}

	/**
	 * Initialize back-to-top link if present
	 */
	function initBackTop() {
		var backTop = doc.getElementById("back-top");
		if (backTop) {
			backTop.addEventListener("click", function (e) {
				e.preventDefault();
				backToTop();
			});
		}
	}

	/**
	 * Initialize theme based on stored preference or system setting
	 */
	function initTheme() {
		var stored = getStored();
		var theme = stored ? stored : systemTheme();
		applyTheme(theme);

		// Listen for system changes only if Auto mode (no stored)
		var onChange = function () {
			if (!getStored()) {
				applyTheme(systemTheme());
			}
		};
		if (typeof mql.addEventListener === "function") {
			mql.addEventListener("change", onChange);
		} else if (typeof mql.addListener === "function") {
			mql.addListener(onChange);
		}

		// Hook toggle UI if present (for inline switch, not FAB)
		var switchEl = doc.getElementById("themeSwitch");
		var autoBtn = doc.getElementById("themeAuto");

		if (switchEl) {
			switchEl.checked = (theme === "dark");
			switchEl.addEventListener("change", function () {
				var choice = switchEl.checked ? "dark" : "light";
				applyTheme(choice);
			});
		}

		if (autoBtn) {
			autoBtn.addEventListener("click", function () {
				clearStored();
				applyTheme(systemTheme());
			});
		}
	}

	/**
	 * Check if theme FAB should be enabled based on body data attribute
	 */
	function shouldEnableThemeFab() {
		return doc.body.getAttribute('data-theme-fab-enabled') === '1';
	}

	/**
	 * Convert sidebar card modules into accordion on mobile.
	 * On screens <= 991px each card collapses; on desktop they revert.
	 */
	function initSidebarAccordion() {
		var BREAKPOINT = 992;
		var sidebars = doc.querySelectorAll(".container-sidebar-left, .container-sidebar-right");
		if (!sidebars.length) return;

		// Build accordion structure once — works at all breakpoints
		sidebars.forEach(function (sidebar, si) {
			var accId = "sidebarAcc-" + si;
			sidebar.setAttribute("id", accId);
			sidebar.classList.add("accordion");

			var isMobile = win.innerWidth < BREAKPOINT;
			var cards = sidebar.querySelectorAll(":scope > .card");

			cards.forEach(function (card, ci) {
				var collapseId = accId + "-c" + ci;
				card.classList.add("accordion-item");

				var header = card.querySelector(".card-header");
				var body = card.querySelector(".card-body");
				if (!header || !body) return;

				// Turn header into accordion button
				header.classList.add("accordion-header");
				var btn = doc.createElement("button");
				btn.className = isMobile ? "accordion-button collapsed" : "accordion-button";
				btn.type = "button";
				btn.setAttribute("data-bs-toggle", "collapse");
				btn.setAttribute("data-bs-target", "#" + collapseId);
				btn.setAttribute("aria-expanded", isMobile ? "false" : "true");
				btn.setAttribute("aria-controls", collapseId);
				btn.textContent = header.textContent;
				header.textContent = "";
				header.appendChild(btn);

				// Wrap body in collapse
				var wrapper = doc.createElement("div");
				wrapper.id = collapseId;
				wrapper.className = isMobile ? "accordion-collapse collapse" : "accordion-collapse collapse show";
				wrapper.setAttribute("data-bs-parent", "#" + accId);
				card.insertBefore(wrapper, body);
				wrapper.appendChild(body);
				body.classList.add("accordion-body");
			});
		});
	}

	/**
	 * Toggle search on mobile via .show class
	 */
	function initSearchToggle() {
		var btn = doc.querySelector(".search-toggler");
		var target = doc.getElementById("headerSearchCollapse");
		if (!btn || !target) return;

		btn.addEventListener("click", function () {
			var isOpen = target.classList.toggle("show");
			btn.setAttribute("aria-expanded", isOpen ? "true" : "false");
		});
	}

	// ========================================================================
	// CSS VARIABLE CLICK-TO-COPY
	// ========================================================================

	/**
	 * Inject toast + variable-chip styles once.
	 */
	function injectVarCopyStyles() {
		if (doc.getElementById("moko-var-copy-styles")) return;
		var style = doc.createElement("style");
		style.id = "moko-var-copy-styles";
		style.textContent =
			".moko-var-chip{cursor:pointer;font-family:var(--font-monospace,monospace);font-size:.875em;" +
			"background:var(--secondary-bg,#151b22);color:var(--link-color,#8ab4f8);" +
			"border:1px solid var(--border-color,#2b323b);border-radius:.25rem;padding:.1em .4em;" +
			"transition:background .15s,border-color .15s;white-space:nowrap;display:inline}" +
			".moko-var-chip:hover{background:var(--color-primary,#112855);color:#fff;border-color:var(--color-primary,#112855)}" +
			".moko-toast{position:fixed;bottom:1.5rem;left:50%;transform:translateX(-50%);z-index:10000;" +
			"background:var(--color-primary,#112855);color:#fff;padding:.6rem 1.25rem;" +
			"border-radius:.375rem;font-size:.875rem;box-shadow:0 4px 12px rgba(0,0,0,.25);" +
			"opacity:0;transition:opacity .2s;pointer-events:none}" +
			".moko-toast--show{opacity:1}";
		doc.head.appendChild(style);
	}

	/**
	 * Show a brief "Copied to clipboard" toast.
	 * @param {string} text - The variable name that was copied
	 */
	function showCopyToast(text) {
		var existing = doc.querySelector(".moko-toast");
		if (existing) existing.remove();

		var toast = doc.createElement("div");
		toast.className = "moko-toast";
		toast.textContent = "Copied to clipboard: " + text;
		doc.body.appendChild(toast);

		// Trigger reflow then show
		void toast.offsetWidth;
		toast.classList.add("moko-toast--show");

		setTimeout(function () {
			toast.classList.remove("moko-toast--show");
			setTimeout(function () { toast.remove(); }, 200);
		}, 2000);
	}

	/**
	 * Copy text to clipboard and show toast.
	 * @param {string} text
	 */
	function copyVariable(text) {
		if (navigator.clipboard && navigator.clipboard.writeText) {
			navigator.clipboard.writeText(text).then(function () {
				showCopyToast(text);
			});
		} else {
			// Fallback for older browsers using deprecated API
			var ta = doc.createElement("textarea");
			ta.value = text;
			ta.style.cssText = "position:fixed;left:-9999px";
			doc.body.appendChild(ta);
			ta.select();
			try { doc.execCommand("copy"); } catch (e) { /* noop */ }
			ta.remove();
			showCopyToast(text);
		}
	}

	/**
	 * Scan text nodes for CSS variable patterns (--variable-name) and wrap
	 * each match in a clickable chip that copies the variable to clipboard.
	 */
	function initVarCopy() {
		injectVarCopyStyles();

		// Pattern: --[a-zA-Z] followed by word/hyphen chars
		var varPattern = /--[a-zA-Z][\w-]*/g;

		// Elements to skip (inputs, scripts, styles, already-processed, code editors)
		var SKIP_TAGS = { SCRIPT: 1, STYLE: 1, TEXTAREA: 1, INPUT: 1, SELECT: 1, NOSCRIPT: 1 };

		var walker = doc.createTreeWalker(
			doc.body,
			NodeFilter.SHOW_TEXT,
			{
				acceptNode: function (node) {
					if (SKIP_TAGS[node.parentNode.tagName]) return NodeFilter.FILTER_REJECT;
					if (node.parentNode.classList && node.parentNode.classList.contains("moko-var-chip")) return NodeFilter.FILTER_REJECT;
					if (!varPattern.test(node.nodeValue)) return NodeFilter.FILTER_REJECT;
					varPattern.lastIndex = 0;
					return NodeFilter.FILTER_ACCEPT;
				}
			}
		);

		var textNodes = [];
		while (walker.nextNode()) textNodes.push(walker.currentNode);

		textNodes.forEach(function (node) {
			var text = node.nodeValue;
			var frag = doc.createDocumentFragment();
			var lastIndex = 0;
			var match;

			varPattern.lastIndex = 0;
			while ((match = varPattern.exec(text)) !== null) {
				// Text before the match
				if (match.index > lastIndex) {
					frag.appendChild(doc.createTextNode(text.slice(lastIndex, match.index)));
				}

				// Clickable chip
				var chip = doc.createElement("span");
				chip.className = "moko-var-chip";
				chip.textContent = match[0];
				chip.setAttribute("role", "button");
				chip.setAttribute("tabindex", "0");
				chip.setAttribute("title", "Click to copy " + match[0]);
				chip.addEventListener("click", (function (varName) {
					return function (e) {
						e.preventDefault();
						copyVariable(varName);
					};
				})(match[0]));
				chip.addEventListener("keydown", (function (varName) {
					return function (e) {
						if (e.key === "Enter" || e.key === " ") {
							e.preventDefault();
							copyVariable(varName);
						}
					};
				})(match[0]));
				frag.appendChild(chip);

				lastIndex = match.index + match[0].length;
			}

			// Remaining text after last match
			if (lastIndex < text.length) {
				frag.appendChild(doc.createTextNode(text.slice(lastIndex)));
			}

			node.parentNode.replaceChild(frag, node);
		});
	}

	/**
	 * Run all template JS initializations
	 */
	function init() {
		// Initialize theme first
		initTheme();

		// Build floating theme toggle if enabled
		if (shouldEnableThemeFab()) {
			buildThemeToggle();
		}

		// Build accessibility toolbar if enabled
		if (doc.body.getAttribute("data-a11y-toolbar") === "1") {
			buildA11yToolbar();
		}

		// Sticky header behavior
		handleScroll();
		win.addEventListener("scroll", handleScroll);

		// Init features
		initDrawers();
		initBackTop();
		initSearchToggle();
		initSidebarAccordion();
		initVarCopy();
	}

	if (doc.readyState === "loading") {
		doc.addEventListener("DOMContentLoaded", init);
	} else {
		init();
	}
})(window, document);
