<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>404 — Page Not Found</title>
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500;600;700&display=swap"
rel="stylesheet"
/>
<script>
window.tailwind = window.tailwind || {};
window.tailwind.config = {
theme: {
extend: {
fontFamily: {
sans: [
"Inter",
"ui-sans-serif",
"system-ui",
"-apple-system",
"Segoe UI",
"Roboto",
"sans-serif",
],
mono: [
"JetBrains Mono",
"ui-monospace",
"SFMono-Regular",
"Menlo",
"Consolas",
"monospace",
],
},
},
},
};
</script>
<script src="https://cdn.tailwindcss.com?plugins=forms,container-queries"></script>
<style>
body {
font-family: "Inter", ui-sans-serif, system-ui, -apple-system,
"Segoe UI", Roboto, sans-serif;
}
.mono {
font-family: "JetBrains Mono", ui-monospace, SFMono-Regular,
Menlo, Consolas, monospace;
}
</style>
</head>
<body
class="min-h-screen bg-slate-950 text-slate-300 antialiased flex flex-col"
>
<header
class="relative z-10 px-6 py-5 flex items-center justify-between"
>
<a
href="/"
class="mono text-xs tracking-widest text-slate-500 hover:text-slate-300 transition-colors"
>
umbral
</a>
<span
class="mono text-[10px] tracking-widest text-slate-600 uppercase"
>
error // not_found
</span>
</header>
<div
class="absolute inset-0 -z-10 bg-[linear-gradient(to_right,#0f172a_1px,transparent_1px),linear-gradient(to_bottom,#0f172a_1px,transparent_1px)] bg-[size:4rem_4rem] [mask-image:radial-gradient(ellipse_60%_50%_at_50%_40%,#000_30%,transparent_100%)] opacity-40"
></div>
<div
class="absolute inset-0 -z-10 bg-[radial-gradient(circle_at_50%_30%,rgba(99,102,241,0.08),transparent_60%)]"
></div>
<main
class="relative flex-1 flex items-center justify-center px-6 py-16"
>
<div class="w-full max-w-2xl mx-auto text-center">
<p
class="mono text-xs tracking-[0.25em] text-slate-500 uppercase"
>
Error // Not_Found
</p>
<h1
class="mono mt-6 text-7xl sm:text-8xl md:text-9xl font-bold tracking-tighter text-slate-200 leading-none"
>
404
</h1>
<h2
class="mt-8 text-2xl sm:text-3xl font-semibold text-slate-100 tracking-tight"
>
Page not found
</h2>
<p
class="mt-4 text-base text-slate-400 max-w-md mx-auto leading-relaxed"
>
The path you requested doesn't match any registered route on
this server.
</p>
{% if path %}
<div class="mt-8 mx-auto max-w-xl">
<div
class="flex items-center gap-2 rounded-md border border-slate-800 bg-slate-900/60 px-3 py-2.5 backdrop-blur-sm"
>
<span
class="mono text-[10px] tracking-widest text-slate-600 uppercase shrink-0"
>GET</span
>
<code
class="mono text-sm text-slate-300 truncate flex-1 text-left"
title="{{ path }}"
>{{ path }}</code
>
<button
type="button"
onclick="navigator.clipboard?.writeText('{{ path }}'); this.textContent='Copied'; setTimeout(()=>this.textContent='Copy',1200);"
class="mono text-[10px] tracking-widest uppercase text-slate-500 hover:text-slate-200 transition-colors shrink-0 px-2 py-1 rounded focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-400"
>
Copy
</button>
</div>
</div>
{% endif %}
<div
class="mt-10 flex flex-col sm:flex-row items-center justify-center gap-3"
>
<a
href="/"
class="inline-flex items-center justify-center gap-2 rounded-md bg-indigo-500 px-5 py-2.5 text-sm font-semibold text-white shadow-sm hover:bg-indigo-400 transition-colors focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-400 w-full sm:w-auto"
>
<span aria-hidden="true">←</span>
<span>Go home</span>
</a>
<button
type="button"
onclick="
if (history.length > 1) {
history.back();
} else {
window.location.href = '/';
}
"
class="inline-flex items-center justify-center gap-2 rounded-md border border-slate-800 bg-slate-900/40 px-5 py-2.5 text-sm font-semibold text-slate-200 hover:bg-slate-900 hover:border-slate-700 transition-colors focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-400 w-full sm:w-auto"
>
Go back
</button>
</div>
{# Dev-mode aid: list every registered route, grouped
by plugin. Production responses set `dev_mode =
false` so this whole block collapses to nothing. The
list is a declared snapshot, not a live introspection
of axum's routing table — see
`crates/umbral-core/src/routes.rs`. #}
{% if dev_mode and routes_by_plugin %}
<div
class="mt-12 mx-auto max-w-2xl text-left rounded-md border border-slate-800 bg-slate-900/40 backdrop-blur-sm"
>
<div
class="flex items-center justify-between gap-3 px-4 py-2.5 border-b border-slate-800"
>
<span
class="mono text-[10px] tracking-widest text-slate-400 uppercase"
>
Dev only // registered routes
</span>
<span class="mono text-[10px] text-slate-600">
{{ routes_by_plugin | length }} plugin{% if routes_by_plugin | length != 1 %}s{% endif %}
</span>
</div>
<div class="divide-y divide-slate-800">
{% for group in routes_by_plugin %}
<details class="group">
<summary
class="flex items-center justify-between gap-3 px-4 py-2.5 cursor-pointer hover:bg-slate-900/60 transition-colors"
>
<span
class="mono text-xs text-slate-300"
>{{ group.plugin }}</span
>
<span
class="mono text-[10px] text-slate-500"
>{{ group.routes | length }} route{% if group.routes | length != 1 %}s{% endif %}</span
>
</summary>
<ul
class="px-4 py-2 space-y-1.5 bg-slate-950/40 border-t border-slate-800"
>
{% for route in group.routes %}
<li class="flex items-baseline gap-2">
{# Method badge: tinted by verb so
the eye can scan a list of mixed
GET/POST/DELETE entries without
reading every label. The single
`method_label` (joined with `·`)
keeps the badge narrow even for
composite routes like
`GET·PUT`. #}
{% set ml = route.method_label %}
<span class="mono text-[10px] tracking-wider uppercase px-1.5 py-0.5 rounded shrink-0
{% if 'POST' in route.methods or 'PUT' in route.methods or 'PATCH' in route.methods %}bg-amber-500/10 text-amber-300 ring-1 ring-amber-500/30
{% elif 'DELETE' in route.methods %}bg-rose-500/10 text-rose-300 ring-1 ring-rose-500/30
{% elif 'GET' in route.methods or 'HEAD' in route.methods %}bg-emerald-500/10 text-emerald-300 ring-1 ring-emerald-500/30
{% else %}bg-slate-700/30 text-slate-400 ring-1 ring-slate-700{% endif %}"
>{{ ml }}</span>
<code
class="mono text-xs text-slate-400 break-all"
>{{ route.path }}</code
>
</li>
{% endfor %}
</ul>
</details>
{% endfor %}
</div>
</div>
{% endif %}
</div>
</main>
<footer
class="relative z-10 px-6 py-5 flex items-center justify-center gap-6"
>
<a
href="/docs"
class="text-xs text-slate-500 hover:text-slate-300 transition-colors"
>Docs</a
>
<span class="text-slate-800" aria-hidden="true">·</span>
<a
href="/status"
class="text-xs text-slate-500 hover:text-slate-300 transition-colors"
>Status</a
>
<span class="text-slate-800" aria-hidden="true">·</span>
<a
href="https://github.com/umbral/umbral"
class="text-xs text-slate-500 hover:text-slate-300 transition-colors"
>GitHub</a
>
</footer>
</body>
</html>