code:
body {
	overflow-x: hidden;
}

/* makes HR colorflip compatible */
hr {
	background:#ccc;
	border:0;
}

/* clears SugarCube's default transition */
.passage {
	transition: none;
	-webkit-transition: none;
}

.passage-in {
	opacity: 1 !important;
}

/* default is 54em */
#passages {
	max-width: 100%;
}

/* small trick to hide broken images */
img {
	text-indent: -10000px;
}

.imageColumn { /* TODO: this is mostly a copy of imageRef to get its flex features working properly. They can probably be removed from imageRef at some point */
	display: flex;
	flex-direction: column;
	flex-wrap: wrap;
	align-items: flex-start;
	position: relative;
	float: right;
}

.imageRef {
	display: flex;
	flex-direction: column;
	flex-wrap: wrap;
	align-items: flex-start;
	position: relative;
	background-color: rgba(80, 80, 80, 0.5);
	margin: 2px;
}

.tinyImg {
	height: 120px;
	width: 120px;
	float: left;
}

.smlImg {
	height: 150px;
	width: 150px;
	float: left;
}

.smlImg > img, .smlImg > video {
	height: auto;
}

.medImg {
	height: 300px;
	width: 300px;
	float: right;
}

.medImg > img, .medImg > video {
	height: auto;
}

.lrgRender {
	height: 531px;
	width: 531px;
	margin-right: -50px;
	margin-left: -50px;
	float: right;
	z-index: -1;
}

.lrgVector {
	height: 600px;
	width: 600px;
	margin-right: -125px;
	margin-left: -125px;
	float: right;
	z-index: -1;
}

.lrgRender > div.mask {
	width: 150px;
	height: 100%;
	background: linear-gradient(90deg, rgba(17,17,17,1), rgba(17,17,17,0.8) 60%, rgba(17,17,17,0));
	z-index: 1;
	/*position: absolute;*/
}

.lrgRender > img, .lrgRender > video {
	margin-left: -150px;
	height: 531px;
	width: auto;
}

.lrgVector > div.mask {
	width: 150px;
	height: 100%;
	background: linear-gradient(90deg, rgba(17,17,17,1), rgba(17,17,17,0.8) 60%, rgba(17,17,17,0));
	z-index: 1;
}

.lrgVector > img, .lrgVector > video {
	margin-left: -150px;
	height: 600px;
	width: auto;
}

.lrgVector svg {
	width: 336px;
}

object {
	object-fit: scale-down;
	position: absolute;
	top: 0;
	left: 0;
}

img.paperdoll {
	position: absolute;
	top: 0;
	left: 0;
	margin-left: 0;
}

/* Colors are made as css classes, to allow them to be changed for a light color scheme (for example). */
/* a version is for this case: text */
.link, .link a { color: var(--link-color) } /* link color */
.aquamarine, .aquamarine a, .skill, .skill a { color: aquamarine }
.coral, .coral a, .fetish.loss, .fetish.loss a { color: coral }
.cyan, .cyan a, .hotkey { color: cyan } /* used for aphrodisiac & neighbor arcs */
.darkgoldenrod, .darkgoldenrod a, .trust.extremely-terrified, .trust.extremely-terrified a { color: darkgoldenrod }
.darkred, .darkred a, .defiant.full, .defiant.full a { color: darkred }
.darkviolet, .darkviolet a, .devotion.hateful, .devotion.hateful a { color: darkviolet }
.deeppink, .deeppink a, .devotion.devoted, .devotion.devoted a { color: deeppink } /* used for devotion once & agent */
.steelblue, .steelblue a { color: steelblue }
.deepskyblue, .deepskyblue a, .intelligent, .intelligent a { color: deepskyblue }
.dodgerblue, .dodgerblue a { color: dodgerblue }
.blue, .blue a { color: blue }
.gold, .gold a, .trust.dec, .trust.dec a, .trust.frightened, .trust.frightened a { color: gold }
.goldenrod, .goldenrod a, .trust.terrified, .trust.terrified a { color: goldenrod }
.gray, .gray a { color: gray }
.green, .green a, .reputation.inc, .reputation.inc a, .improvement, .improvement a, .flaw.break, .flaw.break a, .skill.inc, .skill.inc a, .fuckdoll, .fuckdoll a, .positive, .positive a, .health.inc, .health.inc a { color: green }
.hotpink, .hotpink a, .devotion.inc, .devotion.inc a, .devotion.accept, .devotion.accept a { color: hotpink }
.lawngreen, .lawngreen a { color: lawngreen }
.lightblue, .lightblue a { color: lightblue }
.lightcoral, .lightcoral a, .fetish.gain, .fetish.gain a { color: lightcoral } /* compare pink for fetish */
.lightgreen, .lightgreen a, .relationship, .relationship a, .rivalry.dec, .rivalry.dec a  { color: lightgreen }
.lightpink, .lightpink a { color: lightpink }
.lightsalmon, .lightsalmon a, .fetish.inc, .fetish.inc a, .rivalry.inc, .rivalry.inc a, .relationship.dec, .relationship.dec a { color: lightsalmon }
.lime, .lime a, .change.positive, .change.positive a, .virginity.loss, .virginity.loss a, .puberty, .puberty a, .pregnant, .pregnant a { color: lime } /* tight orifices, breast changes, take virginity, not sure on good aliases */
.limegreen, .limegreen a { color: limegreen } /* multiple questionable uses */
.magenta, .magenta a, .devotion.worship, .devotion.worship a { color: magenta }
.mediumaquamarine, .mediumaquamarine a, .trust.inc, .trust.inc a, .trust.careful, .trust.careful a { color: mediumaquamarine }
.mediumorchid, .mediumorchid a, .devotion.dec, .devotion.dec a, .devotion.resistant, .devotion.resistant a { color: mediumorchid }
.mediumseagreen, .mediumseagreen a, .trust.trusting, .trust.trusting a { color: mediumseagreen }
.orange, .orange a, .stupid, .stupid a, .change.negative, .change.negative a, .defiant.careful, .defiant.careful a, .ncs, .ncs a, .miscarriage, .miscarriage a, .intro.question { color: orange } /* generally between red and green, and a lot of other places */
.orangered, .orangered a, .defiant.inc, .defiant.inc a, .defiant.bold, .defiant.bold, .education.neg a { color: orangered }
.orchid, .orchid a { color: orchid } /* used once (wrong? */
.pink, .pink a, .slave.name.simple { color: pink } /* also fetish start ??? , and a lot of other stuff */
.red, .red a, .health.dec, .health.dec a, .cash.dec, .cash.dec a, .stat.drop, .stat.drop a, .flaw.gain, .flaw.gain a, .mindbreak, .mindbreak a, .error, .error a, .elites.loss, .elites.loss a, .reputation.dec, .reputation.dec a, .warning, .warning a { color: red } /* also generally bad stuff */
/* note: .error is for unexpected behavior, .warning for player feedback */
.seagreen, .seagreen a, .trust.prof-trusting, .trust.prof-trusting a { color: seagreen }
.springgreen, .springgreen a, .skill.player, .skill.player a { color: springgreen }
.tan, .tan a { color: tan } /* some ethnicity */
.chocolate, .chocolate a { color: chocolate }
.saddlebrown, .saddlebrown a { color: saddlebrown }
.teal, .teal a { color: teal }
.yellow, .yellow a, .noteworthy, .noteworthy a, .paraphilia.gain, .paraphilia.gain a, .devotion.ambivalent, .devotion.ambivalent a, .trust.fearful, .trust.fearful a { color: yellow }
.yellowgreen, .yellowgreen a, .cash.inc, .cash.inc a, .cash, .cash a { color: yellowgreen }
.white a { color: white }

/*! <<checkvars>> macro for SugarCube 2.x */
#ui-dialog-body.checkvars{padding:1em}#ui-dialog-body.checkvars h1{font-size:1em;margin-top:0}#ui-dialog-body.checkvars table{border-collapse:collapse;border-spacing:0}#ui-dialog-body.checkvars thead tr{border-bottom:2px solid #444}#ui-dialog-body.checkvars tr:not(:first-child){border-top:1px solid #444}#ui-dialog-body.checkvars td,#ui-dialog-body.checkvars th{padding:.25em 1em}#ui-dialog-body.checkvars td:first-child,#ui-dialog-body.checkvars th:first-child{padding-left:.5em;border-right:1px solid #444}#ui-dialog-body.checkvars td:last-child,#ui-dialog-body.checkvars th:last-child{padding-right:.5em}#ui-dialog-body.checkvars th:first-child{text-align:center}#ui-dialog-body.checkvars td:first-child{font-weight:700;text-align:right}#ui-dialog-body.checkvars td{font-family:monospace,monospace;vertical-align:top;white-space:pre-wrap}#ui-dialog-body.checkvars .scroll-pad{margin:0;padding:0}

div.output{
width: 100%;
width: 100vw;
max-width: 100%;
word-break: break-all;
white-space: normal;
}
/* css rules for rules assistant */
.rajs-list-item {
	display: inline-block;
	color: var(--link-color);
	margin-right: 1em;
}
.rajs-list-item.selected {
	color: gray;
	text-decoration: none;
}
.rajs-list-item:last-of-type { margin-right: 0; }
.rajs-list-item:hover {
	cursor: pointer;
	text-decoration: underline;
}
.rajs-list-item.selected:hover {
	cursor: default;
	text-decoration: none;
}
.rajs-list strong:first-of-type, .rajs-list input {
	margin-right: 2em;
}
.rajs-list-item input {
	margin: 0.25em;
}
.rajs-section h1 {
	border-bottom: 1px solid white;
	cursor: pointer;
}
.rajs-section h1:hover { text-decoration: underline; }

.scroll {
	overflow: auto;
}

h1, h2, h3 {
	margin-bottom: 0;
	margin-top: 0.25em;
}
.founding {
	font-size: 0.8em;
	margin-top: -0.8em;
	margin-left: 0.5em;
	font-style: italic;
}
table.corporate {
	border: 3px darkgreen double;
	border-collapse: collapse;
	min-width: 33%;
}
table.corporate tbody tr:nth-child(even) {
	background-color: rgb(0, 30, 0);
}
table.corporate tbody tr:nth-child(odd) {
	background-color: rgb(15, 40, 15);
}
table.corporate td {
	vertical-align: top;
}
table.corporate tbody th, table.corporate thead th {
	background-color: black;
	font-weight: bold;
}
.minor-note {
	font-size: 0.75em;
	font-style: italic;
}
.majorText {
	margin-top: 0.5em;
	margin-bottom: 1.5em;
}
.tab {
	margin-left: 2em;
}
div.slave-report {
	margin-top: 1em;
	margin-bottom: 1em;
}
div.indent, p.indent {
	text-indent: 2em;
}
div.double-indent, p.double-indent {
	text-indent: 4em;
}
div.choices, p.choices {
	margin-left: 2em;
}
div.double-choices, p.double-choices {
	margin-left: 4em;
}

/* setting at the beginning of a scene / subscene */
.scene-intro {
	font-style: italic;
}

/* adds detail to an option: Do something. Sentence that explains the effect/conditions */
.detail {
	font-style: italic;
}

/* additional information not related to a specific option */
.note {
	font-style: italic;
}

.story-label, .underline {
	text-decoration: underline;
}

/* Note: Do not do a linebreak after span in HTML, because it will underline the automatic space it inserts: "Matilda_is a cow" */
.slave-name {
	color: pink;
	font-weight: bold;
	text-decoration: underline;
	text-decoration-color: white;
}

.name {
	font-weight: bold;
}

.custom-label {
	color: yellow;
	font-weight: bold;
}

div.cheat-menu {
	font-style: italic;
	position: absolute;
	right: 50px;
}

h1 + p {
	margin-top: 0;
}
h2 + p {
	margin-top: 0;
}
h3 + p {
	margin-top: 0;
}

.main-fcnn {
	text-align: center;
	margin: 0 auto;
}

.major-link, .bold {
	font-weight: bold;
}

.clear-formatting {
	color: white;
	font-weight: normal;
	font-style: normal;
}

.major-warning {
	font-weight: bold;
	color: red;
}

div.center, p.center {
	margin-left: auto;
	margin-right: auto;
	text-align: center;
}

div.flex-container {
	display: flex;
}

/* TODO unify tooltip systems */
.hasTooltip {
	text-decoration: underline;
}

/* interactable tooltip-like container - created/destroyed dynamically */
.details-overlay {
	display: inline-block;
	font-size: smaller;
	width: max-content;
	height: max-content;
	border-style: solid;
	border-color: slategray;
	border-width: 2px;
	border-radius: 3px;
	background-color: rgb(17, 17, 17);
	padding: 3px;
	position: absolute;
	z-index: 2;
	text-indent: 0;
}

/* make cheat textboxes fit in sidebar */
#story-caption input {
	min-width: 0;
	width: calc(100% - 0.8em - 2px);
}

/* slave interact navigation */
.adjacent-slave {
	font-weight: bold;
}
.interact-name {
	margin: 0 2em;
}

.icons {
	font-family: 'tme-fa-icons';
}

.favorite, .favorite:hover {
	color: yellow;
	text-decoration: none;
}

.not-favorite, .not-favorite:hover {
	color: grey;
	text-decoration: none;
}


code:
div.options-group {
	display: grid;
	grid-template-columns: max-content auto;
	align-items: center;
}

