diff --git a/src/descriptions/officeDescription.js b/src/descriptions/officeDescription.js
new file mode 100644
index 0000000000000000000000000000000000000000..4ecac53c275b09bf69800c17cb5e04b75ea9c2ce
--- /dev/null
+++ b/src/descriptions/officeDescription.js
@@ -0,0 +1,550 @@
+/**
+ * @param {DocumentFragment} [lastElement] will go on the same line as the last line
+ * @returns {DocumentFragment}
+ */
+App.Desc.officeDescription = function(lastElement) {
+
+	const f = document.createDocumentFragment();
+
+	App.UI.DOM.appendNewElement("div", f, paragraph1(), "indent");
+	App.UI.DOM.appendNewElement("div", f, paragraph2(), "indent");
+
+	const lastDiv = App.UI.DOM.appendNewElement("div", f, paragraph3(), "indent");
+	lastDiv.append(lastElement);
+
+	return f;
+
+	/**
+	 * @returns {string}
+	 */
+	function paragraph1() {
+		const r = [];
+		r.push(`You are at your desk in your penthouse office. It has a glass top interface from which you can rule over ${V.arcologies[0].name}; ${V.assistant.name}'s avatar is visible in one corner.`);
+		r.push(PersonalAssistantAppearance());
+
+		if (V.clubAdsSpending >= 5000) {
+			r.push(`A corner of your desk is piled with sample merchandise from the campaign promoting your club.`);
+			const clubSlaves = V.slaves.filter(s => s.assignment === "serve in the club");
+			if (clubSlaves.length > 0) {
+				const modeledSlave = clubSlaves.random();
+				const {he, his} = getPronouns(modeledSlave);
+
+				if (random(1, 2) === 1 || !canStand(modeledSlave)) {
+					r.push(`This includes a sex toy based on${modeledSlave.slaveName}'s`);
+					if (random(1, 3) === 1 &&
+						modeledSlave.skill.vaginal >= 100) {
+						if (modeledSlave.vagina > 3) {
+							r.push(`massive vagina`);
+						} else if (modeledSlave.vagina > 2) {
+							r.push(`gaping cunt`);
+						} else if (modeledSlave.vagina > 1) {
+							r.push(`hot cunt`);
+						} else if (modeledSlave.vagina > 0) {
+							r.push(`tight pussy`);
+						} else {
+							r.push(`virgin pussy`);
+						}
+						r.push(r.pop() + ".");
+					} else if ((random(1, 2) === 1) && (modeledSlave.skill.oral >= 100)) {
+						if (modeledSlave.lips > 40) {
+							r.push(`huge`);
+						} else if (modeledSlave.lips > 20) {
+							r.push(`pillowlike`);
+						} else if (modeledSlave.lips > 10) {
+							r.push(`pretty`);
+						} else {
+							r.push(`thin`);
+						}
+						r.push(` lips and throat.`);
+					} else {
+						if (modeledSlave.anus > 3) {
+							r.push(`blown-out butthole`);
+						} else if (modeledSlave.anus > 2) {
+							r.push(`roomy anus`);
+						} else if (modeledSlave.anus > 1) {
+							r.push(`big butthole`);
+						} else if (modeledSlave.anus > 0) {
+							r.push(`tight asshole`);
+						} else {
+							r.push(`virgin backdoor`);
+						}
+						r.push(r.pop() + ".");
+					}
+				} else {
+					r.push(`There is a figurine of${modeledSlave.slaveName} ${he}'s depicted`);
+					if (random(1, 3) === 1 && modeledSlave.skill.vaginal >= 100) {
+						r.push(`lying nude on ${his} back, spreading ${his} legs to `);
+						if (modeledSlave.vagina > 3) {
+							r.push(`exhibit ${his} massive vagina`);
+						} else if (modeledSlave.vagina > 2) {
+							r.push(`show off ${his} gaping cunt`);
+						} else if (modeledSlave.vagina > 1) {
+							r.push(`offer ${his} hot cunt`);
+						} else if (modeledSlave.vagina > 0) {
+							r.push(`display ${his} tight pussy`);
+						} else {
+							r.push(`tantalize with ${his} virgin pussy`);
+						}
+						r.push(r.pop() + ".");
+					} else if ((random(1, 2) === 1) && (modeledSlave.skill.oral >= 100)) {
+						r.push(`with ${his} `);
+						if (modeledSlave.lips > 40) {
+							r.push(`huge`);
+						} else if (modeledSlave.lips > 20) {
+							r.push(`pillowlike`);
+						} else if (modeledSlave.lips > 10) {
+							r.push(`pretty`);
+						} else {
+							r.push(`thin`);
+						}
+						r.push(` lips parted, ${his} tongue partway out.`);
+					} else {
+						r.push(`bending at the waist and spreading ${his} `);
+						if (modeledSlave.butt > 6) {
+							r.push(`gigantic buttocks`);
+						} else if (modeledSlave.butt > 4) {
+							r.push(`meaty asscheeks`);
+						} else if (modeledSlave.butt > 2) {
+							r.push(`healthy buttocks`);
+						} else {
+							r.push(`cute butt`);
+						}
+						r.push(` to show off ${his} `);
+						if (modeledSlave.anus > 3) {
+							r.push(`blown-out butthole`);
+						} else if (modeledSlave.anus > 2) {
+							r.push(`roomy butthole`);
+						} else if (modeledSlave.anus > 1) {
+							r.push(`big butthole`);
+						} else if (modeledSlave.anus > 0) {
+							r.push(`tight asshole`);
+						} else {
+							r.push(`virgin backdoor`);
+						}
+						r.push(r.pop() + ".");
+					}
+				}
+			}
+		}
+
+		if (V.brothelAdsSpending >= 5000) {
+			if (V.clubAdsSpending >= 5000) {
+				r.push(`There's just as much from the similar campaign advertising ${V.brothelName}.`);
+			} else {
+				r.push(`A corner of your desk is piled with sample merchandise from the campaign promoting ${V.brothelName}.`);
+			}
+			const brothelSlaves = V.slaves.filter(s => s.assignment === "work in the brothel");
+			if (brothelSlaves.length > 0) {
+				const modeledSlave = brothelSlaves.random();
+				const {he, his} = getPronouns(modeledSlave);
+
+				if (random(1, 2) === 1 || !canStand(modeledSlave)) {
+					r.push(`This includes a sex toy based on ${modeledSlave.slaveName}'s`);
+					if (random(1, 3) === 1 && modeledSlave.skill.vaginal >= 100) {
+						if (modeledSlave.vagina > 3) {
+							r.push(`massive vagina`);
+						} else if (modeledSlave.vagina > 2) {
+							r.push(`gaping cunt`);
+						} else if (modeledSlave.vagina > 1) {
+							r.push(`hot cunt`);
+						} else if (modeledSlave.vagina > 0) {
+							r.push(`tight pussy`);
+						} else {
+							r.push(`virgin pussy`);
+						}
+						r.push(r.pop() + ".");
+					} else if ((random(1, 2) === 1) && (modeledSlave.skill.oral >= 100)) {
+						if (modeledSlave.lips > 40) {
+							r.push(`huge`);
+						} else if (modeledSlave.lips > 20) {
+							r.push(`pillowlike`);
+						} else if (modeledSlave.lips > 10) {
+							r.push(`pretty`);
+						} else {
+							r.push(`thin`);
+						}
+						r.push(` lips and throat.`);
+					} else {
+						if (modeledSlave.anus > 3) {
+							r.push(`blown-out butthole`);
+						} else if (modeledSlave.anus > 2) {
+							r.push(`roomy butthole`);
+						} else if (modeledSlave.anus > 1) {
+							r.push(`big butthole`);
+						} else if (modeledSlave.anus > 0) {
+							r.push(`tight asshole`);
+						} else {
+							r.push(`virgin backdoor`);
+						}
+						r.push(r.pop() + ".");
+					}
+				} else {
+					r.push(`This includes paired figurines of ${modeledSlave.slaveName} with a faceless male figure;`);
+					if (random(1, 3) === 1 && modeledSlave.skill.vaginal >= 100) {
+						r.push(`${he}'s shamelessly riding his dick.`);
+					} else if ((random(1, 2) === 1) && (modeledSlave.skill.oral >= 100)) {
+						r.push(`${he}'s on ${his} `);
+						if (hasAnyLegs(modeledSlave)) {
+							r.push(`${his} knee`);
+							if (hasBothLegs(modeledSlave)) {
+								r.push(`s`);
+							}
+						} else {
+							r.push(`the ground`);
+						}
+						r.push(` with ${his} `);
+						if (modeledSlave.lips > 40) {
+							r.push(`huge`);
+						} else if (modeledSlave.lips > 20) {
+							r.push(`pillowlike`);
+						} else if (modeledSlave.lips > 10) {
+							r.push(`pretty`);
+						} else {
+							r.push(`thin`);
+						}
+						r.push(` lips wrapped around his dick.`);
+					} else {
+						r.push(`${he}'s shown `);
+						if (modeledSlave.anus > 3) {
+							r.push(`looking up teasingly as ${he} takes his dick up ${his} blown-out butthole`);
+						} else if (modeledSlave.anus > 2) {
+							r.push(`looking up teasingly as ${he} takes his dick up ${his} roomy anus`);
+						} else if (modeledSlave.anus > 1) {
+							r.push(`looking up teasingly as ${he} takes his dick in ${his} big butthole`);
+						} else if (modeledSlave.anus > 0) {
+							r.push(`gasping as ${he} takes his dick in ${his} tight asshole`);
+						} else {
+							r.push(`screaming as he fucks ${his} virgin backdoor`);
+						}
+						r.push(r.pop() + ".");
+					}
+				}
+			}
+		}
+
+		return r.join(" ");
+	}
+
+	/**
+	 * @returns {string}
+	 */
+	function paragraph2() {
+		const r = [];
+
+		r.push("Next to your desk is a sturdy black leather couch. All the walls on this floor are glass, so you can see your");
+		if (V.slaves.length > 50) {
+			r.push(`innumerable`);
+		} else if (V.slaves.length > 20) {
+			r.push(`many`);
+		} else if (V.slaves.length > 10) {
+			r.push(`numerous`);
+		} else if (V.slaves.length > 5) {
+			r.push(`handful of`);
+		} else {
+			r.push(`few`);
+		}
+		r.push(` slaves going about their business. The room is designed so that everyone must walk past the door to your office to get anywhere.`);
+
+		if (V.personalArms > 0) {
+			r.push(`Your custom armor rests in the corner of the room where visitors can admire it, and you can don it quickly if necessary.`);
+			if (V.week > (43 - V.nationHate) && V.mercenaries >= 5) {
+				r.push(`Its plates bear scarring won in victorious battle, and from its back rises a banner depicting you at the head of your ${V.mercenariesTitle}.`);
+			} else if (V.week > (43 - V.nationHate)) {
+				r.push(`Its plates bear scarring fairly won.`);
+			}
+			if (V.assistant.personality > 0) {
+				const {
+					HeA, heA, hisA, himA, girlA, himselfA, womanA, loliA
+				} = getPronouns(assistant.pronouns().main).appendSuffix("A");
+
+				r.push(`The last time${heA} had it maintained, ${V.assistant.name} added`);
+				switch (V.assistant.appearance) {
+					case "monstergirl":
+						r.push(`a pinup of ${himselfA} to its plating: ${heA}'s depicted with ${hisA} fangs bared, each strand of ${hisA} tentacle hair holding a lightning bolt, and both of ${hisA} cocks ejaculating fire.`);
+						break;
+					case "shemale":
+						r.push(`a pinup of ${himselfA} to its plating: ${heA}'s depicted straddling a battle rifle so closely that it looks like ${heA}'s intimately entangled in the action.`);
+
+						break;
+					case "amazon":
+						r.push(`a pinup of ${himselfA} to its plating: ${heA}'s depicted in a classic nude bodybuilder's pose, but with a cutely coquettish expression.`);
+
+						break;
+					case "businesswoman":
+						r.push(`a pinup of ${himselfA} to its plating: ${heA}'s depicted wearing underwear, for once, and looking very severe as ${heA} straddles a cruise missile in a classic bombshell pose.`);
+						break;
+					case "fairy":
+						r.push(`a pinup of ${himselfA} to its plating: ${heA}'s depicted naked as usual, standing on top of a large bullet and making finger guns with a grin on ${hisA} face.`);
+						break;
+					case "pregnant fairy":
+						r.push(`a pinup of ${himselfA} to its plating: ${heA}'s depicted naked as usual, straddling a large bullet and making peace signs with ${hisA} tongue sticking out.`);
+						break;
+					case "goddess":
+						r.push(`a pinup of ${himselfA} to its plating: ${heA}'s depicted demurely but barely covering ${hisA} radiant body with a flowing ribbon, like a goddess about to burst with triplets.`);
+						break;
+					case "hypergoddess":
+						r.push(`a pinup of ${himselfA} to its plating: ${heA}'s depicted barely covering ${hisA} hugely pregnant, radiant body with a flowing ribbon, like a goddess about to burst open from ${hisA} hundreds of children.`);
+						break;
+					case "loli":
+						r.push(`a pinup of ${himselfA} to its plating: ${heA}'s cutely hugging a rifle to ${hisA} flat chest.`);
+						break;
+					case "preggololi":
+						r.push(`a pinup of ${himselfA} to its plating: ${heA}'s flashing ${hisA} lewd preggo ${loliA} pussy.`);
+						break;
+					case "angel":
+						r.push(`a pinup of ${himselfA} to its plating: ${heA}'s depicted wielding a flaming sword and golden shield.`);
+						break;
+					case "cherub":
+						r.push(`a pinup of ${himselfA} to its plating: ${heA}'s depicted hugging a bow to ${hisA} chest.`);
+						break;
+					case "incubus":
+						r.push(`a pinup of ${himselfA} to its plating: ${heA}'s depicted mid-orgasm, a bullet rocketing from ${hisA} dick amidst a blast of cum.`);
+						break;
+					case "succubus":
+						r.push(`a pinup of ${himselfA} to its plating:`);
+						switch (V.assistant.fsAppearance) {
+							case "paternalist":
+								r.push(`${heA}'s depicted hiking ${hisA} skirt to flash ${hisA} crotch.`);
+								break;
+							case "degradationist":
+								r.push(`${heA}'s depicted striking a pose showing off ${hisA} countless piercings.`);
+								break;
+							case "roman revivalist":
+								r.push(`${heA}'s depicted in a stola, flashing ${hisA} tits.`);
+								break;
+							case "neoimperialist":
+								r.push(`${heA}'s depicted in a tight Imperial bodysuit that shows off every curve.`);
+								break;
+							case "egyptian revivalist":
+								r.push(`${heA}'s depicted groping ${hisA} perfect bronze breasts while blowing a kiss.`);
+								break;
+							case "edo revivalist":
+								r.push(`${heA}'s depicted in a kimono, pulled open to flash ${hisA} lovely breasts.`);
+								break;
+							case "arabian revivalist":
+								r.push(`${heA}'s depicted wearing fine silks and striking a sexy pose, though they fail to cover anything on ${himA}.`);
+								break;
+							case "chinese revivalist":
+								r.push(`${heA}'s depicted wearing colorful silk robes; ${heA}'s pulled them open to flash ${hisA} lovely body.`);
+								break;
+							case "supremacist":
+								r.push(`${heA}'s depicted wearing the dress of an old world ${V.arcologies[0].FSSupremacistRace} noble ${womanA} and blowing a kiss in a sexy manner.`);
+								break;
+							case "subjugationist":
+								r.push(`${heA}'s depicted sitting with ${hisA} legs wide open and using ${hisA} fingers to spread ${hisA} ${V.arcologies[0].FSSubjugationistRace} pussy lips apart in a lewd manner.`);
+								break;
+							case "chattel religionist":
+								r.push(`${heA}'s depicted striking a sexy pose, chosen specifically to draw attention to the symbols of your religion that adorn ${hisA} nipples.`);
+								break;
+							case "repopulation focus":
+								r.push(`${heA}'s depicted striking a sexy pose made to draw the eye to ${hisA} pregnant belly.`);
+								break;
+							case "eugenics":
+								r.push(`${heA}'s depicted striking a sexy pose; ${heA}'s so stunning you can't look away.`);
+								break;
+							case "physical idealist":
+								r.push(`${heA}'s depicted flexing ${hisA} tremendous`);
+								if (V.arcologies[0].FSPhysicalIdealistStrongFat === 1) {
+									r.push(`${r.pop()}, fat-veiled`);
+								}
+								r.push(` musculature intimidatingly.`);
+								break;
+							case "hedonistic decadence":
+								r.push(`${heA}'s depicted deep throating a banana while groping ${hisA} large, soft belly.`);
+								break;
+							case "gender radicalist":
+								r.push(`${heA}'s depicted facing away from you, looking over ${hisA} shoulder suggestively and presenting`);
+								if (V.arcologies[0].FSGenderRadicalistLawFuta === 1) {
+									r.push(`${hisA} rear. A pair of balls hangs beneath ${hisA} tight pussy.`);
+								} else if (V.arcologies[0].FSGenderRadicalistLawFuta === 2) {
+									r.push(`${hisA} anus. A pair of heavy balls hangs from ${hisA} crotch.`);
+								} else if (V.arcologies[0].FSGenderRadicalistLawFuta === 3) {
+									r.push(`${hisA} gigantic ass.`);
+								} else if (V.arcologies[0].FSGenderRadicalistLawFuta === 4) {
+									r.push(`${hisA} anus. A tiny pair of balls hangs from ${hisA} crotch.`);
+								} else {
+									r.push(`${hisA} rear.`);
+								}
+								break;
+							case "gender fundamentalist":
+								r.push(`${heA}'s depicted with one hand on ${hisA} supple breast and the other tracing the curve of ${hisA} child-bearing hips.`);
+								break;
+							case "asset expansionist":
+								r.push(`${heA}'s depicted cradling ${hisA} own pair of ballistics; ${hisA} gigantic breasts are painted like atom bombs.`);
+								break;
+							case "transformation fetishist":
+								r.push(`${heA}'s depicted striking a pose with one arm supporting ${hisA} enormous implants.`);
+								break;
+							case "pastoralist":
+								r.push(`${heA}'s depicted striking a sexy pose, hands trying to relieve the pressure of ${hisA} quartet of milk filled breasts.`);
+								break;
+							case "maturity preferentialist":
+								r.push(`${heA}'s depicted in a pose not unlike something you'd see on a 60's pinup calendar`);
+								break;
+							case "youth preferentialist":
+								r.push(`${heA}'s depicted in a pose fresh out of a popular idol's newest video.`);
+								break;
+							case "slimness enthusiast":
+								r.push(`${heA}'s depicted striking a sexy pose while running ${hisA} hands across ${hisA}`);
+								if (V.arcologies[0].FSSlimnessEnthusiastLaw === 1) {
+									r.push(`flat chest.`);
+								} else {
+									r.push(`slim assets.`);
+								}
+								break;
+							case "body purist":
+								r.push(`${heA}'s depicted striking a sexy pose that shows off every flawless`);
+								if (V.showInches === 2) {
+									r.push(`inch`);
+								} else {
+									r.push(`centimeter`);
+								}
+								r.push(` of ${hisA} body.`);
+								break;
+							case "intellectual dependency":
+								r.push(`${heA}'s depicted riding a missile, both literally and sexually.`);
+								break;
+							case "slave professionalism":
+								r.push(`${heA}'s depicted getting hands-on with cruise missile, priming it to go off.`);
+								break;
+							case "petite admiration":
+								r.push(`${heA}'s depicted striking a pose with a rifle as large as ${heA} is.`);
+								break;
+							case "statuesque glorification":
+								r.push(`${heA}'s depicted striking a sexy pose. ${HeA} made sure to utilize the armor's entire height.`);
+								break;
+							default:
+								r.push(`${heA}'s posing like a classic centerfold ${girlA}.`);
+						}
+						break;
+					case "imp":
+						r.push(`a pinup of ${himselfA} to its plating: ${heA}'s depicted straddling a trident; pussy juices running down its shaft.`);
+						break;
+					case "witch":
+						r.push(`a pinup of ${himselfA} to its plating: ${heA}'s depicted straddling a broom, winking.`);
+						break;
+					case "ERROR_1606_APPEARANCE_FILE_CORRUPT":
+						r.push(`a pinup of ${himselfA} to its plating: you have no idea what to make of it. Whatever it is, it is devouring your enemies on one end and popping out proper slaves from the other.`);
+						break;
+					case "schoolgirl":
+						r.push(`a pinup of ${himselfA} to its plating: ${heA}'s depicted up on tiptoe, back turned, with ${hisA} school${girlA} skirt riding up to bare${hisA} bottom.`);
+						break;
+					default:
+						r.push(`${hisA} own symbol to its insignia.`);
+				}
+			}
+		}
+		return r.join(" ");
+	}
+
+	/**
+	 * @returns {string}
+	 */
+	function paragraph3() {
+		const r = [];
+
+		r.push(printTrinkets());
+
+		r.push(`A small mirror resides on your desk, facing you.`);
+		r.push(`A ${V.PC.visualAge} year old, ${V.PC.faceShape}`);
+		if (V.PC.markings === "freckles") {
+			r.push(`${r.pop()}, freckled`);
+		} else if (V.PC.markings === "heavily freckled") {
+			r.push(`${r.pop()}, densely freckled`);
+		}
+		r.push(` face stares back at you.`);
+		if (V.playerAging !== 0 && V.PC.birthWeek === 51) {
+			r.push(`You'll be turning ${V.V.PC.actualAge + 1} next week.`);
+		}
+
+		r.push(App.Desc.Player.boobs(), App.Desc.Player.belly(), App.Desc.Player.crotch(), App.Desc.Player.butt());
+
+		return r.join(" ");
+	}
+
+	/**
+	 * @returns {string}
+	 */
+	function printTrinkets() {
+		if (V.trinkets.length === 0) {
+			return "";
+		}
+
+		const trinkets = weightedArray2HashMap(V.trinkets);
+		let trinketString = [];
+		let plurals = false;
+
+		for (const trinketDesc in trinkets) {
+			if (trinkets[trinketDesc] === 1) {
+				trinketString.push(trinketDesc);
+			} else if (trinkets[trinketDesc] > 1) {
+				trinketString.push(trinketPluralReplacer(trinketDesc));
+				plurals = true;
+			}
+		}
+
+		// depending on length of trinketString, add necessary conjunctions
+		if (trinketString.length === 1) {
+			if (plurals === false) {
+				trinketString = `a single item: ${trinketString[0]}`;
+			} else {
+				trinketString = trinketString[0];
+			}
+		} else if (trinketString.length === 2 && plurals === false) {
+			trinketString = `a couple of items: ${trinketString[0]}, and ${trinketString[1]}`;
+		} else {
+			trinketString[trinketString.length - 1] = `and ${trinketString[trinketString.length - 1]}`;
+			trinketString = trinketString.join(", ");
+		}
+		return `There's a display case behind your desk, with ${trinketString}.`;
+	}
+
+	function trinketPluralReplacer(desc) {
+		let r;
+		switch (desc) {
+			/* not supported
+				best in show ribbons
+				napkins
+				App.SlaveAssignment.porn trinkets
+				wedding photos
+			*/
+			// should never have plurals
+			case "a collection of diplomas from expensive schools":
+			case "a framed low denomination piece of paper money from your native country":
+			case "a battered old assault rifle":
+			case "a framed picture of a slave with her sale price scrawled across the bottom":
+			case "an artist's impression of an early arcology design":
+			case "a framed copy of the first news story featuring yourself":
+			case "a miniature model of your first arcology":
+			case "a copy of the first porno you starred in":
+			case "a framed picture of your late Master":
+			case "your favorite handgun, whose sight has instilled fear in many":
+			case "a news clipping of your first successful live hack":
+			case "a damaged plate carrier bearing Daughters of Liberty insignia":
+			case "a Daughters of Liberty flag that once hung in their forward command post within your arcology":
+			case "a Daughters of Liberty brassard":
+			case "a shot-torn flag of the failed nation whose militants attacked the Free City":
+				return desc;
+			// manual replacement
+			case "a thank-you note from a MILF tourist whom you made feel welcome in the arcology":
+				return "several thank-you notes from MILF tourists whom you made feel welcome in the arcology";
+			// replacement by groups
+			default:
+				r = desc;
+				if (desc.endsWith("citizen")) { // will not reduce spam from different future societies
+					r = r.replace("message", "messages");
+					r = r.replace("from a", "from");
+					r = r.replace("a ", "several ");
+					r = r.replace("citizen", "citizens");
+					r = r.replace("number", "numbers");
+					r = r.replace("test", "tests");
+				} else if (desc.endsWith("acquaintance")) {
+					r = r.replace("note", "notes");
+					r = r.replace("from a", "from");
+					r = r.replace("a ", "several ");
+					r = r.replace("owner", "owners");
+				}
+				return r;
+		}
+	}
+};
diff --git a/src/js/storyJS.js b/src/js/storyJS.js
index 25cab312c4d852543b53db801848003cf59626eb..cc771ba9a0fc20fe25c9c486999f69b6c16665b5 100644
--- a/src/js/storyJS.js
+++ b/src/js/storyJS.js
@@ -593,89 +593,6 @@ globalThis.generatePlayerPronouns = function(PC) {
 	}
 };
 
