diff --git a/api/build.gradle.kts b/api/build.gradle.kts
index dbf1fcc..e4a916a 100644
--- a/api/build.gradle.kts
+++ b/api/build.gradle.kts
@@ -26,13 +26,19 @@ dependencies {
     implementation("org.hibernate.orm:hibernate-community-dialects")
     implementation("org.json:json:20250107")
     implementation("org.bouncycastle:bcprov-jdk18on:1.76")
+    implementation("io.opentelemetry.instrumentation:opentelemetry-spring-boot-starter")
 
     developmentOnly("org.springframework.boot:spring-boot-devtools")
     runtimeOnly("com.h2database:h2")
     testImplementation("org.springframework.boot:spring-boot-starter-test")
     testImplementation("org.jetbrains.kotlin:kotlin-test-junit5")
     testRuntimeOnly("org.junit.platform:junit-platform-launcher")
+}
 
+dependencyManagement {
+    imports {
+      mavenBom("io.opentelemetry.instrumentation:opentelemetry-instrumentation-bom:2.14.0")
+    }
 }
 
 springBoot { mainClass.set("com.andr3h3nriqu3s.applications.ApplicationsApplicationKt") }
diff --git a/api/src/main/kotlin/com/andr3h3nriqu3s/applications/ApplicationsController.kt b/api/src/main/kotlin/com/andr3h3nriqu3s/applications/ApplicationsController.kt
index ac59d5f..559f5b9 100644
--- a/api/src/main/kotlin/com/andr3h3nriqu3s/applications/ApplicationsController.kt
+++ b/api/src/main/kotlin/com/andr3h3nriqu3s/applications/ApplicationsController.kt
@@ -1,5 +1,7 @@
 package com.andr3h3nriqu3s.applications
 
+import io.opentelemetry.api.OpenTelemetry
+import io.opentelemetry.api.trace.SpanKind
 import java.sql.ResultSet
 import java.util.UUID
 import kotlin.collections.emptyList
