diff --git a/.gitignore b/.gitignore
index 11530b5..e5543ec 100644
--- a/.gitignore
+++ b/.gitignore
@@ -185,3 +185,5 @@ cython_debug/
 gacha_game*.db
 gacha_game*.db.*
 config*.ini
+
+.idea
\ No newline at end of file
diff --git a/web/app.py b/web/app.py
index f68084c..61ed38f 100644
--- a/web/app.py
+++ b/web/app.py
@@ -1,6 +1,8 @@
-from flask import Flask, render_template
 import sqlite3
 
+from flask import Flask, render_template, abort
+from werkzeug.exceptions import HTTPException
+
 app = Flask(__name__)
 DB_PATH = "./gacha_game.db"  # Adjust path if needed
 
@@ -9,6 +11,14 @@ def get_db_connection():
     conn.row_factory = sqlite3.Row
     return conn
 
+@app.errorhandler(HTTPException)
+def handle_exception(error):
+    return render_template("_error.html", error=error), error.code
+
+@app.route("/i404")
+def i404():
+    return abort(404)
+
 @app.route('/')
 def index():
     conn = get_db_connection()
@@ -33,6 +43,8 @@ def user_profile(user_id):
 
     cursor.execute('SELECT * FROM users WHERE id = ?', (user_id,))
     user = cursor.fetchone()