@media only screen and (min-width: 1600px) {
	div.options-group.double {
		grid-template-columns: max-content auto max-content auto;
    }
}

/* left side */
div.options-group div.description {
	margin-right: 10px;
}

/* right side */
div.options-group div.button-group {
	margin: 6px 0;
}

div.options-group span.comment {
	color: gray;
	font-style: italic;
	margin-left: 10px;
}

div.options-group button {
	color: var(--link-color);
	background-color: var(--button-color);
	border: none; /* outline instead of border */
	/* left & right outline overlap each other so we don't have a double border */
	outline: solid 2px var(--button-border-color);
	margin-left: 2px;
}

div.options-group button:hover {
	background-color: var(--button-hover-color);
}

div.options-group button.selected {
	background-color: var(--button-selected-color);
}

div.options-group button.disabled {
	color: white;
	pointer-events: none;
	cursor: default;
}

div.options-group button.selected.on {
	background-color: #103d10;
}

div.options-group button.on:hover {
	background-color: #1b651b;
}

div.options-group button.selected.off {
	background-color: #40100d;
}

div.options-group button.off:hover {
	background-color: #6a1b16;
}

div.options-group button.selected.neutral {
	background-color: #4d4d00;
}

div.options-group button.neutral:hover {
	background-color: #666600;
}

/* input box */
div.options-group input {
	border: 2px solid var(--button-border-color);
	min-width: unset; /* remove SC styling */
	width: 140px;
}

div.options-group input.number {
	width: 50px;
}

repo_name: Welptard/fc

license: mit


code:
.ql-hidden
{
	display:none;
}

div.quick-list.devotion button.mindbroken
{
	background-color:red;
}
div.quick-list.devotion button.very-hateful
{
	background-color:darkviolet;
}
div.quick-list.devotion button.hateful
{
	background-color:darkviolet;
}
div.quick-list.devotion button.resistant
{
	background-color:mediumorchid;
}
div.quick-list.devotion button.ambivalent
{
	background-color: yellow;
	color: #444444;
}
div.quick-list.devotion button.accepting
{
	background-color: hotpink;
}
div.quick-list.devotion button.devoted
{
	background-color: deeppink;
}
div.quick-list.devotion button.worshipful
{
	background-color: magenta;
}
div.quick-list.trust button.mindbroken
{
	background-color:red;
}
div.quick-list.trust button.extremely-terrified
{
	background-color: darkgoldenrod;
}
div.quick-list.trust button.terrified
{
	background-color: goldenrod;
}
div.quick-list.trust button.frightened
{
	background-color: gold;
	color: coral;
}
div.quick-list.trust button.fearful
{
	background-color: yellow;
	color: green;
}
div.quick-list.trust button.hate-careful
{
	background-color: orange;
}
div.quick-list.trust button.careful
{
	background-color: mediumaquamarine;
	color: forestgreen;
}
div.quick-list.trust button.bold
{
	background-color: orangered;
}
div.quick-list.trust button.trusting
{
	background-color: mediumseagreen;
}
div.quick-list.trust button.defiant
{
	background-color: darkred;
}
div.quick-list.trust button.profoundly-trusting
{
	background-color: seagreen;
}
div.quick-list
{
	table-layout: fixed;
	text-align: center;
	border-collapse: separate;
	border-spacing: 2px;
	border-style: hidden;
	empty-cells: hide;
	width: 70%;
}
div.quick-list button
{
	margin-top: 15px;
	margin-right: 20px;
	white-space: nowrap;
}


code:
/* Style sheet for WardrobeUse.tw */

#passage-wardrobe-use .optionMacro {
	display: inline;
}

#passage-wardrobe-use .optionDescription {
	width: unset;
	text-align: left;
}

#passage-wardrobe-use .optionValue {
	display: flex;
}

#passage-wardrobe-use .optionMacroOption {
	flex-grow: 1;
}

/* Last line shouldn't grow */
#passage-wardrobe-use .optionValue::after {
	flex-grow: 1000000000;
	content: '';
}


code:
/**
 * Displays a value that you can click on to get some details in an overlay
 */
App.UI.DOM.InteractiveDetails = class {
	/**
	 * @param {string} linkText text to use for the show/hide link
	 * @param {function(): HTMLElement|DocumentFragment} [detailsGenerator] function which generates the contents of the details overlay (omit to disable details)
	 * @param {string[]} [linkClasses=[]] list of extra CSS classes to apply to the link
	 */
	constructor(linkText, detailsGenerator, linkClasses=[]) {
		this.span = App.UI.DOM.makeElement("span", "", "details-overlay");
		this.span.style.visibility = "hidden";
		this.link = detailsGenerator ? App.UI.DOM.link(linkText, () => this.toggle()) : App.UI.DOM.makeElement("span", linkText);
		this.link.classList.add(...linkClasses);
		this.func = detailsGenerator;
		this.shown = false;
	}

	/**
	 * Toggle the visibility of the overlay (changing the render state)
	 */
	toggle() {
		this.shown = !this.shown;
		if (this.shown) {
			$(this.span).empty().append(this.func());
			// by default, the CSS will try to show it as inline-block on the right
			this.span.style.removeProperty("right"); // reset style in case we'd moved it last time it was shown
			const overlayRect = this.span.getBoundingClientRect();
			const linkRect = this.link.getBoundingClientRect();
			if (overlayRect.right > window.innerWidth) {
				if (overlayRect.width < linkRect.left) {
					// if it won't fit in the default position, but it *will* fit on the left, force it to move over to the left side of the link
					this.span.style.right = "100%";
				}
				// if it won't fit on either side, give up and leave it where it is.  TODO: maybe do something smarter?
			}
			this.span.style.visibility = "visible";
		} else {
			$(this.span).empty();
			this.span.style.visibility = "hidden";
		}
	}

	/**
	 * Render the object to the page
	 * @returns {HTMLSpanElement}
	 */
	render() {
		const containingSpan = document.createElement("span");
		containingSpan.style.position = "relative"; // required for absolute positioning to work correctly later
		containingSpan.append(this.link, this.span);
		return containingSpan;
	}
};


code:
:: Alpha disclaimer [nobr]

Warning

	This is a text-based game that includes descriptions of sexual activity, graphic violence, drug use, and other subjects not suitable for persons under the age of 18. This is a work of fiction; any resemblance to actual persons, places, or events is unintended.

Welcome!

	An in-game encyclopedia is available from the sidebar, with answers to most basic gameplay questions.

		Important info for new players, and a reminder for FC veterans:

	when the player is offered a set of choices, the

		Continue

	button at the top of the left sidebar will almost always remain available. Using this to decline all the options presented is not cheating. If it's available, it's supposed to be available. It represents the player character politely bowing out of the situation.

Please note

		This is an alpha.

	That means the game is missing content, is full of bugs, is imbalanced, and is generally in an incomplete state. The game will keep a start of turn autosave. If you encounter a bug, we strongly recommend you reload your start of turn autosave immediately. Please submit your feedback and bug reports at https://gitgud.io/pregmodfan/fc-pregmod/issues/. Consider attaching a save file and screenshot of the problem.

	 	Pregmod is a modification of the original Free Cities created by FCdev, which can be seen at https://freecitiesblog.blogspot.com/.

		version: $ver, mod version: $pmodVer, build: $releaseID<<if App.Version.commitHash>>, commit: <<= App.Version.commitHash>><</if>>

		<<link "More version info">>
			<<replace "#version">>

						Mod: expanded age ranges and other tweaks 2016-08-30

						+SV

						Mod: extra preg content and other crap

					Saves from versions prior to 0.6 are not compatible.

			<</replace>>
		<</link>>

	[[I am 18 or more years of age, I understand, and I wish to continue|Economy Intro]]


code:
App.UI.MultipleInspect = (function() {
	/**
	 * Provide a mechanism to inspect multiple slaves at once (for example, for Household Liquidators and recETS).
	 * Intended for use from DOM passages.
	 * @param {Array<App.Entity.SlaveState>} slaves
	 * @param {boolean} showFamilyTree
	 * @param {string} [market]
	 * @returns {DocumentFragment}
	 */
	function MultipleInspectDOM(slaves, showFamilyTree, market) {
		const frag = document.createDocumentFragment();
		const tabBar = App.UI.DOM.appendNewElement("div", frag, "", "tab-bar");

		for (const slave of slaves) {
			tabBar.append(App.UI.tabBar.tabButton(`slave${slave.ID}`, slave.slaveName));
			frag.append(App.UI.tabBar.makeTab(`slave${slave.ID}`, App.Desc.longSlave(slave, {market: market})));
		}

		if (slaves.length > 1 && showFamilyTree) {
			const button = App.UI.tabBar.tabButton(`familyTreeTab`, "Family Tree");
			button.addEventListener('click', event => {
				renderFamilyTree(slaves, slaves[0].ID);
			});
			tabBar.append(button);
			const ftTarget = document.createElement("div");
			ftTarget.setAttribute("id", "family-tree");
			frag.append(App.UI.tabBar.makeTab(`familyTreeTab`, ftTarget));
		}

		App.UI.tabBar.handlePreSelectedTab(`slave${slaves[0].ID}`);

		return frag;
	}

	return MultipleInspectDOM;
})();


code:
:: Description Options [nobr jump-to-safe jump-from-safe]

<<set $nextButton = "Back">>
<<if $storedLink !== "Slave Interact">>
	<<if lastVisited("Slave Interact") === 1>>
		<<set $storedLink = "Slave Interact">>
	<<else>>
		<<set $storedLink = "Options">>
	<</if>>
<</if>>
<<set $nextLink = $storedLink>>

Description Options

//These options will affect both the long form description of each slave and the miniscenes available from the main menu.//

<<set _options = new App.UI.OptionsGroup()>>

<<run _options.addOption("", "surnameOrder")
.addValue("Allow nationality name order", 0).customDescription("Order names ''based on country of origin''.")
.addValue("Force name surname", 1).customDescription("Names will always be ''Name Surname''.")
.addValue("Force surname name", 2).customDescription("Names will always be ''Surname Name''.")>>

<<run _options.addOption("", "seeRace")
.addValue("Disable most mentions of race", 0).off().customDescription("Ethnicity will ''almost never'' be mentioned.")
.addValue("Enable mentions of race", 1).on().customDescription("Ethnicity will ''occasionally'' be mentioned.")>>

<<run _options.addOption("", "seeNationality")
.addValue("Disable most mentions of nationality", 0).off().customDescription("Nationality will ''almost never'' be mentioned.")
.addValue("Enable mentions of nationality", 1).on().customDescription("Nationality will ''occasionally'' be mentioned.")>>

<<run _options.addOption("The effects of implants are", "showImplantEffects")
.addValue("Shown", 1).on().addValue("Hidden", 0).off()>>

<<run _options.addOption("Clothing is mostly", "showClothing")
.addValue("Shown", 1).on().addValue("Hidden", 0).off()>>

<<run _options.addOption("Detailed slave age information is", "showAgeDetail")
.addValue("Shown", 1).on().addValue("Hidden", 0).off()>>

<<run _options.addOption("Approximate height is", "showHeightCMs")
.addValue("Shown", 1).on().addValue("Hidden", 0).off()>>

<<run _options.addOption("Cosmetic body mods are", "showBodyMods")
.addValue("Shown", 1).on().addValue("Hidden", 0).off()>>

<<run _options.addOption("Sexual histories are", "showSexualHistory")
.addValue("Shown", 1).on().addValue("Hidden", 0).off()>>

<<run _options.addOption("Attractiveness and Sexual scores are", "showScores")
.addValue("Shown", 1).on().addValue("Hidden", 0).off()>>

<<run _options.addOption("Volume, in CCs, of breasts is", "showBoobCCs")
.addValue("Shown", 1).on().addValue("Hidden", 0).off()>>

<<run _options.addOption("Height and length units are in", "showInches")
.addValueList([["Metric", 0], ["Both", 1], ["Imperial", 2]])>>

<<if $seeDicks > 0>>

	<<run _options.addOption("Approximate sizes of dicks and balls are", "showDickCMs")
	.addValue("Shown", 1).on().addValue("Hidden", 0).off()>>
<</if>>

<<run _options.addOption("Numbers are displayed as", "showNumbers")
.addValueList([["Integers", 2], ["Both", 1], ["Words", 0]])>>

<<if $showNumbers === 1>>
	<<run _options.addOption("Only numbers up to $showNumbersMax are displayed as words", "showNumbersMax")
	.addValue("Default (20)", 20).showTextBox()>>
<</if>>

<<includeDOM _options.render()>>


code:
div.hotkey-settings {
    display: grid;
    grid-template-columns: repeat(3, max-content) auto;
}

@media only screen and (min-width: 1600px) {
    div.hotkey-settings {
        grid-template-columns: repeat(3, max-content) auto repeat(3, max-content) auto;
    }
}

div.hotkey-settings div.description {
    margin-right: 10px;
    /* center text vertically */
    display: flex;
    justify-content: center;
    flex-direction: column;
}

div.hotkey-settings button {
    margin: 5px;
    border-width: 2px;
    background-color: var(--button-color);
    border-color: var(--button-border-color);
    width: 70px;
}

div.hotkey-settings button.combination {
    min-width: 150px;
    border-width: 0;
}

div.hotkey-settings button.inactive, div.hotkey-settings button.inactive:hover {
    background-color: var(--button-selected-color);
    cursor: default;

}

