diff --git a/js/002-config/fc-js-init.js b/js/002-config/fc-js-init.js
index 62d42623db99d1fd188f9515d8d3129635e6b299..6141ced53d9bf02b955a9cb84d686eb01cbfaffc 100644
--- a/js/002-config/fc-js-init.js
+++ b/js/002-config/fc-js-init.js
@@ -71,4 +71,3 @@ App.UI.SlaveInteract = {};
 App.UI.View = {};
 App.Update = {};
 App.Utils = {};
-App.Utils.Pronouns = {};
\ No newline at end of file
diff --git a/src/gui/css/mainStyleSheet.css b/src/gui/css/mainStyleSheet.css
index 37d1b869d0b7d0a87ddcaf78e6982284e498065c..f9e22da0b9006f450a96fe4ce49366d8fcda9941 100644
--- a/src/gui/css/mainStyleSheet.css
+++ b/src/gui/css/mainStyleSheet.css
@@ -372,4 +372,20 @@ div.flex-container {
 /* TODO unify tooltip systems */
 .hasTooltip {
 	text-decoration: underline;
-}
\ No newline at end of file
+}
+
+/* interactable tooltip-like container - created/destroyed dynamically */
+.details-overlay {
+	display: inline-block;
+	font-size: smaller;
+	width: max-content;
+	height: max-content;
+	border-style: solid;
+	border-color: slategray;
+	border-width: 2px;
+	border-radius: 3px;
+	background-color: rgb(17, 17, 17);
+	padding: 3px;
+	position: absolute;
+	text-indent: 0;
+}
diff --git a/src/gui/interactiveDetails.js b/src/gui/interactiveDetails.js
new file mode 100644
index 0000000000000000000000000000000000000000..1e9ad9db1a72ba88950c2ad3cb80d261a955159f
--- /dev/null
+++ b/src/gui/interactiveDetails.js
@@ -0,0 +1,44 @@
+/**
+ * Displays a value that you can click on to get some details in an overlay
+ */
+App.UI.DOM.InteractiveDetails = class {
+	/**
+	 * @param {string} linkText text to use for the show/hide link
+	 * @param {function(): HTMLElement|DocumentFragment} [detailsGenerator] function which generates the contents of the details overlay (omit to disable details)
+	 * @param {string[]} [linkClasses=[]] list of extra CSS classes to apply to the link
+	 */
+	constructor(linkText, detailsGenerator, linkClasses=[]) {
+		this.span = App.UI.DOM.makeElement("span", "", "details-overlay");
+		this.span.style.visibility = "hidden";
+		this.link = App.UI.DOM.link(linkText, () => this.toggle());
+		this.link.classList.add(...linkClasses);
+		this.func = detailsGenerator;
+		this.shown = false;
+	}
+
+	/**
+	 * Toggle the visibility of the overlay (changing the render state)
+	 */
+	toggle() {
+		this.shown = !this.shown;
+		if (this.shown) {
+			if (this.func) {
+				$(this.span).empty().append(this.func());
+				this.span.style.visibility = "visible";
+			}
+		} else {
+			$(this.span).empty();
+			this.span.style.visibility = "hidden";
+		}
+	}
+
+	/**
+	 * Render the object to the page
+	 * @returns {DocumentFragment}
+	 */
+	render() {
+		const frag = document.createDocumentFragment();
+		frag.append(this.link, this.span);
+		return frag;
+	}
+};
diff --git a/src/js/slaveCostJS.js b/src/js/slaveCostJS.js
index d1d8ee2a0c242260e13fabcfb4fbf219765c0728..65123bbca5f07c4935bf52372ffe9266bc29fae0 100644
--- a/src/js/slaveCostJS.js
+++ b/src/js/slaveCostJS.js
@@ -1596,24 +1596,11 @@ globalThis.Beauty = function(s) {
 
 
 globalThis.BeautyTooltip = function(slave) {
-	// Make a link. Text should be slave's beauty. Clicking the link will display detailed info about that beauty where the link used to be
+	// Make a link. Text should be slave's beauty. Clicking the link will display detailed info about that beauty over the top of the page (tooltip-style)
 	const beauty = Beauty(slave);
-	const el = new DocumentFragment();
-	let span = document.createElement("span");
-	span.id = "beauty-link";
-	if (V.cheatMode || V.debugMode) {
-		span.append(showerButton());
-	} else {
-		App.UI.DOM.appendNewElement("span", span, beauty, ["pink", "bold"]);
-	}
-	el.append(span);
-
-	span = document.createElement("span");
-	span.id = "BeautyTooltip";
-	el.append(span);
-
-	return el;
-
+	const displayFunc = V.cheatMode || V.debugMode ? BeautyDisplay : undefined;
+	const interactor = new App.UI.DOM.InteractiveDetails(beauty.toString(), displayFunc, ["pink", "bold"]);
+	return interactor.render();
 
 	// Upon the link being clicked, set up some links to sort the info and a span to show it in
 	function BeautyDisplay() {
@@ -1631,11 +1618,9 @@ globalThis.BeautyTooltip = function(slave) {
 			App.UI.DOM.link("Descending", () => { direction = "descending"; jQuery('#cheatBeautyContents').empty().append(BeautyFrame()); }, [])
 		]));
 
-		let cheatBeautyContents = document.createElement('div');
+		let cheatBeautyContents = App.UI.DOM.appendNewElement("div", el, BeautyFrame());
 		cheatBeautyContents.id = "cheatBeautyContents";
-		cheatBeautyContents.appendChild(BeautyFrame());
-		el.appendChild(cheatBeautyContents);
-		App.UI.DOM.appendNewElement("div", el, `${beauty * 2}/2 is ${beauty}, their total score`);
+		App.UI.DOM.appendNewElement("div", el, `${beauty * 2}/2 is ${beauty}, ${getPronouns(slave).her} total score`);
 		return el;
 
 		// Set up the frame that contains the info
@@ -1675,32 +1660,6 @@ globalThis.BeautyTooltip = function(slave) {
 			return el;
 		}
 	}
