diff --git a/accounts_handler.php b/accounts_handler.php
index 5d862b900783304ae9b9493d9f2b84c44e9b3330..34e6c0a0ecdeeafcda95822bfea2dae3314f74fc 100644
--- a/accounts_handler.php
+++ b/accounts_handler.php
@@ -2,27 +2,14 @@
 // This file carries functions related to accounts.
 
 function get_avatar_url($bcid):string {
-	global $pdo;
-
-	$sql = "SELECT has_pfp FROM `accounts` WHERE id = ?";
-
-	try {
-		$stmt = $pdo -> prepare($sql);
-		$stmt->execute([$bcid]);
-		$has_pfp = $stmt->fetch();
-	} catch (PDOException $e) {
-		http_response_code(500);
-		die($e);
-	}
 
-	$appendix = "default.png";
+    $exists = db_execute('SELECT public FROM avatars WHERE id = ? LIMIT 1', [$bcid]);
 
-	if ($has_pfp['has_pfp']) {
-		$appendix = $bcid;
-	}
-
-	return 'https://cdn.byecorps.com/id/profile/'.$appendix;
+    if (empty($exists)) {
+        return '/assets/default.png';
+    }
 
+    return '/public/avatars/' . $bcid;
 }
 
 function get_display_name($bcid, $use_bcid_fallback=true, $put_bcid_in_parenthesis=false, $format_bcid=false):string {
diff --git a/admin_apps_create.php b/admin_apps_create.php
index 1e495fbbbaf2a590e5ce4fbd5580e87fe77e7e5b..c769a22edeaf0cd9a920689a805c161562eca09b 100644
--- a/admin_apps_create.php
+++ b/admin_apps_create.php
@@ -23,11 +23,11 @@ if ($_SERVER['REQUEST_METHOD'] == "POST") {
 
 <form method="post">
 	<label for="title">Title</label>
-	<input type="text" name="title" id="title">
+	<input type="text" required name="title" id="title">
 	<label for="description">Description</label>
 	<textarea name="description" id="description" cols="30" rows="10"></textarea>
 	<label for="owner">App owner</label>
-	<select name="owner" id="owner">
+	<select name="owner" required id="owner">
 		<?php
 			$users = db_query("SELECT * FROM accounts");
 			foreach ($users as $row) {
@@ -36,10 +36,14 @@ if ($_SERVER['REQUEST_METHOD'] == "POST") {
 		?>
 	</select>
     <label for="type">App type</label>
-    <select name="type" id="type">
+    <select name="type" required id="type">
         <option value="null">None</option>
         <option value="basic_login">Basic login</option>
     </select>
+
+    <label for="app_icon">App icon</label>
+    <input type="file" id="app_icon" name="app_icon" />
+
     <label for="callback">Callback</label>
     <input type="url" id="callback" name="callback" />
 	<button type="submit" class="primary">Create app</button>
diff --git a/admin_initdatabase.php b/admin_initdatabase.php
index 838580c4140878bb99ae8b273fb41fb3393a2487..fb860c9775e5161cd3c7e72f7d1d6a1286df05ca 100644
--- a/admin_initdatabase.php
+++ b/admin_initdatabase.php
@@ -119,6 +119,23 @@ if ($_SERVER["REQUEST_METHOD"] == "POST") {
             echo('<p>An error occurred: '. $e->getMessage() .'. Most likely this is already set.');
         }
 
+        echo '<p>Create the `tokens` table';
+
+        try {
+            db_query('CREATE TABLE `badge_owners` (
+  `badge_id` int(11) NOT NULL,
+  `owner_id` varchar(7) NOT NULL,
+  `earned` timestamp NULL DEFAULT current_timestamp(),
+  `info` text DEFAULT NULL COMMENT \'App may attach more info about how the badge was won (Killed "CoolGamer69 in battle!")\',
+      
+    constraint badges_owners_badge
+        foreign key (badge_id) references badges (id),
+    constraint badges_owners_owner
+            foreign key (owner_id) references accounts (id)
+);');
+        } catch (PDOException $e) {
+            echo('<p>An error occurred: ' . $e->getMessage() . '. Most likely this is already set.');
+        }
 
         echo "<p>Database initialised.</p>";
     }
diff --git a/api_handler.php b/api_handler.php
index 64e3c59e5a803c766bcb7ad715b1261bbc8e13c6..34c5c5a0d48dabf35a409a0903099ebd3c3461ae 100644
--- a/api_handler.php
+++ b/api_handler.php
@@ -53,6 +53,19 @@ function api_health_check(): array
     return ["message" => "Science compels us to explode the sun!", "time" => time(), "response_code" => 200];
 }
 
+// Potentially authenticated image endpoints
+
+function get_avatar(): array
+{
+    if (!array_key_exists('id', $query)) {
+        return [
+            'response_code' => 404,
+            'message' => 'ID not assigned/found'
+        ];
+    }
+    $user_id = $query['id'];
+}
+
 // User (REQUIRES AUTHORISATION)
 
 function api_user_info() {
@@ -94,7 +107,10 @@ $api_routes = [ // base url is base_url.'/api'
     "/status" => "api_health_check",
 
     // Account stuff
-    "/account/me" => "api_user_info"
+    "/account/me" => "api_user_info",
+
+    // Get avatar
+    "/avatars/get" => "get_avatar"
 ];
 
 $path = str_replace("/api", "", $path);
@@ -107,7 +123,11 @@ if (isset($api_routes[$path])) {
             "message" => "Token expired or invalid."
         ]));
     }
