diff --git a/web/src/app.css b/web/src/app.css index 48f8393..5536413 100644 --- a/web/src/app.css +++ b/web/src/app.css @@ -1,31 +1,45 @@ -/* Vellum — user-facing design tokens. - Media-first: dark by default, covers are the primary content, chrome recedes. - One accent, a tight type scale, and generous spacing so artwork breathes. */ +/* Vellum — design tokens. + The artwork is the colour in this app, so the chrome stays warm-neutral and + one muted gold carries emphasis. Type, spacing and radii come from a fixed + scale rather than ad-hoc values, which is what keeps it from feeling rushed. */ :root { - --bg: #0a0a0c; - --surface: #131316; - --surface-2: #1b1b20; - --surface-3: #24242b; - --border: #26262e; - --border-strong: #34343e; + /* ── Surfaces ─────────────────────────────────────────────────────── */ + --bg: #0c0c0e; + --surface: #141416; + --surface-2: #1b1b1e; + --surface-3: #232327; + --border: #26262a; + --border-strong: #343439; - --text: #f3f3f5; - --muted: #a2a2ae; - --faint: #6c6c78; + /* ── Ink ──────────────────────────────────────────────────────────── */ + --text: #f4f3f5; + --muted: #a3a1a9; + --faint: #6d6b75; - --accent: #6d7cff; - --accent-hover: #808dff; - --accent-soft: color-mix(in srgb, var(--accent) 16%, transparent); - --accent-text: #ffffff; - --danger: #ff6b6b; - --success: #46d17f; + /* ── Emphasis ─────────────────────────────────────────────────────── */ + --accent: #d9a441; + --accent-hover: #e6b556; + --accent-soft: color-mix(in srgb, var(--accent) 18%, transparent); + --accent-text: #1a1204; + --danger: #e0625c; + --success: #4fbf83; - --radius-sm: 6px; - --radius: 10px; - --radius-lg: 14px; - --radius-cover: 8px; + /* ── Type scale (rem, relative to the 15px root) ──────────────────── */ + --fs-xs: 0.8rem; /* 12 */ + --fs-sm: 0.867rem; /* 13 */ + --fs-md: 0.933rem; /* 14 */ + --fs-base: 1rem; /* 15 */ + --fs-lg: 1.133rem; /* 17 */ + --fs-xl: 1.333rem; /* 20 */ + --fs-2xl: 1.733rem; /* 26 */ + --fs-3xl: 2.4rem; /* 36 */ + --lh-tight: 1.15; + --lh-snug: 1.35; + --lh-body: 1.55; + + /* ── Space ────────────────────────────────────────────────────────── */ --space-1: 4px; --space-2: 8px; --space-3: 12px; @@ -34,13 +48,19 @@ --space-6: 32px; --space-7: 48px; - --font: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, - 'Noto Sans', sans-serif; + /* ── Shape ────────────────────────────────────────────────────────── */ + --radius-sm: 5px; + --radius: 8px; + --radius-lg: 12px; + --radius-cover: 8px; + + --font: -apple-system, BlinkMacSystemFont, 'Segoe UI Variable Text', 'Segoe UI', + Roboto, Helvetica, Arial, 'Noto Sans', sans-serif; --mono: ui-monospace, SFMono-Regular, 'SF Mono', Menlo, Consolas, monospace; - --nav-width: 232px; - --shadow-cover: 0 1px 2px rgba(0, 0, 0, 0.4), 0 8px 24px rgba(0, 0, 0, 0.35); - --shadow-lift: 0 12px 32px rgba(0, 0, 0, 0.5); + --nav-width: 236px; + --shadow-cover: 0 1px 2px rgba(0, 0, 0, 0.45), 0 6px 20px rgba(0, 0, 0, 0.35); + --shadow-lift: 0 10px 28px rgba(0, 0, 0, 0.5); /* User-controlled sizing. --ui-scale drives every rem in the app, so the text-size setting scales headings, labels and body together. --card-scale @@ -62,20 +82,26 @@ @media (prefers-color-scheme: light) { :root { - --bg: #f7f7f8; + --bg: #faf9f7; --surface: #ffffff; - --surface-2: #f1f1f3; - --surface-3: #e7e7ea; - --border: #e6e6ea; - --border-strong: #d2d2d9; - --text: #16161a; - --muted: #5d5d68; - --faint: #8b8b96; - --accent: #5563e8; - --accent-hover: #4553d8; + --surface-2: #f3f2ef; + --surface-3: #e9e7e3; + --border: #e6e4df; + --border-strong: #d3d0ca; + + --text: #17161a; + --muted: #5f5d66; + --faint: #8a8791; + + --accent: #a8761c; + --accent-hover: #8f6414; + --accent-soft: color-mix(in srgb, var(--accent) 14%, transparent); --accent-text: #ffffff; + --danger: #c0392b; + --success: #1f8a4c; + --shadow-cover: 0 1px 2px rgba(20, 20, 30, 0.08), 0 6px 18px rgba(20, 20, 30, 0.1); - --shadow-lift: 0 10px 28px rgba(20, 20, 30, 0.16); + --shadow-lift: 0 10px 26px rgba(20, 20, 30, 0.16); } } @@ -101,9 +127,10 @@ body { background: var(--bg); color: var(--text); font-family: var(--font); - font-size: 1rem; - line-height: 1.5; + font-size: var(--fs-base); + line-height: var(--lh-body); -webkit-font-smoothing: antialiased; + text-rendering: optimizeLegibility; } a { @@ -118,17 +145,21 @@ h1, h2, h3 { margin: 0; - font-weight: 600; - letter-spacing: -0.015em; + font-weight: 620; + letter-spacing: -0.02em; + line-height: var(--lh-tight); } h1 { - font-size: 1.571rem; + font-size: var(--fs-2xl); } h2 { - font-size: 1.214rem; + font-size: var(--fs-lg); + letter-spacing: -0.012em; } h3 { - font-size: 1.071rem; + font-size: var(--fs-base); + font-weight: 600; + letter-spacing: -0.006em; } button, @@ -169,12 +200,18 @@ select { border-radius: var(--radius); background: var(--surface-2); color: var(--text); + font-size: var(--fs-md); + font-weight: 500; cursor: pointer; - transition: background 0.12s ease, border-color 0.12s ease, transform 0.08s ease; + transition: + background var(--t-fast) var(--ease), + border-color var(--t-fast) var(--ease), + color var(--t-fast) var(--ease); white-space: nowrap; } .btn:hover:not(:disabled) { background: var(--surface-3); + border-color: var(--faint); } .btn:active:not(:disabled) { transform: translateY(1px); @@ -187,6 +224,7 @@ select { background: var(--accent); border-color: var(--accent); color: var(--accent-text); + font-weight: 600; } .btn-primary:hover:not(:disabled) { background: var(--accent-hover); @@ -198,11 +236,12 @@ select { } .btn-ghost:hover:not(:disabled) { background: var(--surface-2); + border-color: transparent; } .btn-lg { - padding: 11px 22px; - font-size: 1.071rem; - border-radius: 12px; + padding: 10px 20px; + font-size: var(--fs-base); + border-radius: var(--radius-lg); } .input { @@ -212,7 +251,13 @@ select { border-radius: var(--radius); background: var(--bg); color: var(--text); - transition: border-color 0.12s ease, box-shadow 0.12s ease; + font-size: var(--fs-md); + transition: + border-color var(--t-fast) var(--ease), + box-shadow var(--t-fast) var(--ease); +} +.input::placeholder { + color: var(--faint); } .input:focus { outline: none; @@ -226,7 +271,7 @@ select { gap: 6px; } .field label { - font-size: .857rem; + font-size: var(--fs-sm); font-weight: 500; color: var(--muted); } @@ -241,23 +286,25 @@ select { .badge { display: inline-block; - padding: 2px 8px; - border-radius: 999px; + padding: 2px 7px; + border-radius: var(--radius-sm); border: 1px solid var(--border-strong); - font-size: .786rem; + font-size: var(--fs-xs); color: var(--muted); - text-transform: uppercase; - letter-spacing: 0.05em; } .chip { - padding: 5px 12px; + padding: 6px 13px; border: 1px solid var(--border-strong); - border-radius: 999px; + border-radius: var(--radius); background: transparent; color: var(--muted); cursor: pointer; - font-size: .929rem; + font-size: var(--fs-md); + transition: + background var(--t-fast) var(--ease), + color var(--t-fast) var(--ease), + border-color var(--t-fast) var(--ease); } .chip:hover { color: var(--text); @@ -267,6 +314,7 @@ select { background: var(--text); border-color: var(--text); color: var(--bg); + font-weight: 500; } .alert { @@ -274,14 +322,14 @@ select { border: 1px solid color-mix(in srgb, var(--danger) 45%, var(--border)); border-radius: var(--radius); background: color-mix(in srgb, var(--danger) 10%, transparent); - font-size: .929rem; + font-size: var(--fs-md); } .ok { padding: 10px 14px; border: 1px solid color-mix(in srgb, var(--success) 40%, var(--border)); border-radius: var(--radius); background: color-mix(in srgb, var(--success) 9%, transparent); - font-size: .929rem; + font-size: var(--fs-md); } .muted { @@ -292,10 +340,10 @@ select { } .mono { font-family: var(--mono); - font-size: .857rem; + font-size: var(--fs-sm); } -/* ── Cover card ─────────────────────────────────────────────────────── */ +/* ── Cover ──────────────────────────────────────────────────────────── */ .cover { position: relative; @@ -304,7 +352,6 @@ select { background: var(--surface-2); overflow: hidden; box-shadow: var(--shadow-cover); - transition: transform 0.16s ease, box-shadow 0.16s ease; } .cover.wide { aspect-ratio: 1 / 1; @@ -320,8 +367,8 @@ select { inset: 0; display: grid; place-items: center; - font-size: 2.429rem; - font-weight: 700; + font-size: 2.2rem; + font-weight: 600; color: var(--faint); background: linear-gradient(150deg, var(--surface-2), var(--surface-3)); } @@ -329,7 +376,7 @@ select { display: none; } -/* ── Empty state ────────────────────────────────────────────────────── */ +/* ── Empty ──────────────────────────────────────────────────────────── */ .empty { display: flex; @@ -338,10 +385,11 @@ select { justify-content: center; gap: var(--space-2); padding: var(--space-7) var(--space-4); - border: 1px dashed var(--border-strong); + border: 1px solid var(--border); border-radius: var(--radius-lg); text-align: center; color: var(--muted); + background: var(--surface); } .empty h3 { color: var(--text); diff --git a/web/src/lib/components/Featured.svelte b/web/src/lib/components/Featured.svelte index e00fa97..ad9e8c3 100644 --- a/web/src/lib/components/Featured.svelte +++ b/web/src/lib/components/Featured.svelte @@ -1,82 +1,169 @@ - +{/if}