-globalThis.printTrinkets = function() {	// TODO: move these out of global scope
-	function trinketPluralReplacer(desc) {
-		let r;
-		switch (desc) {
-			/* not supported
-				best in show ribbons
-				napkins
-				App.SlaveAssignment.porn trinkets
-				wedding photos
-			*/
-			// should never have plurals
-			case "a collection of diplomas from expensive schools":
-			case "a framed low denomination piece of paper money from your native country":
-			case "a battered old assault rifle":
-			case "a framed picture of a slave with her sale price scrawled across the bottom":
-			case "an artist's impression of an early arcology design":
-			case "a framed copy of the first news story featuring yourself":
-			case "a miniature model of your first arcology":
-			case "a copy of the first porno you starred in":
-			case "a framed picture of your late Master":
-			case "your favorite handgun, whose sight has instilled fear in many":
-			case "a news clipping of your first successful live hack":
-			case "a damaged plate carrier bearing Daughters of Liberty insignia":
-			case "a Daughters of Liberty flag that once hung in their forward command post within your arcology":
-			case "a Daughters of Liberty brassard":
-			case "a shot-torn flag of the failed nation whose militants attacked the Free City":
-				return desc;
-				// manual replacement
-			case "a thank-you note from a MILF tourist whom you made feel welcome in the arcology":
-				return "several thank-you notes from MILF tourists whom you made feel welcome in the arcology";
-				// replacement by groups
-			default:
-				r = desc;
-				if (desc.endsWith("citizen")) { // will not reduce spam from different future societies
-					r = r.replace("message", "messages");
-					r = r.replace("from a", "from");
-					r = r.replace("a ", "several ");
-					r = r.replace("citizen", "citizens");
-					r = r.replace("number", "numbers");
-					r = r.replace("test", "tests");
-				} else if (desc.endsWith("acquaintance")) {
-					r = r.replace("note", "notes");
-					r = r.replace("from a", "from");
-					r = r.replace("a ", "several ");
-					r = r.replace("owner", "owners");
-				}
-				return r;
-		}
-	}
-
-	if (V.trinkets.length === 0) {
-		return "";
-	}
-
-	const trinkets = weightedArray2HashMap(V.trinkets);
-	let trinketString = [];
-	let plurals = false;
-
-	for (const trinketDesc in trinkets) {
-		if (trinkets[trinketDesc] === 1) {
-			trinketString.push(trinketDesc);
-		} else if (trinkets[trinketDesc] > 1) {
-			trinketString.push(trinketPluralReplacer(trinketDesc));
-			plurals = true;
-		}
-	}
-
-	// depending on length of trinketString, add necessary conjunctions
-	if (trinketString.length === 1) {
-		if (plurals === false) {
-			trinketString = `a single item: ${trinketString[0]}`;
-		} else {
-			trinketString = trinketString[0];
-		}
-	} else if (trinketString.length === 2 && plurals === false) {
-		trinketString = `a couple of items: ${trinketString[0]}, and ${trinketString[1]}`;
-	} else {
-		trinketString[trinketString.length - 1] = `and ${trinketString[trinketString.length - 1]}`;
-		trinketString = trinketString.join(", ");
-	}
-	return `There's a display case behind your desk, with ${trinketString}.`;
-};
-
 /**
  * @param {number} nmbr1
  * @param {number} nmbr2
diff --git a/src/uncategorized/main.tw b/src/uncategorized/main.tw
index f01cb6e089b43c9fe7e529aa1c68ec4009bb1735..cd73e8b5f033317e518a90f032a661b8e827dcad 100644
--- a/src/uncategorized/main.tw
+++ b/src/uncategorized/main.tw
@@ -21,12 +21,11 @@
 <</if>>
 
 <<if $seeArcology == 1>>
-	<<includeDOM App.Desc.playerArcology(App.UI.DOM.combineNodes("| ", App.UI.DOM.passageLink("Hide", "Main", () => {V.seeArcology = 0})))>>
+	<<includeDOM App.Desc.playerArcology(App.UI.DOM.passageLink("Hide", "Main", () => {V.seeArcology = 0}))>>
 <</if>>
 
 <<if $seeDesk == 1>>
-	<<include "Office Description">>
-	[[Hide|Main][$seeDesk = 0]]
+	<<includeDOM App.Desc.officeDescription(App.UI.DOM.passageLink("Hide", "Main", () => {V.seeDesk = 0}))>>
 <</if>>
 
 <<includeDOM App.MainView.full()>>
diff --git a/src/uncategorized/managePenthouse.tw b/src/uncategorized/managePenthouse.tw
index 09ad829c0b4ab571d01e30260e3779954c7907f1..34163138a6feb591ba32f7e89e4aeb2102fea304 100644
--- a/src/uncategorized/managePenthouse.tw
+++ b/src/uncategorized/managePenthouse.tw
@@ -10,10 +10,7 @@
 
 <p>
 	<div class="scene-intro">
-	<<include "Office Description">>
-	<<if $PC.career == "mercenary">>
-		You look back at the rifle. It could never hold a zero, and would fail to feed if it wasn't given just the right amount of lubricant. But sometimes, you'd give anything for one more mission with that shitty old rifle.
-	<</if>>
+		<<includeDOM App.Desc.officeDescription($PC.career == "mercenary" ? "You look back at the rifle. It could never hold a zero, and would fail to feed if it wasn't given just the right amount of lubricant. But sometimes, you'd give anything for one more mission with that shitty old rifle." :"")>>
 	</div>
 
 	<div>
diff --git a/src/uncategorized/officeDescription.tw b/src/uncategorized/officeDescription.tw
deleted file mode 100644
index 9f5dd957d7bc8723bd29cc7ca79050aeb9872b8f..0000000000000000000000000000000000000000
--- a/src/uncategorized/officeDescription.tw
+++ /dev/null
@@ -1,201 +0,0 @@
-:: Office Description [nobr]
-
-&nbsp;&nbsp;&nbsp;&nbsp;You are at your desk in your penthouse office. It has a glass top interface from which you can rule over $arcologies[0].name; $assistant.name's avatar is visible in one corner.
-<<= PersonalAssistantAppearance()>>
-<<setAssistantPronouns>>
-
-<<if $clubAdsSpending >= 5000>>
-	A corner of your desk is piled with sample merchandise from the campaign promoting your club.
-	<<set _eventSlaves = $slaves.filter(function(s) { return s.assignment == "serve in the club"; })>>
-	<<if _eventSlaves.length > 0>>
-		<<set _modeledSlave = _eventSlaves.random()>>
-		<<run App.Utils.setLocalPronouns(_modeledSlave)>>
-		<<if random(1,2) == 1 || !canStand(_modeledSlave)>>
-			This includes a sex toy based on _modeledSlave.slaveName's
-			<<if (random(1,3) == 1) && (_modeledSlave.skill.vaginal >= 100)>>
-				<<if _modeledSlave.vagina > 3>>massive vagina<<elseif _modeledSlave.vagina > 2>>gaping cunt<<elseif _modeledSlave.vagina > 1>>hot cunt<<elseif _modeledSlave.vagina > 0>>tight pussy<<else>>virgin pussy<</if>>.
-			<<elseif (random(1,2) == 1) && (_modeledSlave.skill.oral >= 100)>>
-				<<if _modeledSlave.lips > 40>>huge<<elseif _modeledSlave.lips > 20>>pillowlike<<elseif _modeledSlave.lips > 10>>pretty<<else>>thin<</if>> lips and throat.
-			<<else>>
-				<<if _modeledSlave.anus > 3>>blown-out butthole<<elseif _modeledSlave.anus > 2>>roomy anus<<elseif _modeledSlave.anus > 1>>big butthole<<elseif _modeledSlave.anus > 0>>tight asshole<<else>>virgin backdoor<</if>>.
-			<</if>>
-		<<else>>
-			There is a figurine of _modeledSlave.slaveName; $he's depicted
-			<<if (random(1,3) == 1) && (_modeledSlave.skill.vaginal >= 100)>>
-				lying nude on $his back, spreading $his legs to <<if _modeledSlave.vagina > 3>>exhibit $his massive vagina<<elseif _modeledSlave.vagina > 2>>show off $his gaping cunt<<elseif _modeledSlave.vagina > 1>>offer $his hot cunt<<elseif _modeledSlave.vagina > 0>>display $his tight pussy<<else>>tantalize with $his virgin pussy<</if>>.
-			<<elseif (random(1,2) == 1) && (_modeledSlave.skill.oral >= 100)>>
-				with $his <<if _modeledSlave.lips > 40>>huge<<elseif _modeledSlave.lips > 20>>pillowlike<<elseif _modeledSlave.lips > 10>>pretty<<else>>thin<</if>> lips parted, $his tongue partway out.
-			<<else>>
-				bending at the waist and spreading $his <<if _modeledSlave.butt > 6>>gigantic buttocks<<elseif _modeledSlave.butt > 4>>meaty asscheeks<<elseif _modeledSlave.butt > 2>>healthy buttocks<<else>>cute butt<</if>> to show off $his <<if _modeledSlave.anus > 3>>blown-out butthole<<elseif _modeledSlave.anus > 2>>roomy butthole<<elseif _modeledSlave.anus > 1>>big butthole<<elseif _modeledSlave.anus > 0>>tight asshole<<else>>virgin backdoor<</if>>.
-			<</if>>
-		<</if>>
-	<</if>>
-<</if>>
-<<if $brothelAdsSpending >= 5000>>
-	<<if $clubAdsSpending >= 5000>>
-		There's just as much from the similar campaign advertising $brothelName.
-	<<else>>
-		A corner of your desk is piled with sample merchandise from the campaign promoting $brothelName.
-	<</if>>
-	<<set _eventSlaves = $slaves.filter(function(s) { return s.assignment == "work in the brothel"; })>>
-	<<if _eventSlaves.length > 0>>
-		<<set _modeledSlave = _eventSlaves.random()>>
-		<<run App.Utils.setLocalPronouns(_modeledSlave)>>
-		<<if random(1,2) == 1 || !canStand(_modeledSlave)>>
-			This includes a sex toy based on _modeledSlave.slaveName's
-			<<if (random(1,3) == 1) && (_modeledSlave.skill.vaginal >= 100)>>
-				<<if _modeledSlave.vagina > 3>>massive vagina<<elseif _modeledSlave.vagina > 2>>gaping cunt<<elseif _modeledSlave.vagina > 1>>hot cunt<<elseif _modeledSlave.vagina > 0>>tight pussy<<else>>virgin pussy<</if>>.
-			<<elseif (random(1,2) == 1) && (_modeledSlave.skill.oral >= 100)>>
-				<<if _modeledSlave.lips > 40>>huge<<elseif _modeledSlave.lips > 20>>pillowlike<<elseif _modeledSlave.lips > 10>>pretty<<else>>thin<</if>> lips and throat.
-			<<else>>
-				<<if _modeledSlave.anus > 3>>blown-out butthole<<elseif _modeledSlave.anus > 2>>roomy butthole<<elseif _modeledSlave.anus > 1>>big butthole<<elseif _modeledSlave.anus > 0>>tight asshole<<else>>virgin backdoor<</if>>.
-			<</if>>
-		<<else>>
-			This includes paired figurines of _modeledSlave.slaveName with a faceless male figure;
-			<<if (random(1,3) == 1) && (_modeledSlave.skill.vaginal >= 100)>>
-				$he's shamelessly riding his dick.
-			<<elseif (random(1,2) == 1) && (_modeledSlave.skill.oral >= 100)>>
-				$he's on $his <<if hasAnyLegs(_modeledSlave)>>$his knee<<if hasBothLegs(_modeledSlave)>>s<</if>><<else>>the ground<</if>> with $his <<if _modeledSlave.lips > 40>>huge<<elseif _modeledSlave.lips > 20>>pillowlike<<elseif _modeledSlave.lips > 10>>pretty<<else>>thin<</if>> lips wrapped around his dick.
-			<<else>>
-				$he's shown <<if _modeledSlave.anus > 3>>looking up teasingly as $he takes his dick up $his blown-out butthole<<elseif _modeledSlave.anus > 2>>looking up teasingly as $he takes his dick up $his roomy anus<<elseif _modeledSlave.anus > 1>>looking up teasingly as $he takes his dick in $his big butthole<<elseif _modeledSlave.anus > 0>>gasping as $he takes his dick in $his tight asshole<<else>>screaming as he fucks $his virgin backdoor<</if>>.
-			<</if>>
-		<</if>>
-	<</if>>
-<</if>>
-<br>&nbsp;&nbsp;&nbsp;&nbsp;Next to your desk is a sturdy black leather couch. All the walls on this floor are glass, so you can see your <<if $slaves.length > 50>>innumerable<<elseif $slaves.length > 20>>many<<elseif $slaves.length > 10>>numerous<<elseif $slaves.length > 5>>handful of<<else>>few<</if>> slaves going about their business. The room is designed so that everyone must walk past the door to your office to get anywhere.
-<<if $personalArms > 0>>
-	Your custom armor rests in the corner of the room where visitors can admire it, and you can don it quickly if necessary.
-	<<if ($week > (43-$nationHate)) && ($mercenaries >= 5)>>
-		Its plates bear scarring won in victorious battle, and from its back rises a banner depicting you at the head of your $mercenariesTitle.
-	<<elseif $week > (43-$nationHate)>>
-		Its plates bear scarring fairly won.
-	<</if>>
-	<<if $assistant.personality > 0>>
-		The last time _heA had it maintained, $assistant.name added
-		<<switch $assistant.appearance>>
-		<<case "monstergirl">>
-			a pinup of _himselfA to its plating: _heA's depicted with _hisA fangs bared, each strand of _hisA tentacle hair holding a lightning bolt, and both of _hisA cocks ejaculating fire.
-		<<case "shemale">>
-			a pinup of _himselfA to its plating: _heA's depicted straddling a battle rifle so closely that it looks like _heA's intimately entangled in the action.
-		<<case "amazon">>
-			a pinup of _himselfA to its plating: _heA's depicted in a classic nude bodybuilder's pose, but with a cutely coquettish expression.
-		<<case "businesswoman">>
-			a pinup of _himselfA to its plating: _heA's depicted wearing underwear, for once, and looking very severe as _heA straddles a cruise missile in a classic bombshell pose.
-		<<case "fairy">>
-			a pinup of _himselfA to its plating: _heA's depicted naked as usual, standing on top of a large bullet and making finger guns with a grin on _hisA face.
-		<<case "pregnant fairy">>
-			a pinup of _himselfA to its plating: _heA's depicted naked as usual, straddling a large bullet and making peace signs with _hisA tongue sticking out.
-		<<case "goddess">>
-			a pinup of _himselfA to its plating: _heA's depicted demurely but barely covering _hisA radiant body with a flowing ribbon, like a goddess about to burst with triplets.
-		<<case "hypergoddess">>
-			a pinup of _himselfA to its plating: _heA's depicted barely covering _hisA hugely pregnant, radiant body with a flowing ribbon, like a goddess about to burst open from _hisA hundreds of children.
-		<<case "loli">>
-			a pinup of _himselfA to its plating: _heA's cutely hugging a rifle to _hisA flat chest.
-		<<case "preggololi">>
-			a pinup of _himselfA to its plating: _heA's flashing _hisA lewd preggo _loliA pussy.
-		<<case "angel">>
-			a pinup of _himselfA to its plating: _heA's depicted wielding a flaming sword and golden shield.
-		<<case "cherub">>
-			a pinup of _himselfA to its plating: _heA's depicted hugging a bow to _hisA chest.
-		<<case "incubus">>
-			a pinup of _himselfA to its plating: _heA's depicted mid-orgasm, a bullet rocketing from _hisA dick amidst a blast of cum.
-		<<case "succubus">>
-			a pinup of _himselfA to its plating:
-			<<switch $assistant.fsAppearance>>
-			<<case "paternalist">>
-				_heA's depicted hiking _hisA skirt to flash _hisA crotch.
-			<<case "degradationist">>
-				_heA's depicted striking a pose showing off _hisA countless piercings.
-			<<case "roman revivalist">>
-				_heA's depicted in a stola, flashing _hisA tits.
-			<<case "neoimperialist">>
-				_heA's depicted in a tight Imperial bodysuit that shows off every curve.
-			<<case "egyptian revivalist">>
-				_heA's depicted groping _hisA perfect bronze breasts while blowing a kiss.
-			<<case "edo revivalist">>
-				_heA's depicted in a kimono, pulled open to flash _hisA lovely breasts.
-			<<case "arabian revivalist">>
-				_heA's depicted wearing fine silks and striking a sexy pose, though they fail to cover anything on _himA.
-			<<case "chinese revivalist">>
-				_heA's depicted wearing colorful silk robes; _heA's pulled them open to flash _hisA lovely body.
-			<<case "supremacist">>
-				_heA's depicted wearing the dress of an old world $arcologies[0].FSSupremacistRace noble<<= _womanA>> and blowing a kiss in a sexy manner.
-			<<case "subjugationist">>
-				_heA's depicted sitting with _hisA legs wide open and using _hisA fingers to spread _hisA $arcologies[0].FSSubjugationistRace pussy lips apart in a lewd manner.
-			<<case "chattel religionist">>
-				_heA's depicted striking a sexy pose, chosen specifically to draw attention to the symbols of your religion that adorn _hisA nipples.
-			<<case "repopulation focus">>
-				_heA's depicted striking a sexy pose made to draw the eye to _hisA pregnant belly.
-			<<case "eugenics">>
-				_heA's depicted striking a sexy pose; _heA's so stunning you can't look away.
-			<<case "physical idealist">>
-				_heA's depicted flexing _hisA tremendous<<if $arcologies[0].FSPhysicalIdealistStrongFat == 1>>, fat-veiled<</if>> musculature intimidatingly.
-			<<case "hedonistic decadence">>
-				_heA's depicted deep throating a banana while groping _hisA large, soft belly.
-			<<case "gender radicalist">>
-				_heA's depicted facing away from you, looking over _hisA shoulder suggestively and presenting
-				<<if $arcologies[0].FSGenderRadicalistLawFuta == 1>>
-					_hisA rear. A pair of balls hangs beneath _hisA tight pussy.
-				<<elseif $arcologies[0].FSGenderRadicalistLawFuta == 2>>
-					_hisA anus. A pair of heavy balls hangs from _hisA crotch.
-				<<elseif $arcologies[0].FSGenderRadicalistLawFuta == 3>>
-					_hisA gigantic ass.
-				<<elseif $arcologies[0].FSGenderRadicalistLawFuta == 4>>
-					_hisA anus. A tiny pair of balls hangs from _hisA crotch.
-				<<else>>
-					_hisA rear.
-				<</if>>
-			<<case "gender fundamentalist">>
-				_heA's depicted with one hand on _hisA supple breast and the other tracing the curve of _hisA child-bearing hips.
-			<<case "asset expansionist">>
-				_heA's depicted cradling _hisA own pair of ballistics; _hisA gigantic breasts are painted like atom bombs.
-			<<case "transformation fetishist">>
-				_heA's depicted striking a pose with one arm supporting _hisA enormous implants.
-			<<case "pastoralist">>
-				_heA's depicted striking a sexy pose, hands trying to relieve the pressure of _hisA quartet of milk filled breasts.
-			<<case "maturity preferentialist">>
-				_heA's depicted in a pose not unlike something you'd see on a 60's pinup calendar.
-			<<case "youth preferentialist">>
-				_heA's depicted in a pose fresh out of a popular idol's newest video.
-			<<case "slimness enthusiast">>
-				_heA's depicted striking a sexy pose while running _hisA hands across _hisA
-				<<if $arcologies[0].FSSlimnessEnthusiastLaw == 1>>
-					flat chest.
-				<<else>>
-					slim assets.
-				<</if>>
-			<<case "body purist">>
-				_heA's depicted striking a sexy pose that shows off every flawless <<if $showInches == 2>>inch<<else>>centimeter<</if>> of _hisA body.
-			<<case "intellectual dependency">>
-				_heA's depicted riding a missile, both literally and sexually.
-			<<case "slave professionalism">>
-				_heA's depicted getting hands-on with cruise missile, priming it to go off.
-			<<case "petite admiration">>
-				_heA's depicted striking a pose with a rifle as large as _heA is.
-			<<case "statuesque glorification">>
-				_heA's depicted striking a sexy pose. _HeA made sure to utilize the armor's entire height.
-			<<default>>
-				_heA's posing like a classic centerfold _girlA.
-			<</switch>>
-		<<case "imp">>
-			a pinup of _himselfA to its plating: _heA's depicted straddling a trident; pussy juices running down its shaft.
-		<<case "witch">>
-			a pinup of _himselfA to its plating: _heA's depicted straddling a broom, winking.
-		<<case "ERROR_1606_APPEARANCE_FILE_CORRUPT">>
-			a pinup of _himselfA to its plating: you have no idea what to make of it. Whatever it is, it is devouring your enemies on one end and popping out proper slaves from the other.
-		<<case "schoolgirl">>
-			a pinup of _himselfA to its plating: _heA's depicted up on tiptoe, back turned, with _hisA school<<= _girlA>> skirt riding up to bare _hisA bottom.
-		<<default>>
-			_hisA own symbol to its insignia.
-		<</switch>>
-	<</if>>
-<</if>>
-<br>&nbsp;&nbsp;&nbsp;&nbsp;<<= printTrinkets()>>
-
-A small mirror resides on your desk, facing you.
-A $PC.visualAge year old, $PC.faceShape<<if $PC.markings == "freckles">>, freckled<<elseif $PC.markings == "heavily freckled">>, densely freckled<</if>> face stares back at you.
-<<if ($playerAging != 0) && $PC.birthWeek == 51>>You'll be turning <<print $PC.actualAge+1>> next week.<</if>>
-<<= App.Desc.Player.boobs()>>
-<<= App.Desc.Player.belly()>>
-<<= App.Desc.Player.crotch()>>
-<<= App.Desc.Player.butt()>>