From d035a6406b4e997823081989b1aec50187bc9488 Mon Sep 17 00:00:00 2001 From: mkelvers Date: Tue, 7 Apr 2026 15:56:23 +0200 Subject: [PATCH] ui: add fluid sizing with clamp for responsive scaling --- static/css/style.css | 314 +++++++++++++++++++++++-------------------- 1 file changed, 169 insertions(+), 145 deletions(-) diff --git a/static/css/style.css b/static/css/style.css index dcab42f..aae97bb 100644 --- a/static/css/style.css +++ b/static/css/style.css @@ -8,6 +8,30 @@ --link: #4a9eff; --link-hover: #6bb3ff; --link-active: #9966ff; + + /* fluid typography scale */ + --text-xs: clamp(0.625rem, 0.55rem + 0.25vw, 0.75rem); /* 10-12px */ + --text-sm: clamp(0.6875rem, 0.6rem + 0.3vw, 0.8125rem); /* 11-13px */ + --text-base: clamp(0.75rem, 0.65rem + 0.35vw, 0.9375rem); /* 12-15px */ + --text-md: clamp(0.8125rem, 0.7rem + 0.4vw, 1rem); /* 13-16px */ + --text-lg: clamp(0.875rem, 0.75rem + 0.45vw, 1.125rem); /* 14-18px */ + --text-xl: clamp(1rem, 0.85rem + 0.5vw, 1.375rem); /* 16-22px */ + --text-2xl: clamp(1.125rem, 0.95rem + 0.6vw, 1.5rem); /* 18-24px */ + + /* fluid spacing */ + --space-xs: clamp(0.25rem, 0.2rem + 0.15vw, 0.375rem); /* 4-6px */ + --space-sm: clamp(0.375rem, 0.3rem + 0.2vw, 0.5rem); /* 6-8px */ + --space-md: clamp(0.5rem, 0.4rem + 0.3vw, 0.75rem); /* 8-12px */ + --space-lg: clamp(0.75rem, 0.6rem + 0.5vw, 1rem); /* 12-16px */ + --space-xl: clamp(1rem, 0.8rem + 0.7vw, 1.5rem); /* 16-24px */ + --space-2xl: clamp(1.5rem, 1.2rem + 1vw, 2.5rem); /* 24-40px */ + + /* fluid sizing */ + --poster-width: clamp(100px, 8vw + 60px, 180px); + --thumb-width: clamp(120px, 10vw + 40px, 200px); + --search-thumb: clamp(36px, 3vw + 20px, 50px); + --table-thumb: clamp(28px, 2vw + 16px, 40px); + --sidebar-width: clamp(200px, 15vw + 100px, 280px); } * { @@ -18,7 +42,7 @@ body { background-color: var(--bg); color: var(--text); font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif; - font-size: 14px; + font-size: var(--text-lg); line-height: 1.5; margin: 0; padding: 0; @@ -27,7 +51,7 @@ body { /* Header */ header { - padding: 8px 16px; + padding: var(--space-md) var(--space-lg); background: var(--surface); border-bottom: 1px solid var(--border); position: sticky; @@ -38,7 +62,7 @@ header { .header-top { display: flex; align-items: center; - gap: 24px; + gap: var(--space-xl); max-width: 1400px; margin: 0 auto; } @@ -46,11 +70,11 @@ header { .header-left { display: flex; align-items: center; - gap: 24px; + gap: var(--space-xl); } .logo { - font-size: 14px; + font-size: var(--text-lg); font-weight: 700; color: var(--text); } @@ -61,13 +85,13 @@ header { .nav { display: flex; - gap: 16px; + gap: var(--space-lg); border-left: 1px solid var(--border); - padding-left: 16px; + padding-left: var(--space-lg); } .nav a { - font-size: 13px; + font-size: var(--text-md); color: var(--link); text-decoration: none; } @@ -89,9 +113,9 @@ header { background: var(--surface); border: 1px solid var(--border); color: var(--text); - padding: 6px 8px; - font-size: 13px; - width: 320px; + padding: var(--space-sm) var(--space-md); + font-size: var(--text-md); + width: clamp(200px, 25vw + 80px, 400px); font-family: inherit; } @@ -100,6 +124,11 @@ header { border-color: var(--link); } +.search-input:focus + .search-dropdown { + border-color: var(--link); + border-top-color: var(--link); +} + .search-input::placeholder { color: var(--text-muted); } @@ -112,9 +141,9 @@ header { right: 0; background: var(--surface); border: 1px solid var(--border); - border-top: none; + border-top: 1px solid var(--border); margin-top: -1px; - max-height: 480px; + max-height: clamp(300px, 50vh, 600px); overflow-y: auto; z-index: 1000; } @@ -125,8 +154,8 @@ header { } .search-results-title { - padding: 8px 12px; - font-size: 11px; + padding: var(--space-md) var(--space-lg); + font-size: var(--text-xs); font-weight: 600; color: var(--text-muted); text-transform: uppercase; @@ -135,8 +164,8 @@ header { .search-result-item { display: flex; - gap: 10px; - padding: 8px 12px; + gap: var(--space-md); + padding: var(--space-md) var(--space-lg); border-bottom: 1px solid var(--border); text-decoration: none; color: inherit; @@ -149,39 +178,39 @@ header { } .search-result-thumb { - width: 40px; - height: 60px; + width: var(--search-thumb); + aspect-ratio: 2/3; object-fit: cover; border: 1px solid var(--border); flex-shrink: 0; } .search-result-no-image { - width: 40px; - height: 60px; + width: var(--search-thumb); + aspect-ratio: 2/3; display: flex; align-items: center; justify-content: center; background: var(--surface-hover); border: 1px solid var(--border); - font-size: 9px; + font-size: var(--text-xs); color: var(--text-muted); flex-shrink: 0; text-align: center; - padding: 4px; + padding: var(--space-xs); } .search-result-info { display: flex; flex-direction: column; - gap: 3px; + gap: var(--space-xs); min-width: 0; flex: 1; padding-top: 2px; } .search-result-title { - font-size: 12px; + font-size: var(--text-base); color: var(--text); font-weight: 500; display: -webkit-box; @@ -192,16 +221,16 @@ header { } .search-result-type { - font-size: 11px; + font-size: var(--text-sm); color: var(--text-muted); } .search-result-view-all { display: block; - padding: 10px 12px; + padding: var(--space-md) var(--space-lg); text-align: center; color: var(--link); - font-size: 12px; + font-size: var(--text-base); border-top: 1px solid var(--border); text-decoration: none; } @@ -213,7 +242,7 @@ header { /* Main */ main { - padding: 16px; + padding: var(--space-lg); max-width: 1400px; margin: 0 auto; } @@ -234,14 +263,14 @@ a:visited { /* Grid */ .catalog-grid { display: grid; - grid-template-columns: repeat(auto-fill, minmax(160px, 1fr)); - gap: 12px; + grid-template-columns: repeat(auto-fill, minmax(var(--thumb-width), 1fr)); + gap: var(--space-lg); } .catalog-item { display: flex; flex-direction: column; - gap: 4px; + gap: var(--space-xs); } .catalog-thumb { @@ -263,13 +292,13 @@ a:visited { align-items: center; justify-content: center; color: var(--text-muted); - font-size: 12px; + font-size: var(--text-base); background: var(--surface); border: 1px solid var(--border); } .catalog-title { - font-size: 12px; + font-size: var(--text-base); color: var(--text); display: -webkit-box; -webkit-line-clamp: 2; @@ -281,14 +310,14 @@ a:visited { .loading-indicator { display: flex; align-items: center; - gap: 8px; + gap: var(--space-md); color: var(--text-muted); - font-size: 13px; + font-size: var(--text-md); } .loading-dot { - width: 3px; - height: 3px; + width: clamp(3px, 0.3vw + 2px, 5px); + height: clamp(3px, 0.3vw + 2px, 5px); background: var(--text-muted); animation: pulse 1.5s ease-in-out infinite; } @@ -307,18 +336,18 @@ a:visited { /* Empty State */ .empty-state { text-align: center; - padding: 48px 16px; + padding: var(--space-2xl) var(--space-lg); } .empty-state-title { - font-size: 16px; + font-size: var(--text-xl); font-weight: 600; color: var(--text); - margin-bottom: 8px; + margin-bottom: var(--space-md); } .empty-state-text { - font-size: 14px; + font-size: var(--text-lg); color: var(--text-muted); } @@ -332,49 +361,49 @@ a:visited { /* Login */ .login-container { - max-width: 280px; - margin: 60px auto; + max-width: clamp(260px, 20vw + 180px, 360px); + margin: var(--space-2xl) auto; border: 1px solid var(--border); - padding: 16px; + padding: var(--space-lg); background: var(--surface); } .login-container h2 { - font-size: 16px; + font-size: var(--text-xl); font-weight: 600; - margin: 0 0 4px 0; + margin: 0 0 var(--space-xs) 0; } .login-subtitle { color: var(--text-muted); - font-size: 12px; - margin: 0 0 16px 0; + font-size: var(--text-base); + margin: 0 0 var(--space-lg) 0; } .login-form { display: flex; flex-direction: column; - gap: 12px; + gap: var(--space-lg); } .form-group { display: flex; flex-direction: column; - gap: 4px; + gap: var(--space-xs); } .form-group label { - font-size: 12px; + font-size: var(--text-base); color: var(--text); font-weight: 500; } .form-group input { - padding: 6px 8px; + padding: var(--space-sm) var(--space-md); background: var(--surface); border: 1px solid var(--border); color: var(--text); - font-size: 13px; + font-size: var(--text-md); font-family: inherit; } @@ -384,14 +413,14 @@ a:visited { } .login-button { - padding: 6px; + padding: var(--space-sm); background: var(--surface); color: var(--text); border: 1px solid var(--border); - font-size: 13px; + font-size: var(--text-md); font-weight: 500; cursor: pointer; - margin-top: 4px; + margin-top: var(--space-xs); font-family: inherit; } @@ -405,11 +434,11 @@ a:visited { display: flex; justify-content: space-between; align-items: center; - margin-bottom: 16px; + margin-bottom: var(--space-lg); } .watchlist-header h2 { - font-size: 16px; + font-size: var(--text-xl); font-weight: 600; margin: 0; } @@ -417,12 +446,12 @@ a:visited { .watchlist-controls { display: flex; align-items: center; - gap: 16px; - font-size: 13px; + gap: var(--space-lg); + font-size: var(--text-md); } .text-link { - font-size: 13px; + font-size: var(--text-md); font-family: inherit; background: none; border: none; @@ -442,8 +471,8 @@ a:visited { } .view-toggle a { - padding: 4px 8px; - font-size: 12px; + padding: var(--space-xs) var(--space-md); + font-size: var(--text-base); color: var(--link); border-right: 1px solid var(--border); text-decoration: none; @@ -465,14 +494,14 @@ a:visited { .status-tabs { display: flex; gap: 0; - margin-bottom: 16px; + margin-bottom: var(--space-lg); border-bottom: 1px solid var(--border); overflow-x: auto; } .status-tabs a { - padding: 8px 12px; - font-size: 12px; + padding: var(--space-md) var(--space-lg); + font-size: var(--text-base); color: var(--link); white-space: nowrap; border-bottom: 2px solid transparent; @@ -495,10 +524,10 @@ a:visited { .watchlist-item .remove-btn { position: absolute; - top: 4px; - right: 4px; - width: 20px; - height: 20px; + top: var(--space-xs); + right: var(--space-xs); + width: clamp(18px, 1.5vw + 12px, 24px); + height: clamp(18px, 1.5vw + 12px, 24px); display: flex; align-items: center; justify-content: center; @@ -506,7 +535,7 @@ a:visited { border: 1px solid var(--border); color: var(--text-muted); cursor: pointer; - font-size: 12px; + font-size: var(--text-base); opacity: 0; transition: opacity 0.15s; } @@ -521,7 +550,7 @@ a:visited { } .watchlist-status { - font-size: 11px; + font-size: var(--text-sm); color: var(--text-muted); } @@ -533,8 +562,8 @@ a:visited { .watchlist-table th { text-align: left; - padding: 8px 12px; - font-size: 12px; + padding: var(--space-md) var(--space-lg); + font-size: var(--text-base); font-weight: 600; color: var(--text); border-bottom: 1px solid var(--border); @@ -542,10 +571,10 @@ a:visited { } .watchlist-table td { - padding: 8px 12px; + padding: var(--space-md) var(--space-lg); border-bottom: 1px solid var(--border); vertical-align: middle; - font-size: 13px; + font-size: var(--text-md); } .watchlist-table tr:hover { @@ -553,8 +582,8 @@ a:visited { } .watchlist-table .thumb { - width: 32px; - height: 48px; + width: var(--table-thumb); + aspect-ratio: 2/3; object-fit: cover; border: 1px solid var(--border); } @@ -565,12 +594,12 @@ a:visited { .watchlist-table .status-cell { color: var(--text-muted); - font-size: 12px; + font-size: var(--text-base); } .watchlist-table .remove-link { color: var(--link); - font-size: 12px; + font-size: var(--text-base); background: none; border: none; cursor: pointer; @@ -586,7 +615,7 @@ a:visited { /* Anime Page */ .anime-page { display: flex; - gap: 24px; + gap: var(--space-xl); max-width: 1200px; } @@ -597,13 +626,13 @@ a:visited { .anime-hero { display: flex; - gap: 16px; - margin-bottom: 24px; + gap: var(--space-lg); + margin-bottom: var(--space-xl); } .anime-poster { flex-shrink: 0; - width: 140px; + width: var(--poster-width); } .anime-poster img { @@ -617,52 +646,52 @@ a:visited { } .anime-info h1 { - font-size: 20px; + font-size: var(--text-2xl); font-weight: 600; - margin: 0 0 4px 0; + margin: 0 0 var(--space-xs) 0; } .anime-alt-title { - font-size: 12px; + font-size: var(--text-base); color: var(--text-muted); - margin: 0 0 12px 0; + margin: 0 0 var(--space-lg) 0; } .anime-quick-info { display: flex; flex-wrap: wrap; - gap: 8px; - margin-bottom: 12px; + gap: var(--space-md); + margin-bottom: var(--space-lg); } .info-tag { - padding: 2px 6px; + padding: var(--space-xs) var(--space-sm); background: var(--surface-hover); border: 1px solid var(--border); - font-size: 11px; + font-size: var(--text-sm); color: var(--text-muted); } .anime-actions { - margin-top: 12px; + margin-top: var(--space-lg); } .anime-synopsis { - margin-bottom: 24px; + margin-bottom: var(--space-xl); } .anime-synopsis h3, .anime-relations h3 { - font-size: 12px; + font-size: var(--text-base); font-weight: 600; color: var(--text); text-transform: uppercase; letter-spacing: 0.05em; - margin: 0 0 12px 0; + margin: 0 0 var(--space-lg) 0; } .anime-synopsis p { - font-size: 13px; + font-size: var(--text-md); line-height: 1.6; color: var(--text); margin: 0; @@ -676,13 +705,13 @@ a:visited { .relations-grid { display: grid; grid-template-columns: repeat(6, 1fr); - gap: 12px; + gap: var(--space-lg); } .relation-card { display: flex; flex-direction: column; - gap: 4px; + gap: var(--space-xs); } .relation-card.current { @@ -709,7 +738,7 @@ a:visited { } .relation-title { - font-size: 11px; + font-size: var(--text-sm); color: var(--text); display: -webkit-box; -webkit-line-clamp: 2; @@ -720,10 +749,10 @@ a:visited { /* Anime Sidebar */ .anime-sidebar { flex-shrink: 0; - width: 240px; + width: var(--sidebar-width); columns: 2; - column-gap: 8px; - padding: 12px; + column-gap: var(--space-md); + padding: var(--space-lg); background: var(--surface); border: 1px solid var(--border); height: fit-content; @@ -732,39 +761,39 @@ a:visited { .sidebar-row { display: flex; flex-direction: column; - gap: 2px; - margin-bottom: 8px; + gap: var(--space-xs); + margin-bottom: var(--space-md); break-inside: avoid; } .sidebar-label { - font-size: 11px; + font-size: var(--text-sm); font-weight: 600; color: var(--text); text-transform: uppercase; } .sidebar-value { - font-size: 12px; + font-size: var(--text-base); color: var(--text-muted); line-height: 1.4; } .sidebar-row-wrap { - gap: 8px; + gap: var(--space-md); } .sidebar-tags { display: flex; flex-wrap: wrap; - gap: 4px; + gap: var(--space-xs); } .sidebar-tag { - padding: 2px 6px; + padding: var(--space-xs) var(--space-sm); background: var(--surface-hover); border: 1px solid var(--border); - font-size: 11px; + font-size: var(--text-sm); color: var(--text); } @@ -777,12 +806,12 @@ a:visited { .dropdown-trigger { display: flex; align-items: center; - gap: 6px; - padding: 6px 12px; + gap: var(--space-sm); + padding: var(--space-sm) var(--space-lg); background: var(--surface); border: 1px solid var(--border); color: var(--text); - font-size: 13px; + font-size: var(--text-md); font-family: inherit; cursor: pointer; } @@ -793,7 +822,7 @@ a:visited { } .dropdown-arrow { - font-size: 10px; + font-size: var(--text-xs); color: var(--text-muted); } @@ -802,7 +831,7 @@ a:visited { top: 100%; left: 0; right: 0; - min-width: 160px; + min-width: clamp(140px, 12vw + 80px, 200px); background: var(--surface); border: 1px solid var(--border); display: none; @@ -819,11 +848,11 @@ a:visited { align-items: center; justify-content: space-between; width: 100%; - padding: 8px 12px; + padding: var(--space-md) var(--space-lg); background: none; border: none; color: var(--text); - font-size: 13px; + font-size: var(--text-md); font-family: inherit; cursor: pointer; text-align: left; @@ -845,7 +874,7 @@ a:visited { .dropdown-item .check { color: var(--link); - font-size: 12px; + font-size: var(--text-base); } .dropdown-item.remove { @@ -861,9 +890,9 @@ a:visited { /* Sort Filter */ .sort-filter { display: flex; - gap: 16px; - margin-bottom: 16px; - padding: 12px; + gap: var(--space-lg); + margin-bottom: var(--space-lg); + padding: var(--space-lg); background: var(--surface); border: 1px solid var(--border); } @@ -871,11 +900,11 @@ a:visited { .sort-filter-group { display: flex; align-items: center; - gap: 8px; + gap: var(--space-md); } .sort-filter-group label { - font-size: 12px; + font-size: var(--text-base); color: var(--text-muted); font-weight: 500; } @@ -884,8 +913,8 @@ a:visited { background: var(--surface); border: 1px solid var(--border); color: var(--text); - padding: 6px 8px; - font-size: 12px; + padding: var(--space-sm) var(--space-md); + font-size: var(--text-base); font-family: inherit; cursor: pointer; } @@ -918,16 +947,16 @@ a:visited { @media (max-width: 768px) { header { - padding: 8px 12px; + padding: var(--space-md) var(--space-lg); } .header-top { flex-wrap: wrap; - gap: 12px; + gap: var(--space-lg); } .header-left { - gap: 12px; + gap: var(--space-lg); } .nav { @@ -947,49 +976,44 @@ a:visited { } main { - padding: 12px; + padding: var(--space-lg); } .catalog-grid { - grid-template-columns: repeat(auto-fill, minmax(120px, 1fr)); - gap: 8px; + gap: var(--space-md); } .anime-hero { flex-direction: column; - gap: 12px; + gap: var(--space-lg); } .anime-poster { - width: 100px; - } - - .anime-info h1 { - font-size: 16px; + width: clamp(80px, 15vw + 40px, 120px); } .relations-grid { grid-template-columns: repeat(3, 1fr); - gap: 8px; + gap: var(--space-md); } } /* Tabs */ .tabs { display: flex; - gap: 16px; - margin-bottom: 24px; + gap: var(--space-lg); + margin-bottom: var(--space-xl); border-bottom: 1px solid var(--border); - padding-bottom: 8px; + padding-bottom: var(--space-md); } .tab { background: none; border: none; color: var(--text-muted); - font-size: 16px; + font-size: var(--text-xl); cursor: pointer; - padding: 8px 16px; + padding: var(--space-md) var(--space-lg); transition: color 0.2s; text-transform: lowercase; }