@@ -52,6 +54,7 @@ data class Application(
         var job_level: String,
         var flairs: List<Flair>,
         var events: List<Event>,
+        var urls: List<String>,
 ) {
     companion object : RowMapper<Application> {
         override public fun mapRow(rs: ResultSet, rowNum: Int): Application {
@@ -72,6 +75,7 @@ data class Application(
                     rs.getString("job_level"),
                     emptyList(),
                     emptyList(),
+                    emptyList(),
             )
         }
     }
@@ -101,6 +105,7 @@ class ApplicationsController(
         val applicationService: ApplicationService,
         val flairService: FlairService,
         val eventService: EventService,
+        val openTelemetry: OpenTelemetry
 ) {
 
     @GetMapping(path = ["/cv/{id}"], produces = [MediaType.APPLICATION_JSON_VALUE])
@@ -152,6 +157,7 @@ class ApplicationsController(
                         "",
                         emptyList(),
                         emptyList(),
+                        emptyList(),
                 )
 
         if (!applicationService.createApplication(user, application)) {
@@ -169,6 +175,8 @@ class ApplicationsController(
             @RequestBody info: FlairRequest,
             @RequestHeader("token") token: String
     ): Int {
+        val trace = openTelemetry.getTracer("applications")
+
         val user = sessionService.verifyTokenThrow(token)
         val application = applicationService.findApplicationById(user, info.id)
         if (application == null) {
@@ -179,6 +187,7 @@ class ApplicationsController(
 
         var count = 0
 
+        val span = trace.spanBuilder("parse-doc").setSpanKind(SpanKind.INTERNAL).startSpan()
         for (flair: Flair in flairs) {
             val regex =
                     Regex(
@@ -191,6 +200,7 @@ class ApplicationsController(
                 flairService.linkFlair(application, flair)
             }
         }
+        span.end()
 
         return count
     }
@@ -391,7 +401,7 @@ class ApplicationService(
 
         application.flairs = flairService.listFromLinkApplicationId(application.id)
         application.events = eventService.listFromApplicationId(application.id).toList()
-
+        application.urls = this.getUrls(application)
         return application
     }
 
@@ -503,6 +513,7 @@ class ApplicationService(
                             "",
                             emptyList(),
                             emptyList(),
+                            emptyList(),
                     )
                 }
 
@@ -608,6 +619,16 @@ class ApplicationService(
         )
     }
 
+    public fun getUrls(toGet: Application): List<String> {
+        var urls =
+                db.query(
+                        "select * from applications_urls where application_id=?",
+                        arrayOf(toGet.id),
+                        ApplicationUrl
+                )
+        return urls.map { it.url }
+    }
+
     public fun delete(application: Application) {
         db.update(
                 "delete from applications where id=?",
diff --git a/api/src/main/kotlin/com/andr3h3nriqu3s/applications/Events.kt b/api/src/main/kotlin/com/andr3h3nriqu3s/applications/Events.kt
index 4e0c704..172cbba 100644
--- a/api/src/main/kotlin/com/andr3h3nriqu3s/applications/Events.kt
+++ b/api/src/main/kotlin/com/andr3h3nriqu3s/applications/Events.kt
@@ -1,19 +1,21 @@
 package com.andr3h3nriqu3s.applications
 
+import com.fasterxml.jackson.annotation.JsonInclude
+import com.fasterxml.jackson.annotation.JsonInclude.Include
 import java.sql.ResultSet
 import java.sql.Timestamp
 import java.util.Date
 import java.util.UUID
+import org.springframework.http.MediaType
 import org.springframework.jdbc.core.JdbcTemplate
 import org.springframework.jdbc.core.RowMapper
 import org.springframework.stereotype.Service
-import org.springframework.web.bind.annotation.RestController
 import org.springframework.web.bind.annotation.ControllerAdvice
-import org.springframework.web.bind.annotation.RequestMapping
 import org.springframework.web.bind.annotation.GetMapping
 import org.springframework.web.bind.annotation.PathVariable
 import org.springframework.web.bind.annotation.RequestHeader
-import org.springframework.http.MediaType
+import org.springframework.web.bind.annotation.RequestMapping
+import org.springframework.web.bind.annotation.RestController
 
 enum class EventType(val value: Int) {
     Creation(0),
@@ -21,6 +23,15 @@ enum class EventType(val value: Int) {
     View(2)
 }
 
+@JsonInclude(Include.NON_NULL)
+data class EventStat(var i: String, var a: String, var t: Int, var s: String?, var c: Long)
+
+fun String.decodeHex(): ByteArray {
+    check(length % 2 == 0) { "Must have an even length" }
+
+    return chunked(2).map { it.toInt(16).toByte() }.toByteArray()
+}
+
 data class Event(
         var id: String,
         var application_id: String,
@@ -39,6 +50,25 @@ data class Event(
             )
         }
     }
+    fun toSimple(): EventStat {
+        return EventStat(
+                id.replace("-", "").substring(0, 10),
+                application_id,
+                /*Base64.getEncoder()
+                .encodeToString(application_id.replace("-", "").decodeHex())
+                .replace("==", ""),*/
+                event_type,
+                new_status_id,
+                /*if (new_status_id == null) null
+                else
+                        Base64.getEncoder()
+                                .encodeToString(
+                                        (new_status_id as String).replace("-", "").decodeHex()
+                                )
+                                .replace("==", ""),*/
+                time.time
+        )
+    }
 }
 
 @RestController
@@ -60,7 +90,14 @@ class EventController(
             throw NotFound()
         }
 
-        return application.events;
+        return application.events
+    }
+
+    @GetMapping(path = ["/"], produces = [MediaType.APPLICATION_JSON_VALUE])
+    public fun getCV(@RequestHeader("token") token: String): List<EventStat> {
+        sessionService.verifyTokenThrow(token)
+
+        return eventService.findAll().map { it.toSimple() }.toList()
     }
 }
 
@@ -69,7 +106,14 @@ class EventController(
 public class EventService(val db: JdbcTemplate) {
 
     public fun listFromApplicationId(id: String): Iterable<Event> =
-            db.query("select * from events where application_id=? order by time asc;", arrayOf(id), Event)
+            db.query(
+                    "select * from events where application_id=? order by time asc;",
+                    arrayOf(id),
+                    Event
+            )
+
+    public fun findAll(): Iterable<Event> =
+            db.query("select * from events order by time asc;", Event)
 
     public fun getById(id: String): Event? {
         val items = db.query("select * from events where id=?;", arrayOf(id), Event)
@@ -98,7 +142,13 @@ public class EventService(val db: JdbcTemplate) {
         val id = UUID.randomUUID().toString()
 
         var new_event =
-                Event(id, application_id, event_type.value, new_status_id, Timestamp(Date().getTime()))
+                Event(
+                        id,
+                        application_id,
+                        event_type.value,
+                        new_status_id,
+                        Timestamp(Date().getTime())
+                )
 
         db.update(
                 "insert into events (id, application_id, event_type, new_status_id) values (?, ?, ? ,?)",
diff --git a/api/src/main/kotlin/com/andr3h3nriqu3s/applications/Mail.kt b/api/src/main/kotlin/com/andr3h3nriqu3s/applications/Mail.kt
index edd4e2d..1032a05 100644
--- a/api/src/main/kotlin/com/andr3h3nriqu3s/applications/Mail.kt
+++ b/api/src/main/kotlin/com/andr3h3nriqu3s/applications/Mail.kt
@@ -1,5 +1,6 @@
 package com.andr3h3nriqu3s.applications
 
+import io.opentelemetry.api.OpenTelemetry
 import java.time.LocalDate
 import kotlin.io.println
 import org.json.JSONArray
@@ -26,6 +27,7 @@ class MailController(
         val userService: UserService,
         val applicationService: ApplicationService,
         val sessionService: SessionService,
+        val openTelemetry: OpenTelemetry,
 ) {
 
     @Value("\${mail.token.api}") private val ApiToken: String? = null
@@ -46,6 +48,8 @@ class MailController(
         if (TargetUserUUID == null || TargetUserUUID == "") {
             error("Target User not defined")
         }
+        val tracer = openTelemetry.getTracer("applications")
+
         if (user == null) {
             user = userService.findUserById(TargetUserUUID)
             if (user == null) {
@@ -53,6 +57,7 @@ class MailController(
                 error("User ${TargetUserUUID} not found")
             }
         }
+
         if (client == null) {
             val size = 16 * 1024 * 1024
             val strategies =
@@ -101,6 +106,7 @@ class MailController(
             println("mailbox got ${mailbox}")
         }
 
+        val listSpan = tracer.spanBuilder("list email").startSpan()
         println("\n\nGet Email @ ${LocalDate.now()}\n\n")
         val email_get_obj =
                 JMapQueryBuilder("Email/query", "list_emails", account!!)
@@ -171,10 +177,15 @@ class MailController(
                                 JSONArray)
                         .getJSONObject(1)
 
-        if (email_r.getJSONArray("list").length() == 0) {
+        val listSize: Int = email_r.getJSONArray("list").length()
+        if (listSize == 0) {
             println("No emails found")
+            listSpan.setAttribute("emailCount", 0)
+            listSpan.end()
             return arrayListOf()
         }
+        listSpan.setAttribute("emailCount", listSize.toLong())
+        listSpan.end()
 
         val email_html_body = email_r.getJSONArray("list").getJSONObject(0).getJSONArray("htmlBody")
 
@@ -205,6 +216,7 @@ class MailController(
 
         val email_id = email_r.getJSONArray("list").getJSONObject(0).getString("id")
 
+        val setSpan = tracer.spanBuilder("set emails as read").startSpan()
         val update_email =
                 JMapQueryBuilder("Email/set", "set", account!!)
                         .updateNewItem(email_id)
@@ -217,6 +229,7 @@ class MailController(
                 .retrieve()
                 .bodyToMono<String>()
                 .block()!!
+        setSpan.end();
 
         return applications
     }
@@ -341,7 +354,7 @@ class JMapQueryBuilder {
         if (this.sorts == null) {
             this.sorts = JSONArray()
         }
-        var obj = JSONObject()
+        val obj = JSONObject()
         obj.put("property", key)
         obj.put("isAscending", isAscending)
         this.sorts?.put(obj)
diff --git a/site/src/lib/ApplicationsStore.svelte.ts b/site/src/lib/ApplicationsStore.svelte.ts
index d17f3fa..4a43f2b 100644
--- a/site/src/lib/ApplicationsStore.svelte.ts
+++ b/site/src/lib/ApplicationsStore.svelte.ts
@@ -36,6 +36,7 @@ export type Application = {
     job_level: string;
     flairs: Flair[];
     events: ApplicationEvent[];
+    urls: string[];
 };
 
 function createApplicationStore() {
diff --git a/site/src/lib/InplaceDialog.svelte b/site/src/lib/InplaceDialog.svelte
new file mode 100644
index 0000000..b76c280
--- /dev/null
+++ b/site/src/lib/InplaceDialog.svelte
@@ -0,0 +1,45 @@
+<script lang="ts">
+	import { onDestroy, onMount, type Snippet } from 'svelte';
+
+	let {
+		buttonChildren,
+		children,
+		dialogClass = '',
+		buttonClass = ''
+	}: {
+		buttonChildren: Snippet;
+		children: Snippet;
+		dialogClass?: string;
+		buttonClass?: string;
+	} = $props();
+
+	let open = $state(false);
+	let ref: HTMLDivElement;
+
+	function callOutside(e: MouseEvent) {
+		if (!ref) return;
+		if (!ref.contains(e.target as any)) return;
+		open = false;
+	}
+
+	onMount(() => {
+		window.document.addEventListener('click', callOutside);
+	});
+	onDestroy(() => {
+		window.document.removeEventListener('click', callOutside);
+	});
+</script>
+
+<div class="relative">
+	<button class={buttonClass} onclick={() => (open = true)}>
+		{@render buttonChildren()}
+	</button>
+	{#if open}
+		<div
+			bind:this={ref}
+			class="absolute top-full left-0 bg-white p-2 rounded-lg shadow-lg {dialogClass}"
+		>
+			{@render children()}
+		</div>
+	{/if}
+</div>
diff --git a/site/src/routes/+page.svelte b/site/src/routes/+page.svelte
index 1e9d1ae..380b0a9 100644
--- a/site/src/routes/+page.svelte
+++ b/site/src/routes/+page.svelte
@@ -10,7 +10,7 @@
 	<div class="flex flex-col h-[100vh]">
 		<NavBar />
 		<div class="w-full px-4 grow h-full gap-3 flex flex-col">
-			<div class="flex gap-3 flex-grow max-h-[75%]">
+			<div class="flex gap-3 flex-grow">
 				<ApplicationsList />
 				<WorkArea />
 			</div>
diff --git a/site/src/routes/ApplicationsList.svelte b/site/src/routes/ApplicationsList.svelte
index a5278ad..5270818 100644
--- a/site/src/routes/ApplicationsList.svelte
+++ b/site/src/routes/ApplicationsList.svelte
@@ -66,7 +66,7 @@
 	});
 </script>
 
-<div class="w-2/12 card p-3 flex flex-col flex-shrink min-h-0">
+<div class="w-2/12 card p-3 flex flex-col flex-shrink min-h-0 max-h-[75vh]">
 	<h1>To Apply</h1>
 	<div class="flex pb-2 items-center">
 		<input placeholder="Filter" class="p-2 flex-grow" bind:value={filter} />
diff --git a/site/src/routes/cv/+page.svelte b/site/src/routes/cv/+page.svelte
index 8385e0c..57ce131 100644
--- a/site/src/routes/cv/+page.svelte
+++ b/site/src/routes/cv/+page.svelte
@@ -1,16 +1,14 @@
 <script lang="ts">
 	import { userStore } from '$lib/UserStore.svelte';
 	import { get } from '$lib/utils';
-	import { onMount } from 'svelte';
+	import { onMount, onDestroy } from 'svelte';
 	import Pill from './pill.svelte';
 
 	let id: string | undefined | null = $state(undefined);
 
 	onMount(() => {
 		const url = new URLSearchParams(window.location.search);
-
 		id = url.get('id');
-
 		loadData();
 	});
 
@@ -57,7 +55,7 @@
 				return b.sort - a.sort;
 			});
 
-			loadFlairs();
+			await loadFlairs();
 		} catch (e) {
 			console.log('TODO show this to the user', e);
 		}
@@ -74,6 +72,88 @@
 			console.log('TODO inform the user', e);
 		}
 	}
+
+	let rootEml: HTMLDivElement;
+
+	function getDPI() {
+		var div = document.createElement('div');
+		div.style.height = '1in';
+		div.style.width = '1in';
+		div.style.top = '-100%';
+		div.style.left = '-100%';
+		div.style.position = 'absolute';
+
+		document.body.appendChild(div);
+
+		var result = div.offsetHeight;
+
+		document.body.removeChild(div);
+
+		return result;
+	}
+
+	function onPrint() {
+		const dpi = getDPI();
+		function cmToPx(cm: number) {
+			return cm * 0.3937 * dpi;
+		}
+		const padding = 20;
+		// A4 is 29.7
+		const pageHeight = Math.floor(cmToPx(29.7));
+
+		// This will be used for comparansions so we allow the starting padding
+		const limitedPageHeight = pageHeight - padding;
+
+		const children = rootEml.children;
+
+		let page = 0;
+
+		// As we had padding it will not right away update the dom so we need to account for that
+		// this will keep track of that
+		let extraHeight = 0;
+
+		for (let i = 0; i < children.length; i++) {
+			const elm = children[i];
+			// console.log('here', elm);
+			const box = elm.getBoundingClientRect();
+
+			const useHeight = elm.getAttribute('data-useheight')
+				? Number(elm.getAttribute('data-useheight'))
+				: null;
+			if (useHeight !== null) {
+				extraHeight += useHeight - box.height;
+			}
+
+			const end = box.top + box.height + extraHeight;
+
+			// console.log(page, page * pageHeight + limitedPageHeight, end, extraHeight);
+			if (page * pageHeight + limitedPageHeight < end) {
+				// console.log('Goes over recalculating', elm);
+				// Find the autoPadding
+				for (let j = i - 1; j > 0; j--) {
+					const s = children[j];
+					if (s.getAttribute('data-autopad') !== null) {
+						// console.log('found autoPadding', s);
+						const start = s.getBoundingClientRect().top + extraHeight;
+						const distToEnd = Math.ceil(pageHeight - (start - page * pageHeight));
+						(s as any).style.setProperty('--auto-size', `${distToEnd + padding}px`);
+						// console.log('padding with', distToEnd + padding);
+						extraHeight += distToEnd + padding;
+						page += 1;
+						break;
+					}
+				}
+			}
+		}
+	}
+
+	onMount(() => {
+		window.addEventListener('beforeprint', onPrint);
+	});
+
+	onDestroy(() => {
+		window.removeEventListener('beforeprint', onPrint);
+	});
 </script>
 
 <svelte:head>
@@ -86,8 +166,8 @@
 	{/if}
 </svelte:head>
 
-<div class="flex items-center w-full flex-col">
-	<div class="py-5 pb-0 w-[190mm] print:py-0 print:pt-4">
+<div class="flex items-center w-full flex-col" bind:this={rootEml}>
+	<div class="py-5 pb-0 w-[190mm] print:py-0 print:pt-4" data-useheight="228">
 		<div class="bg-white rounded-lg p-3">
 			<div class="w-full flex">
 				<h1 class="text-black text-5xl">Andre Henriques</h1>
@@ -136,7 +216,7 @@
 
 	{#if application}
 		{#if !application.agency}
-			<h2 class="text-white p-6 print:p-0 text-4xl print:text-3xl">
+			<h2 class="text-white p-6 print:p-0 text-4xl print:text-3xl" data-useheight="36">
 				πŸ‘‹ Hello
 				{#if application.recruiter}
 					<span class="font-bold">{application.recruiter}</span> @
@@ -151,19 +231,124 @@
 
 		{#if application.message}
 			<div class="p-3 bg-white w-[190mm] rounded-lg">
-				<h1>A small message from me</h1>
+				<h1>Why your role interests me</h1>
 				<div class="py-2">
 					{@html application.message.split('\n').join('<br>')}
 				</div>
 			</div>
 			<div class="p-1"></div>
 		{/if}
+	{:else}
+		<div class="p-1"></div>
+	{/if}
+
+	<div class="w-[190mm]" data-useheight="32">
+		<h2
+			class="p-3 pt-0 print:p-0 text-4xl print:text-2xl font-bold print:font-normal text-white"
+		>
+			Work Expericence
+		</h2>
+	</div>
+
+	<div class="w-[100vw] flex items-center flex-col" data-useheight="340">
+		<div class="p-3 print:p-0 bg-white w-[190mm] rounded-lg">
+			<h1>Senior Software Engineer @ Planum Solucoes</h1>
+			<h2>4 years - May 2020 - Present</h2>
+			<div class="ml-3">
+				My role is mainly focused on frontend development, while also having a supporting
+				role with the API and DevOps teams.
+				<ul class="pl-5 list-disc">
+					<li>
+						Main developer for frontend on the core platform, and the derivative
+						products, such as video call app for doctors, video call app for vets,
+						timesheets management, budget management, stock management, gambling
+						monitoring platform, survey platform, file sharing platform, issue tracking
+						platform.
+					</li>
+					<li class="ml-4">
+						<b>Stack</b>: Frontend (React, Typescript, Tailwind); Backend (Java, Spring
+						boot, Kafka); Infrastructure (Docker, AWS, Nginx).
+					</li>
+					<li>
+						Championed and Led a move for the use of CI/CD pipelines for deployment
+						using Docker on AWS, and started to introduce better testing.
+					</li>
+					<li>
+						Support any other team with any problem that might arise, for example
+						deploying a Kafka cluster or modifying a python CLI tool.
+					</li>
+				</ul>
+			</div>
+		</div>
+	</div>
+
+	<div class="p-2 print:p-1" data-useheight="4"></div>
+
+	<div class="w-[100vw] flex items-center flex-col" data-useheight="268">
+		<div class="text-black w-[190mm] bg-white p-4 print:p-0 rounded-lg">
+			<div>
+				<div>
+					<h1>Associate DevOps Engineer @ Sky</h1>
+					<h2>1 year: July 2022–June 2023</h2>
+					<div class="ml-3">
+						My time at sky was split into two roles. One role involved maintaining
+						existing data and file pipelines, using Jenkins, Bash, and Python. My second
+						role was full-stack development, where I maintained and upgraded existing
+						applications and developed new ones, mostly with Python and Flask.
+						<ul class="pl-5 list-disc">
+							<li>
+								Maintained and updated and webapp that is used daily to monitor
+								various systems that the team looks after.
+							</li>
+							<li>
+								Created new backup, and rapid deployment solutions for Jenkins
+								servers.
+							</li>
+							<li>
+								Fixed, updated, and created new pipelines that were able to erase
+								terabytes of redundant data, improving performance of other
+								pipelines and the backup system.
+							</li>
+						</ul>
+					</div>
+				</div>
+			</div>
+		</div>
+	</div>
+
+	<div class="p-1"></div>
+
+	<div class="autoPadding" data-autopad></div>
+
+	<div class="w-[190mm]" data-useheight="28">
+		<h2 class="p-3 print:p-0 text-4xl print:text-xl font-bold print:font-normal text-white">
+			Education
+		</h2>
+	</div>
+	<div class="bg-white p-2 text-black rounded-lg w-[190mm] print:text-sm">
+		<div>
+			<div>
+				<h1>BCompSc with First Class Honours @ University of Surrey</h1>
+				<div class="ml-5">
+					<h2>July 2020 - June 2024</h2>
+				</div>
+			</div>
+		</div>
+	</div>
+
+	<div class="p-1"></div>
+
+	<div class="autoPadding" data-autopad></div>
+
+	{#if application}
 		{#if application.flairs.length > 0}
-			<div class="p-3 bg-white w-[190mm] rounded-lg">
-				<h1 class="flex gap-5 items-end">
+			<div class="w-[190mm]">
+				<h2
+					class="p-3 print:p-0 text-4xl print:text-xl font-bold print:font-normal text-white flex gap-2 items-center"
+				>
 					Skills {#if flairs.length > 0}<input
 							placeholder="Click here to search skills!"
-							class="flex-grow text-blue-500 print:hidden"
+							class="flex-grow text-blue-500 print:hidden px-2 rounded-lg h-[30px] placeholder:text-[11px] text-[12px] py-0"
 							bind:value={otherSearch}
 						/>
 						<span class="hidden print:inline text-slate-600 text-sm"
@@ -172,7 +357,9 @@
 							></span
 						>
 					{/if}
-				</h1>
+				</h2>
+			</div>
+			<div class="p-3 bg-white w-[190mm] rounded-lg">
 				<div class="flex flex-wrap gap-2 py-2 print:py-0">
 					{#if otherSearch === ''}
 						{#each application.flairs as flair}
@@ -246,77 +433,18 @@
 		{/if}
 	{/if}
 
-	<div class="w-[190mm]">
-		<h2 class="p-3 print:p-0 text-4xl print:text-2xl font-bold print:font-normal text-white">
-			Work Expericence
-		</h2>
-	</div>
-
-	<div class="w-[100vw] flex items-center flex-col">
-		<div class="p-3 print:p-0 bg-white w-[190mm] rounded-lg">
-			<h1>Senior Software Developer @ Planum Solucoes</h1>
-			<h2>4 years - May 2020 - Present</h2>
-			<div class="ml-5">
-				<h3>Developed various projects:</h3>
-				<ul class="pl-5 list-disc">
-					<li>Developing various websites using React and Svelte.</li>
-					<li>Interacting with a RESTful API</li>
-					<li>Implemented an ORM system using Java Reflection</li>
-					<li>Implemented automatic deployment with GitLab CI/CD tools.</li>
-					<li>Linux Server Administration</li>
-				</ul>
-			</div>
-		</div>
-	</div>
-
-	<div class="p-2 print:p-1"></div>
-
-	<div class="w-[100vw] flex items-center flex-col">
-		<div class="text-black w-[190mm] bg-white p-4 print:p-0 rounded-lg">
-			<div>
-				<div>
-					<h1>Associate Devops Engineer @ Sky UK</h1>
-					<h2>1 year - July 2022 - June 2023</h2>
-					<div class="ml-2">
-						<ul class="pl-5 list-disc">
-							<li>Developed web-based tools for the DevOps team to use</li>
-							<li>
-								Updated Jenkins pipelines that the team uses to manage one of the
-								most important pipelines that the team manages.
-							</li>
-							<li>
-								Created new scripts that were used to clean up multiple terabytes of
-								unused data that led to improvements in the performance of the other
-								scripts running on the same server as well as the performance of the
-								backup system
-							</li>
-						</ul>
-					</div>
-				</div>
-			</div>
-		</div>
-	</div>
-
-	<div class="w-[190mm]">
-		<h2 class="p-3 print:p-0 text-4xl print:text-xl font-bold print:font-normal text-white">
-			Education
-		</h2>
-	</div>
-	<div class="bg-white p-2 text-black rounded-lg w-[190mm] print:text-sm">
-		<div>
-			<div>
-				<h1>BCompSc with First Class Honours @ University of Surrey</h1>
-				<div class="ml-5">
-					<h2>July 2020 - June 2024</h2>
-				</div>
-			</div>
-		</div>
-	</div>
-
-	<div class="p-3 print:hidden"></div>
+	<div class="p-4 print:hidden"></div>
 
 	<!--div class="p-5"></div>
 		<div>TODO: Previous projetcs</div -->
 	<!-- div class="p-5"></div>
 		<div>TODO: Info form</div -->
 </div>
+
+<style>
+	@media print {
+		.autoPadding {
+			height: var(--auto-size);
+		}
+	}
+</style>
diff --git a/site/src/routes/graphs/+page.svelte b/site/src/routes/graphs/+page.svelte
index 50be056..4b81ee5 100644
--- a/site/src/routes/graphs/+page.svelte
+++ b/site/src/routes/graphs/+page.svelte
@@ -1,172 +1,97 @@
 <script lang="ts">
-	import { applicationStore, type Application } from '$lib/ApplicationsStore.svelte';
+	import { applicationStore } from '$lib/ApplicationsStore.svelte';
 	import HasUser from '$lib/HasUser.svelte';
 	import { onMount } from 'svelte';
 	import NavBar from '../NavBar.svelte';
 	import Pie from './Pie.svelte';
 	import { statusStore } from '$lib/Types.svelte';
-	import * as d3 from 'd3';
-	import { goto } from '$app/navigation';
 	import { get } from '$lib/utils';
-	import { flairStore } from '$lib/FlairStore.svelte';
+	import PayRange from './PayRange.svelte';
+	import LineGraphs, { type LineGraphData } from './LineGraph.svelte';
+	import * as d3 from 'd3';
+	import { countReducer } from './utils';
 
 	onMount(() => {
 		applicationStore.loadAll();
 		statusStore.load();
 	});
 
-	let sort: 'asc' | 'desc' = $state('desc');
-
-	const payranges = $derived.by(() => {
-		const obj = applicationStore.all
-			.filter((a) => a.payrange.match(/\d/))
-			.map((a) => {
-				const payrange = a.payrange
-					.replace(/[kK]/g, '000')
-					// The first is a - the other is unicode 8211
-					.replace(/\.\d+/g, '')
-					.replace(/[^\d\-–]/g, '')
-					.replace(/–/g, '-')
-					.split('-')
-					.map((a) => Number(a));
-
-				if (Number.isNaN(payrange[0])) {
-					payrange[0] = 0;
-				}
-				if (Number.isNaN(payrange[1])) {
-					payrange[1] = 0;
-				}
-
-				return { ...a, payrange };
-			})
-			.reduce(
-				(acc, a) => {
-					if (!acc[a.company]) {
-						acc[a.company] = [a];
-					} else {
-						acc[a.company].push(a);
-					}
-					return acc;
-				},
-				{} as Record<string, (Omit<Application, 'payrange'> & { payrange: number[] })[]>
-			);
-
-		return Object.keys(obj)
-			.reduce(
-				(acc, a) => {
-					acc.push([a, obj[a]]);
-					return acc;
-				},
-				[] as [string, (Omit<Application, 'payrange'> & { payrange: number[] })[]][]
-			)
-			.toSorted((a, b) => {
-				const rangesA = a[1].reduce(max_and_min_reducer, [
-					Number.POSITIVE_INFINITY,
-					Number.NEGATIVE_INFINITY
-				]);
-				const rangesB = b[1].reduce(max_and_min_reducer, [
-					Number.POSITIVE_INFINITY,
-					Number.NEGATIVE_INFINITY
-				]);
-
-				const va = (rangesA[1] + rangesA[0]) / 2;
-				const vb = (rangesB[1] + rangesB[0]) / 2;
-
-				if (sort === 'asc') {
-					return va - vb;
-				} else if (sort === 'desc') {
-					return vb - va;
-				}
-				return 0;
-			});
-	});
-
-	let payRangeDiv: HTMLDivElement | undefined = $state(undefined);
-
-	function max_and_min_reducer(
-		acc: [number, number],
-		a: Omit<Application, 'payrange'> & { payrange: number[] }
-	): [number, number] {
-		/*if (a.payrange[0] > 1000000 || a.payrange[1] > 1000000) {
-			console.log(a);
-		}*/
-		return [
-			Math.min(acc[0], a.payrange[0]),
-			Math.max(acc[1], a.payrange[1] ?? 0, a.payrange[0])
-		];
-	}
-
-	const scale = $derived.by(() => {
-		if (!payRangeDiv) return;
-
-		const max_and_min = Object.values(payranges).reduce(
-			(acc, a) => {
-				return a[1].reduce(
-					(acc2, e) => max_and_min_reducer(acc2, e),
-					acc as [number, number]
-				);
-			},
-			[Number.POSITIVE_INFINITY, Number.NEGATIVE_INFINITY] as [number, number]
-		);
-
-		const box = payRangeDiv.getBoundingClientRect();
-
-		const scale = d3
-			.scaleLinear()
-			.domain([max_and_min[0], max_and_min[1]])
-			.range([0, box.width - 40]);
-
-		return scale;
-	});
-
-	const context = (() => {
-		const canvas = document.createElement('canvas');
-		const context = canvas.getContext('2d');
-		if (!context) return null;
-		context.font = '12px Open sans';
-		return context;
-	})();
-
-	let open = $state<string | undefined>(undefined);
-	let searchPayranges = $state('');
-	let expandPayRanges = $state(false);
-	let searchPayRangeMode: 'limit' | 'goto' = $state('goto');
-	let indexPayRanges: HTMLDivElement[] = $state([]);
-	let gotoIndex: number | undefined = $state(undefined);
-
-	$effect(() => {
-		if (searchPayRangeMode !== 'goto' || !searchPayranges) {
-			gotoIndex = undefined;
-			return;
-		}
-		let i = 0;
-		for (let [company] of payranges) {
-			if (company.match(new RegExp(searchPayranges, 'i'))) {
-				indexPayRanges[i].scrollIntoView({
-					behavior: 'smooth',
-					inline: 'center',
-					block: 'center'
-				});
-				gotoIndex = i;
-				return;
-			}
-			i += 1;
-		}
-		gotoIndex = undefined;
-	});
-
 	let flairStats: 'loading' | Record<string, number> = $state('loading');
 
+	let createGraph: { xs: number[]; ys: number[] } = $state({ xs: [], ys: [] });
+	let viewGraph: { xs: number[]; ys: number[] } = $state({ xs: [], ys: [] });
+	let statusGraph: LineGraphData = $state([]);
+
+	let width: number = $state(300);
+
 	onMount(async () => {
-		const items: any[] = await get('flair/stats');
-		flairStats = items.reduce(
-			(acc, a) => {
-				acc[a.name] = a.count;
-				return acc;
-			},
-			{} as Record<string, number>
-		);
+		(async () => {
+			const items: any[] = await get('flair/stats');
+			flairStats = items.reduce(
+				(acc, a) => {
+					acc[a.name] = a.count;
+					return acc;
+				},
+				{} as Record<string, number>
+			);
+		})();
+
+		(async () => {
+			type EventsStat = {
+				// application_id
+				a: string;
+				// created time
+				c: number;
+				// id
+				i: string;
+				// new_status_id
+				s?: string;
+				// Type
+				t: number;
+			};
+			const events: EventsStat[] = await get('events/');
+
+			const pre_created_graph = events
+				.filter((a) => a.t === 0)
+				.reduce(countReducer, {} as Record<number | string, number>);
+
+			const pre_created_graph_xs = Object.keys(pre_created_graph);
+
+			createGraph = {
+				xs: pre_created_graph_xs.map((a) => Number(a)),
+				ys: pre_created_graph_xs.map((a) => pre_created_graph[a])
+			};
+
+			const pre_views_graph = events
+				.filter((a) => a.t === 2)
+				.reduce(countReducer, {} as Record<number | string, number>);
+
+			const pre_view_graph_xs = Object.keys(pre_views_graph);
+
+			viewGraph = {
+				xs: pre_view_graph_xs.map((a) => Number(a)),
+				ys: pre_view_graph_xs.map((a) => pre_views_graph[a])
+			};
+
+			statusGraph = statusStore.nodes
+				.map((a, i) => {
+					const pre = events
+						.filter((e) => e.t === 1 && e.s === a.id)
+						.reduce(countReducer, {} as Record<number | string, number>);
+					const pre_xs = Object.keys(pre);
+					if (pre_xs.length === 0) return undefined;
+					return {
+						name: a.name,
+						color: d3.interpolateRainbow(i / statusStore.nodes.length),
+						xs: pre_xs.map((a) => Number(a)),
+						ys: pre_xs.map((a) => pre[a])
+					};
+				})
+				.filter((a) => a) as LineGraphData;
+		})();
 	});
+
+	const seniorities = ['intern', 'entry', 'junior', 'mid', 'senior', 'staff', 'lead'];
 </script>
 
 <HasUser redirect="/cv">
@@ -253,7 +178,7 @@
 									.replace(/[^\d\-–]/g, '')
 									.replace(/–/g, '-')
 									.split('-');
-								return Number(payrange[0]);
+								return Number(payrange[0]) + Number(payrange[1] ?? payrange[0]);
 							})
 							.reduce(
 								(acc, a) => {
@@ -272,6 +197,21 @@
 								{} as Record<string, number>
 							)}
 					/>
+					<Pie
+						title={'Company'}
+						sensitivity={0.01}
+						data={applicationStore.all.reduce(
+							(acc, item) => {
+								if (acc[item.company]) {
+									acc[item.company] += 1;
+								} else {
+									acc[item.company] = 1;
+								}
+								return acc;
+							},
+							{} as Record<string, number>
+						)}
+					/>
 				</div>
 				{#if flairStats !== 'loading'}
 					<div class="flex gap-5">
@@ -301,253 +241,143 @@
 						/>
 					</div>
 				{/if}
-				<h1 class="text-black">
-					Pay range
-					<button
-						title="Expand/Contract"
-						onclick={() => {
-							expandPayRanges = !expandPayRanges;
-						}}
-					>
-						<span
-							class={!expandPayRanges
-								? 'bi bi-arrows-angle-expand'
-								: 'bi bi-arrows-angle-contract'}
-						></span>
-					</button>
-					<button
-						title="Sorting"
-						onclick={() => {
-							if (sort === 'asc') {
-								sort = 'desc';
-							} else if (sort === 'desc') {
-								sort = 'asc';
-							}
-						}}
-					>
-						<span class={sort === 'asc' ? 'bi bi-arrow-down' : 'bi bi-arrow-up'}></span>
-					</button>
-					<button
-						title="Filter mode"
-						onclick={() => {
-							if (searchPayRangeMode === 'limit') {
-								searchPayRangeMode = 'goto';
-							} else if (searchPayRangeMode === 'goto') {
-								searchPayRangeMode = 'limit';
-							}
-						}}
-					>
-						<span
-							class={searchPayRangeMode === 'limit'
-								? 'bi bi-funnel'
-								: 'bi bi-sort-alpha-down'}
-						></span>
-					</button>
-				</h1>
-				<div
-					class="bg-white {expandPayRanges
-						? ''
-						: 'min-h-[500px] max-h-[500px]'} overflow-y-auto"
-				>
-					<div class="sticky top-0 py-2 px-2 bg-white w-full z-50">
-						<input
-							class="w-full z-20"
-							bind:value={searchPayranges}
-							placeholder="search"
-						/>
-					</div>
-					<div bind:this={payRangeDiv}>
-						{#if scale && context}
-							{#each searchPayranges && searchPayRangeMode === 'limit' ? payranges.filter( (a) => a[0].match(new RegExp(searchPayranges, 'i')) ) : payranges as v, index}
-								{@const company = v[0]}
-								{@const values = v[1]}
-								{@const ranges = values.reduce(max_and_min_reducer, [
-									Number.POSITIVE_INFINITY,
-									Number.NEGATIVE_INFINITY
-								])}
-								{@const nameCompany = company === '' ? 'No Company' : company}
-								{#if open !== company}
-									<div
-										class="relative h-[40px] pointer-cursor {gotoIndex === index
-											? 'bg-purple-200/50'
-											: index % 2 === 0
-												? 'bg-slate-50'
-												: ''}"
-										role="button"
-										onclick={() => (open = company)}
-										onkeydown={() => (open = company)}
-										bind:this={indexPayRanges[index]}
-										tabindex={1}
-									>
-										<div
-											class="bg-blue-500 w-[20px] h-[10px] rounded-full absolute"
-											style="left: {10 +
-												scale(ranges[0]) +
-												10}px; top: 50%; transform: translateY(-50%); width: {scale(
-												ranges[1]
-											) - scale(ranges[0])}px;"
-										></div>
-										<div
-											class="bg-blue-500 w-[20px] h-[20px] rounded-full absolute"
-											title={`pay: ${ranges[0].toLocaleString('en-GB', {
-												notation: 'compact',
-												currency: 'GBP',
-												style: 'currency'
-											})}`}
-											style="left: {10 +
-												scale(
-													ranges[0]
-												)}px; top: 50%; transform: translateY(-50%);"
-										></div>
-										<div
-											class="bg-blue-500 w-[20px] h-[20px] rounded-full absolute"
-											title={`pay: ${ranges[1].toLocaleString('en-GB', {
-												notation: 'compact',
-												currency: 'GBP',
-												style: 'currency'
-											})}`}
-											style="left: {10 +
-												scale(
-													ranges[1]
-												)}px; top: 50%; transform: translateY(-50%);"
-										></div>
-										{#if context.measureText(nameCompany).width < scale(ranges[1]) - scale(ranges[0]) - 40}
-											<div
-												class="absolute text-center text-white font-bold pb-1"
-												style="left: {10 +
-													scale(ranges[0]) +
-													10}px;  width: {scale(ranges[1]) -
-													scale(ranges[0])}px;
-                                        top: 50%; transform: translateY(-50%); font-size: 10px; "
-											>
-												{nameCompany}
-											</div>
-										{:else}
-											<div
-												class="absolute text-center font-bold pb-1"
-												style="left: {10 +
-													scale(ranges[1] ?? ranges[0]) +
-													30}px;
-                                                top: 50%; transform: translateY(-50%); font-size: 10px; "
-											>
-												{nameCompany}
-											</div>
-										{/if}
-									</div>
-								{:else}
-									<div
-										class=" p-[10px] inset-2
-                                        {gotoIndex === index
-											? 'bg-purple-200/50'
-											: 'bg-slate-200/50'}
-
-                                        "
-										bind:this={indexPayRanges[index]}
-									>
-										<h2 class="font-bold">
-											{nameCompany} (Avg: {(
-												(ranges[0] + ranges[1]) /
-												2
-											).toLocaleString('en-GB', {
-												notation: 'compact',
-												currency: 'GBP',
-												style: 'currency'
-											})}; Min: {ranges[0].toLocaleString('en-GB', {
-												notation: 'compact',
-												currency: 'GBP',
-												style: 'currency'
-											})}; Max: {ranges[1].toLocaleString('en-GB', {
-												notation: 'compact',
-												currency: 'GBP',
-												style: 'currency'
-											})})
-										</h2>
-										{#each values as app}
-											<div
-												class="relative -mx-[10px] h-[40px]"
-												role="button"
-												tabindex={1}
-												onclick={() => {
-													applicationStore.loadItem = app as any;
-													goto('/');
-												}}
-												onkeydown={() => {
-													applicationStore.loadItem = app as any;
-												}}
-											>
-												{#if app.payrange[1]}
-													<div
-														class="bg-blue-500 w-[20px] h-[10px] rounded-full absolute"
-														style="left: {10 +
-															scale(app.payrange[0]) +
-															10}px; top: 50%; transform: translateY(-50%); width: {scale(
-															app.payrange[1]
-														) - scale(app.payrange[0])}px;"
-													></div>
-												{/if}
-												<div
-													class="bg-blue-500 w-[20px] h-[20px] rounded-full absolute"
-													title={`pay: ${app.payrange[0].toLocaleString(
-														'en-GB',
-														{
-															notation: 'compact',
-															currency: 'GBP',
-															style: 'currency'
-														}
-													)}`}
-													style="left: {10 +
-														scale(
-															app.payrange[0]
-														)}px; top: 50%; transform: translateY(-50%);"
-												></div>
-												{#if app.payrange[1]}
-													<div
-														class="bg-blue-500 w-[20px] h-[20px] rounded-full absolute"
-														title={`pay: ${app.payrange[1].toLocaleString(
-															'en-GB',
-															{
-																notation: 'compact',
-																currency: 'GBP',
-																style: 'currency'
-															}
-														)}`}
-														style="left: {10 +
-															scale(
-																app.payrange[1]
-															)}px; top: 50%; transform: translateY(-50%);"
-													></div>
-												{/if}
-												{#if context.measureText(app.title).width < scale(app.payrange[1]) - scale(app.payrange[0]) - 40}
-													<div
-														class="absolute text-center text-white font-bold pb-1"
-														style="left: {10 +
-															scale(app.payrange[0]) +
-															10}px;  width: {scale(app.payrange[1]) -
-															scale(app.payrange[0])}px;
-                                                            top: 50%; transform: translateY(-50%); font-size: 10px; "
-													>
-														{app.title}
-													</div>
-												{:else}
-													<div
-														class="absolute text-center font-bold pb-1"
-														style="left: {10 +
-															scale(
-																app.payrange[1] ?? app.payrange[0]
-															) +
-															30}px;
-                                                            top: 50%; transform: translateY(-50%); font-size: 10px; "
-													>
-														{app.title}
-													</div>
-												{/if}
-											</div>
-										{/each}
-									</div>
-								{/if}
-							{/each}
-						{/if}
-					</div>
+				<div bind:clientWidth={width}>
+					<LineGraphs
+						data={[
+							{ name: 'Created Time', color: 'red', ...createGraph },
+							{ name: 'Views', color: 'blue', ...viewGraph }
+						]}
+						xIsDates
+						width={width - 50}
+						height={300}
+					/>
+				</div>
+				<div bind:clientWidth={width}>
+					<h1>Status Graph</h1>
+					<LineGraphs data={statusGraph} xIsDates width={width - 50} height={300} />
+				</div>
+				<h1>Payrange</h1>
+				<PayRange />
+				<div>
+					<h1>Per Seniority</h1>
+					{#each seniorities as level}
+						{@const fapps = applicationStore.all.filter(
+							(a) => a.payrange.match(/\d/) && a.job_level === level
+						)}
+						<h2 class="font-bold text-lg">
+							{level} (AVG pay: {(
+								fapps
+									.map((a) => {
+										const payrange = a.payrange
+											.replace(/[kK]/g, '000')
+											.replace(/[^\d\-–]/g, '')
+											.replace(/–/g, '-')
+											.split('-');
+										return (
+											Number(payrange[0]) + Number(payrange[1] ?? payrange[0])
+										);
+									})
+									.reduce((acc, a) => acc + a, 0) /
+								(fapps.length * 2)
+							).toLocaleString('en-GB', {
+								notation: 'compact',
+								style: 'currency',
+								currency: 'GBP'
+							})})
+						</h2>
+						<div class="flex gap-2">
+							<Pie
+								title={'Higher range Pay Range'}
+								data={fapps
+									.map((a) => {
+										const payrange = a.payrange
+											.replace(/[kK]/g, '000')
+											.replace(/[^\d\-–]/g, '')
+											.replace(/–/g, '-')
+											.split('-');
+										return Number(payrange[payrange.length - 1]);
+									})
+									.reduce(
+										(acc, a) => {
+											const f = Math.floor(a / 10000);
+											let name = `${f * 10}K-${(f + 1) * 10}K`;
+											if (f == 0) {
+												name = '<10K';
+											}
+											if (acc[name]) {
+												acc[name] += 1;
+											} else {
+												acc[name] = 1;
+											}
+											return acc;
+										},
+										{} as Record<string, number>
+									)}
+							/>
+							<Pie
+								title={'Lower range Pay Range'}
+								data={fapps
+									.map((a) => {
+										const payrange = a.payrange
+											.replace(/[kK]/g, '000')
+											// The first is a - the other is unicode 8211
+											.replace(/[^\d\-–]/g, '')
+											.replace(/–/g, '-')
+											.split('-');
+										return Number(payrange[0]);
+									})
+									.reduce(
+										(acc, a) => {
+											const f = Math.floor(a / 10000);
+											let name = `${f * 10}K-${(f + 1) * 10}K`;
+											if (f == 0) {
+												name = '<10K';
+											}
+											if (acc[name]) {
+												acc[name] += 1;
+											} else {
+												acc[name] = 1;
+											}
+											return acc;
+										},
+										{} as Record<string, number>
+									)}
+							/>
+							<Pie
+								title={'AVG Pay'}
+								data={fapps
+									.map((a) => {
+										const payrange = a.payrange
+											.replace(/[kK]/g, '000')
+											// The first is a - the other is unicode 8211
+											.replace(/[^\d\-–]/g, '')
+											.replace(/–/g, '-')
+											.split('-');
+										return (
+											(Number(payrange[0]) +
+												Number(payrange[1] ?? payrange[0])) /
+											2
+										);
+									})
+									.reduce(
+										(acc, a) => {
+											const f = Math.floor(a / 10000);
+											let name = `${f * 10}K-${(f + 1) * 10}K`;
+											if (f == 0) {
+												name = '<10K';
+											}
+											if (acc[name]) {
+												acc[name] += 1;
+											} else {
+												acc[name] = 1;
+											}
+											return acc;
+										},
+										{} as Record<string, number>
+									)}
+							/>
+						</div>
+					{/each}
 				</div>
 			</div>
 		</div>
diff --git a/site/src/routes/graphs/LineGraph.svelte b/site/src/routes/graphs/LineGraph.svelte
new file mode 100644
index 0000000..2f66778
--- /dev/null
+++ b/site/src/routes/graphs/LineGraph.svelte
@@ -0,0 +1,422 @@
+<script lang="ts">
+	import * as d3 from 'd3';
+	import {
+		type AxisProps,
+		Axis,
+		type EnforceSizeType,
+		enforceSizeHelper,
+		PaddingManager
+	} from './utils';
+
+	export type LineGraphData = {
+		ys: number[];
+		xs: number[];
+		name: string;
+		color?: string;
+	}[];
+
+	const {
+		class: className,
+		data,
+		title,
+		useCompactNotation = 'auto',
+		width: inWidth = 300,
+		height: inHeight = 300,
+		area,
+		xAxis: inXAxis,
+		yAxis: inYAxis,
+		xIsDates = false,
+		enforceSize
+	}: {
+		class?: string;
+		data: LineGraphData;
+		title?: string;
+		useCompactNotation?: 'auto' | boolean;
+		width?: number;
+		height?: number;
+		area?: boolean;
+		xAxis?: AxisProps;
+		yAxis?: AxisProps;
+		xIsDates?: boolean;
+		enforceSize?: EnforceSizeType;
+	} = $props();
+
+	const notation = 'compact';
+	const locale = 'en-GB';
+
+	let divRef: HTMLDivElement | null = $state(undefined);
+	let yScaler: d3.ScaleLinear<number, number>;
+
+	let optionsHeight = $state(0);
+
+	let size: { width: number; height: 0 } = $state({ width: 0, height: 0 });
+
+	let mask: Record<string, boolean> = $state({});
+
+	const names = $derived(data.map((d) => d.name));
+	const color = $derived.by(() => {
+		let colors: readonly string[] = [];
+		const groups = names;
+		const len = groups.length;
+		if (len === 0) {
+			// Do nothing
+		} else if (len >= 3 && len < 10) {
+			colors = d3.schemeBlues[len];
+		} else {
+			colors = [...groups].map((_, i) => d3.interpolateBlues(i / len));
+		}
+		return d3.scaleOrdinal(groups, colors);
+	});
+
+	const internalEnforceSize = $derived.by(() => {
+		return (
+			enforceSizeHelper
+				.fromEnforceSize(enforceSize)
+				.h('p-1', '0.5rem')
+				.h('left', 1, 'left')
+				.h('p-2', '0.5rem')
+				//.h('options', optionsHeight)
+				.enforce()
+				.toEnfoceSize('left')
+		);
+	});
+
+	$effect(() => {
+		if (!data || !divRef || data.length === 0) return;
+
+		function gen<T extends number | Date>(xs: T[]) {
+			// Get all possible values and sort them
+			const ys = data.reduce((acc, d) => acc.concat(d.ys), [] as number[]);
+
+			if (ys.length === 0) return;
+
+			ys.sort((a, b) => a - b);
+
+			const xAxisTitle = new Axis(inXAxis);
+			const yAxis = new Axis(inYAxis);
+
+			xAxisTitle.titlePos('bot');
+			yAxis.titlePos('left');
+
+			const padding = new PaddingManager({ width: inWidth, height: inHeight });
+			padding.padAll(20);
+
+			padding
+				.padLeft(
+					`${ys[ys.length - 1].toLocaleString(locale, { notation, maximumFractionDigits: ys[ys.length] > 100 ? 0 : 2 })}`,
+					65
+				)
+				.padLeft(yAxis);
+
+			padding.padBot(50).padTop(xAxisTitle);
+
+			padding.enforce(internalEnforceSize);
+
+			const div = divRef;
+			// clear the html inside the div
+			d3.select(div).html('');
+
+			const svg = d3
+				.select(div)
+				.append('svg')
+				.attr('width', padding.paddedWidth)
+				.attr('height', padding.paddedHeight)
+				.append('g')
+				.attr('transform', padding.translateString);
+
+			size = {
+				width: padding.paddedWidth,
+				height: padding.paddedHeight
+			};
+
+			let x: d3.ScaleTime<number, number, never> | d3.ScaleLinear<number, number, never>;
+
+			let xAxis: d3.Selection<SVGGElement, unknown, null, undefined>;
+
+			const width = padding.width;
+			const height = padding.height;
+
+			if (xIsDates) {
+				x = d3
+					.scaleTime()
+					.domain([new Date(xs[0]), new Date(xs[xs.length - 1])])
+					.range([0, width]);
+				xAxis = svg
+					.append('g')
+					.attr('transform', `translate(0, ${height})`)
+					.call(d3.axisBottom(x).ticks(10));
+				xAxis
+					.selectAll('text')
+					.attr('transform', 'rotate(65)')
+					.attr('dy', '-0.4em')
+					.attr('dx', '2.9em');
+			} else {
+				x = d3
+					.scaleLinear()
+					.domain([xs[0], xs[xs.length - 1]])
+					.range([0, width]);
+				xAxis = svg
+					.append('g')
+					.attr('transform', `translate(0, ${height})`)
+					.call(d3.axisBottom(x).ticks(10));
+				xAxis
+					.selectAll('text')
+					.attr('transform', 'rotate(65)')
+					.attr('dy', '-0.4em')
+					.attr('dx', '2.9em');
+			}
+
+			const y = d3
+				.scaleLinear()
+				.domain([ys[0], ys[ys.length - 1]])
+				.range([height, 0]);
+
+			svg.append('g').call(
+				d3.axisLeft(y).tickFormat((a) => a.toLocaleString(locale, { notation }))
+			);
+
+			yAxis.apply_title(svg, height, width, padding.left);
+			xAxisTitle.apply_title(svg, height, width, padding.bot);
+
+			yScaler = y;
+
+			svg.append('defs')
+				.append('svg:clipPath')
+				.attr('id', 'clip')
+				.append('svg:rect')
+				.attr('width', width)
+				.attr('height', height)
+				.attr('x', 0)
+				.attr('y', 0);
+
+			/*// Create the circle that travels along the curve of chart
+        const focus = svg
+            .append("g")
+            .append("circle")
+            .style("fill", "none")
+            .attr("stroke", "black")
+            .attr("r", 8.5)
+            .style("opacity", 0);
+
+        // Create the text that travels along the curve of chart
+        const focusText = svg
+            .append("g")
+            .append("text")
+            .style("opacity", 0)
+            .attr("text-anchor", "left")
+            .attr("alignment-baseline", "middle");*/
+
+			// Add brushing
+			const brush = d3
+				.brushX() // Add the brush feature using the d3.brush function
+				.extent([
+					[0, 0],
+					[width, height]
+				]) // initialise the brush area: start at 0,0 and finishes at width,height: it means I select the whole graph area
+				.on('end', updateChart);
+
+			//
+			// Create a group that stores all lines
+			//
+			const lines = svg.append('g').attr('clip-path', 'url(#clip)');
+
+			//
+			// Create the lines
+			//
+
+			lines
+				.selectAll('path')
+				.data(data.map((l, i) => ({ ...l, i })))
+				.join('path')
+				.attr('lineId', (_, i) => `l-${i}`)
+				.attr('transform', (l) => {
+					if (!mask[l.name]) {
+						return '';
+					}
+					const m = l.ys.reduce((acc, v) => Math.max(acc, v), 0);
+					return `translate(0, ${height - (y(m) as number)})`;
+				})
+				.sort((a, b) => b.ys[0] - a.ys[0])
+				.attr('fill', (l) => l.color ?? color(l.name))
+				.attr('fill-opacity', 1)
+				.attr('stroke', (l) => l.color ?? color(l.name))
+				.attr('stroke-width', 1.5)
+				.datum((l) => {
+					return l.ys.map((a, j) => ({
+						value: a,
+						x: l.xs[j]
+					}));
+				})
+				.attr('d', (d) => {
+					const a = d3
+						.area<{ x: number; value: number }>()
+						.x((d) => x(xIsDates ? new Date(d.x).getTime() : d.x))
+						.curve(d3.curveBumpX);
+
+					if (area) {
+						return a.y0(y(0)).y1((d) => y(d.value))(d as any);
+					}
+					return a.y((d) => y(d.value))(d as any);
+				});
+
+			/*lines
+				.selectAll('circle')
+				.data(
+					data.reduce(
+						(acc, a) => {
+							for (let i = 0; i < a.xs.length; i++) {
+								acc.push([a.xs[i], a.ys[i]]);
+							}
+							return acc;
+						},
+						[] as [number, number][]
+					)
+				)
+				.join('circle')
+				.attr('cx', (d) => x(xIsDates ? new Date(d[0]).getTime() : d[0]))
+				.attr('cy', (d) => y(d[1]))
+				.attr('fill', 'red')
+				.attr('r', '2px');*/
+
+			lines.append('g').attr('class', 'brush').call(brush);
+
+			let idleTimeout: number | null;
+			function idled() {
+				idleTimeout = null;
+			}
+
+			// A function that update the chart for given boundaries
+			function updateChart(e: any) {
+				// What are the selected boundaries?
+				const extent = e.selection;
+
+				// If no selection, back to initial coordinate. Otherwise, update X axis domain
+				if (!extent) {
+					if (!idleTimeout) {
+						idleTimeout = setTimeout(idled, 350) as unknown as number; // This allows to wait a little bit
+						return;
+					}
+					x.domain([xs[0], xs[xs.length - 1]]);
+				} else {
+					x.domain([x.invert(extent[0]), x.invert(extent[1])]);
+					lines.select('.brush').call(brush.move as any, null); // This remove the grey brush area as soon as the selection has been done
+				}
+
+				// Update axis and line position
+				xAxis
+					.transition()
+					.duration(1000)
+					.call(d3.axisBottom(x).ticks(10))
+					.selectAll('text')
+					.attr('transform', 'rotate(65)')
+					.attr('dy', '-0.4em')
+					.attr('dx', '2.9em');
+
+				lines
+					.selectAll<d3.BaseType, { value: number; x: number }[]>('path')
+					.transition()
+					.duration(1000)
+					.attr('d', (d) => {
+						const a = d3
+							.area<{
+								value: number;
+								x: number;
+							}>()
+							.x((d) => x(xIsDates ? new Date(d.x).getTime() : d.x))
+							.curve(d3.curveBumpX);
+
+						if (area) {
+							return a.y0(y(0)).y1((d) => y(d.value))(d as any);
+						}
+						return a.y((d) => y(d.value))(d as any);
+					});
+			}
+
+			svg.on('dblclick', () => {
+				x.domain([xs[0], xs[xs.length - 1]]);
+				xAxis
+					.transition()
+					.call(d3.axisBottom(x).ticks(10))
+					.selectAll('text')
+					.attr('transform', 'rotate(65)')
+					.attr('dy', '-0.4em')
+					.attr('dx', '2.9em');
+
+				lines
+					.selectAll('path')
+					.transition()
+					.attr('d', (d) => {
+						const a = d3
+							.area<{
+								x: number;
+								value: number;
+							}>()
+							.x((d) => x(xIsDates ? new Date(d.x).getTime() : d.x))
+							.curve(d3.curveBumpX);
+
+						if (area) {
+							return a.y0(y(0)).y1((d) => y(d.value))(d as any);
+						}
+						return a.y((d) => y(d.value))(d as any);
+					});
+			});
+		}
+
+		const xs = data.reduce((acc, d) => acc.concat(d.xs), [] as number[]);
+
+		if (xIsDates) {
+			xs.sort((a, b) => new Date(a).getTime() - new Date(b).getTime());
+			gen(xs.map((a) => new Date(a)));
+		} else {
+			xs.sort((a, b) => a - b);
+			gen(xs);
+		}
+	});
+</script>
+
+<div>
+	<div class="p-2">
+		<div style="width: {size.width}px; height: {size.height}px" bind:this={divRef}></div>
+	</div>
+	<div class="flex flex-wrap" bind:clientHeight={optionsHeight}>
+		{#each data as a, i}
+			<div class="flex items-center p-2">
+				<button
+					type="button"
+					onclick={() => {
+						if (mask[a.name]) {
+							d3.select(divRef)
+								.selectAll(`path[lineId=l-${i}]`)
+								.transition()
+								.duration(1000)
+								.attr('transform', '');
+						} else {
+							const m = a.ys.reduce((acc, v) => Math.max(acc, v), 0);
+							const scale = yScaler ?? ((i) => i);
+
+							d3.select(divRef)
+								.selectAll(`path[lineId=l-${i}]`)
+								.transition()
+								.duration(1500)
+								.attr(
+									'transform',
+									`translate(0, ${inHeight - (scale(m) as number)})`
+								);
+						}
+						mask = { ...mask, [a.name]: !mask[a.name] };
+					}}
+					class="border-0 flex bg-transparent"
+				>
+					<div
+						style="background-color: {mask[a.name]
+							? 'gray'
+							: a.color ?? color(a.name)}; width: 20px; height: 20px;"
+					></div>
+					<div style="textDecoration: {mask[a.name] ? 'line-through' : ''}" class="px-2">
+						{a.name}
+					</div>
+				</button>
+			</div>
+		{/each}
+	</div>
+</div>
diff --git a/site/src/routes/graphs/PayRange.svelte b/site/src/routes/graphs/PayRange.svelte
new file mode 100644
index 0000000..721e7c7
--- /dev/null
+++ b/site/src/routes/graphs/PayRange.svelte
@@ -0,0 +1,438 @@
+<script lang="ts">
+	import { applicationStore, type Application } from '$lib/ApplicationsStore.svelte';
+	import * as d3 from 'd3';
+	import { goto } from '$app/navigation';
+	import type { LineGraphData } from './LineGraph.svelte';
+	import LineGraph from './LineGraph.svelte';
+
+	let payRangeDiv: HTMLDivElement | undefined = $state(undefined);
+
+	let sort: 'asc' | 'desc' = $state('desc');
+
+	let width = $state(300);
+
+	let job_level = $state('all');
+
+	const base_payrange = $derived(
+		applicationStore.all
+			.filter((a) => a.payrange.match(/\d/))
+			.map((a) => {
+				const payrange = a.payrange
+					.replace(/[kK]/g, '000')
+					// The first is a - the other is unicode 8211
+					.replace(/\.\d+/g, '')
+					.replace(/[^\d\-–]/g, '')
+					.replace(/–/g, '-')
+					.split('-')
+					.map((a) => Number(a));
+
+				if (Number.isNaN(payrange[0])) {
+					payrange[0] = 0;
+				}
+				if (Number.isNaN(payrange[1])) {
+					payrange[1] = 0;
+				}
+
+				return { ...a, payrange };
+			})
+	);
+
+	const payrangeGraphs: LineGraphData = $derived.by(() => {
+		const pre_overtime = base_payrange.reduce(
+			(
+				acc: Record<number, [number, number]>,
+				a: Omit<Application, 'payrange'> & { payrange: number[] }
+			) => {
+				const c = new Date(a.create_time);
+				c.setHours(0);
+				c.setMinutes(0);
+				c.setSeconds(0);
+				c.setMilliseconds(0);
+				const ct = c.getTime();
+
+				if (acc[ct]) {
+					acc[ct] = [
+						acc[ct][0] + 1,
+						acc[ct][1] + a.payrange[0] + (a.payrange[1] ?? a.payrange[0])
+					];
+				} else {
+					acc[ct] = [1, a.payrange[0] + (a.payrange[1] ?? a.payrange[0])];
+				}
+				return acc;
+			},
+			{} as Record<number | string, [number, number]>
+		);
+
+		const keys = Object.keys(pre_overtime);
+
+		keys.sort((a, b) => Number(a) - Number(b));
+
+		return [
+			{
+				name: 'Payrange avg',
+				color: 'green',
+				xs: keys.map((a) => Number(a)),
+				ys: keys.map((a) => pre_overtime[a][1] / (pre_overtime[a][0] * 2))
+			}
+		];
+	});
+
+	const payranges = $derived.by(() => {
+		const obj = base_payrange.reduce(
+			(acc, a) => {
+				if (job_level !== 'all' && a.job_level !== job_level) {
+					return acc;
+				}
+				if (!acc[a.company]) {
+					acc[a.company] = [a];
+				} else {
+					acc[a.company].push(a);
+				}
+				return acc;
+			},
+			{} as Record<string, (Omit<Application, 'payrange'> & { payrange: number[] })[]>
+		);
+
+		return Object.keys(obj)
+			.reduce(
+				(acc, a) => {
+					acc.push([a, obj[a]]);
+					return acc;
+				},
+				[] as [string, (Omit<Application, 'payrange'> & { payrange: number[] })[]][]
+			)
+			.toSorted((a, b) => {
+				const rangesA = a[1].reduce(max_and_min_reducer, [
+					Number.POSITIVE_INFINITY,
+					Number.NEGATIVE_INFINITY
+				]);
+				const rangesB = b[1].reduce(max_and_min_reducer, [
+					Number.POSITIVE_INFINITY,
+					Number.NEGATIVE_INFINITY
+				]);
+
+				const va = (rangesA[1] + rangesA[0]) / 2;
+				const vb = (rangesB[1] + rangesB[0]) / 2;
+
+				if (sort === 'asc') {
+					return va - vb;
+				} else if (sort === 'desc') {
+					return vb - va;
+				}
+				return 0;
+			});
+	});
+
+	function max_and_min_reducer(
+		acc: [number, number],
+		a: Omit<Application, 'payrange'> & { payrange: number[] }
+	): [number, number] {
+		/*if (a.payrange[0] > 1000000 || a.payrange[1] > 1000000) {
+			console.log(a);
+		}*/
+		return [
+			Math.min(acc[0], a.payrange[0]),
+			Math.max(acc[1], a.payrange[1] ?? 0, a.payrange[0])
+		];
+	}
+
+	const scale = $derived.by(() => {
+		if (!payRangeDiv) return;
+
+		const max_and_min = Object.values(payranges).reduce(
+			(acc, a) => {
+				return a[1].reduce(
+					(acc2, e) => max_and_min_reducer(acc2, e),
+					acc as [number, number]
+				);
+			},
+			[Number.POSITIVE_INFINITY, Number.NEGATIVE_INFINITY] as [number, number]
+		);
+
+		const box = payRangeDiv.getBoundingClientRect();
+
+		const scale = d3
+			.scaleLinear()
+			.domain([max_and_min[0], max_and_min[1]])
+			.range([0, box.width - 40]);
+
+		return scale;
+	});
+
+	const context = (() => {
+		const canvas = document.createElement('canvas');
+		const context = canvas.getContext('2d');
+		if (!context) return null;
+		context.font = '12px Open sans';
+		return context;
+	})();
+
+	let open = $state<string | undefined>(undefined);
+	let searchPayranges = $state('');
+	let expandPayRanges = $state(false);
+	let searchPayRangeMode: 'limit' | 'goto' = $state('goto');
+	let indexPayRanges: HTMLDivElement[] = $state([]);
+	let gotoIndex: number | undefined = $state(undefined);
+
+	//
+	// Searching
+	//
+	$effect(() => {
+		if (searchPayRangeMode !== 'goto' || !searchPayranges) {
+			gotoIndex = undefined;
+			return;
+		}
+		let i = 0;
+		for (let [company] of payranges) {
+			if (company.match(new RegExp(searchPayranges, 'i'))) {
+				indexPayRanges[i].scrollIntoView({
+					behavior: 'smooth',
+					inline: 'center',
+					block: 'center'
+				});
+				gotoIndex = i;
+				return;
+			}
+			i += 1;
+		}
+		gotoIndex = undefined;
+	});
+</script>
+
+<h1 class="text-black">
+	Pay range
+	<button
+		title="Expand/Contract"
+		onclick={() => {
+			expandPayRanges = !expandPayRanges;
+		}}
+	>
+		<span class={!expandPayRanges ? 'bi bi-arrows-angle-expand' : 'bi bi-arrows-angle-contract'}
+		></span>
+	</button>
+	<button
+		title="Sorting"
+		onclick={() => {
+			if (sort === 'asc') {
+				sort = 'desc';
+			} else if (sort === 'desc') {
+				sort = 'asc';
+			}
+		}}
+	>
+		<span class={sort === 'asc' ? 'bi bi-arrow-down' : 'bi bi-arrow-up'}></span>
+	</button>
+	<button
+		title="Filter mode"
+		onclick={() => {
+			if (searchPayRangeMode === 'limit') {
+				searchPayRangeMode = 'goto';
+			} else if (searchPayRangeMode === 'goto') {
+				searchPayRangeMode = 'limit';
+			}
+		}}
+	>
+		<span class={searchPayRangeMode === 'limit' ? 'bi bi-funnel' : 'bi bi-sort-alpha-down'}
+		></span>
+	</button>
+</h1>
+<div class="bg-white {expandPayRanges ? '' : 'min-h-[500px] max-h-[500px]'} overflow-y-auto">
+	<div class="sticky top-0 py-2 px-2 bg-white w-full z-50 flex">
+		<input class="w-full z-20 flex-grow" bind:value={searchPayranges} placeholder="search" />
+		<select
+			class="finput flex-shrink"
+			style="width: unset;"
+			id="job_level"
+			bind:value={job_level}
+		>
+			<option value="all"> All </option>
+			<option value="intern"> Intern </option>
+			<option value="entry"> Entry </option>
+			<option value="junior"> Junior </option>
+			<option value="mid"> Mid </option>
+			<option value="senior"> Senior </option>
+			<option value="staff"> Staff </option>
+			<option value="lead"> Lead </option>
+		</select>
+	</div>
+	<div bind:this={payRangeDiv}>
+		{#if scale && context}
+			{#each searchPayranges && searchPayRangeMode === 'limit' ? payranges.filter( (a) => a[0].match(new RegExp(searchPayranges, 'i')) ) : payranges as v, index}
+				{@const company = v[0]}
+				{@const values = v[1]}
+				{@const ranges = values.reduce(max_and_min_reducer, [
+					Number.POSITIVE_INFINITY,
+					Number.NEGATIVE_INFINITY
+				])}
+				{@const nameCompany = company === '' ? 'No Company' : company}
+				{#if open !== company}
+					<div
+						class="relative h-[40px] pointer-cursor {gotoIndex === index
+							? 'bg-purple-200/50'
+							: index % 2 === 0
+								? 'bg-slate-50'
+								: ''}"
+						role="button"
+						onclick={() => (open = company)}
+						onkeydown={() => (open = company)}
+						bind:this={indexPayRanges[index]}
+						tabindex={1}
+					>
+						<div
+							class="bg-blue-500 w-[20px] h-[10px] rounded-full absolute"
+							style="left: {10 +
+								scale(ranges[0]) +
+								10}px; top: 50%; transform: translateY(-50%); width: {scale(
+								ranges[1]
+							) - scale(ranges[0])}px;"
+						></div>
+						<div
+							class="bg-blue-500 w-[20px] h-[20px] rounded-full absolute"
+							title={`pay: ${ranges[0].toLocaleString('en-GB', {
+								notation: 'compact',
+								currency: 'GBP',
+								style: 'currency'
+							})}`}
+							style="left: {10 +
+								scale(ranges[0])}px; top: 50%; transform: translateY(-50%);"
+						></div>
+						<div
+							class="bg-blue-500 w-[20px] h-[20px] rounded-full absolute"
+							title={`pay: ${ranges[1].toLocaleString('en-GB', {
+								notation: 'compact',
+								currency: 'GBP',
+								style: 'currency'
+							})}`}
+							style="left: {10 +
+								scale(ranges[1])}px; top: 50%; transform: translateY(-50%);"
+						></div>
+						{#if context.measureText(nameCompany).width < scale(ranges[1]) - scale(ranges[0]) - 40}
+							<div
+								class="absolute text-center text-white font-bold pb-1"
+								style="left: {10 + scale(ranges[0]) + 10}px;  width: {scale(
+									ranges[1]
+								) - scale(ranges[0])}px;
+                                        top: 50%; transform: translateY(-50%); font-size: 10px; "
+							>
+								{nameCompany}
+							</div>
+						{:else}
+							<div
+								class="absolute text-center font-bold pb-1"
+								style="left: {10 + scale(ranges[1] ?? ranges[0]) + 30}px;
+                                                top: 50%; transform: translateY(-50%); font-size: 10px; "
+							>
+								{nameCompany}
+							</div>
+						{/if}
+					</div>
+				{:else}
+					<div
+						class=" p-[10px] inset-2
+                                        {gotoIndex === index
+							? 'bg-purple-200/50'
+							: 'bg-slate-200/50'}
+
+                                        "
+						bind:this={indexPayRanges[index]}
+					>
+						<h2 class="font-bold">
+							{nameCompany} (Avg: {((ranges[0] + ranges[1]) / 2).toLocaleString(
+								'en-GB',
+								{
+									notation: 'compact',
+									currency: 'GBP',
+									style: 'currency'
+								}
+							)}; Min: {ranges[0].toLocaleString('en-GB', {
+								notation: 'compact',
+								currency: 'GBP',
+								style: 'currency'
+							})}; Max: {ranges[1].toLocaleString('en-GB', {
+								notation: 'compact',
+								currency: 'GBP',
+								style: 'currency'
+							})})
+						</h2>
+						{#each values as app}
+							<div
+								class="relative -mx-[10px] h-[40px]"
+								role="button"
+								tabindex={1}
+								onclick={() => {
+									applicationStore.loadItem = app as any;
+									goto('/');
+								}}
+								onkeydown={() => {
+									applicationStore.loadItem = app as any;
+								}}
+							>
+								{#if app.payrange[1]}
+									<div
+										class="bg-blue-500 w-[20px] h-[10px] rounded-full absolute"
+										style="left: {10 +
+											scale(app.payrange[0]) +
+											10}px; top: 50%; transform: translateY(-50%); width: {scale(
+											app.payrange[1]
+										) - scale(app.payrange[0])}px;"
+									></div>
+								{/if}
+								<div
+									class="bg-blue-500 w-[20px] h-[20px] rounded-full absolute"
+									title={`pay: ${app.payrange[0].toLocaleString('en-GB', {
+										notation: 'compact',
+										currency: 'GBP',
+										style: 'currency'
+									})}`}
+									style="left: {10 +
+										scale(
+											app.payrange[0]
+										)}px; top: 50%; transform: translateY(-50%);"
+								></div>
+								{#if app.payrange[1]}
+									<div
+										class="bg-blue-500 w-[20px] h-[20px] rounded-full absolute"
+										title={`pay: ${app.payrange[1].toLocaleString('en-GB', {
+											notation: 'compact',
+											currency: 'GBP',
+											style: 'currency'
+										})}`}
+										style="left: {10 +
+											scale(
+												app.payrange[1]
+											)}px; top: 50%; transform: translateY(-50%);"
+									></div>
+								{/if}
+								{#if context.measureText(app.title).width < scale(app.payrange[1]) - scale(app.payrange[0]) - 40}
+									<div
+										class="absolute text-center text-white font-bold pb-1"
+										style="left: {10 +
+											scale(app.payrange[0]) +
+											10}px;  width: {scale(app.payrange[1]) -
+											scale(app.payrange[0])}px;
+                                                            top: 50%; transform: translateY(-50%); font-size: 10px; "
+									>
+										{app.title}
+									</div>
+								{:else}
+									<div
+										class="absolute text-center font-bold pb-1"
+										style="left: {10 +
+											scale(app.payrange[1] ?? app.payrange[0]) +
+											30}px;
+                                                            top: 50%; transform: translateY(-50%); font-size: 10px; "
+									>
+										{app.title}
+									</div>
+								{/if}
+							</div>
+						{/each}
+					</div>
+				{/if}
+			{/each}
+		{/if}
+	</div>
+</div>
+<div bind:clientWidth={width}>
+	<LineGraph data={payrangeGraphs} xIsDates width={width - 50} height={300} />
+</div>
diff --git a/site/src/routes/graphs/Pie.svelte b/site/src/routes/graphs/Pie.svelte
index 85754f3..69e76a6 100644
--- a/site/src/routes/graphs/Pie.svelte
+++ b/site/src/routes/graphs/Pie.svelte
@@ -27,19 +27,27 @@
 
 		const sum = valueArray.reduce((acc, d) => acc + d, 0);
 
-		let dataf = labelsArray
-			.map((l) => ({ name: l, value: data[l] }))
-			.filter((f) => f.value / sum > sensitivity);
+		let dataf = labelsArray.map((l) => ({
+			name: l,
+			value: data[l],
+			title: `${l}: ${data[l]}`
+		}));
 
-		const otherSum = valueArray.reduce((acc, v) => {
-			if (v / sum > sensitivity) return acc;
-			return acc + v;
+		const other = dataf.filter((v) => v.value / sum < sensitivity);
+
+		dataf = dataf.filter((f) => f.value / sum > sensitivity);
+
+		const otherSum = other.reduce((acc, v) => {
+			return acc + v.value;
 		}, 0);
 
 		if (otherSum > 0) {
 			dataf.push({
 				value: otherSum,
-				name: 'Other'
+				name: 'Other',
+				title: other
+					.toSorted((a, b) => b.value - a.value)
+					.reduce((acc, a) => `${acc}${a.name}: ${a.value}\n`, '')
 			});
 		}
 
@@ -54,11 +62,7 @@
 		const len = groups.length;
 		if (len === 0) {
 			// Do nothing
-		} else if (len === 1) {
-			colors = ['#FFCCC9'];
-		} else if (len === 2) {
-			colors = ['#FFCCC9', '#41EAD4'];
-		} else if (len < 10) {
+		} else if (len >= 3 && len < 10) {
 			colors = d3.schemeBlues[len];
 		} else {
 			colors = [...groups].map((_, i) => d3.interpolateBlues(i / len));
@@ -102,9 +106,7 @@
 			.attr('fill', (d, i) => color(`${names[d.data as number]}-${i}`))
 			.attr('d', arc as unknown as number);
 
-		svg_arcs
-			.append('title')
-			.text((d) => `${names[d.data as number]}: ${values[d.data as number]}`);
+		svg_arcs.append('title').text((d) => dataf[d.data as number].title);
 
 		svg.append('g')
 			.attr('font-family', 'sans-serif')
diff --git a/site/src/routes/graphs/utils.ts b/site/src/routes/graphs/utils.ts
new file mode 100644
index 0000000..3aa3667
--- /dev/null
+++ b/site/src/routes/graphs/utils.ts
@@ -0,0 +1,489 @@
+
+export type Sides = 'left' | 'right' | 'bot' | 'top';
+
+export type AxisProps = {
+    title?: string;
+    titleFontSize?: number;
+    titlePos?: Sides;
+};
+
+export class Axis {
+    private _title?: string;
+    private _titleFontSize: number;
+    private _titlePos: Sides;
+
+    constructor({ title, titleFontSize, titlePos }: AxisProps = {}) {
+        this._title = title;
+        this._titleFontSize = titleFontSize ?? 15;
+        this._titlePos = titlePos ?? 'left';
+    }
+
+    getPadding() {
+        if (!this._title) return 0;
+        return this._titleFontSize + 4;
+    }
+
+    apply_title(
+        svg: d3.Selection<KnownAny, KnownAny, null, KnownAny>,
+        height: number,
+        width: number,
+        padding: number
+    ) {
+        if (!this._title) return undefined;
+        if (this._titlePos === 'left') {
+            return (
+                svg
+                    .append('text')
+                    .attr('text-anchor', 'middle')
+                    .attr('transform', 'rotate(-90)')
+                    .attr('font-size', `${this._titleFontSize}px`)
+                    .attr('font-family', 'Open sans')
+                    // y becomes x
+                    .attr('x', -height / 2)
+                    .attr('y', -padding + this._titleFontSize + 4)
+                    .text(this._title)
+            );
+        }
+        if (this._titlePos === 'right') {
+            return (
+                svg
+                    .append('text')
+                    .attr('text-anchor', 'middle')
+                    .attr('transform', 'rotate(90)')
+                    .attr('font-size', `${this._titleFontSize}px`)
+                    .attr('font-family', 'Open sans')
+                    // y becomes x
+                    .attr('x', height / 2)
+                    .attr('y', -width - padding + this._titleFontSize + 4)
+                    .text(this._title)
+            );
+        }
+        if (this._titlePos === 'bot') {
+            return svg
+                .append('text')
+                .attr('text-anchor', 'middle')
+                .attr('font-size', `${this._titleFontSize}px`)
+                .attr('font-family', 'Open sans')
+                .attr('x', width / 2)
+                .attr('y', height + padding - 4)
+                .text(this._title);
+        }
+        if (this._titlePos === 'top') {
+            return svg
+                .append('text')
+                .attr('text-anchor', 'middle')
+                .attr('font-size', `${this._titleFontSize}px`)
+                .attr('font-family', 'Open sans')
+                .attr('x', width / 2)
+                .attr('y', -padding + this._titleFontSize)
+                .text(this._title);
+        }
+
+        console.error('Unknown title pos', this.titlePos);
+        return undefined;
+    }
+
+    //
+    // Builder pattern functions
+    //
+    title(title?: string) {
+        this._title = title;
+        return this;
+    }
+
+    titlePos(pos: Sides) {
+        this._titlePos = pos;
+        return this;
+    }
+
+    titleFontSize(size: number) {
+        this._titleFontSize = size;
+        return this;
+    }
+
+    enforcePos(pos: 'vert' | 'hoz', defaultPos: Sides) {
+        if (pos === 'vert') {
+            if (this._titlePos !== 'top' && this._titlePos !== 'bot') {
+                return this.titlePos(defaultPos);
+            }
+        } else {
+            if (this._titlePos !== 'left' && this._titlePos !== 'right') {
+                return this.titlePos(defaultPos);
+            }
+        }
+        return this;
+    }
+}
+
+export type EnforceSizeType = [number, number];
+
+export function enforceSizeHelper<
+    H extends Record<NamesH, number>,
+    NamesH extends string = ''
+>(width: number, height: number, enforce: boolean): EnforceHelper<NamesH, H> {
+    const c = document.createElement('canvas');
+    const ctx = c.getContext('2d');
+    if (!ctx) throw new Error('Failed to get ctx');
+
+    const r = {
+        _width: width,
+        _height: height,
+        _enforce: enforce,
+        _w_p: 0,
+
+        _h_indicators: [] as Indicator<NamesH>[]
+    } as EnforceHelper<NamesH, H>;
+
+    r.h = (name, h, type, data, font) => {
+        const nr = r as EnforceHelper<
+            NamesH | typeof name,
+            Record<NamesH | typeof name, number>
+        >;
+
+        // TODO maybe update the values
+        if (nr[name]) {
+            return r;
+        }
+
+        let size = 0;
+        if (typeof h === 'string') {
+            if (h.endsWith('rem')) {
+                const rem = Number(h.substring(0, h.length - 3));
+                if (Number.isNaN(rem)) {
+                    throw new Error('h is not a valid rem value');
+                }
+                size =
+                    rem *
+                    Number.parseFloat(
+                        getComputedStyle(document.documentElement).fontSize
+                    );
+            } else {
+                const n = Number(h);
+                if (Number.isNaN(n)) {
+                    throw new Error('h is not a number');
+                }
+                size = n;
+            }
+        } else {
+            size = h;
+        }
+
+        if (size < 0) throw Error('h is negative');
+
+        nr._h_indicators.push({
+            name,
+            size,
+            type: type ?? 'fixed',
+            data,
+            font
+        });
+
+        (nr as KnownAny)[name] = size;
+
+        return nr as KnownAny;
+    };
+
+    r.w_p = (h) => {
+        let size = 0;
+        if (typeof h === 'string') {
+            if (h.endsWith('rem')) {
+                const rem = Number(h.substring(0, h.length - 3));
+                if (Number.isNaN(rem)) {
+                    throw new Error('h is not a valid rem value');
+                }
+                size =
+                    rem *
+                    Number.parseFloat(
+                        getComputedStyle(document.documentElement).fontSize
+                    );
+            } else {
+                const n = Number(h);
+                if (Number.isNaN(n)) {
+                    throw new Error('h is not a number');
+                }
+                size = n;
+            }
+        } else {
+            size = h;
+        }
+        r._w_p = size * 2;
+        return r;
+    };
+
+    r.enforce = (inEnforce) => {
+        const e = inEnforce ?? r._enforce;
+        if (!e) return r;
+
+        let h_sum = 0;
+        for (const i of r._h_indicators) {
+            h_sum += i.size;
+        }
+
+        // TODO handle width
+        if (h_sum < r._height && !r._h_indicators.some((i) => i.type === 'left'))
+            return r;
+
+        let fSize = r._h_indicators.reduce((acc, i) => {
+            if (i.type !== 'fixed') return acc;
+            return acc + i.size;
+        }, 0);
+
+        // you are fucked anyway
+        if (fSize > r._height) return r;
+
+        const h_leftover = h_sum - fSize;
+        const th_leftover = r._height - fSize;
+
+        const pr = r._h_indicators
+            .filter((i) => i.type === 'dyanmic' || i.type === 'text')
+            .map((i) => {
+                return [i, (i.size / h_leftover) * th_leftover] as const;
+            });
+
+        for (const i of pr) {
+            let s = i[1];
+            if (i[0].type === 'text') {
+                s = Math.floor(
+                    getFitSizeForList(
+                        [i[0].data ?? ''],
+                        r._width - r._w_p,
+                        i[1],
+                        0.5,
+                        ctx,
+                        i[0].font
+                    ) ?? i[1]
+                );
+            }
+
+            fSize += s;
+            (r as KnownAny)[i[0].name] = s;
+        }
+
+        const left = r._h_indicators.filter((i) => i.type === 'left');
+        const len_left = left.length;
+
+        const rest = r._height - fSize;
+
+        for (const i of left) {
+            (r as KnownAny)[i.name] = rest / len_left;
+        }
+
+        return r as KnownAny;
+    };
+
+    r.toEnfoceSize = (name) => {
+        if (!r._enforce) return;
+        return [r._width - r._w_p, r[name]];
+    };
+
+    return r;
+}
+enforceSizeHelper.fromEnforceSize = (enforceSize?: EnforceSizeType) => {
+    return enforceSizeHelper(
+        enforceSize?.[0] ?? 0,
+        enforceSize?.[1] ?? 0,
+        !!enforceSize
+    );
+};
+
+export type PaddingManagerProps = {
+    width: number;
+    height: number;
+    fontSize?: number;
+};
+
+export type Paddable = number | Axis | string[] | string | undefined;
+
+export class PaddingManager {
+    canvas: HTMLCanvasElement;
+    ctx: CanvasRenderingContext2D;
+
+    width: number;
+    height: number;
+
+    private _paddingLeft = 0;
+    private _paddingRight = 0;
+    private _paddingTop = 0;
+    private _paddingBot = 0;
+
+    private _fontSize = 15;
+
+    private _enforceSize?: EnforceSizeType;
+
+    constructor({ width, height, fontSize }: PaddingManagerProps) {
+        this.width = width;
+        this.height = height;
+
+        if (fontSize !== undefined) {
+            this._fontSize = fontSize;
+        }
+
+        // This is used to calculate the size of text
+        this.canvas = document.createElement('canvas');
+        const ctx = this.canvas.getContext('2d');
+        if (!ctx) {
+            throw new Error('Failed to create context for the internal canvas');
+        }
+        this.ctx = ctx;
+        this.ctx.font = `${this._fontSize}px Open sans`;
+    }
+
+    get paddedHeight() {
+        return this.height + this._paddingTop + this._paddingBot;
+    }
+
+    get paddedWidth() {
+        return this.width + this._paddingLeft + this._paddingRight;
+    }
+
+    set fontSize(size: number) {
+        this._fontSize = size;
+        this.ctx.font = `${this._fontSize}px Open sans`;
+    }
+
+    get fontSize() {
+        return this._fontSize;
+    }
+
+    get left() {
+        return this._paddingLeft;
+    }
+
+    get right() {
+        return this._paddingRight;
+    }
+
+    get top() {
+        return this._paddingTop;
+    }
+
+    get bot() {
+        return this._paddingBot;
+    }
+
+    get translateString() {
+        return `translate(${this.left},${this.top})`;
+    }
+
+    //
+    // Add padding
+    //
+    pad(side: Sides, padding: Paddable, angle?: number) {
+        let pn = 0;
+
+        if (padding === undefined) {
+            return this;
+        }
+        if (typeof padding === 'number') {
+            pn = padding;
+        } else if (typeof padding === 'string') {
+            let a: number | undefined = undefined;
+            if (angle !== undefined) {
+                a = angle * (Math.PI / 180);
+            }
+            pn = this.ctx.measureText(padding).width * Math.sin(a ?? Math.PI / 2);
+        } else if (Array.isArray(padding)) {
+            pn = padding.reduce(
+                (acc, s) => Math.max(this.ctx.measureText(s).width, acc),
+                0
+            );
+        } else {
+            pn = padding.getPadding();
+        }
+
+        switch (side) {
+            case 'left':
+                this._paddingLeft += pn;
+                return this;
+            case 'right':
+                this._paddingRight += pn;
+                return this;
+            case 'top':
+                this._paddingTop += pn;
+                return this;
+            case 'bot':
+                this._paddingBot += pn;
+                return this;
+            default:
+                throw new Error(`unknown side: ${side}`);
+        }
+    }
+
+    padHoz(padding: Paddable) {
+        return this.pad('left', padding).pad('right', padding);
+    }
+
+    padLeft(padding: Paddable, angle?: number) {
+        return this.pad('left', padding, angle);
+    }
+
+    padRight(padding: Paddable, angle?: number) {
+        return this.pad('right', padding, angle);
+    }
+
+    padTop(padding: Paddable, angle?: number) {
+        return this.pad('top', padding, angle);
+    }
+
+    padBot(padding: Paddable, angle?: number) {
+        return this.pad('bot', padding, angle);
+    }
+
+    resetPadding(side: Sides) {
+        switch (side) {
+            case 'left':
+                this._paddingLeft = 0;
+                return this;
+            case 'right':
+                this._paddingRight = 0;
+                return this;
+            case 'top':
+                this._paddingTop = 0;
+                return this;
+            case 'bot':
+                this._paddingBot = 0;
+                return this;
+            default:
+                throw new Error(`unknown side: ${side}`);
+        }
+    }
+
+    padAll(n: number) {
+        this._paddingLeft += n;
+        this._paddingRight += n;
+        this._paddingTop += n;
+        this._paddingBot += n;
+        return this;
+    }
+
+    enforce(inEnforce?: EnforceSizeType) {
+        const enforce = this._enforceSize ?? inEnforce;
+        if (enforce === undefined) return this;
+
+        if (this.paddedWidth !== enforce[0]) {
+            this.width = enforce[0] - this.left - this.right;
+        }
+        if (this.paddedHeight !== enforce[1]) {
+            this.height = enforce[1] - this.top - this.bot;
+        }
+
+        return this;
+    }
+}
+
+export function countReducer(acc: Record<number, number>, a: { c: number | string | Date }) {
+    const c = new Date(a.c);
+    c.setHours(0);
+    c.setMinutes(0);
+    c.setSeconds(0);
+    c.setMilliseconds(0);
+    const ct = c.getTime();
+
+    if (acc[ct]) {
+        acc[ct] += 1;
+    } else {
+        acc[ct] = 1;
+    }
+    return acc;
+}
+
diff --git a/site/src/routes/work-area/CompanyField.svelte b/site/src/routes/work-area/CompanyField.svelte
index 51b6cb2..20ccab9 100644
--- a/site/src/routes/work-area/CompanyField.svelte
+++ b/site/src/routes/work-area/CompanyField.svelte
@@ -9,11 +9,15 @@
 		applicationStore.all[index].company === ''
 			? []
 			: [...companies.values()].filter((a) => {
-					// TODO improve this a lot I want to make like matching algo
-					return (
-						a.match(applicationStore.all[index].company) &&
-						a !== applicationStore.all[index].company
-					);
+					try {
+						// TODO improve this a lot I want to make like matching algo
+						return (
+							a.match(applicationStore.all[index].company) &&
+							a !== applicationStore.all[index].company
+						);
+					} catch {
+						return false;
+					}
 				})
 	);
 </script>
diff --git a/site/src/routes/work-area/SearchApplication.svelte b/site/src/routes/work-area/SearchApplication.svelte
index 4a165e1..b848c4b 100644
--- a/site/src/routes/work-area/SearchApplication.svelte
+++ b/site/src/routes/work-area/SearchApplication.svelte
@@ -1,5 +1,6 @@
 <script lang="ts">
 	import { applicationStore, type Application } from '$lib/ApplicationsStore.svelte';
+	import InplaceDialog from '$lib/InplaceDialog.svelte';
 	import { statusStore } from '$lib/Types.svelte';
 
 	let {
@@ -11,9 +12,27 @@
 	} = $props();
 
 	let filter = $state('');
+	let filterStatus: string[] = $state([]);
+	let advFilters = $state(false);
+
+	type ExtraFilterType =
+		| {
+				type: 'name';
+				text: string;
+		  }
+		| { type: 'company'; text: string }
+		| { type: 'query'; text: string };
+
+	let extraFiltersToDisplay: ExtraFilterType[] = $state([]);
 
 	let dialogElement: HTMLDialogElement;
 
+	$effect(() => {
+		if (!filter) {
+			extraFiltersToDisplay = [];
+		}
+	});
+
 	function docKey(e: KeyboardEvent) {
 		if (e.ctrlKey && e.code === 'KeyK') {
 			dialogElement.showModal();
@@ -38,36 +57,135 @@
 			if (application && i.id == application.id) {
 				return false;
 			}
+
+			if (filterStatus.length !== 0 && !filterStatus.includes(i.status_id ?? '')) {
+				return false;
+			}
+
 			if (!filter) {
 				return true;
 			}
 
 			if (filter.includes('@') && i.company) {
 				const splits = filter.split('@');
-				const f = new RegExp(splits[0].trim(), 'ig');
-				const c = new RegExp(splits[1].trim(), 'ig');
-				return i.title.match(f) && i.company.match(c);
+
+				const newExtraFilters: ExtraFilterType[] = [];
+				const name = splits[0].trim();
+				const company = splits[1].trim();
+				if (name.length !== 0) {
+					newExtraFilters.push({
+						type: 'name',
+						text: name
+					});
+				}
+				if (company.length !== 0) {
+					newExtraFilters.push({
+						type: 'company',
+						text: company
+					});
+				}
+				extraFiltersToDisplay = newExtraFilters;
+
+				try {
+					const f = new RegExp(name, 'ig');
+					const c = new RegExp(company, 'ig');
+					return i.title.match(f) && i.company.match(c);
+				} catch {
+					return false;
+				}
 			}
 
-			const f = new RegExp(filter, 'ig');
+			extraFiltersToDisplay = [{ type: 'query', text: filter }];
+			try {
+				const f = new RegExp(filter, 'ig');
+				let x = i.title;
 
-			let x = i.title;
+				if (i.company) {
+					x = `${x} @ ${i.company}`;
+				}
 
-			if (i.company) {
-				x = `${x} @ ${i.company}`;
+				return x.match(f);
+			} catch {
+				return false;
 			}
-
-			return x.match(f);
 		})
 	);
 </script>
 
 <dialog class="card max-w-[50vw]" bind:this={dialogElement}>
-	<div class="flex">
-		<input placeholder="Filter" class="p-2 flex-grow" bind:value={filter} />
-		<div>
-			{internal.length}
+	<div class="flex sticky top-0 bg-white z-50 p-2 shadow-lg rounded-lg gap-2 flex-col">
+		<div class="flex items-center gap-2">
+			<input placeholder="Filter" class="p-2 flex-grow" bind:value={filter} />
+			<button
+				onclick={() => {
+					advFilters = !advFilters;
+				}}
+			>
+				<span class="bi bi-filter"></span>
+			</button>
+			<div>
+				{internal.length}
+			</div>
 		</div>
+		{#if advFilters}
+			<div>
+				<InplaceDialog
+					buttonClass="border-slate-300 border border-solid color-slate-300 p-1 rounded-md bg-slate-100/50"
+				>
+					{#snippet buttonChildren()}
+						<i class="bi bi-plus"></i> Status
+					{/snippet}
+					<div class="flex flex-wrap gap-2">
+						{#each statusStore.nodes.filter((a) => !filterStatus.includes(a.id)) as node}
+							<button
+								class="border-violet-300 border border-solid color-violet-300 bg-violet-100/50 p-1 rounded-md text-violet-800"
+								onclick={() => {
+									//filterStatus.push(node.id);
+									//filterStatus = filterStatus;
+									filterStatus = [...filterStatus, node.id];
+								}}
+							>
+								{node.name}
+							</button>
+						{/each}
+					</div>
+				</InplaceDialog>
+			</div>
+			<h2>Filters</h2>
+			<div class="flex gap-2">
+				{#each statusStore.nodes.filter((a) => filterStatus.includes(a.id)) as node}
+					<button
+						class="border-violet-300 border border-solid color-violet-300 bg-violet-100/50 text-violet-800 p-1 rounded-md"
+						onclick={() => {
+							filterStatus = filterStatus.filter((a) => a != node.id);
+						}}
+					>
+						{node.name}
+					</button>
+				{/each}
+				{#each extraFiltersToDisplay as filter}
+					{#if filter.type === 'name'}
+						<span
+							class="border-blue-300 border border-solid color-blue-300 bg-blue-100/50 p-1 rounded-md"
+						>
+							Name ~ /<span class="text-blue-800 text-bold">{filter.text}</span>/
+						</span>
+					{:else if filter.type === 'company'}
+						<span
+							class="border-green-300 border border-solid color-green-300 bg-green-100/50 p-1 rounded-md"
+						>
+							Company ~ /<span class="text-green-800 text-bold">{filter.text}</span>/
+						</span>
+					{:else if filter.type === 'query'}
+						<span
+							class="border-orange-300 border border-solid color-orange-300 bg-orange-100/50 p-1 rounded-md"
+						>
+							Query ~ /<span class="text-orange-800 text-bold">{filter.text}</span>/
+						</span>
+					{/if}
+				{/each}
+			</div>
+		{/if}
 	</div>
 	<div class="overflow-y-auto overflow-x-hidden flex-grow p-2">
 		<!-- TODO loading screen -->
diff --git a/site/src/routes/work-area/Timeline.svelte b/site/src/routes/work-area/Timeline.svelte
index 2aa9346..713cde9 100644
--- a/site/src/routes/work-area/Timeline.svelte
+++ b/site/src/routes/work-area/Timeline.svelte
@@ -112,11 +112,9 @@
 				<!-- TODO -->
 				<!-- || !endable.includes(event.new_status) -->
 				{#if i != events.length - 1 || !statusStore.nodesR[event.new_status_id].endable}
-					<div
-						class="min-w-[70px] h-[18px] bg-blue-500 -mx-[10px] px-[20px] flex-grow text-center"
-					>
+					<div class="h-[18px] bg-blue-500 -mx-[10px] px-[20px] flex-grow text-center">
 						{#if event.timeDiff}
-							<div class="-mt-[3px] text-white">
+							<div class="-mt-[3px] text-white text-nowrap whitespace-nowrap">
 								<span class="bi bi-clock"></span>
 								{event.timeDiff}
 							</div>
diff --git a/site/src/routes/work-area/WorkArea.svelte b/site/src/routes/work-area/WorkArea.svelte
index d418eda..a8ae0ad 100644
--- a/site/src/routes/work-area/WorkArea.svelte
+++ b/site/src/routes/work-area/WorkArea.svelte
@@ -125,7 +125,16 @@
 		if (!lastExtData || activeItem === undefined || !derivedItem) return;
 		applicationStore.all[activeItem].title = lastExtData.jobTitle.replace(/\&amp;/, '&');
 		applicationStore.all[activeItem].company = lastExtData.company.replace(/\&amp;/, '&');
-		applicationStore.all[activeItem].payrange = lastExtData.money;
+
+		if (
+			!(
+				applicationStore.all[activeItem].payrange.match('Glassdoor est.') &&
+				lastExtData.money.match('Glassdoor est.')
+			) &&
+			!(applicationStore.all[activeItem].payrange !== '' && lastExtData.money === '')
+		) {
+			applicationStore.all[activeItem].payrange = lastExtData.money;
+		}
 
 		const title: string = lastExtData.jobTitle;
 		if (title.match(/intern|apprenticeship/i)) {
@@ -291,6 +300,23 @@
 						</div>
 					</fieldset>
 				{/if}
+				{#if showExtraData}
+					<div>
+						<div class="flabel">Simple Url</div>
+						<div class="flex flex-col gap-2">
+							{#each derivedItem.urls as url}
+								<div>
+									<button
+										class="text-violet-300 text-nowrap whitespace-nowrap overflow-x-hidden"
+										onclick={() => {
+											openWindow(url);
+										}}>{url}</button
+									>
+								</div>
+							{/each}
+						</div>
+					</div>
+				{/if}
 				<fieldset>
 					<label class="flabel" for="title">Job Level</label>
 					<select