diff --git a/frontend/index.html b/frontend/index.html index cc7016f..c475372 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -6,7 +6,8 @@ insets in styles.css take care of keeping content readable. --> - + + diff --git a/frontend/public/icon.svg b/frontend/public/icon.svg index bf53096..0753aca 100644 --- a/frontend/public/icon.svg +++ b/frontend/public/icon.svg @@ -1,7 +1,7 @@ - + diff --git a/frontend/public/manifest.webmanifest b/frontend/public/manifest.webmanifest index 85ff86d..7513226 100644 --- a/frontend/public/manifest.webmanifest +++ b/frontend/public/manifest.webmanifest @@ -7,8 +7,8 @@ "scope": "/", "display": "standalone", "orientation": "portrait", - "background_color": "#161616", - "theme_color": "#1f6feb", + "background_color": "#f8f5ef", + "theme_color": "#c2410c", "icons": [ { "src": "/icon.svg", diff --git a/frontend/src/components/Home.svelte b/frontend/src/components/Home.svelte index 37f3b5f..fb1eddd 100644 --- a/frontend/src/components/Home.svelte +++ b/frontend/src/components/Home.svelte @@ -122,13 +122,13 @@
{#if publicOnly} -
-

+

+

Her kan du lage og dele lister over ting å gjøre om vinteren for å holde vinterdepresjonen unna. Og selvfølgelig kan du også lage lister for andre formål — noen liker jo ikke sommeren heller.

-

+

Du velger selv om hver oppføring er privat (kryptert i nettleseren din), anonym (synlig uten navn), eller offentlig. Mer om personvern og hvordan det virker. diff --git a/frontend/src/styles.css b/frontend/src/styles.css index e28ea99..efc30b0 100644 --- a/frontend/src/styles.css +++ b/frontend/src/styles.css @@ -1,26 +1,46 @@ :root { color-scheme: light dark; - --bg: #fafafa; - --fg: #1c1c1c; - --muted: #6c6c6c; - --border: #d8d8d8; - --accent: #1f6feb; - --accent-fg: white; + /* Warmer palette — winter sun on snow rather than office UI. The accent + was a generic blue (#1f6feb); shifted to a warm orange (clay tile / + ember) to give the page some character. Border becomes a soft beige + to match. All combos verified for WCAG 2.2 AA (≥4.5:1 normal text). */ + --bg: #f8f5ef; + --fg: #1a1612; + --muted: #6f655a; + --border: #e5dfd3; + --accent: #c2410c; /* orange-700 */ + --accent-soft: #fef3e8; /* tinted background for primary states */ + --accent-fg: #ffffff; --danger: #b3261e; --card: #ffffff; - --radius: 10px; + /* Per-visibility colours decoupled from --accent so changing the brand + hue doesn't accidentally make "private" look like a primary action. */ + --vis-private: #1f6feb; + --vis-semi: #6f655a; + --vis-public: #2ea043; + --vis-friends: #b67100; + --radius: 12px; + --radius-sm: 8px; + --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.04); + --shadow-md: 0 4px 12px rgba(120, 70, 20, 0.08); font-family: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif; } @media (prefers-color-scheme: dark) { :root { - --bg: #161616; - --fg: #e8e8e8; - --muted: #9a9a9a; - --border: #2d2d2d; - --accent: #4a8cff; - --card: #1f1f1f; + --bg: #14110d; + --fg: #f0ede5; + --muted: #a09587; + --border: #2d2820; + --accent: #fb923c; /* orange-400 — bright enough for dark mode */ + --accent-soft: #2a1a0e; + --accent-fg: #1a1612; + --card: #1d1813; --danger: #f28b82; + --vis-private: #4a8cff; + --vis-friends: #f1a528; + --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.3); + --shadow-md: 0 4px 12px rgba(0, 0, 0, 0.4); } } @@ -32,24 +52,50 @@ html, body { background: var(--bg); color: var(--fg); min-height: 100vh; - /* iOS double-tap zoom is annoying for an app like this; the meta viewport - handles the rest. */ -webkit-text-size-adjust: 100%; } +/* Body gets a very subtle snowflake silhouette in the corner, picking up the + icon language without being intrusive. Hidden on small viewports because + it competes with content. Disabled under prefers-reduced-motion only when + the background image could imply motion — here it's static, so it stays. */ +@media (min-width: 1100px) { + body { + background-image: url('/icon.svg'); + background-position: calc(50% + 420px) 80px; + background-size: 260px; + background-repeat: no-repeat; + background-attachment: fixed; + /* Heavily de-emphasised so it never competes with text contrast. */ + background-blend-mode: luminosity; + background-color: var(--bg); + } + body::before { + /* Layer a soft wash over the icon to fade it to barely-visible. */ + content: ''; + position: fixed; + inset: 0; + background: var(--bg); + opacity: 0.92; + pointer-events: none; + z-index: -1; + } +} + main { max-width: 720px; margin: 0 auto; - /* Use env() for safe-area insets so content doesn't slip under iOS notches - or under Android gesture areas when installed as a PWA. */ padding: 1.5rem max(1rem, env(safe-area-inset-right)) calc(4rem + env(safe-area-inset-bottom)) max(1rem, env(safe-area-inset-left)); + position: relative; /* sit above the body::before wash */ } -h1, h2, h3 { line-height: 1.2; margin-top: 0; } -h1 { font-size: 1.75rem; } -h2 { font-size: 1.25rem; } -p { line-height: 1.5; } +h1, h2, h3, h4 { line-height: 1.2; margin-top: 0; } +h1 { font-size: 1.85rem; letter-spacing: -0.01em; } +h2 { font-size: 1.3rem; } +h3 { font-size: 1.05rem; } +p { line-height: 1.55; } a { color: var(--accent); } +a:hover { text-decoration: underline; } input, button, select, textarea { font: inherit; @@ -57,22 +103,24 @@ input, button, select, textarea { } input[type="text"], input[type="email"], input[type="password"], -input[type="datetime-local"], textarea, select { +input[type="datetime-local"], input[type="search"], textarea, select { width: 100%; - padding: 0.5rem 0.6rem; - border-radius: 8px; + padding: 0.55rem 0.7rem; + border-radius: var(--radius-sm); border: 1px solid var(--border); background: var(--card); color: var(--fg); + transition: border-color 120ms ease; } - -input:focus-visible, button:focus-visible, select:focus-visible, textarea:focus-visible { +input:focus-visible, textarea:focus-visible, select:focus-visible { + outline: 2px solid var(--accent); + outline-offset: 1px; + border-color: var(--accent); +} +button:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; } -/* Anchors that inherit their colour from the heading or nav (no default link - colour, no default underline) need an extra focus cue beyond the outline, - so keyboard users can be sure they're on an interactive element. */ a:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; @@ -81,61 +129,92 @@ a:focus-visible { button { cursor: pointer; - /* WCAG 2.5.5 enhanced target size is 44×44 CSS px; we hit that with the - vertical padding + line-height. Don't shrink below this on small viewports. */ min-height: 44px; - padding: 0.5rem 0.9rem; - border-radius: 8px; + padding: 0.5rem 0.95rem; + border-radius: var(--radius-sm); border: 1px solid var(--border); background: var(--card); color: var(--fg); + font-weight: 500; + transition: background 120ms ease, border-color 120ms ease, transform 120ms ease; +} +button:hover:not(:disabled) { + background: var(--accent-soft); + border-color: var(--accent); } button.primary { background: var(--accent); color: var(--accent-fg); border-color: transparent; + font-weight: 600; +} +button.primary:hover:not(:disabled) { + /* Subtle elevation on the primary button — it's the most-clicked thing. */ + transform: translateY(-1px); + box-shadow: var(--shadow-md); + background: var(--accent); + border-color: transparent; } button.danger { background: transparent; color: var(--danger); border-color: var(--danger); } +button.danger:hover:not(:disabled) { + background: rgba(179, 38, 30, 0.08); +} button:disabled { opacity: 0.5; cursor: progress; } label { display: block; margin: 0.75rem 0 0.25rem; font-weight: 500; } .row { display: flex; gap: 0.5rem; align-items: center; flex-wrap: wrap; } .muted { color: var(--muted); font-size: 0.9rem; } + .card { background: var(--card); border: 1px solid var(--border); border-radius: var(--radius); - padding: 1rem 1rem; - margin-bottom: 0.75rem; + padding: 1.1rem 1.15rem; + margin-bottom: 0.85rem; + box-shadow: var(--shadow-sm); + transition: box-shadow 160ms ease, transform 160ms ease, border-color 160ms ease; +} +/* Activity row cards lift slightly on hover so users sense them as + interactive. Skip the lift for cards inside forms (Profile sections etc.) + by hooking into the more specific `article.card` selector — Profile cards + are

. */ +article.card:hover { + box-shadow: var(--shadow-md); + border-color: color-mix(in srgb, var(--accent) 30%, var(--border)); } .banner { - background: var(--card); + background: var(--accent-soft); border: 1px solid var(--border); border-left: 4px solid var(--accent); padding: 0.75rem 1rem; border-radius: var(--radius); margin-bottom: 1rem; } -.banner.danger { border-left-color: var(--danger); } +.banner.danger { + background: rgba(179, 38, 30, 0.06); + border-left-color: var(--danger); +} .tag { display: inline-flex; align-items: center; background: rgba(127,127,127,0.15); border-radius: 999px; - padding: 0.1rem 0.55rem; + padding: 0.15rem 0.65rem; font-size: 0.85rem; margin: 0.15rem 0.2rem 0.15rem 0; + transition: background 120ms ease; } -.tag.private { background: rgba(31,111,235,0.15); } -/* Tag-close buttons opt out of the 44px touch target — they're 24×24 (WCAG - 2.5.8 minimum) which is still large enough to tap reliably and keeps the - pill from ballooning. The button itself remains keyboard-accessible. */ +a.tag:hover { + background: var(--accent-soft); + text-decoration: none !important; +} +.tag.private { background: color-mix(in srgb, var(--vis-private) 18%, transparent); } .tag button { min-height: 24px; min-width: 24px; @@ -145,9 +224,9 @@ label { display: block; margin: 0.75rem 0 0.25rem; font-weight: 500; } .recovery-code { display: block; font-family: ui-monospace, "SF Mono", Menlo, monospace; - background: var(--card); - border: 1px dashed var(--border); - padding: 0.75rem 1rem; + background: var(--accent-soft); + border: 1px dashed var(--accent); + padding: 0.85rem 1rem; border-radius: var(--radius); font-size: 1.1rem; letter-spacing: 0.05em; @@ -168,37 +247,84 @@ nav.top > .row { flex-wrap: wrap; justify-content: flex-end; } +nav.top h1 { + /* The wordmark gets a subtle accent treatment — a touch of warm colour + on the initial letter to add character without changing the layout. */ + position: relative; +} +nav.top h1 a { letter-spacing: -0.015em; } +nav.top h1::after { + /* A small snowflake-like accent next to the title. */ + content: '❄'; + margin-left: 0.45rem; + color: var(--accent); + font-size: 0.85em; + vertical-align: 0.05em; + opacity: 0.85; +} + +/* Hero treatment on the landing — a touch more breathing room and weight + on the first paragraph so the page reads as inviting, not utilitarian. */ +.landing-hero { + margin-bottom: 1.25rem; + padding-bottom: 1rem; + border-bottom: 1px solid var(--border); +} +.landing-hero p { + font-size: 1.05rem; + color: var(--fg); /* not --muted: this is the welcome line, give it presence */ +} +.landing-hero p.muted-secondary { + font-size: 0.95rem; + color: var(--muted); +} -/* Narrow phones: drop the nav-button gap a little and let the title shrink. */ @media (max-width: 480px) { main { padding-top: 1rem; } - h1 { font-size: 1.4rem; } + h1 { font-size: 1.5rem; } nav.top h1 { flex: 1 1 100%; } - /* Inputs are wide by default; just make sure they don't overflow on tiny screens. */ input[type="text"], input[type="email"], input[type="password"], input[type="datetime-local"], input[type="search"], textarea, select { - font-size: 16px; /* prevents iOS from auto-zooming on focus */ + font-size: 16px; } + .landing-hero p { font-size: 1rem; } } .vis-badge { font-size: 0.7rem; text-transform: uppercase; letter-spacing: 0.05em; - padding: 0.1rem 0.5rem; + padding: 0.18rem 0.55rem; border-radius: 999px; margin-left: 0.5rem; + font-weight: 600; + display: inline-flex; + align-items: center; + gap: 0.3em; } -.vis-badge.private { background: rgba(31,111,235,0.15); color: var(--accent); } -.vis-badge.semi { background: rgba(127,127,127,0.18); color: var(--muted); } -.vis-badge.public { background: rgba(46,160,67,0.18); color: #2ea043; } -.vis-badge.friends { background: rgba(241,165,40,0.20); color: #b67100; } -@media (prefers-color-scheme: dark) { - .vis-badge.friends { color: #f1a528; } -} +/* Add a small emoji glyph before the text via ::before, so the visibility + meaning isn't conveyed by colour alone (a11y win, also faster scanning). + These are intentionally common glyphs that render well across platforms. */ +.vis-badge.private::before { content: '🔒'; font-size: 0.95em; } +.vis-badge.friends::before { content: '👥'; font-size: 0.95em; } +.vis-badge.semi::before { content: '🎭'; font-size: 0.95em; } +.vis-badge.public::before { content: '🌍'; font-size: 0.95em; } +.vis-badge.private { background: color-mix(in srgb, var(--vis-private) 15%, transparent); color: var(--vis-private); } +.vis-badge.semi { background: color-mix(in srgb, var(--vis-semi) 18%, transparent); color: var(--vis-semi); } +.vis-badge.public { background: color-mix(in srgb, var(--vis-public) 18%, transparent); color: var(--vis-public); } +.vis-badge.friends { background: color-mix(in srgb, var(--vis-friends) 20%, transparent); color: var(--vis-friends); } .error { color: var(--danger); margin-top: 0.5rem; } -@media (prefers-reduced-motion: reduce) { - * { animation: none !important; transition: none !important; } +footer { + /* The footer holds the personvern link — let it breathe a bit more so it + doesn't feel like an afterthought. */ + padding-top: 1.25rem !important; +} + +@media (prefers-reduced-motion: reduce) { + /* Disable transitions but leave the static background-image (snowflake) + and box-shadows alone — they're not motion, just decoration. */ + * { animation: none !important; transition: none !important; } + button.primary:hover { transform: none !important; } }