-
-	function hiderButton() {
-		const link = App.UI.DOM.link(
-			`${beauty}:`,
-			() => {
-				jQuery("#beauty-link").empty().append(showerButton());
-				jQuery('#BeautyTooltip').empty();
-			}
-		);
-		link.style.color = "pink";
-		link.style.fontWeight = "bold";
-		return link;
-	}
-
-	function showerButton() {
-		const link = App.UI.DOM.link(
-			beauty,
-			() => {
-				jQuery("#beauty-link").empty().append(hiderButton());
-				jQuery('#BeautyTooltip').empty().append(BeautyDisplay());
-			}
-		);
-		link.style.color = "pink";
-		link.style.fontWeight = "bold";
-		return link;
-	}
 };
 
 // this is a port of the FResult widget
@@ -2170,25 +2129,13 @@ globalThis.FResult = function(s, forSale = 0) {
  * @returns {Node}
  */
 globalThis.FResultTooltip = function(slave, forSale = 0) {
-	// Make a link. Text should be slave's FResult. Clicking the link will display detailed info about that beauty where the link used to be
-	const el = new DocumentFragment();
-	let span = document.createElement("span");
-	span.id = "f-result-link";
-	if (V.cheatMode || V.debugMode) {
-		span.append(showerButton());
-	} else {
-		App.UI.DOM.appendNewElement("span", span, `${FResult(slave, forSale)}.`, ["lightcoral", "bold"]);
-	}
-	el.append(span);
-
-	span = document.createElement("span");
-	span.id = "FResultTooltip";
-	el.append(span);
-
-	return el;
+	// Make a link. Text should be slave's FResult. Clicking the link will display detailed info about that FResult over the top of the page (tooltip-style)
+	const displayFunc = V.cheatMode || V.debugMode ? FResultDisplay : undefined;
+	const interactor = new App.UI.DOM.InteractiveDetails(FResult(slave, forSale).toString(), displayFunc, ["lightcoral", "bold"]);
+	return interactor.render();
 
 	/** Upon the link being clicked, set up some links to sort the info and a span to show it in
-	 * @returns {Node}
+	 * @returns {HTMLElement}
 	 */
 	function FResultDisplay() {
 		let criteria = "value";
@@ -2205,10 +2152,8 @@ globalThis.FResultTooltip = function(slave, forSale = 0) {
 			App.UI.DOM.link("Descending", () => { direction = "descending"; jQuery('#cheatFResultContents').empty().append(FResultFrame); }, [])
 		]));
 
-		let cheatFResultContents = document.createElement('div');
+		let cheatFResultContents = App.UI.DOM.appendNewElement("div", el, FResultFrame());
 		cheatFResultContents.id = "cheatFResultContents";
-		cheatFResultContents.appendChild(FResultFrame());
-		el.appendChild(cheatFResultContents);
 		return el;
 
 		/** Set up the frame that contains the info
@@ -2234,7 +2179,7 @@ globalThis.FResultTooltip = function(slave, forSale = 0) {
 				domCell.style.float = "left";
 				domCell.style.width = "3em";
 
-				let textNode = document.createTextNode(line.value);
+				let textNode = document.createTextNode(line.value.toString());
 				if (line.value > 0) {
 					domCell.className = "green";
 				} else if (line.value < 0) {
@@ -2250,31 +2195,6 @@ globalThis.FResultTooltip = function(slave, forSale = 0) {
 			return el;
 		}
 	}
-	function hiderButton() {
-		const link = App.UI.DOM.link(
-			`${FResult(slave, forSale)}:`,
-			() => {
-				jQuery("#f-result-link").empty().append(showerButton());
-				jQuery('#FResultTooltip').empty();
-			}
-		);
-		link.style.color = "lightcoral";
-		link.style.fontWeight = "bold";
-		return link;
-	}
-
-	function showerButton() {
-		const link = App.UI.DOM.link(
-			`${FResult(slave, forSale)}.`,
-			() => {
-				jQuery("#f-result-link").empty().append(hiderButton());
-				jQuery('#FResultTooltip').empty().append(FResultDisplay());
-			}
-		);
-		link.style.color = "lightcoral";
-		link.style.fontWeight = "bold";
-		return link;
-	}
 };
 
 /**