Files
dogfather-universe/abonnieren.html
T

674 lines
36 KiB
HTML

<!DOCTYPE html>
<html lang="de" data-theme="dogfather">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>DogiCrew 🩵 — DOGFATHER UNIVERSE</title>
<meta name="description" content="Unterstütze Dogfather dauerhaft mit der DogiCrew 🩵 und sammle exklusive Treueprämien — die Teddy-Kollektion entsteht in Kooperation mit VanVan." />
<link rel="icon" type="image/png" href="assets/img/favicon.png" />
<link rel="manifest" href="/manifest.json" />
<meta name="theme-color" content="#0b0d10" />
<meta property="og:type" content="website" />
<meta property="og:site_name" content="DOGFATHER UNIVERSE" />
<meta property="og:title" content="DogiCrew 🩵 — DOGFATHER UNIVERSE" />
<meta property="og:description" content="Unterstütze Dogfather dauerhaft mit der DogiCrew 🩵 und sammle exklusive Treueprämien — die Teddy-Kollektion entsteht in Kooperation mit VanVan." />
<meta property="og:image" content="https://dogfather-universe.com/assets/img/og-cover.jpg" />
<meta property="og:url" content="https://dogfather-universe.com/abonnieren.html" />
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:title" content="DogiCrew 🩵 — DOGFATHER UNIVERSE" />
<meta name="twitter:description" content="Unterstütze Dogfather dauerhaft mit der DogiCrew 🩵 und sammle exklusive Treueprämien — die Teddy-Kollektion entsteht in Kooperation mit VanVan." />
<meta name="twitter:image" content="https://dogfather-universe.com/assets/img/og-cover.jpg" />
<link rel="stylesheet" href="assets/css/main.css" />
<link rel="stylesheet" href="assets/css/theme-dogfather.css" />
<link rel="stylesheet" href="assets/css/theme-hasidog.css" />
<link rel="stylesheet" href="assets/css/theme-spicymedia.css" />
<style>
/* =====================================================================
Preis-/Anmelde-Kiste — komplett neu gestaltet (Nutzer-Feedback
03.08.2026: "das sieht ja richtig kake aus"). Ziel: dasselbe edle
Gold-Motiv wie beim Nav-Abo-Knopf/.btn-silver, klare visuelle
Hierarchie (Preis dominiert, Bedingungen dezent, Formular großzügig),
spürbar mehr Luft zwischen den Elementen statt der bisherigen dichten
Textwand. Bewusst KEIN max-width auf der Box selbst — soll exakt so
breit sein wie der umgebende .container (1180px), siehe Kommentar
unten bei .abo-preis-box.
===================================================================== */
.abo-preis-box {
width: 100%;
text-align: center;
position: relative;
isolation: isolate;
overflow: hidden;
padding: 2.6rem clamp(1.4rem, 5vw, 3.2rem) 3rem;
border: 1.5px solid rgba(212,175,55,.45);
background:
radial-gradient(circle at 22% 0%, rgba(212,175,55,.16), transparent 55%),
radial-gradient(circle at 82% 100%, rgba(139,92,246,.12), transparent 55%),
linear-gradient(180deg, rgba(23,27,33,.96), rgba(15,17,21,.98));
box-shadow: 0 0 0 1px rgba(212,175,55,.06) inset, 0 30px 60px -30px rgba(0,0,0,.6);
}
/* Feiner, ruhig schimmernder Goldrand oben — reines Deko-Element, kein
rotierendes Objekt (siehe dokumentierte Lektion: rotierende Ringe auf
nicht-runden Formen verzerren sich, deshalb hier nur ein sanftes
Auf-und-Ab-Glühen statt einer Drehung). */
.abo-preis-box::before {
content: "";
position: absolute; top: 0; left: 10%; right: 10%; height: 1px; z-index: 2;
background: linear-gradient(90deg, transparent, rgba(255,214,102,.9), transparent);
animation: abo-goldglanz 4.5s ease-in-out infinite;
}
@keyframes abo-goldglanz { 0%, 100% { opacity: .35; } 50% { opacity: 1; } }
/* Logo als leuchtendes Wasserzeichen im Kartenhintergrund (Nutzer-Wunsch
03.08.2026: "mein Logo integriert, als Hintergrund, richtig geil,
soll so geil dass man nicht davon wegkommt"). Freigestelltes Logo
(logo-dogfather-transparent.png, siehe gate.html-Lektion: Original
hatte einen weißen Hintergrund eingebrannt, hier bereits freigestellt)
— groß, mittig, mit pulsierender Gold/Lila-Glut dahinter. Sitzt per
z-index HINTER dem echten Karteninhalt (Preis/Formular), damit nichts
an Lesbarkeit verliert; .abo-preis-box hat dafür isolation:isolate +
overflow:hidden bekommen, damit die Glut nicht über den Kartenrand
hinausblutet (dieselbe dokumentierte Lektion wie beim TikTok-Button-
Glow). Bewusst KEINE Rotation des Logos selbst (nur Skalieren/
Verblassen) — ein Markenlogo, das sich dreht, würde zeitweise auf dem
Kopf stehen. */
.abo-preis-box .abo-logo-glut {
position: absolute; inset: -10%; z-index: -1; pointer-events: none;
background:
radial-gradient(circle at 50% 28%, rgba(255,233,168,.4) 0%, rgba(212,175,55,.16) 32%, transparent 62%),
radial-gradient(circle at 22% 75%, rgba(139,92,246,.22), transparent 55%),
radial-gradient(circle at 80% 80%, rgba(143,217,234,.16), transparent 55%);
animation: abo-logo-glut-puls 5s ease-in-out infinite;
}
@keyframes abo-logo-glut-puls { 0%, 100% { opacity: .75; } 50% { opacity: 1; } }
.abo-preis-box .abo-logo-wz {
/* Bewusst NICHT inset:0 über die ganze (sehr hohe) Karte — dadurch
wären background-position/mask-Prozentwerte relativ zur kompletten
Kartenhöhe (inkl. Formular) berechnet und kaum kontrollierbar. Eine
feste Zone oben (deckt Badge/Preis/Bedingungen ab) macht Position
und Ausblenden vorhersagbar und garantiert, dass die Eingabefelder
darunter sauber lesbar bleiben (Nutzer-Feedback: Logo lag vorher
über dem Namensfeld). */
position: absolute; top: 0; left: 0; right: 0; height: 420px; z-index: -1; pointer-events: none;
background-image: url('assets/img/logo-dogfather-transparent.png');
background-repeat: no-repeat;
background-position: center 6%;
background-size: min(62%, 320px) auto;
opacity: .4;
filter: drop-shadow(0 0 28px rgba(255,233,168,.65)) drop-shadow(0 0 56px rgba(139,92,246,.4));
-webkit-mask-image: linear-gradient(to bottom, #000 0%, #000 45%, transparent 92%);
mask-image: linear-gradient(to bottom, #000 0%, #000 45%, transparent 92%);
animation: abo-logo-wz-atem 6s ease-in-out infinite;
}
@keyframes abo-logo-wz-atem {
0%, 100% { opacity: .32; transform: scale(.99); }
50% { opacity: .48; transform: scale(1.03); }
}
@media (prefers-reduced-motion: reduce) {
.abo-preis-box .abo-logo-glut, .abo-preis-box .abo-logo-wz, .abo-preis-box::before { animation: none; }
}
.abo-preis-box .eyebrow {
display: inline-flex; align-items: center; gap: .5rem;
color: #ffe9a8; border-color: rgba(255,214,102,.5);
font-size: 1.3rem; letter-spacing: .1em;
}
.abo-preis-zahl {
font-size: clamp(2.6rem, 5vw, 3.4rem); font-weight: 800; color: #ffe9a8;
margin: .6rem 0 .2rem; letter-spacing: -.01em;
text-shadow: 0 0 28px rgba(255,214,102,.35);
}
.abo-preis-zahl small { font-size: 1.05rem; font-weight: 600; color: var(--text-muted); letter-spacing: 0; text-shadow: none; }
.abo-bedingungen {
list-style: none; padding: 0; text-align: left; max-width: 460px;
margin: 1.6rem auto 0; display: flex; flex-direction: column; gap: .55rem;
}
.abo-bedingungen li {
display: flex; align-items: flex-start; gap: .6rem;
color: var(--text-muted); font-size: .96rem; line-height: 1.5;
}
.abo-bedingungen li::before {
content: "✓"; flex-shrink: 0; width: 1.35rem; height: 1.35rem; margin-top: .05rem;
display: inline-flex; align-items: center; justify-content: center;
border-radius: 50%; font-size: .78rem; font-weight: 800;
color: #0b0d10; background: linear-gradient(135deg, #ffe9a8, #d4af37);
}
/* Widerrufsrecht-Checkbox (siehe agb.html Ziffer 6): NICHT vorausgewählt,
sperrt die PayPal-Zahlungsoptionen optisch + funktional (pointer-events),
bis sie aktiv angehakt wurde. */
.abo-widerruf-check {
display: flex; align-items: flex-start; gap: .65rem; text-align: left;
max-width: 460px; margin: 0 auto 1.1rem; padding: .85rem .95rem; border-radius: 12px;
background: rgba(255,255,255,.03); border: 1.5px solid rgba(139,92,246,.35);
font-size: .85rem; line-height: 1.5; color: var(--text-muted); cursor: pointer;
}
.abo-widerruf-check input[type="checkbox"] {
flex-shrink: 0; width: 1.15rem; height: 1.15rem; margin-top: .15rem; cursor: pointer; accent-color: #8b5cf6;
}
.abo-widerruf-check a { color: var(--accent); }
#paypal-button-container.paypal-gesperrt { opacity: .35; filter: grayscale(1); pointer-events: none; min-height: 45px; }
#paypal-gesperrt-hinweis { text-align: center; margin-top: .5rem; }
.abo-panel { max-width: 440px; margin: 2.2rem auto 0; }
.abo-panel[hidden] { display: none; }
.abo-field { margin-bottom: 1.2rem; text-align: left; }
.abo-field label {
display: block; font-size: .82rem; font-weight: 600; letter-spacing: .02em;
color: var(--text-muted); margin-bottom: .45rem;
}
.abo-field input {
display: block; width: 100%; box-sizing: border-box;
padding: .9rem 1.05rem; border-radius: 12px;
background: rgba(255,255,255,.035); border: 1.5px solid var(--border); color: var(--text);
font-size: 1.02rem; transition: border-color .15s ease, box-shadow .15s ease, background .15s ease;
}
.abo-field input::placeholder { color: rgba(154,164,178,.55); }
.abo-field input:focus {
outline: none; border-color: rgba(212,175,55,.7); background: rgba(255,255,255,.055);
box-shadow: 0 0 0 4px rgba(212,175,55,.12);
}
/* Registrieren/Login-Knöpfe: eigener Gold-Foil-Stil statt des generischen
.btn-primary (Nutzer-Feedback 03.08.2026: "viel spezieller" + Text
zentriert). Gleiche sichere Technik wie überall im Projekt — die
Fläche schimmert per background-position, NICHT per rotierendem Ring
(der würde auf dieser Pillenform verzerren, siehe dokumentierte
TikTok-Button-Lektion). */
.abo-panel .btn {
position: relative; isolation: isolate; overflow: hidden;
display: flex; align-items: center; justify-content: center;
padding: 1rem 1.4rem; border-radius: 14px; font-weight: 800; font-size: 1.04rem;
color: #1a1408; text-decoration: none; cursor: pointer;
border: 1.5px solid rgba(255,233,168,.65);
background: linear-gradient(120deg, #ffe9a8 0%, #d4af37 30%, #ffe9a8 55%, #fff2c9 78%, #d4af37 100%);
background-size: 280% 100%;
animation: abo-btn-shine 6s ease-in-out infinite;
box-shadow: 0 10px 26px -12px rgba(212,175,55,.55);
transition: transform .2s ease, box-shadow .2s ease;
}
.abo-panel .btn::before { content: none; }
.abo-panel .btn::after {
content: ""; position: absolute; inset: 0; z-index: 1;
background: linear-gradient(100deg, transparent 30%, rgba(255,255,255,.85) 48%, transparent 66%);
background-size: 240% 100%;
mix-blend-mode: overlay;
animation: abo-btn-glare 3.2s ease-in-out infinite;
pointer-events: none;
}
.abo-panel .btn:hover {
transform: translateY(-3px) scale(1.015);
box-shadow: 0 16px 34px -10px rgba(212,175,55,.65), 0 0 26px rgba(212,175,55,.4);
}
@keyframes abo-btn-shine { 0%, 100% { background-position: 0% 50%; } 50% { background-position: 100% 50%; } }
@keyframes abo-btn-glare { 0% { background-position: -80% 0; } 100% { background-position: 180% 0; } }
@media (prefers-reduced-motion: reduce) { .abo-panel .btn { animation: none; } .abo-panel .btn::after { animation: none; } }
.abo-fehler { color: #ff9a9a; font-size: .88rem; margin: .8rem 0 0; display: none; }
.abo-fehler.zeige { display: block; }
.abo-erfolg { color: #baf7d6; font-size: .88rem; margin: .8rem 0 0; display: none; }
.abo-erfolg.zeige { display: block; }
.abo-switch { text-align: center; margin-top: 1.4rem; font-size: .92rem; color: var(--text-muted); }
.abo-switch a { color: var(--accent); cursor: pointer; font-weight: 600; }
.abo-switch a:hover { text-decoration: underline; }
.abo-oder {
display: flex; align-items: center; gap: .8rem;
color: var(--text-muted); font-size: .78rem; text-transform: uppercase; letter-spacing: .08em;
margin: .3rem 0 1.4rem;
}
.abo-oder::before, .abo-oder::after { content: ""; flex: 1; height: 1px; background: var(--border); }
/* Google liefert seinen Knopf als eigenes iframe aus — die Innenfarben
(Schwarz/Weiß/Blau) lassen sich aus Sicherheitsgründen NICHT per CSS
umfärben. "Größer und passend zur Seite" wird deshalb über einen
eigenen Goldrahmen drumherum gelöst (derselbe Schimmer-Trick wie beim
Preis-Rahmen) plus einer Vergrößerung des Google-Knopfs selbst per
transform:scale — der Knopf bleibt dabei voll funktionsfähig, es wird
nur optisch skaliert. */
.abo-google-frame {
display: flex; justify-content: center; margin: 0 auto 1.3rem; padding: .55rem 0;
border-radius: 999px; border: 1.5px solid transparent;
background: linear-gradient(rgba(20,23,29,.5), rgba(20,23,29,.5)) padding-box,
linear-gradient(120deg, #d4af37, #ffe9a8, #d4af37, #fff2c9) border-box;
background-size: 100% 100%, 260% 100%;
animation: abo-btn-shine 6s ease-in-out infinite;
box-shadow: 0 10px 26px -12px rgba(212,175,55,.5);
}
.abo-google-frame > div { transform: scale(1.18); transform-origin: center; }
.abo-vorteile { max-width: 520px; margin: 1.6rem auto 0; display: flex; flex-direction: column; gap: .6rem; }
.abo-vorteile li { display: flex; gap: .65rem; align-items: baseline; color: var(--text-muted); font-size: .97rem; line-height: 1.5; }
.abo-vorteile li::before { content: "👑"; flex-shrink: 0; }
</style>
</head>
<body class="mit-hintergrund" style="--page-bg:url('/assets/img/bg-abonnieren.jpg');--page-bg-mobile:url('/assets/img/bg-abonnieren-mobile.jpg');">
<div id="site-header"></div>
<main>
<section class="hero page-bg">
<div class="hero-banner"><img src="/assets/img/bg-abonnieren.jpg" alt="Dogfather Supporter-Abo" loading="eager" /></div>
<div class="container">
<span class="eyebrow" data-i18n="ab_eyebrow">👑 DogiCrew 🩵</span>
<h1 data-i18n="ab_h1">Mehr als ein Abo — deine Unterstützung wird Teil unserer Geschichte</h1>
<p class="lead worlds" data-i18n="ab_lead">Kein gewöhnlicher Shop. Ein exklusives Dankeschön- und Treueprogramm für alle, die Dogfather dauerhaft unterstützen.</p>
</div>
</section>
<section class="section-tight">
<div class="container">
<div class="card abo-preis-box">
<div class="abo-logo-glut" aria-hidden="true"></div>
<div class="abo-logo-wz" aria-hidden="true"></div>
<span class="eyebrow" data-i18n="ab_preis_eyebrow">DogiCrew 🩵</span>
<div class="abo-preis-zahl">4,99 € <small data-i18n="ab_preis_pro_monat">/ Monat</small></div>
<p class="small muted" style="margin-top:-.6rem;margin-bottom:1rem;">Keine gesondert ausgewiesene MwSt. gemäß Kleinunternehmerregelung (Art. 57 des luxemburgischen TVA-Gesetzes) — keine weiteren Kosten.</p>
<ul class="abo-bedingungen">
<li data-i18n="ab_bed1">Monatliche automatische Zahlung über PayPal</li>
<li data-i18n="ab_bed2">Keine Mindestlaufzeit, jederzeit kündbar</li>
<li data-i18n="ab_bed3">Kündigung zum Ende des bereits bezahlten Zeitraums</li>
<li data-i18n="ab_bed4">Keine versteckten Zusatzkosten</li>
</ul>
<!-- Zustand 1: lädt (kurz, bis localStorage/Session geprüft ist) -->
<div class="abo-panel" id="panel-lade">
<p class="small" data-i18n="ab_laedt">Einen Moment …</p>
</div>
<!-- Professioneller Login: Google, sitzt über Registrierung/Login und
wird zusammen mit ihnen ein-/ausgeblendet (siehe Skript unten).
Ohne konfigurierte GOOGLE_CLIENT_ID bleibt der Bereich leer/
unsichtbar — der normale E-Mail-Code-Weg funktioniert immer. -->
<div class="abo-panel" id="panel-social-login" hidden>
<!-- Datenschutz: Googles Skript (und damit eine Verbindung/IP-Übertragung
zu Google) wird bewusst NICHT automatisch beim Seitenaufruf geladen,
sondern erst nach explizitem Klick hier — echtes Opt-in statt
versteckter Drittanbieter-Verbindung vor jeder Zustimmung. -->
<div id="google-consent-wrap" style="text-align:center;margin-bottom:1.1rem;" hidden>
<button type="button" id="google-consent-btn" class="btn btn-primary" style="width:100%;display:inline-flex;align-items:center;justify-content:center;gap:.6rem;">
<svg width="20" height="20" viewBox="0 0 48 48" aria-hidden="true" style="flex-shrink:0;">
<path fill="#FFC107" d="M43.611,20.083H42V20H24v8h11.303c-1.649,4.657-6.08,8-11.303,8c-6.627,0-12-5.373-12-12s5.373-12,12-12c3.059,0,5.842,1.154,7.961,3.039l5.657-5.657C34.046,6.053,29.268,4,24,4C12.955,4,4,12.955,4,24s8.955,20,20,20s20-8.955,20-20C44,22.659,43.862,21.35,43.611,20.083z"/>
<path fill="#FF3D00" d="M6.306,14.691l6.571,4.819C14.655,15.108,18.961,12,24,12c3.059,0,5.842,1.154,7.961,3.039l5.657-5.657C34.046,6.053,29.268,4,24,4C16.318,4,9.656,8.337,6.306,14.691z"/>
<path fill="#4CAF50" d="M24,44c5.166,0,9.86-1.977,13.409-5.192l-6.19-5.238C29.211,35.091,26.715,36,24,36c-5.202,0-9.619-3.317-11.283-7.946l-6.522,5.025C9.505,39.556,16.227,44,24,44z"/>
<path fill="#1976D2" d="M43.611,20.083H42V20H24v8h11.303c-0.792,2.237-2.231,4.166-4.087,5.571c0.001-0.001,0.002-0.001,0.003-0.002l6.19,5.238C36.971,39.205,44,34,44,24C44,22.659,43.862,21.35,43.611,20.083z"/>
</svg>
<span data-i18n="ab_google_consent_btn">Mit Google anmelden</span>
</button>
<p class="small muted" style="margin-top:.5rem;" data-i18n="ab_google_consent_hint">Beim Klick wird eine Verbindung zu Google hergestellt (deine IP-Adresse wird dabei übertragen).</p>
</div>
<div class="abo-google-frame" id="google-frame-wrap" hidden>
<div id="google-signin-button"></div>
</div>
<div class="abo-oder" data-i18n="ab_oder_email">oder mit E-Mail</div>
</div>
<!-- Zustand 2: Registrierung -->
<div class="abo-panel" id="panel-register" hidden>
<div class="abo-field">
<label for="reg-name" data-i18n="ab_feld_name">Name oder Anzeigename</label>
<input type="text" id="reg-name" maxlength="60" />
</div>
<div class="abo-field">
<label for="reg-tiktok" data-i18n="ab_feld_tiktok">TikTok-Benutzername</label>
<input type="text" id="reg-tiktok" placeholder="@benutzername" maxlength="40" />
</div>
<div class="abo-field">
<label for="reg-email" data-i18n="ab_feld_email">E-Mail-Adresse</label>
<input type="email" id="reg-email" maxlength="120" />
</div>
<button type="button" class="btn btn-primary" style="width:100%;" id="btn-register" data-i18n="ab_btn_register">Registrieren</button>
<p class="abo-fehler" id="register-fehler"></p>
<p class="abo-switch"><a id="switch-to-login" data-i18n="ab_switch_login">Schon Supporter? Hier einloggen</a></p>
</div>
<!-- Zustand 3: Login (E-Mail-Code anfordern) -->
<div class="abo-panel" id="panel-login" hidden>
<div class="abo-field">
<label for="login-email" data-i18n="ab_feld_email">E-Mail-Adresse</label>
<input type="email" id="login-email" maxlength="120" />
</div>
<button type="button" class="btn btn-primary" style="width:100%;" id="btn-login-request" data-i18n="ab_btn_login_code">Login-Code anfordern</button>
<p class="abo-fehler" id="login-fehler"></p>
<p class="abo-switch"><a id="switch-to-register" data-i18n="ab_switch_register">Noch kein Konto? Jetzt registrieren</a></p>
</div>
<!-- Zustand 4: Code-Eingabe (nach Registrierung ODER Login-Anfrage) -->
<div class="abo-panel" id="panel-code" hidden>
<p class="small" id="code-hinweis" data-i18n="ab_code_hinweis">Wir haben dir einen 6-stelligen Code per E-Mail geschickt.</p>
<div class="abo-field">
<label for="code-input" data-i18n="ab_feld_code">Code</label>
<input type="text" id="code-input" inputmode="numeric" maxlength="6" style="letter-spacing:4px;font-size:1.3rem;text-align:center;" />
</div>
<button type="button" class="btn btn-primary" style="width:100%;" id="btn-code-verify" data-i18n="ab_btn_code_verify">Bestätigen</button>
<p class="abo-fehler" id="code-fehler"></p>
</div>
<!-- Zustand 5: eingeloggt, noch kein Abo -> PayPal Smart Buttons.
Zeigt automatisch alle für die Käuferin/den Käufer verfügbaren
Zahlarten (PayPal-Konto, Kreditkarte als Gast, je nach Land) —
das Geld landet dabei direkt auf Dogis eigenem PayPal-Konto. -->
<div class="abo-panel" id="panel-subscribe" hidden>
<p class="abo-erfolg zeige" data-i18n="ab_eingeloggt_als">Eingeloggt.</p>
<!-- Button-Lösung (§ 312j BGB / entspr. Regelung): Preis- und
Zahlungspflicht-Hinweis unmittelbar vor der Zahlung. -->
<p class="small" style="text-align:center;font-weight:700;margin-bottom:.8rem;">4,99 € / Monat · zahlungspflichtiges Abo · monatlich kündbar</p>
<!-- Widerrufsrecht bei digitalen Inhalten (§ 356 Abs. 5 BGB /
entspr. Regelung, siehe agb.html Ziffer 6): ohne aktives
Ankreuzen bleibt der Zahlungsbereich gesperrt, es gibt keine
Zahlung ohne diese ausdrückliche, nicht vorausgewählte
Zustimmung. -->
<label class="abo-widerruf-check" for="widerruf-consent">
<input type="checkbox" id="widerruf-consent" />
<span>Ich wünsche ausdrücklich, dass der Zugang zum Supporter-Bereich sofort mit Vertragsschluss beginnt, und weiß, dass mein 14-tägiges Widerrufsrecht dadurch erlischt, sobald der Zugang vollständig bereitgestellt ist (Details in den <a href="agb.html" target="_blank" rel="noopener">AGB</a>, Ziffer 6).</span>
</label>
<div id="paypal-button-container" class="paypal-gesperrt"></div>
<p class="small muted" id="paypal-gesperrt-hinweis">Bitte bestätige oben die Checkbox, um die Zahlungsoptionen freizuschalten.</p>
<p class="small" id="paypal-laedt" data-i18n="ab_paypal_laedt" hidden>Zahlungsoptionen werden geladen …</p>
<p class="abo-fehler" id="subscribe-fehler"></p>
</div>
<!-- Zustand 6: bereits Supporter -->
<div class="abo-panel" id="panel-already" hidden>
<p class="abo-erfolg zeige" data-i18n="ab_bereits_supporter">Du bist bereits Supporter! 🩵</p>
<a class="btn btn-primary" style="width:100%;" href="supporter.html" data-i18n="ab_btn_zum_bereich">Zum Supporter-Bereich</a>
</div>
</div>
</div>
</section>
<section class="section-tight">
<div class="container grid grid-2">
<div class="card">
<p data-i18n="ab_text1">Dieses Abonnement ist kein gewöhnlicher Shop und kein einfacher Kauf. Es ist für die Menschen gedacht, die Dogfather dauerhaft unterstützen und ein besonderer Teil dieser gemeinsamen Reise sein möchten.</p>
<p data-i18n="ab_text2">Für 4,99 € im Monat erhältst du Zugang zu einem exklusiven Supporter-Bereich, besonderen Inhalten und einer persönlichen Treuekollektion. Mit jedem erfolgreich bezahlten Meilenstein wächst deine Sammlung: vom kleinen Hasen-Teddy über besondere Jubiläumsprämien bis zum exklusiven Hoodie nach 30 Monaten. Danach beginnt für dich eine neue Kollektion — mit neuen Designs, neuen Erinnerungen und derselben Bedeutung.</p>
<ul class="abo-vorteile">
<li data-i18n="ab_vorteil1">Exklusiver Supporter-Bereich</li>
<li data-i18n="ab_vorteil2">Kleiner Hasen-Teddy nach 6 bezahlten Monaten</li>
<li data-i18n="ab_vorteil3">Mittelgroßer Hasen-Teddy nach 12 bezahlten Monaten</li>
<li data-i18n="ab_vorteil4">Großer Hasen-Teddy nach 18 bezahlten Monaten</li>
<li data-i18n="ab_vorteil5">Tasse &amp; Autogrammkarte nach 24 bezahlten Monaten</li>
<li data-i18n="ab_vorteil6">Exklusiver Hoodie nach 30 bezahlten Monaten</li>
<li data-i18n="ab_vorteil7">Neue Supporter-Kollektion nach jedem abgeschlossenen Zyklus</li>
</ul>
</div>
<div class="card">
<h2 data-i18n="ab_vanvan_h2">Die Teddy-Kollektion — in Kooperation mit VanVan</h2>
<p data-i18n="ab_vanvan_text">Die DogiCrew 🩵 gehört Dogfather. Die Hasen-Teddys und die dazugehörigen Sammlerkollektionen entstehen jedoch in Zusammenarbeit mit VanVan — der rechten Hand von Dogfather, seiner wichtigsten Vertrauensperson und einem festen Bestandteil der Team-Dogi-Familie. Sie stehen für ihre besondere Rolle, den Zusammenhalt innerhalb der Community und die Verbindung zwischen Dogfather, VanVan und allen Menschen, die diesen gemeinsamen Weg dauerhaft unterstützen.</p>
<div style="display:flex;justify-content:flex-end;margin-top:1.4rem;">
<a class="btn-silver" href="#" aria-disabled="true" onclick="return false;"><span class="btn-silver-spark" aria-hidden="true"></span><span class="btn-silver-text" data-i18n="ab_kollektion_coming_soon">Coming soon…</span><span class="btn-silver-spark" aria-hidden="true"></span></a>
</div>
</div>
</div>
</section>
</main>
<div id="site-footer"></div>
<script src="assets/js/i18n-abonnieren.js"></script>
<script src="assets/js/supporter.js"></script>
<script src="assets/js/main.js"></script>
<script>
(function () {
const S = window.DogiSupporter;
const panels = ["panel-lade", "panel-register", "panel-login", "panel-code", "panel-subscribe", "panel-already"];
// panel-social-login (Google-Button) hängt sich an register/login dran,
// ist aber kein "richtiger" exklusiver Zustand — separat gesteuert.
const SOCIAL_LOGIN_PANELS = ["panel-register", "panel-login"];
let publicConfig = {
googleClientId: null,
paypalClientId: null, paypalPlanId: null,
};
function irgendeinSocialLoginAktiv() {
return !!publicConfig.googleClientId;
}
function zeige(id) {
panels.forEach((p) => { document.getElementById(p).hidden = p !== id; });
const socialArea = document.getElementById("panel-social-login");
socialArea.hidden = !(irgendeinSocialLoginAktiv() && SOCIAL_LOGIN_PANELS.includes(id));
// Bugfix/Rechts-Update 04.08.2026: PayPal-Zahlungsoptionen werden NICHT
// mehr automatisch beim Anzeigen dieser Kiste geladen — erst nach
// aktivem Ankreuzen der Widerrufsrecht-Checkbox (siehe
// widerrufCheckbox-Listener unten). Bei jedem erneuten Aufruf dieser
// Kiste wird die Checkbox zurückgesetzt, die Zustimmung gilt immer nur
// für den jeweils aktuellen Besuch.
if (id === "panel-subscribe") {
const check = document.getElementById("widerruf-consent");
if (check) check.checked = false;
document.getElementById("paypal-button-container").classList.add("paypal-gesperrt");
document.getElementById("paypal-gesperrt-hinweis").hidden = false;
}
}
function fehlerZeigen(el, msg) {
el.textContent = msg;
el.classList.add("zeige");
}
function fehlerVerstecken(el) {
el.classList.remove("zeige");
}
let codePurpose = "verify_email"; // oder "login"
let codeEmail = "";
async function pruefeStatus() {
if (!S.getToken()) {
zeige("panel-register");
return;
}
try {
const data = await S.apiFetch("/supporter/me", {}, true);
const status = data.subscription?.status || "none";
S.cacheSubStatus(status);
S.cacheDisplayName(data.profile?.displayName || "");
if (["active", "pending", "suspended", "cancelled"].includes(status)) {
zeige("panel-already");
} else {
zeige("panel-subscribe");
}
} catch (err) {
// Token ungültig/abgelaufen -> zurück zur Registrierung/Login
S.clearToken();
zeige("panel-register");
}
}
/* ---------- "Mit Google anmelden" (professioneller Login, Abschnitt
"screen1" Feedback vom 03.08.2026) — komplett optional, taucht nur
auf, wenn der Websitebetreiber eine GOOGLE_CLIENT_ID hinterlegt hat.
Datenschutz (Nachtrag 04.08.2026): Googles Skript wird NICHT mehr
automatisch beim Seitenaufruf nachgeladen — das würde eine Verbindung
zu Google (inkl. IP-Übertragung) herstellen, bevor der/die Besucher:in
überhaupt zugestimmt hat. Stattdessen zeigt initGoogleConsent() nur
einen eigenen, klar beschrifteten Button; erst der echte Klick darauf
lädt Googles Skript und rendert deren echten Button (initGoogleSignIn). */
function initGoogleConsent() {
const wrap = document.getElementById("google-consent-wrap");
const btn = document.getElementById("google-consent-btn");
if (!publicConfig.googleClientId || !wrap || !btn) return;
wrap.hidden = false;
btn.addEventListener("click", () => {
wrap.hidden = true;
document.getElementById("google-frame-wrap").hidden = false;
initGoogleSignIn();
}, { once: true });
}
function initGoogleSignIn() {
if (!publicConfig.googleClientId) return;
const script = document.createElement("script");
script.src = "https://accounts.google.com/gsi/client";
script.async = true;
script.defer = true;
script.onload = () => {
window.google.accounts.id.initialize({
client_id: publicConfig.googleClientId,
callback: handleGoogleCredential,
});
window.google.accounts.id.renderButton(document.getElementById("google-signin-button"), {
type: "standard", theme: "filled_black", size: "large", shape: "pill", text: "continue_with", width: 340,
});
};
document.head.appendChild(script);
}
async function handleGoogleCredential(response) {
const el = document.getElementById("register-fehler");
fehlerVerstecken(el);
try {
const data = await S.apiFetch("/supporter/google-login", { credential: response.credential });
S.setToken(data.token);
await pruefeStatus();
} catch (err) {
fehlerZeigen(el, err.message);
}
}
/* ---------- PayPal Smart Payment Buttons (Abschnitt "screen2" Feedback
vom 03.08.2026: alle in Deutschland üblichen Zahlarten anzeigen — das
übernimmt PayPal automatisch, sobald die echten Buttons statt einer
reinen Weiterleitung genutzt werden). ---------- */
let paypalSdkGeladen = false;
// Zeitpunkt der Widerrufsrecht-Zustimmung (siehe Checkbox-Listener weiter
// unten) — wird beim Abschluss an den Server mitgegeben, damit ein
// Zeitstempel-Nachweis existiert (siehe Datenschutzerklärung Ziffer 7).
let widerrufConsentAt = null;
function ladePaypalButtons() {
const fehlerEl = document.getElementById("subscribe-fehler");
const ladeHinweis = document.getElementById("paypal-laedt");
fehlerVerstecken(fehlerEl);
ladeHinweis.hidden = false;
ladeHinweis.textContent = "Zahlungsoptionen werden geladen …";
if (!publicConfig.paypalClientId || !publicConfig.paypalPlanId) {
ladeHinweis.textContent = "Das Bezahlsystem wird gerade eingerichtet — bitte später erneut versuchen.";
return;
}
if (paypalSdkGeladen) {
renderPaypalButtons();
return;
}
const script = document.createElement("script");
script.src = `https://www.paypal.com/sdk/js?client-id=${encodeURIComponent(publicConfig.paypalClientId)}&vault=true&intent=subscription&currency=EUR&locale=de_DE`;
script.onload = () => { paypalSdkGeladen = true; renderPaypalButtons(); };
script.onerror = () => { ladeHinweis.textContent = "PayPal konnte nicht geladen werden. Bitte Seite neu laden."; ladeHinweis.hidden = false; };
document.body.appendChild(script);
}
function renderPaypalButtons() {
const container = document.getElementById("paypal-button-container");
const ladeHinweis = document.getElementById("paypal-laedt");
container.innerHTML = "";
window.paypal
.Buttons({
style: { shape: "pill", color: "gold", layout: "vertical", label: "subscribe" },
createSubscription: (data, actions) => actions.subscription.create({ plan_id: publicConfig.paypalPlanId }),
onApprove: async (data) => {
const fehlerEl = document.getElementById("subscribe-fehler");
try {
await S.apiFetch("/supporter/paypal/confirm", { subscriptionId: data.subscriptionID, widerrufConsentAt }, true);
await pruefeStatus();
} catch (err) {
fehlerZeigen(fehlerEl, err.message);
}
},
onError: (err) => {
fehlerZeigen(document.getElementById("subscribe-fehler"), "PayPal-Fehler: " + (err?.message || "Unbekannter Fehler."));
},
})
.render("#paypal-button-container");
ladeHinweis.hidden = true;
}
document.getElementById("switch-to-login").addEventListener("click", () => zeige("panel-login"));
document.getElementById("switch-to-register").addEventListener("click", () => zeige("panel-register"));
// Widerrufsrecht-Checkbox: erst nach aktivem Ankreuzen werden die
// PayPal-Zahlungsoptionen überhaupt geladen/klickbar (siehe agb.html
// Ziffer 6 + Datenschutzerklärung Ziffer 7). Beim Abwählen wird alles
// wieder gesperrt und der Zeitstempel verworfen.
document.getElementById("widerruf-consent").addEventListener("change", (e) => {
const container = document.getElementById("paypal-button-container");
const gesperrtHinweis = document.getElementById("paypal-gesperrt-hinweis");
if (e.target.checked) {
widerrufConsentAt = new Date().toISOString();
container.classList.remove("paypal-gesperrt");
gesperrtHinweis.hidden = true;
ladePaypalButtons();
} else {
widerrufConsentAt = null;
container.classList.add("paypal-gesperrt");
gesperrtHinweis.hidden = false;
}
});
document.getElementById("btn-register").addEventListener("click", async () => {
const el = document.getElementById("register-fehler");
fehlerVerstecken(el);
const displayName = document.getElementById("reg-name").value.trim();
const tiktokUsername = document.getElementById("reg-tiktok").value.trim();
const email = document.getElementById("reg-email").value.trim();
if (!displayName || !email) return fehlerZeigen(el, "Bitte Name und E-Mail-Adresse angeben.");
try {
await S.apiFetch("/supporter/register", { displayName, tiktokUsername, email });
codePurpose = "verify_email";
codeEmail = email;
zeige("panel-code");
} catch (err) {
fehlerZeigen(el, err.message);
}
});
document.getElementById("btn-login-request").addEventListener("click", async () => {
const el = document.getElementById("login-fehler");
fehlerVerstecken(el);
const email = document.getElementById("login-email").value.trim();
if (!email) return fehlerZeigen(el, "Bitte E-Mail-Adresse angeben.");
try {
await S.apiFetch("/supporter/login-request", { email });
codePurpose = "login";
codeEmail = email;
zeige("panel-code");
} catch (err) {
fehlerZeigen(el, err.message);
}
});
document.getElementById("btn-code-verify").addEventListener("click", async () => {
const el = document.getElementById("code-fehler");
fehlerVerstecken(el);
const code = document.getElementById("code-input").value.trim();
if (!code) return fehlerZeigen(el, "Bitte Code eingeben.");
try {
const path = codePurpose === "login" ? "/supporter/verify-login" : "/supporter/verify-email";
const data = await S.apiFetch(path, { email: codeEmail, code });
S.setToken(data.token);
await pruefeStatus();
} catch (err) {
fehlerZeigen(el, err.message);
}
});
async function init() {
try {
const res = await fetch(`${S.API_BASE}/supporter/public-config`);
const data = await res.json();
if (data.ok) publicConfig = data;
} catch {
/* Konfiguration konnte nicht geladen werden — Google-Button/PayPal-Buttons bleiben dann aus. */
}
initGoogleConsent();
await pruefeStatus();
}
init();
})();
</script>
</body>
</html>