diff --git a/.env.sample b/.env.sample
index bc9711c..24e1e91 100644
--- a/.env.sample
+++ b/.env.sample
@@ -2,5 +2,5 @@ MODE=local
MONGO_URI=mongodb://:@127.0.0.1:27017/?authSource=admin&retryWrites=true&w=majority
DOMAIN=https://localhost:8001
PORT=8001
-API_VERSION=""
-APP_NAMe="LOCAL"
\ No newline at end of file
+API_VERSION="/api/v1"
+APP_NAME="LOCAL"
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
index ae1cf18..8a7644e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -59,3 +59,6 @@ poetry.lock
*.tmp
*.temp
*.bak
+
+
+assets/images/qr/*
\ No newline at end of file
diff --git a/app/main.py b/app/main.py
index c960eeb..81e3ece 100644
--- a/app/main.py
+++ b/app/main.py
@@ -2,14 +2,18 @@
from contextlib import asynccontextmanager
from pathlib import Path
import logging
-import traceback
import asyncio
from fastapi import FastAPI, Request
-from fastapi.responses import JSONResponse
+
+# from fastapi.responses import JSONResponse
from fastapi.staticfiles import StaticFiles
from starlette.middleware.sessions import SessionMiddleware
+# from fastapi.exceptions import RequestValidationError
+# from starlette.exceptions import HTTPException as StarletteHTTPException
+from fastapi.templating import Jinja2Templates
+
from app.routes import ui_router
from app.utils import db
from app.utils.cache import cleanup_expired
@@ -90,22 +94,36 @@ async def lifespan(app: FastAPI):
app = FastAPI(title="TinyURL", lifespan=lifespan)
app.add_middleware(SessionMiddleware, secret_key=SESSION_SECRET)
+templates = Jinja2Templates(directory="app/templates")
BASE_DIR = Path(__file__).resolve().parent
STATIC_DIR = BASE_DIR / "static"
app.mount("/static", StaticFiles(directory=STATIC_DIR), name="static")
+# QR codes are now served from /qr, which maps to assets/images/qr in the project root
+PROJECT_ROOT = BASE_DIR.parent
+QR_DIR = PROJECT_ROOT / "assets" / "images" / "qr"
+app.mount("/qr", StaticFiles(directory=QR_DIR), name="qr")
# -----------------------------
# Global error handler
# -----------------------------
-@app.exception_handler(Exception)
-async def global_exception_handler(request: Request, exc: Exception):
- traceback.print_exc()
- return JSONResponse(
- status_code=500,
- content={"success": False, "error": "INTERNAL_SERVER_ERROR"},
+# app.exception_handler(Exception)
+# sync def global_exception_handler(request: Request, exc: Exception):
+# traceback.print_exc()
+# return JSONResponse(
+# status_code=500,
+# content={"success": False, "error": "INTERNAL_SERVER_ERROR"},
+# )
+
+
+@app.exception_handler(404)
+async def custom_404_handler(request: Request, exc):
+ return templates.TemplateResponse(
+ "404.html",
+ {"request": request},
+ status_code=404,
)
diff --git a/app/routes.py b/app/routes.py
index 004484f..0386f6b 100644
--- a/app/routes.py
+++ b/app/routes.py
@@ -22,6 +22,7 @@
from fastapi.templating import Jinja2Templates
from pydantic import BaseModel, Field
+
from app import __version__
from app.utils import db
from app.utils.cache import (
@@ -67,10 +68,11 @@ async def index(request: Request):
if qr_enabled and new_short_url and short_code:
qr_data = new_short_url
qr_filename = f"{short_code}.png"
- qr_dir = BASE_DIR / "static" / "qr"
+ PROJECT_ROOT = BASE_DIR.parent # go from app/ β project root
+ qr_dir = PROJECT_ROOT / "assets" / "images" / "qr"
qr_dir.mkdir(parents=True, exist_ok=True)
generate_qr_with_logo(qr_data, str(qr_dir / qr_filename))
- qr_image = f"/static/qr/{qr_filename}"
+ qr_image = f"/qr/{qr_filename}"
recent_urls = db.get_recent_urls(MAX_RECENT_URLS) or get_recent_from_cache(
MAX_RECENT_URLS
@@ -138,6 +140,7 @@ async def create_short_url(
@ui_router.get("/recent", response_class=HTMLResponse)
+@ui_router.get("/history", response_class=HTMLResponse)
async def recent_urls(request: Request):
recent_urls_list = db.get_recent_urls(MAX_RECENT_URLS) or get_recent_from_cache(
MAX_RECENT_URLS
@@ -222,7 +225,8 @@ def redirect_short_ui(short_code: str, background_tasks: BackgroundTasks):
set_cache_pair(short_code, original_url)
return RedirectResponse(original_url)
- return PlainTextResponse("Invalid short URL", status_code=404)
+ # return PlainTextResponse("Invalid short URL", status_code=404)
+ raise HTTPException(status_code=404, detail="Page not found")
@ui_router.delete("/recent/{short_code}")
diff --git a/app/static/css/tiny.css b/app/static/css/tiny.css
index 873f075..fa81205 100644
--- a/app/static/css/tiny.css
+++ b/app/static/css/tiny.css
@@ -16,80 +16,163 @@ body {
background-image: radial-gradient(circle at 50% -20%, #1e1e2e 0%, transparent 50%);
}
-body {
- background: var(--bg);
- color: var(--text-primary);
- font-family: "Inter", system-ui, sans-serif;
- margin: 0;
- overflow-x: hidden;
- background-image: radial-gradient(circle at 50% -20%, #1e1e2e 0%, transparent 50%);
-}
-
/* Light theme overrides */
body.light-theme {
+ /* background + glass */
--bg: #f9fafb;
--glass: rgba(0, 0, 0, 0.03);
--glass-border: rgba(0, 0, 0, 0.07);
- --accent: #2563eb;
+
+ /* main card + text */
+ --card: #ffffff;
--text-primary: #111827;
--text-secondary: #4b5563;
+ --text-color: #111827;
+
+ /* accent */
+ --accent: #2563eb;
- /* Remove or soften the dark gradient */
+ /* Remove the dark radial gradient */
background-image: none;
- /* clean white background */
- /* Or use a subtle light gradient if you prefer */
- /* background-image: radial-gradient(circle at 50% -20%, #e5e7eb 0%, transparent 50%); */
}
/* Layout */
.main-layout {
max-width: 900px;
margin: 0 auto;
- padding: 4rem 1rem;
+ padding: 6rem 1rem 4rem;
display: flex;
flex-direction: column;
gap: 2rem;
}
-.site-header {
+.page {
+ padding-top: 6rem;
+}
+
+.app-header {
+ position: fixed;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 55px;
display: flex;
- justify-content: space-between;
align-items: center;
- padding: 1rem 1.5rem;
+ justify-content: space-between;
+ padding: 0 10px;
+ box-sizing: border-box;
+
background: var(--glass);
border-bottom: 1px solid var(--glass-border);
- backdrop-filter: blur(10px);
+ z-index: 1000;
+}
+
+body.light-theme .app-header {
+ background: #ffffff;
+ /* solid background */
+ border-bottom: 1px solid #e5e7eb;
+ /* clear separation */
+ box-shadow: 0 2px 10px rgba(0, 0, 0, 0.06);
}
.header-left,
.header-right {
display: flex;
- gap: 1rem;
align-items: center;
+ gap: 12px;
}
-.header-center {
- flex: 1;
- text-align: center;
+.app-logo {
+ width: 36px;
+ height: 36px;
+ background: linear-gradient(135deg, #2563eb, #5ab9ff);
+ color: #ffffff;
+ border-radius: 10px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ font-size: 18px;
}
-.logo {
- margin: 0;
+.app-name {
font-size: 1.5rem;
font-weight: 700;
color: var(--text-primary);
}
-.icon-btn {
- background: none;
- border: none;
+.header-nav {
+ display: flex;
+ gap: 26px;
+ margin: 0 auto;
+}
+
+.nav-link,
+.nav-link:link,
+.nav-link:visited {
+ text-decoration: none;
color: var(--text-primary);
- font-size: 1.2rem;
+ font-weight: 500;
+ position: relative;
+}
+
+body.dark-theme .app-header {
+ background: linear-gradient(180deg, #0b1220, #050b14);
+}
+
+.dark-theme .nav-link {
+ color: #e5e7eb;
+}
+
+.nav-link:hover {
+ color: #2563eb;
+}
+
+.nav-link.active::after {
+ content: "";
+ position: absolute;
+ bottom: -6px;
+ left: 0;
+ width: 100%;
+ height: 2px;
+ background: #111827;
+}
+
+.nav-link {
+ position: relative;
+}
+
+.nav-link::after {
+ content: "";
+ position: absolute;
+ left: 0;
+ bottom: -4px;
+ width: 0;
+ height: 2px;
+ background: var(--text-primary);
+ transition: width 0.3s;
+}
+
+.nav-link.active::after {
+ width: 100%;
+}
+
+
+.dark-theme .nav-link.active::after {
+ background: #f8fafc;
+}
+
+.theme-toggle {
+ background: transparent;
+ border: none;
cursor: pointer;
- transition: color 0.3s;
+ padding: 8px;
+ border-radius: 8px;
+ font-weight: 700;
+ background: var(--glass);
+ color: var(--text-primary);
}
-.icon-btn:hover {
+.theme-toggle:hover {
color: var(--accent);
}
@@ -281,17 +364,246 @@ body.light-theme {
font-weight: bold;
}
-.original-url {
+/*.original-url {
color: var(--text-secondary);
font-size: 0.8rem;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
+}*/
+
+
+.hero {
+ text-align: center;
+ margin: 40px 0;
+}
+
+.hero h1 {
+ font-size: 42px;
+ font-weight: 700;
+}
+
+/* ===============================
+ MODERN GLASS RECENT TABLE
+================================= */
+/* PAGE CONTAINER */
+.recent-page-container {
+ width: 100%;
+ max-width: 1200px;
+ /* controls table width */
+ margin: 0 auto;
+ /* centers */
+ padding: 0 24px;
+ /* space left & right */
+ box-sizing: border-box;
+}
+
+/* Wrapper */
+.recent-table-wrapper {
+ width: 100%;
+ /*margin-top: 20px;
+ margin-bottom: 20px;*/
+ overflow-x: auto;
+}
+
+/* ===============================
+ TABLE BASE
+================================= */
+
+.recent-table {
+ width: 100%;
+ border-collapse: collapse;
+ border-radius: 12px;
+ overflow: hidden;
+ table-layout: fixed;
+ min-width: 800px;
+}
+
+/* Header */
+.recent-table thead {
+ background: var(--glass);
+}
+
+.recent-table th {
+ padding: 10px 14px;
+ text-align: left;
+ font-size: 13px;
+ letter-spacing: 0.08em;
+ text-transform: uppercase;
+ font-weight: 700;
+ color: var(--muted);
+ border-bottom: 1px solid var(--glass-border);
+ white-space: nowrap;
+}
+
+/* Body cells */
+.recent-table td {
+ padding: 14px;
+ font-size: 14px;
+ color: var(--text-primary);
+ border-bottom: 1px solid var(--glass-border);
+ vertical-align: middle;
+ transition: 0.25s ease;
+ white-space: nowrap;
+}
+
+/* Row hover */
+.recent-table tbody tr:hover {
+ background: rgba(255, 255, 255, 0.05);
+}
+
+/* ===============================
+ COLUMN WIDTH CONTROL
+================================= */
+
+/* # column */
+.recent-table th:nth-child(1),
+.recent-table td:nth-child(1) {
+ width: 45px;
+ text-align: center;
+ padding-left: 6px;
+ padding-right: 6px;
+}
+
+/* Short URL */
+.recent-table th:nth-child(2),
+.recent-table td:nth-child(2) {
+ width: 170px;
+}
+
+/* Original URL (main space owner) */
+.recent-table th:nth-child(3),
+.recent-table td:nth-child(3) {
+ width: 45%;
+ min-width: 0;
+}
+
+/* Created */
+.recent-table th:nth-child(4),
+.recent-table td:nth-child(4) {
+ width: 170px;
+}
+
+/* Visits */
+.recent-table th:nth-child(5),
+.recent-table td:nth-child(5) {
+ width: 80px;
+ text-align: center;
+ font-weight: 700;
+ color: var(--accent-2);
+}
+
+/* Actions */
+.recent-table th:nth-child(6),
+.recent-table td:nth-child(6) {
+ width: 120px;
+}
+
+/* ===============================
+ LINKS
+================================= */
+
+.short-code a {
+ color: var(--accent);
+ font-weight: 700;
+ text-decoration: none;
+}
+
+.short-code a:hover {
+ color: var(--accent-2);
+ text-decoration: underline;
+}
+
+/* Original URL truncate */
+.original-url {
+ word-break: break-all;
+}
+
+.original-url a {
+ display: block;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ color: var(--text-secondary);
+}
+
+.original-url a:hover {
+ color: var(--accent);
+}
+
+/* Created time */
+.created-time {
+ font-size: 13px;
+ color: var(--muted);
+ white-space: nowrap;
+}
+
+/* ===============================
+ ACTION BUTTONS
+================================= */
+
+.action-col {
+ display: flex;
+ gap: 10px;
+ justify-content: flex-start;
+}
+
+.action-btn {
+ width: 36px;
+ height: 36px;
+ border-radius: 10px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ text-decoration: none;
+ font-size: 16px;
+ transition: 0.2s ease;
+}
+
+.open-btn {
+ background: #3b82f6;
+ color: #fff;
+}
+
+.delete-btn {
+ background: #ef4444;
+ color: #fff;
+}
+
+/* ===============================
+ DARK MODE
+================================= */
+
+.dark-theme .recent-table th,
+.dark-theme .recent-table td {
+ color: #e5e7eb;
+ border-bottom: 1px solid var(--glass-border);
+}
+
+/* Tablet */
+@media (max-width: 1024px) {
+ .recent-page-container {
+ padding: 0 18px;
+ }
+}
+
+/* Mobile */
+@media (max-width: 768px) {
+ .recent-page-container {
+ padding: 0 12px;
+ }
+}
+
+/* Small phones */
+@media (max-width: 480px) {
+ .recent-page-container {
+ padding: 0 8px;
+ }
}
/* Footer */
-.big-footer {
- background: rgba(255, 255, 255, 0.01);
+footer.big-footer {
+ background: var(--bg);
border-top: 1px solid var(--glass-border);
padding: 4rem 1rem 2rem;
margin-top: 4rem;
@@ -372,6 +684,27 @@ body.light-theme {
color: var(--accent);
}
+/* Dark mode footer adjustments */
+body.dark-theme footer.big-footer {
+ background: #020617 !important;
+ border-top: 1px solid rgba(255, 255, 255, 0.06);
+}
+
+body.dark-theme .footer-col h4 {
+ color: #f3f4f6;
+}
+
+body.dark-theme .footer-col p,
+body.dark-theme .footer-col ul li a,
+body.dark-theme .footer-bottom {
+ color: #cbd5e1;
+}
+
+body.dark-theme .footer-col ul li a:hover,
+body.dark-theme .footer-bottom a {
+ color: #a5f3fc;
+}
+
/* Responsive adjustments */
@media (max-width: 900px) {
.footer-grid {
@@ -413,3 +746,47 @@ body.light-theme {
text-align: center;
}
}
+
+
+/* ===============================
+ HOME PAGE FIX β LONG URL WRAP
+ (does NOT affect table)
+================================= */
+/*.recent-tray .recent-item .original-url,
+.recent-tray .recent-item .original-url a {
+ white-space: normal !important;
+ word-break: break-word !important;
+ overflow-wrap: anywhere !important;
+ line-break: anywhere !important;
+ display: block;
+}
+
+.recent-tray .recent-item {
+ max-width: 20px;
+}*/
+
+
+/* allow wrapping */
+.recent-tray .recent-item .original-url,
+.recent-tray .recent-item .original-url a {
+ display: -webkit-box;
+ -webkit-box-orient: vertical;
+
+ -webkit-line-clamp: 3;
+ /* β change 2 or 3 lines here */
+ line-clamp: 3;
+
+ overflow: hidden;
+ text-overflow: ellipsis;
+
+ white-space: normal;
+ word-break: break-word;
+ overflow-wrap: anywhere;
+}
+
+/* IMPORTANT β remove width restriction */
+.recent-tray .recent-item {
+ min-width: 0;
+ /* allows shrinking inside flex/grid */
+ max-width: 100%;
+}
\ No newline at end of file
diff --git a/app/static/style.css b/app/static/style.css
index b754687..8dd7671 100644
--- a/app/static/style.css
+++ b/app/static/style.css
@@ -1,815 +1,1063 @@
-html,
-body {
- height: 100%;
- margin: 0;
- font-family: Arial;
- padding: 0;
- font-family: "Poppins", system-ui, Arial, sans-serif;
- background: var(--bg);
- background-size: cover;
- background-position: center;
- background-size: cover;
- background-position: center;
-}
-input {
- width: 70%;
- margin-top: 2px;
- margin-bottom: 2px;
- font-size: 16px;
-}
-.admin-box {
- margin: 120px auto 60px;
- /* space from header + footer */
-}
-.app-layout {
- min-height: 100vh;
- display: flex;
- flex-direction: column;
- margin-top: var(--header-height);
-}
-button {
- padding: 8px;
- margin: 5px;
-}
-.error-box {
- margin-bottom: 15px;
- padding: 10px;
- color: #ff4d4d;
- border-radius: 8px;
- font-weight: 600;
-}
-
-.dark-theme h1 {
- background: linear-gradient(90deg, #ffffff, #dddddd, #ffffff);
- -webkit-background-clip: text;
- background-clip: text;
- -webkit-text-fill-color: transparent;
- text-shadow: 0px 0px 10px rgba(255, 255, 255, 0.4);
-}
-
-.dark-theme p {
- background: linear-gradient(90deg, #ffffff, #dddddd, #ffffff);
- -webkit-background-clip: text;
- background-clip: text;
- -webkit-text-fill-color: transparent;
- text-shadow: 0px 0px 10px rgba(255, 255, 255, 0.4);
-}
-.dark-theme {
- --bg-overlay: rgba(0, 0, 0, 0.75);
- --glass-bg: rgba(0, 0, 0, 0.4);
- --text-color: #fff;
- --input-bg: rgba(50, 50, 50, 0.8);
- --input-text-color: #fff;
-}
-
-@keyframes pop {
- 0% {
- transform: scale(0.7);
- opacity: 0;
- }
- 100% {
- transform: scale(1);
- opacity: 1;
- }
-}
-/* INPUT CONTAINER */
-.input-field {
- flex: 1 1 700px;
- display: flex;
- align-items: center;
- gap: 12px;
- border-radius: 12px;
- border: 2px solid rgb(6, 0, 0);
- background: transparent; /* IMPORTANT */
- padding: 12px 12px;
-}
-.dark-theme .input-field {
- border-color: #ffffff;
-}
-/* INPUT ITSELF */
-.input-field input[type="text"] {
- width: 100%;
- border: none;
- outline: none;
- background-color: transparent !important;
- background-image: none !important;
- box-shadow: none !important;
- font-size: 23px;
-}
-
-.input-field input {
- color: #000 !important;
-}
-
-.dark-theme .input-field input {
- color: #fff !important;
-}
-
-.input-field input:-webkit-autofill,
-.input-field input:-webkit-autofill:hover,
-.input-field input:-webkit-autofill:focus,
-.input-field input:-webkit-autofill:active {
- -webkit-box-shadow: 0 0 0 1000px transparent inset !important;
- box-shadow: 0 0 0 1000px transparent inset !important;
- background-color: transparent !important;
- background-image: none !important;
- transition: background-color 9999s ease-in-out 0s;
-}
-
-.input-field input:-webkit-autofill {
- -webkit-text-fill-color: #000 !important;
-}
-
-.dark-theme .input-field input:-webkit-autofill {
- -webkit-text-fill-color: #fff !important;
-}
-.input-field input::selection,
-.input-field input::-moz-selection {
- background: transparent;
- color: inherit;
-}
-.short-code {
- color: #0a0000; /* blue like links */
- font-weight: 700;
-}
-
-.app-header {
- position: fixed;
- top: 0;
- left: 0;
- width: 97%;
- height: 55px;
- background: white;
- display: flex;
- align-items: center;
- padding: 0 28px;
- box-shadow: 0 2px 10px rgba(0, 0, 0, 0.08);
- z-index: 1000;
-}
-
-/* Dark mode */
-.dark-theme .app-header {
- background: linear-gradient(180deg, #0b1220, #050b14);
-}
-
-footer {
- margin-top: 0;
-}
-
-body.dark-theme,
-body.dark-theme .page,
-body.dark-theme main,
-body.dark-theme section {
- background: #0f1720 !important;
-}
-
-.header-left {
- display: flex;
- align-items: center;
- gap: 12px;
-}
-
-.app-logo {
- width: 36px;
- height: 36px;
- background: linear-gradient(135deg, #2563eb, #5ab9ff);
- color: white;
- border-radius: 10px;
- display: flex;
- align-items: center;
- justify-content: center;
- font-size: 18px;
-}
-
-.app-name {
- font-size: 20px;
- font-weight: 700;
- color: #111827;
-}
-
-.dark-theme .app-name {
- color: #f8fafc;
-}
-
-.header-nav {
- position: absolute;
- left: 50%;
- transform: translateX(-50%);
- display: flex;
- gap: 26px;
-}
-
-.nav-link {
- text-decoration: none;
- color: #111827;
- font-weight: 500;
- position: relative;
-}
-
-.dark-theme .nav-link {
- color: #e5e7eb;
-}
-
-.nav-link:hover {
- color: #2563eb;
-}
-
-.nav-link.active::after {
- content: "";
- position: absolute;
- bottom: -6px;
- left: 0;
- width: 100%;
- height: 2px;
- background: #111827;
-}
-
-.dark-theme .nav-link.active::after {
- background: #f8fafc;
-}
-
-.header-right {
- margin-left: auto;
- display: flex;
- align-items: center;
-}
-
-:root {
- --header-height: 55px;
- --bg: #eefaf8;
- --card: rgba(255, 255, 255, 0.95);
- --muted: #7b8b8a;
- --accent-1: #5ab9ff;
- --accent-2: #4cb39f;
- --accent-grad: linear-gradient(90deg, #4cb39f, #5ab9ff);
- --success: #2fb06e;
- --glass: rgba(255, 255, 255, 0.85);
-}
-
-.dark-theme {
- --bg-overlay: rgba(0, 0, 0, 0.75);
- --glass-bg: rgba(0, 0, 0, 0.4);
- --text-color: #f3f3f3;
- --input-bg: rgba(11, 10, 10, 0.8);
- --button-bg: linear-gradient(90deg, #4444ff, #2266ff);
- --recent-bg: rgba(255, 255, 255, 0.1);
-}
-
-/* Preserve your dark theme variables too */
-body.dark-theme {
- --bg: #0f1720;
- --card: rgba(10, 14, 18, 0.92);
- --muted: #9aa7a6;
-}
-
-.page {
- flex: 1;
- display: flex;
- flex-direction: column;
- align-items: center;
- gap: 1rem;
- padding: 2rem;
- min-height: 80vh;
-}
-
-.theme-toggle {
- background: transparent;
- border: none;
- cursor: pointer;
- padding: 8px;
- border-radius: 8px;
- font-weight: 700;
- background: var(--card);
-}
-
-/* Hero */
-.hero {
- width: 100%;
- max-width: 1100px;
- background: transparent;
- text-align: center;
- padding: 10px;
-}
-
-.hero h1 {
- margin: 10px 0 14px;
- font-size: 36px;
- line-height: 1.05;
- color: #000606;
-}
-
-.hero p {
- margin: var(--bg-overlay);
- color: var(--muted);
- max-width: 820px;
- margin-left: auto;
- margin-right: auto;
- color: #000606;
-}
-
-/* Main card & input */
-.card {
- width: 100%;
- max-width: 1100px;
- background: var(--card);
- border-radius: 14px;
- padding: 15px;
- box-shadow: 0 18px 50px rgba(8, 24, 24, 0.06);
-}
-
-.cta {
- min-width: 220px;
- padding: 14px 22px;
- border-radius: 12px;
- border: none;
- color: rgb(12, 1, 1);
- font-weight: 700;
- cursor: pointer;
- background: var(--accent-grad);
- box-shadow: 0 12px 28px rgba(77, 163, 185, 0.12);
-}
-
-.small-action {
- display: flex;
- align-items: center;
- gap: 8px;
- color: var(--muted);
- margin-top: 10px;
-}
-
-.result {
- margin-top: 26px;
- background: white;
- border-radius: 12px;
- padding: 20px;
- border: 1px solid rgba(22, 60, 55, 0.03);
- box-shadow: 0 8px 28px rgba(7, 20, 20, 0.03);
-}
-
-.result-header {
- display: flex;
- align-items: center;
- gap: 12px;
- margin-bottom: 12px;
-}
-
-.result-header .dot {
- width: 30px;
- height: 30px;
- background: var(--success);
- border-radius: 50%;
- display: flex;
- align-items: center;
- justify-content: center;
- color: white;
- font-weight: 700;
-}
-
-.short-actions {
- display: flex;
- justify-content: center;
- align-items: center;
- gap: 8px;
- padding: 10px 14px;
- border-radius: 12px;
- background: linear-gradient(180deg, rgba(75, 194, 176, 0.06), rgba(94, 207, 255, 0.04));
-}
-
-.short-box input {
- align-items: center;
- padding: 10px;
- font-size: 15px;
-}
-
-.btn-copy {
- border: none;
- padding: 10px 14px;
- border-radius: 8px;
- color: white;
- font-weight: 700;
- cursor: pointer;
-}
-
-.btn-share {
- background: #f2f5f5;
- border: none;
- padding: 10px 14px;
- border-radius: 8px;
- color: #0b2b2a;
- font-weight: 700;
- cursor: pointer;
- margin-left: 6px;
-}
-
-.meta-row {
- align-items: center;
- justify-content: center;
- display: grid;
- grid-template-columns: 1fr 1fr;
- gap: 2px;
- padding: 16px;
- margin-top: 1px;
- align-items: top;
- color: black;
-}
-.result-body {
- margin-top: 30px;
-
- display: flex;
- flex-direction: column;
- align-items: center;
- text-align: center;
-}
-
-.qr-block {
- text-align: center;
- padding-top: 8px;
-}
-
-.qr-block img {
- height: 15rem;
- align-items: center;
- aspect-ratio: 1;
- box-shadow: 0 10px 20px rgba(10, 20, 30, 0.06);
- outline: 2px solid green;
- outline-offset: 4px;
-}
-
-.download-qr {
- display: inline-block;
- margin-top: 12px;
- text-decoration: none;
- color: var(--accent-1);
- font-weight: 700;
-}
-
-.action-row {
- display: flex;
- justify-content: right;
- align-items: right;
-}
-
-.action-secondary {
- background: #f6fbfb;
- border: 1px solid rgba(0, 0, 0, 0.03);
- border-radius: 10px;
- cursor: pointer;
- font-weight: 700;
-}
-
-/* Force Generate QR to stay on one line */
-.qr-inline {
- display: inline-flex;
- align-items: center;
- gap: 8px;
- white-space: nowrap;
-}
-
-.qr-inline input {
- margin: 0;
-}
-
-/* Responsive */
-@media (max-width: 880px) {
- .input-row {
- flex-direction: column;
- }
-
- .cta {
- width: 100%;
- }
-
- .meta-row {
- grid-template-columns: 1fr;
- }
-}
-.result-title {
- font-weight: 700;
- color: #0e34f6;
-}
-
-.dark-theme .result-title {
- color: #150cff;
-}
-
-footer {
- min-height: auto;
-}
-
-.app-footer {
- background: white;
- color: #e5e7eb;
- padding: 8px 10px;
- margin-top: auto;
- position: relative;
-}
-.dark-theme .app-footer {
- background: linear-gradient(180deg, #0b1220, #050b14);
-}
-
-.footer-container {
- margin: auto;
- display: flex;
- gap: 60px;
- justify-content: space-between;
- flex-wrap: wrap;
-}
-
-.footer-brand {
- max-width: 420px;
-}
-
-.footer-logo {
- width: 42px;
- height: 42px;
- background: linear-gradient(135deg, #2563eb, #5ab9ff);
- border-radius: 14px;
- display: flex;
- align-items: center;
- justify-content: center;
- font-size: 22px;
-}
-.dark-theme .footer-brand h3,
-.dark-theme .footer-brand p,
-.dark-theme .footer-col h4,
-.dark-theme .app-footer a,
-.dark-theme .footer-bottom {
- color: #f8fafc;
-}
-
-.footer-brand h3 {
- margin: 0;
- color: #000000;
- font-size: 22px;
- font-weight: 700;
-}
-
-.footer-brand p {
- margin-top: 8px;
- color: #000000;
- line-height: 1.6;
- font-size: 14px;
-}
-
-/* MAIN CONTENT */
-
-/* FOOTER */
-.app-footer {
- margin-top: auto;
-}
-
-/* GitHub button */
-.github-btn {
- display: inline-flex;
- align-items: center;
- gap: 2px;
- margin-top: 1px;
- padding: 10px 16px;
- border-radius: 8px;
- background: rgba(255, 255, 255, 0.06);
- color: #000000;
- text-decoration: none;
- font-weight: 600;
- transition: all 0.25s ease;
-}
-
-.github-btn:hover {
- background: black(11, 1, 1);
- transform: translateY(-2px);
-}
-
-.footer-links {
- display: flex;
- gap: 80px;
- flex-wrap: wrap;
-}
-
-.footer-col h4 {
- margin-bottom: 14px;
- font-size: 16px;
- color: #000000;
- font-weight: 700;
-}
-
-.footer-col a {
- display: block;
- text-decoration: none;
- color: #000000;
- margin-bottom: 10px;
- font-size: 14px;
- transition: color 0.2s ease;
-}
-
-.footer-col a:hover {
- text-decoration: underline;
-}
-
-/* Bottom */
-.footer-bottom {
- margin-top: 10px;
- border-top: 1px solid rgba(255, 255, 255, 0.153);
- padding-top: 8px;
- padding-bottom: 1px;
- text-align: center;
- font-size: 14px;
- color: #080808;
-}
-.footer-bottom a {
- color: #030000;
- font-weight: 600;
- text-decoration: none;
-}
-
-.footer-bottom a:hover {
- text-decoration: underline;
-}
-
-/* Responsive */
-@media (max-width: 768px) {
- .footer-container {
- flex-direction: column;
- gap: 40px;
- }
-
- .footer-links {
- gap: 40px;
- }
-}
-/* REMOVE white line above footer in dark mode */
-footer {
- margin-top: 0 !important;
-}
-.recent-table-wrapper {
- margin-top: 20px;
- width: 100%;
- overflow-x: auto;
-}
-
-.recent-table {
- width: 100%;
- border-collapse: collapse;
- border-radius: 12px;
- overflow: hidden;
-}
-
-.recent-table thead {
- background: rgb(0, 0, 0);
-}
-.recent-table th {
- color: rgb(0, 0, 0);
- padding: 8px 14px;
- text-align: left;
- font-size: 16px;
-}
-.short-code a {
- color: #2563eb;
- font-weight: 600;
- text-decoration: none;
-}
-
-.short-code a:hover {
- color: #1d4ed8;
- text-decoration: underline;
-}
-.recent-table td {
- color: rgb(34, 48, 77);
- padding: 10px 14px;
- text-align: left;
- font-size: 14px;
-}
-
-.created-time {
- font-size: 14px;
- color: #374151;
- white-space: nowrap;
-}
-
-.time-ago {
- color: #374151;
- font-size: 13px;
- margin-left: 2px;
-}
-.recent-table th {
- font-weight: 700;
-}
-
-.recent-table tbody tr,
-th {
- background: rgb(255, 255, 255);
- border-bottom: 1px solid rgb(0, 0, 0);
-}
-.dark-theme.recent-table tbody tr,
-td {
- background: rgba(255, 255, 255, 0.04);
- border-bottom: 1px solid rgb(0, 0, 0);
-}
-.recent-table tbody tr:hover {
- background: rgb(196, 196, 196);
-}
-
-/* Short code */
-.short-code {
- font-weight: 700;
-}
-
-.original-url {
- color: #22c55e;
- word-break: break-all;
-}
-
-/* Action buttons */
-.action-col {
- display: flex;
- gap: 10px;
-}
-
-.action-btn {
- width: 36px;
- height: 36px;
- border-radius: 10px;
- display: flex;
- align-items: center;
- justify-content: center;
- text-decoration: none;
- font-size: 16px;
- transition: 0.2s ease;
-}
-
-.open-btn {
- background: #3b82f6;
- color: #fff;
-}
-
-.delete-btn {
- background: #ef4444;
- color: #fff;
-}
-
-.recent-table-wrapper {
- margin-bottom: 20px;
-}
-/* =========================
- Coming Soon Page
-========================= */
-
-.coming-soon-page {
- display: flex;
- align-items: center;
- justify-content: center;
- padding: 120px 20px 60px;
-}
-
-.coming-soon-card {
- max-width: 520px;
- width: 100%;
- background: var(--card);
- border-radius: 16px;
- padding: 50px 40px;
- text-align: center;
- box-shadow: 0 20px 50px rgba(0, 0, 0, 0.08);
-}
-
-.coming-icon {
- font-size: 48px;
- margin-bottom: 18px;
-}
-
-.coming-soon-card h1 {
- font-size: 34px;
- margin-bottom: 14px;
- color: #000;
-}
-
-.dark-theme .coming-soon-card h1 {
- color: #fff;
-}
-
-.coming-soon-card p {
- font-size: 15px;
- color: var(--muted);
- line-height: 1.6;
- margin-bottom: 28px;
-}
-
-.coming-btn {
- display: inline-block;
- padding: 12px 22px;
- border-radius: 10px;
- background: var(--accent-grad);
- color: #fff;
- font-weight: 700;
- text-decoration: none;
- transition: 0.25s ease;
-}
-
-.coming-btn:hover {
- transform: scale(1.05);
- box-shadow: 0 12px 28px rgba(77, 163, 185, 0.25);
-}
-.info-box {
- margin-bottom: 15px;
- padding: 10px;
- color: #0e34f6;
- border-radius: 8px;
- font-weight: 700;
-}
+html,
+body {
+ height: 100%;
+ margin: 0;
+ font-family: Arial;
+ padding: 0;
+ font-family: "Poppins", system-ui, Arial, sans-serif;
+ background: var(--bg);
+ background-size: cover;
+ background-position: center;
+ background-size: cover;
+ background-position: center;
+}
+
+input {
+ width: 70%;
+ margin-top: 2px;
+ margin-bottom: 2px;
+ font-size: 16px;
+}
+
+.admin-box {
+ margin: 120px auto 60px;
+ /* space from header + footer */
+}
+
+.app-layout {
+ min-height: 100vh;
+ display: flex;
+ flex-direction: column;
+ margin-top: var(--header-height);
+}
+
+button {
+ padding: 8px;
+ margin: 5px;
+}
+
+.error-box {
+ margin-bottom: 15px;
+ padding: 10px;
+ color: #ff4d4d;
+ border-radius: 8px;
+ font-weight: 600;
+}
+
+.dark-theme h1 {
+ background: linear-gradient(90deg, #ffffff, #dddddd, #ffffff);
+ -webkit-background-clip: text;
+ background-clip: text;
+ -webkit-text-fill-color: transparent;
+ text-shadow: 0px 0px 10px rgba(255, 255, 255, 0.4);
+}
+
+.dark-theme p {
+ background: linear-gradient(90deg, #ffffff, #dddddd, #ffffff);
+ -webkit-background-clip: text;
+ background-clip: text;
+ -webkit-text-fill-color: transparent;
+ text-shadow: 0px 0px 10px rgba(255, 255, 255, 0.4);
+}
+
+.dark-theme {
+ --bg-overlay: rgba(0, 0, 0, 0.75);
+ --glass-bg: rgba(0, 0, 0, 0.4);
+ --text-color: #fff;
+ --input-bg: rgba(50, 50, 50, 0.8);
+ --input-text-color: #fff;
+}
+
+@keyframes pop {
+ 0% {
+ transform: scale(0.7);
+ opacity: 0;
+ }
+
+ 100% {
+ transform: scale(1);
+ opacity: 1;
+ }
+}
+
+/* INPUT CONTAINER */
+.input-field {
+ flex: 1 1 700px;
+ display: flex;
+ align-items: center;
+ gap: 12px;
+ border-radius: 12px;
+ border: 2px solid rgb(6, 0, 0);
+ background: transparent;
+ /* IMPORTANT */
+ padding: 12px 12px;
+}
+
+.dark-theme .input-field {
+ border-color: #ffffff;
+}
+
+/* INPUT ITSELF */
+.input-field input[type="text"] {
+ width: 100%;
+ border: none;
+ outline: none;
+ background-color: transparent !important;
+ background-image: none !important;
+ box-shadow: none !important;
+ font-size: 23px;
+}
+
+.input-field input {
+ color: #000 !important;
+}
+
+.dark-theme .input-field input {
+ color: #fff !important;
+}
+
+.input-field input:-webkit-autofill,
+.input-field input:-webkit-autofill:hover,
+.input-field input:-webkit-autofill:focus,
+.input-field input:-webkit-autofill:active {
+ -webkit-box-shadow: 0 0 0 1000px transparent inset !important;
+ box-shadow: 0 0 0 1000px transparent inset !important;
+ background-color: transparent !important;
+ background-image: none !important;
+ transition: background-color 9999s ease-in-out 0s;
+}
+
+.input-field input:-webkit-autofill {
+ -webkit-text-fill-color: #000 !important;
+}
+
+.dark-theme .input-field input:-webkit-autofill {
+ -webkit-text-fill-color: #fff !important;
+}
+
+.input-field input::selection,
+.input-field input::-moz-selection {
+ background: transparent;
+ color: inherit;
+}
+
+.short-code {
+ color: #0a0000;
+ /* blue like links */
+ font-weight: 700;
+}
+
+footer {
+ margin-top: 0;
+}
+
+body.dark-theme,
+body.dark-theme .page,
+body.dark-theme main,
+body.dark-theme section {
+ background: #0f1720 !important;
+}
+
+/*:root {
+ --header-height: 55px;
+ --bg: #eefaf8;
+ --card: rgba(255, 255, 255, 0.95);
+ --muted: #7b8b8a;
+ --accent-1: #5ab9ff;
+ --accent-2: #4cb39f;
+ --accent-grad: linear-gradient(90deg, #4cb39f, #5ab9ff);
+ --success: #2fb06e;
+ --glass: rgba(255, 255, 255, 0.85);
+}*/
+
+:root {
+ /* Background */
+ --bg: #eefaf8;
+ --card: rgba(255, 255, 255, 0.85);
+
+ /* Text */
+ --text-color: #1f2937;
+ --text-muted: #6b7280;
+
+ /* Borders */
+ --glass-border: rgba(0, 0, 0, 0.08);
+
+ /* Accent */
+ --accent-1: #5ab9ff;
+ --accent-2: #4cb39f;
+
+ /* Shadow */
+ --card-shadow: 0 20px 60px rgba(0, 0, 0, 0.12);
+ --text-primary: var(--text-color);
+ --text-secondary: var(--text-muted);
+ --accent: var(--accent-1);
+}
+
+.dark-theme {
+ --bg-overlay: rgba(0, 0, 0, 0.75);
+ --glass-bg: rgba(0, 0, 0, 0.4);
+ --text-color: #f3f3f3;
+ --input-bg: rgba(11, 10, 10, 0.8);
+ --button-bg: linear-gradient(90deg, #4444ff, #2266ff);
+ --recent-bg: rgba(255, 255, 255, 0.1);
+}
+
+/* Preserve your dark theme variables too */
+body.dark-theme {
+ --bg: #0f1720;
+ --card: rgba(20, 25, 30, 0.75);
+
+ --text-color: #e5e7eb;
+ --text-muted: #9aa7a6;
+
+ --glass-border: rgba(255, 255, 255, 0.08);
+
+ --card-shadow: 0 20px 60px rgba(0, 0, 0, 0.6);
+}
+
+.page {
+ flex: 1;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ gap: 1rem;
+ padding: 2rem;
+ min-height: 80vh;
+}
+
+.theme-toggle {
+ background: transparent;
+ border: none;
+ cursor: pointer;
+ padding: 8px;
+ border-radius: 8px;
+ font-weight: 700;
+ background: var(--card);
+}
+
+/* Hero */
+.hero {
+ width: 100%;
+ max-width: 1100px;
+ background: transparent;
+ text-align: center;
+ padding: 10px;
+}
+
+.hero h1 {
+ margin: 10px 0 14px;
+ font-size: 36px;
+ line-height: 1.05;
+ color: #000606;
+}
+
+.hero p {
+ margin: var(--bg-overlay);
+ color: var(--muted);
+ max-width: 820px;
+ margin-left: auto;
+ margin-right: auto;
+ color: #000606;
+}
+
+/* Main card & input */
+.card {
+ width: 100%;
+ max-width: 1100px;
+ background: var(--card);
+ border-radius: 14px;
+ padding: 15px;
+ box-shadow: 0 18px 50px rgba(8, 24, 24, 0.06);
+}
+
+.cta {
+ min-width: 220px;
+ padding: 14px 22px;
+ border-radius: 12px;
+ border: none;
+ color: rgb(12, 1, 1);
+ font-weight: 700;
+ cursor: pointer;
+ background: var(--accent-grad);
+ box-shadow: 0 12px 28px rgba(77, 163, 185, 0.12);
+}
+
+.small-action {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ color: var(--muted);
+ margin-top: 10px;
+}
+
+.result {
+ margin-top: 26px;
+ background: white;
+ border-radius: 12px;
+ padding: 20px;
+ border: 1px solid rgba(22, 60, 55, 0.03);
+ box-shadow: 0 8px 28px rgba(7, 20, 20, 0.03);
+}
+
+.result-header {
+ display: flex;
+ align-items: center;
+ gap: 12px;
+ margin-bottom: 12px;
+}
+
+.result-header .dot {
+ width: 30px;
+ height: 30px;
+ background: var(--success);
+ border-radius: 50%;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ color: white;
+ font-weight: 700;
+}
+
+.short-actions {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ gap: 8px;
+ padding: 10px 14px;
+ border-radius: 12px;
+ background: linear-gradient(180deg, rgba(75, 194, 176, 0.06), rgba(94, 207, 255, 0.04));
+}
+
+.short-box input {
+ align-items: center;
+ padding: 10px;
+ font-size: 15px;
+}
+
+.btn-copy {
+ border: none;
+ padding: 10px 14px;
+ border-radius: 8px;
+ color: white;
+ font-weight: 700;
+ cursor: pointer;
+}
+
+.btn-share {
+ background: #f2f5f5;
+ border: none;
+ padding: 10px 14px;
+ border-radius: 8px;
+ color: #0b2b2a;
+ font-weight: 700;
+ cursor: pointer;
+ margin-left: 6px;
+}
+
+.meta-row {
+ align-items: center;
+ justify-content: center;
+ display: grid;
+ grid-template-columns: 1fr 1fr;
+ gap: 2px;
+ padding: 16px;
+ margin-top: 1px;
+ align-items: top;
+ color: black;
+}
+
+.result-body {
+ margin-top: 30px;
+
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ text-align: center;
+}
+
+.qr-block {
+ text-align: center;
+ padding-top: 8px;
+}
+
+.qr-block img {
+ height: 15rem;
+ align-items: center;
+ aspect-ratio: 1;
+ box-shadow: 0 10px 20px rgba(10, 20, 30, 0.06);
+ outline: 2px solid green;
+ outline-offset: 4px;
+}
+
+.download-qr {
+ display: inline-block;
+ margin-top: 12px;
+ text-decoration: none;
+ color: var(--accent-1);
+ font-weight: 700;
+}
+
+.action-row {
+ display: flex;
+ justify-content: right;
+ align-items: right;
+}
+
+.action-secondary {
+ background: #f6fbfb;
+ border: 1px solid rgba(0, 0, 0, 0.03);
+ border-radius: 10px;
+ cursor: pointer;
+ font-weight: 700;
+}
+
+/* Force Generate QR to stay on one line */
+.qr-inline {
+ display: inline-flex;
+ align-items: center;
+ gap: 8px;
+ white-space: nowrap;
+}
+
+.qr-inline input {
+ margin: 0;
+}
+
+/* Responsive */
+@media (max-width: 880px) {
+ .input-row {
+ flex-direction: column;
+ }
+
+ .cta {
+ width: 100%;
+ }
+
+ .meta-row {
+ grid-template-columns: 1fr;
+ }
+}
+
+.result-title {
+ font-weight: 700;
+ color: #0e34f6;
+}
+
+.dark-theme .result-title {
+ color: #150cff;
+}
+
+footer {
+ min-height: auto;
+}
+
+/* /* ===============================
+ MODERN UI STYLE FOOTER (VISIT PAGE)
+================================= */
+
+.app-footer {
+ background: rgba(255, 255, 255, 0.02);
+ backdrop-filter: blur(16px);
+ border-top: 1px solid var(--glass-border);
+ padding: 2.5rem 1rem 1.2rem;
+ /* reduced space */
+ margin-top: 40px;
+}
+
+/* Container */
+.footer-container {
+ max-width: 1100px;
+ margin: 0 auto;
+
+ display: grid;
+ grid-template-columns: 2fr 1fr 1fr 1fr;
+ gap: 1.8rem;
+}
+
+/* Footer columns */
+.footer-col h4 {
+ font-size: 14px;
+ font-weight: 700;
+ letter-spacing: 0.08em;
+ text-transform: uppercase;
+ margin-bottom: 16px;
+ color: var(--text-primary);
+}
+
+.footer-col p {
+ color: var(--text-secondary);
+ font-size: 14px;
+ line-height: 1.6;
+}
+
+.footer-col ul {
+ list-style: none;
+ padding: 0;
+ margin: 0;
+}
+
+.footer-col ul li {
+ margin-bottom: 10px;
+}
+
+.footer-col ul li a {
+ color: var(--text-secondary);
+ text-decoration: none;
+ font-size: 14px;
+ transition: 0.2s ease;
+}
+
+.footer-col ul li a:hover {
+ color: var(--accent);
+}
+
+/* Footer bottom */
+.footer-bottom {
+ /* margin: 3rem auto 0;
+ padding-top: 20px;
+
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+
+ border-top: 1px solid var(--glass-border);
+ font-size: 14px;
+ color: var(--text-secondary); */
+
+ max-width: 1200px;
+ margin: 2rem auto 0;
+ padding-top: 1rem;
+ border-top: 1px solid var(--glass-border);
+ display: flex;
+ flex-wrap: wrap;
+ justify-content: space-between;
+ align-items: center;
+ color: var(--text-secondary);
+ font-size: 0.8rem;
+
+}
+
+/* Version + GitHub area */
+.footer-bottom a {
+ color: var(--accent);
+ text-decoration: none;
+ transition: 0.2s ease;
+}
+
+.footer-bottom a:hover {
+ opacity: 0.8;
+}
+
+/* ===============================
+ DARK MODE SUPPORT
+================================= */
+
+.dark-theme .app-footer {
+ background: #0a0a0c;
+ backdrop-filter: blur(16px);
+ border-top: 1px solid rgba(255, 255, 255, 0.06);
+}
+
+.dark-theme .footer-col h4 {
+ color: #f3f4f6;
+}
+
+.dark-theme .footer-col p,
+.dark-theme .footer-col ul li a,
+.dark-theme .footer-bottom {
+ color: #cbd5e1;
+}
+
+.dark-theme .footer-col ul li a:hover,
+.dark-theme .footer-bottom a {
+ color: var(--accent-2);
+}
+
+/* ===============================
+ MOBILE RESPONSIVE
+================================= */
+
+@media (max-width: 900px) {
+ .footer-container {
+ grid-template-columns: 1fr 1fr;
+ }
+}
+
+@media (max-width: 600px) {
+ .footer-container {
+ grid-template-columns: 1fr;
+ }
+
+ .footer-bottom {
+ flex-direction: column;
+ gap: 10px;
+ text-align: center;
+ }
+}
+
+/* REMOVE white line above footer in dark mode */
+footer {
+ margin-top: 0 !important;
+}
+
+*/
+/* =====================================
+ BIG FOOTER STYLE (FOR FIRST PAGE)
+ Using existing class names
+===================================== */
+
+/*Footer wrapper
+.app-footer {
+ background: rgba(255, 255, 255, 0.01);
+ border-top: 1px solid var(--glass-border);
+ padding: 4rem 1rem 2rem;
+ margin-top: 4rem;
+}
+
+/* Grid container */
+.footer-container {
+ max-width: 1200px;
+ margin: 0 auto;
+
+ display: grid;
+ grid-template-columns: 2fr 1fr 1fr 1fr;
+ gap: 2rem;
+}
+
+/* Brand column (first column) */
+.footer-container>div:first-child h4 {
+ font-size: 1.5rem;
+ margin-bottom: 1rem;
+}
+
+.footer-container>div:first-child p {
+ color: var(--text-secondary);
+ line-height: 1.6;
+ max-width: 320px;
+}
+
+.footer-brand h3 {
+ font-size: 1.5rem;
+ margin-bottom: 1rem;
+}
+
+.footer-brand p {
+ color: var(--text-secondary);
+ line-height: 1.6;
+ max-width: 320px;
+}
+
+/* Other footer columns */
+.footer-col h4 {
+ font-size: 0.85rem;
+ text-transform: uppercase;
+ letter-spacing: 0.1em;
+ margin-bottom: 1rem;
+ color: var(--text-primary);
+}
+
+.footer-col ul {
+ list-style: none;
+ padding: 0;
+ margin: 0;
+}
+
+.footer-col ul li {
+ margin-bottom: 0.8rem;
+}
+
+.footer-col ul li a {
+ color: var(--text-secondary);
+ text-decoration: none;
+ font-size: 0.9rem;
+ transition: color 0.2s ease;
+}
+
+.footer-col ul li a:hover {
+ color: var(--accent);
+}
+
+/* Bottom row */
+.footer-bottom {
+ max-width: 1200px;
+ margin: 2rem auto 0;
+ padding-top: 1rem;
+ border-top: 1px solid var(--glass-border);
+
+ display: flex;
+ flex-wrap: wrap;
+ justify-content: space-between;
+ align-items: center;
+
+ color: var(--text-secondary);
+ font-size: 0.8rem;
+}
+
+/* Footer links inside bottom */
+.footer-bottom a {
+ color: inherit;
+ text-decoration: none;
+ transition: color 0.2s ease;
+}
+
+.footer-bottom a:hover {
+ color: var(--accent);
+}
+
+/* Responsive */
+@media (max-width: 900px) {
+ .footer-container {
+ grid-template-columns: 1fr 1fr;
+ }
+}
+
+@media (max-width: 600px) {
+ .footer-container {
+ grid-template-columns: 1fr;
+ }
+
+ .footer-bottom {
+ flex-direction: column;
+ gap: 1rem;
+ text-align: center;
+ }
+}
+
+*/
+
+/* Footer */
+.big-footer {
+ background: rgba(255, 255, 255, 0.01);
+ border-top: 1px solid var(--glass-border);
+ padding: 4rem 1rem 2rem;
+ margin-top: 4rem;
+}
+
+.footer-grid {
+ max-width: 1200px;
+ margin: 0 auto;
+ display: grid;
+ grid-template-columns: 2fr 1fr 1fr 1fr;
+ gap: 2rem;
+}
+
+.footer-brand h3 {
+ font-size: 1.5rem;
+ margin-bottom: 1rem;
+}
+
+.footer-brand p {
+ color: var(--text-secondary);
+ line-height: 1.6;
+ max-width: 320px;
+}
+
+.footer-col h4 {
+ font-size: 0.85rem;
+ text-transform: uppercase;
+ letter-spacing: 0.1em;
+ margin-bottom: 1rem;
+ color: var(--text-primary);
+}
+
+.footer-col ul {
+ list-style: none;
+ padding: 0;
+ margin: 0;
+}
+
+.footer-col ul li {
+ margin-bottom: 0.8rem;
+}
+
+.footer-col ul li a {
+ color: var(--text-secondary);
+ text-decoration: none;
+ font-size: 0.9rem;
+ transition: color 0.2s;
+}
+
+.footer-col ul li a:hover {
+ color: var(--accent);
+}
+
+.footer-bottom {
+ max-width: 1200px;
+ margin: 2rem auto 0;
+ padding-top: 1rem;
+ border-top: 1px solid var(--glass-border);
+ display: flex;
+ flex-wrap: wrap;
+ justify-content: space-between;
+ align-items: center;
+ color: var(--text-secondary);
+ font-size: 0.8rem;
+}
+
+.footer-meta {
+ display: flex;
+ gap: 1rem;
+}
+
+.footer-meta a {
+ color: inherit;
+ text-decoration: none;
+}
+
+.footer-meta a:hover {
+ color: var(--accent);
+}
+
+/* Responsive adjustments */
+@media (max-width: 900px) {
+ .footer-grid {
+ grid-template-columns: 1fr 1fr;
+ }
+}
+
+@media (max-width: 700px) {
+ .result-card {
+ flex-direction: column;
+ align-items: flex-start;
+ }
+
+ .result-actions {
+ align-items: flex-start;
+ }
+
+ .recent-item {
+ min-width: 180px;
+ }
+}
+
+@media (max-width: 600px) {
+ .hero-input-card h1 {
+ font-size: 2rem;
+ }
+
+ .short-url a {
+ font-size: 1.2rem;
+ }
+
+ .footer-grid {
+ grid-template-columns: 1fr;
+ }
+
+ .footer-bottom {
+ flex-direction: column;
+ gap: 1rem;
+ text-align: center;
+ }
+}
+
+/*===============================
+ MODERN GLASS RECENT TABLE
+================================ */
+
+.recent-page-container {
+ width: 100%;
+ max-width: 1100px;
+ margin: 30px auto;
+ padding: 28px;
+
+ background: var(--card);
+ backdrop-filter: blur(20px);
+
+ border: 1px solid var(--glass-border);
+ border-radius: 20px;
+
+ box-shadow: var(--card-shadow);
+ color: var(--text-color);
+
+ transition: background 0.3s ease, border 0.3s ease;
+}
+
+.recent-table-wrapper {
+ margin-top: 20px;
+ width: 100%;
+ overflow-x: auto;
+}
+
+/* Table */
+.recent-table {
+ width: 100%;
+ border-collapse: collapse;
+ border-radius: 12px;
+ overflow: hidden;
+}
+
+/* Header */
+.recent-table thead {
+ background: var(--glass);
+}
+
+.recent-table th {
+ padding: 8px 14px;
+ text-align: left;
+ font-size: 13px;
+ letter-spacing: 0.08em;
+ text-transform: uppercase;
+ font-weight: 700;
+ color: var(--muted);
+ border-bottom: 1px solid var(--glass-border);
+}
+
+/* Body cells */
+.recent-table td {
+ padding: 14px;
+ font-size: 14px;
+ color: var(--text-primary);
+ border-bottom: 1px solid var(--glass-border);
+ transition: 0.25s ease;
+}
+
+/* Row hover */
+.recent-table tbody tr:hover {
+ background: rgba(255, 255, 255, 0.05);
+}
+
+/* Short link */
+.short-code a {
+ color: var(--accent);
+ font-weight: 700;
+ text-decoration: none;
+}
+
+.short-code a:hover {
+ color: var(--accent-2);
+ text-decoration: underline;
+}
+
+/* Original URL */
+.original-url {
+ word-break: break-all;
+}
+
+.original-url a {
+ color: var(--text-secondary);
+ text-decoration: none;
+}
+
+.original-url a:hover {
+ color: var(--accent);
+}
+
+/* Created time */
+.created-time {
+ font-size: 13px;
+ color: var(--muted);
+ white-space: nowrap;
+}
+
+/* Visit count highlight */
+.recent-table td:nth-child(5) {
+ font-weight: 700;
+ color: var(--accent-2);
+}
+
+/* Dark mode adjustments */
+.dark-theme .recent-table th,
+.dark-theme .recent-table td {
+ color: #e5e7eb;
+ border-bottom: 1px solid var(--glass-border);
+}
+
+/* Action buttons */
+.action-col {
+ display: flex;
+ gap: 10px;
+}
+
+.action-btn {
+ width: 36px;
+ height: 36px;
+ border-radius: 10px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ text-decoration: none;
+ font-size: 16px;
+ transition: 0.2s ease;
+}
+
+.open-btn {
+ background: #3b82f6;
+ color: #fff;
+}
+
+.delete-btn {
+ background: #ef4444;
+ color: #fff;
+}
+
+.recent-table-wrapper {
+ margin-bottom: 20px;
+}
+
+
+/* =========================
+ Coming Soon Page
+========================= */
+
+.coming-soon-page {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ padding: 120px 20px 60px;
+}
+
+.coming-soon-card {
+ max-width: 520px;
+ width: 100%;
+ background: var(--card);
+ border-radius: 16px;
+ padding: 50px 40px;
+ text-align: center;
+ box-shadow: 0 20px 50px rgba(0, 0, 0, 0.08);
+}
+
+.coming-icon {
+ font-size: 48px;
+ margin-bottom: 18px;
+}
+
+.coming-soon-card h1 {
+ font-size: 34px;
+ margin-bottom: 14px;
+ color: #000;
+}
+
+.dark-theme .coming-soon-card h1 {
+ color: #fff;
+}
+
+.coming-soon-card p {
+ font-size: 15px;
+ color: var(--muted);
+ line-height: 1.6;
+ margin-bottom: 28px;
+}
+
+.coming-btn {
+ display: inline-block;
+ padding: 12px 22px;
+ border-radius: 10px;
+ background: var(--accent-grad);
+ color: #fff;
+ font-weight: 700;
+ text-decoration: none;
+ transition: 0.25s ease;
+}
+
+.coming-btn:hover {
+ transform: scale(1.05);
+ box-shadow: 0 12px 28px rgba(77, 163, 185, 0.25);
+}
+
+.info-box {
+ margin-bottom: 15px;
+ padding: 10px;
+ color: #0e34f6;
+ border-radius: 8px;
+ font-weight: 700;
+}
\ No newline at end of file
diff --git a/app/templates/404.html b/app/templates/404.html
new file mode 100644
index 0000000..0825534
--- /dev/null
+++ b/app/templates/404.html
@@ -0,0 +1,51 @@
+{% block content %}
+
+
+
+
+ Page Not Found
+
+
+
+
+
+
π« Page not found
+
The page you are looking for does not exist.
+
+
+ β Go Back
+
+
+
+
+
+{% endblock %}
\ No newline at end of file
diff --git a/app/templates/coming-soon.html b/app/templates/coming-soon.html
deleted file mode 100644
index 1a5e5eb..0000000
--- a/app/templates/coming-soon.html
+++ /dev/null
@@ -1,120 +0,0 @@
-
-
-
-
-
-
- Coming-soon
-
-
-
-
-
-
-
-
-
-
-
-
π§
-
Coming Soon
-
- This feature is under active development.
-
-
-
β Back to Home
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/templates/footer.html b/app/templates/footer.html
new file mode 100644
index 0000000..07569aa
--- /dev/null
+++ b/app/templates/footer.html
@@ -0,0 +1,42 @@
+
\ No newline at end of file
diff --git a/app/templates/header.html b/app/templates/header.html
index c7b19b1..0fa001c 100644
--- a/app/templates/header.html
+++ b/app/templates/header.html
@@ -1,11 +1,28 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Recent Shortened URLs
-
-
-
-
-
-
-
-
-
-
-
diff --git a/app/templates/recent.html b/app/templates/recent.html
index 5d89d19..ff32076 100644
--- a/app/templates/recent.html
+++ b/app/templates/recent.html
@@ -1,218 +1,82 @@
-
-
-
-