code:
/**
 * UI for performing surgery. Refreshes without refreshing the passage.
 * @param {App.Entity.SlaveState} slave
 * @param {()=>void} refresh
 * @param {boolean} [cheat=false]
 * @returns {HTMLElement}
 */
App.UI.surgeryPassageLower = function(slave, refresh, cheat = false) {
	const container = document.createElement("span");
	container.append(content());
	return container;

	function content() {
		const frag = new DocumentFragment();
		// const pubertyAge = Math.min(slave.pubertyAgeXX, slave.pubertyAgeXY);
		const {
			His, He,
			his, he, him
		} = getPronouns(slave);
		// const artificiality = 25 - (5 * Math.trunc(V.PC.skill.medicine / 50)) - (5 * V.surgeryUpgrade);

		App.UI.DOM.appendNewElement("h3", frag, `Butt:`);
		frag.append(butt(), asshole());

		App.UI.DOM.appendNewElement("h3", frag, `Sex:`);
		frag.append(labia(), fertility(), sexDescription(), extraSex());
		if (slave.balls > 0) {
			frag.append(balls());
		}
		frag.append(prostate());

		return frag;

		function butt() {
			const el = new DocumentFragment();
			const r = [];
			r.push(`${He}'s got a`);
			if (slave.butt <= 1) {
				r.push(`flat and ${either("skinny", "slim", "taut")} ass.`);
			} else if (slave.butt <= 2) {
				r.push(`${either("rounded, small", "small but rounded", "small, sleek")} rear end.`);
			} else if (slave.butt <= 3) {
				r.push(`${either("big and healthy", "curved and plump", "healthy and plump")} derrière.`);
			} else if (slave.butt <= 4) {
				r.push(`${either("big bubble", "curvy and enticing", "juicy and large")} butt.`);
			} else if (slave.butt <= 5) {
				r.push(`${either("huge", "juicy and huge", "massive and undeniable")} rear end.`);
			} else if (!hasBothLegs(slave)) {
				r.push(`ridiculous ass. It's so big it would jiggle as ${he} walked — if ${he} could walk.`);
			} else {
				r.push(`ridiculous ass. It's so big it jiggles as ${he} walks.`);
			}

			if (slave.buttImplant > 0) {
				r.push(`${He} has`);
				if (slave.buttImplantType === "string") {
					if (slave.buttImplant > 2) {
						r.push(`massively engorged`);
					}
				} else if (slave.buttImplantType === "normal") {
					if (slave.buttImplant === 1) {
						r.push(`moderate`);
					} else if (slave.buttImplant === 2) {
						r.push(`enormous`);
					} else {
						r.push(`absurd`);
					}
				} else if (slave.buttImplantType === "hyper fillable") {
					if (slave.buttImplant > 19) {
						r.push(`overfilled`);
					} else if (slave.buttImplant < 9) {
						r.push(`underfilled`);
					} else if (slave.buttImplant <= 5) {
						r.push(`deflated`);
					} else {
						r.push(`absurd`);
					}
				} else if (slave.buttImplantType === "advanced fillable") {
					if (slave.buttImplant > 8) {
						r.push(`overfilled`);
					} else if (slave.buttImplant < 5) {
						r.push(`underfilled`);
					} else if (slave.buttImplant <= 3) {
						r.push(`deflated`);
					} else {
						r.push(`massive`);
					}
				} else if (slave.buttImplantType === "fillable") {
					if (slave.buttImplant > 4) {
						r.push(`overfilled`);
					} else if (slave.buttImplant < 3) {
						r.push(`underfilled`);
					} else if (slave.buttImplant === 1) {
						r.push(`deflated`);
					} else {
						r.push(`massive`);
					}
				}
				if (slave.buttImplantType !== "normal") {
					r.push(`${slave.buttImplantType}`);
				}
				r.push(`butt implants.`);
				if (slave.buttImplant > 3 && slave.buttImplantType === "string") {
					r.push(App.UI.DOM.makeElement("span", "Large string based implants are a risk to a slave's health.", "yellow"));
				}
			}
			App.Events.addNode(el, r, "div");

			const surgeries = App.Medicine.Surgery.sizingProcedures.butt(slave, App.Medicine.Surgery.allSizingOptions());
			const surgeryLinks = surgeries.map(s => App.Medicine.Surgery.makeLink(s, refresh, cheat));
			App.UI.DOM.appendNewElement("div", el, App.UI.DOM.generateLinksStrip(surgeryLinks), "choices");
			return el;
		}

		function asshole() {
			const el = new DocumentFragment();
			const r = [];
			const linkArray = [];
			r.push(`${He} has`);
			if (slave.anus === 0) {
				r.push(`a virgin asshole.`);
			} else if (slave.anus === 1) {
				r.push(`a tight asshole.`);
			} else if (slave.anus === 2) {
				r.push(`a loose asshole.`);
			} else if (slave.anus === 3) {
				r.push(`a very loose asshole.`);
			} else {
				r.push(`a permanently gaping asshole.`);
			}
			if (slave.anus > 3) {
				r.push(`${His} anal sphincter could benefit from surgical repair.`);
				linkArray.push(App.Medicine.Surgery.makeLink(
					new App.Medicine.Surgery.Procedures.RepairAnus(slave),
					refresh, cheat));
			} else if (V.surgeryUpgrade === 1 && slave.indentureRestrictions < 2) {
				if (slave.anus > 1) {
					r.push(`${His} anal sphincter could benefit from microsurgical rejuvenation.`);
					linkArray.push(App.Medicine.Surgery.makeLink(
						new App.Medicine.Surgery.Procedures.TightenAnus(slave),
						refresh, cheat));
				} else if (slave.anus > 0) {
					r.push(`${His} butthole is fairly narrow, but could be tightened to virgin status.`);
					linkArray.push(App.Medicine.Surgery.makeLink(
						new App.Medicine.Surgery.Procedures.RestoreAnalVirginity(slave),
						refresh, cheat));
				}
			}

			App.Events.addNode(el, r, "div");
			App.UI.DOM.appendNewElement("div", el, App.UI.DOM.generateLinksStrip(linkArray), "choices");
			return el;
		}

		function labia() {
			const el = new DocumentFragment();
			let r = [];
			let linkArray = [];
			if (slave.vagina > -1) {
				if (slave.labia === 0) {
					r.push(`${He} has minimal pussylips.`);
				} else if (slave.labia === 1) {
					r.push(`${He} has pretty, noticeable pussylips.`);
				} else if (slave.labia === 2) {
					r.push(`${He} has large pussylips.`);
				} else if (slave.labia > 2) {
					r.push(`${He} has extremely large pussylips.`);
				}
				if (slave.labia > 0) {
					if (slave.indentureRestrictions < 2) {
						linkArray.push(App.Medicine.Surgery.makeLink(
							new App.Medicine.Surgery.Procedures.Labiaplasty(slave),
							refresh, cheat));
					}
				}
				if (slave.labia < 3 && V.surgeryUpgrade === 1) {
					if (slave.indentureRestrictions < 1) {
						linkArray.push(App.Medicine.Surgery.makeLink(
							new App.Medicine.Surgery.Procedures.IncreaseLabia(slave),
							refresh, cheat));
					}
				}
				App.Events.addNode(el, r, "div");
				App.UI.DOM.appendNewElement("div", el, App.UI.DOM.generateLinksStrip(linkArray), "choices");
				if (slave.dick === 0) {
					r = [];
					linkArray = [];
					r.push(`${He} has`);
					if (slave.clit === 0) {
						r.push(`a small clit`);
					} else if (slave.clit === 1) {
						r.push(`a big clit`);
					} else if (slave.clit === 2) {
						r.push(`a huge clit`);
					} else if (slave.clit > 2) {
						r.push(`an enormous clit`);
					}
					if (V.seeCircumcision === 1 && slave.foreskin > 0) {
						r.push(`with a hood.`);
					} else {
						r.push(r.pop() + `.`);
					}

					if (slave.clit > 0) {
						if (slave.indentureRestrictions < 2) {
							linkArray.push(App.Medicine.Surgery.makeLink(
								new App.Medicine.Surgery.Procedures.ClitoralReduction(slave),
								refresh, cheat));
						}
					}
					if (slave.clit < 3 && V.surgeryUpgrade === 1) {
						if (slave.indentureRestrictions < 1) {
							linkArray.push(App.Medicine.Surgery.makeLink(
								new App.Medicine.Surgery.Procedures.ClitoralEnlargement(slave),
								refresh, cheat));
						}
					}
					if (slave.foreskin > 0 && slave.clit > 0) {
						if (V.seeCircumcision === 1) {
							if (slave.indentureRestrictions < 2) {
								linkArray.push(App.Medicine.Surgery.makeLink(
									new App.Medicine.Surgery.Procedures.RemoveClitHood(slave),
									refresh, cheat));
							}
						}
					}
					App.Events.addNode(el, r, "div");
					App.UI.DOM.appendNewElement("div", el, App.UI.DOM.generateLinksStrip(linkArray), "choices");
				}
			}
			return el;
		}

		function fertility() {
			const el = new DocumentFragment();
			let r = [];
			let linkArray = [];

			if (slave.preg > -2 && slave.preg < 1 && (slave.ovaries !== 0 || slave.mpreg !== 0) && slave.pubertyXX === 0) {
				r.push(`${He} has not had ${his} first period.`);
			} else if (slave.preg > -2 && slave.preg < 1 && (slave.ovaries !== 0 || slave.mpreg !== 0)) {
				r.push(`${He} has a working womb.`);
			} else if (slave.preg <= -2 && (slave.ovaries !== 0 || slave.mpreg !== 0)) {
				r.push(`${He} has a sterile womb.`);
			}

			if (isFertile(slave) && slave.preg === 0) {
				linkArray.push(
					App.UI.DOM.passageLink(
						"Artificially inseminate",
						"Artificial Insemination"
					)
				);
			}

			if (slave.ovaries !== 0 || slave.mpreg !== 0) {
				if (slave.preg > -2 && slave.preg < 1) {
					if (slave.indentureRestrictions < 1 && (slave.breedingMark !== 1 || V.propOutcome === 0 || V.eugenicsFullControl === 1 || V.arcologies[0].FSRestart === "unset")) {
						linkArray.push(App.Medicine.Surgery.makeLink(
							new App.Medicine.Surgery.Procedures.Sterilize(slave),
							refresh, cheat));
					}
				} else if (slave.preg === -2) {
					linkArray.push(App.Medicine.Surgery.makeLink(
						new App.Medicine.Surgery.Procedures.RestoreFertility(slave),
						refresh, cheat));
				}
			}

			App.Events.addNode(el, r, "div");
			App.UI.DOM.appendNewElement("div", el, App.UI.DOM.generateLinksStrip(linkArray), "choices");
			if (slave.ovaries === 1 || slave.mpreg === 1) {
				r = [];
				linkArray = [];
				if (slave.pubertyXX === 0) {
					r.push(`${He} has`);
					if (slave.eggType !== "human") {
						r.push(slave.eggType);
					}
					r.push(`ovaries but has not had ${his} first period.`);
				} else {
					r.push(`${He} has working`);
					if (slave.eggType !== "human") {
						r.push(slave.eggType);
					}
					r.push(`ovaries${(slave.mpreg) ? ` and a womb attached to ${his} rectum` : ``}.`);
				}

				if (slave.indentureRestrictions > 0) {
					App.UI.DOM.appendNewElement("div", el, `${His} indenture forbids elective surgery`, ["choices", "note"]);
				} else {
					if (slave.ovaImplant !== 0) {
						switch (slave.ovaImplant) {
							case "fertility":
								r.push(`They have fertility implants attached to them.`);
								linkArray.push(App.Medicine.Surgery.makeLink(
									new App.Medicine.Surgery.Procedures.RemoveOvaImplant(slave),
									refresh, cheat));
								break;
							case "sympathy":
								r.push(`They are linked via implants and ovulate in concert.`);
								linkArray.push(App.Medicine.Surgery.makeLink(
									new App.Medicine.Surgery.Procedures.RemoveOvaImplant(slave),
									refresh, cheat));
								break;
							case "asexual":
								r.push(`One has been replaced with a sperm producing analog for self-fertilization.`);
						}
					} else {
						if (V.fertilityImplant === 1) {
							linkArray.push(App.Medicine.Surgery.makeLink(
								new App.Medicine.Surgery.Procedures.InstallOvaImplant(slave, "fertility"),
								refresh, cheat));
						}
						if (V.sympatheticOvaries === 1) {
							linkArray.push(App.Medicine.Surgery.makeLink(
								new App.Medicine.Surgery.Procedures.InstallOvaImplant(slave, "sympathy"),
								refresh, cheat));
						}
					}
					App.Events.addNode(el, r, "div");
					App.UI.DOM.appendNewElement("div", el, App.UI.DOM.generateLinksStrip(linkArray), "choices");
				}

				if (slave.indentureRestrictions < 1 && (slave.breedingMark !== 1 || V.propOutcome === 0 || V.eugenicsFullControl === 1 || V.arcologies[0].FSRestart === "unset")) {
					r = [];
					linkArray = [];
					if (slave.ovaries === 1) {
						if (slave.preg > 0) {
							linkArray.push(
								App.UI.DOM.disabledLink(
									"Oophorectomy",
									[`${His} ovaries and womb cannot be removed while ${he} is pregnant.`]
								)
							);
						} else {
							linkArray.push(App.Medicine.Surgery.makeLink(
								new App.Medicine.Surgery.Procedures.Oophorectomy(slave),
								refresh, cheat));
						}
					}
					if (slave.mpreg === 1) {
						if (slave.preg > 0) {
							linkArray.push(
								App.UI.DOM.disabledLink(
									"Remove anal reproductive organs",
									[`${His} anal womb cannot be removed while ${he} is pregnant.`]
								)
							);
						} else {
							linkArray.push(App.Medicine.Surgery.makeLink(
								new App.Medicine.Surgery.Procedures.RemoveMPreg(slave),
								refresh, cheat));
						}
					}
					App.Events.addNode(el, r, "div");
					App.UI.DOM.appendNewElement("div", el, App.UI.DOM.generateLinksStrip(linkArray), "choices");
				}

				if (V.seeExtreme === 1 && V.seeHyperPreg === 1 && V.seePreg !== 0 && V.permaPregImplant === 1) {
					r = [];
					linkArray = [];
					if (slave.assignment === Job.DAIRY && V.dairyPregSetting > 0) {
						r.push(`${His} womb is already rented out for the production of calves.`);
					} else if (slave.broodmother > 0) {
						r.push(`${He} has been made into a`);
						if (slave.broodmother > 1) {
							r.push(`hyper-`);
						}
						r.push(`broodmother.`);
						if (slave.womb.length === 0) {
							linkArray.push(App.Medicine.Surgery.makeLink(
								new App.Medicine.Surgery.Procedures.RemovePregGenerator(slave),
								refresh, cheat));
						} else {
							r.push(`${He} is pregnant right now, so ${his} broodmother implant can't be safely extracted.`);
							if (slave.broodmother === 1 && slave.broodmotherFetuses === 1 && V.PGHack === 1) {
								// hack can be applied only one time, for type 1 broodmothers, and only if implant already present
								linkArray.push(App.Medicine.Surgery.makeLink(
									new App.Medicine.Surgery.Procedures.HackPregGenerator(slave),
									refresh, cheat));
							} else if (slave.broodmother === 1 && slave.broodmotherFetuses > 1) {
								r.push(`The implant firmware has already been adjusted.`);
							}
						}
					} else if (slave.indentureRestrictions > 0) {
						App.UI.DOM.appendNewElement("div", el, `${His} indenture forbids elective surgery`, ["choices", "note"]);
					} else if (slave.breedingMark === 1 && V.propOutcome === 1 && V.eugenicsFullControl !== 1 && V.arcologies[0].FSRestart !== "unset") {
						App.UI.DOM.appendNewElement("div", el, `${He} is protected from extreme surgery`, ["choices", "note"]);
					} else if (isFertile(slave) && slave.ovaryAge <= 46) {
						r.push(`${He} could be made into a broodmother.`);
						linkArray.push(App.Medicine.Surgery.makeLink(
							new App.Medicine.Surgery.Procedures.ImplantPregGenerator(slave),
							refresh, cheat));
					} else {
						r.push(`${His} body cannot support being a broodmother.`);
					}
					App.Events.addNode(el, r, "div");
					App.UI.DOM.appendNewElement("div", el, App.UI.DOM.generateLinksStrip(linkArray), "choices");
				}
			}

			return el;
		}

		function sexDescription() {
			const el = new DocumentFragment();
			const r = [];
			const linkArray = [];
			if (slave.dick === 0 && slave.vagina === -1) {
				r.push(`${He} is a null, possessing neither penis nor vagina.`);
			} else if (slave.dick !== 0) {
				r.push(`${He} has`);
				if (V.seeCircumcision === 1) {
					if (slave.foreskin === 0) {
						r.push(`a circumcised`);
					} else if (slave.foreskin >= 1) {
						r.push(`an uncircumcised`);
					}
				} else {
					r.push(`a`);
				}
				if (slave.vagina === -1) {
					r.push(`penis.`);
				} else if (slave.ovaries !== 0) {
					r.push(`penis and a`);
				} else if (slave.vagina !== -1) {
					r.push(`penis and`);
					if (slave.genes === "XY") {
						r.push(`an artificial`);
					} else {
						r.push(`a`);
					}
				}
			} else if (slave.dick === 0) {
				r.push(`${He} has a`);
			}

			if (slave.vagina > -1) {
				if (slave.vagina === 0) {
					r.push(`virgin pussy.`);
				} else if (slave.vagina === 1) {
					r.push(`tight pussy.`);
				} else if (slave.vagina === 2) {
					r.push(`used pussy.`);
				} else if (slave.vagina === 3) {
					r.push(`loose pussy.`);
				} else if (slave.vagina === 10) {
					r.push(`ruined cunt.`);
				} else {
					r.push(`gaping cunt.`);
				}
			}

			if (slave.dick !== 0 && (slave.ovaries !== 0 || slave.vagina !== -1)) {
				r.push(`It's possible to remove either and leave ${him} sexually functional.`);
			}
			if (slave.vagina > -1) {
				if (slave.indentureRestrictions < 1 && (slave.breedingMark !== 1 || V.propOutcome === 0 || V.eugenicsFullControl === 1 || V.arcologies[0].FSRestart === "unset")) {
					linkArray.push(App.Medicine.Surgery.makeLink(
						new App.Medicine.Surgery.Procedures.VaginaRemoval(slave),
						refresh, cheat));
				}
			}

			if (slave.indentureRestrictions < 1 && (slave.breedingMark !== 1 || V.propOutcome === 0 || V.eugenicsFullControl === 1 || V.arcologies[0].FSRestart === "unset")) {
				if (slave.vagina === -1 && slave.dick !== 0) {
					linkArray.push(App.Medicine.Surgery.makeLink(
						new App.Medicine.Surgery.Procedures.MaletoFemale(slave),
						refresh, cheat));
				}
				if (slave.vagina === -1 && slave.dick === 0 && V.surgeryUpgrade === 1) {
					linkArray.push(App.Medicine.Surgery.makeLink(
						new App.Medicine.Surgery.Procedures.NoneToFemale(slave),
						refresh, cheat));
				}
				if (slave.dick > 0 && V.seeExtreme === 1) {
					linkArray.push(App.Medicine.Surgery.makeLink(
						new App.Medicine.Surgery.Procedures.ChopPenis(slave),
						refresh, cheat));
				}
				if (slave.foreskin > 0 && slave.dick > 0) {
					if (slave.indentureRestrictions < 2) {
						if (V.seeCircumcision === 1) {
							linkArray.push(App.Medicine.Surgery.makeLink(
								new App.Medicine.Surgery.Procedures.RemoveForeskin(slave),
								refresh, cheat));
						}
						if (slave.foreskin - slave.dick > 0) {
							linkArray.push(App.Medicine.Surgery.makeLink(
								new App.Medicine.Surgery.Procedures.ForeskinTuck(slave),
								refresh, cheat));
						}
					}
				}
			}

			if (slave.dick !== 0 && slave.vagina === -1 && V.surgeryUpgrade === 1) {
				if (slave.indentureRestrictions < 1) {
					linkArray.push(App.Medicine.Surgery.makeLink(
						new App.Medicine.Surgery.Procedures.Herm(slave),
						refresh, cheat));
				}
			}
			App.Events.addNode(el, r, "div");
			App.UI.DOM.appendNewElement("div", el, App.UI.DOM.generateLinksStrip(linkArray), "choices");
			return el;
		}

		function extraSex() {
			const el = new DocumentFragment();
			const r = [];
			const linkArray = [];
			if (slave.vagina > 3) {
				r.push(`${His} vagina could benefit from surgical repair.`);
				linkArray.push(App.Medicine.Surgery.makeLink(
					new App.Medicine.Surgery.Procedures.RepairVagina(slave),
					refresh, cheat));
			} else if (V.surgeryUpgrade === 1 && slave.indentureRestrictions < 2) {
				if (slave.vagina > 1) {
					r.push(`${His} vaginal muscles could benefit from microsurgical rejuvenation.`);
					linkArray.push(App.Medicine.Surgery.makeLink(
						new App.Medicine.Surgery.Procedures.TightenVagina(slave),
						refresh, cheat));
				} else if (slave.vagina > 0) {
					r.push(`${His} pussy is as tight as a virgin's, and ${his} hymen could be restored.`);
					linkArray.push(App.Medicine.Surgery.makeLink(
						new App.Medicine.Surgery.Procedures.RestoreVirginity(slave),
						refresh, cheat));
				}
			}
			App.Events.addNode(el, r, "div");
			App.UI.DOM.appendNewElement("div", el, App.UI.DOM.generateLinksStrip(linkArray), "choices");
			return el;
		}

		function balls() {
			const el = new DocumentFragment();
			const r = [];
			const linkArray = [];
			if (slave.balls === 1) {
				r.push(`${His} testicles are vestigial, but ${he} has balls. Technically. They are`);
			} else if (slave.balls > 1) {
				r.push(`${He} has testicles`);
			}
			if (slave.scrotum > 0) {
				r.push(`located in ${his} scrotum.`);
			} else {
				if (slave.genes === "XY") {
					r.push(`relocated inside ${his} abdomen, and ${his} scrotum has been removed.`);
				} else {
					r.push(`implanted inside ${his} abdomen.`);
				}
			}
			if (slave.scrotum > 0) {
				if (slave.indentureRestrictions < 2) {
					if (slave.scrotum - slave.balls > 0) {
						linkArray.push(App.Medicine.Surgery.makeLink(
							new App.Medicine.Surgery.Procedures.ScrotalTuck(slave),
							refresh, cheat));
					}
				}
				if (slave.indentureRestrictions < 1) {
					linkArray.push(App.Medicine.Surgery.makeLink(
						new App.Medicine.Surgery.Procedures.RelocateBalls(slave),
						refresh, cheat));
				}
			}
			if (V.seeExtreme === 1) {
				linkArray.push(App.Medicine.Surgery.makeLink(
					new App.Medicine.Surgery.Procedures.Geld(slave),
					refresh, cheat));
			}
			if (slave.ballType !== "sterile") {
				linkArray.push(App.Medicine.Surgery.makeLink(
					new App.Medicine.Surgery.Procedures.ChemCastrate(slave),
					refresh, cheat));
			}

			if (slave.vasectomy === 1) {
				r.push(`${He} has had a vasectomy and shoots blanks when ${he} cums${(slave.pubertyXY === 0 || slave.ballType === "sterile") ? `, or would, if ${he} were potent` : ``}.`);
				linkArray.push(App.Medicine.Surgery.makeLink(
					new App.Medicine.Surgery.Procedures.VasectomyUndo(slave),
					refresh, cheat));
			} else {
				if (slave.ballType === "sterile") {
					r.push(`${He} has non-functional testicles.`);
					if (slave.indentureRestrictions < 1) {
						linkArray.push(App.Medicine.Surgery.makeLink(
							new App.Medicine.Surgery.Procedures.Vasectomy(slave),
							refresh, cheat));
					}
				} else {
					r.push(`${He} has working testicles${(slave.pubertyXY === 0) ? `, though ${he} isn't potent` : ``}.`);
					if (slave.indentureRestrictions < 1) {
						linkArray.push(App.Medicine.Surgery.makeLink(
							new App.Medicine.Surgery.Procedures.Vasectomy(slave),
							refresh, cheat));
					}
				}
			}

			App.Events.addNode(el, r, "div");
			App.UI.DOM.appendNewElement("div", el, App.UI.DOM.generateLinksStrip(linkArray), "choices");
			return el;
		}

		function prostate() {
			const el = new DocumentFragment();
			const r = [];
			const linkArray = [];
			if (slave.prostate) {
				r.push(`${He} has a`);
				if (slave.prostate > 2) {
					r.push(`hyperactive, ejaculation enhancing`);
				} else if (slave.prostate > 1) {
					r.push(`hyperactive`);
				} else {
					r.push(`normal`);
				}
				r.push(`prostate.`);
				if (slave.prostate >= 2 && V.prostateImplants === 1) {
					if (slave.prostate < 3) {
						if (slave.indentureRestrictions < 2) {
							linkArray.push(App.Medicine.Surgery.makeLink(
								new App.Medicine.Surgery.Procedures.EjaculationBooster(slave),
								refresh, cheat));
						}
					}
					if (slave.prostate === 3) {
						linkArray.push(App.Medicine.Surgery.makeLink(
							new App.Medicine.Surgery.Procedures.RemoveEjaculationBooster(slave),
							refresh, cheat));
					} else if (slave.prostate === 2) {
						linkArray.push(App.Medicine.Surgery.makeLink(
							new App.Medicine.Surgery.Procedures.EndPrecum(slave),
							refresh, cheat));
					}
				} else {
					if (slave.prostate > 1) {
						linkArray.push(App.Medicine.Surgery.makeLink(
							new App.Medicine.Surgery.Procedures.EndPrecum(slave),
							refresh, cheat));
					}
					if (slave.prostate < 2) {
						if (slave.indentureRestrictions < 2) {
							linkArray.push(App.Medicine.Surgery.makeLink(
								new App.Medicine.Surgery.Procedures.Precum(slave),
								refresh, cheat));
						}
					}
				}
				if (V.seeExtreme === 1) {
					if (slave.indentureRestrictions < 1) {
						linkArray.push(App.Medicine.Surgery.makeLink(
							new App.Medicine.Surgery.Procedures.RemoveProstate(slave),
							refresh, cheat));
					}
				}
			}

			App.Events.addNode(el, r, "div");
			App.UI.DOM.appendNewElement("div", el, App.UI.DOM.generateLinksStrip(linkArray), "choices");
			return el;
		}
	}
};


code:
/**
 * UI for performing surgery. Refreshes without refreshing the passage.
 * @param {App.Entity.SlaveState} slave
 * @param {function():void} refresh
 * @param {boolean} [cheat=false]
 * @returns {HTMLElement}
 */

App.UI.surgeryPassageStructural = function(slave, refresh, cheat = false) {
	const container = document.createElement("span");
	container.append(content());
	return container;

	function content() {
		const frag = new DocumentFragment();
		const {
			His, He,
			he, him
		} = getPronouns(slave);

		frag.append(shoulders(), hips());
		if (hasAnyNaturalLegs(slave)) {
			frag.append(limbLength(), tendons());
		} else if (hasAnyNaturalArms(slave)) {
			frag.append(limbLength());
		}
		App.UI.DOM.appendNewElement("h3", frag, `Amputation`);
		if (slave.indenture < 0) {
			frag.append(amputate());
		} else {
			App.UI.DOM.appendNewElement("div", frag, `${His} indenture forbids disfiguring surgery.`);
		}
		App.UI.DOM.appendNewElement("h3", frag, `Prosthetics`);
		frag.append(prostheticInterface(), tail(), back(), App.Medicine.OrganFarm.fullMenu(slave, refresh, cheat));

		return frag;

		function shoulders() {
			const el = new DocumentFragment();
			const r = [];
			const linkArray = [];

			if (slave.shoulders < -1) {
				r.push(`${He} has very narrow shoulders.`);
			} else if (slave.shoulders < 0) {
				r.push(`${He} has narrow shoulders.`);
			} else if (slave.shoulders < 1) {
				r.push(`${He} has average shoulders.`);
			} else if (slave.shoulders < 2) {
				r.push(`${He} has broad shoulders.`);
			} else if (slave.shoulders === 2) {
				r.push(`${He} has very broad shoulders.`);
			}
			if (slave.shouldersImplant === 0) {
				r.push(`${He} has a natural shoulder structure.`);
			} else if (slave.shouldersImplant > 3) {
				r.push(`${His} shoulders have been completely rebuilt to be massively wider.`);
			} else if (slave.shouldersImplant > 2) {
				r.push(`${His} shoulders have been heavily restructured to broaden them.`);
			} else if (slave.shouldersImplant > 1) {
				r.push(`${His} shoulders have been repeatedly restructured to broaden them.`);
			} else if (slave.shouldersImplant > 0) {
				r.push(`${His} shoulders have been restructured to broaden them.`);
			} else if (slave.shouldersImplant < -3) {
				r.push(`${His} shoulders have been completely rebuilt to be massively narrower.`);
			} else if (slave.shouldersImplant < -2) {
				r.push(`${His} shoulders have been heavily restructured to narrow them.`);
			} else if (slave.shouldersImplant < -1) {
				r.push(`${His} shoulders have been repeatedly restructured to narrow them.`);
			} else if (slave.shouldersImplant < 0) {
				r.push(`${His} shoulders have been restructured to narrow them.`);
			}
			if (slave.indentureRestrictions > 0) {
				App.UI.DOM.appendNewElement("div", el, `${His} indenture forbids elective surgery`, ["choices", "note"]);
			} else {
				if (slave.shouldersImplant === 0 || V.surgeryUpgrade === 1) {
					if (slave.shoulders < 2) {
						linkArray.push(App.Medicine.Surgery.makeLink(new App.Medicine.Surgery.Procedures.BroadenShoulders(slave), refresh, cheat));
					}
					if (slave.shoulders > -2) {
						linkArray.push(App.Medicine.Surgery.makeLink(new App.Medicine.Surgery.Procedures.NarrowShoulders(slave), refresh, cheat));
					}
				}
			}
			App.Events.addNode(el, r, "div");
			App.UI.DOM.appendNewElement("div", el, App.UI.DOM.generateLinksStrip(linkArray), "choices");
			return el;
		}

		function hips() {
			const el = new DocumentFragment();
			const r = [];
			const linkArray = [];
			if (slave.hips < -1) {
				r.push(`${He} has very narrow hips.`);
			} else if (slave.hips < 0) {
				r.push(`${He} has narrow hips.`);
			} else if (slave.hips < 1) {
				r.push(`${He} has average hips.`);
			} else if (slave.hips < 2) {
				r.push(`${He} has broad hips.`);
			} else if (slave.hips < 3) {
				r.push(`${He} has very broad hips.`);
			} else if (slave.hips === 3) {
				r.push(`${He} has doorway-jamming hips.`);
			}
			if (slave.hipsImplant === 0) {
				r.push(`They have not been altered.`);
			} else if (slave.hipsImplant > 3) {
				r.push(`${His} pelvis has been completely rebuilt to be massively wider.`);
			} else if (slave.hipsImplant > 2) {
				r.push(`${His} pelvis has been heavily broadened.`);
			} else if (slave.hipsImplant > 1) {
				r.push(`${His} pelvis has been repeatedly broadened.`);
			} else if (slave.hipsImplant > 0) {
				r.push(`${His} pelvis has been broadened.`);
			} else if (slave.hipsImplant < -3) {
				r.push(`${His} pelvis has been completely rebuilt to be massively narrower.`);
			} else if (slave.hipsImplant < -2) {
				r.push(`${His} pelvis has heavily narrowed.`);
			} else if (slave.hipsImplant < -1) {
				r.push(`${His} pelvis has been repeatedly narrowed.`);
			} else if (slave.hipsImplant < 0) {
				r.push(`${His} pelvis has been narrowed.`);
			}
			if (slave.indentureRestrictions > 0) {
				App.UI.DOM.appendNewElement("div", el, `${His} indenture forbids elective surgery`, ["choices", "note"]);
			} else {
				if (slave.hipsImplant === 0) {
					if (slave.hips < 2 || (slave.hips < 3 && V.surgeryUpgrade === 1)) {
						linkArray.push(App.Medicine.Surgery.makeLink(new App.Medicine.Surgery.Procedures.BroadenPelvis(slave), refresh, cheat));
					}
					if (slave.hips > -2) {
						linkArray.push(App.Medicine.Surgery.makeLink(new App.Medicine.Surgery.Procedures.NarrowPelvis(slave), refresh, cheat));
					}
				} else if (V.surgeryUpgrade === 1) {
					if (slave.hips < 3) {
						linkArray.push(App.Medicine.Surgery.makeLink(new App.Medicine.Surgery.Procedures.BroadenPelvis(slave), refresh, cheat));
					}
					if (slave.hips > -1) {
						linkArray.push(App.Medicine.Surgery.makeLink(new App.Medicine.Surgery.Procedures.NarrowPelvis(slave), refresh, cheat));
					}
				}
			}

			App.Events.addNode(el, r, "div");
			App.UI.DOM.appendNewElement("div", el, App.UI.DOM.generateLinksStrip(linkArray), "choices");
			return el;
		}

		function limbLength() {
			const el = new DocumentFragment();
			const r = [];
			const linkArray = [];

			if (slave.heightImplant === 0) {
				r.push(`${He} has normal femurs and humeri.`);
			} else if (slave.heightImplant > 0) {
				r.push(`${His} femurs, humeri, and other major bones have been `);
				if (slave.heightImplant >= 1) {
					r.push(`considerably `);
				}
				r.push(`lengthened.`);
			} else if (slave.heightImplant < 0) {
				r.push(`${His} femurs, humeri, and other major bones have been `);
				if (slave.heightImplant <= -1) {
					r.push(`considerably `);
				}
				r.push(`shortened.`);
			}
			if (slave.indentureRestrictions < 1) {
				if (slave.heightImplant === 0) {
					linkArray.push(App.Medicine.Surgery.makeLink(new App.Medicine.Surgery.Procedures.IncreaseHeight(slave), refresh, cheat));
					linkArray.push(App.Medicine.Surgery.makeLink(new App.Medicine.Surgery.Procedures.DecreaseHeight(slave), refresh, cheat));
				} else if (slave.heightImplant >= 1) {
					if (slave.height < (Height.mean(slave) + 15) && V.surgeryUpgrade === 1) {
						linkArray.push(App.Medicine.Surgery.makeLink(new App.Medicine.Surgery.Procedures.IncreaseHeight(slave), refresh, cheat));
					}
					if (slave.heightImplant === 1) {
						linkArray.push(App.Medicine.Surgery.makeLink(new App.Medicine.Surgery.Procedures.DecreaseHeight(slave), refresh, cheat));
					} else if (V.surgeryUpgrade === 1) {
						linkArray.push(App.Medicine.Surgery.makeLink(new App.Medicine.Surgery.Procedures.DecreaseHeight(slave), refresh, cheat));
					}
				} else if (slave.heightImplant <= -1) {
					if (slave.height >= (Height.mean(slave) - 15) && V.surgeryUpgrade === 1) {
						linkArray.push(App.Medicine.Surgery.makeLink(new App.Medicine.Surgery.Procedures.DecreaseHeight(slave), refresh, cheat));
					}
					if (slave.heightImplant === -1) {
						linkArray.push(App.Medicine.Surgery.makeLink(new App.Medicine.Surgery.Procedures.IncreaseHeight(slave), refresh, cheat));
					} else if (V.surgeryUpgrade === 1) {
						linkArray.push(App.Medicine.Surgery.makeLink(new App.Medicine.Surgery.Procedures.IncreaseHeight(slave), refresh, cheat));
					}
				}
			}

			App.Events.addNode(el, r, "div");
			App.UI.DOM.appendNewElement("div", el, App.UI.DOM.generateLinksStrip(linkArray), "choices");
			return el;
		}

		function tendons() {
			const el = new DocumentFragment();
			const r = [];
			const linkArray = [];
			if (slave.heels === 0 && hasAnyNaturalLegs(slave)) {
				r.push(`${He} has healthy calves.`);
			} else if (slave.heels === 1 && hasAnyNaturalLegs(slave)) {
				r.push(`${His} calves have been altered so that ${he} cannot walk in anything but very high heels.`);
			}
			if (slave.heels === 0 && hasAnyNaturalLegs(slave) && V.seeExtreme === 1) {
				if (slave.indentureRestrictions < 1) {
					linkArray.push(App.Medicine.Surgery.makeLink(new App.Medicine.Surgery.Procedures.ShortenTendons(slave), refresh, cheat));
				}
			}
			if (slave.heels === 1) {
				linkArray.push(App.Medicine.Surgery.makeLink(new App.Medicine.Surgery.Procedures.ReplaceTendons(slave), refresh, cheat));
			}
			App.Events.addNode(el, r, "div");
			App.UI.DOM.appendNewElement("div", el, App.UI.DOM.generateLinksStrip(linkArray), "choices");
			return el;
		}

		function amputate() {
			const el = new DocumentFragment();
			const r = [];
			r.push(App.Desc.limbs(slave));
			if (isAmputee(slave)) {
				if (slave.PLimb === 1) {
					r.push(`${He} has been implanted with a basic PLimb interface.`);
				} else if (slave.PLimb === 2) {
					r.push(`${He} has been implanted with an advanced PLimb interface.`);
				} else if (slave.PLimb === 3) {
					r.push(`${He} has been implanted with an Quadrupedal Prosthetic interface.`);
				}
			}
			App.Events.addNode(el, r, "div");

			if (V.seeExtreme === 1 && slave.indentureRestrictions < 1 && hasAnyNaturalLimbs(slave)) {
				el.append(amputateSelector());
			}
			return el;
		}

		/**
		 * @returns {HTMLDivElement}
		 */
		function amputateSelector() {
			const outerDiv = document.createElement("div");
			outerDiv.classList.add("choices");
			const linkContainer = document.createElement("div");

			const allLimbs = makeCheckbox("all-limbs");
			/**
			 * @type {Array<HTMLInputElement>}
			 */
			const limbs = [];
			if (getLeftArmID(slave) === 1) {
				limbs.push(makeCheckbox("left-arm"));
			}
			if (getRightArmID(slave) === 1) {
				limbs.push(makeCheckbox("right-arm"));
			}
			if (getLeftLegID(slave) === 1) {
				limbs.push(makeCheckbox("left-leg"));
			}
			if (getRightLegID(slave) === 1) {
				limbs.push(makeCheckbox("right-leg"));
			}

			allLimbs.onchange = () => {
				const checked = allLimbs.checked;
				limbs.forEach(l => l.checked = checked);
				App.UI.DOM.replace(linkContainer, link(limbs.length));
			};

			const checkAllBox = function() {
				let checkedCount = 0;
				limbs.forEach(l => {
					if (l.checked) {
						checkedCount++;
					}
				});

				if (checkedCount === 0) {
					allLimbs.checked = false;
					allLimbs.indeterminate = false;
				} else if (checkedCount === limbs.length) {
					allLimbs.checked = true;
					allLimbs.indeterminate = false;
				} else {
					allLimbs.checked = false;
					allLimbs.indeterminate = true;
				}
				App.UI.DOM.replace(linkContainer, link(checkedCount));
			};

			limbs.forEach(l => l.onchange = checkAllBox);

			/**
			 * @type {Map<string, string>}
			 */
			const idToName = new Map([
				["left-arm", "Left arm"],
				["right-arm", "Right arm"],
				["left-leg", "Left leg"],
				["right-leg", "Right leg"]
			]);

			appendCheckBox(outerDiv, allLimbs, "All limbs");
			const div = document.createElement("div");
			div.classList.add("choices");
			limbs.forEach(l => appendCheckBox(div, l, idToName.get(l.id)));
			outerDiv.append(div);

			linkContainer.append(link(0));
			outerDiv.append(linkContainer);

			/**
			 * @param {number} checkedCount
			 * @returns {HTMLAnchorElement|HTMLSpanElement}
			 */
			function link(checkedCount) {
				const newLimbs = {
					"left-arm": false,
					"right-arm": false,
					"left-leg": false,
					"right-leg": false,
				};
				limbs.forEach(l => {
					newLimbs[l.id] = l.checked;
				});
				return App.Medicine.Surgery.makeLink(
					new App.Medicine.Surgery.Procedures.Amputate(slave,
						newLimbs["left-arm"], newLimbs["right-arm"], newLimbs["left-leg"], newLimbs["right-leg"]),
					refresh, cheat);
			}

			/**
			 * @param {string} id must be unique
			 * @returns {HTMLInputElement}
			 */
			function makeCheckbox(id) {
				const checkbox = document.createElement("input");
				checkbox.id = id;
				checkbox.setAttribute("type", "checkbox");
				checkbox.checked = false;
				return checkbox;
			}

			/**
			 * @param {HTMLElement} container
			 * @param {HTMLInputElement} box
			 * @param {string} name
			 */
			function appendCheckBox(container, box, name) {
				const label = document.createElement("label");
				label.append(box, " ", name);
				App.UI.DOM.appendNewElement("div", container, label);
			}

			return outerDiv;
		}

		function prostheticInterface() {
			const el = new DocumentFragment();
			const r = [];
			const linkArray = [];
			if (!hasAllNaturalLimbs(slave)) {
				if (slave.PLimb === 0 && isProstheticAvailable(slave, "interfaceP1")) {
					linkArray.push(App.Medicine.Surgery.makeLink(
						new App.Medicine.Surgery.Procedures.BasicPLimbInterface(slave), refresh, cheat));
				}
				if (slave.PLimb !== 2 && isProstheticAvailable(slave, "interfaceP2")) {
					linkArray.push(App.Medicine.Surgery.makeLink(
						new App.Medicine.Surgery.Procedures.AdvancedPLimbInterface(slave), refresh, cheat));
				}
				if (slave.PLimb !== 3 && isProstheticAvailable(slave, "interfaceP3")) {
					linkArray.push(App.Medicine.Surgery.makeLink(
						new App.Medicine.Surgery.Procedures.QuadrupedalPLimbInterface(slave), refresh, cheat));
				}
			}
			App.Events.addNode(el, r, "div");
			App.UI.DOM.appendNewElement("div", el, App.UI.DOM.generateLinksStrip(linkArray), "choices");
			return el;
		}

		function tail() {
			const el = new DocumentFragment();
			const r = [];
			const linkArray = [];
			if (slave.PTail === 1) {
				r.push(`${He} has a neural interface allowing attachment of tails.`);
			} else if (isProstheticAvailable(slave, "interfaceTail")) {
				r.push(`${He} lacks a neural interface allowing attachment of tails.`);
				linkArray.push(App.Medicine.Surgery.makeLink(
					new App.Medicine.Surgery.Procedures.TailInterface(slave),
					refresh, cheat));
			} else {
				r.push(`${He} lacks a neural interface allowing attachment of tails and you have none ready for ${him}.`);
			}
			App.Events.addNode(el, r, "div");
			App.UI.DOM.appendNewElement("div", el, App.UI.DOM.generateLinksStrip(linkArray), "choices");
			return el;
		}

		function back() {
			const el = new DocumentFragment();
			const r = [];
			const linkArray = [];
			if (slave.PBack === 1) {
				r.push(`${He} has a neural back interface allowing attachment of dorsal appendages.`);
			} else if (isProstheticAvailable(slave, "interfaceBack")) {
				r.push(`${He} lacks a neural back interface allowing attachment of dorsal appendages.`);
				linkArray.push(App.Medicine.Surgery.makeLink(
					new App.Medicine.Surgery.Procedures.BackInterface(slave),
					refresh, cheat));
			} else {
				r.push(`${He} lacks a neural back interface allowing attachment of dorsal appendages and you have none ready for ${him}.`);
			}
			App.Events.addNode(el, r, "div");
			App.UI.DOM.appendNewElement("div", el, App.UI.DOM.generateLinksStrip(linkArray), "choices");
			return el;
		}
	}
};

repo_name: Mirarara/fc

license: mit


code:
/**
 * UI for performing surgery. Refreshes without refreshing the passage.
 * @param {App.Entity.SlaveState} slave
 * @param {()=>void} refresh
 * @param {boolean} [cheat=false]
 * @returns {HTMLElement}
 */
App.UI.surgeryPassageUpper = function(slave, refresh, cheat = false) {
	const container = document.createElement("span");
	container.append(content());
	return container;

	function content() {
		const frag = new DocumentFragment();
		const {
			His, He,
			his, he
		} = getPronouns(slave);
		/** @type {HTMLAnchorElement[]} */

		App.UI.DOM.appendNewElement("h3", frag, `Chest:`);
		frag.append(
			boobDesc(),
			boobImplants(),
			nipples(),
			areolae(),
			lactation()
		);

		App.UI.DOM.appendNewElement("h3", frag, `Midriff:`);

		frag.append(
			fat(),
			moreFat(),
			belly(),
			wombImplant(),
			bellySag()
		);

		return frag;

		function boobDesc() {
			const el = new DocumentFragment();
			const r = [];
			r.push(`${His}`);
			if (slave.boobs < 300) {
				r.push(`${either("androgynous", "flat")} chest is barely there.`);
			} else if (slave.boobs < 400) {
				r.push(`${either("pointy", "tiny")}, ${slave.boobs}cc chest only fill A-cups.`);
			} else if (slave.boobs < 8500) {
				if (V.showBoobCCs === 1) {
					r.push(App.Desc.boobBits.format("%ADJ %NOUN, %VOLUME CCs, would fill %ACUP.", slave.boobs));
				} else {
					r.push(App.Desc.boobBits.format("%ADJ %NOUN, would fill %ACUP.", slave.boobs));
				}
			} else {
				r.push(App.Desc.boobBits.format("%ADJ %NOUN, %VOLUME CCs, ", slave.boobs));
				r.push(`fill out an enormous custom bra; ${his} tits dominate ${his} entire frame.`);
			}
			App.Events.addNode(el, r, "div");
			return el;
		}

		function boobImplants() {
			const el = new DocumentFragment();
			let r = [];
			r.push(`${He} has`);
			if (["fillable", "advanced fillable", "hyper fillable"].includes(slave.boobsImplantType)) {
				if (slave.boobsImplantType === "hyper fillable") {
					if (slave.boobsImplant < 20000) {
						r.push(`underfilled,`);
					} else {
						r.push(`enormous,`);
					}
				} else if (slave.boobsImplantType === "advanced fillable") {
					if (slave.boobsImplant <= 1000) {
						r.push(`deflated,`);
					} else if (slave.boobsImplant < 2200) {
						r.push(`underfilled,`);
					} else if (slave.boobsImplant > 10000) {
						r.push(`massively overfilled,`);
					} else {
						r.push(`massive,`);
					}
				} else {
					if (slave.boobsImplant <= 500) {
						r.push(`deflated,`);
					} else if (slave.boobsImplant < 800) {
						r.push(`underfilled,`);
					} else if (slave.boobsImplant > 1800) {
						r.push(`massively overfilled,`);
					} else if (slave.boobsImplant > 1000) {
						r.push(`massive,`);
					} else if (slave.boobsImplant >= 800) {
						r.push(`giant,`);
					}
				}
				r.push(`${slave.boobsImplant}cc ${slave.boobsImplantType} breast implants.`);
			} else if (slave.boobsImplantType !== "none") {
				if (slave.boobsImplant > 1000) {
					r.push(`massive, ${slave.boobsImplant}cc`);
				} else if (slave.boobsImplant > 800) {
					r.push(`giant, ${slave.boobsImplant}cc`);
				} else if (slave.boobsImplant > 600) {
					r.push(`huge, ${slave.boobsImplant}cc`);
				} else if (slave.boobsImplant > 400) {
					r.push(`large, ${slave.boobsImplant}cc`);
				} else if (slave.boobsImplant > 200) {
					r.push(`moderate, ${slave.boobsImplant}cc`);
				} else if (slave.boobsImplant > 0) {
					r.push(`small, ${slave.boobsImplant}cc`);
				}
				if (slave.boobsImplantType !== "normal") {
					r.push(`${slave.boobsImplantType}`);
				}
				r.push(`breast implants.`);
				if (slave.boobsImplant > 8000 && slave.boobsImplantType === "string") {
					r.push(`<span class="yellow">Large string based implants are a risk to a slave's health.</span>`);
				}
			} else {
				r.push(`no implants.`);
			}
			App.Events.addNode(el, r, "div");
			const surgeries = App.Medicine.Surgery.sizingProcedures.boobs(slave, App.Medicine.Surgery.allSizingOptions());
			const surgeryLinks = surgeries.map(s => App.Medicine.Surgery.makeLink(s, refresh, cheat));
			App.UI.DOM.appendNewElement("div", el, (App.UI.DOM.generateLinksStrip(surgeryLinks)), "choices");

			r = [];
			const linkArray = [];
			if (slave.boobsImplant !== 0) {
				r.push(`The shape of ${his} breasts is determined by ${his} implants.`);
			} else {
				if (slave.boobs <= 250) {
					r.push(`${He}'s so flat-chested that ${his} breasts don't have much shape.`);
				} else {
					switch (slave.boobShape) {
						case "perky":
							r.push(`They're perky, with nipples that point slightly upwards.`);
							break;
						case "downward-facing":
							r.push(`They're not attractively shaped; ${his} nipples pointing downward.`);
							break;
						case "torpedo-shaped":
							r.push(`They're torpedo-shaped, projecting some way from ${his} chest.`);
							break;
						case "wide-set":
							r.push(`They're wide-set, with nipples pointing away from ${his} sternum.`);
							break;
						case "saggy":
							r.push(`They're not attractively shaped, with ${his} nipples pointing down.`);
							break;
						default:
							r.push(`They're nicely rounded and rest naturally.`);
					}
					if (slave.indentureRestrictions >= 2) {
						r.push(`<span class="note">${His} indenture does not allow breast restructuring</span>`);
					} else if (slave.breastMesh === 1) {
						r.push(`<span class="note">${His} supportive mesh implant prevents reconstruction</span>`);
					} else {
						if (slave.boobShape === "saggy" || slave.boobShape === "downward-facing") {
							linkArray.push(App.Medicine.Surgery.makeLink(
								new App.Medicine.Surgery.Procedures.BreastLift(slave),
								refresh, cheat));
							if (slave.preg > slave.pregData.normalBirth / 1.42 || (slave.boobs >= 5000 && slave.boobs < 8000)) {
								r.push(`<span class="note">${His} current state may result in ${his} breasts becoming saggy again</span>`);
							}
						} else {
							if (slave.boobShape === "normal") {
								linkArray.push(App.Medicine.Surgery.makeLink(
									new App.Medicine.Surgery.Procedures.BreastReconstruction(slave, "perky"),
									refresh, cheat));
								linkArray.push(App.Medicine.Surgery.makeLink(
									new App.Medicine.Surgery.Procedures.BreastReconstruction(slave, "torpedo-shaped"),
									refresh, cheat));
							} else {
								linkArray.push(App.Medicine.Surgery.makeLink(
									new App.Medicine.Surgery.Procedures.BreastReconstruction(slave, "normal"),
									refresh, cheat));
							}
							if (slave.boobs >= 2000 && slave.boobsImplant === 0 && V.meshImplants === 1 && V.surgeryUpgrade === 1) {
								linkArray.push(App.Medicine.Surgery.makeLink(
									new App.Medicine.Surgery.Procedures.BreastShapePreservation(slave),
									refresh, cheat));
							}
						}
					}
				}
			}
			App.Events.addNode(el, r, "div");
			App.UI.DOM.appendNewElement("div", el, App.UI.DOM.generateLinksStrip(linkArray), "choices");
			return el;
		}

		function nipples() {
			const el = new DocumentFragment();
			if (V.surgeryUpgrade === 1) {
				App.UI.DOM.appendNewElement("div", el, `${He} has ${slave.nipples} nipples.`);
				if (slave.indentureRestrictions >= 2) {
					App.UI.DOM.appendNewElement("div", el, `${His} indenture forbids elective surgery`, ["choices", "note"]);
				} else if (slave.indentureRestrictions === 1) {
					App.UI.DOM.appendNewElement("div", el, `${His} indenture forbids extreme body modification`, ["choices", "note"]);
				} else { /* split for possible dicknips later on, should lcd wish to attempt it again. */
					const linkArray = [];
					if (slave.nipples === "fuckable") {
						linkArray.push(App.Medicine.Surgery.makeLink(
							new App.Medicine.Surgery.Procedures.RestoreNipples(slave),
							refresh, cheat));
					} else {
						if (slave.boobs - slave.boobsMilk < 500) {
							App.UI.DOM.appendNewElement("div", el, `${His} breasts are too small to support reshaping ${his} nipples to be penetratable`, ["choices", "note"]);
						} else if (slave.boobs - slave.boobsImplant - slave.boobsMilk < 500) {
							App.UI.DOM.appendNewElement("div", el, `${His} implants are too large to support reshaping ${his} nipples to be penetratable`, ["choices", "note"]);
						} else if (slave.nipples !== "huge") {
							App.UI.DOM.appendNewElement("div", el, `${His} nipples are too small to be made fuckable`, ["choices", "note"]);
						} else {
							linkArray.push(App.Medicine.Surgery.makeLink(
								new App.Medicine.Surgery.Procedures.NippleCunts(slave),
								refresh, cheat));
						}
					}
					App.UI.DOM.appendNewElement("div", el, App.UI.DOM.generateLinksStrip(linkArray), "choices");
				}
			}
			return el;
		}

		function areolae() {
			const el = new DocumentFragment();
			const r = [];
			const linkArray = [];
			if (slave.areolae === 0) {
				r.push(`${His} areolae are small`);
				if (slave.areolaeShape !== "circle") {
					r.push(`and have been surgically altered to be ${slave.areolaeShape}-shaped.`);
				} else {
					r.push(`and fairly normal.`);
				}
			} else if (slave.areolae === 1) {
				r.push(`${His} areolae are large`);
				if (slave.areolaeShape !== "circle") {
					r.push(`and have been surgically altered to be ${slave.areolaeShape}-shaped.`);
				} else {
					r.push(`but still fairly normal.`);
				}
			} else if (slave.areolae > 1) {
				r.push(`${He} has`);
				if (slave.areolae === 2) {
					r.push(`wide`);
				} else if (slave.areolae === 3) {
					r.push(`huge`);
				} else if (slave.areolae === 4) {
					r.push(`massive`);
				}
				r.push(`areolae${(slave.areolaeShape !== "circle") ? `, which have been surgically altered to be ${slave.areolaeShape}-shaped` : ``}.`);
			}
			if (slave.indentureRestrictions < 2) {
				if (slave.areolaeShape !== "circle") {
					r.push(`${His} ${slave.areolaeShape}-shaped areolae can be normalized or reshaped:`);
					linkArray.push(App.Medicine.Surgery.makeLink(
						new App.Medicine.Surgery.Procedures.ReshapeAreolae(slave, "circle"),
						refresh, cheat));
					if (slave.areolaeShape !== "heart") {
						linkArray.push(App.Medicine.Surgery.makeLink(
							new App.Medicine.Surgery.Procedures.ReshapeAreolae(slave, "heart"),
							refresh, cheat));
					}
					if (slave.areolaeShape !== "star") {
						linkArray.push(App.Medicine.Surgery.makeLink(
							new App.Medicine.Surgery.Procedures.ReshapeAreolae(slave, "star"),
							refresh, cheat));
					}
				} else {
					if (slave.areolae > 0 && slave.areolaeShape === "circle") {
						r.push(`They are big enough that they could be reshaped into a pattern. Graft skin to make ${his} areolae:`);
					}
					if (slave.areolae > 0 && slave.areolaeShape === "circle") {
						linkArray.push(App.Medicine.Surgery.makeLink(
							new App.Medicine.Surgery.Procedures.ReshapeAreolae(slave, "heart"),
							refresh, cheat));
						linkArray.push(App.Medicine.Surgery.makeLink(
							new App.Medicine.Surgery.Procedures.ReshapeAreolae(slave, "star"),
							refresh, cheat));
					}
				}

				if (slave.areolae > 0) {
					linkArray.push(App.Medicine.Surgery.makeLink(
						new App.Medicine.Surgery.Procedures.ResizeAreolae(slave, -1),
						refresh, cheat));
				}
				if (slave.areolae < 4) {
					linkArray.push(App.Medicine.Surgery.makeLink(
						new App.Medicine.Surgery.Procedures.ResizeAreolae(slave, +1),
						refresh, cheat));
				}
			}
			App.Events.addNode(el, r, "div");
			App.UI.DOM.appendNewElement("div", el, App.UI.DOM.generateLinksStrip(linkArray), "choices");
			return el;
		}

		function lactation() {
			const el = new DocumentFragment();
			const r = [];
			const linkArray = [];
			if (slave.lactation === 0) {
				r.push(`${He} is not lactating.`);
			} else if (slave.lactation === 2) {
				r.push(`${He} is implanted with slow-release pro-lactation drugs.`);
			} else {
				r.push(`${He} is lactating naturally.`);
			}
			if (slave.lactation < 2) {
				if (slave.indentureRestrictions < 2) {
					linkArray.push(App.Medicine.Surgery.makeLink(
						new App.Medicine.Surgery.Procedures.Lactation(slave),
						refresh, cheat));
				}
			}
			if (slave.lactation > 1) {
				linkArray.push(App.Medicine.Surgery.makeLink(
					new App.Medicine.Surgery.Procedures.EndLactation(slave),
					refresh, cheat));
			}
			App.Events.addNode(el, r, "div");
			App.UI.DOM.appendNewElement("div", el, App.UI.DOM.generateLinksStrip(linkArray), "choices");
			return el;
		}

		function fat() {
			const el = new DocumentFragment();
			const r = [];
			const linkArray = [];
			if (slave.indentureRestrictions >= 2 && slave.weight > 30) {
				App.UI.DOM.appendNewElement("div", el, `${His} indenture forbids elective surgery`, ["choices", "note"]);
			} else if (slave.weight > 30) {
				if (slave.weight > 190) {
					r.push(`${He} is extremely fat.`);
				} else if (slave.weight > 130) {
					r.push(`${He} is fat.`);
				} else if (slave.weight > 30) {
					r.push(`${He} is overweight.`);
				}
				linkArray.push(App.Medicine.Surgery.makeLink(
					new App.Medicine.Surgery.Procedures.Liposuction(slave),
					refresh, cheat));
				if (V.surgeryUpgrade === 1) {
					linkArray.push(App.UI.DOM.link("Fat grafting",
						() => App.UI.SlaveInteract.fatGraft(slave, refresh)));
				}
			}
			App.Events.addNode(el, r, "div");
			App.UI.DOM.appendNewElement("div", el, App.UI.DOM.generateLinksStrip(linkArray), "choices");
			return el;
		}

		function moreFat() {
			const el = new DocumentFragment();
			const r = [];
			const linkArray = [];
			r.push(`${He} has`);
			if (slave.waist > 95) {
				r.push(`a masculine`);
			} else if (slave.waist > 40) {
				r.push(`an ugly`);
			} else if (slave.waist > 10) {
				r.push(`an unattractive`);
			} else if (slave.waist >= -10) {
				r.push(`an average`);
			} else if (slave.waist >= -40) {
				r.push(`a feminine`);
			} else if (slave.waist >= -95) {
				r.push(`an hourglass`);
			} else {
				r.push(`an absurd`);
			}
			r.push(`waist.`);
			App.Events.addNode(el, r, "div");
			if (slave.waist >= -75) {
				if (slave.indentureRestrictions < 2) {
					linkArray.push(App.Medicine.Surgery.makeLink(
						new App.Medicine.Surgery.Procedures.WaistReduction(slave),
						refresh, cheat));
				}
			}
			if (slave.waist >= -95 && slave.waist < -75 && V.seeExtreme === 1) {
				if (slave.indentureRestrictions < 1 && (slave.breedingMark !== 1 || V.propOutcome === 0 || V.eugenicsFullControl === 1 || V.arcologies[0].FSRestart === "unset")) {
					linkArray.push(App.Medicine.Surgery.makeLink(
						new App.Medicine.Surgery.Procedures.Ribs(slave),
						refresh, cheat));
				}
			}
			App.UI.DOM.appendNewElement("div", el, App.UI.DOM.generateLinksStrip(linkArray), "choices");
			return el;
		}

		function belly() {
			const el = new DocumentFragment();
			const r = [];
			const linkArray = [];
			r.push(`${He}'s`);
			if (slave.pregKnown > 0) {
				r.push(`pregnant.`);
			} else if (slave.womb.length === 0 && slave.broodmother > 0) {
				r.push(`got a dormant broodmother implant in ${his} womb.`);
			} else if (slave.preg > 0) {
				r.push(`showing unusual discomfort as ${his} stomach is inspected. A quick test reveals that <span class="lime">${he} is pregnant.</span>`);
				slave.pregKnown = 1;
			} else if (slave.bellyImplant > 0) {
				r.push(`got a ${slave.bellyImplant}cc implant filled implant located in ${his} abdomen.`);
				if (slave.cervixImplant === 1) {
					r.push(`${He} also has a micropump filter installed in ${his} cervix feeding into the implant.`);
				} else if (slave.cervixImplant === 2) {
					r.push(`${He} also has a micropump filter installed in ${his} rectum feeding into the implant.`);
				} else if (slave.cervixImplant === 3) {
					r.push(`${He} also has a micropump filter installed in both ${his} holes feeding into the implant.`);
				}
				if (slave.bellyFluid >= 1500) {
					r.push(`${He} also has a bellyful of ${slave.inflationType}.`);
				}
			} else if (slave.bellyImplant === 0) {
				r.push(`got an empty fillable implant located in ${his} abdomen.`);
				if (slave.cervixImplant === 1) {
					r.push(`${He} also has a micropump filter installed in ${his} cervix feeding into the implant.`);
				} else if (slave.cervixImplant === 2) {
					r.push(`${He} also has a micropump filter installed in ${his} rectum feeding into the implant.`);
				} else if (slave.cervixImplant === 3) {
					r.push(`${He} also has a micropump filter installed in both ${his} holes feeding into the implant.`);
				}
				if (slave.bellyFluid >= 1500) {
					r.push(`${He} also has a bellyful of ${slave.inflationType}.`);
				}
			} else if (slave.bellyFluid >= 1500) {
				r.push(`got a bellyful of ${slave.inflationType}.`);
			} else {
				r.push(`got a normal stomach.`);
			}
			App.Events.addNode(el, r, "div");
			if (slave.indentureRestrictions >= 2) {
				App.UI.DOM.appendNewElement("div", el, `${His} indenture forbids elective surgery`, ["choices", "note"]);
			} else if (slave.breedingMark === 1 && V.propOutcome === 1 && V.eugenicsFullControl !== 1 && V.arcologies[0].FSRestart !== "unset") {
				App.UI.DOM.appendNewElement("div", el, `You are forbidden from affecting ${his} fertility`, ["choices", "note"]);
			} else if (slave.preg > 0 || slave.inflation > 0 || slave.broodmother > 0) {
				App.UI.DOM.appendNewElement("div", el, `${He} is unable to support an abdominal implant at this time`, ["choices", "note"]);
			} else if (slave.bellyImplant >= 750000) {
				App.UI.DOM.appendNewElement("div", el, `${His} abdominal implant is so far beyond its maximum limit it is at risk of rupturing`, ["choices", "note"]);
			} else if (slave.bellyImplant >= 600000) {
				App.UI.DOM.appendNewElement("div", el, `${His} abdominal implant is greatly beyond its maximum limit`, ["choices", "note"]);
			} else if (slave.bellyImplant >= 450000) {
				App.UI.DOM.appendNewElement("div", el, `${His} abdominal implant is over-filled`, ["choices", "note"]);
			} else if (slave.bellyImplant >= 400000) {
				App.UI.DOM.appendNewElement("div", el, `${His} abdominal implant is at its capacity`, ["choices", "note"]);
			} else if (slave.bellyImplant > 130000 && V.arcologies[0].FSTransformationFetishistResearch !== 1) {
				App.UI.DOM.appendNewElement("div", el, `${His} abdominal implant is at its capacity`, ["choices", "note"]);
			} else if (slave.bellyImplant === -1 && V.bellyImplants === 1) {
				if (slave.ovaries === 1 || slave.mpreg === 1) {
					linkArray.push(App.Medicine.Surgery.makeLink(
						new App.Medicine.Surgery.Procedures.BellyIn(slave),
						refresh, cheat));
				} else {
					linkArray.push(App.Medicine.Surgery.makeLink(
						new App.Medicine.Surgery.Procedures.BellyInMale(slave),
						refresh, cheat));
				}
			} else if (slave.bellyPain === 2) {
				App.UI.DOM.appendNewElement("div", el, `${His} body cannot handle more filler this week`, ["choices", "note"]);
			} else if (slave.bellyImplant > -1) {
				linkArray.push(App.Medicine.Surgery.makeLink(
					new App.Medicine.Surgery.Procedures.BellyUp(slave),
					refresh, cheat));
				linkArray.push(App.Medicine.Surgery.makeLink(
					new App.Medicine.Surgery.Procedures.BellyUpLarge(slave),
					refresh, cheat));
			}
			if (slave.bellyImplant > -1) {
				linkArray.push(App.Medicine.Surgery.makeLink(
					new App.Medicine.Surgery.Procedures.BellyDown(slave),
					refresh, cheat));
				if (slave.bellyImplant >= 500) {
					linkArray.push(App.Medicine.Surgery.makeLink(
						new App.Medicine.Surgery.Procedures.BellyDownLarge(slave),
						refresh, cheat));
				}
				if (slave.indentureRestrictions < 2) {
					linkArray.push(App.Medicine.Surgery.makeLink(
						new App.Medicine.Surgery.Procedures.BellyOut(slave),
						refresh, cheat));
					if (slave.cervixImplant !== 1 && slave.cervixImplant !== 3 && V.cervixImplants >= 1 && slave.vagina > -1) { /* slave should have vagina */
						linkArray.push(App.Medicine.Surgery.makeLink(
							new App.Medicine.Surgery.Procedures.CervixPump(slave),
							refresh, cheat));
					}
					if (slave.cervixImplant !== 2 && slave.cervixImplant !== 3 && V.cervixImplants === 2) {
						linkArray.push(App.Medicine.Surgery.makeLink(
							new App.Medicine.Surgery.Procedures.CervixPumpAnus(slave),
							refresh, cheat));
					}
				}
			}
			App.UI.DOM.appendNewElement("div", el, App.UI.DOM.generateLinksStrip(linkArray), "choices");
			return el;
		}

		function wombImplant() {
			const el = new DocumentFragment();
			const linkArray = [];
			if (slave.wombImplant === "none" && (V.UterineRestraintMesh === 1) && (slave.ovaries === 1 || slave.mpreg === 1)) {
				App.UI.DOM.appendNewElement("div", el, `${He} has a normal uterus${(slave.mpreg === 1) ? `, though slightly repositioned` : ``}.`);
				if (slave.indentureRestrictions >= 1) {
					App.UI.DOM.appendNewElement("div", el, `${His} indenture forbids elective surgery`, ["choices", "note"]);
				} else if (slave.bellyImplant > 0 || slave.preg > 0) {
					App.UI.DOM.appendNewElement("div", el, `${His} womb is currently in use and unsafe to operate on`, ["choices", "note"]);
				} else {
					if (V.surgeryUpgrade === 1) {
						if (V.UterineRestraintMesh === 1) {
							App.UI.DOM.appendNewElement("div", el, ``, ["choices", "note"]);
							linkArray.push(App.Medicine.Surgery.makeLink(
								new App.Medicine.Surgery.Procedures.InstallMesh(slave),
								refresh, cheat));
						}
					}
				}
			} else if (slave.wombImplant === "restraint") {
				App.UI.DOM.appendNewElement("div", el, `${He} has a mesh reinforced uterus.`);
				if (slave.indentureRestrictions >= 1) {
					App.UI.DOM.appendNewElement("div", el, `${His} indenture forbids elective surgery`, ["choices", "note"]);
				} else if (slave.bellyImplant > 0 || slave.preg > 0) {
					App.UI.DOM.appendNewElement("div", el, `${His} womb is currently in use and unsafe to operate on`, ["choices", "note"]);
				} else {
					linkArray.push(App.Medicine.Surgery.makeLink(
						new App.Medicine.Surgery.Procedures.RemoveMesh(slave),
						refresh, cheat));
				}
			}
			App.UI.DOM.appendNewElement("div", el, App.UI.DOM.generateLinksStrip(linkArray), "choices");
			return el;
		}

		function bellySag() {
			const el = new DocumentFragment();
			const r = [];
			const linkArray = [];
			if (slave.bellySagPreg > 0) {
				if (slave.belly >= 1500) {
					r.push(`${He} has a sagging midriff, ruined from excessive pregnancy. It is currently filled out by ${his} swollen belly and cannot safely be worked on.`);
				} else {
					r.push(`${He} has a sagging midriff, ruined from excessive pregnancy.`);
					linkArray.push(App.Medicine.Surgery.makeLink(
						new App.Medicine.Surgery.Procedures.TummyTuck(slave),
						refresh, cheat));
				}
			} else if (slave.bellySag > 0) {
				if (slave.belly >= 1500) {
					r.push(`${He} has a sagging midriff, ruined from excessive distention. It is currently filled out by ${his} swollen belly and cannot safely be worked on.`);
				} else {
					r.push(`${He} has a sagging midriff, ruined from excessive distention.`);
					linkArray.push(App.Medicine.Surgery.makeLink(
						new App.Medicine.Surgery.Procedures.TummyTuck(slave),
						refresh, cheat));
				}
			}
			App.Events.addNode(el, r, "div");
			App.UI.DOM.appendNewElement("div", el, App.UI.DOM.generateLinksStrip(linkArray), "choices");
			return el;
		}
	}
};


code:
/**
 * UI for the Body Modification system/studio. Refreshes without refreshing the passage.
 */
App.UI.toyShop = function() {
	const container = document.createElement("span");

	/**
	 * @typedef toyData
	 * @property {string} name
	 * @property {number} width
	 * @property {number} length
	 */

	/**
	 * @typedef toy
	 * @property {string} name
	 * @property {toyData} data
	 * @property {string} selected
	 */

	let buttPlug = {name: "", data: null, selected: ""};
	initToy(buttPlug);
	let vaginalAcc = {name: "", data: null, selected: ""};
	initToy(vaginalAcc);

	container.append(createPage());
	return container;

	function createPage() {
		const el = new DocumentFragment();
		el.append(intro());
		el.append(vaginalAccessory());
		el.append(buttPlugs());
		return el;
	}

	/**
	 * @param {toy} toy
	 */
	function initToy(toy) {
		toy.name = "";
		toy.data = {name: "", width: 1, length: 1};
	}

	function intro() {
		const el = new DocumentFragment();
		// App.UI.DOM.appendNewElement("h1", el, "The Toy Shop");
		App.UI.DOM.appendNewElement("div", el, `The toy shop is filled with the smell of rubber, latex, and various synthetic materials and solvents. A series of screens allows you to design toys of various shapes and sizes, and then produce them at scale. A bin of defects sits in the corner, glistening a bit under a layer of lubrication.`, "scene-intro");
		return el;
	}

	function vaginalAccessory() {
		const frag = new DocumentFragment();
		App.UI.DOM.appendNewElement("h2", frag, "Vaginal Accessories");
		const selectDiv = App.UI.DOM.appendNewElement("div", frag, App.UI.DOM.link("Start a new design", () => {
			initToy(vaginalAcc);
			refresh();
		}));
		if (V.customItem.vaginalAccessory.size > 0) {
			selectDiv.append(selectDesign(vaginalAcc, "vaginalAccessory"));
		}
		frag.append(create());
		return frag;

		function create() {
			const el = new DocumentFragment();
			const existingDesign = V.customItem.vaginalAccessory.get(vaginalAcc.name);
			if (existingDesign) {
				el.append(descLocked());
			} else {
				el.append(desc());
			}
			if (vaginalAcc.data.name) {
				el.append(title(vaginalAcc));
			}
			el.append(
				width(vaginalAcc),
				length(vaginalAcc),
			);

			if (existingDesign) {
				const build = App.UI.DOM.appendNewElement("div", el, `Send updated design to production and make sure all appropriate slaves are updated `);
				const linkArray = [];
				linkArray.push(
					App.UI.DOM.link(
						"Update the mold",
						() => { buildVA(); }
					)
				);

				linkArray.push(
					App.UI.DOM.link(
						`Recall "${vaginalAcc.name}"`,
						() => { deleteVA(); }
					)
				);
				build.append(App.UI.DOM.generateLinksStrip(linkArray));
			} else if (vaginalAcc.name && vaginalAcc.data.name) {
				el.append(apply());
			}

			return el;

			function descLocked() {
				return App.UI.DOM.makeElement("div", `Description has already been selected for this model: "${vaginalAcc.name}"`);
			}
		}

		function desc() {
			const value = App.UI.DOM.makeElement("div", `Enter toy's shape here as it will appear in descriptions: `);
			value.append(App.UI.DOM.makeTextBox(
				vaginalAcc.name,
				v => {
					vaginalAcc.name = v;
					vaginalAcc.data.name = capFirstChar(v);
					refresh();
				}
			));
			App.UI.DOM.appendNewElement("span", value, ` Your slave has a standard ${vaginalAcc.name || `pink dildo`} wedged firmly in their pussy.`, "note");
			return value;
		}

		function buildVA() {
			V.customItem.vaginalAccessory.set(vaginalAcc.name, vaginalAcc.data);
			initToy(vaginalAcc);
			refresh();
		}

		function apply() {
			const build = App.UI.DOM.appendNewElement("div", frag, `Send design to production and make available for all slaves `);
			build.append(
				App.UI.DOM.link(
					"Start the mold",
					() => { buildVA(); }
				)
			);
			return build;
		}

		function deleteVA() {
			V.customItem.vaginalAccessory.delete(vaginalAcc.name);
			for (const slave of V.slaves) {
				if (slave.vaginalAccessory === vaginalAcc.name) {
					slave.vaginalAccessory = "none";
				}
			}
			refresh();
		}
	}

	function buttPlugs() {
		const frag = new DocumentFragment();
		App.UI.DOM.appendNewElement("h2", frag, "Buttplugs");
		const selectDiv = App.UI.DOM.appendNewElement("div", frag, App.UI.DOM.link("Start a new design", () => {
			initToy(buttPlug);
			refresh();
		}));
		if (V.customItem.buttplug.size > 0) {
			selectDiv.append(selectDesign(buttPlug, "buttplug"));
		}
		frag.append(create());
		return frag;

		function create() {
			const el = new DocumentFragment();
			const existingDesign = V.customItem.buttplug.get(buttPlug.name);
			if (existingDesign) {
				el.append(descLocked());
			} else {
				el.append(desc());
			}
			if (buttPlug.data.name) {
				el.append(title(buttPlug));
			}
			el.append(
				width(buttPlug),
				length(buttPlug),
			);

			if (existingDesign) {
				const build = App.UI.DOM.appendNewElement("div", el, `Send updated design to production and make sure all appropriate slaves are updated `);
				const linkArray = [];
				linkArray.push(
					App.UI.DOM.link(
						"Update the mold",
						() => { buildPlug(); }
					)
				);

				linkArray.push(
					App.UI.DOM.link(
						`Recall "${buttPlug.name}"`,
						() => { deletePlug(); }
					)
				);
				build.append(App.UI.DOM.generateLinksStrip(linkArray));
			} else if (buttPlug.name && buttPlug.data.name) {
				el.append(apply());
			}

			return el;

			function descLocked() {
				return App.UI.DOM.makeElement("div", `Description has already been selected for this model: "${buttPlug.name}"`);
			}
		}

		function desc() {
			const value = App.UI.DOM.makeElement("div", `Enter toy's shape here as it will appear in descriptions: `);
			value.append(App.UI.DOM.makeTextBox(
				buttPlug.name,
				v => {
					buttPlug.name = v;
					buttPlug.data.name = capFirstChar(v);
					refresh();
				}
			));
			App.UI.DOM.appendNewElement("span", value, ` Your slave has a standard ${buttPlug.name || `spade-shaped plug`} wedged firmly in their asshole.`, "note");
			return value;
		}

		function buildPlug() {
			V.customItem.buttplug.set(buttPlug.name, buttPlug.data);
			initToy(buttPlug);
			refresh();
		}

		function apply() {
			const build = App.UI.DOM.appendNewElement("div", frag, `Send design to production and make available for all slaves `);
			build.append(
				App.UI.DOM.link(
					"Start the mold",
					() => { buildPlug(); }
				)
			);
			return build;
		}

		function deletePlug() {
			V.customItem.buttplug.delete(buttPlug.name);
			for (const slave of V.slaves) {
				if (slave.buttplug === buttPlug.name) {
					slave.buttplug = "none";
				}
			}
			refresh();
		}
	}

	/**
	 * @param {toy} toy
	 * @returns {HTMLDivElement}
	 */
	function title(toy) {
		const title = App.UI.DOM.makeElement("div", `Enter title as it will appear in lists of choices `);
		title.append(App.UI.DOM.makeTextBox(
			toy.data.name,
			v => {
				toy.data.name = capFirstChar(v);
				refresh();
			}
		));
		return title;
	}

	/**
	 * @param {toy} toy
	 * @returns {HTMLDivElement}
	 */
	function width(toy) {
		const widthOptions = new Map([
			["Standard", 1],
			["Large", 2],
			["Huge", 3],
		]);
		const width = App.UI.DOM.makeElement("div", `Width: `);
		width.append(optionsStrip(toy.data, "width", widthOptions));
		return width;
	}

	/**
	 * @param {toy} toy
	 * @returns {HTMLDivElement}
	 */
	function length(toy) {
		const lengthOptions = new Map([
			["Standard", 1],
			["Long", 2],
		]);
		const length = App.UI.DOM.makeElement("div", `Length: `);
		length.append(optionsStrip(toy.data, "length", lengthOptions));
		return length;
	}

	/**
	 * @param {object} obj
	 * @param {string} objKey
	 * @param {Map<string, any>} map
	 * @returns {HTMLUListElement}
	 */
	function optionsStrip(obj, objKey, map) {
		const linkArray = [];
		for (const [key, value] of map) {
			if (obj[objKey] === value) {
				linkArray.push(
					App.UI.DOM.disabledLink(
						key,
						["Currently selected"]
					)
				);
			} else {
				linkArray.push(
					App.UI.DOM.link(
						key,
						() => {
							obj[objKey] = value;
							refresh();
						}
					)
				);
			}
		}
		return App.UI.DOM.generateLinksStrip(linkArray);
	}

	/**
	 * @param {toy} toy
	 * @param {string} itemKey
	 * @returns {HTMLElement}
	 */
	function selectDesign(toy, itemKey) {
		const choice = App.UI.DOM.makeElement("span", ` or choose an existing design to edit `);
		const options = [];
		for (const [key, values] of V.customItem[itemKey]) {
			options.push({key: key, name: values.name});
		}
		choice.append(App.UI.DOM.makeSelect(options, toy.name, key => {
			toy.selected = key;
			toy.name = toy.selected;
			toy.data = V.customItem[itemKey].get(toy.selected);
			refresh();
		}));
		return choice;
	}

	function refresh() {
		jQuery(container).empty().append(createPage());
		console.log(vaginalAcc);
	}
};


code:
/**
 * Adds a new "Rename Facility" textbox.
 *
 * Allows the use of custom handler functions.
 * @param {App.Entity.Facilities.Facility} facility The entity form of the facility. Typical denoted as `App.Entity.facilities.*`.
 * @param {function():void} [handler] Any custom function to be run upon entering a new name.
 */
App.Facilities.rename = function rename(facility, handler) {
	const renameDiv = App.UI.DOM.makeElement("div", `Rename ${facility.name}: `);
	const renameNote = App.UI.DOM.makeElement("span", ` Use a noun or similar short phrase`, ['note']);

	renameDiv.appendChild(App.UI.DOM.makeTextBox(facility.name, newName => {
		facility.name = newName;

		App.UI.DOM.replace(renameDiv, App.Facilities.rename(facility));

		if (handler) {
			handler();
		}
	}));

	renameDiv.appendChild(renameNote);

	return renameDiv;
};


code:
App.UI.WardrobeShopping = function() {
	const el = document.createElement("p");
	let p;
	el.id = "wardrobe-shopping";

	App.UI.DOM.appendNewElement("h1", el, `Slave Wardrobe`);

	let r = [];
	r.push(`The room containing all the clothes and accessories you have available to dress your slaves in, as well as the supplies and tools your tailor needs to resize them to better fit your slaves. Several mirrors are set up for a slave to try on outfits should they be allowed to dress themselves. The selection includes`);
	const ownItAll = Array.from(App.Data.clothes.keys()).every((key) => isItemAccessible.entry(key, "clothes"));

	if (ownItAll) {
		r.push(`outfits from all manner of cultures and societies; not a single style eludes you.`);
	} else {
		r.push(`many styles of clothing ranging from exciting to mundane and sexy to practical.`);
	}
	if (V.boughtItem.shoes.heels === 1) {
		r.push(`A large variety of shoes are available to select from.`);
	}
	if (V.boughtItem.clothing.dildos === 1 && V.boughtItem.toys.gags === 1 && V.boughtItem.clothing.buttPlugs === 1) {
		r.push(`Sex toys of all kinds and shapes line the shelves.`);
	} else if (V.boughtItem.clothing.dildos === 1 || V.boughtItem.toys.gags === 1 || V.boughtItem.clothing.buttPlugs === 1 || V.boughtItem.clothing.buttPlugTails === 1 || V.boughtItem.clothing.vaginalAttachments === 1) {
		r.push(`Some sex toys line the shelves.`);
	}
	if (V.boughtItem.toys.buckets === 1) {
		r.push(`Several buckets of various sizes and a sturdy cup have been set aside for you in feeding slaves to their limit.`);
	}
	if (V.boughtItem.toys.enema === 1) {
		r.push(`A number of drums of specially formulated water for use in enemas line one of the walls.`);
	}
	if (V.boughtItem.toys.medicalEnema === 1) {
		r.push(`Alongside them, multiple drums of mixtures for use in medical enemas.`);
	}
	App.UI.DOM.appendNewElement("p", el, r.join(" "), "scene-intro");

	App.UI.DOM.appendNewElement("h2", el, `Future Society styles`);

	el.append(categoryBlock("FS"));

	App.UI.DOM.appendNewElement("h2", el, `Future Society Revivalist styles`);

	el.append(categoryBlock("FSrevivalist"));

	App.UI.DOM.appendNewElement("h2", el, `Other`);

	el.append(categoryBlock("other"));

	App.UI.DOM.appendNewElement("h2", el, `Accessories`);

	p = document.createElement("p");
	p.id = "accessory-block";
	p.append(accessoryBlock());
	el.append(p);

	return el;

	/**
	 *
	 * @param {*} category FS, FSrevivalist, or "other"
	 */

	function categoryBlock(category) {
		const data = App.Data.WardrobeShopping.Clothing[category];
		const model = (V.seeDicks === 100) ? GenerateNewSlave("XY") : GenerateNewSlave("XX");

		const el = document.createElement("p");
		el.classList.add("wardrobe-shopping-block");
		el.id = `id${category}`;
		Object.keys(data).forEach(
			(clothing) => {
				const cell = document.createElement("span");
				cell.id = clothing;
				cell.append(createCell(clothing));
				el.append(cell);
			});
		return el;

		/**
		 * Create individual cell for a piece of clothing, including the display model
		 * @param {string} clothing
		 * @param {string} oldOutfit The outfit last worn by the slave. This means that on cycling outfits, we won't immediately repeat
		 */
		function createCell(clothing, oldOutfit = "") {
			const el = document.createElement("div");
			el.classList.add("wardrobe-shopping-cell");
			el.onclick = () => {
				// Randomize devotion and trust a bit, so the model moves their arms and "poses" for the player.
				model.devotion = random(-10, 70);
				model.trust = random(30, 100);
				jQuery(`#${clothing}`).empty().append(createCell(clothing, model.clothes));
			};
			/** @type {wardrobeItem} */
			const clothingObj = App.Data.WardrobeShopping.Clothing[category][clothing];
			const cost = Math.trunc(clothingObj.cost * V.upgradeMultiplierTrade);
			let div;

			// If we have more than one possible outfit to showcase, make sure not to show the outfit we did last time.
			const clothesArray = clothingObj.contains.length > 1 ? clothingObj.contains.filter(item => item !== oldOutfit) : clothingObj.contains;

			// Get a randomly chosen piece of clothing from the set to display
			// This piece will also later be checked to see if we can purchase it or not.
			model.clothes = clothesArray[Math.floor(Math.random() * clothesArray.length)];

			if (V.seeImages === 1) {
				// Some clothing is weird (looking at you, Egyptian necklace)
				if (clothingObj.hasOwnProperty("modelUpdate")) {
					Object.assign(model, clothingObj.modelUpdate);
				}

				App.UI.DOM.appendNewElement("div", el, App.Art.SlaveArtElement(model, 1, 0), ["imageRef", "smlImg"]);

				// Clean up our model. Fuck you, Egypt.
				if (clothingObj.hasOwnProperty("modelUpdate")) {
					for (const prop in clothingObj.modelUpdate) {
						model[prop] = "none";
					}
				}
			}
			if (clothing !== "egypt" && !isItemAccessible.entry(model.clothes, "clothes") ||
				(clothing === "egypt" && !isItemAccessible.entry("ancient Egyptian", "collar")) // Fuck Egypt
			) {
				if (cost < V.cash) {
					App.UI.DOM.appendNewElement(
						"div",
						el,
						App.UI.DOM.link(
							`Order ${clothingObj.title}`,
							() => {
								if (cost < V.cash) { // Check again on click in case the link has become stale
									cashX(forceNeg(cost), "capEx");
									V.boughtItem.clothing[clothing] = 1;
								}
							}
						)
					);
					App.UI.DOM.appendNewElement("div", el, ` Costs ${cashFormat(cost)}`, "detail");
				} else {
					div = App.UI.DOM.disabledLink(
						`Order ${clothingObj.title}`,
						[`Cannot afford ${cashFormat(cost)}`]
					);
					div.style.display = "inline"; // Fixes disabledLink
					el.append(div);
					App.UI.DOM.appendNewElement("div", el, `Costs ${cashFormat(cost)}`, ["red", "detail"]);
				}
			} else {
				App.UI.DOM.appendNewElement("div", el, clothingObj.owned);
			}

			return el;
		}
	}

	function accessoryBlock() {
		const el = document.createElement("p");

		for (const name in App.Data.WardrobeShopping.Accessories) {
			el.append(createLine(name));
		}
		return el;

		function createLine(name) {
			const line = document.createElement("div");
			const purchased = _.get(V.boughtItem, name);
			const obj = (App.Data.WardrobeShopping.Accessories[name]);
			const cost = Math.trunc(obj.cost * V.upgradeMultiplierTrade);
			let div = document.createElement("div");

			if (purchased !== 0 && purchased !== 1) {
				throw Error(`${name} set incorrectly or not found`);
			}

			if (obj.hasOwnProperty("requirements") && obj.requirements !== true) {
				return line;
			}

			if (!purchased) {
				if (cost < V.cash) {
					div.append(
						App.UI.DOM.link(
							`Order ${obj.title}`,
							() => {
								if (cost < V.cash) { // Check again on click in case the link has become stale
									cashX(forceNeg(cost), "capEx");
									_.set(V.boughtItem, name, 1);
								}
								jQuery(`#accessory-block`).empty().append(accessoryBlock());
							}
						)
					);
					if (cost > 0) {
						App.UI.DOM.appendNewElement("span", div, ` Costs ${cashFormat(cost)}`, "detail");
					}
				} else {
					div.append(
						App.UI.DOM.disabledLink(
							`Order ${obj.title}`,
							[`Cannot afford ${cashFormat(cost)}`]
						)
					);
					App.UI.DOM.appendNewElement("span", div, ` Costs ${cashFormat(cost)}`, ["red", "detail"]);
				}
				if (obj.hasOwnProperty("note")) {
					App.UI.DOM.appendNewElement("span", div, ` ${obj.note}`, "note");
				}
			} else {
				div.append(obj.owned);
			}
			line.append(div);

			return line;
		}
	}
};


code:
App.Data.WardrobeShopping = {};

App.Data.WardrobeShopping.Clothing = {
	/**
	 * @typedef {object} wardrobeItem
	 * @property {string} title
	 * @property {number} cost
	 * @property {string} [note] italicize note about a purchase
	 * @property {string[]} contains
	 * @property {string} owned
	 * @property {object} [modelUpdate]
	 * @property {boolean} [requirements] requirements met
	 */

	/**
	 * @type {Object.<string, wardrobeItem>} String will be the property checked to see if the item is owned. So for "bunny", it will check V.boughtItem.clothing["bunny"].
	 */
	FS: {
		"bunny": {
			title: "a shipment of bunny suits",
			cost: 7500,
			contains: ["a bunny outfit"],
			owned: "You are well stocked with classic bunny suits and bowties.",
		},
		"conservative": {
			title: "a shipment of conservative clothes",
			cost: 7500,
			contains: ["conservative clothing"],
			owned: "You are well stocked with modest outfits.",
		},
		"bimbo": {
			title: "a shipment of outfits suitable for bimbos",
			cost: 7500,
			contains: ["a bimbo outfit"],
			owned: "You are well stocked with bimbo attire.",
		},
		"courtesan": {
			title: "a shipment of courtesan dresses",
			cost: 7500,
			contains: ["a courtesan dress"],
			owned: "You are well stocked with courtesan dresses.",
		},
		"chains": {
			title: "a shipment of chains",
			cost: 7500,
			contains: ["chains"],
			owned: "You are well stocked with various lengths of binding chains.",
		},
		"western": {
			title: "a shipment of western outfits",
			cost: 7500,
			contains: ["Western clothing"],
			owned: "You are well stocked with cowgirl outfits.",
		},
		"oil": {
			title: "a shipment of body oil",
			cost: 7500,
			contains: ["body oil"],
			owned: "You are well stocked with various body oils.",
		},
		"lazyClothes": {
			title: "a shipment of comfortable, rather stretchy, clothes",
			cost: 7500,
			contains: ["stretch pants and a crop-top"],
			owned: "You are well stocked with various comfy pants and rather tight crop-tops.",
		},
		"habit": {
			title: "a shipment of chattel habits",
			cost: 7500,
			contains: ["a chattel habit"],
			owned: "You are well stocked with habits from the chattel religion.",
		},
		"maternityDress": {
			title: "a shipment of maternity dresses",
			cost: 7500,
			contains: ["a maternity dress"],
			owned: "You are well stocked with dresses specially tailored for pregnant women.",
		},
		"maternityLingerie": {
			title: "a shipment of maternity lingerie",
			cost: 7500,
			contains: ["attractive lingerie for a pregnant woman"],
			owned: "You are well stocked with sexy silken lingerie designed for pregnant women.",
		},
	},
	FSrevivalist: {
		"egypt": {
			title: "a shipment of Egyptian necklaces",
			cost: 7500,
			contains: ["no clothing"],
			owned: "You are well stocked with ancient Egyptian necklaces.",
			modelUpdate: {collar: "ancient Egyptian"}
		},
		"toga": {
			title: "a shipment of togas and stolas",
			cost: 7500,
			contains: ["a toga"],
			owned: "You are well stocked with fine roman-styled togas and stolas.",
		},
		"huipil": {
			title: "a shipment of huipil",
			cost: 7500,
			contains: ["a huipil"],
			owned: "You are well stocked with exquisite Aztec huipils.",
		},
		"kimono": {
			title: "a shipment of kimonos",
			cost: 7500,
			contains: ["a kimono"],
			owned: "You are well stocked with elegant Japanese kimonos.",
		},
		"harem": {
			title: "a shipment of harem outfits",
			cost: 7500,
			contains: ["harem gauze"],
			owned: "You are well stocked with Arabic harem garb made from the finest available silks.",
		},
		"qipao": {
			title: "a shipment of qipaos",
			cost: 7500,
			contains: ["a slutty qipao"],
			owned: "You are well stocked with slutty Chinese qipaos.",
		},
		"imperialarmor": {
			title: "a shipment of bulky Imperial armor",
			cost: 12500,
			contains: ["Imperial Plate"],
			owned: "You are well stocked with spare sets of bulky powered armor of the same kind worn by your Imperial Knights.",
		},
		"imperialsuit": {
			title: "a shipment of tight Imperial bodysuits",
			cost: 7500,
			contains: ["a tight Imperial bodysuit"],
			owned: "You are well stocked with tight-fitting cybernetic bodysuits clearly bearing your family crest.",
		},
	},
	other: {
		"military": {
			title: "a shipment of military themed clothing",
			cost: 5000,
			contains: ["a military uniform", "a red army uniform", "battlearmor", "battledress"],
			owned: "You are well stocked with a variety of military themed garb.",
		},
		"cultural": {
			title: "a shipment of cultural outfits",
			cost: 15000,
			contains: ["a biyelgee costume", "a dirndl", "a hanbok", "a mounty outfit", "lederhosen"],
			owned: "You are well stocked with a variety of signature outfits from a variety of countries.",
		},
		"middleEastern": {
			title: "a shipment of burqas and similar garb",
			cost: 5000,
			contains: ["a burqa", "a niqab and abaya"],
			owned: "You are well stocked with a number of burqas and similar clothing.",
		},
		"casual": {
			title: "an extra large shipment of casual clothing",
			cost: 5000,
			contains: ["a button-up shirt and panties", "a button-up shirt", "a sweater and cutoffs", "a sweater and panties", "a sweater", "a t-shirt and jeans", "a t-shirt and panties", "a t-shirt", "a tank-top and panties", "a tank-top", "a tube top", "an oversized t-shirt", "cutoffs", "jeans", "leather pants and a tube top", "leather pants"],
			owned: "You are well stocked with casual clothing.",
		},
		"career": {
			title: "a shipment of professional garments",
			cost: 2500,
			contains: ["a nice nurse outfit", "a police uniform", "nice business attire"],
			owned: "You are well stocked with a selection of professional outfits.",
		},
		"dresses": {
			title: "a shipment of professionally tailored dresses",
			cost: 15000,
			contains: ["a ball gown", "a gothic lolita dress"],
			owned: "You are well stocked with a selection of fine dresses.",
		},
		"bodysuits": {
			title: "a shipment of exotic bodysuits",
			cost: 7500,
			contains: ["a cybersuit", "a latex catsuit"],
			owned: "You are well stocked with a selection of bodysuits.",
		},
		"underwear": {
			title: "a shipment of undergarments",
			cost: 5000,
			contains: ["a bra", "a skimpy loincloth", "a thong", "boyshorts", "kitty lingerie", "panties and pasties", "pasties"],
			owned: "You are well stocked with underwear.",
		},
		"sports": {
			title: "a shipment of exercise wear",
			cost: 2500,
			contains: ["a sports bra", "sport shorts and a sports bra", "sport shorts"],
			owned: "You are well stocked with exercise wear.",
		},
		"swimwear": {
			title: "a shipment of swimwear",
			cost: 3500,
			contains: ["a monokini", "a one-piece swimsuit"],
			owned: "You are well stocked with swimwear.",
		},
		"pony": {
			title: "a shipment of specialized latex ponygirl outfits",
			cost: 10000,
			contains: ["a nice pony outfit", "a slutty pony outfit"],
			owned: "You are well stocked with ponygirl bodysuits.",
		},
		"pol": {
			title: "a shipment of politically incorrect clothing",
			cost: 15000,
			contains: ["a klan robe", "a schutzstaffel uniform", "a slutty klan robe", "a slutty schutzstaffel uniform"],
			owned: "You are well stocked with a selection of outfits once considered distasteful.",
		},
		"costume": {
			title: "a shipment of colorful and revealing costumes",
			cost: 15000,
			contains: ["a Santa dress"],
			owned: "You are well stocked with a variety of costume party supplies.",
		},
		"pantsu": {
			title: "a large crate of panties from Japan",
			cost: 2500,
			contains: ["a striped bra", "striped panties", "striped underwear"],
			owned: "You have an impressive stash of panties and other striped underwear that may or may not be have at one point been used.",
		},
	}
};
/**
 * @type {Object.<string, wardrobeItem>} String will be the property checked to see if the item is owned. So for "bunny", it will check V.boughtItem.clothing["bunny"].
 */
App.Data.WardrobeShopping.Accessories = {
	"shoes.heels": {
		title: "a shipment of platform shoes",
		cost: 7500,
		contains: ["platform heels"],
		owned: "You have shelves dedicated to your collection of platform shoes.",
	},
	"clothing.belly": {
		title: "a shipment of fake pregnancy bellies",
		cost: 15000,
		contains: ["a small empathy belly"],
		owned: "You are well stocked with silicone pregnancy bellies modeled after variously sized women.",
	},
	"toys.dildos": {
		title: "a shipment of extra long dildos and bullet vibes",
		cost: 10000,
		contains: ["long dildo"],
		owned: "You are well stocked with extra long dildos in a variety of sizes, as well as a good amount of bullet vibrators.",
	},
	"toys.smartVibes": {
		title: `the "smart" variant of the bullet vibrators`,
		cost: 5000,
		contains: ["long dildo"],
		get requirements() { return V.boughtItem.toys.dildos !== 0; },
		owned: `Some of the bullet vibes are of the "smart" variety, interfaced to the arcology's systems.`,
	},
	"toys.vaginalAttachments": {
		title: "a shipment of vibrating dildo attachments",
		cost: 10000,
		contains: [],
		owned: "You are well stocked with attachments that allow dildos to vibrate.",
	},
	"toys.smartVaginalAttachments": {
		title: `the "smart" variant of the vibrating dildo attachments`,
		cost: 5000,
		contains: [],
		get requirements() { return V.boughtItem.toys.vaginalAttachments !== 0; },
		owned: `Some of the vibrating dildo attachments are of the "smart" variety, interfaced to the arcology's systems.`,
	},
	"toys.buttPlugs": {
		title: "a shipment of extra long buttplugs",
		cost: 10000,
		contains: [],
		owned: "You are well stocked with extra long buttplugs in a variety of sizes.",
	},
	"toys.buttPlugTails": {
		title: "a shipment of attachable tails",
		cost: 5000,
		contains: [],
		owned: "You are well stocked with tails to attach to your buttplugs.",
	},
	"toys.gags": {
		title: "a shipment of massive dildo gags",
		cost: 5000,
		contains: [],
		owned: "You are well stocked with massive dildo gags.",
	},
	"toys.buckets": {
		title: "everything you need to force-feed slaves",
		note: `Some supplies from the cafeteria and a slight adjustment to the feeder settings is all it would take.`,
		cost: 0,
		contains: [],
		owned: "You have everything you need in one place to force-feed slaves. You've also adjusted the feeders to cheaply produce filler food to save on money. However, said food is just empty calories and probably bad for a slave's waistline.",
	},
	"toys.enema": {
		title: "enema supplies",
		cost: 5000,
		contains: [],
		owned: "You are well stocked with specially formulated liquids to be used safely for long term enemas along with the tools needed to keep a slave bloated for extended periods of time",
	},
	"toys.medicalEnema": {
		title: `medical enema supplies`,
		cost: 5000,
		contains: [],
		get requirements() { return (V.boughtItem.toys.enema !== 0); },
		owned: "You are also well stocked with drugs to be mixed with the enema water for use in medical enemas.",
	},
};


code:
/** @param {App.Entity.SlaveState} sacrifice */
App.UI.SlaveInteract.aztecSlaveSacrificeLife = function(sacrifice) {
	const frag = new DocumentFragment();
	let r = [];

	const {He, his} = getPronouns(sacrifice);

	const activeSlaveRepSacrifice = repGainSacrifice(sacrifice, V.arcologies[0]);
	r.push(`${He} dies screaming as ${his} still beating heart is ripped out of ${his} body.`);
	if (activeSlaveRepSacrifice <= 0) {
		r.push(`Nobody cares.`);
	} else if (activeSlaveRepSacrifice < 10) {
		r.push(`The few spectators are suitably impressed.`);
	} else if (activeSlaveRepSacrifice < 100) {
		r.push(`The small crowd appreciates your devotion to the Aztec culture.`);
	} else {
		r.push(`The crowd cheers to the bloody spectacle.`);
	}
	if (V.slaves.length > 0) {
		r.push(`On the other hand, your remaining`);
		if (V.slaves.length === 1) {
			r.push(`slave is`);
		} else {
			r.push(`slaves are`);
		}
		r.push(`suitably <span class="trust dec">horrified.</span>`);
		for (const slave of V.slaves.filter((s) => !isVegetable(s))) {
			slave.trust -= 5 + random(5);
		}
	}
	repX(activeSlaveRepSacrifice, "futureSocieties");
	if (V.arcologies[0].FSAztecRevivalist !== "unset" && V.arcologies[0].FSAztecRevivalist < 100) {
		V.arcologies[0].FSAztecRevivalist += 1;
	}
	V.slavesSacrificedThisWeek = (V.slavesSacrificedThisWeek || 0) + 1;
	removeSlave(sacrifice);

	App.Events.addParagraph(frag, r);
	return frag;
};


code:
/** Replaces <<SetFacilityDecoration>> widget
 * @returns {DocumentFragment}
 */
App.UI.facilityRedecoration = function() {
	const el = new DocumentFragment();
	const options = new App.UI.OptionsGroup();
	const arc = V.arcologies[0];

	FutureSocieties.DecorationCleanup();

	const applicableFS = FutureSocieties.activeFSes(arc).filter(name => (arc[name] > 20));
	const decorationNames = Array.from(applicableFS, FS => FutureSocieties.decorationName(FS)).filter(Boolean);

	const activeFacilities = Object.values(App.Entity.facilities).filter(f => f.isDecorated && f.established);

	// dummy variable to make sure the first option is selected by default
	const currentSelected = {value: "none"};
	let option = options.addOption(`Set decoration value for all facilities to`, "value", currentSelected)
		.addValue("(Select option)", "none")
		.addValue("Standard", "standard");
	if (decorationNames.length > 0) {
		option.addValueList(decorationNames);
		if (decorationNames.length > 1) {
			option.addValue("Distribute Evenly", "even");
		}
	}
	option.addCallbackToEach(value => {
		console.log(value);
		let totalCost = 0;
		if (value === "even") { // Cycles through the list of available FS decorations, and distributes them to facilities round robin style.
			let i = 0;
			for (const facility of activeFacilities) {
				if (facility.decoration !== decorationNames[i]) {
					totalCost += 5000;
					facility.decoration = decorationNames[i];
				}
				i++;
				if (i >= decorationNames.length) {
					i = 0;
				}
			}
		} else if (value !== "none") {
			for (const facility of activeFacilities) {
				if (value !== "standard" && value !== facility.decoration) {
					totalCost += 5000;
				}
				facility.decoration = value;
			}
		}
		if (totalCost > 0) {
			cashX(-totalCost, "capEx");
		}
	}).pulldown();

	for (const facility of activeFacilities) {
		options.addOption(`The decoration style of ${facility.name} is`, "decoration", facility)
			.addValue("Standard", "standard")
			.addValueList(decorationNames)
			.addCallbackToEach(value => {
				if (value !== "standard") {
					cashX(-5000, "capEx");
				}
			})
			.pulldown();
	}
	el.append(options.render());

	return el;
};

/**
 *
 * @param {FC.FutureSociety} FS
 * @param {Array} [items]
 * @returns {HTMLElement}
 */
App.UI.FSChangeDecoration = function(FS, items = []) {
	const el = document.createElement("div");
	el.classList.add("indent");
	const FSDecoration = FS + "Decoration";
	let costs;
	switch (V.arcologies[0][FSDecoration]) {
		case 20:
			costs = 2500;
			el.append(`${V.arcologies[0].name} is not customized to support this goal. `);
			if (V.arcologies[0][FS] >= 10) {
				el.append(
					makePurchase(`Modify your arcology's internal media to support this goal`, costs, "capEx", {
						handler: () => {
							V.arcologies[0][FSDecoration] = 40;
						},
					}),
				);
			} else {
				el.append(`You must advance this goal before customization to support it becomes available. `);
			}
			break;
		case 40:
			el.append(`${V.arcologies[0].name}'s media is supporting this goal. `);
			if (V.arcologies[0][FS] >= 30) {
				costs = 10000;
				el.append(
					makePurchase(`Redecorate your arcology's public spaces to support this goal`, costs, "capEx", {
						handler: () => {
							V.arcologies[0][FSDecoration] = 60;
						}
					}),
				);
			} else {
				el.append(`You must advance this goal before further customization to support it becomes available. `);
			}
			break;
		case 60:
			el.append(`${V.arcologies[0].name}'s media is supporting this goal, and ${V.arcologies[0].name}'s public spaces are decorated to support it too. `);
			if (V.arcologies[0][FS] >= 50) {
				costs = 10000;
				el.append(
					makePurchase(`Station slaves in your arcology's public spaces to promote this goal`, costs, "capEx", {
						handler: () => {
							V.arcologies[0][FSDecoration] = 80;
						}
					}),
				);
			} else {
				el.append(`You must advance this goal before further customization to support it becomes available. `);
			}
			break;
		case 80:
			el.append(`${V.arcologies[0].name}'s media is supporting this goal; ${V.arcologies[0].name}'s public spaces are decorated to support it, and have slaves stationed in them to support it too. `);
			if (V.arcologies[0][FS] >= 70) {
				if (FS === "FSRestart") {
					costs = 75000;
					el.append(
						makePurchase(`Customize the exterior of the arcology to support this goal and fully establish the Societal Elite`, costs, "capEx", {
							handler: () => {
								V.arcologies[0][FSDecoration] = 100;
								V.upgradeMultiplierArcology = upgradeMultiplier('engineering');
								V.upgradeMultiplierMedicine = upgradeMultiplier('medicine');
								for (const item of items) {
									_.set(V, item, 1);
								}
							}
						}),
					);
				} else {
					costs = 10000;
					el.append(
						makePurchase(`Customize the exterior of the arcology to support this goal`, costs, "capEx", {
							handler: () => {
								V.arcologies[0][FSDecoration] = 100;
								cashX(forceNeg(costs), "capEx");
								for (const item of items) {
									_.set(V, item, 1);
								}
							}
						}),
					);
				}
			} else {
				el.append(`You must advance this goal before further customization to support it becomes available. `);
			}
			break;
		case 100:
			el.append(`${V.arcologies[0].name}'s media is supporting this goal; ${V.arcologies[0].name}'s public spaces are decorated to support it, and have slaves stationed in them to support it. The exterior of the arcology has been remodeled to support it as well; the arcology is fully customized for this goal. `);
	}
	return el;
};