diff --git a/app.tpl b/app.tpl
new file mode 100644
index 0000000..30c5596
--- /dev/null
+++ b/app.tpl
@@ -0,0 +1,5 @@
+{{define "main"}}
+<main id="app" class='fade-in-2'>
+</main>
+<script type="module" src="/assets/app.js" ></script>
+{{end}}
diff --git a/components/app.vue b/components/app.vue
index 70f0c30..ba6a806 100644
--- a/components/app.vue
+++ b/components/app.vue
@@ -27,7 +27,7 @@ v-else-if="active == 3"
 :token="token" 
 @addFeeTemp="(f) => fees.push(f)"
 @removeFeeTemp="(fee) => fees = fees.filter(f => f.id != fee.id)"
-@preview="previewEstimate"
+@download="downloadEstimate"
 />
 
 <settings
@@ -224,9 +224,8 @@ function start() {
 
 }
 
-function previewEstimate(estimate) {
-    this.preview = estimate
-    window.location.hash = 'estimate'
+function downloadEstimate(estimate) {
+
 }
 
 export default {
@@ -251,7 +250,7 @@ export default {
 		getAvatar,
 		updateLetterhead,
 		getLetterhead,
-		previewEstimate,
+		downloadEstimate,
 	},
 	data() {
 		return {
@@ -261,7 +260,6 @@ export default {
 			fees: [],
 			loadingError: "",
 			token: '',
-			preview: null,
 		}
 	},
 	created() {
diff --git a/components/estimates.vue b/components/estimates.vue
index 8f98a91..cbd1730 100644
--- a/components/estimates.vue
+++ b/components/estimates.vue
@@ -54,7 +54,7 @@ ${{(estimate.price / 100).toLocaleString()}}
 <label>Total monthly: ${{format(l.result.totalMonthly)}}</label>
 <label>Cash to close: ${{format(l.result.cashToClose)}}</label>
 </div>
-<button @click="() => $emit('preview', estimate)">Preview</button>
+<button @click="() => $emit('download', estimate)">Download</button>
 <button @click="() => estimate = null">Cancel</button>
 </div>
 
diff --git a/components/new.vue b/components/new.vue
new file mode 100644
index 0000000..75b2167
--- /dev/null
+++ b/components/new.vue
@@ -0,0 +1,386 @@
+<template>
+<div id="new" class="page">
+
+<h2>New Loan</h2>
+
+<section class="loans-list">
+
+<h3 v-for="(l, indx) in loans"
+:class="sel == indx ? 'sel' : ''"
+@click="() => sel = indx"
+>
+{{l.title}}
+</h3>
+
+<div class="add">
+<svg @click="create"
+xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor"
+class="bi bi-plus" viewBox="0 0 16 16"> <path d="M8 4a.5.5 0 0 1 .5.5v3h3a.5.5 0
+0 1 0 1h-3v3a.5.5 0 0 1-1 0v-3h-3a.5.5 0 0 1 0-1h3v-3A.5.5 0 0 1 8 4z"/> </svg>
+</div>
+</section>
+
+<section class="form inputs">
+<h3>Loan</h3>
+<label>Name</label>
+<input :value="loans[sel].title" required
+@input="(e) => loans[sel].title = stripLetters(e)">
+<button @click="del">Delete</button>
+</section>
+
+<section class="form inputs">
+
+<div class="hint">
+	<img class="icon" src="/assets/image/icon/question-circle.svg" alt="">
+	<div class="tooltip">
+		<p>Assumes borrower is not self employed, not bankrupt in the past 7
+		years, a citizen, and intends to occupy the property.</p>
+	</div>
+</div>
+
+<h3>Borrower</h3>
+<label>Number of Borrowers</label>
+<input :value="estimate.borrowers"
+@input="(e) => estimate.borrowers = stripInt(e)">
+<label>Credit Score</label>
+<input :value="estimate.creditScore"
+@input="(e) => estimate.creditScore = stripInt(e)">
+<label>Monthly Income ($)</label>
+<input :value="estimate.mIncome"
+@input="(e) => estimate.mIncome = strip(e)">
+
+</section>
+
+<section class="radios form">
+<h3>Transaction Type</h3>
+<input selected type="radio" name="transaction_type" value="0"
+v-model="estimate.transaction" >
+<label>Purchase</label>
+<input type="radio" name="transaction_type" value="1"
+v-model="estimate.transaction">
+<label>Refinance</label>
+</section>
+
+<section class="form inputs">
+<h3>Property Details</h3>
+<label>Price ($)</label>
+<input :value="estimate.price" @input="setPrice">
+<label>Type</label>
+<select id="" name="" v-model="estimate.property">
+	<option value="attched">Single Family Attached</option>
+	<option value="detached">Single Family Detached</option>
+	<option value="lorise">Lo-rise (4 stories or less)</option>
+	<option value="hirise">Hi-rise (over 4 stories)</option>
+</select>
+</section>
+
+<section class="radios form">
+<h3>Loan Type</h3>
+<input type="radio" name="loan_type" value="conv" v-model="loans[sel].type"
+>
+<label>Conventional</label>
+<input type="radio" name="loan_type" value="fha" v-model="loans[sel].type">
+<label>FHA</label>
+<input type="radio" name="loan_type" value="va" v-model="loans[sel].type">
+<label>VA</label>
+<input type="radio" name="loan_type" value="usda" v-model="loans[sel].type">
+<label>USDA</label>
+</section>
+
+<section class="form inputs">
+<h3>Loan Details</h3>
+<label>Loan Term (years)</label>
+<input :value="loans[sel].term"
+@input="(e) => loans[sel].term = strip(e)">
+
+<label>Loan Program</label>
+<select id="" name="" v-model="loans[sel].program">
+	<option value="none">None</option>
+</select>
+
+<label>Loan to Value (%)</label>
+<input :value="loans[sel].ltv" @input="setLtv">
+<label>Loan Amount ($)</label>
+<input :value="loans[sel].amount"
+@input="setAmount">
+<label>Housing Expense DTI (%) - Optional</label>
+<input :value="loans[sel].housingDti" @input="setHousingDti">
+<label>Total DTI (%) - Optional</label>
+<input :value="loans[sel].dti" @input="setDti">
+<label>Home Owner's Association ($/month)</label>
+<input :value="loans[sel].hoa"
+@input="(e) => { loans[sel].hoa = strip(e) }">
+
+<label>Interest Rate (%)</label>
+<input :value="loans[sel].interest"
+@input="(e) => { loans[sel].interest = stripPerc(e) }">
+<label>Days of Interest</label>
+<input :value="loans[sel].interestDays"
+@input="(e) => {loans[sel].interestDays = stripInt(e)}">
+
+<label>Hazard Insurance Escrow (months)</label>
+<input :value="loans[sel].hazardEscrow"
+@input="(e) => {loans[sel].hazardEscrow = stripInt(e)}">
+<label>Hazard Insurance ($/month)</label>
+<input :value="loans[sel].hazard"
+@input="(e) => {loans[sel].hazard = strip(e)}">
+
+<label>Real Estate Tax Escrow (months)</label>
+<input :value="loans[sel].taxEscrow"
+@input="e => {loans[sel].taxEscrow = stripInt(e)}">
+<label>Real Estate Tax ($/month)</label>
+<input :value="loans[sel].tax"
+@input="(e) => {loans[sel].tax = strip(e)}">
+</section>
+
+<section class="form inputs">
+<h3>Fees</h3>
+<div v-for="(fee, indx) in estimate.loans[sel].fees"
+:key="fee.name + indx" class="fee"
+>
+	<label>
+	${{fee.amount}}{{ fee.perc ? ` ${fee.perc}%` : ''}} - {{fee.name}}<br>
+	{{fee.type}}
+	</label>
+	<img width="21" height="21" src="/assets/image/icon/x-red.svg"
+	@click="() => estimate.loans[sel].fees.splice(indx, 1)">
+</div>
+<button @click="resetFees">Reset</button>
+<button @click="createFee">New</button>
+</section>
+
+<fee-dialog v-if="newFee"
+	:heading="'New Fee'"
+	:initial="{}"
+	:price="estimate.price"
+	@close="() => newFee = null"
+	@save="addFee"
+/>
+
+<section class="form radios">
+<h3>Mortgage Insurance</h3>
+<input type="radio" name="transaction_type" value="transaction"
+@input="e => estimate.transaction = 0"
+selected="estimate.transaction == 0">
+<label>1.43% - National MI</label>
+<input type="radio" name="transaction_type" value="refinance"
+@input="e => estimate.transaction = 1"
+selected="estimate.transaction == 1">
+<label>0.73% - MGIC</label>
+</section>
+
+<section class="form inputs">
+
+	<button @click="generate">Generate</button>
+
+	<div class="errors">
+	<span v-for="e in errors">{{e}}</span>
+	</div>
+
+</section>
+
+</div>
+</template>
+
+<script>
+import Dialog from "./dialog.vue"
+import FeeDialog from "./fee-dialog.vue"
+import { stripLetters, strip, stripInt, stripPerc } from "../helpers.js" 
+
+// The default values of a new estimate
+const example = {
+		title: "Example",
+		type: "",
+		term: 0,
+		ltv: 0, // Loan to home value ratio
+		dti: 0,
+		housingDti: 0,
+		amount: 0,
+		interest: 0,
+		interestDays: 0,
+		hazard: 0, // Hazard insurance monthly payment
+		hazardEscrow: 0, // Hazard insurance escrow in months (0 is none)
+		tax: 0, // Real Estate taxes monthly payment
+		taxEscrow: 0, // Months to escrow (0 is none)
+		hoa: 100, // Home owner's association monthly fee
+		program: "",
+		pud: true, // Property under development
+		zip: '',
+		fees: [],
+}
+
+// The default loans on a new estimate
+const loans = [
+	Object.assign({}, example,),
+	Object.assign(
+		Object.assign({}, example),
+		{title: "Another One",}
+	),
+]
+
+// Default estimate fields
+const estimate = {
+	property: "",
+	transaction: 0,
+	price: 0,
+	borrowers: 0,
+	creditScore: 0,
+	mIncome: 0,
+	loans: loans,
+}
+
+const newFee = {
+	name: '', type: '', amount: 0, perc: 0
+ }
+
+// Clone loan from initial example as a new loan
+function create() {
+	this.estimate.loans.push(
+		Object.assign({}, example, {fees: this.createFees()})
+	)
+}
+
+function createFees() {
+	return this.fees.map(f => Object.assign({}, f))
+}
+
+// Setup this.newFee for the creation dialog
+function createFee() {
+	this.newFee = Object.assign({}, newFee)
+}
+
+function resetFees() {
+	this.estimate.loans[this.sel].fees = this.createFees()
+}
+
+// If valid, add the current this.newFee to the array of fees and reset
+// this.newFee to null
+function addFee(fee, isDebit) {
+
+	if (!isDebit) fee.amount = fee.amount * -1
+	this.estimate.loans[this.sel].fees.push(fee)
+	this.newFee = null
+}
+
+function del() {
+	if (this.loans.length > 1) {
+		let x = this.sel
+		this.sel = 0
+		this.loans.splice(x, 1)
+	}
+}
+
+// Changes loan.ltv's <input> and data() values, then syncs with data.amount
+function setLtv(e) {
+	let ltv = strip(e)
+	let loan = this.loans[this.sel]
+	if (!this.estimate.price) return
+
+	if (ltv > 100) ltv = 100
+	if (ltv < 0) ltv = 0
+
+	loan.ltv = ltv
+	loan.amount = (ltv / 100 * this.estimate.price).toFixed(2)
+}
+
+// Changes loan.amount's <input> and data() values, then syncs with data.ltv
+function setAmount(e) {
+	let amount = strip(e)
+	let loan = this.loans[this.sel]
+	if (!this.estimate.price) return
+
+	if (amount > loan.price) amount = loan.price
+	if (amount < 0) amount = 0
+
+	loan.amount = amount
+	loan.ltv = (amount / this.estimate.price * 100).toFixed(2)
+}
+
+// Updates the property price for all loans and their fee amounts.
+function setPrice(e) {
+	let value = strip(e)
+	this.estimate.price = value
+	this.estimate.loans[this.sel].fees.forEach(fee => {
+		if (fee.perc) fee.amount = (fee.perc / 100 * value).toFixed(2)
+	})
+}
+
+function setDti(e) {
+	let dti = strip(e)
+	let loan = this.loans[this.sel]
+	if (!loan.price) return
+
+	if (dti > 100) dti = 100
+	if (dti < 0) dti = 0
+
+	e.target.value = dti
+	loan.dti = dti
+}
+
+function setHousingDti(e) {
+	let housingDti = strip(e)
+	let loan = this.loans[this.sel]
+	if (!loan.price) return
+
+	if (housingDti > 100) housingDti = 100
+	if (housingDti < 0) housingDti = 0
+
+	e.target.value = housingDti
+	loan.housingDti = housingDti
+}
+
+function generate() {
+	this.errors = this.validate()
+}
+
+function validate() {
+	let errors = []
+	const estimate = this.estimate
+
+	// Alternative attribute names for error messages
+	const names = {
+		term: "loan term",
+		ltv: "loan to value",
+		hazard: "hazard insurance",
+		hazardEscrow: "hazard insurance escrow",
+	}
+
+	if (!estimate.property) {
+		errors.push("Missing property type.")
+	} else if (!estimate.price) {
+		errors.push("Missing property price.")
+	} else if (!estimate.borrowers) {
+		errors.push("Missing number of borrowers.")
+	} else if (!estimate.creditScore) {
+		errors.push("Missing credit score.")
+	} else if (!estimate.mIncome) {
+		errors.push("Missing monthly income.")
+	}
+
+	return errors
+}
+
+// Percentage values of fees always takek precedent over amounts. The conversion
+// happens in setPrice()
+export default {
+	components: { Dialog, FeeDialog },
+	methods: {
+		setPrice, setLtv, setAmount, setDti, setHousingDti, strip, stripInt,
+		stripLetters, del, create, createFees, createFee, resetFees,
+		addFee, generate, validate
+	},
+	props: ['user', 'fees'],
+	data() {
+		return {
+				estimate: estimate,
+				loans: estimate.loans,
+				sel: 0,
+				newFee: null,
+				errors: [],
+			}
+	},
+	created() {
+		this.estimate.loans.forEach(l => l.fees = this.createFees())
+	}
+}
+</script>
diff --git a/config.default.go b/config.default.go
new file mode 100644
index 0000000..08da55e
--- /dev/null
+++ b/config.default.go
@@ -0,0 +1,9 @@
+/*
+package main
+
+var config = map[string]string {
+	"dbUsername": "",
+	"dbPassword": "",
+}
+*/
+package main
diff --git a/home.tpl b/home.tpl
new file mode 100644
index 0000000..d4b17c4
--- /dev/null
+++ b/home.tpl
@@ -0,0 +1,13 @@
+{{define "header"}}
+<header class="default fade-in">
+<nav>
+	<li></li>
+	<li></li>
+</nav>
+</header>
+{{end}}
+
+{{define "main"}}
+<main class='fade-in-2'>
+</main>
+{{end}}
diff --git a/master.tpl b/master.tpl
new file mode 100644
index 0000000..bbf5550
--- /dev/null
+++ b/master.tpl
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<head>
+	<meta charset='utf-8'>
+    <meta name="viewport"
+	content="width=device-width, initial-scale=1, shrink-to-fit=no">
+	<link rel="stylesheet" href="/assets/main.css">
+	<link rel="shortcut icon" type="image/svg+xml"
+	href="/assets/image/icon/hat2.png" />
+	<title>Skouter - {{.Title}}</title> 
+</head>
+
+<body>
+{{block "header" .}}
+{{end}}
+
+{{template "main" .}}
+</body>
diff --git a/skouter.go b/skouter.go
index 51628be..dd75eff 100644
--- a/skouter.go
+++ b/skouter.go
@@ -2408,9 +2408,6 @@ func route(w http.ResponseWriter, r *http.Request) {
         page = pages[ "terms" ]
     case match(p, "/app", &args):
         page = pages[ "app" ]
-    case match(p, "/test", &args):
-		checkPdf(w, r)
-		return
     default:
         http.NotFound(w, r)
         return
@@ -2646,11 +2643,16 @@ func seedEstimates(db *sql.DB, users []User, ltypes []LoanType) []Estimate {
 			estimate.Loans = append(estimate.Loans, l)
 		}
 
-		err = estimate.insertEstimate(db)
-		if err != nil {log.Println(err); return estimates}
-		
 		estimates = append(estimates, estimate)
 	}
+	
+	estimate[0].User = users[0].Id
+	estimate[1].User = users[0].Id
+	
+	for i := range estimates {
+		err = estimates[i].insertEstimate(db)
+		if err != nil {log.Println(err); return estimates}
+	}
 
 	return estimates
 }
@@ -2733,7 +2735,7 @@ func main() {
 	switch os.Args[1] {
     case "dev":
 		dev(os.Args[2:])
-    case "check":
+    case "checkpdf":
 		check(os.Args[2:])
     default:
         return
diff --git a/terms.tpl b/terms.tpl
new file mode 100644
index 0000000..e69de29