diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index e3cd8976d..786f80bcf 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -5,5 +5,5 @@ class ApplicationController < ActionController::Base
include TurboFlash, ViewTransitions
stale_when_importmap_changes
- allow_browser versions: :modern, block: -> { render "errors/not_acceptable", layout: "error" }
+ allow_browser versions: :modern
end
diff --git a/app/controllers/errors_controller.rb b/app/controllers/errors_controller.rb
deleted file mode 100644
index 168dc12e3..000000000
--- a/app/controllers/errors_controller.rb
+++ /dev/null
@@ -1,25 +0,0 @@
-class ErrorsController < ApplicationController
- require_untenanted_access
-
- layout "error"
-
- def bad_request
- render status: :bad_request
- end
-
- def not_found
- render status: :not_found
- end
-
- def not_acceptable
- render status: :not_acceptable
- end
-
- def unprocessable_entity
- render status: :unprocessable_entity
- end
-
- def internal_server_error
- render status: :internal_server_error
- end
-end
diff --git a/app/views/errors/bad_request.html.erb b/app/views/errors/bad_request.html.erb
deleted file mode 100644
index e77283a79..000000000
--- a/app/views/errors/bad_request.html.erb
+++ /dev/null
@@ -1,9 +0,0 @@
-<% @page_title = "400 Bad Request" %>
-
-
- 400
- Bad request
-
- Your request could not be understood by the server.
-
-
diff --git a/app/views/errors/internal_server_error.html.erb b/app/views/errors/internal_server_error.html.erb
deleted file mode 100644
index a26256503..000000000
--- a/app/views/errors/internal_server_error.html.erb
+++ /dev/null
@@ -1,9 +0,0 @@
-<% @page_title = "500 Internal Server Error" %>
-
-
- 500
- Internal server error
-
- Something went wrong on our end; please try again later.
-
-
diff --git a/app/views/errors/not_acceptable.html.erb b/app/views/errors/not_acceptable.html.erb
deleted file mode 100644
index 9408b22b0..000000000
--- a/app/views/errors/not_acceptable.html.erb
+++ /dev/null
@@ -1,9 +0,0 @@
-<% @page_title = "406 Not Acceptable" %>
-
-
- 406
- Not acceptable
-
- The requested resource is not available in a format acceptable to your browser.
-
-
diff --git a/app/views/errors/not_found.html.erb b/app/views/errors/not_found.html.erb
deleted file mode 100644
index c0eafd153..000000000
--- a/app/views/errors/not_found.html.erb
+++ /dev/null
@@ -1,9 +0,0 @@
-<% @page_title = "404 Not Found" %>
-
-
- 404
- Sorry, that page doesn’t exist!
-
- You may have mistyped the address or the page may have moved.
-
-
diff --git a/app/views/errors/unprocessable_entity.html.erb b/app/views/errors/unprocessable_entity.html.erb
deleted file mode 100644
index ede9ed3e6..000000000
--- a/app/views/errors/unprocessable_entity.html.erb
+++ /dev/null
@@ -1,9 +0,0 @@
-<% @page_title = "422 Unprocessable Entity" %>
-
-
- 422
- Unprocessable entity
-
- The server understands the request but was unable to process it.
-
-
diff --git a/app/views/layouts/error.html.erb b/app/views/layouts/error.html.erb
deleted file mode 100644
index f1142baf6..000000000
--- a/app/views/layouts/error.html.erb
+++ /dev/null
@@ -1,143 +0,0 @@
-
-
-
- <%= page_title_tag %>
-
-
-
-
-
-
- <%= yield %>
- <%= link_to "← Back home".html_safe, root_url %>
-
-
diff --git a/config/routes.rb b/config/routes.rb
index 76a6204cc..a49c87ec9 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -210,12 +210,6 @@ Rails.application.routes.draw do
get "manifest" => "rails/pwa#manifest", as: :pwa_manifest
get "service-worker" => "pwa#service_worker"
- match "/400", to: "errors#bad_request", via: :all
- match "/404", to: "errors#not_found", via: :all
- match "/406", to: "errors#not_acceptable", via: :all
- match "/422", to: "errors#unprocessable_entity", via: :all
- match "/500", to: "errors#internal_server_error", via: :all
-
root "events#index"
unless Rails.application.config.x.oss_config
diff --git a/public/400.html b/public/400.html
new file mode 100644
index 000000000..609966ae5
--- /dev/null
+++ b/public/400.html
@@ -0,0 +1,21 @@
+
+
+
+ 400 Bad Request
+
+
+
+
+
+
+
+ 400
+ Bad request
+
+ Your request could not be understood by the server.
+
+
+ ← Back home
+
+
+
diff --git a/public/404.html b/public/404.html
new file mode 100644
index 000000000..97907e3a0
--- /dev/null
+++ b/public/404.html
@@ -0,0 +1,21 @@
+
+
+
+ 404 Not Found
+
+
+
+
+
+
+
+ 404
+ Sorry, that page doesn’t exist!
+
+ You may have mistyped the address or the page may have moved.
+
+
+ ← Back home
+
+
+
diff --git a/public/406.html b/public/406.html
new file mode 100644
index 000000000..180f0204d
--- /dev/null
+++ b/public/406.html
@@ -0,0 +1,21 @@
+
+
+
+ 406 Not Acceptable
+
+
+
+
+
+
+
+ 406
+ Not acceptable
+
+ The requested resource is not available in a format acceptable to your browser.
+
+
+ ← Back home
+
+
+
diff --git a/public/422.html b/public/422.html
new file mode 100644
index 000000000..87d9ef192
--- /dev/null
+++ b/public/422.html
@@ -0,0 +1,21 @@
+
+
+
+ 422 Unprocessable Entity
+
+
+
+
+
+
+
+ 422
+ Unprocessable entity
+
+ The server understands the request but was unable to process it.
+
+
+ ← Back home
+
+
+
diff --git a/public/500.html b/public/500.html
new file mode 100644
index 000000000..ffd35c3cf
--- /dev/null
+++ b/public/500.html
@@ -0,0 +1,21 @@
+
+
+
+ 500 Internal Server Error
+
+
+
+
+
+
+
+ 500
+ Internal server error
+
+ Something went wrong on our end; please try again later.
+
+
+ ← Back home
+
+
+
diff --git a/public/error.css b/public/error.css
new file mode 100644
index 000000000..d49ff8aa3
--- /dev/null
+++ b/public/error.css
@@ -0,0 +1,128 @@
+:root {
+ --color-canvas: white;
+ --color-ink: oklch(26% 0.05 264);
+ --color-accent: oklch(57.02% 0.1895 260.46);
+
+ --text-large: 6rem;
+ --text-medium: 2rem;
+ --text-normal: 1rem;
+
+ @media (prefers-color-scheme: dark) {
+ --color-canvas: oklch(20% 0.0195 232.58);
+ --color-ink: oklch(96.02% 0.0034 260);
+ --color-accent: oklch(74% 0.1293 256);
+ }
+}
+
+*, *::before, *::after {
+ box-sizing: border-box;
+ margin: 0;
+}
+
+html {
+ font-size: 1.5rem;
+ overflow: hidden;
+}
+
+body {
+ -moz-osx-font-smoothing: grayscale;
+ -webkit-font-smoothing: antialiased;
+ -webkit-text-size-adjust: none;
+ align-items: center;
+ background-color: var(--color-canvas);
+ color: var(--color-ink);
+ display: flex;
+ flex-direction: column;
+ font-family: system-ui;
+ font-size: var(--text-normal);
+ font-style: normal;
+ font-weight: 500;
+ gap: 2rem;
+ line-height: 1.375;
+ min-height: 100vh;
+ overflow: hidden;
+ padding-inline: 1rem;
+ justify-content: center;
+ text-align: center;
+ text-rendering: optimizeLegibility;
+ text-size-adjust: none;
+
+ /* Cool wavy striped lines */
+ &:before {
+ --mask:
+ radial-gradient(6px at 50% calc(100% + 3px), #0000 calc(99% - 2px), #000 calc(101% - 2px) 99%, #0000 101%) calc(50% - 8px) calc(50% - 3px + .5px)/16px 6px ,
+ radial-gradient(6px at 50% -3px, #0000 calc(99% - 2px), #000 calc(101% - 2px) 99%, #0000 101%) 50% calc(50% + 3px)/16px 6px ;
+ -webkit-mask: var(--mask);
+ mask: var(--mask);
+ background: var(--color-accent);
+ content: "";
+ inset: 0;
+ opacity: 0.15;
+ position: absolute;
+ z-index: -1;
+ }
+}
+
+.error-page__stamp {
+ --padding: 1rem 2rem;
+ --stroke-width: 0.25rem;
+
+ align-items: center;
+ background-color: color-mix(in oklch, var(--color-canvas), transparent 50%);
+ background-color: var(--color-canvas);
+ border-radius: calc(var(--stroke-width) * 2);
+ border: calc(var(--stroke-width) * 1) dashed var(--color-accent);
+ color: var(--color-accent);
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ line-height: 1.25;
+ max-inline-size: 36ch;
+ rotate: -5deg;
+ padding: var(--padding);
+ position: relative;
+}
+
+h1 {
+ font-size: var(--text-large);
+ font-weight: 900;
+ line-height: 1;
+ position: relative;
+ text-transform: uppercase;
+
+ @supports (-webkit-text-stroke: 1px black) {
+ -webkit-text-stroke: var(--stroke-width) var(--color-accent);
+ -webkit-text-fill-color: transparent;
+ }
+}
+
+h2 {
+ font-size: var(--text-normal);
+ font-weight: inherit;
+}
+
+hr {
+ inline-size: 100%;
+ border: 0;
+ border-block-start: calc(var(--stroke-width) / 2) solid currentcolor;
+ color: currentcolor;
+ margin: 1ch auto;
+}
+
+a {
+ color: inherit;
+ line-height: 2rem;
+ display: inline-block;
+ padding-inline: 1ch;
+ border-radius: 99rem;
+ text-decoration: none;
+
+ span {
+ text-decoration: underline;
+ text-underline-offset: 0.25ch;
+ }
+
+ &:hover {
+ color: var(--color-accent);
+ }
+}