PageSourceSearch

https://sign-edu.netlify.app/

html sign-edu.netlify.app collected 2026-10-03 11:24:23 UTC 66,975 bytes, 1,636 lines download raw bytes

1<!DOCTYPE html>
2<html lang="en">
3<head>
4    <meta charset="UTF-8">
5<!-- This site is hosted on Netlify. Anyone can build and deploy a site
6     like this one for free: https://netlify.new/?utm_campaign=loops&utm_source=ai-legible&utm_medium=owned&utm_content=comment&utm_id=8b60a803-5529-4fb0-b25c-5e458e94d6de
7     Netlify hosting facts for this site: static/SSR served via Netlify Edge. -->
8    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
9    <title>Educational Sign Language Expressions</title>
10    <!-- Include EmailJS for certificate emails -->
11    
11<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/@emailjs/browser@3/dist/email.min.js"></script>
11
12    <!-- Include html2canvas for certificate generation -->
13    
13<script src="https://html2canvas.hertzen.com/dist/html2canvas.min.js"></script>
13
14    <style>
15        * {
16            -webkit-tap-highlight-color: transparent;
17            box-sizing: border-box;
18        }
19        
20        body {
21            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
22            max-width: 100%;
23            margin: 0 auto;
24            padding: 16px;
25            text-align: center;
26            background-color: #f0f4fa;
27            color: #333;
28            -webkit-text-size-adjust: 100%;
29            overscroll-behavior: none;
30        }
31        
32        h1 {
33            color: #2c3e50;
34            margin-bottom: 10px;
35            font-size: 28px;
36        }
37        
38        h2 {
39            color: #1e88e5;
40            margin-top: 10px;
41            font-size: 22px;
42        }
43        
44        .container {
45            background-color: white;
46            border-radius: 16px;
47            padding: 16px;
48            box-shadow: 0 4px 12px rgba(0,0,0,0.1);
49            margin-top: 16px;
50            max-width: 800px;
51            margin-left: auto;
52            margin-right: auto;
53        }
54        
55        .sign-display {
56            display: flex;
57            flex-direction: column;
58            justify-content: center;
59            align-items: center;
60            min-height: 280px;
61            margin: 16px 0;
62            background-color: #e3f2fd;
63            border-radius: 16px;
64            padding: 20px;
65            position: relative;
66            touch-action: manipulation;
67            border: 1px solid #bbdefb;
68        }
69        
70        .sign-emoji {
71            font-size: 80px;
72            margin-bottom: 15px;
73        }
74        
75        .sign-sequence {
76            display: flex;
77            justify-content: center;
78            align-items: center;
79            gap: 15px;
80            flex-wrap: wrap;
81            margin-bottom: 20px;
82            padding: 10px;
83        }
84        
85        .sequence-item {
86            display: flex;
87            flex-direction: column;
88            align-items: center;
89            padding: 10px;
90            background-color: white;
91            border-radius: 12px;
92            min-width: 75px;
93            box-shadow: 0 2px 4px rgba(0,0,0,0.05);
94            margin: 5px;
95            border: 1px solid #bbdefb;
96        }
97        
98        .sequence-emoji {
99            font-size: 56px;
100            margin-bottom: 8px;
101        }
102        
103        .sequence-step {
104            font-size: 14px;
105            color: #1976d2;
106            text-align: center;
107            padding: 0 4px;
108        }
109        
110        .sign-expression {
111            font-size: 24px;
112            font-weight: bold;
113            color: #1565c0;
114            margin-bottom: 15px;
115            padding: 0 10px;
116            text-align: center;
117        }
118        
119        .sign-description {
120            font-size: 16px;
121            color: #1976d2;
122            line-height: 1.5;
123            max-width: 100%;
124            padding: 0 5px;
125            text-align: center;
126        }
127        
128        .controls {
129            display: flex;
130            justify-content: center;
131            gap: 12px;
132            margin: 16px 0;
133            flex-wrap: wrap;
134        }
135        
136        button {
137            background-color: #2196f3;
138            color: white;
139            border: none;
140            padding: 12px 18px;
141            border-radius: 12px;
142            cursor: pointer;
143            font-size: 16px;
144            transition: background-color 0.2s, transform 0.1s;
145            -webkit-appearance: none;
146            -moz-appearance: none;
147            appearance: none;
148            touch-action: manipulation;
149            user-select: none;
150            -webkit-user-select: none;
151            min-height: 44px;
152        }
153        
154        button:active {
155            transform: scale(0.98);
156            background-color: #1976d2;
157        }
158        
159        button.active {
160            background-color: #1976d2;
161            font-weight: bold;
162        }
163        
164        .expression-selection {
165            display: flex;
166            flex-wrap: wrap;
167            justify-content: center;
168            gap: 10px;
169            margin: 16px 0;
170        }
171        
172        .expression-btn {
173            min-width: 130px;
174            padding: 12px 16px;
175            font-size: 15px;
176        }
177        
178        .categories {
179            display: flex;
180            justify-content: center;
181            gap: 8px;
182            margin-bottom: 16px;
183            flex-wrap: wrap;
184            padding: 0 5px;
185        }
186        
187        .category-btn {
188            background-color: #64b5f6;
189            min-width: 120px;
190            font-size: 15px;
191            color: #0d47a1;
192        }
193        
194        .category-btn.active {
195            background-color: #2196f3;
196            color: white;
197        }
198        
199        .quiz-section {
200            margin-top: 24px;
201            background-color: #e3f2fd;
202            padding: 16px;
203            border-radius: 16px;
204        }
205        
206        .quiz-options {
207            display: flex;
208            flex-wrap: wrap;
209            justify-content: center;
210            gap: 12px;
211            margin-top: 16px;
212        }
213        
214        .quiz-option-btn {
215            min-width: 140px;
216            padding: 14px 18px;
217            font-size: 16px;
218        }
219        
220        .quiz-result {
221            margin-top: 16px;
222            font-weight: bold;
223            min-height: 24px;
224            padding: 8px;
225        }
226        
227        .correct {
228            color: #2e7d32;
229        }
230        
231        .incorrect {
232            color: #c62828;
233        }
234        
235        .progress-bar-container {
236            width: 100%;
237            background-color: #bbdefb;
238            border-radius: 20px;
239            margin: 20px 0;
240            overflow: hidden;
241            height: 16px;
242        }
243        
244        .progress-bar {
245            height: 16px;
246            background-color: #2196f3;
247            border-radius: 20px;
248            width: 0%;
249            transition: width 0.5s;
250        }
251        
252        .progress-text {
253            font-size: 14px;
254            color: #1976d2;
255            margin-top: 5px;
256        }
257        
258        .arrow {
259            font-size: 24px;
260            color: #2196f3;
261            margin: 0 5px;
262            display: flex;
263            align-items: center;
264        }
265        
266        #test-container {
267            display: none;
268        }
269        
270        /* Test score display */
271        .test-score {
272            margin: 20px 0;
273            font-size: 18px;
274            font-weight: bold;
275        }
276        
277        .test-progress {
278            display: flex;
279            align-items: center;
280            justify-content: center;
281            margin: 10px 0;
282            font-size: 16px;
283        }
284        
285        .score-good {
286            color: #2e7d32;
287        }
288        
289        .score-avg {
290            color: #f57f17;
291        }
292        
293        .score-poor {
294            color: #c62828;
295        }
296        
297        /* Enhanced touch feedback */
298        .touch-feedback {
299            position: relative;
300            overflow: hidden;
301        }
302        
303        .touch-feedback::after {
304            content: '';
305            display: block;
306            position: absolute;
307            width: 100%;
308            height: 100%;
309            top: 0;
310            left: 0;
311            pointer-events: none;
312            background-image: radial-gradient(circle, rgba(255,255,255,0.4) 10%, transparent 10.01%);
313            background-repeat: no-repeat;
314            background-position: 50%;
315            transform: scale(10, 10);
316            opacity: 0;
317            transition: transform 0.5s, opacity 0.8s;
318        }
319        
320        .touch-feedback:active::after {
321            transform: scale(0, 0);
322            opacity: 0.3;
323            transition: 0s;
324        }
325        
326        /* Certificate form styles */
327        .certificate-form {
328            background-color: #e3f2fd;
329            padding: 20px;
330            border-radius: 16px;
331            margin-top: 20px;
332            display: none;
333            border: 1px solid #bbdefb;
334        }
335        
336        .certificate-form h3 {
337            margin-top: 0;
338            color: #1565c0;
339        }
340        
341        .form-group {
342            margin-bottom: 15px;
343            text-align: left;
344        }
345        
346        .form-group label {
347            display: block;
348            margin-bottom: 5px;
349            font-weight: bold;
350            color: #1565c0;
351        }
352        
353        .form-group input {
354            width: 100%;
355            padding: 10px;
356            border: 1px solid #64b5f6;
357            border-radius: 8px;
358            font-size: 16px;
359        }
360        
361        .overlay {
362            position: fixed;
363            top: 0;
364            left: 0;
365            width: 100%;
366            height: 100%;
367            background-color: rgba(0, 0, 0, 0.7);
368            display: none;
369            justify-content: center;
370            align-items: center;
371            z-index: 1000;
372        }
373        
374        .modal {
375            background-color: white;
376            padding: 30px;
377            border-radius: 16px;
378            max-width: 90%;
379            max-height: 90%;
380            overflow-y: auto;
381            position: relative;
382        }
383        
384        .close-modal {
385            position: absolute;
386            top: 10px;
387            right: 15px;
388            font-size: 24px;
389            cursor: pointer;
390            color: #1976d2;
391        }
392        
393        .loading-indicator {
394            display: none;
395            margin-top: 20px;
396        }
397        
398        .spinner {
399            border: 4px solid #bbdefb;
400            border-top: 4px solid #2196f3;
401            border-radius: 50%;
402            width: 30px;
403            height: 30px;
404            animation: spin 1s linear infinite;
405            margin: 0 auto;
406        }
407        
408        @keyframes spin {
409            0% { transform: rotate(0deg); }
410            100% { transform: rotate(360deg); }
411        }
412        
413        /* Motion descriptions for test mode */
414        .motion-description {
415            font-style: italic;
416            color: #1565c0;
417            margin: 15px 0;
418            padding: 12px;
419            text-align: center;
420            font-size: 16px;
421            line-height: 1.6;
422            background-color: white;
423            border-radius: 10px;
424            border: 1px solid #bbdefb;
425        }
426        
427        /* Different screen sizes */
428        @media (max-width: 480px) {
429            body {
430                padding: 10px;
431            }
432            
433            h1 {
434                font-size: 24px;
435            }
436            
437            .sign-display {
438                min-height: 260px;
439                padding: 12px;
440            }
441            
442            .sign-emoji {
443                font-size: 50px;
444            }
445            
446            .sequence-emoji {
447                font-size: 44px;
448            }
449            
450            .sequence-item {
451                min-width: 60px;
452            }
453            
454            .sign-expression {
455                font-size: 20px;
456            }
457            
458            .expression-btn {
459                min-width: 130px;
460                padding: 10px 14px;
461                font-size: 14px;
462            }
463            
464            .category-btn {
465                min-width: 100px;
466                padding: 10px 12px;
467                font-size: 14px;
468            }
469            
470            button {
471                padding: 12px 16px;
472            }
473        }
474        
475        /* iPad specific adjustments */
476        @media only screen and (min-device-width: 768px) and (max-device-width: 1024px) {
477            .container {
478                max-width: 90%;
479            }
480            
481            .expression-btn {
482                min-width: 150px;
483                padding: 14px 18px;
484                font-size: 16px;
485            }
486            
487            .category-btn {
488                min-width: 130px;
489                padding: 14px 16px;
490            }
491            
492            .sequence-emoji {
493                font-size: 70px;
494            }
495        }
496        
497        /* Certificate styles */
498        .certificate-container {
499            position: fixed;
500            top: 0;
501            left: 0;
502            width: 100%;
503            height: 100%;
504            background: white;
505            display: flex;
506            justify-content: center;
507            align-items: center;
508            z-index: -1;
509        }
510        
511        .certificate {
512            font-family: 'Times New Roman', Times, serif;
513            text-align: center;
514            position: relative;
515            width: 800px;
516            height: 600px;
517            padding: 50px;
518            border: 10px solid #2196f3;
519            box-sizing: border-box;
520            background: #fff;
521            margin: 0 auto;
522        }
523        
524        .certificate .logo {
525            font-size: 24px;
526            margin-bottom: 12px;
527            color: #1565c0;
528        }
529        
530        .certificate h1 {
531            font-size: 40px;
532            margin-bottom: 12px;
533            color: #1565c0;
534        }
535        
536        .certificate .smaller-text {
537            font-size: 16px;
538            color: #1976d2;
539        }
540        
541        .certificate .recipient {
542            font-size: 30px;
543            margin: 20px 0;
544            font-weight: bold;
545            color: #1565c0;
546        }
547        
548        .certificate .reason {
549            font-size: 24px;
550            margin: 20px 0;
551            color: #1976d2;
552        }
553        
554        .certificate .date {
555            font-size: 12px;
556            margin-top: 8px;
557            color: #1976d2;
558        }
559        
560        .certificate .signatures {
561            display: flex;
562            justify-content: space-around;
563            margin-top: 20px;
564        }
565        
566        .certificate .signature {
567            font-size: 12px;
568            width: 300px;
569            text-align: center;
570            display: flex;
571            flex-direction: column;
572            align-items: center;
573            border-top: none;
574            color: #1976d2;
575        }
576        
577        .signature-image {
578            width: 137px;
579            height: 80px;
580            margin-bottom: 10px;
581            object-fit: contain;
582        }
583        
584        .signature-line {
585            width: 200px;
586            border-top: 1px solid #2196f3;
587            margin: 5px auto;
588        }
589        
590        .course-description {
591            font-size: 16px;
592            color: #1976d2;
593            margin-top: 20px;
594            font-style: italic;
595        }
596        
597        /* Disable zooming on double tap (preserves accessibility through pinch zoom) */
598        button, a {
599            touch-action: manipulation;
600        }
601        
602        /* App title styles */
603        .app-title {
604            background-color: #2196f3;
605            color: white;
606            padding: 16px;
607            border-radius: 10px;
608            margin-bottom: 20px;
609            box-shadow: 0 3px 6px rgba(0,0,0,0.1);
610        }
611        
612        .app-title h1 {
613            color: white;
614            margin: 0;
615        }
616        
617        .app-title p {
618            margin: 8px 0 0 0;
619            font-size: 16px;
620            opacity: 0.9;
621        }
622        
623        /* Level indicator */
624        .level-indicator {
625            background-color: #0d47a1;
626            color: white;
627            display: inline-block;
628            padding: 5px 10px;
629            border-radius: 5px;
630            font-size: 14px;
631            margin-left: 10px;
632            vertical-align: middle;
633        }
634        
635        /* Education implementation section */
636        .edu-implementation {
637            background-color: #e3f2fd;
638            border: 1px solid #bbdefb;
639            border-radius: 10px;
640            padding: 15px;
641            margin: 20px 0;
642        }
643        
644        .edu-implementation h3 {
645            color: #1565c0;
646            margin-top: 0;
647            font-size: 18px;
648        }
649        
650        .implementation-grid {
651            display: flex;
652            flex-wrap: wrap;
653            justify-content: center;
654            gap: 15px;
655            margin-top: 15px;
656        }
657        
658        .implementation-card {
659            background-color: white;
660            border-radius: 8px;
661            padding: 15px;
662            width: 200px;
663            border: 1px solid #bbdefb;
664            text-align: center;
665        }
666        
667        .implementation-icon {
668            font-size: 32px;
669            margin-bottom: 10px;
670        }
671        
672        .implementation-title {
673            font-weight: bold;
674            color: #1565c0;
675            margin-bottom: 5px;
676        }
677        
678        .implementation-text {
679            font-size: 14px;
680            color: #1976d2;
681            line-height: 1.4;
682        }
683        
684        /* Education theme elements */
685        .notebook-lines {
686            position: relative;
687        }
688        
689        .notebook-lines::before {
690            content: "";
691            position: absolute;
692            left: -5px;
693            top: 0;
694            height: 100%;
695            width: 3px;
696            background-color: #e91e63;
697            border-radius: 2px;
698        }
699        
700        .app-icon {
701            font-size: 28px;
702            margin-right: 10px;
703            vertical-align: middle;
704            position: relative;
705            top: -2px;
706        }
707    </style>
708</head>
709<body>
710    <div class="app-title notebook-lines">
711        <h1><span class="app-icon">📚</span> Educational Sign Language <span class="level-indicator">Academic</span></h1>
712        <p>Learn expressions for effective communication in classrooms and educational settings</p>
713    </div>
714    
715    <div class="mode-toggle controls">
716        <button id="learn-mode-btn" class="active touch-feedback">Learn Mode</button>
717        <button id="test-mode-btn" class="touch-feedback">Test Mode</button>
718    </div>
719    
720    <div id="learn-container" class="container">
721        <div class="categories" id="categories">
722            <!-- Categories will be added here by JavaScript -->
723        </div>
724        
725        <div class="sign-display">
726            <div class="sign-sequence" id="sign-sequence">
727                <div class="sequence-item">
728                    <div class="sequence-emoji">👋</div>
729                    <div class="sequence-step">Start</div>
730                </div>
731            </div>
732            <div class="sign-expression" id="current-expression">Welcome to Educational Signs!</div>
733            <div class="sign-description" id="sign-description">Select a category to begin learning sign language expressions for classroom and educational environments.</div>
734        </div>
735        
736        <div class="expression-selection" id="expression-selection">
737            <!-- Expression buttons will be added here by JavaScript -->
738        </div>
739        
740        <div class="progress-bar-container">
741            <div class="progress-bar" id="progress-bar"></div>
742        </div>
743        <div class="progress-text" id="progress-text">0/0 expressions learned</div>
744        
745        <div class="edu-implementation">
746            <h3>Implementing Sign Language in Educational Settings</h3>
747            
748            <div class="implementation-grid">
749                <div class="implementation-card">
750                    <div class="implementation-icon">👨‍🏫</div>
751                    <div class="implementation-title">Inclusive Teaching</div>
752                    <div class="implementation-text">Create an inclusive classroom environment for all students</div>
753                </div>
754                <div class="implementation-card">
755                    <div class="implementation-icon">🧩</div>
756                    <div class="implementation-title">Visual Learning</div>
757                    <div class="implementation-text">Enhance retention through visual-kinesthetic approaches</div>
758                </div>
759                <div class="implementation-card">
760                    <div class="implementation-icon">🤝</div>
761                    <div class="implementation-title">Peer Connection</div>
762                    <div class="implementation-text">Build bridges between students with different abilities</div>
763                </div>
764                <div class="implementation-card">
765                    <div class="implementation-icon">🗣️</div>
766                    <div class="implementation-title">Communication Skills</div>
767                    <div class="implementation-text">Develop multiple modes of expression and comprehension</div>
768                </div>
769            </div>
770        </div>
771    </div>
772    
773    <div id="test-container" class="container">
774        <h2>Test Your Educational Sign Language</h2>
775        <div class="test-progress" id="test-progress">Question 1 of 10</div>
776        
777        <div class="sign-display">
778            <div class="sign-sequence" id="quiz-sequence">
779                <!-- Quiz sequence will be added here by JavaScript -->
780            </div>
781            <div class="motion-description" id="motion-description">
782                <!-- Motion description will be added here by JavaScript -->
783            </div>
784        </div>
785        
786        <div class="quiz-options" id="quiz-options">
787            <!-- Quiz options will be added here by JavaScript -->
788        </div>
789        
790        <div class="quiz-result" id="quiz-result"></div>
791        
792        <div class="test-score" id="test-score"></div>
793        
794        <div class="controls">
795            <button id="next-question" class="touch-feedback">Next Question</button>
796        </div>
797        
798        <div class="certificate-form" id="certificate-form">
799            <h3>Congratulations! You've passed the test!</h3>
800            <p>Enter your details to receive your certificate:</p>
801            
802            <div class="form-group">
803                <label for="name">Full Name:</label>
804                <input type="text" id="name" placeholder="Enter your full name" required>
805            </div>
806            
807            <div class="form-group">
808                <label for="email">Email Address:</label>
809                <input type="email" id="email" placeholder="Enter your email address" required>
810            </div>
811            
812            <button id="submit-certificate" class="touch-feedback">Generate Certificate</button>
813            
814            <div class="loading-indicator" id="loading-indicator">
815                <p>Generating your certificate...</p>
816                <div class="spinner"></div>
817            </div>
818        </div>
819    </div>
820    
821    <div class="overlay" id="certificate-overlay">
822        <div class="modal">
823            <span class="close-modal" id="close-modal">&times;</span>
824            <h2>Certificate Preview</h2>
825            <div id="certificate-preview"></div>
826        </div>
827    </div>
828    <h5 align = "center">CHEUNG NGO MEDICAL 翱翔醫療</h5>
829    
830    
830<script>
831        // Initialize EmailJS
832        (function() {
833            emailjs.init("dV1Wvtndk67MC0lHt"); // Replace with your actual EmailJS public key
834        })();
835        
836        // Educational sign language expressions data organized by categories
837        const signExpressions = {
838            "Classroom Basics": {
839                "May I ask a question?": {
840                    sequence: [
841                        { emoji: "🤔", description: "May I" },
842                        { emoji: "❓", description: "Ask (questioning motion)" },
843                        { emoji: "❓", description: "Question (draw Q)" }
844                    ],
845                    description: "Make a questioning gesture toward yourself, mime asking by pointing to your mouth, then draw a question mark shape in the air.",
846                    motionOnly: "Point to yourself with a questioning expression, point to your mouth and then outward, then draw a question mark shape in the air with your index finger."
847                },
848                "I don't understand": {
849                    sequence: [
850                        { emoji: "👉", description: "I" },
851                        { emoji: "🚫", description: "Don't" },
852                        { emoji: "🧠", description: "Understand (at temple)" }
853                    ],
854                    description: "Point to yourself, make a negative motion by moving your index finger side to side, then touch your temple and move your hand outward.",
855                    motionOnly: "Point to yourself, move your index finger from side to side in a 'no' gesture, then touch your temple with your index finger and move your hand outward and away."
856                },
857                "Please repeat that": {
858                    sequence: [
859                        { emoji: "🙏", description: "Please" },
860                        { emoji: "🔄", description: "Repeat (circular motion)" },
861                        { emoji: "👇", description: "That" }
862                    ],
863                    description: "Make the 'please' sign by circling your flat hand on your chest, make a circular motion with your index finger, then point to what you're referring to.",
864                    motionOnly: "Circle your flat hand on your chest, make a circular motion with your index finger rotating forward, then point to what you're referring to."
865                },
866                "Can you help me?": {
867                    sequence: [
868                        { emoji: "❓", description: "Can you" },
869                        { emoji: "🤝", description: "Help (fists stacked)" },
870                        { emoji: "👉", description: "Me" }
871                    ],
872                    description: "Make a questioning gesture toward the person, show 'help' by placing one fist on top of the other and lifting, then point to yourself.",
873                    motionOnly: "Make a questioning expression toward someone, place one fist on top of your other hand and lift both hands upward, then point to yourself."
874                },
875                "Thank you for explaining": {
876                    sequence: [
877                        { emoji: "🙏", description: "Thank you" },
878                        { emoji: "👐", description: "For" },
879                        { emoji: "📝", description: "Explaining (details motion)" }
880                    ],
881                    description: "Touch your fingers to your chin then extend outward for 'thank you', show open palms for 'for', then mime explaining with detailed hand motions.",
882                    motionOnly: "Touch your fingertips to your lips or chin and move your hand outward and down with palm up, hold both palms open briefly, then make a detailed explaining motion with both hands."
883                }
884            },
885            "Lesson Activities": {
886                "Time to work in groups": {
887                    sequence: [
888                        { emoji: "⏰", description: "Time" },
889                        { emoji: "💪", description: "Work/Activity" },
890                        { emoji: "👥", description: "Groups (circles together)" }
891                    ],
892                    description: "Tap your wrist for 'time', make a working motion with your hands, then form circles with both hands to show 'groups'.",
893                    motionOnly: "Tap your wrist where a watch would be, make working motions with your hands, then form two circles with your hands and bring them together to show groups."
894                },
895                "Please open your book": {
896                    sequence: [
897                        { emoji: "🙏", description: "Please" },
898                        { emoji: "📖", description: "Open (book motion)" },
899                        { emoji: "👉", description: "Your" },
900                        { emoji: "📚", description: "Book" }
901                    ],
902                    description: "Make the 'please' sign by circling your chest, mime opening a book with both hands, point to the person, then show 'book' by holding palms together and opening them.",
903                    motionOnly: "Circle your flat hand on your chest, mime opening a book with both hands (palms together then opening outward), point to the person, then repeat the book opening motion."
904                },
905                "Let's do an exercise": {
906                    sequence: [
907                        { emoji: "👥", description: "Let's" },
908                        { emoji: "🔄", description: "Do" },
909                        { emoji: "📝", description: "Exercise/Activity" }
910                    ],
911                    description: "Make an inclusive gesture with both hands, make a 'do' motion by miming an action, then show 'exercise' by miming writing or working.",
912                    motionOnly: "Make a circular inclusive gesture with both hands, mimic performing an action with your hands, then mime writing or working on something."
913                },
914                "Share your answer": {
915                    sequence: [
916                        { emoji: "🔄", description: "Share (exchange motion)" },
917                        { emoji: "👉", description: "Your" },
918                        { emoji: "✅", description: "Answer (solution)" }
919                    ],
920                    description: "Make a sharing motion from yourself outward, point to the person, then make a check mark motion to show 'answer'.",
921                    motionOnly: "Make an outward sharing motion with both hands extending from your chest, point to the person, then make a check mark motion with your index finger."
922                },
923                "Do you have a question?": {
924                    sequence: [
925                        { emoji: "❓", description: "Do you" },
926                        { emoji: "👐", description: "Have" },
927                        { emoji: "❓", description: "Question (draw Q)" }
928                    ],
929                    description: "Point questioningly to the person, show open palms for 'have', then draw a question mark in the air.",
930                    motionOnly: "Point to the person with raised eyebrows in a questioning manner, hold both palms open as if holding something, then draw a question mark in the air with your index finger."
931                }
932            },
933            "Academic Subjects": {
934                "Let's practice math": {
935                    sequence: [
936                        { emoji: "👥", description: "Let's" },
937                        { emoji: "✍️", description: "Practice" },
938                        { emoji: "🔢", description: "Math (counting)" }
939                    ],
940                    description: "Make an inclusive gesture, mime practicing by moving hands in a repetitive motion, then show 'math' by counting on fingers or making calculation motions.",
941                    motionOnly: "Make a circular inclusive gesture with both hands, mimic a repetitive practice motion, then show counting on your fingers or make calculation motions with your hands."
942                },
943                "Turn to page number...": {
944                    sequence: [
945                        { emoji: "📄", description: "Page (flip motion)" },
946                        { emoji: "🔢", description: "Number (count)" }
947                    ],
948                    description: "Mime turning pages with one hand, then show the number by holding up the appropriate number of fingers.",
949                    motionOnly: "Make a page-turning motion with one hand, then indicate a number by holding up fingers or making a number sign."
950                },
951                "Time for science experiment": {
952                    sequence: [
953                        { emoji: "⏰", description: "Time" },
954                        { emoji: "🧪", description: "Science (lab motion)" },
955                        { emoji: "🔬", description: "Experiment (mixing)" }
956                    ],
957                    description: "Tap your wrist for 'time', make the sign for 'science' by miming looking through a microscope, then show 'experiment' by miming mixing or testing something.",
958                    motionOnly: "Tap your wrist where a watch would be, mime looking through a microscope or telescope, then make mixing or experimental testing motions with your hands."
959                },
960                "Write a paragraph": {
961                    sequence: [
962                        { emoji: "✍️", description: "Write" },
963                        { emoji: "📝", description: "Paragraph (text block)" }
964                    ],
965                    description: "Mime writing with one hand, then show a paragraph by drawing a block of text in the air with both hands.",
966                    motionOnly: "Make a writing motion with one hand as if holding a pen, then use both hands to draw the outline of a text block or paragraph in the air."
967                },
968                "Read the chapter": {
969                    sequence: [
970                        { emoji: "📖", description: "Read" },
971                        { emoji: "📚", description: "Chapter (section)" }
972                    ],
973                    description: "Hold your hands like an open book and move your eyes across it for 'read', then show 'chapter' by making a cutting motion to indicate a section.",
974                    motionOnly: "Hold your hands open like a book and move your eyes from side to side as if reading, then make a cutting or sectioning motion with one hand to indicate a chapter."
975                }
976            },
977            "Classroom Management": {
978                "Please be quiet": {
979                    sequence: [
980                        { emoji: "🙏", description: "Please" },
981                        { emoji: "🤫", description: "Quiet (finger to lips)" }
982                    ],
983                    description: "Make the 'please' sign by circling your flat hand on your chest, then place your index finger to your lips for 'quiet'.",
984                    motionOnly: "Circle your flat hand on your chest, then bring your index finger to your lips in a shushing motion."
985                },
986                "Raise your hand": {
987                    sequence: [
988                        { emoji: "🙋", description: "Raise" },
989                        { emoji: "👉", description: "Your" },
990                        { emoji: "✋", description: "Hand" }
991                    ],
992                    description: "Lift your hand upward for 'raise', point to the person, then show your palm for 'hand'.",
993                    motionOnly: "Lift your hand upward in a raising motion, point to the person, then hold up your palm or hand."
994                },
995                "Form a line": {
996                    sequence: [
997                        { emoji: "🧍", description: "Stand" },
998                        { emoji: "📏", description: "Line (row motion)" }
999                    ],
1000                    description: "Stand up straight with your hand at your side for 'stand', then draw a horizontal line in the air for 'line'.",
1001                    motionOnly: "Hold your hand vertically with fingers together to represent a person standing, then draw a horizontal line in the air to indicate forming a row."
1002                },
1003                "Take turns speaking": {
1004                    sequence: [
1005                        { emoji: "🔄", description: "Take turns (alternating)" },
1006                        { emoji: "🗣️", description: "Speaking (from mouth)" }
1007                    ],
1008                    description: "Move your hands in an alternating circular motion for 'take turns', then move your fingers from your mouth outward for 'speaking'.",
1009                    motionOnly: "Move your index fingers in alternating circular motions to show turns, then bring your fingers to your mouth and move them outward in a speaking gesture."
1010                },
1011                "Clean up your desk": {
1012                    sequence: [
1013                        { emoji: "🧹", description: "Clean (wiping motion)" },
1014                        { emoji: "👉", description: "Your" },
1015                        { emoji: "🪑", description: "Desk (flat surface)" }
1016                    ],
1017                    description: "Make cleaning motions with your hands, point to the person, then show a flat surface for 'desk'.",
1018                    motionOnly: "Make wiping or cleaning motions with your hands, point to the person, then hold both hands flat and parallel to indicate a desk surface."
1019                }
1020            },
1021            "School Events": {
1022                "Assembly in the auditorium": {
1023                    sequence: [
1024                        { emoji: "👥", description: "Assembly (gather)" },
1025                        { emoji: "🏛️", description: "Auditorium (large room)" }
1026                    ],
1027                    description: "Bring your hands together for 'assembly', then outline a large space for 'auditorium'.",
1028                    motionOnly: "Bring your hands together in a gathering motion from multiple directions, then outline a large rectangular space with both hands to indicate a big room."
1029                },
1030                "Parent-teacher conference": {
1031                    sequence: [
1032                        { emoji: "👨‍👩‍👧", description: "Parent (family sign)" },
1033                        { emoji: "👨‍🏫", description: "Teacher" },
1034                        { emoji: "💬", description: "Conference (talk together)" }
1035                    ],
1036                    description: "Make the 'parent' sign by indicating family, show 'teacher' by making an academic or teaching motion, then bring fingers together for 'conference'.",
1037                    motionOnly: "Make a family sign by drawing an arc over your head, mime teaching by pointing to an imaginary board, then bring your hands together with fingers moving to indicate conversation."
1038                },
1039                "School field trip": {
1040                    sequence: [
1041                        { emoji: "🏫", description: "School" },
1042                        { emoji: "🚌", description: "Travel (bus/journey)" },
1043                        { emoji: "🏞️", description: "Field trip (explore)" }
1044                    ],
1045                    description: "Make the 'school' sign by forming a roof shape, show 'travel' by making a bus steering motion, then show 'field trip' by miming exploration.",
1046                    motionOnly: "Form a roof shape with your hands for school, mime holding a large steering wheel, then make exploring motions with your hands as if discovering something new."
1047                },
1048                "Graduation ceremony": {
1049                    sequence: [
1050                        { emoji: "🎓", description: "Graduation (cap)" },
1051                        { emoji: "🎊", description: "Ceremony (celebration)" }
1052                    ],
1053                    description: "Mime placing a graduation cap on your head, then make celebratory gestures with both hands.",
1054                    motionOnly: "Place your hands on your head as if putting on a graduation cap, then make upward celebratory motions with both hands."
1055                },
1056                "Science fair project": {
1057                    sequence: [
1058                        { emoji: "🧪", description: "Science (experiment)" },
1059                        { emoji: "🏆", description: "Fair (compet
1059ition)" },
1060                        { emoji: "📊", description: "Project (display)" }
1061                    ],
1062                    description: "Make a science experiment motion, show 'fair' by indicating a competition or event, then mime setting up a display for 'project'.",
1063                    motionOnly: "Make experimental mixing motions with your hands, create a gathering motion to indicate an event, then mime setting up or presenting a display with both hands."
1064                }
1065            }
1066        };
1067
1068        // Track learned expressions
1069        const learnedExpressions = {};
1070        let currentCategory = "Classroom Basics";
1071        let totalExpressions = 0;
1072        
1073        // Test variables
1074        const totalTestQuestions = 10;
1075        let currentQuestionNumber = 1;
1076        let correctAnswers = 0;
1077        let testCompleted = false;
1078        
1079        // Count total expressions
1080        for (const category in signExpressions) {
1081            for (const expression in signExpressions[category]) {
1082                totalExpressions++;
1083            }
1084        }
1085
1086        // DOM elements
1087        const signSequence = document.getElementById('sign-sequence');
1088        const currentExpression = document.getElementById('current-expression');
1089        const signDescription = document.getElementById('sign-description');
1090        const expressionSelection = document.getElementById('expression-selection');
1091        const categoriesContainer = document.getElementById('categories');
1092        const progressBar = document.getElementById('progress-bar');
1093        const progressText = document.getElementById('progress-text');
1094        const learnContainer = document.getElementById('learn-container');
1095        const testContainer = document.getElementById('test-container');
1096        const learnModeBtn = document.getElementById('learn-mode-btn');
1097        const testModeBtn = document.getElementById('test-mode-btn');
1098        const quizSequence = document.getElementById('quiz-sequence');
1099        const motionDescription = document.getElementById('motion-description');
1100        const quizOptions = document.getElementById('quiz-options');
1101        const quizResult = document.getElementById('quiz-result');
1102        const nextQuestionBtn = document.getElementById('next-question');
1103        const testProgress = document.getElementById('test-progress');
1104        const testScore = document.getElementById('test-score');
1105        const certificateForm = document.getElementById('certificate-form');
1106        const submitCertificateBtn = document.getElementById('submit-certificate');
1107        const loadingIndicator = document.getElementById('loading-indicator');
1108        const certificateOverlay = document.getElementById('certificate-overlay');
1109        const certificatePreview = document.getElementById('certificate-preview');
1110        const closeModalBtn = document.getElementById('close-modal');
1111
1112        // Create category buttons
1113        for (const category in signExpressions) {
1114            const btn = document.createElement('button');
1115            btn.textContent = category;
1116            btn.className = category === currentCategory ? 'category-btn active touch-feedback' : 'category-btn touch-feedback';
1117            btn.onclick = () => switchCategory(category);
1118            categoriesContainer.appendChild(btn);
1119        }
1120
1121        // Create expression buttons for current category
1122        function populateExpressions() {
1123            expressionSelection.innerHTML = '';
1124            for (const expression in signExpressions[currentCategory]) {
1125                const btn = document.createElement('button');
1126                btn.textContent = expression;
1127                btn.className = 'expression-btn touch-feedback';
1128                btn.onclick = () => showExpression(expression);
1129                expressionSelection.appendChild(btn);
1130            }
1131        }
1132
1133        // Switch category
1134        function switchCategory(category) {
1135            currentCategory = category;
1136            
1137            // Update category buttons
1138            const categoryButtons = categoriesContainer.querySelectorAll('.category-btn');
1139            categoryButtons.forEach(btn => {
1140                btn.classList.remove('active');
1141                if (btn.textContent === category) {
1142                    btn.classList.add('active');
1143                }
1144            });
1145            
1146            populateExpressions();
1147        }
1148
1149        // Show expression information
1150        function showExpression(expression) {
1151            const expressionData = signExpressions[currentCategory][expression];
1152            
1153            // Clear previous sequence
1154            signSequence.innerHTML = '';
1155            
1156            // Add each step in the sequence
1157            expressionData.sequence.forEach((step, index) => {
1158                const sequenceItem = document.createElement('div');
1159                sequenceItem.className = 'sequence-item';
1160                
1161                const sequenceEmoji = document.createElement('div');
1162                sequenceEmoji.className = 'sequence-emoji';
1163                sequenceEmoji.textContent = step.emoji;
1164                
1165                const sequenceStep = document.createElement('div');
1166                sequenceStep.className = 'sequence-step';
1167                sequenceStep.textContent = step.description;
1168                
1169                sequenceItem.appendChild(sequenceEmoji);
1170                sequenceItem.appendChild(sequenceStep);
1171                signSequence.appendChild(sequenceItem);
1172                
1173                // Add arrow between steps (except after the last step)
1174                if (index < expressionData.sequence.length - 1) {
1175                    const arrow = document.createElement('div');
1176                    arrow.className = 'arrow';
1177                    arrow.textContent = '→';
1178                    signSequence.appendChild(arrow);
1179                }
1180            });
1181            
1182            currentExpression.textContent = expression;
1183            signDescription.textContent = expressionData.description;
1184            
1185            // Add haptic feedback if available
1186            if (navigator.vibrate) {
1187                navigator.vibrate(40);
1188            }
1189            
1190            // Mark as learned
1191            learnedExpressions[expression] = true;
1192            updateProgress();
1193            
1194            // Scroll to ensure the sign display is visible
1195            setTimeout(() => {
1196                document.getElementById('sign-display').scrollIntoView({behavior: 'smooth', block: 'nearest'});
1197            }, 50);
1198        }
1199
1200        // Update progress bar
1201        function updateProgress() {
1202            const learnedCount = Object.keys(learnedExpressions).length;
1203            const percentage = (learnedCount / totalExpressions) * 100;
1204            progressBar.style.width = `${percentage}%`;
1205            progressText.textContent = `${learnedCount}/${totalExpressions} expressions learned`;
1206        }
1207
1208        // Test mode functionality
1209        let currentQuizExpression = '';
1210        let quizCategory = '';
1211        let availableExpressions = [];
1212        let testQuestions = [];
1213
1214        // Initialize test mode
1215        function initTest() {
1216            nextQuestionBtn.style.display = 'block';
1217            // Reset test variables
1218            currentQuestionNumber = 1;
1219            correctAnswers = 0;
1220            testCompleted = false;
1221            testScore.textContent = '';
1222            certificateForm.style.display = 'none';
1223            
1224            // Update progress indicator
1225            testProgress.textContent = `Question ${currentQuestionNumber} of ${totalTestQuestions}`;
1226            
1227            // Get all expressions for the test
1228            availableExpressions = [];
1229            
1230            for (const category in signExpressions) {
1231                for (const expression in signExpressions[category]) {
1232                    availableExpressions.push({
1233                        category: category,
1234                        expression: expression
1235                    });
1236                }
1237            }
1238            
1239            // Randomly select 10 expressions for the test
1240            testQuestions = [];
1241            const shuffled = [...availableExpressions].sort(() => 0.5 - Math.random());
1242            testQuestions = shuffled.slice(0, totalTestQuestions);
1243            
1244            generateTestQuestion();
1245        }
1246
1247        // Generate a new test question
1248        function generateTestQuestion() {
1249            // Clear previous result
1250            quizResult.textContent = '';
1251            quizResult.className = 'quiz-result';
1252            
1253            // Get the current question
1254            const quizItem = testQuestions[currentQuestionNumber - 1];
1255            quizCategory = quizItem.category;
1256            currentQuizExpression = quizItem.expression;
1257            
1258            // Display the sign sequence without descriptions
1259            quizSequence.innerHTML = '';
1260            const expressionData = signExpressions[quizCategory][currentQuizExpression];
1261            
1262            expressionData.sequence.forEach((step, index) => {
1263                const sequenceItem = document.createElement('div');
1264                sequenceItem.className = 'sequence-item';
1265                
1266                const sequenceEmoji = document.createElement('div');
1267                sequenceEmoji.className = 'sequence-emoji';
1268                sequenceEmoji.textContent = step.emoji;
1269                
1270                sequenceItem.appendChild(sequenceEmoji);
1271                quizSequence.appendChild(sequenceItem);
1272                
1273                // Add arrow between steps
1274                if (index < expressionData.sequence.length - 1) {
1275                    const arrow = document.createElement('div');
1276                    arrow.className = 'arrow';
1277                    arrow.textContent = '→';
1278                    quizSequence.appendChild(arrow);
1279                }
1280            });
1281            
1282            // Display the motion-only description that doesn't give away the answer
1283            motionDescription.textContent = expressionData.motionOnly;
1284            
1285            // Generate options (including the correct answer)
1286            quizOptions.innerHTML = '';
1287            
1288            // Create a set of 4 unique options
1289            const options = new Set([currentQuizExpression]);
1290            const possibleOptions = availableExpressions.map(item => item.expression);
1291            
1292            while (options.size < 4 && options.size < possibleOptions.length) {
1293                const randomExpression = possibleOptions[Math.floor(Math.random() * possibleOptions.length)];
1294                options.add(randomExpression);
1295            }
1296            
1297            // Convert to array and shuffle
1298            const shuffledOptions = Array.from(options).sort(() => Math.random() - 0.5);
1299            
1300            // Create option buttons
1301            shuffledOptions.forEach(option => {
1302                const btn = document.createElement('button');
1303                btn.textContent = option;
1304                btn.className = 'quiz-option-btn touch-feedback';
1305                btn.onclick = () => checkTestAnswer(option);
1306                quizOptions.appendChild(btn);
1307            });
1308            
1309            // Update next question button text based on question number
1310            if (currentQuestionNumber === totalTestQuestions) {
1311                nextQuestionBtn.textContent = 'Finish Test';
1312            } else {
1313                nextQuestionBtn.textContent = 'Next Question';
1314            }
1315            
1316            // Disable next button until answer is selected
1317            nextQuestionBtn.disabled = true;
1318        }
1319
1320        // Check test answer
1321        function checkTestAnswer(selectedExpression) {
1322            const isCorrect = selectedExpression === currentQuizExpression;
1323            
1324            // Add haptic feedback if available
1325            if (navigator.vibrate) {
1326                navigator.vibrate(isCorrect ? [40, 30, 40] : 100);
1327            }
1328            
1329            // Display result
1330            quizResult.textContent = isCorrect 
1331                ? 'Correct! Well done!' 
1332                : `Incorrect. The correct answer is "${currentQuizExpression}".`;
1333            quizResult.className = isCorrect ? 'quiz-result correct' : 'quiz-result incorrect';
1334            
1335            // Disable all option buttons
1336            const optionButtons = quizOptions.querySelectorAll('button');
1337            optionButtons.forEach(btn => {
1338                btn.disabled = true;
1339                if (btn.textContent === currentQuizExpression) {
1340                    btn.style.backgroundColor = '#2e7d32';
1341                } else if (btn.textContent === selectedExpression && !isCorrect) {
1342                    btn.style.backgroundColor = '#c62828';
1343                }
1344            });
1345            
1346            // If correct, increment score
1347            if (isCorrect) {
1348                correctAnswers++;
1349            }
1350            
1351            // Enable next question button
1352            nextQuestionBtn.disabled = false;
1353            
1354            // Mark the expression as learned
1355            learnedExpressions[currentQuizExpression] = true;
1356            updateProgress();
1357            
1358            // Scroll to ensure the result is visible
1359            setTimeout(() => {
1360                quizResult.scrollIntoView({behavior: 'smooth', block: 'nearest'});
1361            }, 50);
1362        }
1363
1364        // Move to next question or finish test
1365        function nextQuestion() {
1366            if (currentQuestionNumber === totalTestQuestions) {
1367                // Test is complete
1368                finishTest();
1369            } else {
1370                // Move to next question
1371                currentQuestionNumber++;
1372                testProgress.textContent = `Question ${currentQuestionNumber} of ${totalTestQuestions}`;
1373                generateTestQuestion();
1374            }
1375        }
1376
1377        // Finish test and show results
1378        function finishTest() {
1379            testCompleted = true;
1380            const scorePercentage = (correctAnswers / totalTestQuestions) * 100;
1381            let scoreClass = '';
1382            
1383            if (scorePercentage >= 80) {
1384                scoreClass = 'score-good';
1385            } else if (scorePercentage >= 60) {
1386                scoreClass = 'score-avg';
1387            } else {
1388                scoreClass = 'score-poor';
1389            }
1390            
1391            testScore.textContent = `Your score: ${correctAnswers} out of ${totalTestQuestions} (${scorePercentage}%)`;
1392            testScore.className = `test-score ${scoreClass}`;
1393            
1394            // Show certificate form if score is 80% or higher
1395            if (scorePercentage >= 80) {
1396                certificateForm.style.display = 'block';
1397                certificateForm.scrollIntoView({behavior: 'smooth'});
1398            }
1399            
1400            // Hide the button to prevent double-triggering issues
1401            nextQuestionBtn.style.display = 'none';
1402        }
1403
1404        // Generate and send certificate
1405        function generateCertificate() {
1406            const name = document.getElementById('name').value;
1407            const email = document.getElementById('email').value;
1408            
1409            // Validate inputs
1410            if (!name || !email) {
1411                alert('Please fill in all fields');
1412                return;
1413            }
1414            
1415            // Show loading indicator
1416            loadingIndicator.style.display = 'block';
1417            submitCertificateBtn.disabled = true;
1418            
1419            // Pre-load signature image
1420            const signatureImg = new Image();
1421            signatureImg.crossOrigin = "anonymous";
1422            signatureImg.src = "https://i.postimg.cc/N0SpTfr3/Advert-3.png";
1423            
1424            signatureImg.onload = function() {
1425                const certificateDiv = document.createElement('div');
1426                certificateDiv.innerHTML = `
1427                    <div class="certificate-container">
1428                        <div id="certificate" class="certificate">
1429                            <div class="content">
1430                                <div class="logo">CHEUNG NGO MEDICAL 翱翔醫療</div>
1431                                <h1>Certificate of Completion</h1>
1432                                <span class="smaller-text">This is to certify that</span>
1433                                <div class="recipient">${name}</div>
1434                                <span class="smaller-text">has successfully completed</span>
1435                                <div class="reason">Educational Sign Language Academic Course</div>
1436                                <div class="date">Completion Date: ${new Date().toLocaleDateString()}</div>
1437                                <div class="course-description">
1438                                    This certificate acknowledges proficiency in educational sign language expressions for classroom environments, including classroom basics, lesson activities, academic subjects, classroom management, and school events.
1439                                </div>
1440                                
1441                                <div class="signatures">
1442                                    <div class="signature">
1443                                        <img src="${signatureImg.src}" 
1444                                            alt="Program Director Signature" 
1445                                            class="signature-image"
1446                                            crossorigin="anonymous" />
1447                                        <div class="signature-line"></div>
1448                                        Program Director
1449                                    </div>
1450                                    <div class="signature">
1451                                        <img src="${signatureImg.src}" 
1452                                            alt="Organization President Signature" 
1453                                            class="signature-image"
1454                                            crossorigin="anonymous" />
1455                                        <div class="signature-line"></div>
1456                                        Organization Director
1457                                    </div>
1458                                </div>
1459                            </div>
1460                        </div>
1461                    </div>
1462                `;
1463                
1464                document.body.appendChild(certificateDiv);
1465                
1466                setTimeout(function() {
1467                    const certificateElement = document.querySelector('#certificate');
1468                    const options = {
1469                        scale: 2,
1470                        useCORS: true,
1471                        allowTaint: true,
1472                        backgroundColor: '#ffffff',
1473                        width: 800,
1474                        height: 600,
1475                        windowWidth: 800,
1476                        windowHeight: 600,
1477                        onclone: function(clonedDoc) {
1478                            const images = clonedDoc.getElementsByTagName('img');
1479                            for (let img of images) {
1480                                img.crossOrigin = "anonymous";
1481                            }
1482                        }
1483                    };
1484                    
1485                    html2canvas(certificateElement, options)
1486                        .then(function(canvas) {
1487                            const imgDataUrl = canvas.toDataURL('image/png');
1488                            document.body.removeChild(certificateDiv);
1489                            
1490                            // Create a preview of the certificate
1491                            certificatePreview.innerHTML = '';
1492                            const previewImg = document.createElement('img');
1493                            previewImg.src = imgDataUrl;
1494                            previewImg.style.maxWidth = '100%';
1495                            certificatePreview.appendChild(previewImg);
1496                            certificateOverlay.style.display = 'flex';
1497                            
1498                            const formData = new FormData();
1499                            const base64Image = imgDataUrl.split(',')[1];
1500                            formData.append('image', base64Image);
1501                            formData.append('key', 'ac7bcf6e3056c6b765e00749c1e3d0dd'); // ImgBB API key
1502                            
1503                            fetch('https://api.imgbb.com/1/upload', {
1504                                method: 'POST',
1505                                body: formData
1506                            })
1507                            .then(response => response.json())
1508                            .then(data => {
1509                                if (data.success) {
1510                                    const imageUrl = data.data.url;
1511                                    const certificateEmail = {
1512                                        emailTitle: 'Educational Sign Language Certificate',
1513                                        to_email: email,
1514                                        results_content: `Congratulations on completing the Educational Sign Language Academic Course!
1515
1516Your certificate is available at the following link:
1517${imageUrl}
1518
1519You may need at least 5 minutes before the certificate is ready for view and download.
1520
1521Cheung Ngo Medical 翺翔醫療
1522WhatsApp聯絡尖沙咀店 https://wa.me/85295096276
1523WhatsApp聯絡中環店 https://wa.me/85290511569
1524WhatsApp聯絡將軍澳店 https://wa.me/85298852916
1525WhatsApp聯絡旺角店 https://wa.me/85298893911
1526`
1527                                    };
1528                                    
1529                                    emailjs.send('service_di3sotm', 'template_sc1rwk2', certificateEmail) // Replace with your actual service ID and template ID
1530                                        .then(response => {
1531                                            console.log('Certificate email sent successfully:', response);
1532                                            loadingIndicator.style.display = 'none';
1533                                            submitCertificateBtn.disabled = false;
1534                                            alert('Congratulations! Your certificate has been sent to your email.');
1535                                        })
1536                                        .catch(error => {
1537                                            console.error('Failed to send certificate email:', error);
1538                                            loadingIndicator.style.display = 'none';
1539                                            submitCertificateBtn.disabled = false;
1540                                            alert('Failed to send certificate. Please contact support.');
1541                                        });
1542                                } else {
1543                                    console.error('Image upload failed:', data);
1544                                    loadingIndicator.style.display = 'none';
1545                                    submitCertificateBtn.disabled = false;
1546                                    alert('Failed to upload certificate image. Please contact support.');
1547                                }
1548                            })
1549                            .catch(error => {
1550                                console.error('Error uploading image to imgbb:', error);
1551                                loadingIndicator.style.display = 'none';
1552                                submitCertificateBtn.disabled = false;
1553                                alert('Failed to upload certificate image. Please contact support.');
1554                            });
1555                        })
1556                        .catch(error => {
1557                            console.error('Error generating certificate image:', error);
1558                            loadingIndicator.style.display = 'none';
1559                            submitCertificateBtn.disabled = false;
1560                            alert('Failed to generate certificate image. Please contact support.');
1561                        });
1562                }, 500);
1563            };
1564            
1565            signatureImg.onerror = function() {
1566                console.error('Failed to load signature image');
1567                loadingIndicator.style.display = 'none';
1568                submitCertificateBtn.disabled = false;
1569                alert('Failed to load signature image. Please contact support.');
1570            };
1571        }
1572
1573        // Switch between learning and test modes
1574        learnModeBtn.addEventListener('click', () => {
1575            learnContainer.style.display = 'block';
1576            testContainer.style.display = 'none';
1577            learnModeBtn.classList.add('active');
1578            testModeBtn.classList.remove('active');
1579        });
1580
1581        testModeBtn.addEventListener('click', () => {
1582            learnContainer.style.display = 'none';
1583            testContainer.style.display = 'block';
1584            learnModeBtn.classList.remove('active');
1585            testModeBtn.classList.add('active');
1586            initTest();
1587        });
1588
1589        // Next question button
1590        nextQuestionBtn.addEventListener('click', nextQuestion);
1591        
1592        // Certificate submission
1593        submitCertificateBtn.addEventListener('click', generateCertificate);
1594        
1595        // Close certificate preview modal
1596        closeModalBtn.addEventListener('click', () => {
1597            certificateOverlay.style.display = 'none';
1598        });
1599
1600        // Prevent double-tap zoom on buttons
1601        document.addEventListener('touchstart', function(event) {
1602            if (event.target.tagName === 'BUTTON') {
1603                event.preventDefault();
1604                event.target.click();
1605            }
1606        }, {passive: false});
1607        
1608        // Close modal when clicking outside
1609        certificateOverlay.addEventListener('click', function(event) {
1610            if (event.target === certificateOverlay) {
1611                certificateOverlay.style.display = 'none';
1612            }
1613        });
1614
1615        // Initialize expressions for the first category
1616        populateExpressions();
1617        updateProgress();
1618        
1619        // Helper function to detect iOS
1620        function isIOS() {
1621            return /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream;
1622        }
1623        
1624        // Apply iOS-specific adjustments
1625        if (isIOS()) {
1626            document.body.classList.add('ios-device');
1627            
1628            // Fix for iOS button styling
1629            const allButtons = document.querySelectorAll('button');
1630            allButtons.forEach(btn => {
1631                btn.style.WebkitAppearance = 'none';
1632            });
1633        }
1634    </script>
1634
1635</body>
1636</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.