Die zweite Sitzung hat in den Praesentationen des Vaults 83 Stellen
gefunden — und damit auf Loecher in MEINER Wache gezeigt. Ich habe
sie nachgemessen, alle drei waren echt.
LOCH 1 — SIE SAH NUR `server/workspace-*.js`
Also ausgerechnet nicht `workspace.js`, die groesste Datei des
Hauses. Der weitere Filter fand dort sofort drei Stellen:
workspace.js:3404 Kanal „Chat-Moderation" (Protokoll)
workspace.js:3422 „${titel}" -> ${haus} (Protokoll)
workspace.js:3304 „${… || "ohne Titel"}" (siehe Loch 3)
Das ist heute der DRITTE Fall von „die Wache kennt nur die halbe
Menge" — nach pruef-struktur (sah nur die Pruefdateien, nicht die
Anwendung) und pruef-fingermass (sah keine variable Breite).
LOCH 2 — IHR AUSDRUCK GILT JE ZEILE
Ein `„`, das erst in der naechsten Zeile mit einem geraden `"`
schliesst, fiel durch. Gemessen: drei echte Faelle, zwei davon
sichtbarer Seitentext.
workspace/leistung.html „nicht / zugeordnet"
workspace/leistung.html „Backstage-Tabelle / einfuegen"
workspace/assets/js/ampel.js „noch ' + 'verbessern"
Beim letzten laeuft das Zitat ueber eine Zeichenketten-Verkettung.
Neue Regel ohne Fehlalarme: erst alle RICHTIG geschlossenen Paare
entfernen (auch mehrzeilig), dann die einzeilig falschen (die meldet
die alte Regel). Was danach noch ein `„` hat und binnen drei Zeilen
ein gerades `"`, ist ein Fund. Ausgenommen bleibt das Zeichen ALS
WERT — in `content: "„";` und in den Sprachtabellen ist das `„` der
Inhalt und das `"` die Begrenzung.
LOCH 3 — EINE AUSNAHME, DIE EINEN FUND VERSCHLUCKT HAT
Gefunden durch die ZAHL, nicht durch den Blick: Der weitere Filter
liess die Ausnahmen von 12 auf 13 steigen. Die dreizehnte war
`… „${zeile[titelSpalte] || "ohne Titel"}"`
Der Ausdruck blieb am `"` von `"ohne Titel"` haengen; als Inhalt kam
`${zeile[titelSpalte] || ` heraus, das endet auf ein Leerzeichen,
und damit galt „der Satz geht in der naechsten Zeile weiter". Das
echte Schlusszeichen stand hinter dem `}` und war gerade.
Dass die Ausnahmen gezaehlt UND genannt werden, hat ihn gefunden.
Genau dafuer steht die Zeile dort.
Behoben an der Wurzel: Anfuehrungszeichen innerhalb einer Einsetzung
`${…}` werden vorher durch X ersetzt, bei gleicher Laenge und
gleichen Zeilenumbruechen. Das nimmt einer ganzen Sorte
Fehlklassifizierung die Grundlage — die Ausnahmen fielen danach von
13 auf 11.
UND EIN VIERTES, BEIM MESSEN AUFGEFALLEN
`„Van-Van”` in assets/js/data-modis.js schliesst mit U+201D, dem
ENGLISCHEN Zeichen. Zweimal, beide Male in einer DEUTSCHEN Zeile
(`de:` und `"de-CH":`) — nicht einmal eine Uebersetzung, in der es
richtig waere. Eigene Regel dafuer, die keine Ausnahme braucht: Wer
mit `„` oeffnet, schliesst deutsch; in fremdsprachigen Zeilen steht
gar kein `„` am Anfang.
DIE AUSNAHMEZAHL IST JETZT STRENG. Sie stand auf „hoechstens 12" —
damit waere der Anstieg auf 13 nicht aufgefallen. Jetzt genau 11,
wie bei den Grundlinien in pruef-fingermass.
GEPRUEFT: pruef-struktur 68 -> 75 Pruefungen, 0 Fehler. Dazu
leistung-optik 59/0, ampel 47/0, treff 85/0, modi-verborgen 87/0 —
die Seiten, deren Text ich angefasst habe. Steuerzeichen: 830
Dateien, keines. Beide Stempel gesetzt.
Sechs echte Stellen berichtigt, vier neue Gegenproben.
Co-Authored-By: Claude Opus 5 <[email protected]>
577 lines
24 KiB
HTML
577 lines
24 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>Rabattcodes — DOGFATHER UNIVERSE</title>
|
||
<meta name="description" content="Rabattcodes von Dogis Partnern für Team Dogi — spar bares Geld bei ausgewählten Marken." />
|
||
<link rel="icon" type="image/png" href="/assets/img/app-symbole/universe-32.png?v=202610011927" />
|
||
<link rel="apple-touch-icon" href="/assets/img/app-symbole/universe-180.png?v=202610011927" />
|
||
<link rel="manifest" href="/manifest.json" />
|
||
<meta name="theme-color" content="#065f76" />
|
||
<meta property="og:type" content="website" />
|
||
<meta property="og:site_name" content="DOGFATHER UNIVERSE" />
|
||
<meta property="og:title" content="Rabattcodes — DOGFATHER UNIVERSE" />
|
||
<meta property="og:description" content="Rabattcodes von Dogis Partnern für Team Dogi — spar bares Geld bei ausgewählten Marken." />
|
||
<meta property="og:image" content="https://dogfather-universe.com/assets/img/og-cover.jpg" />
|
||
<meta property="og:url" content="https://dogfather-universe.com/rabattcodes.html" />
|
||
<meta name="twitter:card" content="summary_large_image" />
|
||
<meta name="twitter:title" content="Rabattcodes — DOGFATHER UNIVERSE" />
|
||
<meta name="twitter:description" content="Rabattcodes von Dogis Partnern für Team Dogi — spar bares Geld bei ausgewählten Marken." />
|
||
<meta name="twitter:image" content="https://dogfather-universe.com/assets/img/og-cover.jpg" />
|
||
|
||
<link rel="stylesheet" href="assets/css/main.css?v=202610011927" />
|
||
<link rel="stylesheet" href="assets/css/theme-dogfather.css?v=202610011927" />
|
||
<link rel="stylesheet" href="assets/css/theme-hasidog.css?v=202610011927" />
|
||
<link rel="stylesheet" href="assets/css/theme-spicymedia.css?v=202610011927" />
|
||
<style>
|
||
.code-platzhalter {
|
||
max-width: 620px;
|
||
margin: 0 auto;
|
||
text-align: center;
|
||
}
|
||
|
||
/* Gesperrt-Zustand. Er hängt seit dem 08.09.2026 am KONTO, nicht mehr
|
||
am bezahlten Abo (Filipe: "die partner codes sollen auch schon für
|
||
die leute sichtbar sein die angemeldet sind") — die Begründung steht
|
||
ausführlich beim Skript am Seitenende. Unverändert gilt: dieselbe
|
||
Prüfung wie die Kachel auf links.html, damit der direkte Aufruf
|
||
(Lesezeichen, geteilter Link) genau dasselbe zeigt wie der Knopf
|
||
dort. Zwei Sperren, die auseinanderlaufen, sind schlimmer als eine. */
|
||
.code-gesperrt-siegel {
|
||
width: 96px; height: 96px;
|
||
display: flex; align-items: center; justify-content: center;
|
||
margin: 0 auto 1.4rem;
|
||
font-size: 2.6rem;
|
||
border-radius: 50%;
|
||
background: radial-gradient(circle at 32% 28%, rgba(212,175,55,.35), rgba(11,13,16,.9) 70%);
|
||
border: 1.5px solid rgba(212,175,55,.45);
|
||
box-shadow: 0 0 0 6px rgba(212,175,55,.06), 0 10px 30px rgba(0,0,0,.5);
|
||
}
|
||
|
||
/* =====================================================================
|
||
DER ERSTE ECHTE PARTNERCODE (08.09.2026)
|
||
|
||
Bis heute war das hier eine Platzhalterkachel ("Codes folgen in
|
||
Kürze") mit einem erfundenen Beispielcode. Jetzt steht der erste
|
||
echte drauf: DOGI10 für Van's DIY & Bastelbedarf.
|
||
|
||
⚠️ DIE KONDITIONEN SIND ABGELESEN, NICHT GERATEN.
|
||
|
||
Quelle der Wahrheit ist der Shop, nicht diese Seite:
|
||
/home/vandiy/vans-diy-bastelbedarf/src/content/partnercodes.json
|
||
{ "code": "DOGI10", "prozent": 10, "bis": "2026-09-30",
|
||
"aktiv": true, "giltAufSale": false }
|
||
Ausgewertet wird sie an zwei Stellen mit derselben Regel
|
||
(aktiv !== false UND jetzt <= bis 23:59:59): src/scripts/cart.ts für
|
||
den Warenkorb, server/lib/preis-berechnen.js für den Endpreis.
|
||
|
||
Der naheliegende Weg wäre gewesen, "–10 %" einfach aus dem Namen
|
||
"DOGI10" zu schließen. Das hätte hier zufällig gestimmt und wäre
|
||
trotzdem falsch gewesen: Dass der Code NICHT auf bereits reduzierte
|
||
Artikel gilt (giltAufSale: false) und dass er am 30.09.2026 ausläuft,
|
||
steht im Namen nicht drin. Eine falsche Zusage auf einer
|
||
Verkaufsseite kostet VanVan die Diskussion an der Kasse.
|
||
|
||
Abgeschrieben ist abgeschrieben: Wer die Konditionen ändert, ändert
|
||
sie im Shop UND hier — die Zeile unten rechnet nichts aus, sie sagt
|
||
nur an. Damit das nicht schleichend auseinanderläuft, kennt das
|
||
Skript am Seitenende das Ablaufdatum und schaltet die Karte von
|
||
selbst auf "abgelaufen", statt weiter etwas zu versprechen.
|
||
===================================================================== */
|
||
.rc-partner {
|
||
max-width: 620px;
|
||
margin: 0 auto;
|
||
text-align: center;
|
||
padding: 2.4rem 1.6rem 2rem;
|
||
border-color: rgba(94, 234, 167, .3);
|
||
}
|
||
|
||
/* Eckband wie bei den Feature-Kacheln auf links.html — hier aber ohne
|
||
Rotation und in Silber statt Bunt, damit es dem Siegel nicht die
|
||
Aufmerksamkeit wegnimmt. */
|
||
.rc-band {
|
||
position: absolute;
|
||
top: 1rem; right: 1rem;
|
||
font-size: .64rem;
|
||
font-weight: 800;
|
||
letter-spacing: .09em;
|
||
text-transform: uppercase;
|
||
padding: .36rem .72rem;
|
||
border-radius: 999px;
|
||
background: rgba(8, 10, 14, .6);
|
||
border: 1px solid rgba(255, 255, 255, .24);
|
||
color: #dfe6ef;
|
||
}
|
||
|
||
/* ---- Das Medaillon --------------------------------------------------
|
||
Warum für EIN Logo so viel Aufwand: Es ist das einzige Bild auf der
|
||
Seite und das Gesicht des Partners. Der Weg zu "besonders" führt hier
|
||
NICHT über mehr Farbe — das Siegel ist schwarz-weiß, jede Einfärbung
|
||
würde eine fremde Marke umlackieren. Er führt über mehr MATERIAL: aus
|
||
dem runden Siegel wird eine geprägte Münze, aus sechs Lagen:
|
||
|
||
1. Aura weicher Lichthof dahinter, atmet sehr langsam
|
||
2. Rändel die geriffelte Münzkante (repeating-conic-gradient),
|
||
72 Zähne. Sie steht STILL — eine sich drehende
|
||
Riffelung flimmert bei 148 px, und genau diese grelle
|
||
Optik soll hier nicht sein (Grundregel: augenschonend)
|
||
3. Glanz stattdessen wandert EIN Lichtpunkt in 22 s einmal um
|
||
die Kante. Das ist die Bewegung, die eine Münze im
|
||
Licht macht, und sie ist ruhig genug fürs Auge
|
||
4. Siegel das freigestellte Logo (partner-vandiy.webp)
|
||
5. Schliff Prägekante nach innen (oben Licht, unten Schatten) und
|
||
ein langsamer Lichtstreif über die Fläche
|
||
6. Ablage elliptischer Schatten darunter, damit die Münze auf der
|
||
Karte LIEGT statt zu schweben
|
||
|
||
Alles davon ist reines CSS: kein zweites Bild, kein Skript, keine
|
||
Abhängigkeit. Und alles davon steht still, sobald der Rechner
|
||
"weniger Bewegung" meldet (Block ganz unten). */
|
||
.rc-medaillon {
|
||
position: relative;
|
||
width: clamp(116px, 34vw, 148px);
|
||
aspect-ratio: 1 / 1;
|
||
margin: .2rem auto 1.5rem;
|
||
border-radius: 50%;
|
||
transition: transform .4s cubic-bezier(.22, .9, .3, 1);
|
||
}
|
||
.rc-medaillon > * {
|
||
position: absolute;
|
||
inset: 0;
|
||
border-radius: 50%;
|
||
}
|
||
|
||
/* 1 — Aura. Silber (die Farbe des Siegels) mit einem Hauch Mint (die
|
||
Farbe, in der diese Seite über Codes spricht). */
|
||
.rc-medaillon::before {
|
||
content: "";
|
||
position: absolute;
|
||
inset: -28%;
|
||
z-index: 0;
|
||
border-radius: 50%;
|
||
background: radial-gradient(circle at 50% 45%,
|
||
rgba(226, 234, 244, .30), rgba(94, 234, 167, .11) 45%, transparent 70%);
|
||
filter: blur(12px);
|
||
animation: rc-aura-atmen 9s ease-in-out infinite;
|
||
pointer-events: none;
|
||
}
|
||
|
||
/* 6 — Ablageschatten. Steht bewusst VOR der Aura im Quelltext, damit
|
||
die Reihenfolge im Kopf der Lage entspricht, nicht der Nummer. */
|
||
.rc-medaillon::after {
|
||
content: "";
|
||
position: absolute;
|
||
left: 14%; right: 14%;
|
||
bottom: -8%;
|
||
height: 13%;
|
||
z-index: 0;
|
||
border-radius: 50%;
|
||
background: radial-gradient(ellipse at center, rgba(0, 0, 0, .6), transparent 72%);
|
||
filter: blur(4px);
|
||
pointer-events: none;
|
||
}
|
||
|
||
/* 2 — Die geriffelte Münzkante. Der Ring entsteht aus zwei Teilen:
|
||
border-radius beschneidet den Kegelverlauf auf den Kreis, die Maske
|
||
stanzt die Mitte heraus. Das Siegel (Lage 4) deckt anschließend
|
||
alles bis zu seinem eigenen Rand ab — sichtbar bleibt genau der
|
||
Streifen, der außen übersteht. */
|
||
.rc-raendel {
|
||
inset: -10%;
|
||
z-index: 1;
|
||
background: repeating-conic-gradient(from 0deg,
|
||
rgba(228, 234, 243, .92) 0deg 2.5deg,
|
||
rgba(70, 80, 94, .8) 2.5deg 5deg);
|
||
-webkit-mask: radial-gradient(closest-side, transparent 0 82%, #000 86%);
|
||
mask: radial-gradient(closest-side, transparent 0 82%, #000 86%);
|
||
opacity: .45;
|
||
}
|
||
|
||
/* 3 — Der wandernde Lichtpunkt auf derselben Kante. */
|
||
.rc-glanz {
|
||
inset: -10%;
|
||
z-index: 2;
|
||
background: conic-gradient(from 0deg,
|
||
rgba(255, 255, 255, 0) 0deg,
|
||
rgba(255, 255, 255, 0) 248deg,
|
||
rgba(255, 255, 255, .72) 322deg,
|
||
rgba(255, 255, 255, 0) 360deg);
|
||
-webkit-mask: radial-gradient(closest-side, transparent 0 82%, #000 86%);
|
||
mask: radial-gradient(closest-side, transparent 0 82%, #000 86%);
|
||
animation: rc-glanz-dreht 22s linear infinite;
|
||
pointer-events: none;
|
||
}
|
||
|
||
/* 4 — Das Siegel selbst. */
|
||
.rc-medaillon img {
|
||
z-index: 3;
|
||
width: 100%;
|
||
height: 100%;
|
||
object-fit: contain;
|
||
filter: drop-shadow(0 10px 20px rgba(0, 0, 0, .55));
|
||
}
|
||
|
||
/* 5 — Prägekante und Lichtstreif. Der Streifen benutzt dieselbe
|
||
Bewegung wie die Marken-Kacheln auf links.html (nav-cta-shimmer aus
|
||
main.css), nur deutlich langsamer. */
|
||
.rc-schliff {
|
||
z-index: 4;
|
||
pointer-events: none;
|
||
background: linear-gradient(118deg, transparent 36%, rgba(255, 255, 255, .28) 49%, transparent 62%);
|
||
background-size: 260% 100%;
|
||
box-shadow:
|
||
inset 0 2px 4px rgba(255, 255, 255, .3),
|
||
inset 0 -8px 16px rgba(0, 0, 0, .4),
|
||
inset 0 0 0 1px rgba(255, 255, 255, .1);
|
||
animation: nav-cta-shimmer 6.5s linear infinite;
|
||
}
|
||
|
||
/* Beim Zeigen kippt die Münze leicht ins Licht. Ausgelöst wird das an
|
||
der ganzen KARTE, nicht am Medaillon: Es ist kein Knopf, und ein
|
||
Effekt, der erst kommt, wenn man ein Bild genau trifft, findet
|
||
niemand. */
|
||
.rc-partner:hover .rc-medaillon {
|
||
transform: perspective(680px) rotateX(9deg) rotateY(-7deg) scale(1.045);
|
||
}
|
||
|
||
@keyframes rc-aura-atmen {
|
||
0%, 100% { opacity: .75; transform: scale(1); }
|
||
50% { opacity: 1; transform: scale(1.05); }
|
||
}
|
||
@keyframes rc-glanz-dreht { to { transform: rotate(360deg); } }
|
||
|
||
/* ---- Name, Beschreibung ------------------------------------------- */
|
||
.rc-marke {
|
||
font-size: clamp(1.35rem, 5vw, 1.7rem);
|
||
line-height: 1.2;
|
||
margin: 0;
|
||
}
|
||
.rc-marke small {
|
||
display: block;
|
||
font-size: .58em;
|
||
font-weight: 700;
|
||
letter-spacing: .05em;
|
||
color: var(--text-muted);
|
||
margin-top: .25rem;
|
||
}
|
||
.rc-beschreibung {
|
||
margin: .7rem auto 0;
|
||
max-width: 40ch;
|
||
font-size: .97rem;
|
||
}
|
||
|
||
/* ---- Der Code selbst ----------------------------------------------
|
||
Ein Knopf, kein Textfeld: Die einzige Handlung hier ist "kopieren",
|
||
und die gehört auf etwas Drückbares — mit Tastatur erreichbar, ohne
|
||
dass jemand erst markieren muss. Der gestrichelte Rand ist der
|
||
Gutschein-Look, den diese Seite vorher schon in der Vorschaukachel
|
||
hatte; er bleibt, das Erfundene daran verschwindet. */
|
||
.rc-code {
|
||
position: relative;
|
||
display: block;
|
||
width: 100%;
|
||
max-width: 340px;
|
||
margin: 1.7rem auto 0;
|
||
padding: .9rem 1.1rem 1rem;
|
||
border: 1.5px dashed rgba(94, 234, 167, .45);
|
||
border-radius: 14px;
|
||
background: rgba(52, 211, 153, .06);
|
||
color: inherit;
|
||
font-family: inherit;
|
||
cursor: pointer;
|
||
text-align: center;
|
||
transition: border-color .2s ease, background-color .2s ease, transform .12s ease;
|
||
}
|
||
.rc-code:hover {
|
||
border-color: rgba(94, 234, 167, .8);
|
||
background: rgba(52, 211, 153, .1);
|
||
}
|
||
.rc-code:active { transform: scale(.99); }
|
||
.rc-code.ist-kopiert {
|
||
border-style: solid;
|
||
border-color: rgba(94, 234, 167, .9);
|
||
background: rgba(52, 211, 153, .16);
|
||
}
|
||
.rc-code-kopf {
|
||
display: block;
|
||
font-size: .7rem;
|
||
font-weight: 800;
|
||
letter-spacing: .16em;
|
||
text-transform: uppercase;
|
||
color: var(--text-muted);
|
||
}
|
||
.rc-code-wert {
|
||
display: block;
|
||
margin: .32rem 0 .4rem;
|
||
font-size: clamp(1.7rem, 7.5vw, 2.15rem);
|
||
font-weight: 900;
|
||
letter-spacing: .16em;
|
||
text-indent: .16em; /* gleicht den Sperrsatz hinter dem letzten Zeichen aus */
|
||
background: linear-gradient(100deg,
|
||
#7fe3b4 0%, #ffffff 26%, #d9fff1 44%, #86e9bd 62%, #ffffff 80%, #7fe3b4 100%);
|
||
background-size: 260% 100%;
|
||
-webkit-background-clip: text;
|
||
background-clip: text;
|
||
color: transparent;
|
||
animation: btn-silver-text-shine 5.5s linear infinite; /* aus main.css */
|
||
}
|
||
.rc-code-fuss {
|
||
display: block;
|
||
font-size: .8rem;
|
||
color: var(--text-muted);
|
||
}
|
||
/* Rückmeldung steht AUSSERHALB des Knopfes und wird nicht per Skript
|
||
beschriftet, sondern nur ein- und ausgeblendet. Sonst wäre der Text
|
||
nach einem Sprachwechsel deutsch geblieben — data-i18n greift nur an
|
||
Elementen, die im HTML stehen. Die feste Höhe verhindert, dass die
|
||
Karte beim Kopieren springt. */
|
||
.rc-code-echo {
|
||
min-height: 1.4em;
|
||
margin: .5rem 0 0;
|
||
font-size: .85rem;
|
||
font-weight: 700;
|
||
color: #8ff0c0;
|
||
}
|
||
.rc-code-echo .fehler { color: #ffc9a3; }
|
||
|
||
/* ---- Konditionen --------------------------------------------------- */
|
||
.rc-fakten {
|
||
list-style: none;
|
||
margin: 1.2rem 0 0;
|
||
padding: 0;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
gap: .4rem;
|
||
font-size: .9rem;
|
||
color: var(--text-muted);
|
||
}
|
||
.rc-fakten li { display: flex; gap: .5rem; align-items: baseline; }
|
||
.rc-fakten b { color: #8ff0c0; font-weight: 800; }
|
||
|
||
/* ---- Abgelaufen ---------------------------------------------------- */
|
||
.rc-abgelaufen {
|
||
max-width: 380px;
|
||
margin: 1.2rem auto 0;
|
||
padding: .7rem 1rem;
|
||
border-radius: 12px;
|
||
border: 1.5px solid rgba(212, 175, 55, .4);
|
||
background: rgba(212, 175, 55, .08);
|
||
color: #ffe9a8;
|
||
font-size: .88rem;
|
||
}
|
||
.rc-abgelaufen[hidden] { display: none; }
|
||
.rc-partner.ist-abgelaufen .rc-code-wert {
|
||
text-decoration: line-through;
|
||
opacity: .5;
|
||
animation: none;
|
||
}
|
||
.rc-partner.ist-abgelaufen .rc-code { cursor: not-allowed; opacity: .75; }
|
||
|
||
/* Steht unter den beiden Knöpfen der Sperrkachel: ohne sie wäre
|
||
"Supporter werden" eine Falle, weil das Abo noch nicht bezahlbar
|
||
ist. */
|
||
.rc-abo-hinweis {
|
||
max-width: 44ch;
|
||
margin: 1rem auto 0;
|
||
font-size: .84rem;
|
||
color: var(--text-muted);
|
||
}
|
||
|
||
.rc-mehr {
|
||
max-width: 620px;
|
||
margin: 1.4rem auto 0;
|
||
text-align: center;
|
||
font-size: .9rem;
|
||
color: var(--text-muted);
|
||
}
|
||
|
||
@media (prefers-reduced-motion: reduce) {
|
||
.rc-medaillon,
|
||
.rc-medaillon::before,
|
||
.rc-glanz,
|
||
.rc-schliff,
|
||
.rc-code-wert { animation: none; transition: none; }
|
||
.rc-partner:hover .rc-medaillon { transform: none; }
|
||
}
|
||
</style>
|
||
</head>
|
||
<body class="mit-hintergrund" style="--page-bg:url('/assets/img/bg-links.jpg?v=202610011927');--page-bg-mobile:url('/assets/img/bg-links-mobile.jpg?v=202610011927');">
|
||
<div id="site-header"></div>
|
||
|
||
<main>
|
||
<section class="hero page-bg">
|
||
<div class="hero-banner"><img src="/assets/img/bg-links.jpg?v=202610011927" alt="" loading="eager" /></div>
|
||
<div class="container">
|
||
<span class="eyebrow" data-i18n="rc_eyebrow">🔒 Nur mit Konto</span>
|
||
<h1 data-i18n="rc_h1">Rabattcodes</h1>
|
||
<p class="lead worlds" data-i18n="rc_lead">Codes von Dogis Partnern — für alle mit einem Konto im DOGFATHER UNIVERSE.</p>
|
||
</div>
|
||
</section>
|
||
|
||
<section class="section-tight">
|
||
<div class="container">
|
||
<!-- Nur für Supporter sichtbar (siehe Skript unten) -->
|
||
<div id="rc-inhalt" hidden>
|
||
<article class="card rc-partner" id="rc-partner">
|
||
<span class="rc-band" data-i18n="rc_band">Partner Nr. 1</span>
|
||
|
||
<div class="rc-medaillon">
|
||
<span class="rc-raendel" aria-hidden="true"></span>
|
||
<span class="rc-glanz" aria-hidden="true"></span>
|
||
<img src="/assets/img/partner-vandiy.webp?v=202610011927" width="384" height="384"
|
||
alt="Logo von Van’s DIY & Bastelbedarf"
|
||
data-i18n-attr="alt:rc_logo_alt" loading="lazy" decoding="async" />
|
||
<span class="rc-schliff" aria-hidden="true"></span>
|
||
</div>
|
||
|
||
<h2 class="rc-marke">VAN’S DIY<small>& Bastelbedarf</small></h2>
|
||
<p class="rc-beschreibung" data-i18n="rc_beschreibung">Häkelzubehör, Bastelbedarf, DIY-Plushies und Modeschmuck — VanVans eigener Shop.</p>
|
||
|
||
<button type="button" class="rc-code" id="rc-code" data-code="DOGI10">
|
||
<span class="rc-code-kopf" data-i18n="rc_code_kopf">Dein Code</span>
|
||
<span class="rc-code-wert">DOGI10</span>
|
||
<span class="rc-code-fuss" data-i18n="rc_code_fuss">Tippen zum Kopieren</span>
|
||
</button>
|
||
<p class="rc-code-echo" role="status" aria-live="polite">
|
||
<span id="rc-echo-ok" data-i18n="rc_code_kopiert" hidden>Code kopiert ✓</span>
|
||
<span class="fehler" id="rc-echo-fehler" data-i18n="rc_code_fehler" hidden>Kopieren ging nicht — bitte von Hand abtippen.</span>
|
||
</p>
|
||
|
||
<ul class="rc-fakten">
|
||
<li><span aria-hidden="true">💸</span><span data-i18n="rc_fakt_rabatt"><b>10 %</b> Rabatt auf deinen Einkauf</span></li>
|
||
<li><span aria-hidden="true">📅</span><span data-i18n="rc_fakt_bis">Gültig bis 30.09.2026</span></li>
|
||
<li><span aria-hidden="true">ℹ️</span><span data-i18n="rc_fakt_sale">Nicht auf bereits reduzierte Artikel</span></li>
|
||
</ul>
|
||
|
||
<p class="rc-abgelaufen" id="rc-abgelaufen" hidden data-i18n="rc_abgelaufen">Dieser Code ist ausgelaufen. Dogi klärt gerade die Verlängerung — schau bald wieder rein.</p>
|
||
|
||
<div class="btn-row" style="justify-content:center;margin-top:1.6rem;">
|
||
<a class="btn btn-primary" href="https://vans-diy-bastelbedarf.com/" target="_blank" rel="noopener" data-i18n="rc_btn_shop">Zum Shop von Van’s DIY ↗</a>
|
||
<a class="btn btn-outline" href="links.html" data-i18n="rc_btn_zurueck">← Zurück zu allen Links</a>
|
||
</div>
|
||
</article>
|
||
|
||
<p class="rc-mehr" data-i18n="rc_mehr">Weitere Codes folgen, sobald die nächsten Kooperationen stehen.</p>
|
||
</div>
|
||
|
||
<!-- Nur für Ausgeloggte sichtbar (siehe Skript unten) -->
|
||
<div class="card code-platzhalter" id="rc-gesperrt" hidden>
|
||
<div class="code-gesperrt-siegel" aria-hidden="true">🔒</div>
|
||
<h2 data-i18n="rc_gesperrt_titel">Melde dich an, dann sind sie da</h2>
|
||
<p data-i18n="rc_gesperrt_text">Die Rabattcodes gibt es für alle mit einem Konto bei Dogfather — Registrieren ist kostenlos und dauert eine Minute. Der erste Partnercode wartet schon.</p>
|
||
<div class="btn-row" style="justify-content:center;margin-top:1.8rem;">
|
||
<a class="btn btn-primary" href="abonnieren.html" data-i18n="rc_btn_anmelden">Anmelden oder kostenlos registrieren</a>
|
||
<a class="btn btn-outline" href="abonnieren.html" data-i18n="rc_btn_abo">Supporter werden 👑</a>
|
||
</div>
|
||
<p class="rc-abo-hinweis" data-i18n="rc_abo_hinweis">Fürs Abo brauchst du ebenfalls erst ein Konto — es startet, sobald es offiziell live geht.</p>
|
||
<div class="btn-row" style="justify-content:center;margin-top:.6rem;">
|
||
<a class="btn btn-outline" href="links.html" data-i18n="rc_btn_zurueck">← Zurück zu allen Links</a>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
</main>
|
||
|
||
<div id="site-footer"></div>
|
||
<script src="assets/js/i18n-rabattcodes.js?v=202610011927"></script>
|
||
<script src="assets/js/main.js?v=202610011927"></script>
|
||
<script>
|
||
(function () {
|
||
/* Ablaufdatum von DOGI10 — dieselbe Angabe wie "bis" in
|
||
src/content/partnercodes.json im Shop, und dieselbe Auslegung:
|
||
einschließlich dieses Tages bis 23:59:59 (server/lib/preis-
|
||
berechnen.js, istRabattAktiv).
|
||
|
||
WARUM DAS HIER ÜBERHAUPT STEHT: Ein fest eingetipptes Datum in einem
|
||
Satz ist eine Zeitbombe — es stimmt, bis der Kalender es überholt,
|
||
und ab dann verspricht die Seite etwas, das der Shop schon ablehnt.
|
||
Deshalb steht das Datum genau EINMAL als Zahl da und nicht nur als
|
||
Text, damit die Seite selbst merken kann, wann sie stillhalten muss.
|
||
|
||
Gerechnet wird in der Zeitzone des Besuchers, der Shop rechnet in
|
||
seiner. In den wenigen Stunden Unterschied kann die Seite den Code
|
||
bereits als abgelaufen zeigen, während er noch gilt — das ist die
|
||
harmlose Richtung des Fehlers. Andersherum wäre sie es nicht. */
|
||
var ABLAUF = "2026-09-30";
|
||
|
||
document.addEventListener("DOMContentLoaded", function () {
|
||
/* WER DIE CODES SIEHT — seit 08.09.2026 das KONTO, nicht das Abo.
|
||
|
||
Anlass (Filipe): "die partner codes sollen auch schon für die leute
|
||
sichtbar sein die angemeldet sind." Der alte Riegel verlangte einen
|
||
Abo-Status. Der war zu diesem Zeitpunkt für NIEMANDEN erreichbar:
|
||
Die Bezahlung auf abonnieren.html steht auf "Coming soon", bis
|
||
Dogis PayPal-Business-Zugang da ist. Der erste echte Partnercode
|
||
wäre also hinter einer Tür gelegen, die sich gar nicht öffnen lässt.
|
||
|
||
"supporterToken" ist der Nachweis, dass jemand angemeldet ist — er
|
||
wird beim Login gesetzt und beim Logout wieder entfernt
|
||
(supporter.js, clearToken). "supporterSubStatus" sagt nur, OB und
|
||
wie bezahlt wird ("none", wenn ein Konto ohne Abo besteht).
|
||
|
||
Warum der Abo-Stand trotzdem noch mit abgefragt wird, obwohl er
|
||
ohne Token gar nicht vorkommen kann: Es ist ein Sicherheitsnetz.
|
||
Niemand, der die Codes gestern sehen konnte, soll sie heute
|
||
verlieren, nur weil ein Speicherstand anders aussieht als gedacht.
|
||
|
||
Die Prüfung ist bewusst rein clientseitig (wie vorher schon) — es
|
||
geht darum, wem etwas angeboten wird, nicht darum, ein Geheimnis zu
|
||
hüten. Der Code steht ohnehin in jedem geteilten Bildschirmfoto. */
|
||
var angemeldet = !!localStorage.getItem("supporterToken");
|
||
var status = localStorage.getItem("supporterSubStatus");
|
||
var hatAbo = ["active", "pending", "suspended", "cancelled"].indexOf(status) !== -1;
|
||
var darfSehen = angemeldet || hatAbo;
|
||
var inhalt = document.getElementById("rc-inhalt");
|
||
var gesperrt = document.getElementById("rc-gesperrt");
|
||
if (inhalt) inhalt.hidden = !darfSehen;
|
||
if (gesperrt) gesperrt.hidden = darfSehen;
|
||
|
||
var karte = document.getElementById("rc-partner");
|
||
var knopf = document.getElementById("rc-code");
|
||
var ok = document.getElementById("rc-echo-ok");
|
||
var fehler = document.getElementById("rc-echo-fehler");
|
||
var abgelaufen = new Date() > new Date(ABLAUF + "T23:59:59");
|
||
|
||
if (abgelaufen) {
|
||
if (karte) karte.classList.add("ist-abgelaufen");
|
||
var hinweis = document.getElementById("rc-abgelaufen");
|
||
if (hinweis) hinweis.hidden = false;
|
||
if (knopf) knopf.disabled = true;
|
||
}
|
||
|
||
if (!knopf) return;
|
||
var uhr = null;
|
||
knopf.addEventListener("click", function () {
|
||
if (abgelaufen) return;
|
||
var zeigen = function (welches) {
|
||
if (ok) ok.hidden = welches !== "ok";
|
||
if (fehler) fehler.hidden = welches !== "fehler";
|
||
knopf.classList.toggle("ist-kopiert", welches === "ok");
|
||
clearTimeout(uhr);
|
||
uhr = setTimeout(function () {
|
||
if (ok) ok.hidden = true;
|
||
if (fehler) fehler.hidden = true;
|
||
knopf.classList.remove("ist-kopiert");
|
||
}, 2600);
|
||
};
|
||
/* Ohne HTTPS gibt es navigator.clipboard nicht, und auch mit kann
|
||
das Versprechen abgelehnt werden. Beide Fälle bekommen dieselbe
|
||
ehrliche Antwort statt einer stillen Nicht-Reaktion — der Code
|
||
steht ja sichtbar da und lässt sich abtippen. */
|
||
if (navigator.clipboard && navigator.clipboard.writeText) {
|
||
navigator.clipboard.writeText(knopf.getAttribute("data-code") || "").then(
|
||
function () { zeigen("ok"); },
|
||
function () { zeigen("fehler"); }
|
||
);
|
||
} else {
|
||
zeigen("fehler");
|
||
}
|
||
});
|
||
});
|
||
})();
|
||
</script>
|
||
</body>
|
||
</html>
|