diff --git a/src/site/html/static/img/tick.svg b/src/site/html/static/img/tick.svg
new file mode 100644
index 0000000..38a5458
--- /dev/null
+++ b/src/site/html/static/img/tick.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/site/pug/settings.pug b/src/site/pug/settings.pug
new file mode 100644
index 0000000..9f5c191
--- /dev/null
+++ b/src/site/pug/settings.pug
@@ -0,0 +1,101 @@
+mixin form-component(id, description)
+ .field-row
+ label.description(for=id)= description
+ block(id="ten")
+
+mixin fieldset(name)
+ fieldset
+ legend= name
+ .fieldset-contents
+ block
+
+mixin input(id, description, value, disabled)
+ .field-row
+ label.description(for=id)= description
+ input(type="text" id=id name=id value=value disabled=disabled)
+
+mixin checkbox(id, description, label, checked, disabled)
+ .field-row.checkbox-row
+ label.description(for=id)= description
+ input.checkbox(type="checkbox" id=id name=id checked=checked disabled=disabled autocomplete="off")
+ label.pill(for=id tabindex=(disabled ? null : 0) onkeypress=`[" ", "Enter"].includes(event.key) && this.click()`)= label
+ span.fake-checkbox
+
+mixin select(id, description, disabled, options)
+ .field-row
+ label.description(for=id)= description
+ select(id=id name=id disabled=disabled)
+ block
+
+doctype html
+html
+ head
+ title Settings | Bibliogram
+ include includes/head
+ body.settings-page
+ main.settings
+ form(action="/settings" method="post")
+ h1 Settings
+
+ +fieldset("Features")
+ +select("language", "Language", true)
+ option English (International)
+
+ +checkbox("show_comments", "Display comments", "Display", false, true)
+
+ +checkbox("link_hashtags", "Clickable hashtags", "Clickable", false, true)
+
+ +checkbox("spa", "Fast navigation", "Enabled", true, true)
+
+ +fieldset("Appearance")
+ +select("theme", "Theme", true)
+ option Classic
+
+ +select("caption_side", "Caption side", true)
+ option Left (Bibliogram)
+ option Right (Instagram)
+
+ +checkbox("display_alt", "Display alt text inline", "Display", false, true)
+
+ //- div
+ //- Here are all the possible input styles. Uncomment to test styling.
+ - let i = 2
+ - let id = 0
+ - let thisID
+ while --i >= 0
+ fieldset
+ legend Style demo
+ .field-row
+ - thisID = "in"+(id++)
+ label.description(for=thisID) Placeholder
+ input(type="text" placeholder="Placeholder" id=thisID)
+
+ .field-row
+ - thisID = "in"+(id++)
+ label.description(for=thisID) Disabled
+ input(type="text" disabled placeholder="Disabled" value="Value" id=thisID)
+
+ .field-row
+ label.description Button
+ button(type="button") Button
+
+ .field-row
+ - thisID = "in"+(id++)
+ label.description(for=thisID) Select
+ select(id=thisID)
+ option Select
+ option Yes
+ option No
+ option Always
+ option Never
+
+ .field-row.checkbox-row
+ - thisID = "in"+(id++)
+ label.description(for=thisID) Checkbox
+ input.checkbox(type="checkbox" id=thisID)
+ label.pill(for=thisID tabindex=0 onkeypress=`[" ", "Enter"].includes(event.key) && this.click()`) Label
+ span.fake-checkbox
+
+ .action-container
+ a(href="/").home-link ← Home
+ button(type="submit").save-button Save settings
diff --git a/src/site/sass/_forms.sass b/src/site/sass/_forms.sass
new file mode 100644
index 0000000..985e92a
--- /dev/null
+++ b/src/site/sass/_forms.sass
@@ -0,0 +1,152 @@
+@mixin medium-border
+ border-color: #aaa
+
+@mixin full-border
+ border-color: #888
+
+@mixin outside-shadow
+ box-shadow: 0px 0px 1px 0px rgba(0, 0, 0, 0.2)
+
+@mixin inside-shadow
+ box-shadow: 1px 1px 3px 0px rgba(0, 0, 0, 0.2) inset
+
+@mixin curve-in
+ background: linear-gradient(to bottom, #efebe9, #faf8f7)
+
+@mixin curve-out
+ background: linear-gradient(to bottom, #fff 20%, #efeceb)
+
+@mixin curve-out-major
+ background: linear-gradient(to bottom, #fff 10%, #e4e2e0)
+
+@mixin disabled
+ background-color: #dfd6cb
+ color: #606060
+
+@mixin acts-like-button
+ &:not(:disabled)
+ cursor: pointer
+ @include curve-out
+
+ &:hover, &:focus
+ @include medium-border
+ @include outside-shadow
+
+ &:active
+ @include full-border
+ @include inside-shadow
+ @include curve-in
+
+fieldset
+ border: none
+ padding: 55px 0px 0px 0px
+ position: relative
+
+ @media screen and (max-width: 400px)
+ padding-top: 70px
+
+ legend
+ position: absolute
+ top: 5px
+ left: 0px
+ width: 100%
+ font-size: 28px
+ font-weight: bold
+ padding: 0
+ border-bottom: 1px solid #333
+ line-height: 1.56
+
+ @media screen and (max-width: 400px)
+ margin-top: 15px
+
+
+.field-row
+ line-height: 1
+ display: flex
+ align-items: center
+ justify-content: space-between
+ position: relative
+ padding-bottom: 5px
+ margin-bottom: 5px
+ border-bottom: 1px solid #bbb
+
+ @media screen and (max-width: 400px)
+ flex-direction: column
+ align-items: start
+ padding-bottom: 15px
+
+ .description
+ padding: 8px 8px 8px 0px
+
+button, select, input, .checkbox-row .pill
+ font-family: inherit
+ font-size: inherit
+ color: #222
+ border: 1px solid #ccc
+ border-radius: 4px
+ background-color: #fff
+ padding: 8px
+ line-height: 1
+
+ &::placeholder
+ font-style: italic
+
+ &:disabled
+ @include disabled
+
+input[type="text"]
+ width: 200px
+
+select
+ padding: 4px 6px 4px 4px
+
+input:not(:disabled)
+ &:hover
+ @include medium-border
+
+ &:focus
+ @include full-border
+ @include outside-shadow
+
+select:not(:disabled)
+ &:hover, &:focus
+ @include medium-border
+ @include outside-shadow
+ @include curve-out
+
+button
+ @include acts-like-button
+
+.checkbox-row
+ .pill
+ display: flex
+ align-items: center
+ user-select: none
+
+ .fake-checkbox
+ -webkit-appearance: none
+ background-color: white
+ width: 16px
+ height: 16px
+ padding: 0px
+ border: 1px solid #666
+ border-radius: 3px
+ margin-left: 8px
+ position: relative
+ outline: none
+
+ .checkbox
+ display: none
+
+ &:checked + .pill .fake-checkbox
+ background: center center / contain url(/static/img/tick.svg)
+
+ &:disabled + .pill
+ @include disabled
+
+ .fake-checkbox
+ @include disabled
+
+ &.checkbox:not(:disabled) + .pill
+ @include acts-like-button
+ cursor: pointer
diff --git a/src/site/sass/main.sass b/src/site/sass/main.sass
index 2f308df..1c9ca27 100644
--- a/src/site/sass/main.sass
+++ b/src/site/sass/main.sass
@@ -1,3 +1,5 @@
+@use "forms"
+
$layout-a-max: 820px
$layout-b-min: 821px
$layout-c-max: 680px
@@ -5,6 +7,7 @@ $layout-home-a-max: 520px
$layout-home-b-min: 521px
$main-theme-link-color: #085cae
$medium-red-bg: #6a2222
+$solar-background: #fff4e8
@font-face
font-family: "Bariol"
@@ -124,7 +127,7 @@ body
.timeline
--image-size: 260px
$image-size: var(--image-size)
- $background: #fff4e8
+ $background: $solar-background
@media screen and (max-width: $layout-a-max)
--image-size: 150px
@@ -159,9 +162,6 @@ body
top: 50%
border-top: 1px solid
-
- &:no-posts
-
.number
position: relative
z-index: 1
@@ -633,3 +633,27 @@ body
a, a:visited
color: $main-theme-link-color
+
+.settings-page
+ background-color: #fff4e8
+ padding: 0px 10px 50px
+
+ a, a:visited
+ color: $main-theme-link-color
+
+ .settings
+ max-width: 600px
+ margin: 0 auto
+
+ .action-container
+ margin-top: 20px
+ display: flex
+ justify-content: space-between
+ align-items: center
+
+ .save-button
+ @include forms.curve-out-major
+ width: 180px
+
+ .home-link
+ font-size: 21px
diff --git a/src/site/server.js b/src/site/server.js
index 4eec316..5ca7294 100644
--- a/src/site/server.js
+++ b/src/site/server.js
@@ -22,6 +22,7 @@ subdirs("pug", async (err, dirs) => {
pinski.setNotFoundTarget("/404")
pinski.addRoute("/static/css/main.css", "sass/main.sass", "sass")
+ pinski.addRoute("/settings", "pug/settings.pug", "pug")
pinski.addPugDir("pug", dirs)
pinski.addSassDir("sass")
pinski.addStaticHashTableDir("html/static/js")