diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 0000000..64d3d6a
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,12 @@
+# EditorConfig is awesome: https://EditorConfig.org
+
+# top-most EditorConfig file
+root = true
+
+[*]
+indent_style = space
+indent_size = 2
+end_of_line = lf
+charset = utf-8
+trim_trailing_whitespace = true
+insert_final_newline = true
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..b4b6374
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,88 @@
+# Lume generated site
+dist/
+
+# DS Store
+.DS_Store
+._.DS_Store
+**/.DS_Store
+**/._.DS_Store
+
+# Logs
+logs
+*.log
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+
+# Runtime data
+pids
+*.pid
+*.seed
+*.pid.lock
+
+# Directory for instrumented libs generated by jscoverage/JSCover
+lib-cov
+
+# Coverage directory used by tools like istanbul
+coverage
+
+# nyc test coverage
+.nyc_output
+
+# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
+.grunt
+
+# Bower dependency directory (https://bower.io/)
+bower_components
+
+# node-waf configuration
+.lock-wscript
+
+# Compiled binary addons (https://nodejs.org/api/addons.html)
+build/Release
+
+# Dependency directories
+node_modules/
+jspm_packages/
+
+# TypeScript v1 declaration files
+typings/
+
+# Optional npm cache directory
+.npm
+
+# Optional eslint cache
+.eslintcache
+
+# Optional REPL history
+.node_repl_history
+
+# Output of 'npm pack'
+*.tgz
+
+# Yarn Integrity file
+.yarn-integrity
+
+# dotenv environment variables file
+.env
+
+# parcel-bundler cache (https://parceljs.org/)
+.cache
+
+# next.js build output
+.next
+
+# nuxt.js build output
+.nuxt
+
+# vuepress build output
+.vuepress/dist
+
+# Serverless directories
+.serverless
+
+# FuseBox cache
+.fusebox/
+
+# Snyk
+.dccache
diff --git a/.vscode/settings.json b/.vscode/settings.json
new file mode 100644
index 0000000..3c2d050
--- /dev/null
+++ b/.vscode/settings.json
@@ -0,0 +1,11 @@
+{
+  "deno.enable": true,
+  "deno.lint": true,
+  "deno.unstable": true,
+  "[typescript]": {
+    "editor.defaultFormatter": "denoland.vscode-deno"
+  },
+  "[typescriptreact]": {
+    "editor.defaultFormatter": "denoland.vscode-deno"
+  }
+}
diff --git a/_config.ts b/_config.ts
new file mode 100644
index 0000000..c9a347b
--- /dev/null
+++ b/_config.ts
@@ -0,0 +1,60 @@
+import lume from "lume/mod.ts"
+
+// Stable plugins
+import attributes from "lume/plugins/attributes.ts"
+import codeHighlight from "lume/plugins/code_highlight.ts"
+import esbuild from "lume/plugins/esbuild.ts"
+import jsx from "lume/plugins/jsx_preact.ts"
+import katex from "lume/plugins/katex.ts"
+import lightningcss from "lume/plugins/lightningcss.ts"
+import metas from "lume/plugins/metas.ts"
+import minifyHTML from "lume/plugins/minify_html.ts"
+import mdx from "lume/plugins/mdx.ts"
+import pug from "lume/plugins/pug.ts"
+import remark from "lume/plugins/remark.ts"
+import sass from "lume/plugins/sass.ts"
+import sitemap from "lume/plugins/sitemap.ts"
+import sourceMaps from "lume/plugins/source_maps.ts"
+import svgo from "lume/plugins/svgo.ts"
+
+// Experimental plugins
+
+// Custom plugins
+import toml from "./custom/toml/toml.ts"
+
+const site = lume({
+  src: "./src",
+  dest: "./dist",
+  location: new URL("https://samtherapy.net"),
+})
+
+site
+  .copy("static", ".")
+  .copy("static/.well-known", ".well-known")
+  .copy(".domains")
+  .loadData([".toml"], toml)
+  .use(attributes())
+  .use(codeHighlight())
+  .use(katex())
+  .use(metas())
+  .use(jsx())
+  .use(mdx())
+  .use(remark())
+  .use(pug())
+  .use(sitemap())
+  .use(svgo())
+  .remoteFile(
+    "_includes/styles/external/nord.min.css",
+    "https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11.6.0/build/styles/nord.min.css",
+  )
+  .use(esbuild({
+    extensions: [".ts", ".js"],
+  }))
+  .use(lightningcss())
+  .use(sass())
+  .use(minifyHTML())
+  .use(sourceMaps({
+    sourceContent: true,
+  }))
+
+export default site
diff --git a/_werc/config.json b/_werc/config.json
deleted file mode 100644
index 20fc637..0000000
--- a/_werc/config.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
-  "title": "dns.froth.zone",
-  "subtitle": "DNS can be frothworthy too!",
-  "lang": "en"
-}
diff --git a/_werc/pub/style.css b/_werc/pub/style.css
deleted file mode 100644
index e1e1ae7..0000000
--- a/_werc/pub/style.css
+++ /dev/null
@@ -1,13 +0,0 @@
-body { display: flex; flex-wrap: wrap; font-family: sans; background: black; color: white}
-header { flex-basis: 100%; flex-shrink: 0; }
-article { flex-basis: 60%; padding-left: 1em; }
-article {padding: 0.5ex 0 5vh 1vw;}
-footer { flex-basis: 100%; flex-shrink: 0; }
-header nav { display: flex; justify-content: space-between; }
-nav a, header a { text-decoration: none ; color: #c0c0c0; }
-a { color: #a0a0a0}
-header h1 span { margin-left: 1em; font-size: 50%; font-style: italic; }
-body > nav { flex-basis: content; padding-right: 1vw; min-width: 16em; }
-nav ul { display: flex; flex-direction: column; list-style-type: none; list-style-position: outside; padding-left: 0;  }
-nav li ul { padding-left: 0.6em }
-footer { display: flex; justify-content: space-between; }
diff --git a/awl/index.html b/awl/index.html
deleted file mode 100644
index 2ac0700..0000000
--- a/awl/index.html
+++ /dev/null
@@ -1,138 +0,0 @@
-<head>
-	<meta
-		name="go-import"
-		content="dns.froth.zone/awl git https://git.froth.zone/sam/awl"
-	/>
-	<meta
-		name="go-source"
-		content="dns.froth.zone/awl https://git.froth.zone/sam/awl https://git.froth.zone/sam/awl/src/branch/master{/dir} https://git.froth.zone/sam/awl/src/branch/master{/dir}/{file}#L{line}"
-	/>
-</head>
-<p>
-	<a href="./code">awl</a> is a simple DNS query client, much like dig and
-	drill.
-</p>
-<pre><code>❯ awl NS froth.zone @https://dns.froth.zone/dns-query 
-;; opcode: QUERY, status: NOERROR, id: 46274
-;; flags: qr rd ra; QUERY: 1, ANSWER: 4, AUTHORITY: 0, ADDITIONAL: 8
-
-;; QUESTION SECTION:
-;froth.zone.    IN       NS
-
-;; ANSWER SECTION:
-froth.zone.     1650    IN      NS      illya.froth.zone.
-froth.zone.     1650    IN      NS      rin.froth.zone.
-froth.zone.     1650    IN      NS      sakura.froth.zone.
-froth.zone.     1650    IN      NS      saber.froth.zone.
-
-;; ADDITIONAL SECTION:
-rin.froth.zone. 1650    IN      AAAA    2607:5300:201:3100::931b
-sakura.froth.zone.      1650    IN      AAAA    2001:41d0:304:200::d12b
-saber.froth.zone.       1650    IN      AAAA    2602:fe90:100:2::164d:4c70
-illya.froth.zone.       1650    IN      AAAA    2603:c020:4004:62ee::8888
-rin.froth.zone. 1650    IN      A       158.69.1.114
-sakura.froth.zone.      1650    IN      A       141.94.206.97
-saber.froth.zone.       1650    IN      A       45.13.232.162
-illya.froth.zone.       1650    IN      A       129.213.157.255
-
-;; Query time: 404.9936ms
-;; SERVER: https://dns.froth.zone/dns-query
-;; WHEN: Never
-;; MSG SIZE  rcvd: 489</code></pre>
-<hr />
-<p>
-	<code>awl</code> understands DNSSEC, like
-	<a href="https://linux.die.net/man/1/drill"><code>drill(1)</code></a
-	>:
-</p>
-<pre><code>❯ awl brokendnssec.net @1.1.1.1 --tcp
-;; opcode: QUERY, status: SERVFAIL, id: 45766
-;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 0
-
-;; QUESTION SECTION:
-;brokendnssec.net.      IN       A
-
-;; Query time: 6.0461ms
-;; SERVER: 1.1.1.1:53 (TCP)
-;; WHEN: Never
-;; MSG SIZE  rcvd: 34
-❯ awl brokendnssec.net @1.1.1.1 --cd +tcp
-;; opcode: QUERY, status: NOERROR, id: 37917
-;; flags: qr rd ra cd; QUERY: 1, ANSWER: 3, AUTHORITY: 0, ADDITIONAL: 0
-
-;; QUESTION SECTION:
-;brokendnssec.net.      IN       A
-
-;; ANSWER SECTION:
-brokendnssec.net.       294     IN      A       172.67.36.129
-brokendnssec.net.       294     IN      A       104.22.35.212
-brokendnssec.net.       294     IN      A       104.22.34.212
-
-;; Query time: 8.4461ms
-;; SERVER: 1.1.1.1:53 (TCP)
-;; WHEN: Never
-;; MSG SIZE  rcvd: 130</code></pre>
-<hr />
-<p>
-	It supports many of the flags that
-	<a href="https://man.openbsd.org/dig.1"><code>dig(1)</code></a> does:
-</p>
-<pre><code>❯ awl +noquestion +noauthority +nostats cat-v.org
-;; opcode: QUERY, status: NOERROR, id: 39675
-;; flags: qr rd ra; QUERY: 0, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0
-
-;; ANSWER SECTION:
-cat-v.org.      9418    IN      A       168.235.69.224</code></pre>
-<hr />
-<p>And <a href="./man">some new features</a>, too!</p>
-<div class="sourceCode" id="cb4">
-	<pre
-		class="sourceCode xml"
-	><code class="sourceCode xml"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a>❯ awl +quic --xml codeberg.org</span>
-<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a> &lt;<span class="kw">Message</span>&gt;</span>
-<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a>  &lt;<span class="kw">opcode</span>&gt;QUERY&lt;/<span class="kw">opcode</span>&gt;</span>
-<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a>  &lt;<span class="kw">status</span>&gt;NOERROR&lt;/<span class="kw">status</span>&gt;</span>
-<span id="cb4-5"><a href="#cb4-5" aria-hidden="true" tabindex="-1"></a>  &lt;<span class="kw">id</span>&gt;51837&lt;/<span class="kw">id</span>&gt;</span>
-<span id="cb4-6"><a href="#cb4-6" aria-hidden="true" tabindex="-1"></a>  &lt;<span class="kw">response</span>&gt;true&lt;/<span class="kw">response</span>&gt;</span>
-<span id="cb4-7"><a href="#cb4-7" aria-hidden="true" tabindex="-1"></a>  &lt;<span class="kw">authoritative</span>&gt;false&lt;/<span class="kw">authoritative</span>&gt;</span>
-<span id="cb4-8"><a href="#cb4-8" aria-hidden="true" tabindex="-1"></a>  &lt;<span class="kw">truncated</span>&gt;false&lt;/<span class="kw">truncated</span>&gt;</span>
-<span id="cb4-9"><a href="#cb4-9" aria-hidden="true" tabindex="-1"></a>  &lt;<span class="kw">recursionDesired</span>&gt;true&lt;/<span class="kw">recursionDesired</span>&gt;</span>
-<span id="cb4-10"><a href="#cb4-10" aria-hidden="true" tabindex="-1"></a>  &lt;<span class="kw">recursionAvailable</span>&gt;true&lt;/<span class="kw">recursionAvailable</span>&gt;</span>
-<span id="cb4-11"><a href="#cb4-11" aria-hidden="true" tabindex="-1"></a>  &lt;<span class="kw">zero</span>&gt;false&lt;/<span class="kw">zero</span>&gt;</span>
-<span id="cb4-12"><a href="#cb4-12" aria-hidden="true" tabindex="-1"></a>  &lt;<span class="kw">authenticatedData</span>&gt;false&lt;/<span class="kw">authenticatedData</span>&gt;</span>
-<span id="cb4-13"><a href="#cb4-13" aria-hidden="true" tabindex="-1"></a>  &lt;<span class="kw">checkingDisabled</span>&gt;false&lt;/<span class="kw">checkingDisabled</span>&gt;</span>
-<span id="cb4-14"><a href="#cb4-14" aria-hidden="true" tabindex="-1"></a>  &lt;<span class="kw">opt</span>&gt;</span>
-<span id="cb4-15"><a href="#cb4-15" aria-hidden="true" tabindex="-1"></a>    &lt;<span class="kw">name</span>&gt;Version&lt;/<span class="kw">name</span>&gt;</span>
-<span id="cb4-16"><a href="#cb4-16" aria-hidden="true" tabindex="-1"></a>  &lt;<span class="kw">value</span>&gt;0&lt;/<span class="kw">value</span>&gt;</span>
-<span id="cb4-17"><a href="#cb4-17" aria-hidden="true" tabindex="-1"></a>  &lt;/<span class="kw">opt</span>&gt;</span>
-<span id="cb4-18"><a href="#cb4-18" aria-hidden="true" tabindex="-1"></a>  &lt;<span class="kw">opt</span>&gt;</span>
-<span id="cb4-19"><a href="#cb4-19" aria-hidden="true" tabindex="-1"></a>    &lt;<span class="kw">name</span>&gt;Flags&lt;/<span class="kw">name</span>&gt;</span>
-<span id="cb4-20"><a href="#cb4-20" aria-hidden="true" tabindex="-1"></a>    &lt;<span class="kw">value</span>&gt;&lt;/<span class="kw">value</span>&gt;</span>
-<span id="cb4-21"><a href="#cb4-21" aria-hidden="true" tabindex="-1"></a>  &lt;/<span class="kw">opt</span>&gt;</span>
-<span id="cb4-22"><a href="#cb4-22" aria-hidden="true" tabindex="-1"></a>  &lt;<span class="kw">opt</span>&gt;</span>
-<span id="cb4-23"><a href="#cb4-23" aria-hidden="true" tabindex="-1"></a>    &lt;<span class="kw">name</span>&gt;UDP Buffer Size&lt;/<span class="kw">name</span>&gt;</span>
-<span id="cb4-24"><a href="#cb4-24" aria-hidden="true" tabindex="-1"></a>    &lt;<span class="kw">value</span>&gt;1232&lt;/<span class="kw">value</span>&gt;</span>
-<span id="cb4-25"><a href="#cb4-25" aria-hidden="true" tabindex="-1"></a>  &lt;/<span class="kw">opt</span>&gt;</span>
-<span id="cb4-26"><a href="#cb4-26" aria-hidden="true" tabindex="-1"></a>  &lt;<span class="kw">question</span>&gt;</span>
-<span id="cb4-27"><a href="#cb4-27" aria-hidden="true" tabindex="-1"></a>    &lt;<span class="kw">name</span>&gt;codeberg.org.&lt;/<span class="kw">name</span>&gt;</span>
-<span id="cb4-28"><a href="#cb4-28" aria-hidden="true" tabindex="-1"></a>    &lt;<span class="kw">class</span>&gt;IN&lt;/<span class="kw">class</span>&gt;</span>
-<span id="cb4-29"><a href="#cb4-29" aria-hidden="true" tabindex="-1"></a>    &lt;<span class="kw">type</span>&gt;A&lt;/<span class="kw">type</span>&gt;</span>
-<span id="cb4-30"><a href="#cb4-30" aria-hidden="true" tabindex="-1"></a>  &lt;/<span class="kw">question</span>&gt;</span>
-<span id="cb4-31"><a href="#cb4-31" aria-hidden="true" tabindex="-1"></a>  &lt;<span class="kw">answer</span>&gt;</span>
-<span id="cb4-32"><a href="#cb4-32" aria-hidden="true" tabindex="-1"></a>    &lt;<span class="kw">response</span>&gt;193.26.156.135&lt;/<span class="kw">response</span>&gt;</span>
-<span id="cb4-33"><a href="#cb4-33" aria-hidden="true" tabindex="-1"></a>    &lt;<span class="kw">name</span>&gt;codeberg.org.&lt;/<span class="kw">name</span>&gt;</span>
-<span id="cb4-34"><a href="#cb4-34" aria-hidden="true" tabindex="-1"></a>    &lt;<span class="kw">ttl</span>&gt;449&lt;/<span class="kw">ttl</span>&gt;</span>
-<span id="cb4-35"><a href="#cb4-35" aria-hidden="true" tabindex="-1"></a>    &lt;<span class="kw">class</span>&gt;IN&lt;/<span class="kw">class</span>&gt;</span>
-<span id="cb4-36"><a href="#cb4-36" aria-hidden="true" tabindex="-1"></a>    &lt;<span class="kw">type</span>&gt;A&lt;/<span class="kw">type</span>&gt;</span>
-<span id="cb4-37"><a href="#cb4-37" aria-hidden="true" tabindex="-1"></a>  &lt;/<span class="kw">answer</span>&gt;</span>
-<span id="cb4-38"><a href="#cb4-38" aria-hidden="true" tabindex="-1"></a>  &lt;<span class="kw">queryTime</span>&gt;128.726593ms&lt;/<span class="kw">queryTime</span>&gt;</span>
-<span id="cb4-39"><a href="#cb4-39" aria-hidden="true" tabindex="-1"></a>  &lt;<span class="kw">server</span>&gt;dns.adguard.com:853 (QUIC)&lt;/<span class="kw">server</span>&gt;</span>
-<span id="cb4-40"><a href="#cb4-40" aria-hidden="true" tabindex="-1"></a>  &lt;<span class="kw">when</span>&gt;Thu, 13 Oct 2022 15:29:58 +0200&lt;/<span class="kw">when</span>&gt;</span>
-<span id="cb4-41"><a href="#cb4-41" aria-hidden="true" tabindex="-1"></a>  &lt;<span class="kw">msgSize</span>&gt;69&lt;/<span class="kw">msgSize</span>&gt;</span>
-<span id="cb4-42"><a href="#cb4-42" aria-hidden="true" tabindex="-1"></a>&lt;/<span class="kw">Message</span>&gt;</span></code></pre>
-</div>
-<hr />
-<p>
-	A full list of the features <code>awl</code> supports can be found
-	<a href="https://git.froth.zone/sam/awl/wiki/Supported">here</a>.
-</p>
diff --git a/awl/man.txt b/awl/man.txt
deleted file mode 100644
index 1609d90..0000000
--- a/awl/man.txt
+++ /dev/null
@@ -1,309 +0,0 @@
-NAME
-
-awl - DNS lookup tool
-
-SYNOPSIS
-
-awl [ OPTIONS ] name [ @server ] [ type ], where
-
-name is the query to make (example: froth.zone)
-@server is the server to query (example: dns.froth.zone)
-type is the DNS resource type (example: AAAA)
-
-DESCRIPTION
-
-awl (awls want licorice) is a simple tool designed to make DNS queries,
-much like the venerable dig(1). An awl is a tool used to make small
-holes, typically used in leatherworking.
-
-awl is designed to be a more "modern" version of drill(1) by including
-some more recent RFCs and output options.
-
-When no arguments are given, awl will perform an NS query on the root
-('.').
-
-When a nameserver is not given, awl will query a random system
-nameserver. If one cannot be found, awl will query localhost.
-
-OPTIONS
-
-Anything in [brackets] is optional.
-
--D, --dnssec, +dnssec
-
-  Enable DNSSEC. This needs to be manually enabled.
-
--v[=int]
-
-  Set verbosity Accepted values are as follows:
-
-  -   0: Only log errors.
-
-  -   1: Log warnings. This is the default.
-
-  -   2: Log information Default when specifying just -v.
-
-  -   3: Log information useful for debugging.
-
-  Setting a value lower than 0 disables logging entirely.
-
-  By default, specifying just -v sets the verbosity to 2 (info).
-
--V
-
-  Print the version and exit.
-
--h
-
-  Show a "short" help message.
-
-Query Options
-
--4
-
-  Only make query over IPv4
-
--6
-
-  Only make query over IPv6
-
--p, --port port
-
-  Sets the port to query. Default ports listed below.
-
-  -   53 for UDP and TCP
-
-  -   853 for TLS and QUIC
-
-  -   443 for HTTPS
-
--q, --query domain
-
-  Domain to query (eg. example.com)
-
--c, --class class
-
-  DNS class to query (eg. IN, CH) The default is IN.
-
--t, --qType type
-
-  DNS type to query (eg. A, AAAA, NS) The default is A.
-
---no-truncate, +ignore
-
-  Ignore UDP truncation (by default, awl retries with TCP).
-
---no-bad-cookie, +[no]badcookie
-
-  [Do not] ignore BADCOOKIE responses
-
---tcp, +tcp, +vc
-
-  Use TCP for the query (see RFC 7766).
-
---dnscrypt, +dnscrypt
-
-  Use DNSCrypt.
-
--T, --tls, +tls
-
-  Use DNS-over-TLS, implies --tcp (see RFC 7858)
-
---tls-host string
-
-  Set hostname to use for TLS certificate validation. Default is the
-  name of the domain when querying over TLS, and empty for IPs.
-
---tls-no-verify
-
-  Ignore TLS validation when performing a DNS query.
-
--H. --https, +https
-
-  Use DNS-over-HTTPS (see RFC 8484).
-
--Q. --quic, +quic
-
-  Use DNS-over-QUIC (see RFC 9250).
-
--x, --reverse
-
-  Do a reverse lookup. Sets default type to PTR. awl automatically makes
-  an IP or phone number canonical.
-
---timeout seconds, +timeout=seconds
-
-  Set the timeout period. Floating point numbers are accepted. 0.5
-  seconds is the minimum.
-
---retries int, +tries=int, +retry=int
-
-  Set the number of retries. Retry is one more than tries, dig style.
-
-DNS Flags
-
---aa[=bool], +[no]aaflag
-
-  (Set, Unset) AA (Authoritative Answer) flag.
-
---ad[=bool], +[no]adflag
-
-  (Set, Unset) AD (Authenticated Data) flag.
-
---tc[=bool], +[no]tcflag
-
-  (Set, Unset) TC (TrunCated) flag
-
--z[=bool], +[no]zflag
-
-  (Set, Unset) Z (Zero) flag.
-
---cd[=bool], +[no]cdflag
-
-  (Set, Unset) CD (Checking Disabled) flag.
-
---qr[=bool], +[no]qrflag
-
-  (Set, Unset) QR (QueRy) flag.
-
---rd[=bool], +[no]rdflag
-
-  (Set, Unset) RD (Recursion Desired) flag.
-
---ra[=bool], +[no]raflag
-
-  (Set, Unset) RA (Recursion Available) flag.
-
-EDNS
-
-All of these options except disabling EDNS imply +edns.
-
---no-edns, +noedns
-
-  Disable EDNS.
-
---edns-ver, +edns[=int]
-
-  Enable EDNS and set EDNS version. The maximum value is 255, and the
-  minimum (default) value is 0.
-
---expire. +[no]expire
-
-  Send an EDNS Expire.
-
---nsid, +[no]nsid
-
-  Send an EDNS name server ID request.
-
---no-cookie, +[no]cookie[=string]
-
-  Send an EDNS cookie. This is enabled by default with a random string.
-
---keep-alive, +[no]keepalive, +[no]keepopen
-
-  Send an EDNS keep-alive. This does nothing unless using TCP.
-
---buffer-size int, +bufize=int
-
-  Set the UDP message buffer size, using EDNS. Max is 65535, minimum is
-  zero. The default value is 1232.
-
---zflag int, +ednsflags=int
-
-  Set the must-be-zero EDNS flags. Decimal, hexadecimal and octal are
-  supported. Trying to set DO will be ignored.
-
---subnet ip[/prefix], +[no]subnet=ip[/prefix]
-
-  Send an EDNS Client Subnet option with the specified address.
-
-  Like dig(1), setting the IP to 0.0.0.0/0, ::/0 or 0 will signal the
-  resolver to not use any client information when returning the query.
-
-Output Display
-
---no-question, +[no]question
-
-  Toggle the display of the Question section.
-
---no-answer, +[no]answer
-
-  Toggle the display of the Answer section.
-
---no-answer, +[no]answer
-
-  Toggle the display of the Answer section.
-
---no-authority, +[no]authority
-
-  Toggle the display of the Authority section.
-
---no-additional, +[no]additional
-
-  Toggle the display of the Additional section.
-
---no-statistics, +[no]stats
-
-  Toggle the display of the Statistics (additional comments) section.
-
-Output Formats
-
--j, --json, +json
-
-  Print the query results as JSON.
-
--X, --xml, +xml
-
-  Print the query results as XML.
-
--y, --yaml, +yaml
-
-  Print the query results as YAML.
-
--s, --short, +short
-
-  Print just the address of the answer.
-
-EXIT STATUS
-
-The exit code is 0 when a query is successfully made and received. This
-includes SERVFAILs, NOTIMPL among others.
-
-EXAMPLES
-
-    awl grumbulon.xyz -j +cd
-
-Run a query of your local resolver for the A records of grumbulon.xyz,
-print them as JSON and disable DNSSEC verification.
-
-    awl +short example.com AAAA @1.1.1.1
-
-Query 1.1.1.1 for the AAAA records of example.com, print just the
-answers
-
-    awl -xT PTR 8.8.4.4 @dns.google
-
-Query dns.google over TLS for the PTR record to the IP address 8.8.4.4
-
-SEE ALSO
-
-drill(1), dig(1)
-
-STANDARDS
-
-RFC 1034,1035 (UDP), 7766 (TCP), 7858 (TLS), 8484 (HTTPS), 9230 (QUIC)
-
-Probably more, https://www.statdns.com/rfc
-
-BUGS
-
-OPT records are only printed when using a standard output, not
-JSON/XML/YAML.
-
-Full parity with dig(1) is not complete.
-
-This man page is probably not complete.
-
-Likely numerous more, report them either to the tracker
-https://git.froth.zone/sam/awl/issues or via email
-~sammefishe/awl-dev@lists.sr.ht
diff --git a/awl/repo.html b/awl/repo.html
deleted file mode 100644
index 9bc7fae..0000000
--- a/awl/repo.html
+++ /dev/null
@@ -1,4 +0,0 @@
-<a href="https://git.froth.zone/sam/awl">https://git.froth.zone/sam/awl</a>
-<script>
-    window.location.replace("https://git.froth.zone/sam/awl");
-</script>
\ No newline at end of file
diff --git a/custom/toml/toml.ts b/custom/toml/toml.ts
new file mode 100644
index 0000000..7789bc0
--- /dev/null
+++ b/custom/toml/toml.ts
@@ -0,0 +1,6 @@
+import { parse } from "std/encoding/toml.ts"
+
+export default async function toml(path: string | URL) {
+  const content = await Deno.readTextFile(path)
+  return parse(content)
+}
diff --git a/deno.json b/deno.json
new file mode 100644
index 0000000..3fb6bd5
--- /dev/null
+++ b/deno.json
@@ -0,0 +1,42 @@
+{
+  "tasks": {
+    "lume": "echo \"import 'lume/cli.ts'\" | deno run --unstable -A -",
+    "build": "deno task lume",
+    "serve": "deno task lume -s"
+  },
+  "lock": false,
+  "compilerOptions": {
+    "jsx": "react-jsx",
+    "jsxImportSource": "npm:preact",
+    "lib": [
+      "dom",
+      "dom.iterable",
+      "dom.asynciterable",
+      "deno.ns"
+    ]
+  },
+  "imports": {
+    "lume/": "https://deno.land/x/lume@v1.15.2/",
+    "experimental/": "https://raw.githubusercontent.com/lumeland/experimental-plugins/main/",
+    "std/": "https://deno.land/std/"
+  },
+  "lint": {
+    "files": {
+      "exclude": [
+        "src/_includes/styles/external/",
+        "dist/"
+      ]
+    }
+  },
+  "fmt": {
+    "options": {
+      "semiColons": false
+    },
+    "files": {
+      "exclude": [
+        "src/_includes/styles/external/",
+        "dist"
+      ]
+    }
+  }
+}
diff --git a/resolver.md b/resolver.md
deleted file mode 100644
index d71f71f..0000000
--- a/resolver.md
+++ /dev/null
@@ -1,28 +0,0 @@
-# Froth.zone DNS resolving service
-
-I also host an [OpenNIC](https://www.opennic.org/)-compatible DNS resolving server.
-
-### Never asked questions (NAQs)
-
-- *Why OpenNIC?*
-    : Why not? The root servers seamlessly connect to ICANN space, so it's just free extra domains.
-
-- *Where is it?*
-    : Right here. This domain you're looking at right now.
-
-- *What about DNS-over-TCP?*
-    : Yes.
-
-- *DNS-over-TLS?*
-    : Yes, DNS-over-TLS too.
-
-- *DNSCrypt?*
-    : Nope. ¯\\\_(ツ)\_/¯ \
-Maybe when it becomes an RFC.
-
-- *What about DNS-over-HTTPS?*
-    : Yes! Use __ht<span>tp</span>s://dns.froth.zone/dns-query__ as the endpoint URL.
-
-- *What about QUIC?*
-    : Since the software I use doesn't support QUIC yet
-    (I don't think _any_ do yet), no. Maybe soon(tm)
\ No newline at end of file
diff --git a/server.ts b/server.ts
new file mode 100644
index 0000000..70cb8d2
--- /dev/null
+++ b/server.ts
@@ -0,0 +1,21 @@
+import Server from "lume/core/server.ts"
+import expires from "lume/middlewares/expires.ts"
+import not_found from "lume/middlewares/not_found.ts"
+
+const port = 8000
+
+const server = new Server({
+  port: port,
+  root: `${Deno.cwd()}/dist`,
+})
+
+server.use(expires())
+
+server.use(not_found({
+  root: `${Deno.cwd()}/dist`,
+  page404: "404.html",
+}))
+
+server.start()
+
+console.log(`Listening on http://localhost:${port}`)
diff --git a/src/_data.toml b/src/_data.toml
new file mode 100644
index 0000000..12db5ea
--- /dev/null
+++ b/src/_data.toml
@@ -0,0 +1,35 @@
+# Site metas from Lume metas plugin
+[metas]
+site = "Froth DNS"
+lang = "en"
+description = "All you need to know about the services provided by dns.froth.zone"
+# icon = "img/favicon.png"
+keywords = ["DNS", "nameserver", "DNS server", "froth.zone", "froth DNS", "froth zone"]
+generator = true
+
+[[menu.left]]
+name = "/"
+url = "/"
+
+[[menu.left]]
+name = "Nameservers"
+url = "/nameservers"
+
+[[menu.left]]
+name = "Resolver"
+url = "/resolver"
+
+[[menu.left]]
+name = "awl"
+url = "/awl"
+
+[[menu.left]]
+name = "pomme"
+url = "/pomme"
+
+[[menu.right]]
+name = "Status"
+url = "https://status.froth.zone/status/dns"
+
+[mergedKeys]
+metas = "object"
diff --git a/src/_includes/layouts/base.pug b/src/_includes/layouts/base.pug
new file mode 100644
index 0000000..36d45e1
--- /dev/null
+++ b/src/_includes/layouts/base.pug
@@ -0,0 +1,14 @@
+doctype html
+html(lang=metas.lang)
+  head
+    title= title
+    include meta.pug
+    include nav.pug
+  body
+    header
+      h1= title
+      h2= subtitle
+    main
+      | !{content}
+    footer
+      include footer.html
diff --git a/src/_includes/layouts/footer.html b/src/_includes/layouts/footer.html
new file mode 100644
index 0000000..5bed6ac
--- /dev/null
+++ b/src/_includes/layouts/footer.html
@@ -0,0 +1,8 @@
+<!-- This is a template because I need to make raw HTML -->
+<small>
+  Built with <a href="https://lume.land">Lume</a>
+  •
+  <a href="https://git.froth.zone/sam/dns.froth.zone">Source</a>
+  •
+  <a href="https://samtherapy.net">Owner</a>
+</small>
diff --git a/src/_includes/layouts/meta.pug b/src/_includes/layouts/meta.pug
new file mode 100644
index 0000000..b08f1b2
--- /dev/null
+++ b/src/_includes/layouts/meta.pug
@@ -0,0 +1,10 @@
+if goimport
+  meta(name="go-import", content=`${goimport.url} ${goimport.vcs} ${goimport.repo}`)
+  if goimport.gitea
+    meta(name="go-source", content=`${goimport.url} ${goimport.repo} ${goimport.repo}/tree/${goimport.branch}\{/dir\} ${goimport.repo}/src/branch/${goimport.branch}\{/dir\}/\{file\}\#L\{line\}`)
+  else
+    meta(name="go-source", content=`${goimport.url} ${goimport.repo} ${goimport.repo}/tree/${goimport.branch}\{/dir\} ${goimport.repo}/blob/${goimport.branch}\{/dir\}/\{file\}\#L\{line\}`)
+meta(charset="utf-8")
+meta(name='viewport', content='width=device-width, initial-scale=1')
+link(rel="shortcut icon", href="/img/favicon.png", type="image/png")
+link(rel="stylesheet", href="/css/style.css")
diff --git a/src/_includes/layouts/nav.pug b/src/_includes/layouts/nav.pug
new file mode 100644
index 0000000..7277013
--- /dev/null
+++ b/src/_includes/layouts/nav.pug
@@ -0,0 +1,9 @@
+nav
+  ul(class= "main-nav")
+    each val in menu.left
+      li
+        a(href=val.url)= val.name
+
+    each val in menu.right
+      li(class= "push")
+        a(href=val.url)= val.name
diff --git a/src/_includes/styles/base.scss b/src/_includes/styles/base.scss
new file mode 100644
index 0000000..280bcd2
--- /dev/null
+++ b/src/_includes/styles/base.scss
@@ -0,0 +1,32 @@
+@use "styles/sakura.theme";
+
+// Highlight.js theme
+@use "styles/external/nord.min";
+
+
+:root {
+  font-family: -apple-system, BlinkMacSystemFont, "Avenir Next", Avenir, "Nimbus Sans L", Roboto, Noto, "Segoe UI", Arial, Helvetica, "Helvetica Neue", sans-serif;
+}
+
+.row {
+  display: flex;
+}
+
+.column {
+  flex: 50%;
+}
+
+.main-nav {
+  display: flex;
+  list-style: none;
+  max-width: 75%;
+}
+
+nav li {
+  margin: 0.5em;
+}
+
+.push {
+  justify-content: flex-end;
+  margin-left: auto;
+}
diff --git a/src/_includes/styles/external/nord.min.css b/src/_includes/styles/external/nord.min.css
new file mode 100644
index 0000000..efbb0c1
--- /dev/null
+++ b/src/_includes/styles/external/nord.min.css
@@ -0,0 +1 @@
+pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}.hljs{background:#2e3440}.hljs,.hljs-subst{color:#d8dee9}.hljs-selector-tag{color:#81a1c1}.hljs-selector-id{color:#8fbcbb;font-weight:700}.hljs-selector-attr,.hljs-selector-class{color:#8fbcbb}.hljs-property,.hljs-selector-pseudo{color:#88c0d0}.hljs-addition{background-color:rgba(163,190,140,.5)}.hljs-deletion{background-color:rgba(191,97,106,.5)}.hljs-built_in,.hljs-class,.hljs-type{color:#8fbcbb}.hljs-function,.hljs-function>.hljs-title,.hljs-title.hljs-function{color:#88c0d0}.hljs-keyword,.hljs-literal,.hljs-symbol{color:#81a1c1}.hljs-number{color:#b48ead}.hljs-regexp{color:#ebcb8b}.hljs-string{color:#a3be8c}.hljs-title{color:#8fbcbb}.hljs-params{color:#d8dee9}.hljs-bullet{color:#81a1c1}.hljs-code{color:#8fbcbb}.hljs-emphasis{font-style:italic}.hljs-formula{color:#8fbcbb}.hljs-strong{font-weight:700}.hljs-link:hover{text-decoration:underline}.hljs-comment,.hljs-quote{color:#4c566a}.hljs-doctag{color:#8fbcbb}.hljs-meta,.hljs-meta .hljs-keyword{color:#5e81ac}.hljs-meta .hljs-string{color:#a3be8c}.hljs-attr{color:#8fbcbb}.hljs-attribute{color:#d8dee9}.hljs-name{color:#81a1c1}.hljs-section{color:#88c0d0}.hljs-tag{color:#81a1c1}.hljs-template-variable,.hljs-variable{color:#d8dee9}.hljs-template-tag{color:#5e81ac}.language-abnf .hljs-attribute{color:#88c0d0}.language-abnf .hljs-symbol{color:#ebcb8b}.language-apache .hljs-attribute{color:#88c0d0}.language-apache .hljs-section{color:#81a1c1}.language-arduino .hljs-built_in{color:#88c0d0}.language-aspectj .hljs-meta{color:#d08770}.language-aspectj>.hljs-title{color:#88c0d0}.language-bnf .hljs-attribute{color:#8fbcbb}.language-clojure .hljs-name{color:#88c0d0}.language-clojure .hljs-symbol{color:#ebcb8b}.language-coq .hljs-built_in{color:#88c0d0}.language-cpp .hljs-meta .hljs-string{color:#8fbcbb}.language-css .hljs-built_in{color:#88c0d0}.language-css .hljs-keyword{color:#d08770}.language-diff .hljs-meta,.language-ebnf .hljs-attribute{color:#8fbcbb}.language-glsl .hljs-built_in{color:#88c0d0}.language-groovy .hljs-meta:not(:first-child),.language-haxe .hljs-meta,.language-java .hljs-meta{color:#d08770}.language-ldif .hljs-attribute{color:#8fbcbb}.language-lisp .hljs-name,.language-lua .hljs-built_in,.language-moonscript .hljs-built_in,.language-nginx .hljs-attribute{color:#88c0d0}.language-nginx .hljs-section{color:#5e81ac}.language-pf .hljs-built_in,.language-processing .hljs-built_in{color:#88c0d0}.language-scss .hljs-keyword,.language-stylus .hljs-keyword{color:#81a1c1}.language-swift .hljs-meta{color:#d08770}.language-vim .hljs-built_in{color:#88c0d0;font-style:italic}.language-yaml .hljs-meta{color:#d08770}
\ No newline at end of file
diff --git a/src/_includes/styles/external/sakura.scss b/src/_includes/styles/external/sakura.scss
new file mode 100644
index 0000000..5aa9bc5
--- /dev/null
+++ b/src/_includes/styles/external/sakura.scss
@@ -0,0 +1,264 @@
+/* Sakura.css v1.4.1
+ * ================
+ * Minimal css theme.
+ * Project: https://github.com/oxalorg/sakura/
+ */
+
+/* Body */
+
+html {
+  font-size: 62.5%; // So that root size becomes 10px
+  font-family: $font-family-base;
+}
+
+body {
+  // $font-size-base must be a rem value
+  font-size: $font-size-base;
+  line-height: 1.618;
+  max-width: 60em;
+  margin: auto;
+  color: $color-text;
+  background-color: $color-bg;
+  padding: 13px;
+}
+
+@media (max-width: 684px) {
+  body {
+    font-size: $font-size-base * 0.85;
+  }
+}
+
+@media (max-width: 382px) {
+  body {
+    font-size: $font-size-base * 0.75;
+  }
+}
+
+@mixin word-wrap() {
+  overflow-wrap: break-word;
+  word-wrap: break-word;
+  -ms-word-break: break-all;
+  word-break: break-word;
+}
+
+h1,
+h2,
+h3,
+h4,
+h5,
+h6 {
+  line-height: 1.1;
+  font-family: $font-family-heading;
+  font-weight: 700;
+  margin-top: 3rem;
+  margin-bottom: 1.5rem;
+  @include word-wrap;
+}
+
+h1 {
+  font-size: 2.35em
+}
+
+h2 {
+  font-size: 2.00em
+}
+
+h3 {
+  font-size: 1.75em
+}
+
+h4 {
+  font-size: 1.5em
+}
+
+h5 {
+  font-size: 1.25em
+}
+
+h6 {
+  font-size: 1em
+}
+
+p {
+  margin-top: 0px;
+  margin-bottom: 2.5rem;
+}
+
+small,
+sub,
+sup {
+  font-size: 75%;
+}
+
+hr {
+  border-color: $color-blossom;
+}
+
+a {
+  text-decoration: none;
+  color: $color-blossom;
+
+  &:visited {
+    color: darken($color-blossom, 10%);
+  }
+
+  &:hover {
+    color: $color-fade;
+    border-bottom: 2px solid $color-text;
+  }
+
+}
+
+ul {
+  padding-left: 1.4em;
+  margin-top: 0px;
+  margin-bottom: 2.5rem;
+}
+
+li {
+  margin-bottom: 0.4em;
+}
+
+blockquote {
+  margin-left: 0px;
+  margin-right: 0px;
+  padding-left: 1em;
+  padding-top: 0.8em;
+  padding-bottom: 0.8em;
+  padding-right: 0.8em;
+  border-left: 5px solid $color-blossom;
+  margin-bottom: 2.5rem;
+  background-color: $color-bg-alt;
+}
+
+blockquote p {
+  margin-bottom: 0;
+}
+
+img,
+video {
+  height: auto;
+  max-width: 100%;
+  margin-top: 0px;
+  margin-bottom: 2.5rem;
+}
+
+/* Pre and Code */
+
+pre {
+  background-color: $color-bg-alt;
+  display: block;
+  padding: 1em;
+  overflow-x: auto;
+  margin-top: 0px;
+  margin-bottom: 2.5rem;
+  font-size: 0.9em;
+}
+
+code,
+kbd,
+samp {
+  font-size: 0.9em;
+  padding: 0 0.5em;
+  background-color: $color-bg-alt;
+  white-space: pre-wrap;
+}
+
+pre>code {
+  padding: 0;
+  background-color: transparent;
+  white-space: pre;
+  font-size: 1em;
+}
+
+/* Tables */
+
+table {
+  text-align: justify;
+  width: 100%;
+  border-collapse: collapse;
+}
+
+td,
+th {
+  padding: 0.5em;
+  border-bottom: 1px solid $color-bg-alt;
+}
+
+/* Buttons, forms and input */
+
+input,
+textarea {
+  border: 1px solid $color-text;
+
+  &:focus {
+    border: 1px solid $color-blossom;
+  }
+}
+
+textarea {
+  width: 100%;
+}
+
+.button,
+button,
+input[type="submit"],
+input[type="reset"],
+input[type="button"] {
+  display: inline-block;
+  padding: 5px 10px;
+  text-align: center;
+  text-decoration: none;
+  white-space: nowrap;
+
+  background-color: $color-blossom;
+  color: $color-bg;
+  border-radius: 1px;
+  border: 1px solid $color-blossom;
+  cursor: pointer;
+  box-sizing: border-box;
+
+  &[disabled] {
+    cursor: default;
+    opacity: .5;
+  }
+
+  &:focus:enabled,
+  &:hover:enabled {
+    background-color: $color-fade;
+    border-color: $color-fade;
+    color: $color-bg;
+    outline: 0;
+  }
+}
+
+textarea,
+select,
+input {
+  color: $color-text;
+  padding: 6px 10px;
+  /* The 6px vertically centers text on FF, ignored by Webkit */
+  margin-bottom: 10px;
+  background-color: $color-bg-alt;
+  border: 1px solid $color-bg-alt;
+  border-radius: 4px;
+  box-shadow: none;
+  box-sizing: border-box;
+
+  &:focus {
+    border: 1px solid $color-blossom;
+    outline: 0;
+  }
+}
+
+input[type="checkbox"]:focus {
+  outline: 1px dotted $color-blossom;
+}
+
+label,
+legend,
+fieldset {
+  display: block;
+  margin-bottom: .5rem;
+  font-weight: 600;
+}
diff --git a/src/_includes/styles/sakura.theme.scss b/src/_includes/styles/sakura.theme.scss
new file mode 100644
index 0000000..faf575a
--- /dev/null
+++ b/src/_includes/styles/sakura.theme.scss
@@ -0,0 +1,15 @@
+// Settings for SakuraCSS
+$color-blossom: #ffffff;
+$color-fade: #c9c9c9;
+
+$color-bg: #222222;
+$color-bg-alt: #4a4a4a;
+
+/* $color-text: #dedce5; */
+$color-text: #c9c9c9;
+$font-size-base: 1.8rem;
+
+$font-family-base: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif;
+$font-family-heading: $font-family-base;
+
+@import "styles/external/sakura";
diff --git a/src/_includes/types.ts b/src/_includes/types.ts
new file mode 100644
index 0000000..e69de29
diff --git a/src/awl/index.mdx b/src/awl/index.mdx
new file mode 100644
index 0000000..426f69b
--- /dev/null
+++ b/src/awl/index.mdx
@@ -0,0 +1,133 @@
+---
+title: Froth DNS Service
+subtitle: Welcome to the Froth DNS service!
+goimport:
+  url: dns.froth.zone/awl
+  vcs: git
+  repo: https://git.froth.zone/sam/awl
+  branch: master
+  gitea: true
+layout: layouts/base.pug
+---
+
+[awl](https://git.froth.zone/sam/awl) is a simple DNS query client, much like dig and drill.
+
+
+```
+❯ awl NS froth.zone @https://dns.froth.zone/dns-query
+;; opcode: QUERY, status: NOERROR, id: 46274
+;; flags: qr rd ra; QUERY: 1, ANSWER: 4, AUTHORITY: 0, ADDITIONAL: 8
+
+;; QUESTION SECTION:
+;froth.zone.    IN       NS
+
+;; ANSWER SECTION:
+froth.zone.     1650    IN      NS      illya.froth.zone.
+froth.zone.     1650    IN      NS      rin.froth.zone.
+froth.zone.     1650    IN      NS      sakura.froth.zone.
+froth.zone.     1650    IN      NS      saber.froth.zone.
+
+;; ADDITIONAL SECTION:
+rin.froth.zone. 1650    IN      AAAA    2607:5300:201:3100::931b
+sakura.froth.zone.      1650    IN      AAAA    2001:41d0:304:200::d12b
+saber.froth.zone.       1650    IN      AAAA    2602:fe90:100:2::164d:4c70
+illya.froth.zone.       1650    IN      AAAA    2603:c020:4004:62ee::8888
+rin.froth.zone. 1650    IN      A       158.69.1.114
+sakura.froth.zone.      1650    IN      A       141.94.206.97
+saber.froth.zone.       1650    IN      A       45.13.232.162
+illya.froth.zone.       1650    IN      A       129.213.157.255
+
+;; Query time: 404.9936ms
+;; SERVER: https://dns.froth.zone/dns-query
+;; WHEN: Never
+;; MSG SIZE  rcvd: 489
+```
+
+---
+
+`awl` understands DNSSEC, like [`drill(1)`](https://linux.die.net/man/1/drill):
+
+```
+❯ awl brokendnssec.net @1.1.1.1 --tcp
+;; opcode: QUERY, status: SERVFAIL, id: 45766
+;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 0
+
+;; QUESTION SECTION:
+;brokendnssec.net.      IN       A
+
+;; Query time: 6.0461ms
+;; SERVER: 1.1.1.1:53 (TCP)
+;; WHEN: Never
+;; MSG SIZE  rcvd: 34
+❯ awl brokendnssec.net @1.1.1.1 --cd +tcp
+;; opcode: QUERY, status: NOERROR, id: 37917
+;; flags: qr rd ra cd; QUERY: 1, ANSWER: 3, AUTHORITY: 0, ADDITIONAL: 0
+
+;; QUESTION SECTION:
+;brokendnssec.net.      IN       A
+
+;; ANSWER SECTION:
+brokendnssec.net.       294     IN      A       172.67.36.129
+brokendnssec.net.       294     IN      A       104.22.35.212
+brokendnssec.net.       294     IN      A       104.22.34.212
+
+;; Query time: 8.4461ms
+;; SERVER: 1.1.1.1:53 (TCP)
+;; WHEN: Never
+;; MSG SIZE  rcvd: 130
+```
+
+---
+
+It supports many of the flags that [`dig(1)`](https://man.openbsd.org/dig.1)
+does:
+
+```
+❯ awl +noquestion +noauthority +nostats cat-v.org
+;; opcode: QUERY, status: NOERROR, id: 39675
+;; flags: qr rd ra; QUERY: 0, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0
+
+;; ANSWER SECTION:
+cat-v.org.      9418    IN      A       168.235.69.224
+```
+
+---
+
+And [some new features](./man), too!
+
+```xml
+❯ awl +quic --xml codeberg.org
+<Msg>
+  <Id>22108</Id>
+  <Response>true</Response>
+  <Opcode>0</Opcode>
+  <Authoritative>false</Authoritative>
+  <Truncated>false</Truncated>
+  <RecursionDesired>true</RecursionDesired>
+  <RecursionAvailable>true</RecursionAvailable>
+  <Zero>false</Zero>
+  <AuthenticatedData>false</AuthenticatedData>
+  <CheckingDisabled>false</CheckingDisabled>
+  <Rcode>0</Rcode>
+  <Compress>false</Compress>
+  <Question>
+    <Name>codeberg.org.</Name>
+    <Qtype>1</Qtype>
+    <Qclass>1</Qclass>
+  </Question>
+  <Answer>
+    <Hdr>
+      <Name>codeberg.org.</Name>
+      <Rrtype>1</Rrtype>
+      <Class>1</Class>
+      <Ttl>3600</Ttl>
+      <Rdlength>4</Rdlength>
+    </Hdr>
+    <A>193.26.156.135</A>
+  </Answer>
+</Msg>
+```
+
+------
+
+A full list of the features `awl` supports can be found [here](https://git.froth.zone/sam/awl/wiki/Supported).
diff --git a/src/css/style.scss b/src/css/style.scss
new file mode 100644
index 0000000..619e85f
--- /dev/null
+++ b/src/css/style.scss
@@ -0,0 +1 @@
+@use "styles/base";
diff --git a/index.md b/src/index.mdx
similarity index 54%
rename from index.md
rename to src/index.mdx
index cbdb162..45c8bad 100644
--- a/index.md
+++ b/src/index.mdx
@@ -1,5 +1,11 @@
-# Welcome to the Froth DNS service!
 ---
+title: Froth DNS Service
+subtitle: Welcome to the Froth DNS service!
+layout: layouts/base.pug
+---
+
+#### Hello there.
+
 This is a landing page for the DNS services that I host.
 
 \
diff --git a/nameservers.md b/src/nameservers.mdx
similarity index 89%
rename from nameservers.md
rename to src/nameservers.mdx
index 389d257..b31573d 100644
--- a/nameservers.md
+++ b/src/nameservers.mdx
@@ -1,10 +1,14 @@
-# Froth.zone Nameservers
+---
+title: Froth.zone Nameservers
+subtitle:
+layout: layouts/base.pug
+---
 
 I host four nameservers in servers all over ~~NATO~~ the world,
 so anybody ~~in the US or Western Europe~~ can more easily access my
 services:
 
-The IP addresses are found by using [awl](./awl/):
+The IP addresses are found by using [awl](/awl/):
 
 - [rin.froth.zone](https://rin.froth.zone) (Hosted in Canada)\
     ❯  awl +short rin.froth.zone && awl +short AAAA rin.froth.zone
diff --git a/src/pomme.mdx b/src/pomme.mdx
new file mode 100644
index 0000000..3926bb4
--- /dev/null
+++ b/src/pomme.mdx
@@ -0,0 +1,11 @@
+---
+title: Pomme - A web interface
+subtitle: Coming soon :)
+goimport:
+  url: dns.froth.zone/pomme
+  vcs: git
+  repo: https://git.freecumextremist.com/grumbulon/pomme
+  branch: master
+  gitea: true
+layout: layouts/base.pug
+---
diff --git a/src/resolver.mdx b/src/resolver.mdx
new file mode 100644
index 0000000..489db3c
--- /dev/null
+++ b/src/resolver.mdx
@@ -0,0 +1,32 @@
+---
+title: Froth.zone DNS resolving service
+subtitle:
+layout: layouts/base.pug
+---
+
+I also host an [OpenNIC](https://www.opennic.org/)-compatible DNS resolving server.
+
+### Never asked questions (NAQs)
+
+- *Why OpenNIC?* \
+    Why not? The root servers seamlessly connect to ICANN space, so it's just free extra domains.
+
+- *Where is it?* \
+    Right here. This domain you're looking at right now.
+
+- *What about DNS-over-TCP?* \
+    Yes.
+
+- *DNS-over-TLS?* \
+    Yes, DNS-over-TLS too.
+
+- *DNSCrypt?* \
+    Nope. ¯\\\_(ツ)\_/¯ \
+Maybe when it becomes an RFC.
+
+- *What about DNS-over-HTTPS?* \
+    Yes! Use __ht<span>tp</span>s://dns.froth.zone/dns-query__ as the endpoint URL.
+
+- *What about QUIC?* \
+    Since the software I use doesn't support QUIC yet \
+    (I don't think _any_ do yet), no. Maybe soon(tm)
diff --git a/src/static/img/favicon.png b/src/static/img/favicon.png
new file mode 100644
index 0000000..6e027bf
Binary files /dev/null and b/src/static/img/favicon.png differ
diff --git a/src/static/robots.txt b/src/static/robots.txt
new file mode 100644
index 0000000..37bb545
--- /dev/null
+++ b/src/static/robots.txt
@@ -0,0 +1,5 @@
+User-agent: *
+Allow: /
+Disallow: /dns-query/
+
+Sitemap: http://localhost:3000/sitemap.xml
