From c515250108257189b77a623f64c9c52f12ae30a8 Mon Sep 17 00:00:00 2001
From: Arkerthan <arkerthan@mailbox.org>
Date: Tue, 28 Feb 2023 21:43:58 +0100
Subject: [PATCH] Redesign cash/rep budget overview

---
 css/002-variables/colors.css |   5 +-
 css/manage/budget.css        | 109 ++++++-
 src/budget/budget.js         | 577 ++++++++++++++++-------------------
 3 files changed, 368 insertions(+), 323 deletions(-)

diff --git a/css/002-variables/colors.css b/css/002-variables/colors.css
index a592b04a14f..4a3db10c344 100644
--- a/css/002-variables/colors.css
+++ b/css/002-variables/colors.css
@@ -6,5 +6,8 @@
 	--button-disabled-color: #1a1a1a;
 
 	--link-color: #68D;
-	--link-hover-color: #8af
+	--link-hover-color: #8af;
+
+	--background-default: #111;
+	--background-light: #222;
 }
diff --git a/css/manage/budget.css b/css/manage/budget.css
index 680f4f74402..bbcfee4be92 100644
--- a/css/manage/budget.css
+++ b/css/manage/budget.css
@@ -1,31 +1,110 @@
-table.budget {
+/* Table-Grid */
+.budget {
+	border: 2px white solid;
+	width: fit-content;
+	display: grid;
+	grid-template-columns: auto auto auto auto;
+}
+
+@media only screen and (min-width: 768px) {
+	.budget {
+		grid-template-columns: max-content max-content max-content auto;
+	}
+}
+
+.budget div {
+	padding: 0 20px;
+}
+
+.budget div.last-row {
+	padding-bottom: 10px;
+}
+
+.budget div.section {
+	border-top: 1px solid white;
+	margin-top: 5px;
+	padding-top: 5px;
+	font-size: 18px;
+	font-weight: bold;
+}
+
+.budget div.section:nth-child(4n+1) {
+	padding-left: 10px;
+}
+
+.budget div.group {
+	font-weight: bold;
+}
+
+.budget div.group:nth-child(4n+1) {
+	padding-left: 30px
+}
+
+.budget .entry {
+	background: var(--background-light);
+}
+
+.budget .entry:nth-child(4n+1) {
+	border-left: 1px solid white;
+	margin-left: 30px;
+	padding-left: 10px;
+}
+
+.budget div.final-result {
+	border-bottom: 3px double white;
+}
+
+
+.budget div.number {
 	text-align: right;
-	border-collapse: separate;
-	width: 90%;
-	border-style: solid;
-	border-width: 1px;
-	border-color: white;
-	padding: 5px;
 	font-family: monospace;
+	font-weight: normal;
 }
-table.budget .colored {
-	background-color: #001700;
+
+.budget > :nth-child(4n) {
+	border-left: 1px dashed white;
 }
 
-table.budget .accordion:not(.closed) .cash {
+/* Floating Header */
+.budget div.header {
+	font-size: 20px;
+	font-weight: bold;
+	text-align: center;
+	position: sticky;
+	z-index: 1;
+	top: -1px;
+	background: var(--background-default);
+	border-bottom: 1px solid white;
+	padding-top: 5px;
+	padding-bottom: 5px;
+}
+
+/* Accordion */
+.budget .accordion:not(.closed) .cash,
+.budget .accordion:not(.closed) .reputation {
 	color: gray;
 }
 
-table.budget .accordion > :first-child {
+.budget .accordion-content {
+	margin: 0
+}
+
+.budget .accordion:nth-child(4n+1) {
 	position: relative;
 }
 
-table.budget .accordion > :first-child::before {
+.budget .accordion:nth-child(4n+1)::before {
 	font-family: "tme-fa-icons";
-	position: absolute;
-	left: 10px;
 	content: "\e81c";
+	position: absolute;
+	left: 0;
+	min-width: 30px;
+	text-align: center;
+	border-bottom: 1px solid white;
+	font-weight: normal;
 }
-table.budget .accordion.closed > :first-child::before {
+
+.budget .accordion.closed:nth-child(4n+1)::before {
 	content: "\e81e";
+	border-bottom: none;
 }
diff --git a/src/budget/budget.js b/src/budget/budget.js
index f37dcd826e2..d6a1c43d238 100644
--- a/src/budget/budget.js
+++ b/src/budget/budget.js
@@ -1,49 +1,44 @@
 /**
  *
  * @param {"cash"|"rep"} budgetType
- * @returns {HTMLTableElement}
+ * @returns {HTMLDivElement}
  */
 App.Budget.table = function(budgetType) {
-	let coloredRow = true;
-
 	// Set up object to track calculated displays
 	const income = (budgetType === "cash") ? "lastWeeksCashIncome" : "lastWeeksRepIncome";
 	const expenses = (budgetType === "cash") ? "lastWeeksCashExpenses" : "lastWeeksRepExpenses";
 
-	const table = document.createElement("table");
-	table.classList.add("budget");
+	const tableDiv = document.createElement("div");
+	tableDiv.classList.add("budget");
 
 	// HEADER
 	generateHeader();
 
-	// BODY
-	table.createTBody();
-
 	// HEADER: FACILITIES
 	createSectionHeader("Facilities");
 
-	const f = App.Entity.facilities; // shortcut
+	const F = App.Entity.facilities; // shortcut
 
 	if (budgetType === "cash") {
 		// PENTHOUSE
 		addToggle(generateRowGroup("Penthouse", "PENTHOUSE"), [
-			generateRowCategory("Resting Slaves", "slaveAssignmentRest"),
-			generateRowCategory("Resting Vign", "slaveAssignmentRestVign"),
-			generateRowCategory("Fucktoys", "slaveAssignmentFucktoy"),
-			generateRowCategory("Taking Classes", "slaveAssignmentClasses"),
-			generateRowCategory("House Servants", "slaveAssignmentHouse"),
-			generateRowCategory("House Servant Vign", "slaveAssignmentHouseVign"),
-			generateRowCategory("Whores", "slaveAssignmentWhore"),
-			generateRowCategory("Whore Vign", "slaveAssignmentWhoreVign"),
-			generateRowCategory("Public Sluts", "slaveAssignmentPublic"),
-			generateRowCategory("Public Slut Vign", "slaveAssignmentPublicVign"),
-			generateRowCategory("Subordinate Slaves", "slaveAssignmentSubordinate"),
-			generateRowCategory("Milked", "slaveAssignmentMilked"),
-			generateRowCategory("MilkedVign", "slaveAssignmentMilkedVign"),
-			generateRowCategory("ExtraMilk", "slaveAssignmentExtraMilk"),
-			generateRowCategory("ExtraMilkVign", "slaveAssignmentExtraMilkVign"),
-			generateRowCategory("Gloryhole", "slaveAssignmentGloryhole"),
-			generateRowCategory("Confined Slaves", "slaveAssignmentConfinement")
+			...generateRowCategory("Resting Slaves", "slaveAssignmentRest"),
+			...generateRowCategory("Resting Vign", "slaveAssignmentRestVign"),
+			...generateRowCategory("Fucktoys", "slaveAssignmentFucktoy"),
+			...generateRowCategory("Taking Classes", "slaveAssignmentClasses"),
+			...generateRowCategory("House Servants", "slaveAssignmentHouse"),
+			...generateRowCategory("House Servant Vign", "slaveAssignmentHouseVign"),
+			...generateRowCategory("Whores", "slaveAssignmentWhore"),
+			...generateRowCategory("Whore Vign", "slaveAssignmentWhoreVign"),
+			...generateRowCategory("Public Sluts", "slaveAssignmentPublic"),
+			...generateRowCategory("Public Slut Vign", "slaveAssignmentPublicVign"),
+			...generateRowCategory("Subordinate Slaves", "slaveAssignmentSubordinate"),
+			...generateRowCategory("Milked", "slaveAssignmentMilked"),
+			...generateRowCategory("MilkedVign", "slaveAssignmentMilkedVign"),
+			...generateRowCategory("ExtraMilk", "slaveAssignmentExtraMilk"),
+			...generateRowCategory("ExtraMilkVign", "slaveAssignmentExtraMilkVign"),
+			...generateRowCategory("Gloryhole", "slaveAssignmentGloryhole"),
+			...generateRowCategory("Confined Slaves", "slaveAssignmentConfinement")
 		]);
 		// Other
 		generateRowCategory("Choosing Own Assignment", "slaveAssignmentChoice");
@@ -52,449 +47,411 @@ App.Budget.table = function(budgetType) {
 
 		// HEAD GIRL
 		// find passage name for HGSuite
-		addToggle(generateRowGroup(f.headGirlSuite.nameCaps, "HEADGIRLSUITE"), [
-			generateRowCategory("Head Girl", "slaveAssignmentHeadgirl"),
-			generateRowCategory("Head Girl Fucktoys", "slaveAssignmentHeadgirlsuite")
+		addToggle(generateRowGroup(F.headGirlSuite.nameCaps, "HEADGIRLSUITE"), [
+			...generateRowCategory("Head Girl", "slaveAssignmentHeadgirl"),
+			...generateRowCategory("Head Girl Fucktoys", "slaveAssignmentHeadgirlsuite")
 		]);
 
 		// RECRUITER
 		addToggle(generateRowGroup("Recruiter", "RECRUITER"), [
-			generateRowCategory("Recruiter", "slaveAssignmentRecruiter")
+			...generateRowCategory("Recruiter", "slaveAssignmentRecruiter")
 		]);
 
 		// BODYGUARD
 		// find passage name for Armory
-		addToggle(generateRowGroup(f.armory.nameCaps, "DOJO"), [
-			generateRowCategory("Bodyguard", "slaveAssignmentBodyguard")
+		addToggle(generateRowGroup(F.armory.nameCaps, "DOJO"), [
+			...generateRowCategory("Bodyguard", "slaveAssignmentBodyguard")
 		]);
 
 		// CONCUBINE
-		addToggle(generateRowGroup(f.masterSuite.nameCaps, "MASTERSUITE"), [
-			generateRowCategory("Master Suite Operation", "masterSuite"),
-			generateRowCategory("Master Suite Concubine", "slaveAssignmentConcubine"),
-			generateRowCategory("Master Suite Fucktoys", "slaveAssignmentMastersuite")
+		addToggle(generateRowGroup(F.masterSuite.nameCaps, "MASTERSUITE"), [
+			...generateRowCategory("Master Suite Operation", "masterSuite"),
+			...generateRowCategory("Master Suite Concubine", "slaveAssignmentConcubine"),
+			...generateRowCategory("Master Suite Fucktoys", "slaveAssignmentMastersuite")
 		]);
 
 		// AGENT
 		addToggle(generateRowGroup("Agent", "AGENT"), [
-			generateRowCategory("Agent", "slaveAssignmentAgent"),
-			generateRowCategory("Agent's Partner", "slaveAssignmentAgentPartner")
+			...generateRowCategory("Agent", "slaveAssignmentAgent"),
+			...generateRowCategory("Agent's Partner", "slaveAssignmentAgentPartner")
 		]);
 
 		// ARCADE
-		addToggle(generateRowGroup(f.arcade.nameCaps, "ARCADE"), [
-			generateRowCategory("Arcade Operation", "arcade"),
-			generateRowCategory("Arcade Fuckdolls", "slaveAssignmentArcade")
+		addToggle(generateRowGroup(F.arcade.nameCaps, "ARCADE"), [
+			...generateRowCategory("Arcade Operation", "arcade"),
+			...generateRowCategory("Arcade Fuckdolls", "slaveAssignmentArcade")
 		]);
 
 		// BROTHEL
-		addToggle(generateRowGroup(f.brothel.nameCaps, "BROTHEL"), [
-			generateRowCategory("Brothel Operation", "brothel"),
-			generateRowCategory("Brothel Madam", "slaveAssignmentMadam"),
-			generateRowCategory("Brothel MadamVign", "slaveAssignmentMadamVign"),
-			generateRowCategory("Brothel Whore", "slaveAssignmentBrothel"),
-			generateRowCategory("Brothel WhoreVign", "slaveAssignmentBrothelVign"),
-			generateRowCategory("Brothel Ads", "brothelAds")
+		addToggle(generateRowGroup(F.brothel.nameCaps, "BROTHEL"), [
+			...generateRowCategory("Brothel Operation", "brothel"),
+			...generateRowCategory("Brothel Madam", "slaveAssignmentMadam"),
+			...generateRowCategory("Brothel MadamVign", "slaveAssignmentMadamVign"),
+			...generateRowCategory("Brothel Whore", "slaveAssignmentBrothel"),
+			...generateRowCategory("Brothel WhoreVign", "slaveAssignmentBrothelVign"),
+			...generateRowCategory("Brothel Ads", "brothelAds")
 		]);
 
 		// CELLBLOCK
-		addToggle(generateRowGroup(f.cellblock.nameCaps, "CELLBLOCK"), [
-			generateRowCategory("Cellblock Operation", "cellblock"),
-			generateRowCategory("Cellblock Warden", "slaveAssignmentWarden"),
-			generateRowCategory("Cellblock Slaves", "slaveAssignmentCellblock")
+		addToggle(generateRowGroup(F.cellblock.nameCaps, "CELLBLOCK"), [
+			...generateRowCategory("Cellblock Operation", "cellblock"),
+			...generateRowCategory("Cellblock Warden", "slaveAssignmentWarden"),
+			...generateRowCategory("Cellblock Slaves", "slaveAssignmentCellblock")
 		]);
 
 		// CLUB
-		addToggle(generateRowGroup(f.club.nameCaps, "CLUB"), [
-			generateRowCategory("Club Operation", "club"),
-			generateRowCategory("Club DJ", "slaveAssignmentDj"),
-			generateRowCategory("Club DJVign", "slaveAssignmentDjVign"),
-			generateRowCategory("Club Sluts", "slaveAssignmentClub"),
-			generateRowCategory("Club Slut Vign", "slaveAssignmentClubVign"),
-			generateRowCategory("Club Ads", "clubAds")
+		addToggle(generateRowGroup(F.club.nameCaps, "CLUB"), [
+			...generateRowCategory("Club Operation", "club"),
+			...generateRowCategory("Club DJ", "slaveAssignmentDj"),
+			...generateRowCategory("Club DJVign", "slaveAssignmentDjVign"),
+			...generateRowCategory("Club Sluts", "slaveAssignmentClub"),
+			...generateRowCategory("Club Slut Vign", "slaveAssignmentClubVign"),
+			...generateRowCategory("Club Ads", "clubAds")
 		]);
 
 		// CLINIC
-		addToggle(generateRowGroup(f.clinic.nameCaps, "CLINIC"), [
-			generateRowCategory("Clinic Operation", "clinic"),
-			generateRowCategory("Clinic Nurse", "slaveAssignmentNurse"),
-			generateRowCategory("Clinic Slaves", "slaveAssignmentClinic")
+		addToggle(generateRowGroup(F.clinic.nameCaps, "CLINIC"), [
+			...generateRowCategory("Clinic Operation", "clinic"),
+			...generateRowCategory("Clinic Nurse", "slaveAssignmentNurse"),
+			...generateRowCategory("Clinic Slaves", "slaveAssignmentClinic")
 		]);
 
 		// DAIRY
-		addToggle(generateRowGroup(f.dairy.nameCaps, "DAIRY"), [
-			generateRowCategory("Dairy Operation", "dairy"),
-			generateRowCategory("Dairy Milkmaid", "slaveAssignmentMilkmaid"),
-			generateRowCategory("Dairy Cows", "slaveAssignmentDairy"),
-			generateRowCategory("Dairy CowsVign", "slaveAssignmentDairyVign")
+		addToggle(generateRowGroup(F.dairy.nameCaps, "DAIRY"), [
+			...generateRowCategory("Dairy Operation", "dairy"),
+			...generateRowCategory("Dairy Milkmaid", "slaveAssignmentMilkmaid"),
+			...generateRowCategory("Dairy Cows", "slaveAssignmentDairy"),
+			...generateRowCategory("Dairy CowsVign", "slaveAssignmentDairyVign")
 		]);
 
 		// FARMYARD
-		addToggle(generateRowGroup(f.farmyard.nameCaps, "FARMYARD"), [
-			generateRowCategory("Farmyard Operation", "farmyard"),
-			generateRowCategory("Farmyard Farmer", "slaveAssignmentFarmer"),
-			generateRowCategory("Farmyard Farmhands", "slaveAssignmentFarmyard"),
-			generateRowCategory("Farmyard FarmhandsVign", "slaveAssignmentFarmyardVign")
+		addToggle(generateRowGroup(F.farmyard.nameCaps, "FARMYARD"), [
+			...generateRowCategory("Farmyard Operation", "farmyard"),
+			...generateRowCategory("Farmyard Farmer", "slaveAssignmentFarmer"),
+			...generateRowCategory("Farmyard Farmhands", "slaveAssignmentFarmyard"),
+			...generateRowCategory("Farmyard FarmhandsVign", "slaveAssignmentFarmyardVign")
 		]);
 
 		// INCUBATOR
-		addToggle(generateRowGroup(f.incubator.nameCaps, "INCUBATOR"), [
-			generateRowCategory("Incubator Operation", "incubator"),
-			generateRowCategory("Incubator Babies", "incubatorSlaves")
+		addToggle(generateRowGroup(F.incubator.nameCaps, "INCUBATOR"), [
+			...generateRowCategory("Incubator Operation", "incubator"),
+			...generateRowCategory("Incubator Babies", "incubatorSlaves")
 		]);
 
 		// NURSERY
-		addToggle(generateRowGroup(f.nursery.nameCaps, "NURSERY"), [
-			generateRowCategory("Nursery Operation", "nursery"),
-			generateRowCategory("Nursery Matron", "slaveAssignmentMatron"),
-			generateRowCategory("Nursery Nannies", "slaveAssignmentNursery"),
-			generateRowCategory("Nursery NanniesVign", "slaveAssignmentNurseryVign")
+		addToggle(generateRowGroup(F.nursery.nameCaps, "NURSERY"), [
+			...generateRowCategory("Nursery Operation", "nursery"),
+			...generateRowCategory("Nursery Matron", "slaveAssignmentMatron"),
+			...generateRowCategory("Nursery Nannies", "slaveAssignmentNursery"),
+			...generateRowCategory("Nursery NanniesVign", "slaveAssignmentNurseryVign")
 		]);
 
 		// PIT
-		addToggle(generateRowGroup(f.pit.nameCaps, "PIT"), [
-			generateRowCategory("Pit Operation", "pit")
+		addToggle(generateRowGroup(F.pit.nameCaps, "PIT"), [
+			...generateRowCategory("Pit Operation", "pit")
 		]);
 
 		// PROSTHETIC LAB
 		addToggle(generateRowGroup("Prosthetic Lab", "PROSTHETICLAB"), [
-			generateRowCategory("Prosthetic Lab Operation", "lab"),
-			generateRowCategory("Prosthetic Lab Research", "labResearch"),
-			generateRowCategory("Prosthetic Lab Scientists", "labScientists"),
-			generateRowCategory("Prosthetic Lab Menials", "labMenials")
+			...generateRowCategory("Prosthetic Lab Operation", "lab"),
+			...generateRowCategory("Prosthetic Lab Research", "labResearch"),
+			...generateRowCategory("Prosthetic Lab Scientists", "labScientists"),
+			...generateRowCategory("Prosthetic Lab Menials", "labMenials")
 		]);
 
 		// SCHOOLROOM
-		addToggle(generateRowGroup(f.schoolroom.nameCaps, "SCHOOLROOM"), [
-			generateRowCategory("Schoolroom Operation", "school"),
-			generateRowCategory("Schoolroom Teacher", "slaveAssignmentTeacher"),
-			generateRowCategory("Schoolroom Students", "slaveAssignmentSchool")
+		addToggle(generateRowGroup(F.schoolroom.nameCaps, "SCHOOLROOM"), [
+			...generateRowCategory("Schoolroom Operation", "school"),
+			...generateRowCategory("Schoolroom Teacher", "slaveAssignmentTeacher"),
+			...generateRowCategory("Schoolroom Students", "slaveAssignmentSchool")
 		]);
 
 		// SERVANTS' QUARTERS
-		addToggle(generateRowGroup(f.servantsQuarters.nameCaps, "SERVANTSQUARTERS"), [
-			generateRowCategory("Servants' Quarters Operation", "servantsQuarters"),
-			generateRowCategory("Servants' Quarters Steward", "slaveAssignmentSteward"),
-			generateRowCategory("Servants' Quarters Servants", "slaveAssignmentQuarter"),
-			generateRowCategory("Servants' Quarters ServantsVign", "slaveAssignmentQuarterVign")
+		addToggle(generateRowGroup(F.servantsQuarters.nameCaps, "SERVANTSQUARTERS"), [
+			...generateRowCategory("Servants' Quarters Operation", "servantsQuarters"),
+			...generateRowCategory("Servants' Quarters Steward", "slaveAssignmentSteward"),
+			...generateRowCategory("Servants' Quarters Servants", "slaveAssignmentQuarter"),
+			...generateRowCategory("Servants' Quarters ServantsVign", "slaveAssignmentQuarterVign")
 		]);
 
 		// SPA
-		addToggle(generateRowGroup(f.spa.nameCaps, "SPA"), [
-			generateRowCategory("Spa Operation", "spa"),
-			generateRowCategory("Spa Attendant", "slaveAssignmentAttendant"),
-			generateRowCategory("Spa Slaves", "slaveAssignmentSpa")
+		addToggle(generateRowGroup(F.spa.nameCaps, "SPA"), [
+			...generateRowCategory("Spa Operation", "spa"),
+			...generateRowCategory("Spa Attendant", "slaveAssignmentAttendant"),
+			...generateRowCategory("Spa Slaves", "slaveAssignmentSpa")
 		]);
 
 		// HEADER: ARCOLOGY
 		createSectionHeader("Arcology");
 
 		// SLAVES
-		addToggle(generateRowGroup("Miscellaneous Slave Income and Expenses", "SLAVES"), [
-			generateRowCategory("Slave Porn", "porn"),
-			generateRowCategory("Slave Modifications", "slaveMod"),
-			generateRowCategory("Slave Surgery", "slaveSurgery"),
-			generateRowCategory("Slave Birthing", "birth")
+		addToggle(generateRowGroup("Slave Miscellaneous", "SLAVES"), [
+			...generateRowCategory("Slave Porn", "porn"),
+			...generateRowCategory("Slave Modifications", "slaveMod"),
+			...generateRowCategory("Slave Surgery", "slaveSurgery"),
+			...generateRowCategory("Slave Birthing", "birth")
 		]);
 
 		// MENIAL LABOR
 		addToggle(generateRowGroup("Menial Labor", "LABOR"), [
-			generateRowCategory("Menials: Slaves", "menialTrades"),
-			generateRowCategory("Menials: Fuckdolls", "fuckdolls"),
-			generateRowCategory("Menials: Bioreactors", "menialBioreactors")
+			...generateRowCategory("Menials: Slaves", "menialTrades"),
+			...generateRowCategory("Menials: Fuckdolls", "fuckdolls"),
+			...generateRowCategory("Menials: Bioreactors", "menialBioreactors")
 		]);
 
 		// FLIPPING
 		addToggle(generateRowGroup("Flipping", "FLIPPING"), [
-			generateRowCategory("Slave Transfer", "slaveTransfer"),
-			generateRowCategory("Menials", "menialTransfer"),
-			generateRowCategory("Fuckdolls", "fuckdollsTransfer"),
-			generateRowCategory("Bioreactors", "menialBioreactorsTransfer"),
-			generateRowCategory("Assistant: Menials", "menialTransferA"),
-			generateRowCategory("Assistant: Fuckdolls", "fuckdollsTransferA"),
-			generateRowCategory("Assistant: Bioreactors", "menialBioreactorsTransferA"),
-			generateRowCategory("Menial Retirement", "menialRetirement"),
-			generateRowCategory("Scientist Transfer", "labScientistsTransfer"),
-			generateRowCategory("Slave Babies", "babyTransfer")
+			...generateRowCategory("Slave Transfer", "slaveTransfer"),
+			...generateRowCategory("Menials", "menialTransfer"),
+			...generateRowCategory("Fuckdolls", "fuckdollsTransfer"),
+			...generateRowCategory("Bioreactors", "menialBioreactorsTransfer"),
+			...generateRowCategory("Assistant: Menials", "menialTransferA"),
+			...generateRowCategory("Assistant: Fuckdolls", "fuckdollsTransferA"),
+			...generateRowCategory("Assistant: Bioreactors", "menialBioreactorsTransferA"),
+			...generateRowCategory("Menial Retirement", "menialRetirement"),
+			...generateRowCategory("Scientist Transfer", "labScientistsTransfer"),
+			...generateRowCategory("Slave Babies", "babyTransfer")
 		]);
 
 		// FINANCIALS
 		addToggle(generateRowGroup("Financials", "FINANCIALS"), [
-			generateRowCategory("Weather", "weather"),
-			generateRowCategory("Rents", "rents"),
-			generateRowCategory("Fines", "fines"),
-			generateRowCategory("Events", "event"),
-			generateRowCategory("Capital Expenses", "capEx"),
-			generateRowCategory("Future Society Shaping", "futureSocieties"),
-			generateRowCategory("School Subsidy", "schoolBacking"),
-			generateRowCategory("Arcology conflict", "war"),
-			generateRowCategory("Cheating", "cheating")
+			...generateRowCategory("Weather", "weather"),
+			...generateRowCategory("Rents", "rents"),
+			...generateRowCategory("Fines", "fines"),
+			...generateRowCategory("Events", "event"),
+			...generateRowCategory("Capital Expenses", "capEx"),
+			...generateRowCategory("Future Society Shaping", "futureSocieties"),
+			...generateRowCategory("School Subsidy", "schoolBacking"),
+			...generateRowCategory("Arcology conflict", "war"),
+			...generateRowCategory("Cheating", "cheating")
 		]);
 
 		// POLICIES
 		addToggle(generateRowGroup("Policies", "POLICIES"), [
-			generateRowCategory("Policies", "policies"),
-			generateRowCategory("Subsidies and Barriers", "subsidiesAndBarriers")
+			...generateRowCategory("Policies", "policies"),
+			...generateRowCategory("Subsidies and Barriers", "subsidiesAndBarriers")
 		]);
 
 		// EDICTS
 		addToggle(generateRowGroup("Edicts", "EDICTS"), [
-			generateRowCategory("Edicts", "edicts")
+			...generateRowCategory("Edicts", "edicts")
 		]);
 
 		// PERSONAL FINANCE
 		addToggle(generateRowGroup("Personal Finance", "PERSONALFINANCE"), [
-			generateRowCategory("Personal Business", "personalBusiness"),
-			generateRowCategory("Personal Living Expenses", "personalLivingExpenses"),
-			generateRowCategory("Your skills", "PCSkills"),
-			generateRowCategory("Your training expenses", "PCtraining"),
-			generateRowCategory("Your food expenses", "PCdiet"),
-			generateRowCategory("Your drug expenses", "PCdrugs"),
-			generateRowCategory("Your medical expenses", "PCmedical"),
-			generateRowCategory("Your cosmetic expenses", "PCcosmetics"),
-			generateRowCategory("Citizen Orphanage", "citizenOrphanage"),
-			generateRowCategory("Private Orphanage", "privateOrphanage"),
-			generateRowCategory("Stock dividends", "stocks"),
-			generateRowCategory("Stock trading", "stocksTraded")
+			...generateRowCategory("Personal Business", "personalBusiness"),
+			...generateRowCategory("Personal Living Expenses", "personalLivingExpenses"),
+			...generateRowCategory("Your skills", "PCSkills"),
+			...generateRowCategory("Your training expenses", "PCtraining"),
+			...generateRowCategory("Your food expenses", "PCdiet"),
+			...generateRowCategory("Your drug expenses", "PCdrugs"),
+			...generateRowCategory("Your medical expenses", "PCmedical"),
+			...generateRowCategory("Your cosmetic expenses", "PCcosmetics"),
+			...generateRowCategory("Citizen Orphanage", "citizenOrphanage"),
+			...generateRowCategory("Private Orphanage", "privateOrphanage"),
+			...generateRowCategory("Stock dividends", "stocks"),
+			...generateRowCategory("Stock trading", "stocksTraded")
 		]);
 
 		// SECURITY
 		addToggle(generateRowGroup("Security", "SECURITY"), [
-			generateRowCategory("Mercenaries", "mercenaries"),
-			generateRowCategory("Security Expansion", "securityExpansion"),
-			generateRowCategory("Special Forces", "specialForces"),
-			generateRowCategory("Special Forces Capital Expenses", "specialForcesCap"),
-			generateRowCategory("Peacekeepers", "peacekeepers")
+			...generateRowCategory("Mercenaries", "mercenaries"),
+			...generateRowCategory("Security Expansion", "securityExpansion"),
+			...generateRowCategory("Special Forces", "specialForces"),
+			...generateRowCategory("Special Forces Capital Expenses", "specialForcesCap"),
+			...generateRowCategory("Peacekeepers", "peacekeepers")
 		]);
 	} else if (budgetType === "rep") {
 		// PENTHOUSE
 		addToggle(generateRowGroup("Penthouse", "PENTHOUSE"), [
-			generateRowCategory("Fucktoys", "fucktoy"),
-			generateRowCategory("Public servants", "publicServant"),
-			generateRowCategory("Free glory holes", "gloryhole"),
-			generateRowCategory("Concubine", "concubine"),
-			generateRowCategory("Head girl", "headGirl"),
-			generateRowCategory("Bodyguard", "bodyguard"),
-			generateRowCategory("Recruiter", "recruiter"),
+			...generateRowCategory("Fucktoys", "fucktoy"),
+			...generateRowCategory("Public servants", "publicServant"),
+			...generateRowCategory("Free glory holes", "gloryhole"),
+			...generateRowCategory("Concubine", "concubine"),
+			...generateRowCategory("Head girl", "headGirl"),
+			...generateRowCategory("Bodyguard", "bodyguard"),
+			...generateRowCategory("Recruiter", "recruiter"),
 		]);
 
 		// ARCADE
-		addToggle(generateRowGroup(f.arcade.nameCaps, "ARCADE"), [
-			generateRowCategory("Arcade Operation", "arcade"),
-			generateRowCategory("Free arcade", "gloryholeArcade")
+		addToggle(generateRowGroup(F.arcade.nameCaps, "ARCADE"), [
+			...generateRowCategory("Arcade Operation", "arcade"),
+			...generateRowCategory("Free arcade", "gloryholeArcade")
 		]);
 
 		// BROTHEL
-		addToggle(generateRowGroup(f.brothel.nameCaps, "BROTHEL"), [
-			generateRowCategory("Brothel Operation", "brothel"),
+		addToggle(generateRowGroup(F.brothel.nameCaps, "BROTHEL"), [
+			...generateRowCategory("Brothel Operation", "brothel"),
 		]);
 
 		// CLUB
-		addToggle(generateRowGroup(f.club.nameCaps, "CLUB"), [
-			generateRowCategory("Club Operation", "club"),
-			generateRowCategory("Club servants", "publicServantClub"),
-			generateRowCategory("Club ads", "clubAds"),
+		addToggle(generateRowGroup(F.club.nameCaps, "CLUB"), [
+			...generateRowCategory("Club Operation", "club"),
+			...generateRowCategory("Club servants", "publicServantClub"),
+			...generateRowCategory("Club ads", "clubAds"),
 		]);
 
 		// PIT
-		addToggle(generateRowGroup(f.pit.nameCaps, "PIT"), [
-			generateRowCategory("Pit Operation", "pit")
+		addToggle(generateRowGroup(F.pit.nameCaps, "PIT"), [
+			...generateRowCategory("Pit Operation", "pit")
 		]);
 
 		// SERVANTS' QUARTERS
-		addToggle(generateRowGroup(f.servantsQuarters.nameCaps, "SERVANTSQUARTERS"), [
-			generateRowCategory("Servants' Quarters Operation", "servantsQuarters"),
+		addToggle(generateRowGroup(F.servantsQuarters.nameCaps, "SERVANTSQUARTERS"), [
+			...generateRowCategory("Servants' Quarters Operation", "servantsQuarters"),
 		]);
 
 		// SPA
-		addToggle(generateRowGroup(f.spa.nameCaps, "SPA"), [
-			generateRowCategory("Spa Operation", "spa"),
+		addToggle(generateRowGroup(F.spa.nameCaps, "SPA"), [
+			...generateRowCategory("Spa Operation", "spa"),
 		]);
 
 		// FARMYARD
-		addToggle(generateRowGroup(f.farmyard.nameCaps, "FARMYARD"), [
-			generateRowCategory("Shows", "shows"),
+		addToggle(generateRowGroup(F.farmyard.nameCaps, "FARMYARD"), [
+			...generateRowCategory("Shows", "shows"),
 		]);
 
 		// HEADER: ARCOLOGY
 		createSectionHeader("Arcology");
 
 		// SLAVES
-		addToggle(generateRowGroup("Miscellaneous Slave Income and Expenses", "SLAVES"), [
-			generateRowCategory("Slave trust and devotion", "slavesViewOfPC"),
-			generateRowCategory("Prestigious slaves", "prestigiousSlave"),
-			generateRowCategory("Porn", "porn"),
-			generateRowCategory("Selling/buying major slaves", "slaveTransfer"),
-			generateRowCategory("Slave surgery", "babyTransfer"),
-			generateRowCategory("Birth", "birth"),
-			generateRowCategory("Slave retirement", "retirement"),
-			generateRowCategory("Vignettes", "vignette"),
-			generateRowCategory("Free Fuckdolls", "fuckdolls"),
+		addToggle(generateRowGroup("Slave Miscellaneous", "SLAVES"), [
+			...generateRowCategory("Slave trust and devotion", "slavesViewOfPC"),
+			...generateRowCategory("Prestigious slaves", "prestigiousSlave"),
+			...generateRowCategory("Porn", "porn"),
+			...generateRowCategory("Selling/buying major slaves", "slaveTransfer"),
+			...generateRowCategory("Slave surgery", "babyTransfer"),
+			...generateRowCategory("Birth", "birth"),
+			...generateRowCategory("Slave retirement", "retirement"),
+			...generateRowCategory("Vignettes", "vignette"),
+			...generateRowCategory("Free Fuckdolls", "fuckdolls"),
 		]);
 
 		// POLICIES
 		addToggle(generateRowGroup("Policies", "POLICIES"), [
-			generateRowCategory("Capital expenses", "capEx"),
-			generateRowCategory("Subsidies and Barriers", "subsidiesAndBarriers"),
-			generateRowCategory("Society shaping", "futureSocieties"),
-			generateRowCategory("Food", "food"),
+			...generateRowCategory("Capital expenses", "capEx"),
+			...generateRowCategory("Subsidies and Barriers", "subsidiesAndBarriers"),
+			...generateRowCategory("Society shaping", "futureSocieties"),
+			...generateRowCategory("Food", "food"),
 		]);
 
 		// EDICTS
 		addToggle(generateRowGroup("Edicts", "EDICTS"), [
-			generateRowCategory("Edicts", "edicts")
+			...generateRowCategory("Edicts", "edicts")
 		]);
 
 		// PERSONAL FINANCE
 		addToggle(generateRowGroup("Personal Finance", "PERSONALFINANCE"), [
-			generateRowCategory("Personal Business", "personalBusiness"),
-			generateRowCategory("Your appearance", "PCappearance"),
-			generateRowCategory("Your actions", "PCactions"),
-			generateRowCategory("Your skills", "PCRelationships"),
-			generateRowCategory("Slave relationships", "SlaveRelationships"),
-			generateRowCategory("Events", "event"),
+			...generateRowCategory("Personal Business", "personalBusiness"),
+			...generateRowCategory("Your appearance", "PCappearance"),
+			...generateRowCategory("Your actions", "PCactions"),
+			...generateRowCategory("Your skills", "PCRelationships"),
+			...generateRowCategory("Slave relationships", "SlaveRelationships"),
+			...generateRowCategory("Events", "event"),
 		]);
 
 		// SECURITY
 		addToggle(generateRowGroup("Security", "SECURITY"), [
-			generateRowCategory("Security Expansion", "securityExpansion"),
-			generateRowCategory("Special Forces", "specialForces"),
-			generateRowCategory("Conflict", "war"),
-			generateRowCategory("Peacekeepers", "peacekeepers")
+			...generateRowCategory("Security Expansion", "securityExpansion"),
+			...generateRowCategory("Special Forces", "specialForces"),
+			...generateRowCategory("Conflict", "war"),
+			...generateRowCategory("Peacekeepers", "peacekeepers")
 		]);
 
 		addToggle(generateRowGroup("Waste", "WASTE"), [
-			generateRowCategory("Reputation decay", "multiplier"),
-			generateRowCategory("Overflow (your reputation cannot be higher than 20k)", "overflow"),
-			generateRowCategory("Income curve", "curve")
+			...generateRowCategory("Reputation decay", "multiplier"),
+			...generateRowCategory("Overflow (your reputation cannot be higher than 20k)", "overflow"),
+			...generateRowCategory("Income curve", "curve")
 		]);
 	}
 
-
 	// BUDGET REPORT
 	generateSummary();
 
-	return table;
+	return tableDiv;
 
 	function generateHeader() {
-		const header = table.createTHead();
-		const row = header.insertRow();
-		const cell = row.insertCell();
-		let pent = document.createElement("h1");
-		pent.textContent = (budgetType === "cash") ? "Budget Overview" : "Reputation Overview";
-		cell.appendChild(pent);
-
-		for (let column of ["Income", "Expense", "Totals"]) {
-			let cell = document.createElement("th");
-			cell.textContent = column;
-			row.appendChild(cell);
-		}
+		App.UI.DOM.appendNewElement("div", tableDiv, (budgetType === "cash") ? "Budget Overview" : "Reputation Overview", ["header"]);
+		App.UI.DOM.appendNewElement("div", tableDiv, "Income", ["header"]);
+		App.UI.DOM.appendNewElement("div", tableDiv, "Expense", ["header"]);
+		App.UI.DOM.appendNewElement("div", tableDiv, "Totals", ["header"]);
 	}
 
 	function generateSummary() {
-		let row; let cell;
 		createSectionHeader("Summary Report");
 
-		row = table.insertRow();
-		cell = row.insertCell();
-		cell.append("Tracked totals");
+		App.UI.DOM.appendNewElement("div", tableDiv, "Tracked totals");
 
-		cell = row.insertCell();
 		// Make the total 0 first, otherwise it gets counted as part of the new total
 		V[income].Total = 0;
 		V[income].Total = hashSum(V[income]);
-		cell.append(formatColorDOM(Math.trunc(V[income].Total)));
-
-		cell = row.insertCell();
+		App.UI.DOM.appendNewElement("div", tableDiv, formatColorDOM(Math.trunc(V[income].Total)), ["number", "final-result"]);
 		V[expenses].Total = 0;
 		V[expenses].Total = hashSum(V[expenses]);
-		cell.append(formatColorDOM(Math.trunc(V[expenses].Total)));
-
-		cell = row.insertCell();
-		cell.append(formatColorDOM(Math.trunc(V[income].Total + V[expenses].Total)));
-		flipColors(row);
+		App.UI.DOM.appendNewElement("div", tableDiv, formatColorDOM(Math.trunc(V[expenses].Total)),
+			["number", "final-result"]);
+		App.UI.DOM.appendNewElement("div", tableDiv, formatColorDOM(Math.trunc(V[income].Total + V[expenses].Total)),
+			["number", "final-result"]);
 
 		if (budgetType === "cash") {
-			row = table.insertRow();
-			cell = row.insertCell();
-			cell.append(`Expenses budget for week ${V.week + 1}`);
-			row.insertCell();
-			cell = row.insertCell();
-			cell.append(formatColorDOM(-V.costs));
-			flipColors(row);
+			App.UI.DOM.appendNewElement("div", tableDiv, `Expenses budget for week ${V.week + 1}`);
+			tableDiv.append(document.createElement("div"));
+			App.UI.DOM.appendNewElement("div", tableDiv, formatColorDOM(-V.costs), ["number"]);
+			tableDiv.append(document.createElement("div"));
 		}
 
-		row = table.insertRow();
-		cell = row.insertCell();
-		cell.append(`Last week actuals`);
-		row.insertCell();
-		row.insertCell();
-		cell = row.insertCell();
+		App.UI.DOM.appendNewElement("div", tableDiv, `Last week actuals`);
+		tableDiv.append(document.createElement("div"));
+		tableDiv.append(document.createElement("div"));
 		if (budgetType === "cash") {
-			cell.append(formatColorDOM(V.cash - V.cashLastWeek));
+			App.UI.DOM.appendNewElement("div", tableDiv, formatColorDOM(V.cash - V.cashLastWeek), ["number"]);
 		} else {
-			cell.append(formatColorDOM(V.rep - V.repLastWeek));
+			App.UI.DOM.appendNewElement("div", tableDiv, formatColorDOM(V.rep - V.repLastWeek), ["number"]);
 		}
-		flipColors(row);
 
-		row = table.insertRow();
 		if (
 			(budgetType === "cash" && (V.cash - V.cashLastWeek) === (V.lastWeeksCashIncome.Total + V.lastWeeksCashExpenses.Total)) ||
 			(budgetType === "rep" && (V.rep - V.repLastWeek) === (V.lastWeeksRepIncome.Total + V.lastWeeksRepExpenses.Total))
 		) {
-			cell = row.insertCell();
-			const span = document.createElement('span');
-			span.className = "green";
-			span.textContent = `The books are balanced, ${properTitle()}!`;
-			cell.append(span);
+			App.UI.DOM.appendNewElement("div", tableDiv, `The books are balanced, ${properTitle()}!`, ["green", "last-row"]);
+			tableDiv.append(document.createElement("div"));
+			tableDiv.append(document.createElement("div"));
+			tableDiv.append(document.createElement("div"));
 		} else {
-			cell = row.insertCell();
-			cell.append("Transaction tracking off by:");
-			row.insertCell();
-			row.insertCell();
-			cell = row.insertCell();
+			App.UI.DOM.appendNewElement("div", tableDiv, "Transaction tracking off by", ["red", "last-row"]);
+			tableDiv.append(document.createElement("div"));
+			tableDiv.append(document.createElement("div"));
 			if (budgetType === "cash") {
-				cell.append(formatColorDOM((V.cash - V.cashLastWeek) - (V.lastWeeksCashIncome.Total + V.lastWeeksCashExpenses.Total)));
+				App.UI.DOM.appendNewElement("div", tableDiv, formatColorDOM(
+					(V.cash - V.cashLastWeek) - (V.lastWeeksCashIncome.Total + V.lastWeeksCashExpenses.Total)
+				), ["number"]);
 			} else {
-				cell.append(formatColorDOM((V.rep - V.repLastWeek) - (V.lastWeeksRepIncome.Total + V.lastWeeksRepExpenses.Total)));
+				App.UI.DOM.appendNewElement("div", tableDiv, formatColorDOM(
+					(V.rep - V.repLastWeek) - (V.lastWeeksRepIncome.Total + V.lastWeeksRepExpenses.Total)
+				), ["number"]);
 			}
 		}
-		flipColors(row);
 	}
 
 	function createSectionHeader(text) {
-		coloredRow = true; // make sure the following section begins with color.
-		const row = table.insertRow();
-		const cell = row.insertCell();
-		const headline = document.createElement('h2');
-		headline.textContent = text;
-		cell.append(headline);
+		App.UI.DOM.appendNewElement("div", tableDiv, text, ["section"]);
+		App.UI.DOM.appendNewElement("div", tableDiv, null, ["section"]);
+		App.UI.DOM.appendNewElement("div", tableDiv, null, ["section"]);
+		App.UI.DOM.appendNewElement("div", tableDiv, null, ["section"]);
 	}
 
 	function generateRowCategory(node, category) {
-		if (category === "") {
-			const row = table.insertRow();
-			row.append(document.createElement('br'));
-			row.insertCell();
-			row.insertCell();
-			row.insertCell();
-			flipColors(row);
-			return row;
-		}
-
+		const r = [];
 		if (V[income][category] || V[expenses][category] || V.showAllEntries[budgetType === "cash" ? "costsBudget" : "repBudget"]) {
-			const row = table.insertRow();
-			let cell = row.insertCell();
-			cell.append(node);
-			cell = row.insertCell();
-			cell.append(formatColorDOM(V[income][category]));
-			cell = row.insertCell();
-			cell.append(formatColorDOM(-Math.abs(V[expenses][category])));
-			flipColors(row);
-			cell = row.insertCell();
-			cell.append(formatColorDOM(V[income][category] + V[expenses][category]));
-			return row;
+			r.push(App.UI.DOM.appendNewElement("div", tableDiv, node, ["entry"]));
+			r.push(App.UI.DOM.appendNewElement("div", tableDiv, formatColorDOM(V[income][category]),
+				["number", "entry"]));
+			r.push(App.UI.DOM.appendNewElement("div", tableDiv, formatColorDOM(-Math.abs(V[expenses][category])),
+				["number", "entry"]));
+			r.push(App.UI.DOM.appendNewElement("div", tableDiv, formatColorDOM(V[income][category] + V[expenses][category]),
+				["number", "entry"]));
 		}
+		return r;
 	}
 
 	function generateRowGroup(title, name) {
@@ -503,35 +460,48 @@ App.Budget.table = function(budgetType) {
 		const groupIn = members.map((k) => V[income][k]).reduce((acc, cur) => acc + cur);
 		const groupEx = members.map((k) => V[expenses][k]).reduce((acc, cur) => acc + cur);
 
+		const r = [];
 		if (groupIn || groupEx || V.showAllEntries[budgetType === "cash" ? "costsBudget" : "repBudget"]) {
-			const row = table.insertRow();
-			let cell = row.insertCell();
-			const headline = document.createElement('h3');
-			headline.textContent = title;
-			cell.append(headline);
-			cell = row.insertCell();
-			cell.append(formatColorDOM(groupIn));
-			cell = row.insertCell();
-			cell.append(formatColorDOM(groupEx));
-			cell = row.insertCell();
-			cell.append(formatColorDOM(groupIn + groupEx));
-			return row;
+			r.push(App.UI.DOM.appendNewElement("div", tableDiv, title, ["group"]));
+			r.push(App.UI.DOM.appendNewElement("div", tableDiv, formatColorDOM(groupIn), ["group", "number"]));
+			r.push(App.UI.DOM.appendNewElement("div", tableDiv, formatColorDOM(groupEx), ["group", "number"]));
+			r.push(App.UI.DOM.appendNewElement("div", tableDiv, formatColorDOM(groupIn + groupEx),
+				["group", "number"]));
 		}
+		return r;
 	}
 
 	/**
-	 * @param {HTMLTableRowElement} head
-	 * @param {Array<HTMLTableRowElement>} content
+	 * @param {Array<HTMLDivElement>} heads
+	 * @param {Array<HTMLDivElement>} content
 	 */
-	function addToggle(head, content) {
-		if (!head) {
+	function addToggle(heads, content) {
+		heads = heads.filter(e => !!e);
+		if (heads.length === 0) {
 			return;
 		}
 		content = content.filter(e => !!e);
 		if (content.length === 0) {
 			return;
 		}
-		App.UI.DOM.elementToggle(head, content);
+		// Based on App.UI.DOM.elementToggle(), which only allows one toggle element
+		for (let htmlElement of heads) {
+			htmlElement.classList.add("accordion", "closed");
+		}
+		for (let htmlElement of content) {
+			htmlElement.classList.add("accordion-content", "hidden");
+		}
+		const toggle = () => {
+			for (let htmlElement of heads) {
+				htmlElement.classList.toggle("closed");
+			}
+			for (let htmlElement of content) {
+				htmlElement.classList.toggle("hidden");
+			}
+		};
+		for (let htmlElement of heads) {
+			htmlElement.onclick = toggle;
+		}
 	}
 
 	function formatColorDOM(num, invert = false) {
@@ -556,11 +526,4 @@ App.Budget.table = function(budgetType) {
 		}
 		return span;
 	}
-
-	function flipColors(row) {
-		if (coloredRow) {
-			row.classList.add("colored");
-		}
-		coloredRow = !coloredRow;
-	}
 };
-- 
GitLab