PageSourceSearch

https://www.zitatdestages.net/app/quiz

html zitatdestages.net collected 2026-10-01 23:53:13 UTC 54,005 bytes, 1,667 lines download raw bytes

1<!DOCTYPE html>
2<html lang="de">
3
4<head>
5    <meta charset="UTF-8">
6    <meta name="viewport" content="width=device-width, initial-scale=1.0">
7    <title>Quiz - Zitat des Tages</title>
8    <link rel="preconnect" href="https://fonts.googleapis.com">
9    <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
10    <link
11        href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Readex+Pro:wght@300;400;500;600;700&display=swap"
12        rel="stylesheet">
13    <style>
14        * {
15            margin: 0;
16            padding: 0;
17            box-sizing: border-box;
18        }
19
20        body {
21            font-family: 'Readex Pro', sans-serif;
22            background-color: #00001A;
23            color: #F5F5F5;
24            min-height: 100vh;
25            overflow: hidden;
26        }
27
28        .quiz-container {
29            position: relative;
30            width: 100%;
31            height: 100vh;
32            background-size: cover;
33            background-position: center;
34            background-repeat: no-repeat;
35            display: flex;
36            flex-direction: column;
37            justify-content: center;
38            align-items: center;
39            padding: 20px;
40            transition: background-image 0.5s ease-in-out;
41        }
42
43        .quiz-container::before {
44            content: '';
45            position: absolute;
46            top: 0;
47            left: 0;
48            right: 0;
49            bottom: 0;
50            background: rgba(0, 0, 26, 0.6);
51            backdrop-filter: blur(5px);
52        }
53
54        .content {
55            position: relative;
56            z-index: 1;
57            max-width: 800px;
58            width: 100%;
59            text-align: center;
60        }
61
62        .header {
63            margin-bottom: 40px;
64        }
65
66        .header h1 {
67            font-family: 'Inter', sans-serif;
68            font-size: 28px;
69            font-weight: 600;
70            color: white;
71            margin-bottom: 12px;
72        }
73
74        .header p {
75            color: #19DB8A;
76            font-size: 16px;
77            font-weight: 500;
78        }
79
80        .quote-card {
81            background: rgba(255, 255, 255, 0.05);
82            backdrop-filter: blur(20px);
83            border-radius: 20px;
84            padding: 24px 32px;
85            margin-bottom: 32px;
86            border: 1px solid rgba(255, 255, 255, 0.1);
87            box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);
88        }
89
90        .quote-text {
91            font-size: 24px;
92            line-height: 1.6;
93            color: white;
94            font-style: italic;
95            margin-bottom: 20px;
96            min-height: 50px;
97            display: flex;
98            align-items: center;
99            justify-content: center;
100            text-align: center;
101        }
102
103        .question-text {
104            font-size: 18px;
105            color: #19DB8A;
106            font-weight: 500;
107            margin-bottom: 32px;
108        }
109
110        .answers-container {
111            display: grid;
112            grid-template-columns: 1fr 1fr;
113            gap: 12px;
114            margin-bottom: 0;
115        }
116
117        .answer-btn {
118            background: rgba(255, 255, 255, 0.1);
119            border: 2px solid rgba(255, 255, 255, 0.2);
120            border-radius: 12px;
121            padding: 16px;
122            color: white;
123            font-size: 16px;
124            font-weight: 500;
125            cursor: pointer;
126            transition: all 0.3s ease;
127            min-height: 70px;
128            display: flex;
129            align-items: center;
130            justify-content: center;
131            text-align: center;
132        }
133
134        .answer-btn:hover {
135            background: rgba(255, 255, 255, 0.15);
136            border-color: rgba(25, 219, 138, 0.5);
137            transform: translateY(-2px);
138        }
139
140        /* Entferne Animation von Button selbst */
141        .answer-btn.correct,
142        .answer-btn.wrong {
143            /* nur Farbänderung, keine transform-animation */
144            background: rgba(25, 219, 138, 0.2);
145            border-color: #19DB8A;
146        }
147
148        .answer-btn.wrong {
149            background: rgba(255, 59, 48, 0.2);
150            border-color: #FF3B30;
151        }
152
153        /* Neues internes Label für Animation */
154        .answer-btn .label {
155            display: inline-block;
156            will-change: transform;
157            transform-origin: center center;
158        }
159
160        .answer-btn.correct .label {
161            animation: pulse 0.6s ease;
162        }
163
164        .answer-btn.wrong .label {
165            animation: shake 0.6s ease;
166        }
167
168        @keyframes pulse {
169
170            0%,
171            100% {
172                transform: scale(1);
173            }
174
175            50% {
176                transform: scale(1.12);
177            }
178        }
179
180        @keyframes shake {
181
182            0%,
183            100% {
184                transform: translateX(0);
185            }
186
187            20% {
188                transform: translateX(-14px);
189            }
190
191            40% {
192                transform: translateX(14px);
193            }
194
195            60% {
196                transform: translateX(-12px);
197            }
198
199            80% {
200                transform: translateX(12px);
201            }
202        }
203
204        .stats-bar {
205            display: flex;
206            justify-content: space-between;
207            gap: 16px;
208            margin-top: 24px;
209        }
210
211        .stat {
212            background: rgba(255, 255, 255, 0.1);
213            backdrop-filter: blur(10px);
214            border-radius: 12px;
215            padding: 16px 24px;
216            flex: 1;
217            border: 1px solid rgba(255, 255, 255, 0.1);
218        }
219
220        .stat-label {
221            font-size: 12px;
222            color: #A0A0A0;
223            margin-bottom: 4px;
224        }
225
226        .stat-value {
227            font-size: 24px;
228            font-weight: 700;
229            color: #19DB8A;
230        }
231
232        .loading {
233            text-align: center;
234            padding: 60px;
235            color: #A0A0A0;
236        }
237
238        .spinner {
239            border: 4px solid rgba(255, 255, 255, 0.1);
240            border-top: 4px solid #19DB8A;
241            border-radius: 50%;
242            width: 50px;
243            height: 50px;
244            animation: spin 1s linear infinite;
245            margin: 20px auto;
246        }
247
248        @keyframes spin {
249            0% {
250                transform: rotate(0deg);
251            }
252
253            100% {
254                transform: rotate(360deg);
255            }
256        }
257
258        .error {
259            background: rgba(255, 0, 0, 0.1);
260            color: #ff6b6b;
261            padding: 20px;
262            border-radius: 12px;
263            margin: 20px 0;
264            border: 1px solid rgba(255, 0, 0, 0.3);
265        }
266
267        .next-btn {
268            background: linear-gradient(135deg, #19DB8A 0%, #0FA968 100%);
269            border: none;
270            border-radius: 12px;
271            padding: 16px 48px;
272            color: #00001A;
273            font-size: 16px;
274            font-weight: 600;
275            cursor: pointer;
276            transition: all 0.3s ease;
277            margin-top: 12px;
278        }
279
280        .next-btn:hover {
281            transform: translateY(-2px);
282            box-shadow: 0 8px 24px rgba(25, 219, 138, 0.4);
283        }
284
285        .next-btn:disabled {
286            opacity: 0.5;
287            cursor: not-allowed;
288        }
289
290        .result-message {
291            font-size: 20px;
292            font-weight: 600;
293            margin-top: 12px;
294            min-height: 0;
295        }
296
297        .completed-message {
298            text-align: center;
299            padding: 40px;
300        }
301
302        .completed-message h2 {
303            font-size: 32px;
304            color: #19DB8A;
305            margin-bottom: 16px;
306        }
307
308        .completed-message p {
309            font-size: 18px;
310            color: #A0A0A0;
311            margin-bottom: 32px;
312        }
313
314        .results-btn {
315            background: linear-gradient(135deg, #19DB8A 0%, #0FA968 100%);
316            border: none;
317            border-radius: 12px;
318            padding: 16px 48px;
319            color: #00001A;
320            font-size: 16px;
321            font-weight: 600;
322            cursor: pointer;
323            text-decoration: none;
324            display: inline-block;
325            transition: all 0.3s ease;
326        }
327
328        .results-btn:hover {
329            transform: translateY(-2px);
330            box-shadow: 0 8px 24px rgba(25, 219, 138, 0.4);
331        }
332
333        /* App Button (Desktop Only) */
334        .app-btn-top {
335            position: fixed;
336            top: 20px;
337            right: 20px;
338            z-index: 1000;
339            background: rgba(160, 160, 160, 0.15);
340            backdrop-filter: blur(20px);
341            -webkit-backdrop-filter: blur(20px);
342            border: 1px solid rgba(160, 160, 160, 0.3);
343            border-radius: 50px;
344            padding: 12px 24px;
345            color: #E0E0E0;
346            text-decoration: none;
347            font-weight: 600;
348            font-size: 0.95rem;
349            display: flex;
350            align-items: center;
351            gap: 8px;
352            transition: all 0.3s ease;
353        }
354
355        .app-btn-top:hover {
356            background: rgba(160, 160, 160, 0.25);
357            border-color: #19DB8A;
358            transform: translateY(-2px);
359            box-shadow: 0 4px 12px rgba(25, 219, 138, 0.3);
360        }
361
362        .app-btn-top svg {
363            width: 20px;
364            height: 20px;
365        }
366
367        /* Hide app button on mobile/tablet */
368        @media (max-width: 1024px) {
369            .app-btn-top {
370                display: none;
371            }
372        }
373
374        /* Hamburger Menu Styles */
375        .hamburger-menu {
376            position: fixed;
377            top: 20px;
378            left: 60px;
379            z-index: 1000;
380        }
381
382        .hamburger-btn {
383            background: rgba(160, 160, 160, 0.15);
384            backdrop-filter: blur(20px);
385            border: 1px solid rgba(160, 160, 160, 0.3);
386            border-radius: 12px;
387            width: 50px;
388            height: 50px;
389            display: flex;
390            flex-direction: column;
391            justify-content: center;
392            align-items: center;
393            gap: 5px;
394            cursor: pointer;
395            transition: all 0.3s ease;
396            padding: 0;
397        }
398
399        .hamburger-btn:hover {
400            background: rgba(160, 160, 160, 0.25);
401            transform: scale(1.05);
402        }
403
404        .hamburger-btn span {
405            width: 24px;
406            height: 2px;
407            background: #A0A0A0;
408            border-radius: 2px;
409            transition: all 0.3s ease;
410        }
411
412        .hamburger-btn.active span:nth-child(1) {
413            transform: rotate(45deg) translate(6px, 6px);
414        }
415
416        .hamburger-btn.active span:nth-child(2) {
417            opacity: 0;
418        }
419
420        .hamburger-btn.active span:nth-child(3) {
421            transform: rotate(-45deg) translate(6px, -6px);
422        }
423
424        .menu-overlay {
425            position: fixed;
426            top: 0;
427            left: -100%;
428            width: 100%;
429            max-width: 320px;
430            height: 100vh;
431            background: rgb(0 0 0 / 25%);
432            backdrop-filter: blur(40px);
433            -webkit-backdrop-filter: blur(40px);
434            z-index: 999;
435            transition: left 0.3s ease;
436            padding: 92px 40px 30px 40px;
437            overflow-y: auto;
438            border-right: 1px solid rgba(255, 255, 255, 0.1);
439        }
440
441        .menu-overlay.active {
442            left: 0;
443        }
444
445        .menu-items {
446            list-style: none;
447            padding: 0;
448            margin: 0;
449            display: flex;
450            flex-direction: column;
451            align-items: center;
452        }
453
454        .menu-item {
455            margin-bottom: 12px;
456            width: 100%;
457            max-width: 240px;
458        }
459
460        .menu-item a {
461            display: block;
462            background: rgba(255, 255, 255, 0.1);
463            backdrop-filter: blur(10px);
464            -webkit-backdrop-filter: blur(10px);
465            border: 2px solid rgba(255, 255, 255, 0.2);
466            border-radius: 12px;
467            padding: 14px 24px;
468            color: #E0E0E0;
469            text-decoration: none;
470            font-size: 16px;
471            font-weight: 500;
472            transition: all 0.3s ease;
473            text-align: center;
474            word-wrap: break-word;
475        }
476
477        .menu-item a:hover {
478            background: rgba(255, 255, 255, 0.15);
479            border-color: rgba(25, 219, 138, 0.5);
480            transform: translateX(5px);
481        }
482
483        .menu-item.featured a {
484            font-weight: 700;
485            background: rgba(25, 219, 138, 0.2);
486            border-color: #19DB8A;
487            color: #19DB8A;
488        }
489
490        .menu-item.featured a:hover {
491            background: rgba(25, 219, 138, 0.25);
492            border-color: #19DB8A;
493        }
494
495        .menu-backdrop {
496            position: fixed;
497            top: 0;
498            left: 0;
499            width: 100%;
500            height: 100vh;
501            background: rgba(0, 0, 0, 0.5);
502            z-index: 998;
503            opacity: 0;
504            visibility: hidden;
505            transition: all 0.3s ease;
506        }
507
508        .menu-backdrop.active {
509            opacity: 1;
510            visibility: visible;
511        }
512
513        .quick-links {
514            margin-top: 28px;
515            display: flex;
516            gap: 12px;
517            flex-wrap: wrap;
518            justify-content: center;
519        }
520
521        .quick-links a {
522            background: rgba(255, 255, 255, 0.1);
523            border: 2px solid rgba(255, 255, 255, 0.2);
524            border-radius: 12px;
525            padding: 14px 24px;
526            color: #E0E0E0;
527            font-size: 14px;
528            font-weight: 500;
529            text-decoration: none;
530            backdrop-filter: blur(10px);
531            transition: all 0.3s ease;
532        }
533
534        .quick-links a:hover {
535            background: rgba(255, 255, 255, 0.15);
536            border-color: rgba(25, 219, 138, 0.5);
537        }
538
539        @media (min-width: 769px) {
540            .quiz-container::before {
541                backdrop-filter: blur(10px);
542            }
543        }
544
545        @media (max-width: 768px) {
546            body {
547                overflow-y: auto;
548            }
549
550            .quiz-container {
551                padding: 16px;
552                min-height: 100vh;
553                height: auto;
554                display: flex;
555                flex-direction: column;
556                align-items: center;
557                justify-content: flex-start;
558                /* oben ausrichten */
559                padding-top: 50px;
560                /* kleineres Padding */
561            }
562
563            .quiz-container::before {
564                backdrop-filter: blur(5px);
565            }
566
567            .content {
568                width: 100%;
569            }
570
571            .header {
572                margin-bottom: 24px;
573            }
574
575            .header h1 {
576                font-size: 20px;
577            }
578
579            .header p {
580                font-size: 14px;
581            }
582
583            .quote-card {
584                padding: 16px 20px;
585                margin-bottom: 20px;
586            }
587
588            .quote-text {
589                font-size: 16px;
590                min-height: auto;
591                line-height: 1.5;
592                margin-bottom: 16px;
593            }
594
595            .question-text {
596                font-size: 14px;
597                margin-bottom: 20px;
598            }
599
600            .answers-container {
601                grid-template-columns: 1fr;
602                gap: 10px;
603            }
604
605            .answer-btn {
606                min-height: 54px;
607                font-size: 14px;
608                padding: 12px;
609            }
610
611            .result-message {
612                font-size: 16px;
613                margin-top: 12px;
614            }
615
616            .next-btn {
617                padding: 14px 32px;
618                font-size: 14px;
619                margin-top: 10px;
620            }
621
622            .stats-bar {
623                flex-direction: row;
624                gap: 8px;
625                margin-top: 16px;
626            }
627
628            .stat {
629                padding: 12px 8px;
630            }
631
632            .stat-label {
633                font-size: 10px;
634            }
635
636            .stat-value {
637                font-size: 18px;
638            }
639
640            .completed-message {
641                padding: 24px 16px;
642            }
643
644            .completed-message h2 {
645                font-size: 24px;
646                margin-bottom: 12px;
647            }
648
649            .completed-message p {
650                font-size: 14px;
651                margin-bottom: 16px;
652            }
653
654            .results-btn {
655                padding: 14px 32px;
656                font-size: 14px;
657            }
658
659            .loading {
660                padding: 40px 20px;
661            }
662
663            .loading p {
664                font-size: 14px;
665            }
666
667            .error {
668                font-size: 14px;
669                padding: 16px;
670            }
671
672            .hamburger-menu {
673                top: 16px;
674                left: 16px;
675            }
676
677            .menu-overlay {
678                max-width: 280px;
679                padding: 82px 0 20px 16px;
680                background: rgb(0 0 0 / 25%);
681            }
682
683            .menu-items {
684                align-items: flex-start;
685            }
686
687            .menu-item {
688                max-width: calc(100% - 16px);
689            }
690
691            .menu-item a {
692                text-align: left;
693            }
694
695            .menu-item a:hover {
696                transform: translateX(5px);
697            }
698        }
699
700        @media (max-width: 480px) {
701            .quiz-container {
702                padding: 12px;
703                padding-top: 30px;
704            }
705
706            .header h1 {
707                font-size: 18px;
708            }
709
710            .quote-text {
711                font-size: 15px;
712            }
713
714            .stat-label {
715                font-size: 9px;
716            }
717
718            .stat-value {
719                font-size: 16px;
720            }
721
722            .hamburger-menu {
723                top: 12px;
724                left: 12px;
725            }
726
727            .menu-overlay {
728                padding: 82px 0 20px 12px;
729            }
730
731            .menu-item {
732                max-width: calc(100% - 12px);
733            }
734        }
735
736        /* Newsletter Overlay Styles */
737        .share-overlay {
738            position: fixed;
739            top: 0;
740            left: 0;
741            width: 100%;
742            height: 100%;
743            background: rgba(0, 0, 0, 0.6);
744            backdrop-filter: blur(8px);
745            -webkit-backdrop-filter: blur(8px);
746            z-index: 2000;
747            display: none;
748            justify-content: center;
749            align-items: center;
750            padding: 20px;
751            opacity: 0;
752            transition: opacity 0.3s ease;
753        }
754
755        .share-overlay.active {
756            display: flex;
757            opacity: 1;
758        }
759
760        .share-modal {
761            background: linear-gradient(135deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0.08));
762            backdrop-filter: blur(30px);
763            -webkit-backdrop-filter: blur(30px);
764            border: 1px solid rgba(255, 255, 255, 0.2);
765            border-radius: 24px;
766            padding: 40px;
767            max-width: 500px;
768            width: 100%;
769            text-align: center;
770            position: relative;
771            box-shadow: 0 20px 60px rgba(0, 0, 0, 0.5);
772            animation: slideUp 0.4s ease-out;
773        }
774
775        @keyframes slideUp {
776            from {
777                transform: translateY(30px);
778                opacity: 0;
779            }
780
781            to {
782                transform: translateY(0);
783                opacity: 1;
784            }
785        }
786
787        .share-modal h3 {
788            font-size: 1.5rem;
789            margin-bottom: 15px;
790            color: #fff;
791            font-family: 'Readex Pro', sans-serif;
792        }
793
794        .share-modal p {
795            font-size: 1rem;
796            color: #cbd5e1;
797            margin-bottom: 30px;
798            line-height: 1.6;
799        }
800
801        .share-close-btn {
802            position: absolute;
803            top: 15px;
804            right: 15px;
805            background: rgba(255, 255, 255, 0.1);
806            border: 1px solid rgba(255, 255, 255, 0.2);
807            color: white;
808            width: 35px;
809            height: 35px;
810            border-radius: 50%;
811            cursor: pointer;
812            font-size: 20px;
813            transition: all 0.3s;
814            display: flex;
815            align-items: center;
816            justify-content: center;
817        }
818
819        .share-close-btn:hover {
820            background: rgba(255, 255, 255, 0.2);
821            transform: scale(1.1);
822        }
823
824        .newsletter-input {
825            width: 100%;
826            padding: 12px 15px;
827            border-radius: 12px;
828            border: 1px solid rgba(255, 255, 255, 0.2);
829            background: rgba(255, 255, 255, 0.1);
830            color: white;
831            margin-bottom: 15px;
832            font-size: 1rem;
833            outline: none;
834            transition: all 0.3s;
835            font-family: 'Readex Pro', sans-serif;
836        }
837
838        .newsletter-input:focus {
839            background: rgba(255, 255, 255, 0.2);
840            border-color: rgba(255, 255, 255, 0.4);
841        }
842
843        .newsletter-input::placeholder {
844            color: rgba(255, 255, 255, 0.6);
845        }
846
847        .newsletter-submit {
848            width: 100%;
849            cursor: pointer;
850            justify-content: center;
851            border: none;
852            font-size: 1rem;
853            font-weight: 600;
854            background: linear-gradient(135deg, #19DB8A 0%, #0FA968 100%);
855            color: #00001A;
856            padding: 12px;
857            border-radius: 12px;
858            transition: all 0.3s ease;
859            font-family: 'Readex Pro', sans-serif;
860        }
861
862        .newsletter-submit:hover {
863            transform: translateY(-2px);
864            box-shadow: 0 8px 24px rgba(25, 219, 138, 0.4);
865        }
866
867        .newsletter-footer {
868            font-size: 0.85rem !important;
869            opacity: 0.7;
870            margin-top: 20px !important;
871            margin-bottom: 0 !important;
872        }
873    </style>
874</head>
875
876<body>
877    <!-- Hamburger Menu -->
878    <div class="hamburger-menu">
879        <button class="hamburger-btn" id="hamburgerBtn" aria-label=
879"Menü öffnen">
880            <span></span>
881            <span></span>
882            <span></span>
883        </button>
884    </div>
885
886    <!-- App Button (Desktop Only) -->
887    <a href="/app" class="app-btn-top" aria-label="Zur App">
888        <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"
889            stroke-linejoin="round">
890            <rect x="5" y="2" width="14" height="20" rx="2" ry="2"></rect>
891            <line x1="12" y1="18" x2="12.01" y2="18"></line>
892        </svg>
893        App
894    </a>
895
896    <!-- Menu Backdrop -->
897    <div class="menu-backdrop" id="menuBackdrop"></div>
898
899    <!-- Menu Overlay -->
900    <div class="menu-overlay" id="menuOverlay">
901        <ul class="menu-items">
902            <li class="menu-item">
903                <a href="https://www.zitatdestages.net">Zitat des Tages</a>
904            </li>
905            <li class="menu-item">
906                <a href="#" onclick="openNewsletterOverlay(); return false;">Newsletter</a>
907            </li>
908            <li class="menu-item featured">
909                <a href="/app">App</a>
910            </li>
911        </ul>
912    </div>
913
914    <div class="quiz-container" id="quizContainer">
915        <div class="content">
916            <div id="quizContent">
917                <div class="loading">
918                    <div class="spinner"></div>
919                    <p>Lade Quiz...</p>
920                </div>
921            </div>
922        </div>
923    </div>
924
925    
925<script>
926        // Hamburger Menu Logic
927        const hamburgerBtn = document.getElementById('hamburgerBtn');
928        const menuOverlay = document.getElementById('menuOverlay');
929        const menuBackdrop = document.getElementById('menuBackdrop');
930
931        function toggleMenu() {
932            hamburgerBtn.classList.toggle('active');
933            menuOverlay.classList.toggle('active');
934            menuBackdrop.classList.toggle('active');
935
936            // Prevent body scroll when menu is open
937            if (menuOverlay.classList.contains('active')) {
938                document.body.style.overflow = 'hidden';
939            } else {
940                document.body.style.overflow = '';
941            }
942        }
943
944        hamburgerBtn.addEventListener('click', toggleMenu);
945        menuBackdrop.addEventListener('click', toggleMenu);
946
947        // Close menu on Escape key
948        document.addEventListener('keydown', (e) => {
949            if (e.key === 'Escape' && menuOverlay.classList.contains('active')) {
950                toggleMenu();
951            }
952        });
953
954        // Configuration
955        const API_BASE_URL = 'https://api.zitatdestages.net';
956        const API_VERSION = 'quotes';
957        const MAX_QUESTIONS_PER_DAY = 5;
958
959        // LocalStorage Keys
960        const STORAGE_KEYS = {
961            QUIZ_POINTS_TODAY: 'quiz_points_today',
962            QUIZ_STREAK: 'quiz_streak',
963            QUIZ_TOTAL_POINTS: 'quiz_total_points',
964            QUIZ_LAST_PLAY_DATE: 'quiz_last_play_date',
965            QUIZ_QUESTIONS_TODAY: 'quiz_questions_today',
966            QUIZ_QUESTIONS_LEFT: 'quiz_questions_left',
967            QUIZ_QUESTIONS_CACHE: 'quiz_questions_cache',
968            QUIZ_CACHE_DATE: 'quiz_cache_date',
969            QUIZ_PERFORMANCE_WEEK: 'quiz_performance_week',
970            QUIZ_PLAYED_DATES: 'quiz_played_dates' // NEU: Liste aller gespielten Datums
971        };
972
973        // State
974        let currentQuestion = null;
975        let currentQuestionIndex = 0;
976        let questionsToday = [];
977        let answered = false;
978        let correctAnswers = 0;
979        let stats = {
980            totalPoints: 0,
981            questionsLeft: MAX_QUESTIONS_PER_DAY
982        };
983
984        // Initialize
985        document.addEventListener('DOMContentLoaded', () => {
986            const isIPad = /iPad|Macintosh/.test(navigator.userAgent) && 'ontouchend' in document;
987            if (isIPad) {
988                const container = document.querySelector('.quiz-container');
989                if (container) {
990                    container.style.justifyContent = 'flex-start';
991                    container.style.paddingTop = '100px';
992                }
993            }
994
995            loadStats();
996            initializeQuiz();
997        });
998
999        // Load Stats
1000        function loadStats() {
1001            stats.totalPoints = parseInt(localStorage.getItem(STORAGE_KEYS.QUIZ_TOTAL_POINTS) || '0');
1002            const questionsLeft = parseInt(localStorage.getItem(STORAGE_KEYS.QUIZ_QUESTIONS_LEFT) || MAX_QUESTIONS_PER_DAY.toString());
1003            stats.questionsLeft = questionsLeft;
1004        }
1005
1006        // Add Points
1007        function addPoints(points) {
1008            const currentPoints = parseInt(localStorage.getItem(STORAGE_KEYS.QUIZ_POINTS_TODAY) || '0');
1009            localStorage.setItem(STORAGE_KEYS.QUIZ_POINTS_TODAY, (currentPoints + points).toString());
1010
1011            const totalPoints = parseInt(localStorage.getItem(STORAGE_KEYS.QUIZ_TOTAL_POINTS) || '0');
1012            const newTotalPoints = totalPoints + points;
1013            localStorage.setItem(STORAGE_KEYS.QUIZ_TOTAL_POINTS, newTotalPoints.toString());
1014            stats.totalPoints = newTotalPoints;
1015
1016            // Update last play date
1017            const today = new Date().toDateString();
1018            localStorage.setItem(STORAGE_KEYS.QUIZ_LAST_PLAY_DATE, today);
1019
1020            // Update performance data for chart
1021            updatePerformanceData(points);
1022        }
1023
1024        // Update Performance Data
1025        function updatePerformanceData(points) {
1026            const today = new Date().toDateString();
1027            let performanceData = JSON.parse(localStorage.getItem(STORAGE_KEYS.QUIZ_PERFORMANCE_WEEK) || '{}');
1028
1029            performanceData[today] = (performanceData[today] || 0) + points;
1030
1031            const dates = Object.keys(performanceData).sort((a, b) => new Date(b) - new Date(a));
1032            const last7Days = {};
1033            dates.slice(0, 7).forEach(date => {
1034                last7Days[date] = performanceData[date];
1035            });
1036
1037            localStorage.setItem(STORAGE_KEYS.QUIZ_PERFORMANCE_WEEK, JSON.stringify(last7Days));
1038        }
1039
1040        // Update Streak - Simple: increment if played yesterday, reset otherwise
1041        function updateStreak() {
1042            const today = new Date().toDateString();
1043            const lastPlayDate = localStorage.getItem(STORAGE_KEYS.QUIZ_LAST_PLAY_DATE);
1044
1045            if (!lastPlayDate) {
1046                // First time playing - start streak at 1
1047                localStorage.setItem(STORAGE_KEYS.QUIZ_STREAK, '1');
1048                return;
1049            }
1050
1051            // Only update streak once per day
1052            if (lastPlayDate === today) {
1053                return;
1054            }
1055
1056            const lastPlay = new Date(lastPlayDate);
1057            const todayDate = new Date(today);
1058            const diffDays = Math.floor((todayDate - lastPlay) / (1000 * 60 * 60 * 24));
1059
1060            let currentStreak = parseInt(localStorage.getItem(STORAGE_KEYS.QUIZ_STREAK) || '1');
1061
1062            if (diffDays === 1) {
1063                // Played yesterday - increment streak
1064                currentStreak++;
1065                localStorage.setItem(STORAGE_KEYS.QUIZ_STREAK, currentStreak.toString());
1066            } else if (diffDays > 1) {
1067                // Missed a day - reset to 1
1068                localStorage.setItem(STORAGE_KEYS.QUIZ_STREAK, '1');
1069            }
1070        }
1071
1072        // Initialize Quiz
1073        async function initializeQuiz() {
1074            const today = new Date().toDateString();
1075            const lastPlayDate = localStorage.getItem(STORAGE_KEYS.QUIZ_LAST_PLAY_DATE);
1076
1077            // Reset if new day
1078            if (lastPlayDate !== today) {
1079                localStorage.setItem(STORAGE_KEYS.QUIZ_QUESTIONS_LEFT, MAX_QUESTIONS_PER_DAY.toString());
1080                localStorage.setItem(STORAGE_KEYS.QUIZ_QUESTIONS_TODAY, JSON.stringify([]));
1081                localStorage.setItem(STORAGE_KEYS.QUIZ_POINTS_TODAY, '0');
1082
1083                // Update streak BEFORE setting new last_play_date
1084                updateStreak();
1085            }
1086
1087            const questionsLeft = parseInt(localStorage.getItem(STORAGE_KEYS.QUIZ_QUESTIONS_LEFT) || MAX_QUESTIONS_PER_DAY.toString());
1088
1089            if (questionsLeft <= 0) {
1090                showCompletedMessage();
1091                return;
1092            }
1093
1094            await loadQuestion();
1095        }
1096
1097        // Load Question from API
1098        async function loadQuestion() {
1099            const container = document.getElementById('quizContent');
1100
1101            try {
1102                // Simuliere API-Call (ersetze mit echtem API-Endpoint wenn verfügbar)
1103                const question = await fetchQuizQuestion();
1104
1105                if (!question) {
1106                    throw new Error('Keine Frage verfügbar');
1107                }
1108
1109                currentQuestion = question;
1110                displayQuestion(question);
1111
1112            } catch (error) {
1113                console.error('Error loading question:', error);
1114                container.innerHTML = `
1115                    <div class="error">
1116                        <h3>Fehler beim Laden der Frage</h3>
1117                        <p>Bitte versuche es später erneut.</p>
1118                    </div>
1119                `;
1120            }
1121        }
1122
1123        // Fetch Quiz Question (Real API Call)
1124        async function fetchQuizQuestion() {
1125            try {
1126                const urlParams = getUrlParams();
1127                const cacheDate = localStorage.getItem(STORAGE_KEYS.QUIZ_CACHE_DATE);
1128                const today = new Date().toDateString();
1129
1130                // Cache check
1131                if (cacheDate !== today) {
1132                    localStorage.removeItem(STORAGE_KEYS.QUIZ_QUESTIONS_CACHE);
1133                    localStorage.removeItem(STORAGE_KEYS.QUIZ_CACHE_DATE);
1134                } else {
1135                    const cachedQuestions = JSON.parse(localStorage.getItem(STORAGE_KEYS.QUIZ_QUESTIONS_CACHE) || '[]');
1136                    if (cachedQuestions.length > 0) {
1137                        const firstQuestion = cachedQuestions[0];
1138                        const hasValidFormat = firstQuestion &&
1139                            firstQuestion.quote &&
1140                            firstQuestion.answer1 &&
1141                            firstQuestion.answer2 &&
1142                            typeof firstQuestion.correctAnswer === 'number';
1143
1144                        if (hasValidFormat) {
1145                            return selectQuestionByDate(cachedQuestions, urlParam
1145s.date);
1146                        } else {
1147                            localStorage.removeItem(STORAGE_KEYS.QUIZ_QUESTIONS_CACHE);
1148                            localStorage.removeItem(STORAGE_KEYS.QUIZ_CACHE_DATE);
1149                        }
1150                    }
1151                }
1152
1153                // Fetch all questions from API
1154                const language = 'de';
1155                const url = `${API_BASE_URL}/quotes/questions?l=${language}`;
1156                const response = await fetch(url);
1157                if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`);
1158                const data = await response.json();
1159                if (!data || data.length === 0) throw new Error('No questions available');
1160
1161                // Transform API response
1162                const questions = data.map(item => {
1163                    const backgroundImageUuid = item.background_image;
1164                    const backgroundImageUrl = backgroundImageUuid
1165                        ? `http://api.zitatdestages.net/image?b=${backgroundImageUuid}`
1166                        : 'https://images.unsplash.com/photo-1506126613408-eca07ce68773?w=1920';
1167                    return {
1168                        uuid: item.uuid || '',
1169                        date: item.date || '',
1170                        quote: item.quote || '',
1171                        answer1: item.answer1 || '',
1172                        answer2: item.answer2 || '',
1173                        correctAnswer: parseInt(item.correct_answer) || 1,
1174                        answer1Uuid: item.answer1_uuid || '',
1175                        answer2Uuid: item.answer2_uuid || '',
1176                        backgroundImage: backgroundImageUrl,
1177                        backgroundImageUuid: backgroundImageUuid || '',
1178                        language: item.language || 'de'
1179                    };
1180                });
1181
1182                // Cache questions
1183                localStorage.setItem(STORAGE_KEYS.QUIZ_QUESTIONS_CACHE, JSON.stringify(questions));
1184                localStorage.setItem(STORAGE_KEYS.QUIZ_CACHE_DATE, today);
1185
1186                return selectQuestionByDate(questions, urlParams.date);
1187
1188            } catch (error) {
1189                console.error('Error fetching quiz question:', error);
1190                return getFallbackQuestion();
1191            }
1192        }
1193
1194        // Smart question selection based on played dates
1195        function selectQuestionByDate(questions, requestedDate) {
1196            const playedDates = JSON.parse(localStorage.getItem(STORAGE_KEYS.QUIZ_PLAYED_DATES) || '[]');
1197
1198            // Get today's date in user timezone (YYYY-MM-DD)
1199            const now = new Date();
1200            const todayDate = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}-${String(now.getDate()).padStart(2, '0')}`;
1201
1202            // Case 1: Specific date requested (via URL parameter)
1203            if (requestedDate) {
1204                const filtered = questions.filter(q => q.date === requestedDate);
1205                if (filtered.length > 0) {
1206                    return filtered[0];
1207                }
1208            }
1209
1210            // Case 2: No URL parameter → Show today's quiz (if not played)
1211            if (!requestedDate) {
1212                const todayQuestion = questions.find(q => q.date === todayDate);
1213                const todayPlayed = playedDates.includes(todayDate);
1214
1215                if (todayQuestion && !todayPlayed) {
1216                    return todayQuestion;
1217                }
1218            }
1219
1220            // Case 3: Find an unplayed question
1221            const unplayedQuestions = questions.filter(q => !playedDates.includes(q.date));
1222
1223            if (unplayedQuestions.length > 0) {
1224                const randomIndex = Math.floor(Math.random() * unplayedQuestions.length);
1225                return unplayedQuestions[randomIndex];
1226            }
1227
1228            // Case 4: All questions played → Show random question
1229            const randomIndex = Math.floor(Math.random() * questions.length);
1230            return questions[randomIndex];
1231        }
1232
1233        // Mark date as played
1234        function markDateAsPlayed(date) {
1235            if (!date) return;
1236
1237            const playedDates = JSON.parse(localStorage.getItem(STORAGE_KEYS.QUIZ_PLAYED_DATES) || '[]');
1238
1239            if (!playedDates.includes(date)) {
1240                playedDates.push(date);
1241                localStorage.setItem(STORAGE_KEYS.QUIZ_PLAYED_DATES, JSON.stringify(playedDates));
1242            }
1243        }
1244
1245        // Update Streak - Verbessert: berücksichtigt mehrere Tage
1246        function updateStreak() {
1247            const today = new Date().toDateString();
1248            const lastPlayDate = localStorage.getItem(STORAGE_KEYS.QUIZ_LAST_PLAY_DATE);
1249
1250            if (!lastPlayDate) {
1251                // First time playing - start streak at 1
1252                localStorage.setItem(STORAGE_KEYS.QUIZ_STREAK, '1');
1253                return;
1254            }
1255
1256            // Only update streak once per day
1257            if (lastPlayDate === today) {
1258                return;
1259            }
1260
1261            const lastPlay = new Date(lastPlayDate);
1262            const todayDate = new Date(today);
1263            const diffDays = Math.floor((todayDate - lastPlay) / (1000 * 60 * 60 * 24));
1264
1265            let currentStreak = parseInt(localStorage.getItem(STORAGE_KEYS.QUIZ_STREAK) || '1');
1266
1267            if (diffDays === 1) {
1268                // Played yesterday - increment streak
1269                currentStreak++;
1270                localStorage.setItem(STORAGE_KEYS.QUIZ_STREAK, currentStreak.toString());
1271            } else if (diffDays > 1) {
1272                // Missed a day - reset to 1
1273                localStorage.setItem(STORAGE_KEYS.QUIZ_STREAK, '1');
1274            }
1275        }
1276
1277        // Check Answer
1278        function checkAnswer(selectedAnswer) {
1279            if (answered) return;
1280            answered = true;
1281
1282            const buttons = document.querySelectorAll('.answer-btn');
1283            const resultMessage = document.getElementById('resultMessage');
1284            const isCorrect = selectedAnswer === currentQuestion.correctAnswer;
1285
1286            buttons.forEach((btn, index) => {
1287                btn.disabled = true;
1288                if (index + 1 === currentQuestion.correctAnswer) {
1289                    btn.classList.add('correct');
1290                } else if (index + 1 === selectedAnswer && !isCorrect) {
1291                    btn.classList.add('wrong');
1292                }
1293            });
1294
1295            if (isCorrect) {
1296                correctAnswers++;
1297                resultMessage.textContent = 'Richtig!';
1298                resultMessage.className = 'result-message correct';
1299                addPoints(1);
1300                updateStatsDisplay();
1301            } else {
1302                resultMessage.textContent = 'Leider falsch!';
1303                resultMessage.className = 'result-message wrong';
1304            }
1305
1306            // Mark current quiz date as played
1307            if (currentQuestion && currentQuestion.date) {
1308                markDateAsPlayed(currentQuestion.date);
1309            }
1310
1311            // Update questions left
1312            const questionsLeft = parseInt(localStorage.getItem(STORAGE_KEYS.QUIZ_QUESTIONS_LEFT) || MAX_QUESTIONS_PER_DAY.toString());
1313            localStorage.setItem(STORAGE_KEYS.QUIZ_QUESTIONS_LEFT, (questionsLeft - 1).toString());
1314
1315            // Remove URL parameters after auto-answer
1316            const urlParams = getUrlParams();
1317            if (urlParams.date || urlParams.answer) {
1318                const cleanUrl = window.location.pathname;
1319                window.history.replaceState({}, document.title, cleanUrl);
1320            }
1321
1322            // Show next button
1323            const quoteCard = document.querySelector('.quote-card');
1324            const nextButton = document.createElement('button');
1325            nextButton.className = 'next-btn';
1326
1327            if (questionsLeft - 1 > 0) {
1328                nextButton.textContent = 'Nächste Frage';
1329                nextButton.onclick = () => {
1330                    loadQuestion();
1331                };
1332            } else {
1333                nextButton.textContent = 'Ergebnisse ansehen';
1334                nextButton.onclick = () => {
1335                    window.location.href = '/app/quiz-results';
1336                };
1337            }
1338
1339            quoteCard.appendChild(nextButton);
1340        }
1341
1342        // Update Stats Display
1343        function updateStatsDisplay() {
1344            const todayPoints = parseInt(localStorage.getItem(STORAGE_KEYS.QUIZ_POINTS_TODAY) || '0');
1345            const questionsLeft = parseInt(localStorage.getItem(STORAGE_KEYS.QUIZ_QUESTIONS_LEFT) || MAX_QUESTIONS_PER_DAY.toString());
1346
1347            const statValues = document.querySelectorAll('.stat-value');
1348            if (statValues.length >= 3) {
1349                statValues[0].textContent = questionsLeft;
1350                statValues[1].textContent = todayPoints;
1351                statValues[2].textContent = stats.totalPoints;
1352            }
1353        }
1354
1355        // Show Completed Message
1356        function showCompletedMessage() {
1357            const content = document.getElementById('quizContent');
1358            const todayPoints = parseInt(localStorage.getItem(STORAGE_KEYS.QUIZ_POINTS_TODAY) || '0');
1359
1360            content.innerHTML = `
1361                <div class="completed-message">
1362                    <h2>Glückwunsch!</h2>
1363                    <p>Du hast heute alle ${MAX_QUESTIONS_PER_DAY} Fragen beantwortet.</p>
1364                    <p>Du hast heute <strong>${todayPoints} Punkte</strong> erzielt.</p>
1365                    <p>Komm morgen wieder für neue Fragen.</p>
1366                    <a href="/app/quiz-results" class="results-btn">Ergebnisse ansehen</a>
1367                    <div class="quick-links">
1368                        <a href="https://www.zitatdestages.net">Zitat des Tages</a>
1369                        <a href="/newsletter">Newsletter</a>
1370                        <a href="/app">App</a>
1371                    </div>
1372                </div>
1373            `;
1374        }
1375
1376        // Fallback Question
1377        function getFallbackQuestion() {
1378            const now = new Date();
1379            const todayDate = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}-${String(now.getDate()).padStart(2, '0')}`;
1380
1381            return {
1382                quote: "Das Leben ist das, was passiert, während du eifrig dabei bist, andere Pläne zu machen.",
1383                answer1: "John Lennon",
1384                answer2: "Albert Einstein",
1385                correctAnswer: 1,
1386                backgroundImage: "https://images.unsplash.com/photo-1506126613408-eca07ce68773?w=1920",
1387                date: todayDate,
1388                uuid: 'fallback-1',
1389                answer1Uuid: '',
1390                answer2Uuid: '',
1391                backgroundImageUuid: '',
1392                language: 'de'
1393            };
1394        }
1395
1396        // Display Question
1397        function displayQuestion(question) {
1398            const container = document.getElementById('quizContainer');
1399            const content = document.getElementById('quizContent');
1400
1401            if (!question || !question.quote) {
1402                content.innerHTML = `
1403                    <div class="error">
1404                        <h3>Fehler</h3>
1405                        <p>Ungültige Frage. Bitte versuche es erneut.</p>
1406                        <button class="next-btn" onclick="location.reload()">Neu laden</button>
1407                    </div>
1408                `;
1409                return;
1410            }
1411
1412            // Set background image with fallback
1413            const backgroundImage = question.backgroundImage || 'https://images.unsplash.com/photo-1506126613408-eca07ce68773?w=1920';
1414
1415            // Preload image before setting
1416            const img = new Image();
1417            img.onload = () => {
1418                container.style.backgroundImage = `url('${backgroundImage}')`;
1419            };
1420            img.onerror = () => {
1421                container.style.backgroundImage = `url('https://images.unsplash.com/photo-1506126613408-eca07ce68773?w=1920')`;
1422            };
1423            img.src = backgroundImage;
1424
1425            const questionsLeft = parseInt(localStorage.getItem(STORAGE_KEYS.QUIZ_QUESTIONS_LEFT) || MAX_QUESTIONS_PER_DAY.toString());
1426            const todayPoints = parseInt(localStorage.getItem(STORAGE_KEYS.QUIZ_POINTS_TODAY) || '0');
1427
1428            content.innerHTML = `
1429                <div class="header">
1430                    <h1>Quiz des Tages</h1>
1431                    <p>
1431Von wem stammt dieses Zitat?</p>
1432                </div>
1433
1434                <div class="quote-card">
1435                    <div class="quote-text">${escapeHtml(question.quote)}</div>
1436
1437                    <div class="answers-container">
1438                        <button class="answer-btn" onclick="checkAnswer(1)"><span class="label">${escapeHtml(question.answer1)}</span></button>
1439                        <button class="answer-btn" onclick="checkAnswer(2)"><span class="label">${escapeHtml(question.answer2)}</span></button>
1440                    </div>
1441
1442                    <div class="result-message" id="resultMessage"></div>
1443                </div>
1444
1445                <div class="stats-bar">
1446                    <div class="stat">
1447                        <div class="stat-label">Fragen übrig</div>
1448                        <div class="stat-value">${questionsLeft}</div>
1449                    </div>
1450                    <div class="stat">
1451                        <div class="stat-label">Heute richtig</div>
1452                        <div class="stat-value">${todayPoints}</div>
1453                    </div>
1454                    <div class="stat">
1455                        <div class="stat-label">Gesamtpunkte</div>
1456                        <div class="stat-value">${stats.totalPoints}</div>
1457                    </div>
1458                </div>
1459            `;
1460
1461            answered = false;
1462
1463            // NEU: Auto-Answer wenn answer-Parameter vorhanden
1464            const urlParams = getUrlParams();
1465            if (urlParams.answer && (urlParams.answer === '1' || urlParams.answer === '2')) {
1466                // Kleine Verzögerung damit Animation sichtbar ist
1467                setTimeout(() => {
1468                    checkAnswer(parseInt(urlParams.answer));
1469                }, 300);
1470            }
1471        }
1472
1473        // Utility: URL-Parameter auslesen
1474        function getUrlParams() {
1475            const params = new URLSearchParams(window.location.search);
1476            return {
1477                date: params.get('date'), // z.B. ?date=2024-01-15
1478                answer: params.get('answer') // z.B. ?answer=1 oder ?answer=2
1479            };
1480        }
1481
1482        // Utility: Escape HTML
1483        function escapeHtml(text) {
1484            const map = {
1485                '&': '&amp;',
1486                '<': '&lt;',
1487                '>': '&gt;',
1488                '"': '&quot;',
1489                "'": '&#039;'
1490            };
1491            return text.replace(/[&<>"']/g, m => map[m]);
1492        }
1493    </script>
1493
1494</body>
1495
1496<!-- Share Overlay -->
1497<div class="share-overlay" id="shareOverlay">
1498    <div class="share-modal">
1499        <button class="share-close-btn" onclick="closeShareOverlay()">×</button>
1500        <h3 id="shareTitle">Tu dir selbst oder jemandem anderen was gutes</h3>
1501        <p>Sende das Zitat des Tages an dein Handy, deine Freunden oder Familie. Gemeinsam inspirieren wir uns
1502            gegenseitig!</p>
1503        <div class="share-modal-buttons">
1504            <button class="newsletter-submit" onclick="shareApp()"
1505                style="width: 100%; padding: 12px 24px; display: flex; align-items: center; justify-content: center; gap: 8px;">
1506                <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"
1507                    stroke-linecap="round" stroke-linejoin="round">
1508                    <circle cx="18" cy="5" r="3"></circle>
1509                    <circle cx="6" cy="12" r="3"></circle>
1510                    <circle cx="18" cy="19" r="3"></circle>
1511                    <line x1="8.59" y1="13.51" x2="15.42" y2="17.49"></line>
1512                    <line x1="15.41" y1="6.51" x2="8.59" y2="10.49"></line>
1513                </svg>
1514                Sende dieses Quiz an ...
1515            </button>
1516        </div>
1517    </div>
1518</div>
1519
1520<script>
1521    // Share functionality
1522    let shareOverlayShown = false;
1523
1524    function shareApp() {
1525        const url = window.location.href;
1526        const title = 'Quiz - Zitat des Tages';
1527        const text = 'Teste dein Wissen beim Zitat des Tages Quiz!';
1528
1529        if (navigator.share) {
1530            navigator.share({
1531                title: title,
1532                text: text,
1533                url: url
1534            }).then(() => {
1535                closeShareOverlay();
1536            }).catch((error) => {
1537                console.log('Share cancelled or failed:', error);
1538            });
1539        } else {
1540            // Fallback: Copy to clipboard
1541            navigator.clipboard.writeText(url).then(() => {
1542                alert('Link wurde in die Zwischenablage kopiert!');
1543                closeShareOverlay();
1544            }).catch((error) => {
1545                console.error('Failed to copy:', error);
1546            });
1547        }
1548    }
1549
1550    function openShareOverlay(title) {
1551        if (shareOverlayShown) return;
1552
1553        shareOverlayShown = true;
1554        const overlay = document.getElementById('shareOverlay');
1555        const titleElement = document.getElementById('shareTitle');
1556
1557        if (title) {
1558            titleElement.textContent = title;
1559        }
1560
1561        overlay.classList.add('active');
1562    }
1563
1564    function closeShareOverlay() {
1565        const overlay = document.getElementById('shareOverlay');
1566        overlay.classList.remove('active');
1567    }
1568
1569    // Detect mobile
1570    function isMobile() {
1571        return window.innerWidth <= 768;
1572    }
1573
1574    // Timer-based trigger (20 seconds)
1575    setTimeout(() => {
1576        if (!shareOverlayShown) {
1577            openShareOverlay(isMobile() ? 'Tu dir selbst oder jemandem anderen was gutes!' : 'Tu dir selbst oder jemandem anderen was gutes!');
1578        }
1579    }, 20000);
1580
1581    // Desktop: Mouse out detection
1582    if (!isMobile()) {
1583        document.addEventListener('mouseout', function (e) {
1584            if (!e.toElement && !e.relatedTarget && !shareOverlayShown) {
1585                openShareOverlay('Bitte geh noch nicht!');
1586            }
1587        });
1588    }
1589
1590    // Scroll to bottom detection
1591    let scrollTriggered = false;
1592    window.addEventListener('scroll', function () {
1593        if (scrollTriggered || shareOverlayShown) return;
1594
1595        const scrollTop = window.pageYOffset || document.documentElement.scrollTop;
1596        const windowHeight = window.innerHeight;
1597        const documentHeight = document.documentElement.scrollHeight;
1598
1599        // Check if scrolled to bottom (with 100px threshold)
1600        if (scrollTop + windowHeight >= documentHeight - 100) {
1601            scrollTriggered = true;
1602            openShareOverlay('Tu dir selbst oder jemandem anderen was gutes!');
1603        }
1604    });
1605
1606    // Close overlay when clicking outside
1607    document.getElementById('shareOverlay').addEventListener('click', function (e) {
1608        if (e.target === this) {
1609            closeShareOverlay();
1610        }
1611    });
1612</script>
1612
1613
1614<!-- Newsletter Overlay -->
1615<div class="share-overlay" id="newsletterOverlay">
1616    <div class="share-modal">
1617        <button class="share-close-btn" onclick="closeNewsletterOverlay()">×</button>
1618        <h3>Abonniere das Zitat des Tages per Mail</h3>
1619        <p>Täglich ein ausgewähltes Zitat in dein Postfach</p>
1620
1621        <div class="newsletter-form-container">
1622            <form style="display:inline" method="post" action="https://www.zitatdestages.net/?na=s"
1623                onsubmit="return newsletter_check(this)">
1624                <input type="hidden" name="nlang" value="">
1625                <input type="hidden" name="nr" value="page">
1626                <input class="newsletter-input" placeholder="Deine E-Mail Adresse" type="email" name="ne" required="">
1627                <input class="newsletter-submit" type="submit" value="Anmelden">
1628            </form>
1629        </div>
1630
1631        <p class="newsletter-footer">Kostenlos, ohne Spam und jederzeit wieder abmelden.</p>
1632    </div>
1633</div>
1634
1635<script>
1636    // Newsletter Overlay Logic
1637    function openNewsletterOverlay() {
1638        document.getElementById('newsletterOverlay').classList.add('active');
1639        document.body.style.overflow = 'hidden';
1640        // Close menu if open
1641        if (document.getElementById('menuOverlay').classList.contains('active')) {
1642            toggleMenu();
1643        }
1644    }
1645
1646    function closeNewsletterOverlay() {
1647        document.getElementById('newsletterOverlay').classList.remove('active');
1648        document.body.style.overflow = '';
1649    }
1650
1651    // Close on click outside
1652    document.getElementById('newsletterOverlay').addEventListener('click', (e) => {
1653        if (e.target.id === 'newsletterOverlay') closeNewsletterOverlay();
1654    });
1655
1656    function newsletter_check(f) {
1657        var re = /^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/;
1658        if (!re.test(f.elements["ne"].value)) {
1659            alert("Bitte eine gültige E-Mail Adresse eingeben.");
1660            return false;
1661        }
1662        return true;
1663    }
1664</script>
1664
1665</body>
1666
1667</html>

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.