Wrapper-Frontend vor cryptgeon: der Browser verschluesselt lokal, per Mail geht nur der Link raus. Fuer das Deployment nach den Konventionen aus DEPLOY.md hergerichtet: - docker-compose.yml mit festem Projekt- und Container-Namen, kein ports-Mapping, Healthcheck als Deploy-Gate. cryptgeon und redis liegen im internen Netz, nur app haengt im Web-Netz. - cryptgeon von latest auf 2.9.3 gepinnt. Das ist derselbe Stand, den latest bisher geliefert hat; 2.6.2 existiert nicht. - /healthz in server.js, vor dem Catch-all-Proxy registriert. - Dockerfile auf npm ci mit Lockfile und non-root umgestellt. - .gitea/workflows/deploy.yml: Build und Syntaxpruefung vor dem Deploy, .env aus dem Repo-Secret DOTENV. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
401 lines
11 KiB
CSS
401 lines
11 KiB
CSS
/* ── Reset ───────────────────────────────────────────────── */
|
||
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
|
||
|
||
/* ── Design Tokens (1:1 domaincheck.lucas-orth.de) ───────── */
|
||
:root {
|
||
--color-accent: #1E40AF;
|
||
--color-accent-hover: #1E378A;
|
||
--color-ink: #111827;
|
||
--color-ink-muted: #6B7280;
|
||
--color-ink-light: #9CA3AF;
|
||
--color-surface: #FFFFFF;
|
||
--color-surface-offset: #FAFAFA; /* footer bg */
|
||
--color-surface-section: #F3F4F6; /* hero + steps section bg */
|
||
--color-border: #E5E7EB;
|
||
--color-border-strong: #D1D5DB; /* step numbers */
|
||
--color-success: #16A34A;
|
||
--color-success-bg: #F0FDF4;
|
||
--color-success-border: #BBF7D0;
|
||
--color-error: #DC2626;
|
||
--color-error-bg: #FEF2F2;
|
||
--color-error-border: #FECACA;
|
||
|
||
--font-heading: 'Space Grotesk', sans-serif;
|
||
--font-body: 'Manrope', sans-serif;
|
||
|
||
--radius: 4px;
|
||
--shadow-card: 0 1px 4px 0 rgba(0,0,0,0.07), 0 1px 2px -1px rgba(0,0,0,0.05);
|
||
--transition: 180ms;
|
||
}
|
||
|
||
/* ── Base ────────────────────────────────────────────────── */
|
||
html {
|
||
font-family: var(--font-body);
|
||
font-size: 16px;
|
||
color: var(--color-ink);
|
||
background: var(--color-surface-section);
|
||
-webkit-font-smoothing: antialiased;
|
||
-moz-osx-font-smoothing: grayscale;
|
||
}
|
||
|
||
a { text-decoration: none; color: inherit; }
|
||
|
||
/* ── Page ────────────────────────────────────────────────── */
|
||
.page {
|
||
min-height: 100dvh;
|
||
display: flex;
|
||
flex-direction: column;
|
||
}
|
||
|
||
/* ── Container (max-w-5xl = 1024px, px-6 = 24px) ────────── */
|
||
.container {
|
||
max-width: 1024px;
|
||
margin: 0 auto;
|
||
padding: 0 24px;
|
||
}
|
||
|
||
/* ── Header ──────────────────────────────────────────────── */
|
||
.header {
|
||
position: sticky;
|
||
top: 0;
|
||
z-index: 40;
|
||
background: var(--color-surface);
|
||
border-bottom: 1px solid var(--color-border);
|
||
height: 64px;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.nav {
|
||
height: 100%;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
}
|
||
|
||
/* Logo: h-[45px] wie im Domainchecker */
|
||
.logo {
|
||
height: 45px;
|
||
width: auto;
|
||
object-fit: contain;
|
||
display: block;
|
||
}
|
||
|
||
/* ── Hero Section ────────────────────────────────────────── */
|
||
/* bg-surface-section border-b border-border, py-20 md:py-28 */
|
||
.hero {
|
||
background: var(--color-surface-section);
|
||
border-bottom: 1px solid var(--color-border);
|
||
padding: 80px 0;
|
||
flex: 1;
|
||
}
|
||
|
||
@media (min-width: 768px) {
|
||
.hero { padding: 112px 0; }
|
||
}
|
||
|
||
.hero__inner { max-width: 672px; } /* max-w-xl ≈ max-w-2xl für form */
|
||
|
||
/* ── Eyebrow ─────────────────────────────────────────────── */
|
||
/* text-sm font-semibold tracking-widest uppercase text-accent mb-4 */
|
||
.eyebrow {
|
||
font-family: var(--font-body);
|
||
font-size: 12px;
|
||
font-weight: 600;
|
||
letter-spacing: 0.1em;
|
||
text-transform: uppercase;
|
||
color: var(--color-accent);
|
||
margin-bottom: 16px;
|
||
}
|
||
|
||
/* ── Hero Title ──────────────────────────────────────────── */
|
||
/* text-4xl md:text-6xl leading-tight mb-4 */
|
||
.hero-title {
|
||
font-family: var(--font-heading);
|
||
font-size: 36px;
|
||
font-weight: 700;
|
||
color: var(--color-ink);
|
||
line-height: 1.15;
|
||
margin-bottom: 16px;
|
||
letter-spacing: -0.01em;
|
||
}
|
||
|
||
.hero-title .accent { color: var(--color-accent); }
|
||
|
||
@media (min-width: 768px) {
|
||
.hero-title { font-size: 60px; line-height: 1.1; }
|
||
}
|
||
|
||
/* ── Lead Text ───────────────────────────────────────────── */
|
||
/* text-lg mb-10 max-w-xl */
|
||
.lead {
|
||
font-size: 18px;
|
||
color: var(--color-ink-muted);
|
||
line-height: 1.7;
|
||
margin-bottom: 40px;
|
||
max-width: 512px;
|
||
}
|
||
|
||
/* ── Hero Form ───────────────────────────────────────────── */
|
||
/* max-w-2xl = 672px */
|
||
.hero-form {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 12px;
|
||
max-width: 672px;
|
||
}
|
||
|
||
.field {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 6px;
|
||
}
|
||
|
||
.label {
|
||
font-size: 13px;
|
||
font-weight: 600;
|
||
color: var(--color-ink);
|
||
}
|
||
|
||
/* Textarea: h-14 equivalent stacked, border-btn focus */
|
||
.textarea,
|
||
.input {
|
||
width: 100%;
|
||
padding: 12px 20px;
|
||
border: 1px solid var(--color-border);
|
||
border-radius: var(--radius);
|
||
font-family: var(--font-body);
|
||
font-size: 16px;
|
||
color: var(--color-ink);
|
||
background: var(--color-surface);
|
||
transition: border-color var(--transition), box-shadow var(--transition);
|
||
outline: none;
|
||
}
|
||
|
||
.textarea {
|
||
resize: vertical;
|
||
min-height: 130px;
|
||
line-height: 1.6;
|
||
}
|
||
|
||
.textarea::placeholder,
|
||
.input::placeholder {
|
||
color: var(--color-ink-light);
|
||
}
|
||
|
||
.textarea:focus,
|
||
.input:focus {
|
||
border-color: var(--color-accent);
|
||
box-shadow: 0 0 0 2px rgba(30, 64, 175, 0.15);
|
||
}
|
||
|
||
.input--mono {
|
||
font-family: 'Menlo', 'Monaco', 'Courier New', monospace;
|
||
font-size: 13px;
|
||
color: var(--color-ink-muted);
|
||
background: #F9FAFB;
|
||
word-break: break-all;
|
||
}
|
||
|
||
/* ── Hint ────────────────────────────────────────────────── */
|
||
/* text-xs text-ink-light mt-4 */
|
||
.hint {
|
||
font-size: 12px;
|
||
color: var(--color-ink-light);
|
||
margin-top: 4px;
|
||
}
|
||
|
||
/* ── Buttons ─────────────────────────────────────────────── */
|
||
/* px-4 py-3 font-semibold text-base rounded-btn transition */
|
||
.btn {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
gap: 6px;
|
||
padding: 12px 16px;
|
||
border-radius: var(--radius);
|
||
font-family: var(--font-body);
|
||
font-size: 15px;
|
||
font-weight: 600;
|
||
cursor: pointer;
|
||
border: none;
|
||
text-decoration: none;
|
||
transition: background-color var(--transition), opacity var(--transition);
|
||
white-space: nowrap;
|
||
line-height: 1;
|
||
-webkit-appearance: none;
|
||
}
|
||
|
||
.btn:disabled { opacity: 0.5; cursor: not-allowed; }
|
||
|
||
.btn--primary {
|
||
background: var(--color-accent);
|
||
color: #FAFAFA;
|
||
}
|
||
.btn--primary:hover:not(:disabled) {
|
||
background: var(--color-accent-hover);
|
||
}
|
||
|
||
.btn--secondary {
|
||
background: var(--color-surface);
|
||
color: var(--color-ink);
|
||
border: 1px solid var(--color-border-strong);
|
||
}
|
||
.btn--secondary:hover:not(:disabled) { background: #F9FAFB; }
|
||
|
||
.btn--ghost {
|
||
background: transparent;
|
||
color: var(--color-ink-muted);
|
||
font-weight: 500;
|
||
}
|
||
.btn--ghost:hover:not(:disabled) {
|
||
background: var(--color-border);
|
||
color: var(--color-ink);
|
||
}
|
||
|
||
.btn--copied {
|
||
background: var(--color-success-bg) !important;
|
||
color: var(--color-success) !important;
|
||
border-color: var(--color-success-border) !important;
|
||
}
|
||
|
||
/* ── Alert ───────────────────────────────────────────────── */
|
||
.alert {
|
||
padding: 11px 14px;
|
||
border-radius: var(--radius);
|
||
font-size: 14px;
|
||
line-height: 1.5;
|
||
}
|
||
.alert--error {
|
||
background: var(--color-error-bg);
|
||
color: var(--color-error);
|
||
border: 1px solid var(--color-error-border);
|
||
}
|
||
|
||
/* ── Link Row ────────────────────────────────────────────── */
|
||
.link-row { display: flex; gap: 8px; align-items: stretch; }
|
||
.link-row .input { flex: 1; min-width: 0; }
|
||
|
||
/* ── Success State ───────────────────────────────────────── */
|
||
.success-icon {
|
||
width: 52px;
|
||
height: 52px;
|
||
background: var(--color-success-bg);
|
||
color: var(--color-success);
|
||
border: 1px solid var(--color-success-border);
|
||
border-radius: 50%;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
font-size: 20px;
|
||
font-weight: 700;
|
||
margin-bottom: 20px;
|
||
}
|
||
|
||
/* ── Steps Section ───────────────────────────────────────── */
|
||
/* bg-surface-section py-20 – gleicher Hintergrund wie Hero, weiße Karten */
|
||
.section-steps {
|
||
background: var(--color-surface-section);
|
||
padding: 80px 0;
|
||
}
|
||
|
||
.section-steps .lead { margin-bottom: 0; }
|
||
|
||
/* Section heading: text-3xl md:text-4xl */
|
||
.section-title {
|
||
font-family: var(--font-heading);
|
||
font-size: 30px;
|
||
font-weight: 700;
|
||
color: var(--color-ink);
|
||
line-height: 1.2;
|
||
margin-bottom: 12px;
|
||
letter-spacing: -0.01em;
|
||
}
|
||
|
||
@media (min-width: 768px) {
|
||
.section-title { font-size: 36px; }
|
||
}
|
||
|
||
/* mb-12 */
|
||
.section-header { margin-bottom: 48px; }
|
||
|
||
/* grid grid-cols-1 md:grid-cols-3 gap-6 */
|
||
.steps-grid {
|
||
display: grid;
|
||
grid-template-columns: repeat(3, 1fr);
|
||
gap: 24px;
|
||
}
|
||
|
||
@media (max-width: 768px) {
|
||
.steps-grid { grid-template-columns: 1fr; }
|
||
}
|
||
|
||
/* bg-white rounded-card border border-border p-7 shadow-card */
|
||
.step-card {
|
||
background: var(--color-surface);
|
||
border: 1px solid var(--color-border);
|
||
border-radius: var(--radius);
|
||
box-shadow: var(--shadow-card);
|
||
padding: 28px;
|
||
}
|
||
|
||
/* text-4xl font-semibold text-border-strong leading-none block mb-4 */
|
||
.step-num {
|
||
display: block;
|
||
font-family: var(--font-heading);
|
||
font-size: 36px;
|
||
font-weight: 600;
|
||
color: var(--color-border-strong);
|
||
line-height: 1;
|
||
margin-bottom: 16px;
|
||
letter-spacing: -0.02em;
|
||
}
|
||
|
||
/* font-heading text-lg text-ink mb-2 */
|
||
.step-title {
|
||
font-family: var(--font-heading);
|
||
font-size: 18px;
|
||
font-weight: 600;
|
||
color: var(--color-ink);
|
||
margin-bottom: 8px;
|
||
}
|
||
|
||
/* text-sm text-ink-muted leading-relaxed */
|
||
.step-text {
|
||
font-size: 14px;
|
||
color: var(--color-ink-muted);
|
||
line-height: 1.65;
|
||
}
|
||
|
||
/* ── Footer ──────────────────────────────────────────────── */
|
||
/* border-t border-border bg-surface-offset py-8 */
|
||
.footer {
|
||
background: var(--color-surface-offset);
|
||
border-top: 1px solid var(--color-border);
|
||
padding: 32px 0;
|
||
flex-shrink: 0;
|
||
margin-top: auto;
|
||
}
|
||
|
||
.footer__inner {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
font-size: 12px;
|
||
color: var(--color-ink-light);
|
||
gap: 12px;
|
||
flex-wrap: wrap;
|
||
}
|
||
|
||
@media (max-width: 640px) {
|
||
.footer__inner { flex-direction: column; text-align: center; }
|
||
}
|
||
|
||
.footer__links { display: flex; gap: 20px; }
|
||
|
||
.footer a {
|
||
color: var(--color-ink-light);
|
||
text-decoration: none;
|
||
transition: color var(--transition);
|
||
}
|
||
.footer a:hover { color: var(--color-accent); }
|