div.hotkey-settings button:hover {
    background-color: var(--button-hover-color);
    border-color: var(--button-border-color);
}


code:
:: Hotkey Settings [nobr jump-to-safe jump-from-safe]

<<set $nextButton = "Back", $nextLink = "Main">>

Hotkey Settings

            On keyboard layouts other than the US-QWERTY layout  there may be keys or combinations of keys where the recorded key is
            different from the key used to listen to key events. You will have to find these keys yourself through trial
            and error.

            Custom hotkeys are browser specific and are not part of your save.

            While we try not to overwrite browser or OS level key combinations it is possible to do so with custom
            hotkeys. This also means that during recording of custom hotkeys no browser or OS level key combinations are
            available. There are however keys that cannot be overwritten, the Win key on Windows is an
            example for this.

<<includeDOM App.UI.Hotkeys.settings()>>


code:
App.UI.OptionsGroup = (function() {
	/**
	 * @typedef value
	 * @property {*} value
	 * @property {string} [name]
	 * @property {string} mode
	 * @property {number} [compareValue]
	 * @property {string} [descAppend] can be SC markup
	 * @property {boolean} [on]
	 * @property {boolean} [off]
	 * @property {boolean} [neutral]
	 * @property {Function} [callback]
	 */

	const Option = class {
		/**
		 * @param {string} description can be SC markup
		 * @param {string} property
		 * @param {object} [object=V]
		 */
		constructor(description, property, object = V) {
			this.description = description;
			this.property = property;
			this.object = object;
			/**
			 * @type {Array<value>}
			 */
			this.valuePairs = [];
		}

		/**
		 * @param {*} name
		 * @param {*} [value=name]
		 * @param {Function} [callback]
		 * @returns {Option}
		 */
		addValue(name, value = name, callback = undefined) {
			this.valuePairs.push({
				name: name, value: value, mode: "=", callback: callback
			});
			return this;
		}

		/**
		 * @param {Array<*|Array>} values
		 * @returns {Option}
		 */
		addValueList(values) {
			for (const value of values) {
				if (Array.isArray(value)) {
					this.addValue(value[0], value[1]);
				} else {
					this.addValue(value);
				}
			}
			return this;
		}

		/**
		 * @param {*} value
		 * @param {number} compareValue
		 * @param {string} mode on of: "<", "<=", ">", ">="
		 * @param {string} [name=value]
		 */
		addRange(value, compareValue, mode, name = value) {
			this.valuePairs.push({
				name: name, value: value, mode: mode, compareValue: compareValue
			});
			return this;
		}

		/**
		 * @param {string} [unit]
		 * @returns {Option}
		 */
		showTextBox(unit) {
			this.textbox = true;
			if (unit) {
				this.unit = unit;
			}
			return this;
		}

		/**
		 * @param {string} comment can be SC markup
		 * @returns {Option}
		 */
		addComment(comment) {
			this.comment = comment;
			return this;
		}

		/**
		 * Adds a button that executes the callback when clicked AND reloads the passage
		 *
		 * @param {string} name
		 * @param {Function} callback
		 * @param {string} passage
		 */
		customButton(name, callback, passage) {
			this.valuePairs.push({
				name: name, value: passage, callback: callback, mode: "custom"
			});
			return this;
		}

		/**
		 * @param {string} element can be SC markup
		 * @returns {Option}
		 */
		addCustomElement(element) {
			this.valuePairs.push({
				value: element, mode: "plain"
			});
			return this;
		}

		/* modify last added option */

		/**
		 * Added to the description if last added value is selected.
		 * example use: addValue(...).customDescription(...).addValue(...).customDescription(...)
		 * @param {string} description can be SC markup
		 */
		customDescription(description) {
			this.valuePairs.last().descAppend = description;
			return this;
		}

		/**
		 * @param {Function} callback gets executed on every button click. Selected value is given as argument.
		 */
		addCallback(callback) {
			this.valuePairs.last().callback = callback;
			return this;
		}

		/**
		 * Mark option as on to style differently.
		 * @returns {Option}
		 */
		on() {
			this.valuePairs.last().on = true;
			return this;
		}

		/**
		 * Mark option as off to style differently.
		 * @returns {Option}
		 */
		off() {
			this.valuePairs.last().off = true;
			return this;
		}

		/**
		 * Mark option as neutral to style differently.
		 * @returns {Option}
		 */
		neutral() {
			this.valuePairs.last().neutral = true;
			return this;
		}
	};

	return class {
		constructor() {
			/**
			 * @type {Array<Option>}
			 */
			this.options = [];
		}

		/**
		 * @returns {App.UI.OptionsGroup}
		 */
		enableDoubleColumn() {
			this.doubleColumn = true;
			return this;
		}

		addOption(name, property, object = V) {
			const option = new Option(name, property, object);
			this.options.push(option);
			return option;
		}

		render() {
			const container = document.createElement("div");
			container.className = "options-group";
			if (this.doubleColumn) {
				container.classList.add("double");
			}
			for (/** @type {Option} */ const option of this.options) {
				/* left side */
				const desc = document.createElement("div");
				desc.className = "description";
				$(desc).wiki(option.description);
				container.append(desc);

				/* right side */
				const currentValue = option.object[option.property];
				let anySelected = false;

				const buttonGroup = document.createElement("div");
				buttonGroup.classList.add("button-group");
				for (const value of option.valuePairs) {
					if (value.mode === "plain") {
						/* insert custom SC markup and go to next element */
						$(buttonGroup).wiki(value.value);
						continue;
					}
					const button = document.createElement("button");
					button.append(value.name);
					if (value.on) {
						button.classList.add("on");
					} else if (value.off) {
						button.classList.add("off");
					} else if (value.neutral) {
						button.classList.add("neutral");
					}
					if (value.mode === "custom") {
						button.onclick = () => {
							value.callback();
							if (value.value) {
								Engine.play(value.value);
							} else {
								App.UI.reload();
							}
						};
					} else {
						if (value.mode === "=" && currentValue === value.value) {
							button.classList.add("selected", "disabled");
							anySelected = true;
							if (value.descAppend !== undefined) {
								desc.append(" ");
								$(desc).wiki(value.descAppend);
							}
						} else if (!anySelected && inRange(value.mode, value.compareValue, currentValue)) {
							button.classList.add("selected");
							// disable the button if clicking it won't change the variable value
							if (currentValue === value.value) {
								button.classList.add("disabled");
							}
							anySelected = true;
							if (value.descAppend !== undefined) {
								desc.append(" ");
								$(desc).wiki(value.descAppend);
							}
						}
						button.onclick = () => {
							option.object[option.property] = value.value;
							if (value.callback) {
								value.callback();
							}
							App.UI.reload();
						};
					}
					buttonGroup.append(button);
				}
				if (option.textbox) {
					const isNumber = typeof currentValue === "number";
					const textbox = App.UI.DOM.makeTextBox(currentValue, input => {
						option.object[option.property] = input;
						App.UI.reload();
					}, isNumber);
					if (isNumber) {
						textbox.classList.add("number");
					}
					buttonGroup.append(textbox);
					if (option.unit) {
						buttonGroup.append(" ", option.unit);
					}
				}
				if (option.comment) {
					const comment = document.createElement("span");
					comment.classList.add("comment");
					$(comment).wiki(option.comment);
					buttonGroup.append(comment);
				}
				container.append(buttonGroup);
			}

			return container;

			function inRange(mode, compareValue, value) {
				if (mode === "<") {
					return value < compareValue;
				} else if (mode === "<=") {
					return value <= compareValue;
				} else if (mode === ">") {
					return value > compareValue;
				} else if (mode === ">=") {
					return value >= compareValue;
				}
				return false;
			}
		}
	};
})();


code:
:: Options [nobr jump-to-safe jump-from-safe]

<<if lastVisited("Slave Interact") === 1>>
	<<set $storedLink = "Slave Interact">>
<<else>>
	<<set $storedLink = "Main">>
<</if>>

<<set $nextButton = "Back", $nextLink = $storedLink, $encyclopedia = "How to Play">>
<<set $passageSwitchHandler = App.EventHandlers.optionsChanged>>

<<set _options = new App.UI.OptionsGroup()>>
<<run _options.addOption("End of week autosaving is currently", "autosave")
.addValue("Enabled", 1).on().addValue("Disabled", 0).off()>>
<<includeDOM _options.render()>>

	This save was created using FC version $ver build $releaseID. You are currently playing version: <<= App.Version.base>>, mod version: <<= App.Version.pmod>>, build: <<= App.Version.release>><<if App.Version.commitHash>>, commit: <<= App.Version.commitHash>><</if>>

	[[Apply Backwards Compatibility Update|Backwards Compatibility]]

<<link "Reset extended family mode controllers">>
	<<run resetFamilyCounters()>>
	<<replace "#family-hint">>//@@.lightgreen;Done:@@ all family relations flushed and rebuilt.//<</replace>>
<</link>>
//Clears and rebuilds .sister and .daughter tracking.//
<<if isNaN($rep)>>

[[Reset Reputation|Options][$rep = 0]]
<</if>>
<<if isNaN($cash)>>

[[Reset Money|Options][$cash = 500]]
<</if>>
<<if $releaseID == 1057>>

[[Free male anatomy removal due to accidentally flawed updater|Options][$PC.dick = 0, $PC.balls = 0, $PC.prostate = 0, $PC.scrotum = 0, $PC.ballsImplant = 0]] //Use this if your female PC picked up a few extra parts during the conversion process.//
<</if>>

<<if ($releaseID >= 1000) || $ver.startsWith("0.9") || $ver.startsWith("0.8") || $ver.startsWith("0.7") || $ver.startsWith("0.6")>>

	''NEW GAME PLUS''

	//You can begin a new game with up to five (or more) of your current slaves, although starting resources other than these slaves will be reduced. New Game Plus @@.yellow;MAY@@ work across versions. To attempt to migrate a save across versions://

    //1) Save on this screen//

    //2) Re-open the .html in a new tab then load the above save.//

    //3) [[Activate New Game Plus.|New Game Plus][$ui = "start"]]
<<else>>
	//New Game Plus is not available because this game was not started with a compatible version.//
<</if>>

<<run App.UI.tabBar.handlePreSelectedTab($tabChoice.Options)>>

	<button class="tab-links" onclick="App.UI.tabBar.openTab(event, 'display')" id="tab display">Display</button>
	<button class="tab-links" onclick="App.UI.tabBar.openTab(event, 'content&flavor')" id="tab content&flavor">Content & flavour</button>
	<button class="tab-links" onclick="App.UI.tabBar.openTab(event, 'mods')" id="tab mods">Mods</button>
	<button class="tab-links" onclick="App.UI.tabBar.openTab(event, 'debug&cheating')" id="tab debug&cheating">Debug/cheating</button>
	<button class="tab-links" onclick="App.UI.tabBar.openTab(event, 'experimental')" id="tab experimental">Experimental</button>

Reports

		<<set _options = new App.UI.OptionsGroup()>>

		<<run _options.addOption("End week report descriptive details are", "showEWD")
		.addValue("Enabled", 1).on().addValue("Disabled", 0).off()>>

		<<run _options.addOption("End week report performance details are", "showEWM")
		.addValue("Enabled", 1).on().addValue("Disabled", 0).off()>>

		<<run _options.addOption("Master Suite report details such as slave changes are", "verboseDescriptions")
		.addValue("Enabled", 1).on().addValue("Disabled", 0).off()>>

		<<run _options.addOption("End week societal effects from slaves are", "compressSocialEffects", $UI)
		.addValue("Expanded", 0).on().addValue("Compacted", 1).off()>>

		<<run _options.addOption("Accordion on week end defaults to", "useAccordion")
		.addValue("Open", 0).on().addValue("Collapsed", 1).off()>>

		<<run _options.addOption("Economic Tabs on weekly reports are", "useTabs")
		.addValue("Enabled", 1).on().addValue("Disabled", 0).off()>>

		<<run _options.addOption("Economic detail sheets for facilities are", "showEconomicDetails")
		.addValue("Enabled", 1).on().addValue("Disabled", 0).off()>>

		<<run _options.addOption("Economic report neighbor details such as trade impacts on culture are", "showNeighborDetails")
		.addValue("Enabled", 1).on().addValue("Disabled", 0).off()>>

		<<run _options.addOption("Numeric formatting is currently", "formatNumbers")
		.addValue("Enabled", 1).on().addValue("Disabled", 0).off()
		.addComment("This will comma-format numbers in some areas.")>>

		<<includeDOM _options.render()>>

