diff --git a/src/js/salon.js b/src/js/salon.js
index 5892475b4a20ba21710e9910a363db3a14d171d3..d8e3d69716ee4ff5598bca4a9ca5d84f893b3cd9 100644
--- a/src/js/salon.js
+++ b/src/js/salon.js
@@ -322,7 +322,7 @@ App.Medicine.Salon.ears = function(slave, {primaryEarColor = 0, secondaryEarColo
  * @param {string} [params.secondaryHairColor]
  * @returns {node}
  */
-App.Medicine.Salon.hair = function(slave, {primaryHairColor = 0, secondaryHairColor = ""} = {}) {
+App.Medicine.Salon.hair = function(slave, {primaryHairColor = 0, secondaryHairColor = "", primaryTailColor = 0, secondaryTailColor = ""} = {}) {
 	const frag = new DocumentFragment();
 	let updatePrimary = (newVal) => { primaryHairColor = newVal.value; apply(); };
 	let updateSecondary = (newVal) => { secondaryHairColor = newVal.value; apply(); };
@@ -343,6 +343,7 @@ App.Medicine.Salon.hair = function(slave, {primaryHairColor = 0, secondaryHairCo
 		frag.append(wigStyle());
 		frag.append(wigLength());
 	}
+	frag.append(tailDye());
 	return jQuery("#salonHair").empty().append(frag);
 
 	function hairDye() {
@@ -359,6 +360,8 @@ App.Medicine.Salon.hair = function(slave, {primaryHairColor = 0, secondaryHairCo
 					"Restore natural color",
 					() => {
 						slave.hColor = slave.origHColor;
+						App.Art.refreshSlaveArt(slave, 3, "artFrame");
+						cashX(forceNeg(V.modCost), "slaveMod", slave);
 						apply();
 					}
 				)
@@ -650,6 +653,70 @@ App.Medicine.Salon.hair = function(slave, {primaryHairColor = 0, secondaryHairCo
 		return frag;
 	}
 
+	function tailDye() {
+		const frag = new DocumentFragment();
+		if (slave.tail === "none") {
+			return frag;
+		}
+		let updatePrimary = (newVal) => { primaryTailColor = newVal.value; apply(); };
+		let updateSecondary = (newVal) => { secondaryTailColor = newVal.value; apply(); };
+		let div;
+		let p;
+		frag.append(`${His} tail is ${slave.tailColor}.`);
+
+		div = document.createElement("div");
+		div.classList.add("choices");
+		if (slave.origHColor !== slave.hColor) {
+			div.append(
+				App.UI.DOM.link(
+					"Match current hair",
+					() => {
+						slave.tailColor = slave.hColor;
+						App.Art.refreshSlaveArt(slave, 3, "artFrame");
+						cashX(forceNeg(V.modCost), "slaveMod", slave);
+						apply();
+					}
+				)
+			);
+			div.append(" or ");
+			App.UI.DOM.appendNewElement("span", div, "choose a new one: ", "note");
+		} else {
+			App.UI.DOM.appendNewElement("span", div, `Choose a dye color before dyeing ${his} tail:`, "note");
+		}
+		frag.append(div);
+
+		div = document.createElement("div");
+		div.classList.add("choices");
+		div.append(`Colors:`);
+		div.append(createList(App.Medicine.Modification.Color.Primary, updatePrimary));
+		frag.append(div);
+
+		div = document.createElement("div");
+		div.classList.add("choices");
+		div.append(`Highlights:`);
+		div.append(createList(App.Medicine.Modification.Color.Secondary, updateSecondary));
+		frag.append(div);
+
+		if (primaryTailColor !== 0) {
+			p = document.createElement("p");
+			p.classList.add("choices");
+			p.append(
+				App.UI.DOM.link(
+					`Color ${his} tail`,
+					() => {
+						slave.tailColor = (primaryTailColor + secondaryTailColor);
+						App.Art.refreshSlaveArt(slave, 3, "artFrame");
+						cashX(forceNeg(V.modCost), "slaveMod", slave);
+						App.Medicine.Salon.hair(slave); // discard selections after locking them in.
+					}
+				)
+			);
+			p.append(` ${primaryTailColor}${secondaryTailColor} now?`);
+			frag.append(p);
+		}
+		return frag;
+	}
+
 	function createList(array, method) {
 		const links = [];
 		for (const item of array) {
@@ -676,6 +743,8 @@ App.Medicine.Salon.hair = function(slave, {primaryHairColor = 0, secondaryHairCo
 			{
 				primaryHairColor: primaryHairColor,
 				secondaryHairColor: secondaryHairColor,
+				primaryTailColor: primaryTailColor,
+				secondaryTailColor: secondaryTailColor,
 			}
 		);
 	}