+    if user is None:
+        abort(404)
 
     cursor.execute('''
         SELECT pulls.timestamp, characters.name as character_name, characters.rarity
diff --git a/web/static/style.css b/web/static/style.css
new file mode 100644
index 0000000..74231c1
--- /dev/null
+++ b/web/static/style.css
@@ -0,0 +1,92 @@
+body {
+            font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif;
+            background-color: #f4f6fa;
+            color: #333;
+            margin: 0;
+            padding: 0;
+        }
+
+        header {
+            background-color: #7289da;
+            color: white;
+            padding: 20px;
+            text-align: center;
+        }
+
+        header h1 {
+            margin: 0;
+            font-size: 2.5em;
+        }
+
+        header p {
+            margin-top: 5px;
+            font-size: 1.1em;
+        }
+
+        .container {
+            max-width: 800px;
+            margin: 30px auto;
+            padding: 20px;
+            background-color: #ffffff;
+            border-radius: 10px;
+            box-shadow: 0 3px 10px rgba(0, 0, 0, 0.07);
+        }
+
+        h2 {
+            border-bottom: 1px solid #ccc;
+            padding-bottom: 8px;
+            margin-top: 30px;
+        }
+
+        ul {
+            list-style-type: none;
+            padding-left: 0;
+        }
+
+        li {
+            margin: 10px 0;
+        }
+
+        a {
+            text-decoration: none;
+            color: #2c3e50;
+            font-weight: bold;
+            background-color: #e3eaf3;
+            padding: 8px 12px;
+            border-radius: 6px;
+            display: inline-block;
+            transition: background-color 0.2s;
+        }
+
+        a:hover {
+            background-color: #cdd8e6;
+        }
+
+        .leaderboard-entry {
+            margin-bottom: 8px;
+            padding: 6px 10px;
+            background: #f9fafc;
+            border-left: 4px solid #7289da;
+            border-radius: 5px;
+        }
+
+        footer {
+            text-align: center;
+            margin-top: 40px;
+            font-size: 0.9em;
+            color: #888;
+        }
+
+        .note {
+            background: #fcfcf0;
+            border: 1px dashed #bbb;
+            padding: 10px;
+            border-radius: 8px;
+            margin-top: 30px;
+            font-size: 0.95em;
+            color: #666;
+        }
+
+        .footer-link {
+            margin: 0 10px;
+        }
\ No newline at end of file
diff --git a/web/templates/_base.html b/web/templates/_base.html
new file mode 100644
index 0000000..a1f1b22
--- /dev/null
+++ b/web/templates/_base.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='style.css') }}">
+    <link rel="shortcut icon" href="{{ url_for('static', filename='logo.png') }}">
+    <title>
+    {% if title %}
+        {{ title }}
+    {% else %}
+        {% block title %}{% endblock %}
+    {% endif %}
+        &nbsp;|&nbsp;Kemoverse
+    </title>
+</head>
+<body>
+    <header>
+        {% block header %}{% endblock %}
+    </header>
+
+    <div class="container">
+    {% block content %}{% endblock %}
+    </div>
+
+    <footer>
+        <a class="footer-link" href="{{ url_for('about') }}">About</a>
+        <a class="footer-link" href="{{ url_for('submit_character') }}">Submit a Character</a>
+        {% block footer_extra %}{% endblock %}
+    </footer>
+</body>
+</html>
diff --git a/web/templates/_error.html b/web/templates/_error.html
new file mode 100644
index 0000000..defc5d8
--- /dev/null
+++ b/web/templates/_error.html
@@ -0,0 +1,8 @@
+{% extends "_base.html" %}
+{% block title %}
+	{{ error.code }}
+{% endblock %}
+{% block content %}
+    <h2>{{ error.code }}&nbsp;-&nbsp;{{ error.name }} </h2>
+    <p>{{ error.description }}</p>
+{% endblock %}
\ No newline at end of file
diff --git a/web/templates/about.html b/web/templates/about.html
index 89519db..184fde9 100644
--- a/web/templates/about.html
+++ b/web/templates/about.html
@@ -1,13 +1,9 @@
-<!DOCTYPE html>
-<html>
-<head>
-    <title>About - Misskey Gacha Center</title>
-</head>
-<body>
+{% extends "_base.html" %}
+
+{% block content %}
     <h1>About This Gacha</h1>
     <p>This is a playful Misskey-themed gacha tracker made with Flask and SQLite.</p>
     <p>All rolls are stored, stats are tracked, and characters are added manually for now.</p>
     <p>Built with love, chaos, and way too much caffeine ☕.</p>
     <a href="{{ url_for('index') }}">← Back to Home</a>
-</body>
-</html>
+{% endblock %}
\ No newline at end of file
diff --git a/web/templates/index.html b/web/templates/index.html
index e9b1680..f9bf7a0 100644
--- a/web/templates/index.html
+++ b/web/templates/index.html
@@ -1,110 +1,11 @@
-<!DOCTYPE html>
-<html>
-<head>
-    <title>Misskey Gacha Center</title>
-    <style>
-        body {
-            font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif;
-            background-color: #f4f6fa;
-            color: #333;
-            margin: 0;
-            padding: 0;
-        }
+{% extends "_base.html" %}
 
-        header {
-            background-color: #7289da;
-            color: white;
-            padding: 20px;
-            text-align: center;
-        }
+{% block header %}
+    <h1>Misskey Gacha Center</h1>
+    <p>Track your luck. Compare your pulls. Compete with friends.</p>
+{% endblock %}
 
-        header h1 {
-            margin: 0;
-            font-size: 2.5em;
-        }
-
-        header p {
-            margin-top: 5px;
-            font-size: 1.1em;
-        }
-
-        .container {
-            max-width: 800px;
-            margin: 30px auto;
-            padding: 20px;
-            background-color: #ffffff;
-            border-radius: 10px;
-            box-shadow: 0 3px 10px rgba(0, 0, 0, 0.07);
-        }
-
-        h2 {
-            border-bottom: 1px solid #ccc;
-            padding-bottom: 8px;
-            margin-top: 30px;
-        }
-
-        ul {
-            list-style-type: none;
-            padding-left: 0;
-        }
-
-        li {
-            margin: 10px 0;
-        }
-
-        a {
-            text-decoration: none;
-            color: #2c3e50;
-            font-weight: bold;
-            background-color: #e3eaf3;
-            padding: 8px 12px;
-            border-radius: 6px;
-            display: inline-block;
-            transition: background-color 0.2s;
-        }
-
-        a:hover {
-            background-color: #cdd8e6;
-        }
-
-        .leaderboard-entry {
-            margin-bottom: 8px;
-            padding: 6px 10px;
-            background: #f9fafc;
-            border-left: 4px solid #7289da;
-            border-radius: 5px;
-        }
-
-        footer {
-            text-align: center;
-            margin-top: 40px;
-            font-size: 0.9em;
-            color: #888;
-        }
-
-        .note {
-            background: #fcfcf0;
-            border: 1px dashed #bbb;
-            padding: 10px;
-            border-radius: 8px;
-            margin-top: 30px;
-            font-size: 0.95em;
-            color: #666;
-        }
-
-        .footer-link {
-            margin: 0 10px;
-        }
-    </style>
-</head>
-<body>
-
-    <header>
-        <h1>Misskey Gacha Center</h1>
-        <p>Track your luck. Compare your pulls. Compete with friends.</p>
-    </header>
-
-    <div class="container">
+{% block content %}
 
         <h2>🎖️ Leaderboard: Most Rolls</h2>
         {% for user in top_users %}
@@ -125,13 +26,4 @@
         <div class="note">
             🚀 This is a fun little gacha tracker! More features coming soon. Want to help shape it?
         </div>
-
-    </div>
-
-    <footer>
-        <a class="footer-link" href="{{ url_for('about') }}">About</a>
-        <a class="footer-link" href="{{ url_for('submit_character') }}">Submit a Character</a>
-    </footer>
-
-</body>
-</html>
+{% endblock %}
\ No newline at end of file
diff --git a/web/templates/submit.html b/web/templates/submit.html
index 5dc5ac9..d0424b8 100644
--- a/web/templates/submit.html
+++ b/web/templates/submit.html
@@ -1,12 +1,8 @@
-<!DOCTYPE html>
-<html>
-<head>
-    <title>Submit a Character - Misskey Gacha Center</title>
-</head>
-<body>
+{% extends "_base.html" %}
+
+{% block content %}
     <h1>Submit a Character</h1>
     <p>Want to add a new character to the gacha pool?</p>
     <p>This feature will be available soon. Stay tuned!</p>
     <a href="{{ url_for('index') }}">← Back to Home</a>
-</body>
-</html>
+{% endblock %}
\ No newline at end of file
diff --git a/web/templates/user.html b/web/templates/user.html
index 0004052..8010538 100644
--- a/web/templates/user.html
+++ b/web/templates/user.html
@@ -1,57 +1,5 @@
-<!DOCTYPE html>
-<html>
-<head>
-    <title>{{ user['username'] }}'s Rolls</title>
-    <style>
-        body {
-            font-family: Arial, sans-serif;
-            background-color: #f4f4f8;
-            margin: 0;
-            padding: 20px;
-        }
-        .profile, .pulls {
-            background-color: white;
-            padding: 15px;
-            border-radius: 10px;
-            box-shadow: 0 0 10px rgba(0,0,0,0.1);
-            margin-bottom: 20px;
-        }
-        h1, h2 {
-            margin-top: 0;
-        }
-        ul {
-            list-style-type: none;
-            padding: 0;
-        }
-        li {
-            padding: 10px 0;
-            border-bottom: 1px solid #eee;
-        }
-        .rarity {
-            color: gold;
-            font-weight: bold;
-            margin-left: 8px;
-        }
-        .timestamp {
-            color: #888;
-            font-size: 0.9em;
-        }
-        a {
-            display: inline-block;
-            margin-top: 20px;
-            color: #333;
-            text-decoration: none;
-            background-color: #ddd;
-            padding: 8px 12px;
-            border-radius: 5px;
-        }
-        a:hover {
-            background-color: #bbb;
-        }
-    </style>
-</head>
-<body>
-
+{% extends "_base.html" %}
+{% block content %}
     <div class="profile">
         <h1>{{ user['username'] }}'s Gacha Rolls</h1>
         <p>User ID: {{ user['id'] }}</p>
@@ -72,6 +20,4 @@
     </div>
 
     <a href="{{ url_for('index') }}">← Back to Users</a>
-
-</body>
-</html>
+{% endblock %}
\ No newline at end of file