General

		<<set _options = new App.UI.OptionsGroup()>>

		<<run _options.addOption("Main menu leadership controls displayed", "positionMainLinks")
		.addValueList([["Above", 1], ["Above and below", 0], ["Below", -1]])>>

		<<run _options.addOption("New Model UI", "newModelUI")
		.addValue("Enabled", 1).on().addValue("Disabled", 0).off()>>

		<<run _options.addOption("Penthouse Facility Display", "verticalizeArcologyLinks")
		.addValueList([["Triple column", 3], ["Double Coloumn", 2], ["Single Column", 1], ["Collapsed", 0]])>>

		<<run _options.addOption("Main menu arcology description", "seeArcology")
		.addValue("Enabled", 1).on().addValue("Disabled", 0).off()>>

		<<run _options.addOption("Main menu desk description", "seeDesk")
		.addValue("Enabled", 1).on().addValue("Disabled", 0).off()>>

		<<run _options.addOption("Main menu newsfeed", "seeFCNN")
		.addValue("Enabled", 1).on().addValue("Disabled", 0).off()>>

		<<run _options.addOption("Tips from the Encyclopedia are", "showTipsFromEncy")
		.addValue("Enabled", 1).on().addValue("Disabled", 0).off()>>

		<<run _options.addOption("Help tooltips are", "tooltipsEnabled")
		.addValue("Enabled", 1).on().addValue("Disabled", 0).off()
		.addComment("This is mostly for new players. @@.exampleTooltip.noteworthy;Colored text@@ can have tooltips.")>>

		<<run _options.addOption("Main menu slave tabs are", "useSlaveSummaryTabs")
		.addValue("Enabled", 1).on().addValue("CardStyle", 2).on().addValue("Disabled", 0).off()>>

		<<run _options.addOption("The slave Quick list in-page scroll-to is", "useSlaveListInPageJSNavigation")
		.addValue("Enabled", 1).on().addValue("Disabled", 0).off()>>

		<<run _options.addOption("Condense special slaves into their own tab", "useSlaveSummaryOverviewTab")
		.addValue("Enabled", 1).on().addValue("Disabled", 0).off()>>

		<<run _options.addOption("Interactions with your fucktoys are", "fucktoyInteractionsPosition")
		.addValueList([["next to them", 1], ["at page bottom", 0]])>>

		<<run _options.addOption("Hide tabs in Slave Interact", "slaveInteractLongForm")
		.addValue("Enabled", true).on().addValue("Disabled", false).off()>>

		<<run _options.addOption("Line separations are", "lineSeparations")
		.addValue("Shown", 1).on().addValue("Hidden", 0).off()>>

		<<includeDOM _options.render()>>

			UI theme selector. Allows to select a single CSS file to be loaded. The file has to be located in the same directory as the HTML file otherwise it will simply not load at all.
			<<includeDOM App.UI.Theme.selector()>>

Sidebar

		<<set _options = new App.UI.OptionsGroup()>>

		<<run _options.addOption("Cash is", "Cash", $sideBarOptions)
		.addValue("Shown", 1).on().addValue("Hidden", 0).off()>>

		<<run _options.addOption("Upkeep is", "Upkeep", $sideBarOptions)
		.addValue("Shown", 1).on().addValue("Hidden", 0).off()>>

		<<run _options.addOption("Sex slave count is", "SexSlaveCount", $sideBarOptions)
		.addValue("Shown", 1).on().addValue("Hidden", 0).off()>>

		<<run _options.addOption("Room population is", "roomPop", $sideBarOptions)
		.addValue("Shown", 1).on().addValue("Hidden", 0).off()>>

		<<run _options.addOption("GSP is", "GSP", $sideBarOptions)
		.addValue("Shown", 1).on().addValue("Hidden", 0).off()>>

		<<run _options.addOption("Rep is", "Rep", $sideBarOptions)
		.addValue("Shown", 1).on().addValue("Hidden", 0).off()>>

		<<run _options.addOption("Confirmation before ending a week is", "confirmWeekEnd", $sideBarOptions)
		.addValue("Enabled", 1).on().addValue("Disabled", 0).off()
		.addComment("Enabling this will open a dialog box to confirm you meant to end a week.")>>

		<<if $secExpEnabled > 0>>
			<<run _options.addOption("Authority is", "Authority", $sideBarOptions)
			.addValue("Shown", 1).on().addValue("Hidden", 0).off()>>

			<<run _options.addOption("Security is", "Security", $sideBarOptions)
			.addValue("Shown", 1).on().addValue("Hidden", 0).off()>>

			<<run _options.addOption("Crime is", "Crime", $sideBarOptions)
			.addValue("Shown", 1).on().addValue("Hidden", 0).off()>>
		<</if>>

		<<includeDOM _options.render()>>

Images

		<<set _options = new App.UI.OptionsGroup()>>

		<<run _options.addOption("Images are", "seeImages")
		.addValue("Enabled", 1).on().addValue("Disabled", 0).off()>>

		<<includeDOM _options.render()>>

		<<if $seeImages > 0>>

				<<= SlaveArt(BaseSlave(), 0, 0)>>

			<<set _options = new App.UI.OptionsGroup()>>

			<<run _options.addOption("", "imageChoice")
			.addValueList([["Revamped embedded vector art", 3], ["Non-embedded vector art", 2], ["NoX/Deepmurk's vector art", 1], ["Shokushu's rendered imagepack", 0]])>>

			<<if $imageChoice === 1>>
				<<run _options.addOption("").addComment('Git compiled only, no exceptions.')>>

				<<run _options.addOption("Face artwork is", "seeFaces")
				.addValue("Enabled", 1).on().addValue("Disabled", 0).off()>>

				<<run _options.addOption("Highlights on shiny clothing are", "seeVectorArtHighlights")
				.addValue("Enabled", 1).on().addValue("Disabled", 0).off()>>

				<<run _options.addOption("Height scaling", "seeHeight")
				.addValue("All images", 2).on().addValue("Small images", 1).neutral().addValue("Disabled", 0).off()>>

				<<run _options.addOption("Clothing erection bulges are", "showClothingErection")
				.addValue("Enabled", true).on().addValue("Disabled", false).off()>>
			<<elseif $imageChoice === 0>>
				<<run _options.addOption("").addComment(`You need """to"""
					download the image pack
					"""and""" put the 'renders' folder into the resources/ folder where this html file is.`
				)>>

				<<run _options.addOption("Slave summary fetish images are", "seeMainFetishes")
				.addValue("Enabled", 1).on().addValue("Disabled", 0).off()>>
			<<elseif $imageChoice === 3>>
				<<run _options.addOption("").addComment('Git compiled only, no exceptions.')>>

				<<run _options.addOption("Clothing erection bulges are", "showClothingErection")
				.addValue("Enabled", true).on().addValue("Disabled", false).off()>>
			<</if>>

			<<run _options.addOption("PA avatar art is", "seeAvatar")
			.addValue("Enabled", 1).on().addValue("Disabled", 0).off()>>

			<<run _options.addOption("Slave images in lists are", "seeSummaryImages")
			.addValue("Enabled", 1).on().addValue("Disabled", 0).off()>>

			<<run _options.addOption("Slave images in the weekly report are", "seeReportImages")
			.addValue("Enabled", 1).on().addValue("Disabled", 0).off()>>

			<<includeDOM _options.render()>>
		<</if>>

Content

		//More granular control of what appears is in [[Description Options]].//

		<<set _options = new App.UI.OptionsGroup()>>

		<<run _options.addOption("The difficulty setting is currently set to", "baseDifficulty")
		.addValueList([["Very easy", 1], ["Easy", 2], ["Default", 3], ["Hard", 4], ["Very hard", 5]])>>

		<<run _options.addOption("Slaves falling ill is currently", "seeIllness")
		.addValue("Enabled", 1).on().addValue("Disabled", 0).off()
		.addComment("Will not affect existing ill slaves already in-game.")>>

		<<run _options.addOption("Extreme content like amputation is currently", "seeExtreme")
		.addValue("Enabled", 1).on().addValue("Disabled", 0).off()
		.addComment("Will not affect extreme surgeries already applied in-game.")>>

		<<run _options.addOption("Bestiality related content is currently", "seeBestiality")
		.addValue("Enabled", 1).on().addValue("Disabled", 0).off()>>

		<<run _options.addOption("Watersports related content is currently", "seePee")
		.addValue("Enabled", 1).on().addValue("Disabled", 0).off()>>

		<<run _options.addOption("Incest content is currently", "seeIncest")
		.addValue("Enabled", 1).on().addValue("Disabled", 0).off()>>

		<<run _options.addOption("Pregnancy related content is currently", "seePreg")
		.addValue("Enabled", 1).on().addValue("Disabled", 0).off()
		.addComment("Will not affect existing pregnancies already in-game.")>>

		<<run _options.addOption("Child gender to be generated based off dick content settings", "seeDicksAffectsPregnancy")
		.addValue("Enabled", 1).on().addValue("Disabled", 0).off()
		.addComment("<<if $seeDicksAffectsPregnancy === 1>>Currently <<print $seeDicks>>% of children will be born male. <</if>>Will not affect existing pregnancies already in-game.")>>

		<<if $seeDicksAffectsPregnancy === 0>>
			<<run _options.addOption("XX slaves only father daughters", "adamPrinciple")
			.addValue("Enabled", 1).on().addValue("Disabled", 0).off()
			.addComment("Will not affect existing pregnancies already in-game.")>>
		<</if>>

		<<run _options.addOption("Extreme pregnancy content like broodmothers is currently", "seeHyperPreg")
		.addValue("Enabled", 1).on().addValue("Disabled", 0).off()
		.addComment("Will not affect existing hyperpregnancies already in-game.")>>

		<<run _options.addOption("Pregnancy complications due to multiples and body size are currently", "dangerousPregnancy")
		.addValue("Enabled", 1).on().addValue("Disabled", 0).off()>>

		<<run _options.addOption("Precocious puberty (pregnancy younger than $fertilityAge)", "precociousPuberty")
		.addValue("Enabled", 1).on().addValue("Disabled", 0).off()
		.addComment("Will not affect existing precocious puberty cases already in-game.")>>

		<<run _options.addOption("Slaves with fat lips or heavy oral piercings may lisp", "disableLisping")
		.addValue("Yes", 0).on().addValue("No", 1).off()>>

		<<run _options.addOption("Disables the long term damage mechanic. //Temp option//", "disableLongDamage")
		.addValue("Enabled", 0).on().addValue("Disabled", 1).off()>>

		<<run _options.addOption("Experimental male pronouns are currently", "diversePronouns")
		.addValue("Enabled", 1).on().addValue("Disabled", 0).off()
		.addComment("Apply Backwards Compatibility after changing to update slave's pronouns. Not all scenes support male pronouns and this is not yet incorporated into the lore or mechanics.")>>

		<<run _options.addOption("Male slave names are currently", "allowMaleSlaveNames")
		.addValue("Enabled", true).on().addValue("Disabled", false).off()
		.addComment("This only affects slave generation and not your ability to name your slaves.")>>

		<<run _options.addOption("Missing slave names are currently", "showMissingSlaves")
		.addValue("Enabled", true).on().addValue("Disabled", false).off()>>

		<<includeDOM _options.render()>>

Intersecting mechanics

		<<set _options = new App.UI.OptionsGroup()>>

		<<run _options.addOption("Slave assets affected by weight is", "weightAffectsAssets")
		.addValue("Enabled", 1).on().addValue("Disabled", 0).off()
		.addComment("Diet will still affect asset size.")>>

		<<run _options.addOption("Curative side effects are", "curativeSideEffects")
		.addValue("Enabled", 1).on().addValue("Disabled", 0).off()
		.addComment("If enabled, curatives have a chance to give slaves harmful side effects.")>>

		<<includeDOM _options.render()>>

