diff --git a/public/assets/css/document.css b/public/assets/css/document.css
new file mode 100644
index 0000000..27adae2
--- /dev/null
+++ b/public/assets/css/document.css
@@ -0,0 +1,152 @@
+:root {
+ --primer-color-deep: 0, 128, 255;
+ --primer-color-light: 135, 255, 255;
+ --color-deep: rgba(var(--primer-color-deep));
+ --color-light: rgba(var(--primer-color-light));
+
+ --padding: 10px;
+ --running-size: 70px;
+}
+
+/* # Cornerstones */
+
+* {
+ margin: 0;
+ color: inherit;
+ font-size: inherit;
+ box-sizing: border-box;
+ font-family: monospace;
+}
+
+body {
+ font-size: 15px;
+ min-height: 100svh;
+ overflow-x: hidden;
+ overscroll-behavior: none;
+}
+
+a {
+ color: inherit;
+ display: contents;
+ text-decoration: none;
+}
+
+/* # Components */
+
+:is(h1, h2, h3, p, li) > a {
+ --underline-tickness: 3px;
+
+ display: initial;
+ text-decoration: underline;
+ text-decoration-color: var(--color-accent);
+ text-underline-offset: var(--underline-tickness);
+ text-decoration-thickness: var(--underline-tickness);
+}
+
+h1 {
+ font-size: 30px;
+ color: var(--color-accent);
+}
+
+h2 {
+ font-size: 25px;
+}
+
+h3 {
+ font-size: 25px;
+}
+
+/* ## Sections */
+
+/* ## Container */
+
+container {
+ margin: auto;
+ height: 100%;
+ display: flex;
+ width: clamp(900px, 80vw, 1400px);
+ align-items: center;
+ gap: var(--padding);
+ padding: var(--padding) 0;
+}
+
+container.split {
+ display: grid;
+ grid-template-columns: repeat(2, 1fr);
+}
+
+container.split > div {
+ display: flex;
+ flex-direction: column;
+ gap: var(--padding);
+}
+
+container.split > div:first-child {
+ align-items: baseline;
+ justify-content: center;
+}
+
+/* ## Button */
+
+button {
+ border: unset;
+ cursor: pointer;
+ padding: 10px 15px;
+ border-radius: 4px;
+ background-color: rgba(0, 0, 0, 0);
+}
+
+button.solid {
+ color: white;
+ background-color: var(--color-deep);
+}
+
+@media (hover: hover) {
+ button:hover {
+ background-color: rgba(0, 0, 0, .05);
+ }
+
+ button.solid:hover {
+ color: var(--color-light);
+ background-color: var(--color-deep);
+ }
+}
+
+/* # Content */
+
+header {
+ --border-width: 2px;
+
+ top: 0px;
+ position: sticky;
+ background-color: white;
+ height: calc(var(--running-size) + var(--border-width));
+ border-bottom: solid var(--border-width) rgba(var(--primer-color-deep), .1);
+ z-index: 1000;
+}
+
+header .logo {
+ height: 40px;
+ padding: 5px;
+ border-radius: 4px;
+ background-color: var(--color-deep);
+}
+
+header ul {
+ display: flex;
+ padding-left: 0;
+ list-style: none;
+ gap: var(--padding);
+}
+
+header ul:last-child {
+ margin-left: auto;
+}
+
+[vv-top-page="/help"] header a[href="/help"] button,
+[vv-top-page="/docs"] header a[href="/docs"] button,
+[vv-top-page="/demos"] header a[href="/demos"] button,
+[vv-top-page="/why"] header a[href="/why"] button {
+ font-weight: bold;
+ background-color: rgba(0, 0, 0, .05);
+}
\ No newline at end of file
diff --git a/public/assets/css/pages/index.css b/public/assets/css/pages/index.css
new file mode 100644
index 0000000..73c618c
--- /dev/null
+++ b/public/assets/css/pages/index.css
@@ -0,0 +1,74 @@
+:root {
+ --wavelength: 20vw;
+}
+
+body {
+ background-color: var(--color-deep);
+}
+
+header.transparent {
+ color: white;
+ background-color: transparent;
+ border-color: rgba(255, 255, 255, .1);
+}
+
+header.transparent .logo {
+ fill: var(--color-deep);
+ background-color: white;
+}
+
+header.transparent button.solid {
+ color: var(--color-deep);
+ background-color: white;
+}
+
+/* # Sections */
+
+/* ## Intro */
+
+section#intro {
+ color: white;
+ height: 400px;
+}
+
+section#intro div {
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: baseline;
+}
+
+section#intro h1 {
+ font-size: 50px;
+}
+
+section#intro h2 {
+ background-color: black;
+}
+
+/* ### Waves */
+
+section#intro .waves {
+ position: relative;
+ z-index: -1;
+}
+
+section#intro .waves img {
+ width: calc(100% + var(--wavelength));
+ object-fit: cover;
+ animation: waves 9s linear infinite;
+}
+
+@keyframes waves {
+ to {
+ transform: translateX(calc((var(--wavelength) * 2) * -1));
+ }
+}
+
+/* ## Example */
+
+section#example {
+ margin-top: calc(var(--wavelength) / 2);
+ background-color: white;
+ height: 700px;
+}
\ No newline at end of file
diff --git a/public/assets/css/pages/why.css b/public/assets/css/pages/why.css
new file mode 100644
index 0000000..4b090fa
--- /dev/null
+++ b/public/assets/css/pages/why.css
@@ -0,0 +1,59 @@
+/* # Sections */
+
+/* ## Title */
+
+section.title {
+ color: white;
+ padding: calc(var(--padding) * 2) 0;
+ align-items: center;
+ background-color: var(--color-deep);
+}
+
+section.title container {
+ display: flex;
+ gap: 50px;
+}
+
+section.title svg {
+ height: 150px;
+}
+
+section.title container > div {
+ display: flex;
+ flex-direction: column;
+ gap: var(--padding);
+}
+
+section.title h1 span {
+ text-decoration: underline;
+}
+
+section.title h2 {
+ background-color: black;
+}
+
+/* ## Text */
+
+section.text {
+ min-height: 400px;
+ padding: calc(var(--padding) * 2) 0;
+}
+
+section.text h2 {
+ color: white;
+ background-color: black;
+}
+
+/* ## Free */
+
+section#free {
+ background-position: 50% 50%;
+ background-size: 400px;
+ background-color: red;
+ background-blend-mode: lighten;
+ background-image: url("/assets/media/gnu.png");
+}
+
+section#free svg {
+ filter: drop-shadow(0 0 40px rgba(255, 255, 255, .3));
+}
\ No newline at end of file
diff --git a/public/assets/js/pages/index.js b/public/assets/js/pages/index.js
new file mode 100644
index 0000000..5df688f
--- /dev/null
+++ b/public/assets/js/pages/index.js
@@ -0,0 +1,10 @@
+const headerElement = document.querySelector("header");
+
+const updateHeader = () => {
+ document.documentElement.scrollTop > 0
+ ? headerElement.classList.remove("transparent")
+ : headerElement.classList.add("transparent")
+}
+
+window.addEventListener("scroll", updateHeader);
+updateHeader();
\ No newline at end of file
diff --git a/public/assets/media/gnu.png b/public/assets/media/gnu.png
new file mode 100644
index 0000000..a8622ed
Binary files /dev/null and b/public/assets/media/gnu.png differ
diff --git a/public/assets/media/gnu.webp b/public/assets/media/gnu.webp
new file mode 100644
index 0000000..0fca84d
Binary files /dev/null and b/public/assets/media/gnu.webp differ
diff --git a/public/assets/media/logo.svg b/public/assets/media/logo.svg
new file mode 100644
index 0000000..618f44d
--- /dev/null
+++ b/public/assets/media/logo.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/public/assets/media/waves/waves.svg b/public/assets/media/waves/waves.svg
new file mode 100644
index 0000000..1f46bfa
--- /dev/null
+++ b/public/assets/media/waves/waves.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/public/assets/media/why-gnu.svg b/public/assets/media/why-gnu.svg
new file mode 100644
index 0000000..a9adf30
--- /dev/null
+++ b/public/assets/media/why-gnu.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/public/index.php b/public/index.php
new file mode 100644
index 0000000..2d35b59
--- /dev/null
+++ b/public/index.php
@@ -0,0 +1,19 @@
+
+
+
+
+
Vegvisir
+
A PHP and JavaScript Web Framework
+
that handles navigation and routing, and nothing else
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/public/why.php b/public/why.php
new file mode 100644
index 0000000..f0349d7
--- /dev/null
+++ b/public/why.php
@@ -0,0 +1,36 @@
+
+
+
+
+
Load what's needed and change what needs to change
+
+
+
+
+
+
+
Sorry, did I studder?
+
By loading what's needed and changing only what needs to change on a page, Vegvisir can compile a custom server-side rendered response body for each request depending on what the client already has loaded.
+
For example, why should the header on this page be loaded again when you navigate to another page on this site? Your browser has already fetched, compiled, and rendered everything needed to display it. And when you for example navigate to the documentation page, why should the documentation pages inner "shell" be replaced when you navigate the documentation pages?
+
Each Vegvisir navigation request contains a list of all loaded shells, which the Vegvisir back-end uses to determine what content should be returned depending on what the client has already loaded.
+
+
+
+
+
+ = VV::embed("public/assets/media/why-gnu.svg") ?>
+
+
It's a GNU!
+ Vegvisir is and will always be free software.
+
+
+
+
+
+
+
Free as in freedom
+
Major PHP frameworks like Laravel, Symphony, and CakePHP are all licensed under the permissive MIT software license. These frameworks can and are being used today to develop proprietary software.
+
Vegvisir is licensed under GNU GPL v3 (or newer) and that will never change.
+
+
+
\ No newline at end of file
diff --git a/shells/document.php b/shells/document.php
new file mode 100644
index 0000000..9c9db22
--- /dev/null
+++ b/shells/document.php
@@ -0,0 +1,62 @@
+
+
+
+
+
+
+
+
+
+
+ Vegvisir
+
+
+
+
+ = VV::init(); ?>
+
+
\ No newline at end of file