-    echo json_encode($api_routes[$path]());
+    $response = $api_routes[$path]();
+    if (array_key_exists('response_code', $response)) {
+        http_response_code($response['response_code']);
+    }
+    echo json_encode($response);
 } else {
     http_response_code(404);
     echo (json_encode([
diff --git a/assets/icons/apple-icon-180.png b/assets/icons/apple-icon-180.png
new file mode 100644
index 0000000000000000000000000000000000000000..f07b87c89f135d2996cc9bca2cbc94c5493f5cc7
Binary files /dev/null and b/assets/icons/apple-icon-180.png differ
diff --git a/assets/icons/apple-splash-1125-2436.png b/assets/icons/apple-splash-1125-2436.png
new file mode 100644
index 0000000000000000000000000000000000000000..50920b97b8336200fa3538251b3e401f13f82176
Binary files /dev/null and b/assets/icons/apple-splash-1125-2436.png differ
diff --git a/assets/icons/apple-splash-1136-640.png b/assets/icons/apple-splash-1136-640.png
new file mode 100644
index 0000000000000000000000000000000000000000..235e1f97661f022be126214033da3ab1416f4e21
Binary files /dev/null and b/assets/icons/apple-splash-1136-640.png differ
diff --git a/assets/icons/apple-splash-1170-2532.png b/assets/icons/apple-splash-1170-2532.png
new file mode 100644
index 0000000000000000000000000000000000000000..c6cd4a14d981cb7e3f5c66917698e312042b608c
Binary files /dev/null and b/assets/icons/apple-splash-1170-2532.png differ
diff --git a/assets/icons/apple-splash-1179-2556.png b/assets/icons/apple-splash-1179-2556.png
new file mode 100644
index 0000000000000000000000000000000000000000..5f90799a900db4524bee7e853a59e7aa7c9e28b3
Binary files /dev/null and b/assets/icons/apple-splash-1179-2556.png differ
diff --git a/assets/icons/apple-splash-1242-2208.png b/assets/icons/apple-splash-1242-2208.png
new file mode 100644
index 0000000000000000000000000000000000000000..2e56b173c742033861397e73a5d43d13fa89bb5f
Binary files /dev/null and b/assets/icons/apple-splash-1242-2208.png differ
diff --git a/assets/icons/apple-splash-1242-2688.png b/assets/icons/apple-splash-1242-2688.png
new file mode 100644
index 0000000000000000000000000000000000000000..45c72d46c48e015edf310793b4ba6d92755a33fb
Binary files /dev/null and b/assets/icons/apple-splash-1242-2688.png differ
diff --git a/assets/icons/apple-splash-1284-2778.png b/assets/icons/apple-splash-1284-2778.png
new file mode 100644
index 0000000000000000000000000000000000000000..5d26b9d6a162b3aa78603bab754eabf5fa99b02b
Binary files /dev/null and b/assets/icons/apple-splash-1284-2778.png differ
diff --git a/assets/icons/apple-splash-1290-2796.png b/assets/icons/apple-splash-1290-2796.png
new file mode 100644
index 0000000000000000000000000000000000000000..cee06dbbb8b2de6722bfbc0d2f5f7e9201eac4fa
Binary files /dev/null and b/assets/icons/apple-splash-1290-2796.png differ
diff --git a/assets/icons/apple-splash-1334-750.png b/assets/icons/apple-splash-1334-750.png
new file mode 100644
index 0000000000000000000000000000000000000000..fb37712491698fdc9d653d7e538d3a16259daeef
Binary files /dev/null and b/assets/icons/apple-splash-1334-750.png differ
diff --git a/assets/icons/apple-splash-1488-2266.png b/assets/icons/apple-splash-1488-2266.png
new file mode 100644
index 0000000000000000000000000000000000000000..657fcb31e56d3c00e846ffc45d9bea7062c82fd7
Binary files /dev/null and b/assets/icons/apple-splash-1488-2266.png differ
diff --git a/assets/icons/apple-splash-1536-2048.png b/assets/icons/apple-splash-1536-2048.png
new file mode 100644
index 0000000000000000000000000000000000000000..c313eec3775251e5d3334bcdf6937cf53be6848e
Binary files /dev/null and b/assets/icons/apple-splash-1536-2048.png differ
diff --git a/assets/icons/apple-splash-1620-2160.png b/assets/icons/apple-splash-1620-2160.png
new file mode 100644
index 0000000000000000000000000000000000000000..7e08f6d724ade8c556a3c48c08137261c8fde802
Binary files /dev/null and b/assets/icons/apple-splash-1620-2160.png differ
diff --git a/assets/icons/apple-splash-1640-2360.png b/assets/icons/apple-splash-1640-2360.png
new file mode 100644
index 0000000000000000000000000000000000000000..b400cd308b32ad1d04bb18a3348f3e3a9d1b4270
Binary files /dev/null and b/assets/icons/apple-splash-1640-2360.png differ
diff --git a/assets/icons/apple-splash-1668-2224.png b/assets/icons/apple-splash-1668-2224.png
new file mode 100644
index 0000000000000000000000000000000000000000..f01df0b8c790be0890a4044abbe50d231617cbd8
Binary files /dev/null and b/assets/icons/apple-splash-1668-2224.png differ
diff --git a/assets/icons/apple-splash-1668-2388.png b/assets/icons/apple-splash-1668-2388.png
new file mode 100644
index 0000000000000000000000000000000000000000..41f4ca6780f387ab26cb46b3839cfb4423c5b609
Binary files /dev/null and b/assets/icons/apple-splash-1668-2388.png differ
diff --git a/assets/icons/apple-splash-1792-828.png b/assets/icons/apple-splash-1792-828.png
new file mode 100644
index 0000000000000000000000000000000000000000..2d7e31267eded3790d91f9c7cd70aaefa9b0e48a
Binary files /dev/null and b/assets/icons/apple-splash-1792-828.png differ
diff --git a/assets/icons/apple-splash-2048-1536.png b/assets/icons/apple-splash-2048-1536.png
new file mode 100644
index 0000000000000000000000000000000000000000..a53ba1c6cf49be2e67de301f6eec55585a6a4d0b
Binary files /dev/null and b/assets/icons/apple-splash-2048-1536.png differ
diff --git a/assets/icons/apple-splash-2048-2732.png b/assets/icons/apple-splash-2048-2732.png
new file mode 100644
index 0000000000000000000000000000000000000000..75dcd5f3ae0de1f09db1e13167367bab02147c34
Binary files /dev/null and b/assets/icons/apple-splash-2048-2732.png differ
diff --git a/assets/icons/apple-splash-2160-1620.png b/assets/icons/apple-splash-2160-1620.png
new file mode 100644
index 0000000000000000000000000000000000000000..760d67a888dd1719af2af0b503597299bd5bffa1
Binary files /dev/null and b/assets/icons/apple-splash-2160-1620.png differ
diff --git a/assets/icons/apple-splash-2208-1242.png b/assets/icons/apple-splash-2208-1242.png
new file mode 100644
index 0000000000000000000000000000000000000000..1b5012d4f0bab25c155c3e4734a7c13d4d5a58a0
Binary files /dev/null and b/assets/icons/apple-splash-2208-1242.png differ
diff --git a/assets/icons/apple-splash-2224-1668.png b/assets/icons/apple-splash-2224-1668.png
new file mode 100644
index 0000000000000000000000000000000000000000..24d1b32565d5304d4d697dec113b95a8840c87cb
Binary files /dev/null and b/assets/icons/apple-splash-2224-1668.png differ
diff --git a/assets/icons/apple-splash-2266-1488.png b/assets/icons/apple-splash-2266-1488.png
new file mode 100644
index 0000000000000000000000000000000000000000..fa7ff4ee0aa9e55aa9a7317dc916cb5b4dcdc0ff
Binary files /dev/null and b/assets/icons/apple-splash-2266-1488.png differ
diff --git a/assets/icons/apple-splash-2360-1640.png b/assets/icons/apple-splash-2360-1640.png
new file mode 100644
index 0000000000000000000000000000000000000000..74192f744471ed19a0b948dc4128faac759c707c
Binary files /dev/null and b/assets/icons/apple-splash-2360-1640.png differ
diff --git a/assets/icons/apple-splash-2388-1668.png b/assets/icons/apple-splash-2388-1668.png
new file mode 100644
index 0000000000000000000000000000000000000000..28956138fd56d27c5e014a81275c327889e6c5ee
Binary files /dev/null and b/assets/icons/apple-splash-2388-1668.png differ
diff --git a/assets/icons/apple-splash-2436-1125.png b/assets/icons/apple-splash-2436-1125.png
new file mode 100644
index 0000000000000000000000000000000000000000..d4b6f87215d890a45f561fd0949edcf8701bdd8e
Binary files /dev/null and b/assets/icons/apple-splash-2436-1125.png differ
diff --git a/assets/icons/apple-splash-2532-1170.png b/assets/icons/apple-splash-2532-1170.png
new file mode 100644
index 0000000000000000000000000000000000000000..b8ca512a0fabc881e1ab01a2fd4a59c854c078f6
Binary files /dev/null and b/assets/icons/apple-splash-2532-1170.png differ
diff --git a/assets/icons/apple-splash-2556-1179.png b/assets/icons/apple-splash-2556-1179.png
new file mode 100644
index 0000000000000000000000000000000000000000..44a462f07bc14bc2fc2e6ca4c24abf548a97cedb
Binary files /dev/null and b/assets/icons/apple-splash-2556-1179.png differ
diff --git a/assets/icons/apple-splash-2688-1242.png b/assets/icons/apple-splash-2688-1242.png
new file mode 100644
index 0000000000000000000000000000000000000000..6c8da45f5e4ab99d344da8c0b255b7a363c95b9b
Binary files /dev/null and b/assets/icons/apple-splash-2688-1242.png differ
diff --git a/assets/icons/apple-splash-2732-2048.png b/assets/icons/apple-splash-2732-2048.png
new file mode 100644
index 0000000000000000000000000000000000000000..6d325da141e93fba0e7959687c6e32d2b0bfee56
Binary files /dev/null and b/assets/icons/apple-splash-2732-2048.png differ
diff --git a/assets/icons/apple-splash-2778-1284.png b/assets/icons/apple-splash-2778-1284.png
new file mode 100644
index 0000000000000000000000000000000000000000..f3d1776fdc28b66c1c03e5aadad51db61cc4ce9d
Binary files /dev/null and b/assets/icons/apple-splash-2778-1284.png differ
diff --git a/assets/icons/apple-splash-2796-1290.png b/assets/icons/apple-splash-2796-1290.png
new file mode 100644
index 0000000000000000000000000000000000000000..e906f5e324f8ef8943d0b0a47db4fab149682d06
Binary files /dev/null and b/assets/icons/apple-splash-2796-1290.png differ
diff --git a/assets/icons/apple-splash-640-1136.png b/assets/icons/apple-splash-640-1136.png
new file mode 100644
index 0000000000000000000000000000000000000000..1e8208d9a18f8aa37048edc74032e9fb8a988450
Binary files /dev/null and b/assets/icons/apple-splash-640-1136.png differ
diff --git a/assets/icons/apple-splash-750-1334.png b/assets/icons/apple-splash-750-1334.png
new file mode 100644
index 0000000000000000000000000000000000000000..a9ae50458736d90a8ac0082dae5bd5653f009d65
Binary files /dev/null and b/assets/icons/apple-splash-750-1334.png differ
diff --git a/assets/icons/apple-splash-828-1792.png b/assets/icons/apple-splash-828-1792.png
new file mode 100644
index 0000000000000000000000000000000000000000..668f2f710ae0622b8b58863e1db173af18f8eb13
Binary files /dev/null and b/assets/icons/apple-splash-828-1792.png differ
diff --git a/assets/icons/manifest-icon-192.maskable.png b/assets/icons/manifest-icon-192.maskable.png
new file mode 100644
index 0000000000000000000000000000000000000000..f7735bce248c912588326cf1a2ae3c5fe9ecbe81
Binary files /dev/null and b/assets/icons/manifest-icon-192.maskable.png differ
diff --git a/assets/icons/manifest-icon-512.maskable.png b/assets/icons/manifest-icon-512.maskable.png
new file mode 100644
index 0000000000000000000000000000000000000000..ad7db2bb6465cf9efa78120d311448c09d1b5fae
Binary files /dev/null and b/assets/icons/manifest-icon-512.maskable.png differ
diff --git a/dashboard.php b/dashboard.php
new file mode 100644
index 0000000000000000000000000000000000000000..58d5592d91d97bf9efddc189973ee03552cccbcf
--- /dev/null
+++ b/dashboard.php
@@ -0,0 +1,12 @@
+<?php
+
+if (!$_SESSION['auth']) {
+    echo("You are being redirected...");
+    http_response_code(302);
+    header('Location '. BASE_URL .'/signin?callback=/dashboard');
+    die();
+}
+
+?>
+
+<h1>Hey there <?= $user['display_name'] ?>!</h1>
diff --git a/database.php b/database.php
index bd1fcbd9487b4e596f9438e2b0d3269c225106a0..9d794f97b38ab680bb846efe50baa951bc3200f4 100644
--- a/database.php
+++ b/database.php
@@ -10,6 +10,15 @@ function db_execute($sql, $variables=[]) {
 
 }
 
+function db_execute_all($sql, $variables=[]) {
+    global $pdo;
+
+    $stmt = $pdo->prepare($sql);
+    $stmt->execute($variables);
+    return $stmt->fetchAll();
+
+}
+
 function db_query($sql) {
 	global $pdo;
 
diff --git a/head.php b/head.php
index 2d5c6551c5b885fd9e1a649c95bdd8f8be085702..37e681ad809baedbdc1312971eeda4659d7ed6ad 100644
--- a/head.php
+++ b/head.php
@@ -1,13 +1,55 @@
-<meta charset="UTF-8">
-<meta http-equiv="X-UA-Compatible" content="IE=edge">
-<meta name="viewport" content="width=device-width, initial-scale=1.0">
+
 <script
         src="https://js.sentry-cdn.com/15d71a72983891268a3298cdc2bd1498.min.js"
         crossorigin="anonymous"
 ></script>
-<title><?php if (isset($doc_title)) { echo $doc_title." | "; } ?>ByeCorps ID</title>
+<!--<title>--><?php //if (isset($doc_title)) { echo $doc_title." | "; } ?><!--ByeCorps ID</title>-->
+
+<link rel="shortcut icon" href="favicon.svg" type="image/svg" />
+
+<link rel="manifest" href="manifest.json" />
+
+<!-- 0_o -->
+
+<link rel="apple-touch-icon" href="/assets/icons/apple-icon-180.png">
+
+<meta name="apple-mobile-web-app-capable" content="yes">
+
+<link rel="apple-touch-startup-image" href="/assets/icons/apple-splash-2048-2732.png" media="(device-width: 1024px) and (device-height: 1366px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)">
+<link rel="apple-touch-startup-image" href="/assets/icons/apple-splash-2732-2048.png" media="(device-width: 1024px) and (device-height: 1366px) and (-webkit-device-pixel-ratio: 2) and (orientation: landscape)">
+<link rel="apple-touch-startup-image" href="/assets/icons/apple-splash-1668-2388.png" media="(device-width: 834px) and (device-height: 1194px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)">
+<link rel="apple-touch-startup-image" href="/assets/icons/apple-splash-2388-1668.png" media="(device-width: 834px) and (device-height: 1194px) and (-webkit-device-pixel-ratio: 2) and (orientation: landscape)">
+<link rel="apple-touch-startup-image" href="/assets/icons/apple-splash-1536-2048.png" media="(device-width: 768px) and (device-height: 1024px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)">
+<link rel="apple-touch-startup-image" href="/assets/icons/apple-splash-2048-1536.png" media="(device-width: 768px) and (device-height: 1024px) and (-webkit-device-pixel-ratio: 2) and (orientation: landscape)">
+<link rel="apple-touch-startup-image" href="/assets/icons/apple-splash-1488-2266.png" media="(device-width: 744px) and (device-height: 1133px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)">
+<link rel="apple-touch-startup-image" href="/assets/icons/apple-splash-2266-1488.png" media="(device-width: 744px) and (device-height: 1133px) and (-webkit-device-pixel-ratio: 2) and (orientation: landscape)">
+<link rel="apple-touch-startup-image" href="/assets/icons/apple-splash-1640-2360.png" media="(device-width: 820px) and (device-height: 1180px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)">
+<link rel="apple-touch-startup-image" href="/assets/icons/apple-splash-2360-1640.png" media="(device-width: 820px) and (device-height: 1180px) and (-webkit-device-pixel-ratio: 2) and (orientation: landscape)">
+<link rel="apple-touch-startup-image" href="/assets/icons/apple-splash-1668-2224.png" media="(device-width: 834px) and (device-height: 1112px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)">
+<link rel="apple-touch-startup-image" href="/assets/icons/apple-splash-2224-1668.png" media="(device-width: 834px) and (device-height: 1112px) and (-webkit-device-pixel-ratio: 2) and (orientation: landscape)">
+<link rel="apple-touch-startup-image" href="/assets/icons/apple-splash-1620-2160.png" media="(device-width: 810px) and (device-height: 1080px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)">
+<link rel="apple-touch-startup-image" href="/assets/icons/apple-splash-2160-1620.png" media="(device-width: 810px) and (device-height: 1080px) and (-webkit-device-pixel-ratio: 2) and (orientation: landscape)">
+<link rel="apple-touch-startup-image" href="/assets/icons/apple-splash-1290-2796.png" media="(device-width: 430px) and (device-height: 932px) and (-webkit-device-pixel-ratio: 3) and (orientation: portrait)">
+<link rel="apple-touch-startup-image" href="/assets/icons/apple-splash-2796-1290.png" media="(device-width: 430px) and (device-height: 932px) and (-webkit-device-pixel-ratio: 3) and (orientation: landscape)">
+<link rel="apple-touch-startup-image" href="/assets/icons/apple-splash-1179-2556.png" media="(device-width: 393px) and (device-height: 852px) and (-webkit-device-pixel-ratio: 3) and (orientation: portrait)">
+<link rel="apple-touch-startup-image" href="/assets/icons/apple-splash-2556-1179.png" media="(device-width: 393px) and (device-height: 852px) and (-webkit-device-pixel-ratio: 3) and (orientation: landscape)">
+<link rel="apple-touch-startup-image" href="/assets/icons/apple-splash-1284-2778.png" media="(device-width: 428px) and (device-height: 926px) and (-webkit-device-pixel-ratio: 3) and (orientation: portrait)">
+<link rel="apple-touch-startup-image" href="/assets/icons/apple-splash-2778-1284.png" media="(device-width: 428px) and (device-height: 926px) and (-webkit-device-pixel-ratio: 3) and (orientation: landscape)">
+<link rel="apple-touch-startup-image" href="/assets/icons/apple-splash-1170-2532.png" media="(device-width: 390px) and (device-height: 844px) and (-webkit-device-pixel-ratio: 3) and (orientation: portrait)">
+<link rel="apple-touch-startup-image" href="/assets/icons/apple-splash-2532-1170.png" media="(device-width: 390px) and (device-height: 844px) and (-webkit-device-pixel-ratio: 3) and (orientation: landscape)">
+<link rel="apple-touch-startup-image" href="/assets/icons/apple-splash-1125-2436.png" media="(device-width: 375px) and (device-height: 812px) and (-webkit-device-pixel-ratio: 3) and (orientation: portrait)">
+<link rel="apple-touch-startup-image" href="/assets/icons/apple-splash-2436-1125.png" media="(device-width: 375px) and (device-height: 812px) and (-webkit-device-pixel-ratio: 3) and (orientation: landscape)">
+<link rel="apple-touch-startup-image" href="/assets/icons/apple-splash-1242-2688.png" media="(device-width: 414px) and (device-height: 896px) and (-webkit-device-pixel-ratio: 3) and (orientation: portrait)">
+<link rel="apple-touch-startup-image" href="/assets/icons/apple-splash-2688-1242.png" media="(device-width: 414px) and (device-height: 896px) and (-webkit-device-pixel-ratio: 3) and (orientation: landscape)">
+<link rel="apple-touch-startup-image" href="/assets/icons/apple-splash-828-1792.png" media="(device-width: 414px) and (device-height: 896px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)">
+<link rel="apple-touch-startup-image" href="/assets/icons/apple-splash-1792-828.png" media="(device-width: 414px) and (device-height: 896px) and (-webkit-device-pixel-ratio: 2) and (orientation: landscape)">
+<link rel="apple-touch-startup-image" href="/assets/icons/apple-splash-1242-2208.png" media="(device-width: 414px) and (device-height: 736px) and (-webkit-device-pixel-ratio: 3) and (orientation: portrait)">
+<link rel="apple-touch-startup-image" href="/assets/icons/apple-splash-2208-1242.png" media="(device-width: 414px) and (device-height: 736px) and (-webkit-device-pixel-ratio: 3) and (orientation: landscape)">
+<link rel="apple-touch-startup-image" href="/assets/icons/apple-splash-750-1334.png" media="(device-width: 375px) and (device-height: 667px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)">
+<link rel="apple-touch-startup-image" href="/assets/icons/apple-splash-1334-750.png" media="(device-width: 375px) and (device-height: 667px) and (-webkit-device-pixel-ratio: 2) and (orientation: landscape)">
+<link rel="apple-touch-startup-image" href="/assets/icons/apple-splash-640-1136.png" media="(device-width: 320px) and (device-height: 568px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)">
+<link rel="apple-touch-startup-image" href="/assets/icons/apple-splash-1136-640.png" media="(device-width: 320px) and (device-height: 568px) and (-webkit-device-pixel-ratio: 2) and (orientation: landscape)">
 
-<link rel="shortcut icon" href="favicon.svg" type="image/svg">
 
-<link rel="stylesheet" href="/styles/global.css">
-<link rel="stylesheet" href="/fontawesome/css/all.css">
\ No newline at end of file
+<link rel="stylesheet" href="/styles/global.css" />
+<link rel="stylesheet" href="/fontawesome/css/all.css" />
\ No newline at end of file
diff --git a/image_grabber.php b/image_grabber.php
new file mode 100644
index 0000000000000000000000000000000000000000..ed82256da8baebbe2669034a0c9375a8b4849c6c
--- /dev/null
+++ b/image_grabber.php
@@ -0,0 +1,17 @@
+<?php
+
+if (array_key_exists(2, $uri)) {
+    $avatar_links = db_execute('SELECT public FROM avatars WHERE id = ? LIMIT 1', [$uri[2]]);
+
+    if (empty($avatar_links)) {
+        $fp = fopen('./assets/default.png', 'rb');
+    } else {
+        $fp = fopen(DATA_LOCATION . $avatar_links['public'], 'rb');
+    }
+
+    header("Content-Type: image/png");
+    header("Content-Length: " . filesize(DATA_LOCATION . $avatar_links['public']));
+
+    fpassthru($fp);
+    exit;
+}
diff --git a/index.php b/index.php
old mode 100644
new mode 100755
index 7a6bd0b5d9a86add0beb1b396680f8d8e841d293..b5fde9e0369c95a3647038183472c9f63b2f7244
--- a/index.php
+++ b/index.php
@@ -118,14 +118,17 @@ $paths = array(
     "/admin/list/accounts" => ["admin_accounts.php"],
     "/admin/list/apps" => ["admin_apps.php"],
     "/admin/create/app" => ["admin_apps_create.php"],
+    "/admin/signinas" => ["signinas.php"],
     "/admin/purge" => ["admin_purge.php"],
 
-    "/account" => ["account.php", "Your account"],
+    // Settings
+    "/dashboard" => ["dashboard.php", "Dashboard", true],
+
+    "/account" => ["account.php", "Your account", true],
     "/signin" => ["signin.php", "Sign in"],
     "/signup" => ["signup.php", "Sign up"],
-    "/signout" => ["signout.php", "Signed out"],
+    "/signout" => ["signout.php", "Signed out". false, true],
     "/forgot/password" => ["forgot_password.php", "Forgot password"],
-    "/admin/signinas" => ["signinas.php"],
     "/reset/password" => ["reset_password.php", "Reset password"],
     "/docs" => ["docs.php", "Docs"],
     "/credits" => ["credits.php", "Credits"],
@@ -139,6 +142,10 @@ if (!empty($uri) ) { // Go to jail. Go directly to jail. Do not pass Go.
         include("api_handler.php");
         exit(); // fuck this shit i'm out
     }
+    if ($uri[0] == "public" && $uri[1] == "avatars") {
+        include("image_grabber.php");
+        exit();
+    }
 }
 
 if (isset($paths[$path])) {
@@ -146,6 +153,11 @@ if (isset($paths[$path])) {
     if (isset($paths[$path][1])) {
         $doc_title = $paths[$path][1];
     }
+    if (array_key_exists(3, $paths[$path])) {
+        if ($paths[$path][3]) {
+            goto skip_formalities;
+        }
+    }
 }
 
 else {
@@ -167,8 +179,7 @@ if ($include == "login_external_basic.php") {
 <body>
     <?php include("header.php"); ?>
     <main>
-        <?php 
-
+        <?php
         if (!empty($uri)) {
 //            print_r ($uri);
 
@@ -187,8 +198,9 @@ if ($include == "login_external_basic.php") {
         }
 
         skip_formalities:
-        include($include); ?>
+        include($include);
+        ?>
     </main>
     <?php include("footer.php"); ?>
 </body>
-</html>
\ No newline at end of file
+</html>
diff --git a/login_external_basic.php b/login_external_basic.php
index 916921193f1a20fb04f6e2206a1a0b2a49c12348..5b3d55b82bc01cb08ffa70ac250dfdf3a97a9c48 100644
--- a/login_external_basic.php
+++ b/login_external_basic.php
@@ -96,9 +96,14 @@ login:
     <main>
         <div id="loginform">
             <?php if ("" != $error) {goto error_no_app;} ?>
-            <h1>Sign into <?= $app['title'] ?></h1>
+            <div id="connection_img">
+                <img src="<?= get_avatar_url($_SESSION['id']) ?>" alt="<?= htmlspecialchars($user['display_name']) ?>'s avatar" />
+                <span class="sep">×</span>
+                <img src="<?= $app['icon'] ?>" alt="<?= htmlspecialchars($user['title']) ?>'s avatar" />
+            </div>
+            <h1>Sign into <?= htmlspecialchars($app['title']) ?></h1>
             <p class="subtitle">Owned by <strong><?= get_display_name($app['owner_id'], put_bcid_in_parenthesis: true) ?></strong></p>
-            <p><?= $app['description'] ?></p>
+<!--            <p>--><?php //= htmlspecialchars($app['description']) ?><!--</p>-->
             <?php
             error_no_app:
             if ($error) {
diff --git a/manifest.json b/manifest.json
new file mode 100644
index 0000000000000000000000000000000000000000..14766c7e7c9cfacadcabf46902f9e8e072aee063
--- /dev/null
+++ b/manifest.json
@@ -0,0 +1,34 @@
+{
+  "name": "ByeCorps ID",
+  "short_name": "ByeCorps ID",
+  "start_url": "/?pwa=true",
+
+  "display": "minimal-ui",
+
+  "icons": [
+      {
+        "src": "/assets/icons/manifest-icon-192.maskable.png",
+        "sizes": "192x192",
+        "type": "image/png",
+        "purpose": "any"
+      },
+      {
+        "src": "/assets/icons/manifest-icon-192.maskable.png",
+        "sizes": "192x192",
+        "type": "image/png",
+        "purpose": "maskable"
+      },
+      {
+        "src": "/assets/icons/manifest-icon-512.maskable.png",
+        "sizes": "512x512",
+        "type": "image/png",
+        "purpose": "any"
+      },
+      {
+        "src": "/assets/icons/manifest-icon-512.maskable.png",
+        "sizes": "512x512",
+        "type": "image/png",
+        "purpose": "maskable"
+      }
+    ]
+}
\ No newline at end of file
diff --git a/profile.php b/profile.php
index 9b365d2d95f891203ac1cf1ecbfa73c5e151cb9b..75829b8ede4d3a3e7d063851ebe9b2a19e8f0ae9 100644
--- a/profile.php
+++ b/profile.php
@@ -18,13 +18,11 @@ if (empty($profile)) {
     ];
 }
 
-$avatar = "https://cdn.byecorps.com/id/profile/default.png";
+$avatar = "/assets/default.png";
 $display_name = "";
 
 if ($_SESSION['id'] != $profile['id']) {
-    if ($profile['public_avatar']) {
-        $avatar = get_avatar_url($profile['id']);
-    }
+    $avatar = get_avatar_url($profile['id']);
     if ($profile['public_display_name']) {
         $display_name = get_display_name($profile['id'], false);
     }
@@ -33,14 +31,20 @@ if ($_SESSION['id'] != $profile['id']) {
     $display_name = get_display_name($profile['id'], false);
 }
 
-
+// Get badges owned by this person
+$badges = db_execute_all('SELECT * FROM badge_owners INNER JOIN badges b on badge_owners.badge_id = b.id; ', []);
+if (!empty($badges)) {
+    if (!array_is_list($badges)) {
+        $badges = array (0 => $badges);
+    }
+}
 
 ?>
 
 <div id="profile">
     <img src="<?= $avatar ?>" class="avatar" alt="Avatar">
     <div class="info">
-        <div class="displayname"><?= $display_name ?></div>
+        <div class="displayname"><?= htmlspecialchars($display_name) ?></div>
         <div class="bcid"><?= format_bcid( $profile['id'] ); ?></div>
     </div>
 </div>
@@ -48,6 +52,23 @@ if ($_SESSION['id'] != $profile['id']) {
 <div id="details">
     <div id="badges">
         <h2>Badges</h2>
+        <?php
+        if (empty($badges)) {
+            echo '<p>This profile has no badges :(</p>';
+        } else {
+            foreach ($badges as $badge) {
+                echo "<div class='badge'>
+<img src='". $badge['image'] ."' alt='". htmlspecialchars($badge['title']) ."' />
+<div class='details'>
+<span class='title'>" . htmlspecialchars($badge['title']) . "</span>
+<p>". htmlspecialchars($badge['description']) ."</p>
+<p class='subtitle'>". htmlspecialchars($badge['description']) ."</p>
+<p class='earned subtitle'>Earned " . $badge['earned'] . "</p>
+</div>
+</div>";
+            }
+        }
+        ?>
     </div>
 
     <div id="info">
@@ -58,6 +79,10 @@ if ($_SESSION['id'] != $profile['id']) {
                 <th>Joined</th>
                 <td><?= $user['created_date'] ?></td>
             </tr>
+            <tr>
+                <th>Badges earned</th>
+                <td><?= count($badges) ?></td>
+            </tr>
         </table>
 
     </div>
diff --git a/signin.php b/signin.php
index a1904f54a50caaa3048120c472dd7bcdbb828875..88f8619698e3f49d9036418190ba7a913aae6715 100644
--- a/signin.php
+++ b/signin.php
@@ -29,11 +29,14 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
 //        print_r($_POST);
 //        echo(is_string($_POST['keep_logged_in']));
 
-        if ($_POST['keep_logged_in'] == "on") {
-            $token = generate_cookie_access_token($user['id']);
+        if (array_key_exists('keep_logged_in', $_POST)) {
+            if ($_POST['keep_logged_in'] == "on") {
+                $token = generate_cookie_access_token($user['id']);
 //            print_r($token);
-            setcookie("keep_me_logged_in", $token['access']);
+                setcookie("keep_me_logged_in", $token['access']);
+            }
         }
+
 //
         if (isset($query['callback'])) {
             header("Location: ".$query['callback']);
@@ -57,14 +60,14 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
         echo "<div class='flash'>$message</div>";
     }?>
     <form class="login" method="post">
-        <input type="email" name="email" id="email" placeholder="Email" />
-        <input type="password" name="password" id="password" placeholder="Password" />
+        <input type="email" required name="email" id="email" placeholder="Email" />
+        <input type="password" required name="password" id="password" placeholder="Password" />
         <div class="checkbox"><input type="checkbox" name="keep_logged_in" id="keep_logged_in" />
             <label for="keep_logged_in">Keep me logged in (for 365 days)</label></div>
         <button class="primary" type="submit">Sign in</button>
     </form>
 
     <p class="center">
-        <a href="/forgot/password">Forgot password?</a> &bull; New? <a href="/register">Register</a> for a ByeCorps ID.
+        <a href="/forgot/password">Forgot password?</a> &bull; New? <a href="/signup">Sign up</a> for a ByeCorps ID.
     </p>
-</div>
\ No newline at end of file
+</div>
diff --git a/signup.php b/signup.php
index 13fc42ed372dfb57267bff70faf94b2d7b3ed860..612426a46320b403e068f16eaf551b5603fa244b 100644
--- a/signup.php
+++ b/signup.php
@@ -55,7 +55,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
 
 <h2>Sign up for ByeCorps ID</h2>
 <form method="post">
-    <input type="email" name="email" id="email" placeholder="Email">
-    <input type="password" name="password" id="password" placeholder="Password">
+    <input type="email" required name="email" id="email" placeholder="Email">
+    <input type="password" required name="password" id="password" placeholder="Password">
     <button type="submit">Sign up</button>
 </form>
\ No newline at end of file
diff --git a/styles/design.css b/styles/design.css
index c6748d9dee138b643d42228d3aacd2f7639553b8..0d5d2d8dc37a04ee7bea563cdf968d6fd54dd56d 100644
--- a/styles/design.css
+++ b/styles/design.css
@@ -15,9 +15,9 @@ button, .button {
     cursor: pointer;
 }
 
-header a {
-    text-decoration: none;
-}
+/*header a {*/
+/*    text-decoration: underline;*/
+/*}*/
 
 /* inputs */
 
@@ -72,6 +72,23 @@ table > tbody > tr > td {
     padding: .5em;
 }
 
+#connection_img {
+    display: flex;
+    gap: 1rem;
+
+    justify-content: center;
+}
+
+#connection_img img {
+    height:7.5rem;
+    border-radius: 50%;
+}
+
+#connection_img .sep {
+    font-size: 4rem;
+    align-self: center;
+}
+
 @media screen and (prefers-color-scheme: dark) {
     table {
         background-color: var(--grey-9);
diff --git a/styles/global.css b/styles/global.css
index c68901509760252597ac7cd040401c8e2aa1625f..adf6fc59bc574978fcffed241be00a79ff71ca78 100644
--- a/styles/global.css
+++ b/styles/global.css
@@ -9,10 +9,10 @@
 }
 
 body::after {
-    content: "Development: Subject To Change";
+    content: "BETA";
     position: fixed;
-    top: 4.5rem;
-    right: -1rem;
+    top: 5rem;
+    right: 1rem;
 
     text-align: right;
     font-size: 2.5rem;
diff --git a/styles/profiles.css b/styles/profiles.css
index 147c159de3c5d79444ff78dd00131f0c8fff2089..01c8d670261341ef3e0d3b8093a9fcf8c87e202f 100644
--- a/styles/profiles.css
+++ b/styles/profiles.css
@@ -32,6 +32,36 @@
     grid-template-columns: 3fr 1fr;
 }
 
+#badges {
+    display: grid;
+    grid-template-columns: repeat(auto-fit, 1fr);
+    gap: 0.5rem;
+}
+
+#badges .badge {
+    display: flex;
+    align-items: center;
+
+    gap: 1rem;
+}
+
+.badge .details {
+    display: flex;
+    flex-direction: column;
+}
+
+.badge img {
+    height: 7.5em;
+    width: 7.5em;
+    object-fit: contain;
+    border-radius: 1em;
+}
+
+.badge .details .title {
+    font-size: 1.5rem;
+    font-weight: 700;
+}
+
 @media screen and (prefers-color-scheme: dark) {
     #profile {
         background: var(--grey-9);
diff --git a/styles/types.css b/styles/types.css
index 10cea6075c88c511f32962d272554f5b00baaf42..2fec09e2ed1f1d31193bdfee003865764403ee44 100644
--- a/styles/types.css
+++ b/styles/types.css
@@ -1,7 +1,7 @@
 /* This file deals with font types and font families. */
 
 @import url(https://fonts.bunny.net/css?family=montserrat:400,400i,600,600i,700,700i,900,900i);
-@import url(https://fonts.bunny.net/css2?family=courier+prime:wght@400;700&display=swap); /* for BCIDs */
+@import url(https://fonts.bunny.net/css2?family=Space+Mono:wght@400;700&display=swap); /* for BCIDs */
 
 @import url(/fontawesome/css/all.css);
 
@@ -39,10 +39,10 @@ h2.subheading + h1 {
 }
 
 .bcid {
-    font-family: 'Courier Prime', monospace;
+    font-family: 'Space Mono', monospace;
 }
 
-p.subtitle {
+.subtitle {
     font-size: 0.9rem;
     margin: 0;
     opacity: 0.8;
@@ -59,3 +59,28 @@ p.subtitle {
 .icon-false::before {
     content: "\f00d";
 }
+
+.space-mono-regular {
+    font-family: "Space Mono", monospace;
+    font-weight: 400;
+    font-style: normal;
+}
+
+.space-mono-regular-italic {
+    font-family: "Space Mono", monospace;
+    font-weight: 400;
+    font-style: italic;
+}
+
+.space-mono-bold {
+    font-family: "Space Mono", monospace;
+    font-weight: 700;
+    font-style: normal;
+}
+
+.space-mono-bold-italic {
+    font-family: "Space Mono", monospace;
+    font-weight: 700;
+    font-style: italic;
+}
+