Files
familienarchiv/frontend/src/routes/login/+page.svelte
Marcel 17d9328c62 style(login): banner body text raised from text-xs to text-sm
text-xs (12px) is below Leonie's body-copy floor for the senior reader cohort
who hit /login?reason=expired on a phone in sunlight after being logged out.
text-sm (14px) restores legibility without breaking the visual hierarchy with
the heading. Addresses PR #612 / Leonie L3.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-17 22:52:19 +02:00

136 lines
4.0 KiB
Svelte

<script lang="ts">
import { m } from '$lib/paraglide/messages.js';
import AuthHeader from '../AuthHeader.svelte';
let {
data,
form
}: {
data: { registered: boolean; reason?: string | null };
form?: { error?: string; success?: boolean };
} = $props();
</script>
<svelte:head>
<title>{m.page_title_login()}</title>
</svelte:head>
<div class="flex min-h-screen flex-col bg-canvas">
<AuthHeader />
<div class="flex flex-1 items-center justify-center px-4">
<div class="w-full max-w-sm">
<!-- Logo -->
<div class="mb-10 text-center">
<a href="/" class="inline-flex items-center" aria-label="Familienarchiv">
<span class="font-sans text-2xl font-bold tracking-widest text-ink uppercase"
>Familienarchiv</span
>
</a>
</div>
<!-- Card -->
<div class="rounded-sm border border-line bg-surface p-8 shadow-sm">
{#if data.registered}
<div
role="status"
aria-live="polite"
class="mb-5 rounded-sm border border-green-200 bg-green-50 px-4 py-3 font-sans text-xs font-medium text-green-800"
>
{m.login_registered_success()}
</div>
{/if}
{#if data.reason === 'expired'}
<div
role="status"
aria-live="polite"
class="mb-5 flex items-start gap-3 rounded-sm border border-amber-200 bg-amber-50 px-4 py-3 font-sans"
>
<svg
aria-hidden="true"
viewBox="0 0 20 20"
fill="currentColor"
class="mt-0.5 h-5 w-5 shrink-0 text-warning"
>
<path
fill-rule="evenodd"
d="M8.485 2.495c.673-1.167 2.357-1.167 3.03 0l6.28 10.875c.673 1.167-.17 2.625-1.516 2.625H3.72c-1.347 0-2.189-1.458-1.515-2.625L8.485 2.495ZM10 6a.75.75 0 0 1 .75.75v3.5a.75.75 0 0 1-1.5 0v-3.5A.75.75 0 0 1 10 6Zm0 9a1 1 0 1 0 0-2 1 1 0 0 0 0 2Z"
clip-rule="evenodd"
/>
</svg>
<div>
<p class="text-sm font-medium text-warning">{m.error_session_expired()}</p>
<p class="mt-1 text-sm text-warning">{m.error_session_expired_explainer()}</p>
</div>
</div>
{/if}
<h1 class="mb-6 font-sans text-sm font-bold tracking-widest text-ink uppercase">
{m.login_heading()}
</h1>
<form method="POST" action="?/login" class="space-y-5">
<div>
<label
for="email"
class="mb-1.5 block font-sans text-xs font-bold tracking-widest text-ink-2 uppercase"
>{m.login_label_email()}</label
>
<!-- svelte-ignore a11y_autofocus -->
<input
type="email"
name="email"
id="email"
required
autofocus
autocomplete="email"
class="block w-full border border-line px-3 py-2.5 font-serif text-sm text-ink placeholder-ink-3 focus:outline-none focus-visible:ring-2 focus-visible:ring-focus-ring"
/>
</div>
<div>
<label
for="password"
class="mb-1.5 block font-sans text-xs font-bold tracking-widest text-ink-2 uppercase"
>{m.login_label_password()}</label
>
<input
type="password"
name="password"
id="password"
required
autocomplete="current-password"
class="block w-full border border-line px-3 py-2.5 font-serif text-sm text-ink placeholder-ink-3 focus:outline-none focus-visible:ring-2 focus-visible:ring-focus-ring"
/>
</div>
{#if form?.error}
<div class="text-center font-sans text-xs font-medium text-red-600">{form.error}</div>
{/if}
<button
type="submit"
class="mt-2 min-h-[44px] w-full bg-primary py-2.5 font-sans text-xs font-bold tracking-widest text-primary-fg uppercase transition-colors hover:bg-primary/90"
>
{m.login_btn_submit()}
</button>
<div class="mt-4 text-center">
<a
href="/forgot-password"
class="font-sans text-xs text-ink-3 transition-colors hover:text-ink"
>{m.login_forgot_password()}</a
>
</div>
</form>
</div>
</div>
</div>
<!-- Footer -->
<div class="py-4 text-center">
<p class="font-sans text-xs tracking-widest text-ink-3 uppercase">Familienarchiv</p>
</div>
</div>