Flavour

		<<set _options = new App.UI.OptionsGroup()>>

		<<run _options.addOption("Slave reactions to facility assignments are", "showAssignToScenes")
		.addValue("Enabled", 1).on().addValue("Disabled", 0).off()>>

		<<run _options.addOption("Post sex clean up", "postSexCleanUp")
		.addValue("Enabled", 1).on().addValue("Disabled", 0).off()>>

		<<run _options.addOption("Appraisal miniscenes on slave sale are", "showAppraisal")
		.addValue("Enabled", 1).on().addValue("Disabled", 0).off()>>

		<<run _options.addOption("Assignment performance vignettes on the end week report are", "showVignettes")
		.addValue("Enabled", 1).on().addValue("Disabled", 0).off()>>

		<<run _options.addOption("Slaves can have alternate titles", "newDescriptions")
		.addValue("Enabled", 1).on().addValue("Disabled", 0).off()>>

		<<run _options.addOption("Family titles for relatives", "allowFamilyTitles")
		.addValue("Enabled", 1).on().addValue("Disabled", 0).off()>>

		<<run _options.addOption("Limit family growth", "limitFamilies")
		.addValue("Enabled", 1).on().addValue("Disabled", 0).off()
		.addComment("Restricts acquisition of additional relatives, by means other than birth, for slaves with families.")>>

		<<run _options.addOption("Distant relatives such as aunts, nieces and cousins are", "showDistantRelatives")
		.addValue("Enabled", 1).on().addValue("Disabled", 0).off()>>

		<<includeDOM _options.render()>>

		<<set _options = new App.UI.OptionsGroup()>>

		<<run _options.addOption("The Special Force Mod is currently", "Toggle", $SF)
		.addValue("Enabled", 1).on().addValue("Disabled", 0).off()
		.addComment("
This mod is triggered after week 72. It is non-canon where it conflicts with canonical updates to the base game.
")>>

		<<run _options.addOption("The Security Expansion mod is", "secExpEnabled")
		.addValue("Enabled", 1).on().addValue("Disabled", 0).off()
		.addComment("
The mod can be activated in any moment, but it may result in unbalanced gameplay if activated very late in the game.
")>>

		<<includeDOM _options.render()>>

		<<if $secExpEnabled > 0>>
			<<if Object.values(V.SecExp).length === 0>>
				<<include "SecExpBackwardCompatibility">>
				<<goto "Options">>
			<</if>>

Security Expansion mod options

			<<if $terrain === "oceanic">>

Oceanic arcologies are not by default subject to external attacks. You can however allow them to happen anyway. If you choose to do so please keep in mind that descriptions and mechanics are not intended for naval combat but land combat.

			<</if>>
			<<set _options = new App.UI.OptionsGroup()>>

			<<if $SecExp.settings.battle.enabled > 0 || $SecExp.settings.rebellion.enabled > 0>>
				<<run _options.addOption("Detailed battle statistics are", "showStats", $SecExp.settings)
				.addValue("Shown", 1).on().addValue("Hidden", 0).off()
				.addComment("Visibility of detailed statistics and battle turns.")>>

				<<run _options.addOption("Difficulty is", "difficulty", $SecExp.settings)
				.addValueList([["Extremely hard", 2], ["Very hard", 1.5], ["Hard", 1.25], ["Normal", 1], ["Easy", 0.75], ["Very easy", 0.5]])>>

				<<run _options.addOption("Unit descriptions are", "unitDescriptions", $SecExp.settings)
				.addValue("Abbreviated", 1).addValue("Summarized", 0)>>
			<</if>>

			<<run _options.addOption("Battles are", "enabled", $SecExp.settings.battle)
			.addValue("Enabled", 1).on().addValue("Disabled", 0).off()>>

			<<run _options.addOption("Rebellions are", "enabled", $SecExp.settings.rebellion)
			.addValue("Enabled", 1).on().addValue("Disabled", 0).off()>>

			<<if $SecExp.settings.battle.enabled > 0>>
				<<run _options.addOption("Battle frequency", "frequency", $SecExp.settings.battle)
				.addValueList([["Extremely high", 2], ["Very high", 1.5], ["High", 1.25], ["Normal", 1], ["Low", 0.75], ["Very low", 0.5]])>>
			<</if>>

			<<if $SecExp.settings.rebellion.enabled > 0>>
				<<run _options.addOption("Rebellion buildup", "speed", $SecExp.settings.rebellion)
				.addValueList([["Extremely fast", 2], ["Very fast", 1.5], ["Fast", 1.25], ["Normal", 1], ["Slow", 0.75], ["Very slow", 0.5]])>>
			<</if>>

			<<if $SecExp.settings.battle.enabled > 0>>
				<<run _options.addOption("Commanders gain a prestige rank every 10 victories", "allowSlavePrestige", $SecExp.settings.battle)
				.addValue("Yes", 1).on().addValue("No", 0).off()>>
			<</if>>

			<<if $SecExp.settings.battle.enabled > 0>>
				<<run _options.addOption("Force battles", "force", $SecExp.settings.battle)
				.addValue("Yes", 1).on().addValue("No", 0).off()>>
			<</if>>
			<<if $SecExp.settings.rebellion.enabled > 0>>
				<<run _options.addOption("Force rebellions", "force", $SecExp.settings.rebellion)
				.addValue("Yes", 1).on().addValue("No", 0).off()
				.addComment("Rebellions take precedence over Battles.")>>
			<</if>>

			<<if $SecExp.settings.battle.enabled > 0>>
				<<run _options.addOption("Late game major battles are", "enabled", $SecExp.settings.battle.major)
				.addValue("Enabled", 1).on().addValue("Disabled", 0).off()>>
			<</if>>

			<<if $SecExp.settings.battle.enabled > 0 && $SecExp.settings.battle.major.enabled > 0>>
				<<run _options.addOption("Multiplier is", "mult", $SecExp.settings.battle.major)
				.addValueList([["Extremely high", 2], ["Very high", 1.5], ["High", 1.25], ["Normal", 1], ["Low", 0.75], ["Very low", 0.5]])>>

				<<run _options.addOption("This week a major battle is", "force", $SecExp.settings.battle.major)
				.addValue("Guaranteed", 1).on().addValue("Not guaranteed", 0).off()>>
			<</if>>

			<<if $SecExp.settings.battle.enabled > 0 && $SecExp.settings.battle.major.enabled > 0>>
				<<run _options.addOption("Gameover on battle loss", "gameOver", $SecExp.settings.battle.major)
				.addValue("Yes", 1).on().addValue("No", 0).off()>>
			<</if>>

			<<if $SecExp.settings.rebellion.enabled > 0>>
				<<run _options.addOption("Gameover on rebellion loss", "gameOver", $SecExp.settings.rebellion)
				.addValue("Yes", 1).on().addValue("No", 0).off()>>
			<</if>>

			<<includeDOM _options.render()>>

			<<if $debugMode || $cheatMode || $cheatModeM>>
				''Debug/cheat''
				<<set _popCap = menialPopCap()>>

				<<link "Set loyalty high" "Options">>
					<<for _i = 0; _i < $militiaUnits.length; _i++>>
						<<set $militiaUnits[_i].loyalty = random(80,100)>>
					<</for>>

					<<for _i = 0; _i < $slaveUnits.length; _i++>>
						<<set $slaveUnits[_i].loyalty = random(80,100)>>
					<</for>>

					<<for _i = 0; _i < $mercUnits.length; _i++>>
						<<set $mercUnits[_i].loyalty = random(80,100)>>
					<</for>>
				<</link>>
				| <<link "Set loyalty average" "Options">>
					<<for _i = 0; _i < $militiaUnits.length; _i++>>
						<<set $militiaUnits[_i].loyalty = random(40,60)>>
					<</for>>

					<<for _i = 0; _i < $slaveUnits.length; _i++>>
						<<set $slaveUnits[_i].loyalty = random(40,60)>>
					<</for>>

					<<for _i = 0; _i < $mercUnits.length; _i++>>
						<<set $mercUnits[_i].loyalty = random(40,60)>>
					<</for>>
				<</link>>
				| <<link "Set loyalty low" "Options">>
					<<for _i = 0; _i < $militiaUnits.length; _i++>>
						<<set $militiaUnits[_i].loyalty = random(20)>>
					<</for>>

					<<for _i = 0; _i < $slaveUnits.length; _i++>>
						<<set $slaveUnits[_i].loyalty = random(20)>>
					<</for>>

					<<for _i = 0; _i < $mercUnits.length; _i++>>
						<<set $mercUnits[_i].loyalty = random(20)>>
					<</for>>
				<</link>>
				| <<link "Randomize loyalty" "Options">>
					<<for _i = 0; _i < $militiaUnits.length; _i++>>
						<<set $militiaUnits[_i].loyalty = random(100)>>
					<</for>>

					<<for _i = 0; _i < $slaveUnits.length; _i++>>
						<<set $slaveUnits[_i].loyalty = random(100)>>
					<</for>>

					<<for _i = 0; _i < $mercUnits.length; _i++>>
						<<set $mercUnits[_i].loyalty = random(100)>>
					<</for>>
				<</link>>

				<<link "Give Authority" "Options">>
					<<set $SecExp.core.authority = Math.clamp($SecExp.core.authority + 1000, 0, 20000)>>
				<</link>>
				| <<link "Remove Authority" "Options">>
					<<set $SecExp.core.authority = Math.clamp($SecExp.core.authority - 1000, 0, 20000)>>
				<</link>>

				<<link "Raise security" "Options">>
					<<set $SecExp.core.security = Math.clamp($SecExp.core.security + 5, 0, 100)>>
				<</link>>
				| <<link "Lower security" "Options">>
					<<set $SecExp.core.security = Math.clamp($SecExp.core.security - 5, 0, 100)>>
				<</link>>

				<<link "Raise crime" "Options">>
					<<set $SecExp.core.crimeLow = Math.clamp($SecExp.core.crimeLow + 5, 0, 100)>>
				<</link>>
				| <<link "Lower crime" "Options">>
					<<set $SecExp.core.crimeLow = Math.clamp($SecExp.core.crimeLow - 5, 0, 100)>>
				<</link>>

				<<link "Give militia manpower" "Options">>
					<<set $militiaFreeManpower += 30>>
				<</link>>
				| <<link "Remove militia manpower" "Options">>
					<<set $militiaFreeManpower = Math.max($militiaFreeManpower - 30, 0)>>
				<</link>>

				<<link "Give mercs manpower" "Options">>
					<<set $mercFreeManpower += 30>>
				<</link>>
				| <<link "Remove mercs manpower" "Options">>
					<<set $mercFreeManpower = Math.max($mercFreeManpower - 30, 0)>>
				<</link>>

			<</if>>	/* closes cheatmode check */

		<</if>> /* closes SecExp check*/

Debug

		<<set _options = new App.UI.OptionsGroup()>>

		<<run _options.addOption("DebugMode is", "debugMode")
		.addValue("Enabled", 1).on().addValue("Disabled", 0).off()
		.addComment("This will add a Display Variables and Bug Report passage to the sidebar.")>>

		<<if $debugMode > 0>>
			<<run _options.addOption("The custom function part of debug mode is", "debugModeCustomFunction")
			.addValue("Enabled", 1).on().addValue("Disabled", 0).off()>>
		<</if>>

		<<set _option =  _options.addOption("Genetics array")
		.customButton("Run test", () => Engine.play("test genetics"))>>
		<<if $cheatMode == 1>>
			<<run _option.customButton("Edit Genetics", () => Engine.play("Edit Genetics"))>>
		<<else>>
			<<run _option.addComment("Enable cheat mode to edit genetics.")>>
		<</if>>

		<<run _options.addOption("Rules Assistant").addCustomElement('<<button "Reset Rules">><<run initRules()>><<goto "Rules Assistant">><</button>>')>>

		<<run _options.addOption("Passage Profiler is", "profiler")
		.addValue("Enabled", 1).on().addValue("Disabled", 0).off()
		.addComment("Outputs performance data at the bottom of every passage.")>>

		<<includeDOM _options.render()>>

Cheating

		<<set _options = new App.UI.OptionsGroup()>>

		<<run _options.addOption("CheatMode is", "cheatMode")
		.addValue("Enabled", 1).on().addValue("Disabled", 0).off()
		.addComment("This will allow manual selection of events and unlock some options that would usually be restricted by progress.")>>

		<<if $cheatMode === 0>>
			<<includeDOM _options.render()>>
		<<else>>
			<<run _options.addOption("Sidebar Cheats are currently", "cheatModeM")
			.addValue("Shown", 1).on().addValue("Hidden", 0).off()>>

			<<run _options.addOption("Slave aging", "seeAge")
			.addValue("Enabled", 1).on().addValue("Celebrate birthdays, but don't age.", 2).neutral().addValue("Disabled", 0).off()>>

			<<includeDOM _options.render()>>

			[[Add 100000 money|Options][$cheater = 1, cashX(100000, "cheating")]] | [[Add 10000 rep|Options][$cheater = 1, repX(10000, "cheating")]] //Cheating will be flagged in your save//

			<<= SectorCounts()>>
			<<link "Raise prosperity cap" "Options">>
				<<set $AProsperityCapModified += 10>>
			<</link>>
			| <<link "Lower prosperity cap" "Options">>
				<<set $AProsperityCapModified -= 10>>
			<</link>>

			<<link "Raise prosperity" "Options">>
				<<set $arcologies[0].prosperity = Math.clamp($arcologies[0].prosperity + 10, 0, $AProsperityCap)>>
			<</link>>
			| <<link "Lower prosperity" "Options">>
				<<set $arcologies[0].prosperity = Math.clamp($arcologies[0].prosperity - 10, 0, $AProsperityCap)>>
			<</link>>

			<<link "Give menial slaves" "Options">>
				<<set $menials = Math.clamp($menials + 30, 0, _popCap.value)>>
			<</link>>
			| <<link "Remove menial slaves" "Options">>
				<<set $menials = Math.clamp($menials - 30, 0, _popCap.value)>>
			<</link>>

			/%

Thanks for making this a right pain twine

			<<link "Add citizens" "Options">> /*Will no longer work as intended due to population changes*/
				<<set $lowerClass = Math.max($lowerClass + 200, 0)>>
			<</link>>
			| <<link "Remove citizens" "Options">> /*also no longer properly functional*/
				<<set $lowerClass = Math.max($lowerClass - 200, 0)>>
			<</link>>

			<<link "Add slaves" "Options">> /*Will work to a limited degree, minimums and maximums for slaves are set through population*/
				<<set $NPCSlaves = Math.max($NPCSlaves + 200, 0)>>
			<</link>>
			| <<link "Remove slaves" "Options">> /*Will work to a limited degree*/
				<<set $NPCSlaves = Math.max($NPCSlaves - 200, 0)>>
			<</link>>
			%/
		<</if>>

		Experimental means just that: experimental. Options below are likely to be in an even more incomplete or broken state than usual. THEY MAY NOT WORK AT ALL. Make sure you back up your save before enabling any of these, and if you are that interested, consider helping to improve them.

	<<set _options = new App.UI.OptionsGroup()>>

	<<if $seePreg !== 0>>
		<<run _options.addOption("Nursery is", "nursery", $experimental)
		.addValue("Enabled", 1).on().addValue("Disabled", 0).off()
		.addComment("This will enable the experimental nursery, which allows players to interact with growing slave children. An alternative to the incubator.")>>
	<</if>>

	<<run _options.addOption("Food is", "food", $experimental)
	.addValue("Enabled", 1).on().addValue("Disabled", 0).off()
	.addComment("This will enable the experimental food supply and demand system, as well as a new farmyard building and assignments.")>>

	<<if $seeExtreme === 1 && $seeBestiality === 1>>
		<<run _options.addOption("Animal Ovaries are", "animalOvaries", $experimental)
		.addValue("Enabled", 1).on().addValue("Disabled", 0).off()
		.addComment("This will allow slaves to be impregnated by animals.")>>
	<</if>>

	<<if $seeExtreme === 1>>
		<<run _options.addOption("Dinner party", "dinnerParty", $experimental)
		.addValue("Enabled", 1).on().addValue("Disabled", 0).off()
		.addComment("This will enable a controversial but very broken event. Warning: Snuff, cannibalism.")>>
	<</if>>

	<<run _options.addOption("New event", "tempEventToggle")
		.addValue("Enabled", 1).on().addValue("Disabled", 0).off()>>

	<<includeDOM _options.render()>>


code:
:: Summary Options [nobr jump-to-safe jump-from-safe]

<<set $nextButton = "Back">>
<<if $storedLink !== "Slave Interact" && $storedLink !== "Main">>
	<<if lastVisited("Main") === 1>>
		<<set $storedLink = "Main">>
	<<else>>
		<<set $storedLink = "Options">>
	<</if>>
<</if>>
<<set $nextLink = $storedLink>>
<<set $passageSwitchHandler = App.EventHandlers.optionsChanged>>

Summary Options

	These options will affect the short slave summaries that appear on the main menu and the facility management screens.

Main menu features

<<set _options = new App.UI.OptionsGroup()>>

<<run _options.addOption("Rules Assistant visibility", "rulesAssistantMain")
.addValue("Shown", 1).on().addValue("Hidden", 0).off()>>

<<run _options.addOption("Facilities in the sidebar are", "abbreviateSidebar")
.addValueList([["Summarized", 2], ["Abbreviated", 1]])>>

<<run _options.addOption("Sorting main menu options are", "sortSlavesMain")
.addValue("Shown", 1).on().addValue("Hidden", 0).off()>>

<<if $sortSlavesMain > 0>>
	<<run _options.addOption("Sorting direction", "sortSlavesOrder")
	.addValueList([["Ascending", "ascending"], ["Descending", "descending"]])>>

	<<run _options.addOption("Slaves are sorted by", "sortSlavesBy")
	.addValueList([["Devotion", "devotion"], ["Name", "name"], ["Date purchased", "seniority"], ["Age", "actualAge"],
	["How old they look", "visualAge"], ["Age of their body", "physicalAge"], ["Assignment", "assignment"], ["Weekly Income", "weeklyIncome"]])>>
<</if>>

<<includeDOM _options.render()>>

Individual panels

Sample summary:
<<includeDOM App.UI.SlaveList.render([$slaves.random().ID], new Array(), App.UI.SlaveList.SlaveInteract.stdInteract)>>

<<set _options = (new App.UI.OptionsGroup()).enableDoubleColumn()>>

<<run _options.addOption("Panel style is", "slavePanelStyle")
.addValueList([["None", 0], ["Line Separator", 1], ["Card", 2]])>>

<<run App.UI.SlaveSummary.addOptions(_options)>>

<<run _options.addOption("Granular slave stat numbers are", "summaryStats")
.addValue("Shown", 1).on().addValue("Hidden", 0).off()>>

<<run _options.addOption("Main menu assignment shortcuts are", "displayAssignments")
.addValue("Shown", 1).on().addValue("Hidden", 0).off()>>

<<if $showMissingSlaves>>
	<<run _options.addOption("Missing slave parents are", "showMissingSlavesSD")
	.addValue("Shown", true).on().addValue("Hidden", false).off()>>
<</if>>

<<includeDOM _options.render()>>

	[[FC Dev's preferred options|Summary Options ][$seeDesk = 0, $seeFCNN = 0, $sortSlavesBy = "devotion",$sortSlavesOrder = "descending",$sortSlavesMain = 0,$rulesAssistantMain = 1, $UI.slaveSummary.abbreviation = {devotion: 1, mental: 1, rules: 1, clothes: 2, health: 1, diet: 1, drugs: 1, hormoneBalance: 1, race: 1, genitalia: 1, physicals: 1, skills: 1, nationality: 1, rulesets: 1, clothes: 0, origins: 0} ,$abbreviateSidebar = 1]]


code:
/**
 * Generate a list of links the player can safely jump to.
 *
 * Tags are:
 * jump-to-safe: Allow to jump to this passage from anywhere
 * jump-from-safe: Allow to jump from this passage to anywhere
 * hidden: Allows to jump to via history, but does not show up in the quick links menu; use together with jump-to-safe
 * no-history: Do not record history for this passage, act as if was never opened; mutually exclusive with the jump tags
 *
 * @returns {DocumentFragment}
 */
App.UI.quickMenu = (function() {
	// setup passage lists
	const jumpFrom = Story.lookup("tags", "jump-from-safe").map(passage => passage.title);
	const jumpTo = Story.lookup("tags", "jump-to-safe").map(passage => passage.title);
	const hidden = Story.lookup("tags", "jump-hidden").map(passage => passage.title);
	const noHistory = Story.lookup("tags", "no-history").map(passage => passage.title);

	// if property name is a passage name, then it's a link, otherwise only text.
	// category titles are never links to passages
	// Only two values are allowed: true or an object following the same rules
	const layout = addOtherCategory({
		Main: true,
		Manage: {
			"Manage Penthouse": true,
			"Manage Arcology": true,
			"Manage Personal Affairs": true,
			"Manage Corporation": true,
			"Personal assistant options":true,
			Firebase: true,
			propagandaHub: true,
			securityHQ: true,
			secBarracks: true,
			riotControlCenter: true,
		},
		Social: {
			"Future Society": true,
			Policies: true,
			edicts: true,
			"Universal Rules": true,
			"Neighbor Interact": true,
		},
		Facilities: {
			"Head Girl Suite": true,
			"BG Select": true,
			Brothel: true,
			Club: true,
			Arcade: true,
			Dairy: true,
			Farmyard: true,
			"Servants' Quarters": true,
			"Master Suite": true,
			Schoolroom: true,
			Spa: true,
			Nursery: true,
			Clinic: true,
			Cellblock: true,
			Incubator: true,
			Pit: true,
		},
		Locations: {
			"Gene Lab": true,
			Dispensary: true,
			"Organ Farm": true,
			"Implant Manufactory": true,
			"Prosthetic Lab": true,
			Wardrobe: true,
			"The Black Market": true,
		},
		Tools: {
			"Find Slave": true,
			"Underperforming Slaves": true,
			"Rules Assistant": true,
			"Personal Attention Select": true,
		},
		Options: {
			Options: true,
			"Summary Options": true,
			"Description Options": true,
			"Hotkey Settings": true,
		}
	});

	// true means hidden
	const hiddenPassages = cleanPassageMapping({
		Arcade: () => !V.arcade,
		"BG Select": () => V.dojo <= 1,
		Brothel: () => !V.brothel,
		Cellblock: () => !V.cellblock,
		Clinic: () => !V.clinic,
		Club: () => !V.club,
		Dairy: () => !V.dairy,
		Dispensary: () => !V.dispensary,
		edicts: () => V.secExpEnabled <= 0,
		Farmyard: () => !V.farmyard,
		Firebase: () => !V.SF.Toggle || V.SF.Toggle < 1 || V.SF.Active < 1,
		"Future Society": () => !V.FSAnnounced,
		"Gene Lab": () => !V.geneticMappingUpgrade,
		"Head Girl Suite": () => !V.HGSuite,
		"Implant Manufactory": () => !V.ImplantProductionUpgrade,
		Incubator: () => !V.incubator,
		"Manage Corporation": () => V.corp.Announced !== 1,
		"Master Suite": () => !V.masterSuite,
		"Neighbor Interact": () => V.arcologies.length === 0,
		Nursery: () => !V.nursery,
		"Organ Farm": () => !V.organFarmUpgrade,
		Pit: () => !V.pit,
		propagandaHub: () => V.secExpEnabled === 0 || !V.SecExp.buildings.propHub,
		"Prosthetic Lab": () => V.researchLab.level === 0,
		riotControlCenter: () => V.secExpEnabled === 0 || !V.SecExp.buildings.riotCenter,
		Schoolroom: () => !V.schoolroom,
		secBarracks: () => V.secExpEnabled === 0 || !V.SecExp.buildings.barracks,
		securityHQ: () => V.secExpEnabled === 0 || !V.SecExp.buildings.secHub,
		"Servants' Quarters": () => !V.servantsQuarters,
		Spa: () => !V.spa,
		"The Black Market": () => V.rep < 10000,
	});

	// show different names than the actual passage name, can be a function
	const uiNames = cleanPassageMapping({
		Arcade: () => App.Entity.facilities.arcade.UIName,
		"BG Select": "Armory",
		Brothel: () => App.Entity.facilities.brothel.UIName,
		Cellblock: () => App.Entity.facilities.cellblock.UIName,
		Clinic: () => App.Entity.facilities.clinic.UIName,
		Club: () => App.Entity.facilities.club.UIName,
		Dairy: () => App.Entity.facilities.dairy.UIName,
		Dispensary: "Pharmaceutical Fabricator",
		edicts: "Edicts",
		Farmyard: () => App.Entity.facilities.farmyard.UIName,
		"Find Slave": "Locate Slave",
		Firebase: () => `${capFirstChar(V.SF.Lower || "No one")}'s Firebase`,
		"Future Society": "Future Societies",
		"Head Girl Suite": () => App.Entity.facilities.headGirlSuite.UIName,
		Incubator: () => App.Entity.facilities.incubator.UIName,
		"Master Suite": () => App.Entity.facilities.masterSuite.UIName,
		"Neighbor Interact": "Diplomacy",
		Nursery: () => App.Entity.facilities.nursery.UIName,
		Options: "Game Options",
		"Personal assistant options": "Personal Assistant",
		"Personal Attention Select":"Personal Attention",
		Pit: () => App.Entity.facilities.pit.UIName,
		propagandaHub: "Manage PR",
		riotControlCenter: "Manage Rebels",
		Schoolroom: () => App.Entity.facilities.schoolroom.UIName,
		secBarracks: "Manage Military",
		securityHQ: "Manage Security",
		"Servants' Quarters": () => App.Entity.facilities.servantsQuarters.UIName,
		Spa: () => App.Entity.facilities.spa.UIName,
		"The Black Market": "Black Market",
	});

	// extra information behind the link, is a function
	const f = App.Entity.facilities;
	const extraInfo = cleanPassageMapping({
		Arcade: () => occupancy(f.arcade),
		"BG Select": () => occupancy(f.armory),
		Brothel: () => occupancy(f.brothel),
		Cellblock: () => occupancy(f.cellblock),
		Clinic: () => occupancy(f.clinic),
		Club: () => occupancy(f.club),
		Dairy: () => occupancy(f.dairy),
		Farmyard: () => occupancy(f.farmyard),
		"Head Girl Suite": () => occupancy(f.headGirlSuite),
		Incubator: () => occupancy(f.incubator),
		"Master Suite": () => occupancy(f.masterSuite),
		Nursery: () => occupancy(f.nursery),
		Pit: () => occupancy(f.pit),
		Schoolroom: () => occupancy(f.schoolroom),
		"Servants' Quarters": () => occupancy(f.servantsQuarters),
		Spa: () => occupancy(f.spa),
	});

	// true shows a notification symbol
	const notifications = cleanPassageMapping({
		"Future Society": () => FutureSocieties.availCredits() > 0 || V.FSReminder,
		Incubator: () => V.readySlaves > 0,
		"Manage Corporation": () => V.corp.SpecToken > 0 && V.corp.SpecTimer === 0,
	});

	/**
	 * The DOM element of name of the currently played passage or any of it's parents. Used during generation to
	 * uncollapse the category with the current passage.
	 * @type {HTMLElement}
	 */
	let currentPassage;
	/**
	 * DOM elements that have a notification. Used to traverse upwards to give the categories notifications too.
	 * @type {Array<HTMLElement>}
	 */
	let notificationPassages;

	let hotkeysEnabled = false;

	// register hotkeys
	// this is in it's own scope as we can forget the hotkeys object immediately afterwards
	{
		// setup hotkeys list, upper/lower case is important!
		const hotkeys = cleanPassageMapping({
			"BG Select": "b",
			"Buy Slaves": "s",
			edicts: "shift+e",
			Firebase: "z",
			"Future Society": "f",
			Main: "m",
			"Manage Arcology": "c",
			"Manage Corporation": "shift+c",
			"Manage Penthouse": "p",
			"Manage Personal Affairs": "x",
			"Neighbor Interact": "d",
			Options: "o",
			"Personal assistant options": "t",
			"Personal Attention Select": "a",
			Policies: "y",
			propagandaHub: "shift+h",
			"Recruiter Select": "u",
			riotControlCenter: "shift+r",
			"Rules Assistant": "r",
			secBarracks: "shift+a",
			securityHQ: "shift+s",
			"Universal Rules": "v",
			// Facilities
			Brothel: "1",
			Club: "2",
			Arcade: "3",
			Dairy: "4",
			Farmyard: "5",
			"Servants' Quarters": "6",
			"Master Suite": "7",
			Schoolroom: "8",
			Spa: "9",
			Nursery: "0",
			Clinic: "shift+1",
			Cellblock: "shift+2",
			Incubator: "shift+3",
			Pit: "shift+4",
		});

		// register
		for (const passage of jumpTo) {
			if (!hidden.includes(passage)) {
				const action = {
					callback: () => {
						if (hotkeysEnabled
							// we are not already on the passage
							&& State.passage !== passage
							// the passage is accessible
							&& !(hiddenPassages[passage] && hiddenPassages[passage]())) {
							Engine.play(passage);
						}
					},
					combinations: [],
				};
				// add hotkey if there is one
				if (hotkeys[passage]) {
					action.combinations.push(hotkeys[passage]);
				}
				// custom ui text
				if (uiNames[passage]) {
					action.uiName = uiNames[passage];
				}
				App.UI.Hotkeys.add(passage, action);
			}
		}
	}

	// setup history
	let history = [];
	let historyNavigation = false;
	$(document).on(':passageinit', event => {
		// if navigated here normally, add passage to history, otherwise remove last entry from history
		if (!historyNavigation) {
			if (State.passage === event.passage.title // reloaded
				|| noHistory.includes(State.passage) // came from a no-history passage
				|| noHistory.includes(event.passage.title) // no history for this passage
			) {
				return;
			}
			// if last passage can be jumped to add passage to history, otherwise clear history
			if (jumpTo.includes(State.passage)) {
				history.unshift(State.passage);
			} else {
				history = [];
			}
		} else {
			historyNavigation = false;
			history.shift();
		}
	});
	App.UI.Hotkeys.add("historyBack", {callback: goBack, combinations: ["backspace"], uiName: "Back in history"});

	/**
	 * Goes back in history if possible.
	 */
	function goBack() {
		if (history.length > 0 && jumpFrom.includes(State.passage)) {
			historyNavigation = true;
			Engine.play(history[0]);
		}
	}

	/**
	 * Add a "Return" link at second position if there is a history.
	 * @param {Array<HTMLElement>} linkList
	 */
	function addBackLink(linkList) {
		if (history.length > 0) {
			const div = document.createElement("div");
			div.classList.add("menu-link");
			const a = document.createElement("a");
			a.append("Return");
			a.onclick = goBack;
			const hotkey = App.UI.Hotkeys.hotkeys("historyBack");
			if (hotkey !== "") {
				div.append(a, " ", App.UI.DOM.makeElement("span", hotkey, "hotkey"));
			}
			// insert at second position
			linkList.splice(1, 0, div);
		}
	}

	/**
	 * Generate a quick menu
	 * @returns {string|HTMLDivElement}
	 */
	function generateMenu() {
		if (!jumpFrom.includes(State.passage)) {
			hotkeysEnabled = false;
			return "";
		}
		hotkeysEnabled = true;
		currentPassage = null;
		notificationPassages = [];

		const div = document.createElement("div");
		div.classList.add("quick-links");

		try {
			// quick menu
			const links = generateLinkList(layout);

			if (V.debugMode) {
				addCategory(links, "Hidden", hidden.reduce((acc, cur) => {
					acc[cur] = true;
					return acc;
				}, {}));
			}

			addBackLink(links);
			div.append(...links);

			// traverse from current passage up to uncollapse.
			if (currentPassage !== null) {
				while (!currentPassage.classList.contains("quick-links")) {
					currentPassage.classList.remove("collapsed");
					currentPassage = currentPassage.parentElement;
				}
			}

			// traverse from notifications up to add icon
			for (let i = 0; i < notificationPassages.length; i++) {
				while (!notificationPassages[i].classList.contains("quick-links")) {
					if (notificationPassages[i].classList.contains("category")) {
						notificationPassages[i].classList.add("notification");
					}
					notificationPassages[i] = notificationPassages[i].parentElement;
				}
			}
		} catch (e) {
			console.error(e);
			div.append("Quick Links generation failed. Please run ", App.UI.DOM.passageLink("Backwards Compatibility", "Backwards Compatibility"));
		}

		return div;
	}

	/**
	 * Create a list of links and/or categories based on the given category
	 *
	 * @param {object} category
	 * @returns {Array<HTMLElement>}
	 */
	function generateLinkList(category) {
		/** @type {Array<HTMLElement>} */
		const links = [];
		for (const passage in category) {
			if (category[passage] === true) {
				addMenuLink(links, passage);
			} else {
				addCategory(links, passage, category[passage]);
			}
		}
		return links;
	}

	/**
	 * Add a category to a link list
	 *
	 * @param {Array<HTMLElement>} outerLinkList
	 * @param {string} name
	 * @param {object} category
	 */
	function addCategory(outerLinkList, name, category) {
		const innerLinkList = generateLinkList(category);
		if (innerLinkList.length === 0) {
			// category is empty
			return;
		}
		const toggle = document.createElement("div");
		toggle.classList.add("toggle");
		toggle.append(name);
		const content = document.createElement("div");
		content.classList.add("content");
		content.append(...innerLinkList);

		// wrap everything in one div, so we can control collapsing by changing only one class
		const wrapper = document.createElement("div");
		wrapper.classList.add("category", "collapsed");
		toggle.onclick = () => {
			wrapper.classList.toggle("collapsed");
		};
		wrapper.append(toggle, content);
		outerLinkList.push(wrapper);
	}

	/**
	 * Create a link to the given passage and add it to the link list if link is accessible.
	 *
	 * @param {Array<HTMLElement>} linkList
	 * @param {string} passage
	 */
	function addMenuLink(linkList, passage) {
		// passage is hidden
		if (hiddenPassages.hasOwnProperty(passage) && hiddenPassages[passage]()) {
			return;
		}
		// we show some kind of text/link
		const div = document.createElement("div");
		linkList.push(div);
		div.classList.add("menu-link");
		// this passage has a notification
		if (notifications[passage] && notifications[passage]()) {
			notificationPassages.push(div);
			div.classList.add("notification");
		}
		// there is additional non-link info
		if (extraInfo[passage]) {
			div.append(" ", extraInfo[passage]());
		}
		// we are already on this passage
		if (State.passage === passage) {
			div.prepend(uiName(passage));
			currentPassage = div;
			return;
		}
		// That is not a passage we can safely jump to, it's a deco element
		if (!jumpTo.includes(passage)) {
			div.prepend(uiName(passage));
			return;
		}
		// Create link
		const a = document.createElement("a");
		a.append(uiName(passage));
		a.onclick = () => {
			Engine.play(passage);
		};
		div.prepend(a);
		const hotkeyString = App.UI.Hotkeys.hotkeys(passage);
		if (hotkeyString !== "") {
			div.append(" ", App.UI.DOM.makeElement("span", hotkeyString, "hotkey"));
		}
	}

	/**
	 * Gives back the proper name for the passage or the passage title itself if there is none
	 *
	 * @param {string} passage
	 * @returns {string}
	 */
	function uiName(passage) {
		if (uiNames[passage]) {
			if (typeof uiNames[passage] === "function") {
				return uiNames[passage]();
			}
			return uiNames[passage];
		}
		return passage;
	}

	/**
	 * Adds an "Other" category to a given layout consisting of passages that can be jumped to not sorted into the
	 * existing layout.
	 *
	 * @param {object} layout
	 * @returns {object}
	 */
	function addOtherCategory(layout) {
		const passages = jumpTo.slice();

		// filter out passages used in layout
		filterPassages(passages, layout);

		// filter out hidden passages
		for (let i = 0; i < hidden.length; i++) {
			const index = passages.indexOf(hidden[i]);
			if (index > -1) {
				passages.splice(index, 1);
			}
		}

		// Other category
		if (passages.length > 0) {
			const other = {};
			for (let i = 0; i < passages.length; i++) {
				other[passages[i]] = true;
			}
			layout.Other = other;
		}
		return layout;
	}

	/**
	 * Remove all entries from a given list that exist as keys in a given layout.
	 *
	 * @param {Array<string>} passages
	 * @param {object} layout
	 */
	function filterPassages(passages, layout) {
		for (const category in layout) {
			if (layout[category] === true) {
				const index = passages.indexOf(category);
				if (index > -1) {
					passages.splice(index, 1);
				}
			} else {
				filterPassages(passages, layout[category]);
			}
		}
	}

	/**
	 * @param {App.Entity.Facilities.Facility} facility
	 * @returns {string}
	 */
	function occupancy(facility) {
		const desc = facility.occupancyReport(V.abbreviateSidebar === 2);
		if (desc === "") {
			return "";
		}
		return `(${desc})`;
	}

	/**
	 * Cleans out all mappings that are not contained in jumpTo and therefore not considered safe.
	 *
	 * @param {object} keys
	 * @returns {object}
	 */
	function cleanPassageMapping(keys) {
		const result = {};
		for (const key in keys) {
			if (jumpTo.includes(key)) {
				result[key] = keys[key];
			} else {
				console.log("Found mapping to unsafe passage: " + key + " to " + keys[key]);
			}
		}
		return result;
	}

	return generateMenu;
})();


code:
App.UI.storyCaption = function() {
	const pass = passage();
	const fragment = document.createDocumentFragment();

	if (V.ui !== "start") {
		App.UI.DOM.appendNewElement("p", fragment, App.Utils.userButton());

		if (V.cheatMode || V.debugMode) {
			App.UI.DOM.appendNewElement("div", fragment, pass);
			if (pass === "JS Random Event") {
				App.UI.DOM.appendNewElement("div", fragment, V.event.eventName);
			}
		}

		fragment.append(week());
		fragment.append(weather());

		if (V.sideBarOptions.Cash > 0) {
			fragment.append(cash());
		}

		if (V.foodMarket > 0) {
			fragment.append(food());
		}

		if (V.sideBarOptions.Upkeep > 0) {
			fragment.append(upkeep());
		}

		if (V.sideBarOptions.SexSlaveCount > 0) {
			fragment.append(slaves());
		}

		if (V.sideBarOptions.roomPop > 0) {
			fragment.append(rooms());
		}

		if (pass !== "Manage Penthouse") {
			if (V.sideBarOptions.GSP > 0 && pass !== "Neighbor Interact") {
				fragment.append(economy());
			}

			if (V.sideBarOptions.Rep > 0) {
				fragment.append(reputation());
			}

			if (V.secExpEnabled > 0) {
				if (V.sideBarOptions.Authority > 0) {
					fragment.append(authority());
				}

				if (V.sideBarOptions.Security > 0) {
					fragment.append(security());
				}

				if (V.sideBarOptions.Crime > 0) {
					fragment.append(crime());
				}
			}
		}

		App.UI.DOM.appendNewElement("p", fragment, App.UI.quickMenu());

		if (V.nextButton !== "Continue" && V.nextButton !== " ") {
			if (pass === "Rules Assistant") {
				App.UI.DOM.appendNewElement("p", fragment,
					App.UI.DOM.passageLink("Rules Assistant Summary", "Rules Assistant Summary"));
			}

			if (V.debugMode > 0) {
				fragment.append(debug());
			}
			/* Closes nextButton != "Continue" && nextButton != " " */
		}
	} else if (pass === "Starting Girls") {
		fragment.append(startingGirls());
	}

	const p = document.createElement("p");
	p.append(App.UI.DOM.makeElement("span", "FCE", "bold"), ": ",
		App.Encyclopedia.Dialog.linkDOM(V.encyclopedia, V.encyclopedia));
	fragment.append(p);

	return fragment;

	function week() {
		const fragment = document.createDocumentFragment();
		const div = document.createElement("div");
		App.UI.DOM.appendNewElement("span", div, `Week ${V.week}`, "bold");
		if (V.week > 52) {
			div.append(` (${years(V.week)})`);
		}
		fragment.append(div);
		App.UI.DOM.appendNewElement("div", fragment, `Week of ${asDateString(V.week)}`);

		if (showCheats()) {
			fragment.append(App.UI.DOM.makeTextBox(V.week, week => {
				week = Math.trunc(week);
				V.week = week > 0 ? week : V.week;
				App.Utils.scheduleSidebarRefresh();
			}, true));
		}
		return fragment;
	}

	function weather() {
		const div = App.UI.DOM.appendNewElement("div", fragment, V.weatherToday.name, "note");
		if (V.weatherToday.severity === 1) {
			div.classList.add("cyan");
		} else if (V.weatherToday.severity === 2) {
			div.classList.add("yellow");
		} else if (V.weatherToday.severity === 3) {
			div.classList.add("orange");
		} else {
			div.classList.add("red");
		}
		return div;
	}

	function cash() {
		const fragment = document.createDocumentFragment();
		V.cash = Math.trunc(V.cash);
		const css = ["cash"];
		if (V.cash <= 0) {
			css.push("dec");
		}
		const cashDiv = document.createElement("div");
		App.UI.DOM.appendNewElement("span", cashDiv, "Cash", css);
		cashDiv.append(" | ");
		App.UI.DOM.appendNewElement("span", cashDiv, cashFormat(V.cash), css);
		fragment.append(cashDiv);

		if (pass === "Main") {
			const div = document.createElement("div");
			div.append("(");
			let cashDiff = V.cash - V.cashLastWeek;
			if (cashDiff > 0) {
				App.UI.DOM.appendNewElement("span", div, cashFormat(cashDiff), "green");
			} else {
				App.UI.DOM.appendNewElement("span", div, cashFormat(cashDiff), ["cash", "dec"]);
			}
			div.append(" since last week)");
			fragment.append(div);
		}

		if (showCheats()) {
			fragment.append(App.UI.DOM.makeTextBox(V.cash, cash => {
				V.cash = Math.trunc(cash);
				V.cheater = 1;
				App.Utils.scheduleSidebarRefresh();
			}, true));
		}
		return fragment;
	}

	function food() {
		const fragment = document.createDocumentFragment();

		const foodDiv = document.createElement("div");
		V.food = Math.trunc(V.food);
		V.foodConsumption = Math.trunc((V.lowerClass * V.foodRate.lower)
			+ (V.middleClass * V.foodRate.middle)
			+ (V.upperClass * V.foodRate.upper)
			+ (V.topClass * V.foodRate.top));
		/* check if there is enough food for the next week */
		if (V.food > V.foodConsumption) {
			App.UI.DOM.appendNewElement("span", foodDiv, "Food", "chocolate");
		} else {
			App.UI.DOM.appendNewElement("span", foodDiv, "Food", "red");
		}
		if (V.food < 0) {
			V.food = 0;
		}
		foodDiv.append(" | ");
		App.UI.DOM.appendNewElement("span", foodDiv, massFormat(V.food), "chocolate");
		fragment.append(foodDiv);

		if (pass === "Main") {
			const foodDiv2 = document.createElement("div");
			foodDiv2.append("(");
			const foodDiff = (V.food - V.foodLastWeek);
			App.UI.DOM.appendNewElement("span", foodDiv2, massFormat(foodDiff), foodDiff < 0 ? "red" : "chocolate");
			foodDiv2.append(" since last week)");
			fragment.append(foodDiv2);
		}

		if (showCheats()) {
			fragment.append(App.UI.DOM.makeTextBox(V.food, food => {
				food = Math.trunc(food);
				V.food = food > 0 ? food : 0;
				App.Utils.scheduleSidebarRefresh();
			}, true));
		}
		return fragment;
	}

	function upkeep() {
		const div = document.createElement("div");
		if (pass === "Main") {
			div.append(App.UI.DOM.passageLink("Upkeep", "Costs Budget"), " | ");
		} else {
			div.append(" Upkeep | ");
		}
		App.UI.DOM.appendNewElement("span", div, cashFormat(V.costs), ["cash", "dec"]);
		return div;
	}

	function slaves() {
		const div = document.createElement("div");
		App.UI.DOM.appendNewElement("span", div, "Total Sex Slaves", "pink");
		div.append(` | ${V.slaves.length}`);
		return div;
	}

	function rooms() {
		const fragment = document.createDocumentFragment();

		fragment.append(roomRow("Penthouse Beds", V.dormitoryPopulation + V.roomsPopulation, V.dormitory + V.rooms));
		fragment.append(roomRow("Dormitory Beds", V.dormitoryPopulation, V.dormitory));
		fragment.append(roomRow("Luxury Rooms", V.roomsPopulation, V.rooms));

		return fragment;
	}

	/**
	 * @param {string} name
	 * @param {number} pops
	 * @param {number} cap
	 * @returns {HTMLDivElement}
	 */
	function roomRow(name, pops, cap) {
		const div = document.createElement("div");
		App.UI.DOM.appendNewElement("span", div, name, "pink");
		div.append(" | ");
		if (pops > cap) {
			App.UI.DOM.appendNewElement("span", div, pops, "warning");
		} else {
			div.append(pops);
		}
		div.append(`/${cap}`);
		return div;
	}

	function economy() {
		const div = document.createElement("div");
		App.UI.DOM.appendNewElement("span", div, "GSP", "yellowgreen");
		div.append(` | ${num(Math.trunc(0.1 * V.arcologies[0].prosperity))}`);
		if (V.showNumbers === 2 || (V.showNumbers === 1 && Math.trunc(0.1 * V.arcologies[0].prosperity) > V.showNumbersMax)) {
			div.append("m");
		} else {
			div.append(" million");
		}
		div.append(" ", ownershipReport(true));
		return div;
	}

	function reputation() {
		const div = document.createElement("div");
		if (pass === "Main") {
			div.append(App.UI.DOM.passageLink("Rep", "Rep Budget"));
		} else {
			App.UI.DOM.appendNewElement("span", div, "Rep", ["reputation", "inc"]);
		}
		div.append(" | ");

		if (V.rep > 19000) {
			App.UI.DOM.appendNewElement("span", div, "worshipped").style.color = "rgb(0,145,0)";
		} else if (V.rep > 18000) {
			App.UI.DOM.appendNewElement("span", div, "great").style.color = "rgb(0,150,0)";
		} else if (V.rep > 17000) {
			App.UI.DOM.appendNewElement("span", div, "exalted").style.color = "rgb(0,155,0)";
		} else if (V.rep > 16000) {
			App.UI.DOM.appendNewElement("span", div, "illustrious").style.color = "rgb(0,160,0)";
		} else if (V.rep > 15000) {
			App.UI.DOM.appendNewElement("span", div, "prestigious").style.color = "rgb(0,165,0)";
		} else if (V.rep > 14000) {
			App.UI.DOM.appendNewElement("span", div, "renowned").style.color = "rgb(0,170,0)";
		} else if (V.rep > 13000) {
			App.UI.DOM.appendNewElement("span", div, "famed").style.color = "rgb(0,175,0)";
		} else if (V.rep > 12000) {
			App.UI.DOM.appendNewElement("span", div, "celebrated").style.color = "rgb(0,180,0)";
		} else if (V.rep > 11000) {
			App.UI.DOM.appendNewElement("span", div, "honored").style.color = "rgb(0,185,0)";
		} else if (V.rep > 10000) {
			App.UI.DOM.appendNewElement("span", div, "acclaimed").style.color = "rgb(0,190,0)";
		} else if (V.rep > 9000) {
			App.UI.DOM.appendNewElement("span", div, "eminent").style.color = "rgb(0,195,0)";
		} else if (V.rep > 8250) {
			App.UI.DOM.appendNewElement("span", div, "prominent").style.color = "rgb(0,200,0)";
		} else if (V.rep > 7500) {
			App.UI.DOM.appendNewElement("span", div, "distinguished").style.color = "rgb(0,205,0)";
		} else if (V.rep > 6750) {
			App.UI.DOM.appendNewElement("span", div, "admired").style.color = "rgb(0,210,0)";
		} else if (V.rep > 6000) {
			App.UI.DOM.appendNewElement("span", div, "esteemed").style.color = "rgb(0,215,0)";
		} else if (V.rep > 5250) {
			App.UI.DOM.appendNewElement("span", div, "respected").style.color = "rgb(0,220,0)";
		} else if (V.rep > 4500) {
			App.UI.DOM.appendNewElement("span", div, "known").style.color = "rgb(0,225,0)";
		} else if (V.rep > 3750) {
			App.UI.DOM.appendNewElement("span", div, "recognized").style.color = "rgb(0,230,0)";
		} else if (V.rep > 3000) {
			App.UI.DOM.appendNewElement("span", div, "rumored").style.color = "rgb(0,235,0)";
		} else if (V.rep > 2250) {
			App.UI.DOM.appendNewElement("span", div, "envied").style.color = "rgb(0,240,0)";
		} else if (V.rep > 1500) {
			App.UI.DOM.appendNewElement("span", div, "resented").style.color = "rgb(0,245,0)";
		} else if (V.rep > 750) {
			App.UI.DOM.appendNewElement("span", div, "disliked").style.color = "rgb(0,250,0)";
		} else {
			App.UI.DOM.appendNewElement("span", div, "unknown").style.color = "rgb(0,255,0)";
		}
		div.append(` (${num(V.rep)})`);

		if (showCheats()) {
			div.append(App.UI.DOM.makeTextBox(V.rep, rep => {
				V.rep = Math.clamp(Math.trunc(rep), 0, 20000);
				V.cheater = 1;
				App.Utils.scheduleSidebarRefresh();
			}, true));
		}
		return div;
	}

	function authority() {
		const div = document.createElement("div");
		App.UI.DOM.appendNewElement("span", div, "Auth", "darkviolet");

		div.append(" | ");
		const span = document.createElement("span");
		span.className = "darkviolet";
		V.SecExp.core.authority = Math.clamp(Math.trunc(V.SecExp.core.authority), 0, 20000);
		if (V.SecExp.core.authority > 19500) {
			span.append("divine will");
		} else if (V.SecExp.core.authority > 19000) {
			span.append("sovereign");
		} else if (V.SecExp.core.authority > 18000) {
			span.append("monarch");
		} else if (V.SecExp.core.authority > 17000) {
			span.append("tyrant");
		} else if (V.SecExp.core.authority > 15000) {
			span.append("dictator");
		} else if (V.SecExp.core.authority > 14000) {
			span.append("prince");
		} else if (V.SecExp.core.authority > 13000) {
			span.append("master");
		} else if (V.SecExp.core.authority > 12000) {
			span.append("leader");
		} else if (V.SecExp.core.authority > 11000) {
			span.append("director");
		} else if (V.SecExp.core.authority > 10000) {
			span.append("overseer");
		} else if (V.SecExp.core.authority > 9000) {
			span.append("chief");
		} else if (V.SecExp.core.authority > 8000) {
			span.append("manager");
		} else if (V.SecExp.core.authority > 7000) {
			span.append("principal");
		} else if (V.SecExp.core.authority > 6000) {
			span.append("auxiliary");
		} else if (V.SecExp.core.authority > 5000) {
			span.append("subordinate");
		} else if (V.SecExp.core.authority > 4000) {
			span.append("follower");
		} else if (V.SecExp.core.authority > 3000) {
			span.append("powerless");
		} else if (V.SecExp.core.authority > 2000) {
			span.append("toothless");
		} else if (V.SecExp.core.authority > 1000) {
			span.append("mostly harmless");
		} else {
			span.append("harmless");
		}

		div.append(span, ` (${num(V.SecExp.core.authority)})`);
		if (showCheats()) {
			div.append(App.UI.DOM.makeTextBox(V.SecExp.core.authority, auth => {
				V.SecExp.core.authority = Math.clamp(Math.trunc(auth), 0, 20000);
				V.cheater = 1;
				App.Utils.scheduleSidebarRefresh();
			}));
		}
		return div;
	}

	function security() {
		const div = document.createElement("div");
		App.UI.DOM.appendNewElement("span", div, "Security", "deepskyblue");
		div.append(" | ");

		App.UI.DOM.appendNewElement("span", div, `${Math.trunc(V.SecExp.core.security)}%`, "deepskyblue");
		if (showCheats()) {
			div.append(App.UI.DOM.makeTextBox(V.SecExp.core.security, sec => {
				V.SecExp.core.security = Math.clamp(Math.trunc(sec), 0, 100);
				V.cheater = 1;
				App.Utils.scheduleSidebarRefresh();
			}, true));
		}
		return div;
	}

	function crime() {
		const div = document.createElement("div");
		App.UI.DOM.appendNewElement("span", div, "Crime", "orangered");
		div.append(" | ");
		App.UI.DOM.appendNewElement("span", div, `${Math.trunc(V.SecExp.core.crimeLow)}%`, "orangered");

		if (showCheats()) {
			div.append(App.UI.DOM.makeTextBox(V.SecExp.core.crimeLow, crime => {
				V.SecExp.core.crimeLow = Math.clamp(Math.trunc(crime), 0, 100);
				V.cheater = 1;
				App.Utils.scheduleSidebarRefresh();
			}, true));
		}
		return div;
	}

	function showCheats() {
		return pass === "Main" && V.cheatMode && V.cheatModeM;
	}

	function debug() {
		const p = document.createElement("p");
		p.append("Debugging Tools");

		App.UI.DOM.appendNewElement("div", p, App.UI.DOM.link("Display Variables", App.checkVars));

		App.UI.DOM.appendNewElement("div", p, App.UI.DOM.link("Display Changed Variables", () => {
			/* makes sure we store the current state so we can return to it */
			Config.history.maxStates = 2;
			Engine.play("Variable Difference");
		}));

		if (V.debugModeCustomFunction > 0) {
			const textarea = document.createElement("textarea");
			textarea.id = "cheat-function";
			p.append(textarea);

			p.append(App.UI.DOM.link("Run Custom Function", () => {
				let value = textarea.value;
				if (value.charAt(0) !== "(") {
					value = `() => {${value}}`;
				}
				if (typeof eval(value) === "function") {
					(eval(value))();
					Engine.play(pass);
				} else {
					Dialog.append("Not a valid function").open();
				}
			}));
		}

		App.UI.DOM.appendNewElement("div", p, App.UI.DOM.link("Dump Game State", App.Debug.dumpGameState));

		return p;
	}

	function startingGirls() {
		let _slaveCost = startingSlaveCost(V.activeSlave);
		const p = document.createElement("p");

		if (_slaveCost > V.cash) {
			const div = document.createElement("div");
			div.classList.add("cash", "dec");
			div.append("This slave will cost ",
				App.UI.DOM.makeElement("span", cashFormat(_slaveCost), "bold"), ".",
				App.UI.DOM.makeElement("div", `You only have: ${cashFormat(V.cash)}.`));
			p.append(div);
		} else {
			const div = document.createElement("div");
			div.append("This slave will cost ",
				App.UI.DOM.makeElement("span", cashFormat(_slaveCost), "cash"), ".",
				App.UI.DOM.makeElement("div", `You have ${cashFormat(V.cash)}.`));
			p.append(div);
		}
		return p;
	}
};


code:
:: StoryCaption [nobr]

<<includeDOM App.UI.storyCaption()>>