PageSourceSearch

https://toycad.app/subscribe.html

html toycad.app collected 2026-10-02 01:15:16 UTC 120,807 bytes, 3,071 lines download raw bytes

1<!DOCTYPE html>
2<html lang="en">
3
4<head>
5    <meta charset="UTF-8">
6    <meta name="viewport" content="width=device-width, initial-scale=1.0">
7    <title>ToyCAD — Subscribe Online & Save 20%</title>
8
9  <!-- BEGIN seo (see scripts/generate_sitemap.py for the sitemap) -->
10  <meta name="description" content="Subscribe to ToyCAD online and save 20% on lifetime or yearly access. Design and 3D print toys from an iPad. No CAD experience needed." />
11  <link rel="canonical" href="https://toycad.app/subscribe.html" />
12
13  <meta property="og:type" content="website" />
14  <meta property="og:site_name" content="ToyCAD" />
15  <meta property="og:locale" content="en_US" />
16  <meta property="og:title" content="ToyCAD — Subscribe Online &amp; Save 20%" />
17  <meta property="og:description" content="Subscribe to ToyCAD online and save 20% on lifetime or yearly access. Design and 3D print toys from an iPad. No CAD experience needed." />
18  <meta property="og:url" content="https://toycad.app/subscribe.html" />
19  <meta property="og:image" content="https://toycad.app/img_new/og/toycad.jpg" />
20  <meta property="og:image:width" content="1200" />
21  <meta property="og:image:height" content="630" />
22  <meta property="og:image:alt" content="Toys designed in ToyCAD on an iPad, next to the 3D-printed versions" />
23  <meta name="twitter:card" content="summary_large_image" />
24  <meta name="twitter:title" content="ToyCAD — Subscribe Online &amp; Save 20%" />
25  <meta name="twitter:description" content="Subscribe to ToyCAD online and save 20% on lifetime or yearly access. Design and 3D print toys from an iPad. No CAD experience needed." />
26  <meta name="twitter:image" content="https://toycad.app/img_new/og/toycad.jpg" />
27
28  <link rel="icon" href="/favicon.ico" sizes="48x48" />
29  <link rel="icon" type="image/png" sizes="32x32" href="/img_new/icons/favicon-32.png" />
30  <link rel="icon" type="image/png" sizes="16x16" href="/img_new/icons/favicon-16.png" />
31  <link rel="apple-touch-icon" href="/img_new/icons/apple-touch-icon.png" />
32  <link rel="manifest" href="/site.webmanifest" />
33  <meta name="theme-color" content="#7b3ff2" />
34  <meta name="apple-mobile-web-app-title" content="ToyCAD" />
35  <!-- END seo -->
36<!-- Rewardful Affiliate Tracking -->
37    
37<script>(function (w, r) { w._rwq = r; w[r] = w[r] || function () { (w[r].q = w[r].q || []).push(arguments) } })(window, 'rewardful');</script>
37
38    
38<script async src="https://r.wdfl.co/rw.js" data-rewardful="052dd7"></script>
38
39    <!-- End Rewardful -->
40
41    <!-- Meta Pixel Code -->
42    
42<script>
vendor: 595 bytes, lines 42-54
42
43        !function (f, b, e, v, n, t, s) {
44            if (f.fbq) return; n = f.fbq = function () {
45                n.callMethod ?
46                    n.callMethod.apply(n, arguments) : n.queue.push(arguments)
47            };
48            if (!f._fbq) f._fbq = n; n.push = n; n.loaded = !0; n.version = '2.0';
49            n.queue = []; t = b.createElement(e); t.async = !0;
50            t.src = v; s = b.getElementsByTagName(e)[0];
51            s.parentNode.insertBefore(t, s)
52        }(window, document, 'script',
53            'https://connect.facebook.net/en_US/fbevents.js');
54        fbq('init', '
541373546107509124
vendor: 42 bytes, lines 54-56
54');
55        fbq('track', 'PageView');
56    
56</script>
56
57    <noscript><img height="1" width="1" style="display:none"
58            src="https://www.facebook.com/tr?id=1373546107509124&ev=PageView&noscript=1" /></noscript>
59    <!-- End Meta Pixel Code -->
60
61    <!-- Google Analytics -->
vendor: 68 bytes, lines 61-62
61
62    <script async src="https://www.googletagmanager.com/gtag/js?id=
62G-NMVRFPGBCN
vendor: 16 bytes, lines 62-63
62"></script>
63    
63<script>
64        
vendor: 154 bytes, lines 64-67
64window.dataLayer = window.dataLayer || [];
65        function gtag() { dataLayer.push(arguments); }
66        gtag('js', new Date());
67        gtag('config', '
67G-NMVRFPGBCN
vendor: 8 bytes, lines 67-68
67');
68    
68</script>
68
69
70    <link
71        href="https://fonts.googleapis.com/css2?family=Fraunces:ital,opsz,wght@0,9..144,300;0,9..144,700;0,9..144,900;1,9..144,400&family=DM+Sans:wght@300;400;500;600&display=swap"
72        rel="stylesheet">
73
74    <style>
75        :root {
76            --green: #209850;
77            --green-dark: #177a3e;
78            --green-light: #e6f5ec;
79            --orange: #F49100;
80            --yellow: #FFDE06;
81            --ink: #0d1f12;
82            --dark: #0f1a0f;
83            --cream: #f8faf8;
84            --mid: #5a6b5e;
85            --border: rgba(32, 152, 80, 0.15);
86        }
87
88        *,
89        *::before,
90        *::after {
91            box-sizing: border-box;
92            margin: 0;
93            padding: 0;
94        }
95
96        html {
97            scroll-behavior: smooth;
98        }
99
100        body {
101            font-family: 'DM Sans', sans-serif;
102            background: var(--cream);
103            color: var(--ink);
104            overflow-x: hidden;
105        }
106
107        /* ── NAV ── */
108        nav {
109            position: fixed;
110            top: 0;
111            left: 0;
112            right: 0;
113            z-index: 100;
114            display: flex;
115            align-items: center;
116            justify-content: space-between;
117            padding: 14px 24px;
118            background: rgba(13, 26, 15, 0.96);
119            backdrop-filter: blur(12px);
120            border-bottom: 1px solid rgba(255, 255, 255, 0.06);
121        }
122
123        .nav-logo img {
124            height: 34px;
125            display: block;
126        }
127
128        .nav-cta {
129            background: var(--green);
130            color: #fff;
131            border: none;
132            border-radius: 100px;
133            padding: 10px 22px;
134            font-family: 'DM Sans', sans-serif;
135            font-size: 14px;
136            font-weight: 600;
137            cursor: pointer;
138            text-decoration: none;
139            transition: background 0.2s, transform 0.15s;
140            white-space: nowrap;
141        }
142
143        .nav-cta:hover {
144            background: var(--green-dark);
145            transform: translateY(-1px);
146        }
147
148        /* ── SUCCESS BANNER ── */
149        .success-banner {
150            display: none;
151            background: var(--green);
152            color: #fff;
153            padding: 20px 24px;
154            text-align: center;
155            position: relative;
156            z-index: 90;
157            margin-top: 62px;
158        }
159
160        .success-banner-text {
161            font-size: 16px;
162            font-weight: 600;
163            margin-bottom: 16px;
164        }
165
166        .success-banner-actions {
167            display: flex;
168            align-items: center;
169            justify-content: center;
170            flex-wrap: wrap;
171            gap: 12px;
172        }
173
174        .success-banner a {
175            color: var(--yellow);
176            text-decoration: underline;
177        }
178
179        .banner-manage-btn {
180            background: rgba(255, 255, 255, 0.2);
181            color: #fff;
182            border: 1.5px solid rgba(255, 255, 255, 0.5);
183            border-radius: 100px;
184            padding: 9px 20px;
185            font-family: 'DM Sans', sans-serif;
186            font-size: 14px;
187            font-weight: 600;
188            cursor: pointer;
189            transition: background 0.2s;
190            white-space: nowrap;
191        }
192
193        .banner-manage-btn:hover {
194            background: rgba(255, 255, 255, 0.3);
195        }
196
197        /* ── HERO ── */
198        .hero {
199            min-height: 100vh;
200            padding: 80px 24px 60px;
201            display: flex;
202            flex-direction: column;
203            align-items: center;
204            justify-content: center;
205            text-align: center;
206            position: relative;
207            overflow: hidden;
208            background: var(--dark);
209        }
210
211        .hero::before {
212            content: '';
213            position: absolute;
214            inset: 0;
215            background: radial-gradient(ellipse 70% 50% at 50% 0%, rgba(32, 152, 80, 0.18) 0%, transparent 65%);
216            pointer-events: none;
217        }
218
219        .hero-badge {
220            display: inline-flex;
221            align-items: center;
222            gap: 8px;
223            background: rgba(32, 152, 80, 0.15);
224            color: #4cce7e;
225            border: 1px solid rgba(32, 152, 80, 0.3);
226            border-radius: 100px;
227            padding: 6px 16px;
228            font-size: 13px;
229            font-weight: 600;
230            letter-spacing: 0.3px;
231            margin-bottom: 28px;
232            animation: fadeUp 0.6s ease both;
233        }
234
235        .dot {
236            width: 7px;
237            height: 7px;
238            background: var(--green);
239            border-radius: 50%;
240            animation: pulse 2s infinite;
241        }
242
243        @keyframes pulse {
244
245            0%,
246            100% {
247                opacity: 1;
248                transform: scale(1);
249            }
250
251            50% {
252                opacity: 0.5;
253                transform: scale(1.3);
254            }
255        }
256
257        .hero h1 {
258            font-family: 'Fraunces', serif;
259            font-size: clamp(36px, 7vw, 62px);
260            font-weight: 900;
261            line-height: 1.06;
262            letter-spacing: -2px;
263            max-width: 820px;
264            margin-bottom: 24px;
265            color: #fff;
266            animation: fadeUp 0.7s 0.1s ease both;
267        }
268
269        .hero h1 em {
270            font-style: italic;
271            color: var(--yellow);
272        }
273
274        .hero-sub {
275            font-size: clamp(16px, 2.5vw, 19px);
276            color: rgba(255, 255, 255, 0.6);
277            max-width: 560px;
278            line-height: 1.65;
279            margin-bottom: 40px;
280            animation: fadeUp 0.7s 0.2s ease both;
281        }
282
283        .hero-actions {
284            display: flex;
285            flex-direction: column;
286            align-items: center;
287            gap: 14px;
288            animation: fadeUp 0.7s 0.3s ease both;
289        }
290
291        .btn-primary {
292            background: var(--green);
293            color: #fff;
294            border: none;
295            border-radius: 100px;
296            padding: 18px 44px;
297            font-family: 'DM Sans', sans-serif;
298            font-size: 17px;
299            font-weight: 600;
300            cursor: pointer;
301            text-decoration: none;
302            transition: all 0.2s;
303            box-shadow: 0 4px 32px rgba(32, 152, 80, 0.4);
304            display: inline-block;
305        }
306
307        .btn-primary:hover {
308            background: var(--green-dark);
309            transform: translateY(-2px);
310            box-shadow: 0 8px 40px rgba(32, 152, 80, 0.45);
311        }
312
313        .hero-note {
314            font-size: 13px;
315            color: rgba(255, 255, 255, 0.28);
316            margin-top: 4px;
317        }
318
319        .hero-pricing-preview {
320            display: flex;
321            gap: 24px;
322            margin-top: 52px;
323            flex-wrap: wrap;
324            justify-content: center;
325            animation: fadeUp 0.8s 0.4s ease both;
326        }
327
328        .hero-price-pill {
329            background: rgba(255, 255, 255, 0.06);
330            border: 1px solid rgba(32, 152, 80, 0.3);
331            border-radius: 20px;
332            padding: 20px 28px;
333            text-align: center;
334            min-width: 180px;
335        }
336
337        .hero-price-pill .old-price {
338            font-size: 14px;
339            color: rgba(255, 255, 255, 0.35);
340            text-decoration: line-through;
341            margin-bottom: 4px;
342        }
343
344        .hero-price-pill .new-price {
345            font-family: 'Fraunces', serif;
346            font-size: 32px;
347            font-weight: 900;
348            color: var(--yellow);
349            letter-spacing: -1px;
350        }
351
352        .hero-price-pill .plan-name {
353            font-size: 13px;
354            color: rgba(255, 255, 255, 0.6);
355            margin-top: 4px;
356        }
357
358        .hero-price-pill[onclick] {
359            cursor: pointer;
360            transition: transform 0.15s ease, border-color 0.15s ease, box-shadow 0.15s ease;
361        }
362
363        .hero-price-pill[onclick]:hover {
364            transform: translateY(-3px);
365            border-color: rgba(32, 152, 80, 0.7);
366            box-shadow: 0 8px 32px rgba(32, 152, 80, 0.25);
367        }
368
369        .discount-badge {
370            display: inline-block;
371            background: var(--orange);
372            color: #fff;
373            font-size: 11px;
374            font-weight: 800;
375            letter-spacing: 1px;
376            text-transform: uppercase;
377            padding: 3px 10px;
378            border-radius: 100px;
379            margin-top: 8px;
380        }
381
382        @keyframes fadeUp {
383            from {
384                opacity: 0;
385                transform: translateY(24px);
386            }
387
388            to {
389                opacity: 1;
390                transform: translateY(0);
391            }
392        }
393
394        /* ── PROOF BAR ── */
395        .proof-bar {
396            background: var(--green);
397            color: #fff;
398            padding: 16px 24px;
399            text-align: center;
400            font-size: 14px;
401            font-weight: 500;
402        }
403
404        .proof-bar span {
405            color: var(--yellow);
406            font-weight: 700;
407        }
408
409        /* ── TOYS / KIDS MADE GRID ── */
410        .toys-section {
411            background: var(--ink);
412            color: #fff;
413            text-align: center;
414        }
415
416        .toys-section .section-title {
417            color: #fff;
418        }
419
420        .toys-section .section-sub {
421            color: rgba(255, 255, 255, 0.55);
422            margin: 0 auto 0;
423        }
424
425        .toys-grid {
426            display: flex;
427            justify-content: center;
428            gap: 20px;
429            flex-wrap: wrap;
430            margin-top: 40px;
431        }
432
433        .toy-card {
434            flex: 1 1 220px;
435            max-width: 280px;
436            background: rgba(255, 255, 255, 0.06);
437            border: 1px solid rgba(32, 152, 80, 0.2);
438            border-radius: 20px;
439            overflow: hidden;
440            text-align: center;
441        }
442
443        .toy-card video,
444        .toy-card img {
445            width: 100%;
446            height: auto;
447            display: block;
448        }
449
450        .toy-card h3 {
451            padding: 14px 12px;
452            font-family: 'Fraunces', serif;
453            font-size: 16px;
454            font-weight: 700;
455            color: #fff;
456        }
457
458        /* ── PARENTS SAY ── */
459        .parents-section {
460            background: var(--cream);
461        }
462
463        .parents-grid {
464            display: flex;
465            justify-content: center;
466            gap: 20px;
467            flex-wrap: wrap;
468            margin-top: 40px;
469        }
470
471        .parent-card {
472            flex: 1 1 240px;
473            max-width: 320px;
474            background: #fff;
475            border-radius: 20px;
476            padding: 24px;
477            border: 1px solid var(--border);
478            font-style: italic;
479            font-size: 14px;
480            color: var(--mid);
481            line-height: 1.65;
482        }
483
484        .parent-card strong {
485            font-style: normal;
486        }
487
488        .parent-card .parent-name {
489            display: block;
490            margin-top: 12px;
491            font-style: normal;
492            font-weight: 700;
493            font-size: 13px;
494            color: var(--ink);
495        }
496
497        /* ── KIDS MADE PHOTO GRID ── */
498        .kids-section {
499            background: #fff;
500        }
501
502        /* ── SECTIONS ── */
503        section {
504            padding: 72px 24px;
505        }
506
507        .section-label {
508            font-size: 12px;
509            font-weight: 700;
510            letter-spacing: 2px;
511            text-transform: uppercase;
512            color: var(--green);
513            margin-bottom: 12px;
514        }
515
516        .section-title {
517            font-family: 'Fraunces', serif;
518            font-size: clamp(28px, 5vw, 44px);
519            font-weight: 900;
520            line-height: 1.1;
521            letter-spacing: -1px;
522            margin-bottom: 16px;
523        }
524
525        .section-sub {
526            font-size: 17px;
527            color: var(--mid);
528            line-height: 1.6;
529            max-width: 540px;
530        }
531
532        .container {
533            max-width: 960px;
534            margin: 0 auto;
535        }
536
537        /* ── PRICING ── */
538        .pricing {
539            background: #fff;
540        }
541
542        .pricing-grid {
543            display: grid;
544            grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
545            gap: 24px;
546            margin-top: 48px;
547            max-width: 1060px;
548        }
549
550        .pricing-card {
551            border-radius: 24px;
552            padding: 32px 28px;
553            border: 2px solid var(--border);
554            position: relative;
555            transition: transform 0.2s;
556        }
557
558        .pricing-card:hover {
559            transform: translateY(-4px);
560        }
561
562        .pricing-card.featured {
563            background: var(--dark);
564            color: #fff;
565            border-color: var(--green);
566            box-shadow: 0 16px 48px rgba(32, 152, 80, 0.25);
567        }
568
569        .pricing-badge {
570            position: absolute;
571            top: -14px;
572            left: 28px;
573            background: var(--orange);
574            color: #fff;
575            font-size: 11px;
576            font-weight: 800;
577            letter-spacing: 1px;
578            text-transform: uppercase;
579            padding: 4px 12px;
580            border-radius: 100px;
581        }
582
583        .pricing-discount-badge {
584            position: absolute;
585            top: -14px;
586            right: 28px;
587            background: var(--green);
588            color: #fff;
589            font-size: 11px;
590            font-weight: 800;
591            letter-spacing: 1px;
592            text-transform: uppercase;
593            padding: 4px 12px;
594            border-radius: 100px;
595        }
596
597        .pricing-card h3 {
598            font-family: 'Fraunces', serif;
599            font-size: 22px;
600            font-weight: 900;
601            margin-bottom: 4px;
602        }
603
604        .price-row {
605            display: flex;
606            align-items: baseline;
607            gap: 10px;
608            margin-bottom: 2px;
609        }
610
611        .price {
612            font-family: 'Fraunces', serif;
613            font-size: 48px;
614            font-weight: 900;
615            letter-spacing: -2px;
616            line-height: 1;
617        }
618
619        .pricing-card.featured .price {
620            color: var(--yellow);
621        }
622
623        .price-was {
624            font-size: 20px;
625            color: rgba(0, 0, 0, 0.3);
626            text-decoration: line-through;
627            font-family: 'Fraunces', serif;
628            font-weight: 700;
629        }
630
631        .pricing-card.featured .price-was {
632            color: rgba(255, 255, 255, 0.25);
633        }
634
635        .price-note {
636            font-size: 13px;
637            opacity: 0.6;
638            margin-bottom: 24px;
639        }
640
641        .pricing-card ul {
642            list-style: none;
643            display: flex;
644            flex-direction: column;
645            gap: 10px;
646            margin-bottom: 28px;
647        }
648
649        .pricing-card ul li {
650            font-size: 14px;
651            display: flex;
652            align-items: flex-start;
653            gap: 8px;
654            line-height: 1.4;
655        }
656
657        .pricing-card ul li::before {
658            content: '✓';
659            font-weight: 700;
660            color: var(--green);
661            flex-shrink: 0;
662            margin-top: 1px;
663        }
664
665        .btn-outline {
666            display: block;
667            text-align: center;
668            border: 2px solid var(--green);
669            color: var(--green);
670            border-radius: 100px;
671            padding: 14px 24px;
672            font-family: 'DM Sans', sans-serif;
673            font-size: 15px;
674            font-weight: 600;
675            text-decoration: none;
676            cursor: pointer;
677            background: none;
678            transition: all 0.2s;
679            width: 100%;
680        }
681
682        .btn-outline:hover {
683            background: var(--green);
684            color: #fff;
685        }
686
687        .btn-green {
688            display: block;
689            text-align: center;
690            background: var(--green);
691            color: #fff;
692            border-radius: 100px;
693            padding: 14px 24px;
694            font-family: 'DM Sans', sans-serif;
695            font-size: 15px;
696            font-weight: 700;
697            text-decoration: none;
698            cursor: pointer;
699            border: none;
700            transition: all 0.2s;
701            width: 100%;
702        }
703
704        .btn-green:hover {
705            background: var(--green-dark);
706        }
707
708        /* ── HOW IT WORKS ── */
709        .how {
710            background: #fff;
711        }
712
713        .steps {
714            display: grid;
715            grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
716            gap: 32px;
717            margin-top: 48px;
718        }
719
720        .step {
721            display: flex;
722            flex-direction: column;
723            gap: 14px;
724        }
725
726        .step-num {
727            width: 44px;
728            height: 44px;
729            background: var(--green-light);
730            color: var(--green);
731            border-radius: 12px;
732            display: flex;
733            align-items: center;
734            justify-content: center;
735            font-family: 'Fraunces', serif;
736            font-size: 22px;
737            font-weight: 900;
738        }
739
740        .step h3 {
741            font-family: 'Fraunces', serif;
742            font-size: 20px;
743            font-weight: 700;
744            letter-spacing: -0.3px;
745        }
746
747        .step p {
748            font-size: 15px;
749            color: var(--mid);
750            line-height: 1.6;
751        }
752
753        /* ── BENEFITS ── */
754        .why {
755            background: var(--cream);
756        }
757
758        .benefits {
759            display: grid;
760            grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
761            gap: 24px;
762            margin-top: 48px;
763        }
764
765        .benefit-card {
766            background: #fff;
767            border-radius: 20px;
768            padding: 28px 24px;
769            border: 1px solid var(--border);
770            transition: transform 0.2s, box-shadow 0.2s;
771        }
772
773        .benefit-card:hover {
774            transform: translateY(-4px);
775            box-shadow: 0 12px 40px rgba(32, 152, 80, 0.08);
776        }
777
778        .benefit-icon {
779            font-size: 32px;
780            margin-bottom: 14px;
781        }
782
783        .benefit-card h3 {
784            font-family: 'Fraunces', serif;
785            font-size: 19px;
786            font-weight: 700;
787            margin-bottom: 8px;
788            letter-spacing: -0.3px;
789        }
790
791        .benefit-card p {
792            font-size: 14px;
793            color: var(--mid);
794            line-height: 1.6;
795        }
796
797        /* ── TESTIMONIALS ── */
798        .testimonials {
799            background: var(--dark);
800            color: #fff;
801        }
802
803        .testimonials .section-label {
804            color: #4cce7e;
805        }
806
807        .testimonials .section-title {
808            color: #fff;
809        }
810
811        .reviews {
812            display: grid;
813            grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
814            gap: 20px;
815            margin-top: 48px;
816        }
817
818        .review-card {
819            background: rgba(255, 255, 255, 0.05);
820            border: 1px solid rgba(32, 152, 80, 0.2);
821            border-radius: 20px;
822            padding: 24px;
823        }
824
825        .stars {
826            color: var(--yellow);
827            font-size: 16px;
828            margin-bottom: 12px;
829        }
830
831        .review-text {
832            font-size: 15px;
833            line-height: 1.65;
834            color: rgba(255, 255, 255, 0.8);
835            margin-bottom: 16px;
836            font-style: italic;
837        }
838
839        .review-author {
840            font-size: 13px;
841            font-weight: 600;
842            color: rgba(255, 255, 255, 0.4);
843            text-transform: uppercase;
844            letter-spacing: 0.5px;
845        }
846
847        /* ── DOWNLOAD SECTION ── */
848        .download-section {
849            background: var(--cream);
850            text-align: center;
851        }
852
853        .store-buttons {
854            display: flex;
855            flex-wrap: wrap;
856            gap: 16px;
857            justify-content: center;
858            margin-top: 32px;
859        }
860
861        .store-buttons a img {
862            height: 54px;
863            display: block;
864        }
865
866        .store-buttons a {
867            transition: transform 0.2s;
868            display: block;
869        }
870
871        .store-buttons a:hover {
872            transform: translateY(-2px);
873        }
874
875        /* ── FAQ ── */
876        .faq {
877            background: #fff;
878        }
879
880        .faq-list {
881            margin-top: 48px;
882            display: flex;
883            flex-direction: column;
884            gap: 16px;
885            max-width: 680px;
886        }
887
888        .faq-item {
889            background: var(--cream);
890            border-radius: 16px;
891            border: 1px solid var(--border);
892            overflow: hidden;
893        }
894
895        .faq-q {
896            width: 100%;
897            text-align: left;
898            background: none;
899            border: none;
900            padding: 20px 24px;
901            font-family: 'DM Sans', sans-serif;
902            font-size: 16px;
903            font-weight: 600;
904            color: var(--ink);
905            cursor: pointer;
906            display: flex;
907            align-items: center;
908            justify-content: space-between;
909            gap: 12px;
910        }
911
912        .faq-q .arrow {
913            font-size: 18px;
914            color: var(--green);
915            transition: transform 0.25s;
916            flex-shrink: 0;
917        }
918
919        .faq-item.open .faq-q .arrow {
920            transform: rotate(45deg);
921        }
922
923        .faq-a {
924            max-height: 0;
925            overflow: hidden;
926            transition: max-height 0.3s ease, padding 0.3s;
927            font-size: 15px;
928            color: var(--mid);
929            line-height: 1.65;
930            padding: 0 24px;
931        }
932
933        .faq-item.open .faq-a {
934            max-height: 300px;
935            padding: 0 24px 20px;
936        }
937
938        /* ── CTA SECTION ── */
939        .cta-section {
940            background: var(--dark);
941            color: #fff;
942            text-align: center;
943            padding: 80px 24px;
944            position: relative;
945            overflow: hidden;
946        }
947
948        .cta-section::before {
949            content: '';
950            position: absolute;
951            inset: 0;
952            background: radial-gradient(ellipse 60% 60% at 50% 100%, rgba(32, 152, 80, 0.2) 0%, transparent 70%);
953            pointer-events: none;
954        }
955
956        .cta-section .section-title {
957            color: #fff;
958            max-width: 600px;
959            margin: 0 auto 16px;
960            position: relative;
961        }
962
963        .cta-section .section-sub {
964            color: rgba(255, 255, 255, 0.55);
965            margin: 0 auto 40px;
966            position: relative;
967        }
968
969        .cta-section .btn-primary {
970            position: relative;
971        }
972
973        .cta-note {
974            margin-top: 16px;
975            font-size: 13px;
976            color: rgba(255, 255, 255, 0.3);
977            position: relative;
978        }
979
980        /* ── FOOTER ── */
981        footer {
982            background: #080f09;
983            color: rgba(255, 255, 255, 0.3);
984            text-align: center;
985            padding: 28px 24px;
986            font-size: 13px;
987        }
988
989        footer a {
990            color: rgba(255, 255, 255, 0.3);
991            text-decoration: none;
992        }
993
994        footer a:hover {
995            color: rgba(255, 255, 255, 0.6);
996        }
997
998        /* ── MODAL ── */
999        .modal-overlay {
1000            display: none;
1001            position: fixed;
1002            inset: 0;
1003            z-index: 200;
1004            background: rgba(0, 0, 0, 0.75);
1005            backdrop-filter: blur(6px);
1006            align-items: center;
1007            justify-content: center;
1008            padding: 24px;
1009        }
1010
1011        .modal-overlay.active {
1012            display: flex;
1013        }
1014
1015        .modal {
1016            background: #fff;
1017            border-radius: 28px;
1018            padding: 40px 36px;
1019            max-width: 480px;
1020            width: 100%;
1021            position: relative;
1022            animation: modalIn 0.3s ease;
1023            max-height: 90vh;
1024            overflow-y: auto;
1025        }
1026
1027        @keyframes modalIn {
1028            from {
1029                opacity: 0;
1030                transform: scale(0.95) translateY(16px);
1031            }
1032
1033            to {
1034                opacity: 1;
1035                transform: scale(1) translateY(0);
1036            }
1037        }
1038
1039        .modal-close {
1040            position: absolute;
1041            top: 16px;
1042            right: 20px;
1043            background: none;
1044            border: none;
1045            font-size: 24px;
1046            cursor: pointer;
1047            color: var(--mid);
1048            line-height: 1;
1049        }
1050
1051        .modal-plan-chip {
1052            display: inline-flex;
1053            align-items: center;
1054            gap: 6px;
1055            background: var(--green-light);
1056            color: var(--green);
1057            border: 1px solid rgba(32, 152, 80, 0.2);
1058            border-radius: 100px;
1059            padding: 5px 14px;
1060            font-size: 13px;
1061            font-weight: 700;
1062            margin-bottom: 20px;
1063        }
1064
1065        .modal h2 {
1066            font-family: 'Fraunces', serif;
1067            font-size: 24px;
1068            font-weight: 900;
1069            letter-spacing: -0.5px;
1070            margin-bottom: 6px;
1071        }
1072
1073        .modal .modal-sub {
1074            font-size: 14px;
1075            color: var(--mid);
1076            margin-bottom: 24px;
1077            line-height: 1.5;
1078        }
1079
1080        /* Auth tabs */
1081        .auth-tabs {
1082            display: flex;
1083            background: var(--cream);
1084            border-radius: 12px;
1085            padding: 4px;
1086            margin-bottom: 24px;
1087            gap: 4px;
1088        }
1089
1090        .auth-tab {
1091            flex: 1;
1092            padding: 10px;
1093            border: none;
1094            background: none;
1095            border-radius: 10px;
1096            font-family: 'DM Sans', sans-serif;
1097            font-size: 14px;
1098            font-weight: 600;
1099            color: var(--mid);
1100            cursor: pointer;
1101            transition: all 0.2s;
1102        }
1103
1104        .auth-tab.active {
1105            background: #fff;
1106            color: var(--ink);
1107            box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
1108        }
1109
1110        .form-group {
1111            margin-bottom: 14px;
1112        }
1113
1114        .form-group label {
1115            display: block;
1116            font-size: 13px;
1117            font-weight: 600;
1118            margin-bottom: 6px;
1119            color: var(--ink);
1120        }
1121
1122        .form-group input {
1123            width: 100%;
1124            border: 1.5px solid var(--border);
1125            border-radius: 12px;
1126            padding: 13px 16px;
1127            font-family: 'DM Sans', sans-serif;
1128            font-size: 15px;
1129            color: var(--ink);
1130            background: var(--cream);
1131            outline: none;
1132            transition: border-color 0.2s;
1133        }
1134
1135        .form-group input:focus {
1136            border-color: var(--green);
1137        }
1138
1139        .modal-submit-btn {
1140            width: 100%;
1141            background: var(--green);
1142            color: #fff;
1143            border: none;
1144            border-radius: 100px;
1145            padding: 16px;
1146            font-family: 'DM Sans', sans-serif;
1147            font-size: 16px;
1148            font-weight: 700;
1149            cursor: pointer;
1150            margin-top: 8px;
1151            transition: background 0.2s;
1152        }
1153
1154        .modal-submit-btn:hover {
1155            background: var(--green-dark);
1156        }
1157
1158        .modal-submit-btn:disabled {
1159            opacity: 0.6;
1160            cursor: default;
1161        }
1162
1163        .modal-link-btn {
1164            background: none;
1165            border: none;
1166            color: var(--green);
1167            font-size: 13px;
1168            font-weight: 600;
1169            cursor: pointer;
1170            padding: 0;
1171            text-decoration: underline;
1172            margin-top: 12px;
1173            display: block;
1174        }
1175
1176        .form-fine {
1177            font-size: 12px;
1178            color: var(--mid);
1179            text-align: center;
1180            margin-top: 12px;
1181            line-height: 1.5;
1182        }
1183
1184        .modal-error {
1185            display: none;
1186            font-size: 14px;
1187            padding: 10px 14px;
1188            border-radius: 10px;
1189            margin-bottom: 14px;
1190            background: #fef2f2;
1191            color: #c0392b;
1192            border: 1px solid #fca5a5;
1193        }
1194
1195        .modal-error.success-msg {
1196            background: var(--green-light);
1197            color: var(--green);
1198            border-color: rgba(32, 152, 80, 0.3);
1199        }
1200
1201        /* Checkout state */
1202        .checkout-plan-box {
1203            background: var(--dark);
1204            border-radius: 20px;
1205            padding: 24px;
1206            margin-bottom: 24px;
1207            text-align: center;
1208        }
1209
1210        .checkout-plan-box .plan-label {
1211            font-size: 14px;
1212            color: rgba(255, 255, 255, 0.5);
1213            margin-bottom: 4px;
1214        }
1215
1216        .checkout-plan-box .plan-name {
1217            font-family: 'Fraunces', serif;
1218            font-size: 22px;
1219            font-weight: 900;
1220            color: #fff;
1221            margin-bottom: 4px;
1222        }
1223
1224        .checkout-plan-box .plan-price {
1225            font-family: 'Fraunces', serif;
1226            font-size: 38px;
1227            font-weight: 900;
1228            color: var(--yellow);
1229            letter-spacing: -1px;
1230        }
1231
1232        .checkout-plan-box .plan-note {
1233            font-size: 13px;
1234            color: rgba(255, 255, 255, 0.4);
1235            margin-top: 4px;
1236        }
1237
1238        .checkout-user-row {
1239            display: flex;
1240            align-items: center;
1241            gap: 10px;
1242            background: var(--cream);
1243            border-radius: 12px;
1244            padding: 14px 16px;
1245            margin-bottom: 20px;
1246            font-size: 14px;
1247            color: var(--mid);
1248        }
1249
1250        .checkout-user-row strong {
1251            color: var(--ink);
1252        }
1253
1254        /* Success state */
1255        .modal-success-state {
1256            text-align: center;
1257            padding: 12px 0;
1258        }
1259
1260        .success-icon {
1261            font-size: 52px;
1262            margin-bottom: 16px;
1263        }
1264
1265        .modal-success-state h3 {
1266            font-family: 'Fraunces', serif;
1267            font-size: 24px;
1268            font-weight: 900;
1269            margin-bottom: 10px;
1270        }
1271
1272        .modal-success-state p {
1273            font-size: 15px;
1274            color: var(--mid);
1275            line-height: 1.6;
1276            margin-bottom: 16px;
1277        }
1278
1279        .activate-steps {
1280            background: var(--green-light);
1281            border-radius: 16px;
1282            padding: 20px 20px;
1283            text-align: left;
1284            margin-top: 16px;
1285        }
1286
1287        .activate-steps p {
1288            font-size: 14px;
1289            color: var(--ink);
1290            margin-bottom: 8px;
1291            font-weight: 600;
1292        }
1293
1294        .activate-steps ol {
1295            padding-left: 20px;
1296        }
1297
1298        .activate-steps ol li {
1299            font-size: 14px;
1300            color: var(--mid);
1301            line-height: 1.7;
1302        }
1303
1304        /* Loading spinner */
1305        .loading-state {
1306            text-align: center;
1307            padding: 32px 0;
1308        }
1309
1310        .spinner {
1311            width: 42px;
1312            height: 42px;
1313            border: 4px solid var(--green-light);
1314            border-top-color: var(--green);
1315            border-radius: 50%;
1316            animation: spin 0.8s linear infinite;
1317            margin: 0 auto 16px;
1318        }
1319
1320        @keyframes spin {
1321            to {
1322                transform: rotate(360deg);
1323            }
1324        }
1325
1326        .loading-state p {
1327            font-size: 15px;
1328            color: var(--mid);
1329        }
1330
1331        /* Reveal animation */
1332        .reveal {
1333            opacity: 0;
1334            transform: translateY(30px);
1335            transition: opacity 0.6s ease, transform 0.6s ease;
1336        }
1337
1338        .reveal.visible {
1339            opacity: 1;
1340            transform: translateY(0);
1341        }
1342
1343        .reveal-delay-1 {
1344            transition-delay: 0.1s;
1345        }
1346
1347        .reveal-delay-2 {
1348            transition-delay: 0.2s;
1349        }
1350
1351        @media (max-width: 600px) {
1352            nav {
1353                padding: 12px 16px;
1354            }
1355
1356            .nav-logo img {
1357                height: 28px;
1358            }
1359
1360            section {
1361                padding: 56px 16px;
1362            }
1363
1364            .modal {
1365                padding: 32px 20px;
1366            }
1367
1368            .pricing-grid {
1369                grid-template-columns: 1fr;
1370            }
1371
1372            .hero-pricing-preview {
1373                gap: 12px;
1374            }
1375
1376            .hero-price-pill {
1377                min-width: 140px;
1378                padding: 16px 20px;
1379            }
1380        }
1381
1382        /* ── FEATURE SECTIONS ── */
1383        .features-section {
1384            background: #fff;
1385        }
1386
1387        .feature-row {
1388            display: flex;
1389            align-items: center;
1390            gap: 48px;
1391            padding: 64px 0;
1392            border-bottom: 1px solid var(--border);
1393        }
1394
1395        .feature-row:last-child {
1396            border-bottom: none;
1397        }
1398
1399        .feature-row.reverse {
1400            flex-direction: row-reverse;
1401        }
1402
1403        .feature-row-text {
1404            flex: 1 1 0;
1405        }
1406
1407        .feature-row-text h2 {
1408            font-family: 'Fraunces', serif;
1409            font-size: clamp(24px, 4vw, 36px);
1410            font-weight: 900;
1411            letter-spacing: -0.5px;
1412            line-height: 1.1;
1413            margin-bottom: 14px;
1414            color: var(--ink);
1415        }
1416
1417        .feature-row-text p {
1418            font-size: 16px;
1419            color: var(--mid);
1420            line-height: 1.7;
1421        }
1422
1423        .feature-row-image {
1424            flex: 1 1 0;
1425            display: flex;
1426            justify-content: center;
1427        }
1428
1429        .feature-row-image img {
1430            width: 100%;
1431            max-width: 420px;
1432            border-radius: 20px;
1433            box-shadow: 0 12px 48px rgba(0, 0, 0, 0.1);
1434            display: block;
1435        }
1436
1437        @media (max-width: 700px) {
1438
1439            .feature-row,
1440            .feature-row.reverse {
1441                flex-direction: column;
1442                gap: 28px;
1443                padding: 40px 0;
1444            }
1445        }
1446
1447        .hero-slider-wrap {
1448            width: 100%;
1449            max-width: 1100px;
1450            margin-top: 0;
1451            margin-bottom: 56px;
1452            border-radius: 20px;
1453            overflow: hidden;
1454            border: 1px solid rgba(32, 152, 80, 0.25);
1455            box-shadow: 0 24px 80px rgba(0, 0, 0, 0.45);
1456            animation: fadeUp 0.9s 0.5s ease both;
1457            position: relative;
1458            z-index: 1;
1459        }
1460
1461        .slider {
1462            position: relative;
1463            width: 100%;
1464            overflow: hidden;
1465            touch-action: pan-y;
1466        }
1467
1468        .slider .slides {
1469            display: flex;
1470            transition: transform 0.6s ease;
1471            will-change: transform;
1472            flex-wrap: nowrap;
1473            align-items: stretch;
1474        }
1475
1476        .slider .slide {
1477            flex: 0 0 100%;
1478            width: 100%;
1479            display: flex;
1480            align-items: center;
1481            justify-content: center;
1482            padding: 0;
1483        }
1484
1485        .slider img,
1486        .slider video {
1487            width: 100%;
1488            max-width: 100%;
1489            height: auto;
1490            display: block;
1491        }
1492
1493        .slider .arrow {
1494            position: absolute;
1495            top: 50%;
1496            transform: translateY(-50%);
1497            background: rgba(32, 152, 80, 0.75);
1498            color: #fff;
1499            border: none;
1500            padding: 10px 14px;
1501            border-radius: 8px;
1502            cursor: pointer;
1503            z-index: 10;
1504            font-size: 22px;
1505            line-height: 1;
1506            transition: background 0.2s;
1507        }
1508
1509        .slider .arrow:hover {
1510            background: var(--green-dark);
1511        }
1512
1513        .slider .arrow.left {
1514            left: 16px;
1515        }
1516
1517        .slider .arrow.right {
1518            right: 16px;
1519        }
1520
1521        /* ── SUBSCRIPTION MANAGEMENT STATE ── */
1522        .sub-info-box {
1523            background: var(--green-light);
1524            border: 1px solid rgba(32, 152, 80, 0.2);
1525            border-radius: 20px;
1526            padding: 24px;
1527            margin-bottom: 20px;
1528            text-align: center;
1529        }
1530
1531        .sub-status-badge {
1532            display: inline-flex;
1533            align-items: center;
1534            gap: 6px;
1535            font-size: 12px;
1536            font-weight: 700;
1537            letter-spacing: 0.5px;
1538            text-transform: uppercase;
1539            padding: 4px 12px;
1540            border-radius: 100px;
1541            margin-bottom: 10px;
1542        }
1543
1544        .sub-status-badge.active {
1545            background: var(--green);
1546            color: #fff;
1547        }
1548
1549        .sub-status-badge.past_due {
1550            background: var(--orange);
1551            color: #fff;
1552        }
1553
1554        .sub-status-badge.cancelled {
1555            background: #e5e7eb;
1556            color: #6b7280;
1557        }
1558
1559        .sub-info-box .sub-plan-name {
1560            font-family: 'Fraunces', serif;
1561            font-size: 22px;
1562            font-weight: 900;
1563            color: var(--ink);
1564            margin-bottom: 6px;
1565        }
1566
1567        .sub-renews {
1568            font-size: 13px;
1569            color: var(--mid);
1570        }
1571
1572        .sub-source-note {
1573            font-size: 14px;
1574            color: var(--mid);
1575            line-height: 1.65;
1576            padding: 16px;
1577            background: var(--cream);
1578            border-radius: 14px;
1579            border: 1px solid var(--border);
1580            margin-bottom: 20px;
1581        }
1582    </style>
1583
1584  <!-- Structured data: the three consumer plans, so search engines and
1585       assistants quote the right prices. Keep in step with the pricing grid
1586       below. Test changes with https://validator.schema.org/ -->
1587  
1587<script type="application/ld+json">
1588  {
1589    "@context": "https://schema.org",
1590    "@graph": [
1591      {
1592        "@type": "Product",
1593        "@id": "https://toycad.app/subscribe.html#product",
1594        "name": "ToyCAD",
1595        "description": "Full access to ToyCAD, the 3D design app that turns a child's drawing into a toy they can 3D print. Subscribe online and pay 20% less than the in-app price.",
1596        "image": "https://toycad.app/img_new/og/toycad.jpg",
1597        "brand": { "@type": "Brand", "name": "ToyCAD" },
1598        "offers": [
1599          {
1600            "@type": "Offer",
1601            "name": "Lifetime licence",
1602            "price": "71.99",
1603            "priceCurrency": "USD",
1604            "url": "https://toycad.app/subscribe.html#pricing",
1605            "availability": "https://schema.org/InStock"
1606          },
1607          {
1608            "@type": "Offer",
1609            "name": "Yearly subscription",
1610            "price": "31.99",
1611            "priceCurrency": "USD",
1612            "url": "https://toycad.app/subscribe.html#pricing",
1613            "availability": "https://schema.org/InStock"
1614          },
1615          {
1616            "@type": "Offer",
1617            "name": "Monthly subscription",
1618            "price": "5.59",
1619            "priceCurrency": "USD",
1620            "url": "https://toycad.app/subscribe.html#pricing",
1621            "availability": "https://schema.org/InStock"
1622          }
1623        ]
1624      },
1625      {
1626        "@type": "WebPage",
1627        "@id": "https://toycad.app/subscribe.html#webpage",
1628        "url": "https://toycad.app/subscribe.html",
1629        "name": "ToyCAD \u2014 Subscribe Online & Save 20%",
1630        "inLanguage": "en-US",
1631        "isPartOf": { "@id": "https://toycad.app/#website" },
1632        "breadcrumb": {
1633          "@type": "BreadcrumbList",
1634          "itemListElement": [
1635            { "@type": "ListItem", "position": 1, "name": "ToyCAD", "item": "https://toycad.app/" },
1636            { "@type": "ListItem", "position": 2, "name": "Plans & Pricing", "item": "https://toycad.app/subscribe.html" }
1637          ]
1638        }
1639      }
1640    ]
1641  }
1642  </script>
1642
1643
1644</head>
1645
1646<body>
1647
1648    <!-- Success banner (shown after returning from Stripe) -->
1649    <div class="success-banner" id="success-banner">
1650        <div class="success-banner-text">🎉 You're subscribed! Open the ToyCAD app → Profile tab → sign in with <strong
1651                id="banner-email">your email</strong> to activate your subscription.</div>
1652        <div class="success-banner-actions">
1653            <a href="https://apps.apple.com/us/app/toycad/id6711330232?mt=8" target="_blank" rel="noopener noreferrer">
1654                <img src="img_new/appstore.png" alt="Download on App Store" style="height:38px;display:block;">
1655            </a>
1656            <a href="https://play.google.com/store/apps/details?id=com.toycad.app&hl=en_US" target="_blank"
1657                rel="noopener noreferrer">
1658                <img src="img_new/playstore.png" alt="Get it on Google Play" style="height:38px;display:block;">
1659            </a>
1660            <button class="banner-manage-btn" onclick="openModal(null)">Manage Subscription →</button>
1661        </div>
1662    </div>
1663
1664    <nav>
1665        <a href="https://toycad.app" class="nav-logo">
1666            <img src="img_new/logo.png" alt="ToyCAD">
1667        </a>
1668        <div id="nav-signed-out">
1669            <button class="nav-cta" onclick="openModal(null, 'signin')">Sign In</button>
1670        </div>
1671        <div id="nav-signed-in" style="display:none;align-items:center;gap:10px;">
1672            <span id="nav-user-email" onclick="openModal(null)"
1673                style="font-size:13px;color:rgba(255,255,255,0.55);max-width:180px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;cursor:pointer;"
1674                title="Manage subscription"></span>
1675            <button class="nav-cta"
1676                style="background:transparent;border:1px solid rgba(255,255,255,0.25);font-size:13px;padding:8px 16px;"
1677                onclick="handleSignOut()">Sign Out</button>
1678        </div>
1679    </nav>
1680
1681    <!-- HERO -->
1682    <section class="hero">
1683        <!-- HERO SLIDER -->
1684        <div class="hero-slider-wrap">
1685            <div class="slider" id="heroSlider" aria-roledescription="carousel">
1686                <div class="slides">
1687                    <div class="slide">
1688                        <picture>
1689                            <source srcset="img_new/headerVertical.png" media="(orientation: portrait)">
1690                            <img src="img_new/header.png" alt="ToyCAD Header Image">
1691                        </picture>
1692                    </div>
1693                    <div class="slide">
1694                        <video id="heroIntroVideo" playsinline muted preload="metadata"
1695                            style="width:100%;display:block;">
1696                            <source src="img/getstarted_with_subtitles.mp4" type="video/mp4">
1697                        </video>
1698                    </div>
1699                    <div class="slide">
1700                        <picture>
1701                            <source srcset="img_new/CoverPhotoVertical.png" media="(orientation: portrait)">
1702                            <img src="img_new/CoverPhoto.png" alt="ToyCAD Header Image">
1703                        </picture>
1704                    </div>
1705                    <div class="slide">
1706                        <picture>
1707                            <source srcset="img_new/kid1.png" media="(orientation: portrait)">
1708                            <img src="img_new/kid1expanded.png" alt="ToyCAD Header Image">
1709                        </picture>
1710                    </div>
1711                    <div class="slide">
1712                        <picture>
1713                            <source srcset="img_new/kid2.png" media="(orientation: portrait)">
1714                            <img src="img_new/kid2expanded.png" alt="ToyCAD Header Image">
1715                        </picture>
1716                    </div>
1717                    <div class="slide">
1718                        <picture>
1719                            <source srcset="img_new/kid3.jpg" media="(orientation: portrait)">
1720                            <img src="img_new/kid3expanded.jpg" alt="ToyCAD Header Image">
1721                        </picture>
1722                    </div>
1723                </div>
1724                <button class="arrow left" id="sliderPrev" aria-label="Previous">&#8249;</button>
1725                <button class="arrow right" id="sliderNext" aria-label="Next">&#8250;</button>
1726            </div>
1727        </div>
1728
1729        <div class="hero-badge"><span class="dot"></span>The Easiest 3D Toy Design App for Kids</div>
1730        <h1>Turn Your Child's Imagination<br>into <em>Real Toys</em> Today!</h1>
1731        <p class="hero-sub">ToyCAD lets kids draw any toy and 3D print it — no CAD experience needed. </p>
1732        <div
1733            style="display:flex;flex-direction:column;align-items:center;gap:32px;margin-top:8px;width:100%;max-width:700px;">
1734
1735            <!-- Step 1: Try for free -->
1736            <div style="display:flex;flex-direction:column;align-items:center;gap:16px;width:100%;">
1737                <div style="display:flex;align-items:center;gap:12px;">
1738                    <div
1739                        style="width:38px;height:38px;background:rgba(255,255,255,0.12);border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:16px;font-weight:700;color:rgba(255,255,255,0.5);flex-shrink:0;">
1740                        1</div>
1741                    <p style="font-size:19px;font-weight:700;color:rgba(255,255,255,0.7);margin:0;">Try ToyCAD for free
1742                        <span
1743                            style="background:rgba(32,152,80,0.25);color:#4cce7e;border:1px solid rgba(76,206,126,0.4);border-radius:100px;padding:2px 12px;font-size:14px;font-weight:700;letter-spacing:0.3px;white-space:nowrap;">3-day
1744                            free trial</span>
1745                    </p>
1746                </div>
1747                <div style="display:flex;align-items:center;gap:14px;flex-wrap:wrap;justify-content:center;">
1748                    <a href="https://apps.apple.com/us/app/toycad/id6711330232?mt=8" target="_blank"
1749                        rel="noopener noreferrer">
1750                        <img src="img_new/appstore.png" alt="Download on App Store"
1751                            style="width:160px;height:auto;display:block;border-radius:8px;box-shadow:0 4px 12px rgba(0,0,0,0.3);">
1752                    </a>
1753                    <a href="https://play.google.com/store/apps/details?id=com.toycad.app&hl=en_US" target="_blank"
1754                        rel="noopener noreferrer">
1755                        <img src="img_new/playstore.png" alt="Get it on Google Play"
1756                            style="width:160px;height:auto;display:block;border-radius:8px;box-shadow:0 4px 12px rgba(0,0,0,0.3);">
1757                    </a>
1758                    <!-- <a href="https://toycad.online" target="_blank" rel="noopener noreferrer">
1759                        <img src="img_new/webapp.png" alt="Try it on the Web"
1760                            style="width:160px;height:auto;display:block;border-radius:8px;box-shadow:0 4px 12px rgba(0,0,0,0.3);">
1761                    </a> -->
1762                </div>
1763            </div>
1764
1765            <!-- Divider -->
1766            <div style="display:flex;align-items:center;gap:14px;width:100%;max-width:500px;">
1767                <div style="flex:1;height:1px;background:rgba(255,255,255,0.1);"></div>
1768                <span style="font-size:13px;color:rgba(255,255,255,0.3);white-space:nowrap;">then, save 20% when you
1769                    subscribe online</span>
1770                <div style="flex:1;height:1px;background:rgba(255,255,255,0.1);"></div>
1771            </div>
1772
1773            <!-- Step 2: Subscribe online -->
1774            <div style="display:flex;flex-direction:column;align-items:center;gap:16px;width:100%;">
1775                <div style="display:flex;align-items:center;gap:12px;">
1776                    <div
1777                        style="width:38px;height:38px;background:rgba(32,152,80,0.3);border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:16px;font-weight:700;color:#4cce7e;flex-shrink:0;">
1778                        2</div>
1779                    <p style="font-size:19px;font-weight:700;color:rgba(255,255,255,0.7);margin:0;">Subscribe online —
1780                        save 20%</p>
1781                </div>
1782                <div style="display:flex;gap:12px;flex-wrap:wrap;justify-content:center;">
1783                    <button class="btn-primary"
1784                        onclick="document.querySelector('#pricing').scrollIntoView({behavior:'smooth'})">See Plans &amp;
1785                        Pricing →</button>
1786                    <a href="https://toycad.app/subscribeSchools.html#pricing"
1787                        style="display:inline-flex;align-items:center;justify-content:center;border:2px solid rgba(76,206,126,0.5);color:#4cce7e;border-radius:100px;padding:14px 24px;font-family:'DM Sans',sans-serif;font-size:15px;font-weight:600;text-decoration:none;white-space:nowrap;transition:border-color 0.15s,background 0.15s;"
1788                        onmouseover="this.style.borderColor='#4cce7e';this.style.background='rgba(76,206,126,0.08)'"
1789                        onmouseout="this.style.borderColor='rgba(76,206,126,0.5)';this.style.background='transparent'">School
1790                        Plans →</a>
1791                </div>
1792                <p class="hero-note">Secure checkout via Stripe · cancel yearly any time</p>
1793            </div>
1794
1795        </div>
1796
1797    </section>
1798
1799    <div class="proof-bar">
1800        <span>★★★★★</span> &nbsp;"My girls 8 and 6 love it and we printed a couple items they made. I was amazed how
1801        fast they picked it up — especially my 6 yr old!" — Aaron W.
1802    </div>
1803
1804    <!-- FEATURES -->
1805    <section class="features-section">
1806        <div class="container">
1807            <div class="feature-row reveal">
1808                <div class="feature-row-text">
1809                    <div class="section-label">Kid-Friendly Design Tool</div>
1810                    <h2>The Easiest Way for Kids<br>to Design Toys</h2>
1811                    <p>ToyCAD's intuitive interface seamlessly turns simple drawings into 3D models — perfect for little
1812                        creators. It's all about making 3D design a fun, approachable experience for any age.</p>
1813                </div>
1814                <div class="feature-row-image">
1815                    <img src="img_new/kid1.png" alt="Kid drawing in ToyCAD">
1816                </div>
1817            </div>
1818            <div class="feature-row reverse reveal">
1819                <div class="feature-row-text">
1820                    <div class="section-label">Educational &amp;
1820 Entertaining</div>
1821                    <h2>Builds Creativity &amp;<br>Problem-Solving Skills</h2>
1822                    <p>ToyCAD blends education with play. Every design session builds your child's spatial reasoning,
1823                        problem-solving, and creative confidence — skills that set them up for future success.</p>
1824                </div>
1825                <div class="feature-row-image">
1826                    <img src="img_new/kid2.png" alt="Child learning with ToyCAD">
1827                </div>
1828            </div>
1829            <div class="feature-row reveal">
1830                <div class="feature-row-text">
1831                    <div class="section-label">Design, Print, Play</div>
1832                    <h2>From Drawing to Real Toy<br>in Their Hands</h2>
1833                    <p>From idea to physical toy — kids see their creations come to life. Holding something they
1834                        designed themselves sparks a pride and love for making things that lasts a lifetime.</p>
1835                </div>
1836                <div class="feature-row-image">
1837                    <img src="img_new/kid3.jpg" alt="Kid holding a printed toy">
1838                </div>
1839            </div>
1840        </div>
1841    </section>
1842
1843    <!-- MAKE ALL KINDS OF TOYS -->
1844    <section class="toys-section">
1845        <div class="container">
1846            <div class="section-label" style="color:#4cce7e;">What You Can Make</div>
1847            <h2 class="section-title">Make All Kinds of Toys</h2>
1848            <p class="section-sub">ToyCAD is easy but still powerful! Combining freeform shaping like playdough with
1849                accurate engineering concepts for things like joints.</p>
1850            <div class="toys-grid">
1851                <div class="toy-card reveal">
1852                    <video autoplay muted loop playsinline>
1853                        <source src="img_new/interlocking1.mp4" type="video/mp4">
1854                    </video>
1855                    <h3>Interlocking Parts</h3>
1856                </div>
1857                <div class="toy-card reveal reveal-delay-1">
1858                    <video autoplay muted loop playsinline>
1859                        <source src="img_new/articulate.mp4" type="video/mp4">
1860                    </video>
1861                    <h3>Articulated Toys</h3>
1862                </div>
1863                <div class="toy-card reveal reveal-delay-2">
1864                    <video autoplay muted loop playsinline>
1865                        <source src="img_new/magnetic.mp4" type="video/mp4">
1866                    </video>
1867                    <h3>Snap-Fit Toys</h3>
1868                </div>
1869                <div class="toy-card reveal">
1870                    <img src="img_new/endless.gif" alt="Character Toys">
1871                    <h3>Character Toys</h3>
1872                </div>
1873            </div>
1874        </div>
1875    </section>
1876
1877    <!-- WHAT PARENTS SAY -->
1878    <section class="parents-section">
1879        <div class="container">
1880            <div class="section-label">Real Reviews</div>
1881            <h2 class="section-title">What Parents Say</h2>
1882            <div class="parents-grid">
1883                <div class="parent-card reveal">
1884                    <p>"I have a 4 year old and she <strong>loves</strong> to draw in this app with me. Watching her
1885                        face glow with excitement when a random set of squiggles can become a 3D print she can hold is
1886                        amazing for us both. Toycad is worth 5 stars to me."</p>
1887                    <span class="parent-name">— Drivenapollo</span>
1888                </div>
1889                <div class="parent-card reveal reveal-delay-1">
1890                    <p>"My daughter and I absolutely <strong>ADORE</strong> the app you've created. It's brilliant! So
1891                        intuitive and easy to dive into!"</p>
1892                    <span class="parent-name">— Kate O.</span>
1893                </div>
1894                <div class="parent-card reveal reveal-delay-2">
1895                    <p>"My girls 8 and 6 <strong>love</strong> it and we printed a couple items they made. I was amazed
1896                        to see how fast they picked it up — especially my 6 yr old!"</p>
1897                    <span class="parent-name">— Aaron W.</span>
1898                </div>
1899                <div class="parent-card reveal">
1900                    <p>"My son <strong>loves</strong> it. He's 6 and it's amazing to see the joy in his eyes when I hand
1901                        him something he designed himself."</p>
1902                    <span class="parent-name">— Michael J.</span>
1903                </div>
1904                <div class="parent-card reveal reveal-delay-1">
1905                    <p>"My 5yo <strong>loves</strong> it and did that all on her own. In fact wouldn't let me help her!"
1906                    </p>
1907                    <span class="parent-name">— Matt W.</span>
1908                </div>
1909                <div class="parent-card reveal reveal-delay-2">
1910                    <p>"We had a lot of fun designing and printing the first toys for 5 and 6 year old yesterday! Really
1911                        <strong>impressed</strong> overall with the program!"
1912                    </p>
1913                    <span class="parent-name">— Ryan W.</span>
1914                </div>
1915                <div class="parent-card reveal">
1916                    <p>"My kids absolutely <strong>love</strong> the app by the way. I appreciate it! Keep up the good
1917                        work!"</p>
1918                    <span class="parent-name">— Brandon F.</span>
1919                </div>
1920                <div class="parent-card reveal reveal-delay-1">
1921                    <p>"My daughter just started using the web version and is loving knowing that we can create
1922                        <strong>whatever</strong> she is drawing on our printer!"
1923                    </p>
1924                    <span class="parent-name">— Amanda P.</span>
1925                </div>
1926            </div>
1927        </div>
1928    </section>
1929
1930    <!-- WHAT KIDS MADE -->
1931    <section class="kids-section">
1932        <div class="container">
1933            <div class="section-label">Community Gallery</div>
1934            <h2 class="section-title">What Kids Made</h2>
1935            <div class="toys-grid" style="margin-top:40px;">
1936                <div class="toy-card reveal reveal-delay-1" style="background:var(--cream);border-color:var(--border);">
1937                    <img src="img_new/kids/dinasour.jpg" alt="Kid creation">
1938                </div>
1939                <div class="toy-card reveal reveal-delay-1" style="background:var(--cream);border-color:var(--border);">
1940                    <img src="img_new/kids/sp_kitty.jpg" alt="Kid creation">
1941                </div>
1942                <div class="toy-card reveal" style="background:var(--cream);border-color:var(--border);"><img
1943                        src="img_new/kids/friends.jpg" alt="Kid creation"></div>
1944                <div class="toy-card reveal reveal-delay-1" style="background:var(--cream);border-color:var(--border);">
1945                    <img src="img_new/kids/0.JPG" alt="Kid creation">
1946                </div>
1947                <div class="toy-card reveal reveal-delay-2" style="background:var(--cream);border-color:var(--border);">
1948                    <img src="img_new/kids/clicker.jpg" alt="Kid creation">
1949                </div>
1950                <div class="toy-card reveal reveal-delay-1" style="background:var(--cream);border-color:var(--border);">
1951                    <img src="img_new/kids/1.jpg" alt="Kid creation">
1952                </div>
1953                <div class="toy-card reveal reveal-delay-2" style="background:var(--cream);border-color:var(--border);">
1954                    <img src="img_new/kids/2.jpg" alt="Kid creation">
1955                </div>
1956                <div class="toy-card reveal" style="background:var(--cream);border-color:var(--border);"><img
1957                        src="img_new/kids/3.jpg" alt="Kid creation"></div>
1958                <div class="toy-card reveal reveal-delay-1" style="background:var(--cream);border-color:var(--border);">
1959                    <img src="img_new/kids/4.jpg" alt="Kid creation">
1960                </div>
1961                <div class="toy-card reveal reveal-delay-2" style="background:var(--cream);border-color:var(--border);">
1962                    <img src="img_new/kids/5.jpg" alt="Kid creation">
1963                </div>
1964                <div class="toy-card reveal" style="background:var(--cream);border-color:var(--border);"><img
1965                        src="img_new/kids/6.jpg" alt="Kid creation"></div>
1966                <div class="toy-card reveal reveal-delay-1" style="background:var(--cream);border-color:var(--border);">
1967                    <img src="img_new/kids/7.jpg" alt="Kid creation">
1968                </div>
1969                <div class="toy-card reveal reveal-delay-2" style="background:var(--cream);border-color:var(--border);">
1970                    <img src="img_new/kids/8.jpg" alt="Kid creation">
1971                </div>
1972                <div class="toy-card reveal" style="background:var(--cream);border-color:var(--border);"><img
1973                        src="img_new/kids/10.jpg" alt="Kid creation"></div>
1974                <div class="toy-card reveal reveal-delay-1" style="background:var(--cream);border-color:var(--border);">
1975                    <img src="img_new/kids/11.jpg" alt="Kid creation">
1976                </div>
1977                <div class="toy-card reveal reveal-delay-2" style="background:var(--cream);border-color:var(--border);">
1978                    <img src="img_new/kids/12.jpg" alt="Kid creation">
1979                </div>
1980            </div>
1981        </div>
1982    </section>
1983    <section class="pricing" id="pricing">
1984        <div class="container">
1985            <div class="section-label">
1985Online Exclusive Pricing</div>
1986            <h2 class="section-title">20% off when you<br>subscribe online.</h2>
1987            <p class="section-sub">Subscribe here to save 20% vs. in-app prices. Full access activates immediately in
1988                the ToyCAD app when you sign in with your account.</p>
1989            <div class="pricing-grid">
1990                <div class="pricing-card reveal">
1991                    <div class="pricing-discount-badge">20% OFF</div>
1992                    <div
1993                        style="font-size:11px;font-weight:800;letter-spacing:2px;text-transform:uppercase;color:var(--mid);margin-bottom:14px;">
1994                        Individual</div>
1995                    <h3>Lifetime License</h3>
1996                    <div class="price-row">
1997                        <div class="price">$71.99</div>
1998                        <div class="price-was">$89.99</div>
1999                    </div>
2000                    <div class="price-note">one-time · use forever · save $18</div>
2001                    <ul>
2002                        <li>One-time payment — never renews</li>
2003                        <li>Full app access forever</li>
2004                        <li>All future updates included</li>
2005                        <li>Works with any 3D printer</li>
2006                        <li>Activate in the app via email sign-in</li>
2007                    </ul>
2008                    <button class="btn-outline" onclick="openModal('lifetime')">Get Lifetime — $71.99 →</button>
2009                </div>
2010                <div class="pricing-card featured reveal reveal-delay-1">
2011                    <div class="pricing-badge">MOST POPULAR</div>
2012                    <div class="pricing-discount-badge">20% OFF</div>
2013                    <div
2014                        style="font-size:11px;font-weight:800;letter-spacing:2px;text-transform:uppercase;color:rgba(255,255,255,0.45);margin-bottom:14px;">
2015                        Individual</div>
2016                    <h3>Yearly Subscription</h3>
2017                    <div class="price-row">
2018                        <div class="price">$31.99</div>
2019                        <div class="price-was">$39.99</div>
2020                    </div>
2021                    <div class="price-note">per year · billed annually · save $8/yr</div>
2022                    <ul>
2023                        <li>Full app access for one year</li>
2024                        <li>Auto-renews · cancel any time</li>
2025                        <li>All future updates included</li>
2026                        <li>Works with any 3D printer</li>
2027                        <li>Activate in the app via email sign-in</li>
2028                    </ul>
2029                    <button class="btn-green" onclick="openModal('yearly')">Get Yearly — $31.99/yr →</button>
2030                </div>
2031                <div class="pricing-card reveal reveal-delay-2">
2032                    <div class="pricing-discount-badge">20% OFF</div>
2033                    <div
2034                        style="font-size:11px;font-weight:800;letter-spacing:2px;text-transform:uppercase;color:var(--mid);margin-bottom:14px;">
2035                        Individual</div>
2036                    <h3>Monthly Subscription</h3>
2037                    <div class="price-row">
2038                        <div class="price">$5.59</div>
2039                        <div class="price-was">$6.99</div>
2040                    </div>
2041                    <div class="price-note">per month · billed monthly · save $1.40/mo</div>
2042                    <ul>
2043                        <li>Full app access each month</li>
2044                        <li>Auto-renews · cancel any time</li>
2045                        <li>All future updates included</li>
2046                        <li>Works with any 3D printer</li>
2047                        <li>Activate in the app via email sign-in</li>
2048                    </ul>
2049                    <button class="btn-outline" onclick="openModal('monthly')">Get Monthly — $5.59/mo →</button>
2050                </div>
2051                <div class="pricing-card reveal">
2052                    <div
2053                        style="font-size:11px;font-weight:800;letter-spacing:2px;text-transform:uppercase;
2053color:var(--mid);margin-bottom:14px;">
2054                        Schools</div>
2055                    <h3>School Plans</h3>
2056                    <div class="price-row">
2057                        <div class="price" style="font-size:36px;">From $9</div>
2058                    </div>
2059                    <div class="price-note">per month · billed yearly</div>
2060                    <ul>
2061                        <li>Teacher, Classroom &amp; School tiers</li>
2062                        <li>Up to 3, 35, or unlimited students</li>
2063                        <li>Class codes students redeem in-app</li>
2064                        <li>Manage seats from a teacher dashboard</li>
2065                        <li>Cancel any time</li>
2066                    </ul>
2067                    <a href="https://toycad.app/subscribeSchools.html" class="btn-outline">View School Plans →</a>
2068                </div>
2069            </div>
2070            <p style="margin-top:24px;font-size:13px;color:var(--mid);">
2071                After subscribing, open ToyCAD → Profile tab → sign in with the same email to activate your subscription
2072                in the app.
2073            </p>
2074        </div>
2075    </section>
2076
2077    <!-- HOW IT WORKS -->
2078    <section class="how" id="how">
2079        <div class="container">
2080            <div class="section-label">How It Works</div>
2081            <h2 class="section-title">Subscribe here. Use it<br>in the app. That's it.</h2>
2082            <p class="section-sub">Your subscription activates automatically the moment you sign in with your account
2083                inside the ToyCAD app.</p>
2084            <div class="steps">
2085                <div class="step reveal">
2086                    <div class="step-num">1</div>
2087                    <h3>Subscribe online</h3>
2088                    <p>Pick Lifetime, Yearly, or Monthly, create an account, and complete payment via Stripe. Takes
2089                        under 2
2090                        minutes.</p>
2091                </div>
2092                <div class="step reveal reveal-delay-1">
2093                    <div class="step-num">2</div>
2094                    <h3>Open ToyCAD → Profile</h3>
2095                    <p>In the app, go to the Profile tab and sign in with the same email and password you used here.</p>
2096                </div>
2097                <div class="step reveal reveal-delay-2">
2098                    <div class="step-num">3</div>
2099                    <h3>Subscription activates</h3>
2100                    <p>Your subscription is recognized instantly. Full access activated — start designing your first
2101                        toy!</p>
2102                </div>
2103            </div>
2104        </div>
2105    </section>
2106
2107    <!-- BENEFITS -->
2108    <section class="why">
2109        <div class="container">
2110            <div class="section-label">What You Get</div>
2111            <h2 class="section-title">Full ToyCAD — everything<br>unlocked.</h2>
2112            <p class="section-sub">No feature limits, no watermarks. The complete ToyCAD experience on your iPad.</p>
2113            <div class="benefits">
2114                <div class="benefit-card reveal">
2115                    <div class="benefit-icon">✏️</div>
2116                    <h3>Draw any toy freehand</h3>
2117                    <p>Sketch any shape with your finger or Apple Pencil. ToyCAD converts it to a 3D-printable STL
2118                        instantly.</p>
2119                </div>
2120                <div class="benefit-card reveal reveal-delay-1">
2121                    <div class="benefit-icon">🔗</div>
2122                    <h3>Interlocking parts</h3>
2123                    <p>Engineer pieces that snap and fit together. Hinges, connectors, and moving joints — all from a
2124                        drawing.</p>
2125                </div>
2126                <div class="benefit-card reveal reveal-delay-2">
2127                    <div class="benefit-icon">🧲</div>
2128                    <h3>Snap-fit & articulated</h3>
2129                    <p>Design snap-fit toys and movable articulated figures. Full engineering features, zero
2130                        tutorials needed.</p>
2131                </div>
2132                <div class="benefit-card reveal">
2133                    <div class="benefit-icon">🖨️</div>
2134                    <h3>
2134Any 3D printer</h3>
2135                    <p>Exports standard STL — works with Bambu Lab, Creality, Prusa, MakerBot and every major brand.</p>
2136                </div>
2137                <div class="benefit-card reveal reveal-delay-1">
2138                    <div class="benefit-icon">📦</div>
2139                    <h3>All future updates</h3>
2140                    <p>New tools, new toy types, new tutorials — all included with your subscription at no extra cost.
2141                    </p>
2142                </div>
2143                <div class="benefit-card reveal reveal-delay-2">
2144                    <div class="benefit-icon">🔐</div>
2145                    <h3>One account, any device</h3>
2146                    <p>Your subscription follows your account. Sign into any iPad and your full access is there
2147                        instantly.</p>
2148                </div>
2149            </div>
2150        </div>
2151    </section>
2152
2153    <!-- DOWNLOAD / TRY FIRST -->
2154    <section class="download-section">
2155        <div class="container">
2156            <div class="section-label">Try Before You Subscribe</div>
2157            <h2 class="section-title">Download free and<br>try your first designs.</h2>
2158            <p class="section-sub" style="margin:0 auto;">
2159                ToyCAD is free to download. Explore the app and try a few designs — then subscribe online to unlock
2160                everything and save 20%.
2161            </p>
2162            <div class="store-buttons">
2163                <a href="https://apps.apple.com/us/app/toycad/id6711330232?mt=8" target="_blank">
2164                    <img src="img_new/appstore.png" alt="Download on App Store">
2165                </a>
2166                <a href="https://play.google.com/store/apps/details?id=com.toycad.app&hl=en_US" target="_blank">
2167                    <img src="img_new/playstore.png" alt="Get it on Google Play">
2168                </a>
2169            </div>
2170            <p style="margin-top:20px;font-size:13px;color:var(--mid);">
2171                Remember: subscribe here (not in-app) to get the 20% online discount.
2172            </p>
2173        </div>
2174    </section>
2175
2176    <!-- FAQ -->
2177    <section class="faq">
2178        <div class="container">
2179            <div class="section-label">Questions</div>
2180            <h2 class="section-title">Everything you need to know</h2>
2181            <div class="faq-list">
2182                <div class="faq-item">
2183                    <button class="faq-q" onclick="toggleFaq(this)">How does the 20% online discount work?<span
2184                            class="arrow">+</span></button>
2185                    <div class="faq-a">Subscribe here on the website instead of through the App Store or Google Play. By
2186                        subscribing directly, we skip the app store fee and pass the savings to you — 20% off. The same
2187                        full ToyCAD access, just cheaper.</div>
2188                </div>
2189                <div class="faq-item">
2190                    <button class="faq-q" onclick="toggleFaq(this)">How do I activate my subscription in the app?<span
2191                            class="arrow">+</span></button>
2192                    <div class="faq-a">After subscribing here, open ToyCAD on your iPad and go to the Profile tab. Sign
2193                        in with the same email and password you used when subscribing. Your subscription will activate
2194                        automatically within seconds.</div>
2195                </div>
2196                <div class="faq-item">
2197                    <button class="faq-q" onclick="toggleFaq(this)">What's the difference between Lifetime and
2198                        Yearly?<span class="arrow">+</span></button>
2199                    <div class="faq-a">The Lifetime license is a one-time payment of $71.99 — you pay once and have full
2200                        access forever, including all future updates. The Yearly subscription is $31.99/year and renews
2201                        annually. You can cancel the yearly plan at any time from your account settings.</div>
2202                </div>
2203                <div class="faq-item">
2204                    <button class="faq-q" onclick="toggleFaq(this)">Is my payment secure?<span
2205                            class="arrow">+</span></button>
2206                    <div class="faq-a">Yes. All payments are processed securely by Stripe, the same payment platform
2207                        used by millions of businesses worldwide. We never store your card details.</div>
2208                </div>
2209                <div class="faq-item">
2210                    <button class="faq-q" onclick="toggleFaq(this)">Can I use ToyCAD on multiple devices?<span
2211                            class="arrow">+</span></button>
2212                    <div class="faq-a">Yes. Your subscription is tied to your account (email). Sign in on any iPad with
2213                        the same email and password to activate your subscription on that device.</div>
2214                </div>
2215                <div class="faq-item">
2216                    <button class="faq-q" onclick="toggleFaq(this)">What 3D printers does it work with?<span
2217                            class="arrow">+</span></button>
2218                    <div class="faq-a">
2218ToyCAD exports standard STL files which work with every major 3D printer
2219                        including Bambu Lab, Creality, Prusa, MakerBot, and more.</div>
2220                </div>
2221            </div>
2222        </div>
2223    </section>
2224
2225    <!-- CTA -->
2226    <section class="cta-section">
2227        <h2 class="section-title">Ready to start designing?</h2>
2228        <p class="section-sub">Subscribe online now and save 20%. Full ToyCAD access — activated instantly in the app.
2229        </p>
2230        <button class="btn-primary" onclick="openModal('lifetime')">Get started — 20% Off →</button>
2231        <p class="cta-note">Secure checkout via Stripe. No hidden fees.</p>
2232    </section>
2233
2234    <footer>
2235        <p>© 2026 ToyCAD LLC · Burlington, MA · <a href="https://toycad.app/contact.html">Contact</a> · <a
2236                href="https://toycad.app/privacyPolicy.html">Privacy Policy</a> · <a
2237                href="https://toycad.app/webTerms.html">Terms</a></p>
2238    </footer>
2239
2240    <!-- SUBSCRIPTION MODAL -->
2241    <div class="modal-overlay" id="sub-modal" onclick="handleModalOverlayClick(event)">
2242        <div class="modal" id="modal-inner">
2243            <button class="modal-close" onclick="closeModal()">×</button>
2244
2245            <!-- Plan chip (shown in auth + checkout states) -->
2246            <div class="modal-plan-chip" id="modal-plan-chip" style="display:none;">
2247                ✦ <span id="modal-plan-chip-text">Lifetime — $71.99</span>
2248            </div>
2249
2250            <!-- Error / success message -->
2251            <div class="modal-error" id="modal-error"></div>
2252
2253            <!-- ── STATE: AUTH ── -->
2254            <div id="modal-auth-state">
2255                <h2 id="auth-state-heading">Create your account</h2>
2256                <p class="modal-sub">Create a free account or sign in — then complete your subscription.</p>
2257
2258                <div class="auth-tabs">
2259                    <button class="auth-tab active" id="tab-signup" onclick="setAuthMode('signup')">Sign Up</button>
2260                    <button class="auth-tab" id="tab-signin" onclick="setAuthMode('signin')">Log In</button>
2261                </div>
2262
2263                <!-- Sign Up form -->
2264                <div id="auth-signup-form">
2265                    <div class="form-group">
2266                        <label>Email address</label>
2267                        <input type="email" id="signup-email" placeholder="[email protected]" autocomplete="email">
2268                    </div>
2269                    <div class="form-group">
2270                        <label>Password <span style="color:var(--mid);font-weight:400">(min 6 characters)</span></label>
2271                        <input type="password" id="signup-password" placeholder="Create a password"
2272                            autocomplete="new-password">
2273                    </div>
2274                    <button class="modal-submit-btn" id="signup-btn" onclick="handleSignUp()">Create Account & Continue
2275                        →</button>
2276                    <p class="form-fine">By continuing you agree to our <a href="https://toycad.app/webTerms.html"
2277                            style="color:var(--green)">Terms</a> and <a href="https://toycad.app/privacyPolicy.html"
2278                            style="color:var(--green)">Privacy Policy</a>.</p>
2279                </div>
2280
2281                <!-- Sign In form -->
2282                <div id="auth-signin-form" style="display:none;">
2283                    <div class="form-group">
2284                        <label>Email address</label>
2285                        <input type="email" id="signin-email" placeholder="[email protected]" autocomplete="email">
2286                    </div>
2287                    <div class="form-group">
2288                        <label>Password</label>
2289                        <input type="password" id="signin-password" placeholder="Your password"
2290                            autocomplete="current-password">
2291                    </div>
2292                    <button class="modal-submit-btn" id="signin-btn" onclick="handleSignIn()">Log In & Continue
2293                        →</button>
2294                    <button class="modal-link-btn" onclick="setAuthMode('forgot')">Forgot password?</button>
2295                </div>
2296
2297                <!-- Forgot Password form -->
2298                <div id="auth-forgot-form" style="display:none;">
2299                    <p class="modal-sub" style="margin-bottom:16px;">Enter your email and we'll send you a reset link.
2300                    </p>
2301                    <div class="form-group">
2302                        <label>Email address</label>
2303                        <input type="email" id="forgot-email" placeholder="[email protected]" autocomplete="email">
2304                    </div>
2305                    <button class="modal-submit-btn" id="forgot-btn" onclick="handleForgotPassword()">Send Reset
2306                        Email</button>
2307                    <button class="modal-link-btn" onclick="setAuthMode('signin')">← Back to Log In</button>
2308                </div>
2309            </div>
2310
2311            <!-- ── STATE: CHECKOUT ── -->
2312            <div id="modal-checkout-state" style="display:none;">
2313                <h2>Complete your subscription</h2>
2314                <p class="modal-sub">You're signed in. Review your plan and proceed to secure checkout.</p>
2315                <div class="checkout-plan-box">
2316                    <div class="plan-label">Your selected plan</div>
2317                    <div class="plan-name" id="checkout-plan-name">Lifetime License</div>
2318                    <div class="plan-price" id="checkout-plan-price">$71.99</div>
2319                    <div class="plan-note" id="checkout-plan-note">one-time · use forever</div>
2320                </div>
2321                <div class="checkout-user-row">
2322                    <span>Signed in as:</span>
2323                    <strong id="checkout-user-email"></strong>
2324                    <button onclick="handleSignOut()"
2325                        style="margin-left:auto;background:none;border:none;color:var(--mid);font-size:12px;cursor:pointer;text-decoration:underline;">Sign
2326                        out</button>
2327                </div>
2328                <button class="modal-submit-btn" id="checkout-btn" onclick="handleCheckout()">Continue to Secure
2329                    Checkout →</button>
2330                <p class="form-fine">Secure payment via Stripe · 20% online discount applied</p>
2331            </div>
2332
2333            <!-- ── STATE: LOADING ── -->
2334            <div id="modal-loading-state" style="display:none;">
2335                <div class="loading-state">
2336                    <div class="spinner"></div>
2337                    <p>Preparing secure checkout…</p>
2338                </div>
2339            </div>
2340
2341            <!-- ── STATE: SUCCESS ── -->
2342            <div id="modal-success-state" style="display:none;">
2343                <div class="modal-success-state">
2344                    <div class="success-icon">🎉</div>
2345                    <h3>You're subscribed!</h3>
2346                    <p>Your <strong id="success-plan-name">ToyCAD</strong> subscription is active. Now activate it in
2347                        the app:</p>
2348                    <div class="activate-steps">
2349                        <p>To activate in the ToyCAD app:</p>
2350                        <ol>
2351                            <li>Download ToyCAD from the App Store or Google Play</li>
2352                            <li>Open the app and go to the <strong>Profile</strong> tab</li>
2353                            <li>Sign in with email: <strong id="success-email"></strong></li>
2354                            <li>Your subscription activates automatically ✓</li>
2355                        </ol>
2356                    </div>
2357                    <div style="display:flex;flex-direction:column;align-items:center;gap:10px;margin-top:20px;">
2358                        <a href="https://apps.apple.com/us/app/toycad/id6711330232?mt=8" target="_blank">
2359                            <img src="img_new/appstore.png" alt="Download on App Store" style="height:44px;">
2360                        </a>
2361                        <a href="https://play.google.com/store/apps/details?id=com.toycad.app&hl=en_US" target="_blank">
2362                            <img src="img_new/playstore.png" alt="Get it on Google Play" style="height:44px;">
2363                        </a>
2364                    </div>
2365                </div>
2366            </div>
2367
2368            <!-- ── STATE: SUBSCRIPTION MANAGEMENT ── -->
2369            <div id="modal-subscription-state" style="display:none;">
2370                <h2>Your Subscription</h2>
2371                <p class="modal-sub" id="sub-state-user-email" style="margin-bottom:20px;"></p>
2372                <div class="sub-info-box">
2373                    <div id="sub-status-badge" class="sub-status-badge active">● <span
2374                            id="sub-status-text">Active</span></div>
2375                    <div class="sub-plan-name" id="sub-plan-name">Lifetime License</div>
2376                    <div class="sub-renews" id="sub-renews-text"></div>
2377                </div>
2378                <!-- Web (Stripe) subscriber actions -->
2379                <div id="sub-web-actions">
2380                    <button class="modal-submit-btn" id="manage-sub-btn" onclick="handleManageSubscription()">Manage
2381                        Subscription →</button>
2382                    <p class="form-fine" style="margin-top:10px;">Opens Stripe's secure billing portal — update your
2383                        payment method, download invoices, or cancel.</p>
2384                </div>
2385                <!-- In-app subscriber note -->
2386                <div id="sub-inapp-note" style="display:none;">
2387                    <div class="sub-source-note">
2388                        This subscription was purchased through the <strong>App Store or Google Play</strong>. To manage
2389                        or cancel it, go to <strong>Settings → [Your Name] → Subscriptions</strong> on your device, or
2390                        open the ToyCAD app.
2391                    </div>
2392                </div>
2393                <div style="display:flex;flex-direction:column;align-items:center;gap:10px;margin-top:20px;">
2394                    <p style="font-size:13px;
2394color:var(--mid);margin-bottom:4px;">Open the app and sign in to use your
2395                        subscription:</p>
2396                    <a href="https://apps.apple.com/us/app/toycad/id6711330232?mt=8" target="_blank"
2397                        rel="noopener noreferrer">
2398                        <img src="img_new/appstore.png" alt="Download on App Store" style="height:44px;">
2399                    </a>
2400                    <a href="https://play.google.com/store/apps/details?id=com.toycad.app&hl=en_US" target="_blank"
2401                        rel="noopener noreferrer">
2402                        <img src="img_new/playstore.png" alt="Get it on Google Play" style="height:44px;">
2403                    </a>
2404                </div>
2405                <div style="text-align:center;margin-top:16px;">
2406                    <button onclick="handleSignOut()"
2407                        style="background:none;border:none;color:var(--mid);font-size:13px;cursor:pointer;text-decoration:underline;">Sign
2408                        out</button>
2409                </div>
2410            </div>
2411
2412        </div>
2413    </div>
2414
2415    <!-- Firebase compat SDK -->
2416    
2416<script src="https://www.gstatic.com/firebasejs/10.12.0/firebase-app-compat.js"></script>
2416
2417    
2417<script src="https://www.gstatic.com/firebasejs/10.12.0/firebase-auth-compat.js"></script>
2417
2418
2419    
2419<script>
2420        // ── Firebase init ──
2421        const firebaseConfig = {
2422            apiKey: 'AIzaSyCZgEKh22mtNd5KV3NaoDZ1Ln4HaLB6Tdg',
2423            authDomain: 'dtoymaker.firebaseapp.com',
2424            projectId: 'dtoymaker',
2425            storageBucket: 'dtoymaker.appspot.com',
2426            messagingSenderId: '659050400404',
2427            appId: '1:659050400404:web:86e7804c42d7ef87480281'
2428        };
2429        firebase.initializeApp(firebaseConfig);
2430        const auth = firebase.auth();
2431
2432        // ── State ──
2433        let currentUser = null;
2434        let selectedPlan = null; // 'lifetime' | 'yearly' | 'monthly'
2435        let authMode = 'signup'; // 'signup' | 'signin' | 'forgot'
2436        let userSubscription = null; // cached from Firestore via Cloud Function
2437
2438        const CHECKOUT_FUNCTION_URL = 'https://us-central1-dtoymaker.cloudfunctions.net/createStripeCheckoutSession';
2439        const PORTAL_FUNCTION_URL = 'https://us-central1-dtoymaker.cloudfunctions.net/createStripePortalSession';
2440
2441        // ── Auth state listener ──
2442        auth.onAuthStateChanged(async function (user) {
2443            currentUser = user;
2444            userSubscription = null;
2445            // Update nav
2446            if (user) {
2447                document.getElementById('nav-signed-out').style.display = 'none';
2448                document.getElementById('nav-signed-in').style.display = 'flex';
2449                document.getElementById('nav-user-email').textContent = user.email;
2450                await syncUserProfile(user);
2451                await fetchSubscriptionStatus();
2452            } else {
2453                document.getElementById('nav-signed-out').style.display = 'block';
2454                document.getElementById('nav-signed-in').style.display = 'none';
2455            }
2456            if (document.getElementById('sub-modal').classList.contains('active')) {
2457                updateModalForAuthState();
2458            }
2459        });
2460
2461        // ── Check URL params on load ──
2462        window.addEventListener('DOMContentLoaded', function () {
2463            const params = new URLSearchParams(window.location.search);
2464
2465            if (params.get('success') === '1') {
2466                const plan = params.get('plan') || 'subscription';
2467                const banner = document.getElementById('success-banner');
2468                banner.style.display = 'block';
2469                // Track purchase with value/currency for ROAS optimization
2470                var _purchaseValue = plan === 'lifetime' ? 71.99 : plan === 'monthly' ? 5.59 : 31.99;
2471                var _purchaseName = plan === 'lifetime' ? 'Lifetime License' : plan === 'monthly' ? 'Monthly Subscription' : 'Yearly Subscription';
2472                if (typeof fbq === 'function') {
2473                    fbq('track', 'Purchase', {
2474                        value: _purchaseValue,
2475                        currency: 'USD',
2476                        content_name: _purchaseName,
2477                        content_type: 'product'
2478                    });
2479                }
2480                if (typeof gtag === 'function') {
2481                    gtag('event', 'purchase', {
2482                        currency: 'USD',
2483                        value: _purchaseValue,
2484                        items: [{ item_name: _purchaseName, price: _purchaseValue, quantity: 1 }]
2485                    });
2486                }
2487            }
2488
2489            if (params.get('cancelled') === '1') {
2490                // Reopen modal if user had a plan selected (stored in sessionStorage)
2491                const savedPlan = sessionStorage.getItem('tcSelectedPlan');
2492                if (savedPlan) {
2493                    sessionStorage.removeItem('tcSelectedPlan');
2494                    openModal(savedPlan);
2495                    showError('Checkout was cancelled. You can try again whenever you\'re ready.');
2496                }
2497            }
2498
2499            // Reveal animation observer
2500            const observer = new IntersectionObserver(function (entries) {
2501                entries.forEach(function (e) { if (e.isIntersecting) e.target.classList.add('visible'); });
2502            }, { threshold: 0.12 });
2503            document.querySelectorAll('.reveal').forEach(function (el) { observer.observe(el); });
2504        });
2505
2506        // ── Modal open/close ──
2507        function openModal(plan, initialMode) {
2508            if (plan) selectedPlan = plan;
2509            if (initialMode) authMode = initialMode;
2510
2511            // Update plan chip
2512            if (selectedPlan) {
2513                const chipText = selectedPlan === 'lifetime' ? 'Lifetime — $71.99'
2514                    : selectedPlan === 'monthly' ? 'Monthly — $5.59/mo'
2515                        : 'Yearly — $31.99/yr';
2516                document.getElementById('modal-plan-chip-text').textContent = chipText;
2517                document.getElementById('modal-plan-chip').style.display = 'inline-flex';
2518            } else {
2519                document.getElementById('modal-plan-chip').style.display = 'none';
2520            }
2521
2522            clearError();
2523            document.getElementById('sub-modal').classList.add('active');
2524            document.body.style.overflow = 'hidden';
2525            updateModalForAuthState();
2526            // Track plan view
2527            if (plan && typeof fbq === 'function') {
2528                fbq('track', 'ViewContent', {
2529                    content_name: plan === 'lifetime' ? 'Lifetime License' : plan === 'monthly' ? 'Monthly Subscription' : 'Yearly Subscription',
2530                    content_category: 'Subscription',
2531                    value: plan === 'lifetime' ? 71.99 : plan === 'monthly' ? 5.59 : 31.99,
2532                    currency: 'USD'
2533                });
2534            }
2535        }
2536
2537        function closeModal() {
2538            document.getElementById('sub-modal').classList.remove('active');
2539            document.body.style.overflow = '';
2540        }
2541
2542        function handleModalOverlayClick(e) {
2543            if (e.target === document.getElementById('sub-modal')) closeModal();
2544        }
2545
2546        function updateModalForAuthState() {
2547            if (currentUser) {
2548                const webSub = userSubscription && userSubscription.webSubscription;
2549                const lifetime = userSubscription && userSubscription.lifetime;
2550                const hasActiveSub = (webSub && (webSub.status === 'active' || webSub.status === 'past_due'))
2551                    || (lifetime && lifetime.enabled);
2552
2553                if (hasActiveSub) {
2554                    showSubscriptionState();
2555                    return;
2556                }
2557            }
2558
2559            if (currentUser && selectedPlan) {
2560                showState('checkout');
2561                document.getElementById('checkout-user-email').textContent = currentUser.email;
2562                const isLifetime = selectedPlan === 'lifetime';
2563                const isMonthly = selectedPlan === 'monthly';
2564                document.getElementById('checkout-plan-name').textContent = isLifetime ? 'Lifetime License' : isMonthly ? 'Monthly Subscription' : 'Yearly Subscription';
2565                document.getElementById('checkout-plan-price').textContent = isLifetime ? '$71.99' : isMonthly ? '$5.59/mo' : '$31.99';
2566                document.getElementById('checkout-plan-note').textContent = isLifetime ? 'one-time · use forever' : isMonthly ? 'billed monthly · cancel any time' : 'billed annually · cancel any time';
2567            } else if (currentUser && !selectedPlan) {
2568                // Signed in, no plan, no active sub — scroll to pricing
2569                closeModal();
2570                document.querySelector('#pricing').scrollIntoView({ behavior: 'smooth' });
2571            } else {
2572                showState('auth');
2573                setAuthMode(authMode, false);
2574            }
2575        }
2576
2577        function showSubscriptionState() {
2578            showState('subscription');
2579            document.getElementById('sub-state-user-email').textContent = currentUser.email;
2580
2581            const webSub = userSubscription && userSubscription.webSubscription;
2582            const lifetime = userSubscription && userSubscription.lifetime;
2583            const isWebSub = webSub && (webSub.status === 'active' || webSub.status === 'past_due');
2584
2585            let planName, statusText, statusClass, renewsText = '';
2586
2587            if (isWebSub) {
2588                planName = webSub.plan === 'lifetime' ? 'Lifetime License' : webSub.plan === 'monthly' ? 'Monthly Subscription' : 'Yearly Subscription';
2589                if (webSub.status === 'active') { statusText = 'Active'; statusClass = 'active'; }
2590                else { statusText = 'Payment Past Due'; statusClass = 'past_due'; }
2591
2592                if ((webSub.plan === 'yearly' || webSub.plan === 'monthly') && webSub.currentPeriodEnd) {
2593                    const d = new Date(webSub.currentPeriodEnd);
2594                    renewsText = 'Renews ' + d.toLocaleDateString('en-US', { month: 'long', day: 'numeric', year: 'numeric' });
2595                } else if (webSub.plan === 'lifetime') {
2596                    renewsText = 'Never expires';
2597                }
2598                document.getElementById('sub-web-actions').style.display = 'block';
2599                document.getElementById('sub-inapp-note').style.display = 'none';
2600            } else {
2601                // In-app subscription
2602                planName = 'Lifetime License';
2603                statusText = 'Active'; statusClass = 'active';
2604                renewsText = 'Never expires';
2605                document.getElementById('sub-web-actions').style.display = 'none';
2606                document.getElementById('sub-inapp-note').style.display = 'block';
2607            }
2608
2609            const badge = document.getElementById('sub-status-badge');
2610            badge.className = 'sub-status-badge ' + statusClass;
2611            document.getElementById('sub-status-text').textContent = statusText;
2612            document.getElementById('sub-plan-name').textContent = planName;
2613            document.getElementById('sub-renews-text').textContent = renewsText;
2614        }
2615
2616        // ── Modal states ──
2617        function showState(state) {
2618            document.getElementById('modal-auth-state').style.display = state === 'auth' ? 'block' : 'none';
2619            document.getElementById('modal-checkout-state').style.display = state === 'checkout' ? 'block' : 'none';
2620            document.getElementById('modal-loading-state').style.display = state === 'loading' ? 'block' : 'none';
2621            document.getElementById('modal-success-state').style.display = state === 'success' ? 'block' : 'none';
2622            document.getElementById('modal-subscription-state').style.display = state === 'subscription' ? 'block' : 'none';
2623            clearError();
2624        }
2625
2626        // ── Auth mode switching ──
2627        function setAuthMode(mode, clearErr) {
2628            if (clearErr !== false) clearError();
2629            authMode = mode;
2630            document.getElementById('auth-signup-form').style.display = mode === 'signup' ? 'block' : 'none';
2631            document.getElementById('auth-signin-form').style.display = mode === 'signin' ? 'block' : 'none';
2632            document.getElementById('auth-forgot-form').style.display = mode === 'forgot' ? 'block' : 'none';
2633            document.getElementById('tab-signup').classList.toggle('active', mode === 'signup');
2634            document.getElementById('tab-signin').classList.toggle('active', mode === 'signin');
2635
2636            const heading = document.getElementById('auth-state-heading');
2637            if (mode === 'signup') heading.textContent = 'Create your account';
2638            else if (mode === 'signin') heading.textContent = 'Sign in to your account';
2639            else heading.textContent = 'Reset your password';
2640        }
2641
2642        // ── Auth handlers ──
2643        async function handleSignUp() {
2644            const email = document.getElementById('signup-email').value.trim();
2645            const password = document.getElementById('signup-password').value;
2646            if (!email || !password) { showError('Please enter your email and password.'); return; }
2647            if (password.length < 6) { showError('Password must be at least 6 characters.'); return; }
2648            setSubmitting(true);
2649            try {
2650                await auth.createUserWithEmailAndPassword(email, password);
2651                // Auth state listener calls syncUserProfile + updateModalForAuthState()
2652                if (typeof fbq === 'function') { fbq('track', 'CompleteRegistration'); }
2653            } catch (err) {
2654                if (err.code === 'auth/email-already-in-use') {
2655                    // Try signing in with same credentials
2656                    try {
2657                        await auth.signInWithEmailAndPassword(email, password);
2658                    } catch (_) {
2659                        showError('An account with this email already exists. Please sign in.');
2660                        setAuthMode('signin');
2661                    }
2662                } else {
2663                    showError(getAuthErrorMessage(err));
2664                }
2665            } finally {
2666                setSubmitting(false);
2667            }
2668        }
2669
2670        async function handleSignIn() {
2671            const email = document.getElementById('signin-email').value.trim();
2672            const password = document.getElementById('signin-password').value;
2673            if (!email || !password) { showError('Please enter your email and password.'); return; }
2674            setSubmitting(true);
2675            try {
2676                await auth.signInWithEmailAndPassword(email, password);
2677                if (typeof fbq === 'function') { fbq('track', 'Lead'); }
2678            } catch (err) {
2679                showError(getAuthErrorMessage(err));
2680            } finally {
2681                setSubmitting(false);
2682            }
2683        }
2684
2685        async function handleForgotPassword() {
2686            const email = document.getElementById('forgot-email').value.trim();
2687            if (!email) { showError('Please enter your email address.'); return; }
2688            setSubmitting(true);
2689            try {
2690                await auth.sendPasswordResetEmail(email);
2691                showError('Password reset email sent! Check your inbox.', 'success');
2692            } catch (err) {
2693                showError(getAuthErrorMessage(err));
2694            } finally {
2695                setSubmitting(false);
2696            }
2697        }
2698
2699        function handleSignOut() {
2700            auth.signOut();
2701        }
2702
2703        // ── Fetch subscription status directly from Firestore ──
2704        // ── Sync user profile to Firestore (matches app's syncUserAccountEntitlements) ──
2705        // Uses commit API with updateMask so webSubscription/lifetime fields are never overwritten.
2706        async function syncUserProfile(user) {
2707            try {
2708                const token = await user.getIdToken();
2709                const nowIso = new Date().toISOString();
2710                const docPath = 'projects/dtoymaker/databases/toycadusersdb/documents/users/' + user.uid;
2711                await fetch('https://firestore.googleapis.com/v1/projects/dtoymaker/databases/toycadusersdb/documents:commit', {
2712                    method: 'POST',
2713                    headers: { 'Authorization': 'Bearer ' + token, 'Content-Type': 'application/json' },
2714                    body: JSON.stringify({
2715                        writes: [
2716                            {
2717                                update: {
2718                                    name: docPath,
2719                                    fields: {
2720                                        updatedAtIso: { stringValue: nowIso },
2721                                        profile: {
2722                                            mapValue: {
2723                                                fields: {
2724                                                    uid: { stringValue: user.uid },
2725                                                    email: { stringValue: user.email || '' },
2726                                                    lastSeenAtIso: { stringValue: nowIso }
2727                                                }
2728                                            }
2729                                        },
2730                                        identity: {
2731                                            mapValue: {
2732                                                fields: {
2733                                                    revenueCatLinked: { booleanValue: false },
2734                                                    lastSyncAtIso: { stringValue: nowIso }
2735                                                }
2736                                            }
2737                                        }
2738                                    }
2739                                },
2740                                updateMask: {
2741                                    fieldPaths: [
2742                                        'updatedAtIso',
2743                                        'profile.uid', 'profile.email', 'profile.lastSeenAtIso',
2744                                        'identity.revenueCatLinked', 'identity.lastSyncAtIso'
2745                                    ]
2746                                }
2747                            },
2748                            {
2749                                transform: {
2750                                    document: docPath,
2751                                    fieldTransforms: [
2752                                        { fieldPath: 'updatedAt', setToServerValue: 'REQUEST_TIME' },
2753                                        { fieldPath: 'profile.lastSeenAt', setToServerValue: 'REQUEST_TIME' },
2754                                        { fieldPath: 'identity.lastSyncAt', setToServerValue: 'REQUEST_TIME' }
2755                                    ]
2756                                }
2757                            }
2758                        ]
2759                    })
2760                });
2761            } catch (err) {
2762                console.warn('Could not sync user profile:', err);
2763            }
2764        }
2765
2766        // ── Fetch subscription status via Firestore REST API (named database) ──
2767        async function fetchSubscriptionStatus() {
2768            if (!currentUser) return;
2769            try {
2770                const token = await currentUser.getIdToken();
2771                const url = 'https://firestore.googleapis.com/v1/projects/dtoymaker/databases/toycadusersdb/documents/users/' + currentUser.uid;
2772                const response = await fetch(url, {
2773                    headers: { 'Authorization': 'Bearer ' + token }
2774                });
2775                if (response.status === 404) {
2776                    // New user — profile will be created by syncUserProfile (called before this)
2777                    userSubscription = null;
2778                    return;
2779                }
2780                if (!response.ok) throw new Error('Firestore REST error ' + response.status);
2781                const doc = await response.json();
2782                const fields = doc.fields || {};
2783
2784                function getField(obj, key) {
2785                    return obj && obj[key] ? (obj[key].stringValue || obj[key].booleanValue || null) : null;
2786                }
2787                function getMapField(fields, key) {
2788                    return fields[key] && fields[key].mapValue ? fields[key].mapValue.fields || {} : null;
2789                }
2790
2791                const webSubFields = getMapField(fields, 'webSubscription');
2792                const lifetimeFields = getMapField(fields, 'lifetime');
2793
2794                userSubscription = {
2795                    webSubscription: webSubFields ? {
2796                        plan: getField(webSubFields, 'plan'),
2797                        status: getField(webSubFields, 'status'),
2798                        currentPeriodEnd: getField(webSubFields, 'currentPeriodEnd')
2799                    } : null,
2800                    lifetime: lifetimeFields ? {
2801                        enabled: getField(lifetimeFields, 'enabled') === true || lifetimeFields.enabled && lifetimeFields.enabled.booleanValue === true,
2802                        source: getField(lifetimeFields, 'source')
2803                    } : null
2804                };
2805            } catch (err) {
2806                console.warn('Could not fetch subscription status:', err);
2807                userSubscription = null;
2808            }
2809        }
2810
2811        // ── Open Stripe Customer Portal ──
2812        async function handleManageSubscription() {
2813            const btn = document.getElementById('manage-sub-btn');
2814            if (btn) { btn.disabled = true; btn.textContent = 'Opening…'; }
2815            try {
2816                const token = await currentUser.getIdToken();
2817                const response = await fetch(PORTAL_FUNCTION_URL, {
2818                    method: 'POST',
2819                    headers: {
2820                        'Content-Type': 'application/json',
2821                        'Authorization': 'Bearer ' + token
2822                    }
2823                });
2824                if (!response.ok) {
2825                    const errData = await response.json().catch(function () { return {}; });
2826                    throw new Error(errData.error || 'Could not open billing portal.');
2827                }
2828                const data = await response.json();
2829                if (data.url) {
2830                    window.open(data.url, '_blank', 'noopener,noreferrer');
2831                }
2832            } catch (err) {
2833                showError(err.message || 'Could not open billing portal. Please try again.');
2834            } finally {
2835                if (btn) { btn.disabled = false; btn.textContent = 'Manage Subscription →'; }
2836            }
2837        }
2838
2839        // ── Stripe Checkout ──
2840        async function handleCheckout() {
2841            if (!currentUser || !selectedPlan) return;
2842
2843            showState('loading');
2844            sessionStorage.setItem('tcSelectedPlan', selectedPlan);
2845
2846            // Track checkout initiation
2847            var _checkoutValue = selectedPlan === 'lifetime' ? 71.99 : selectedPlan === 'monthly' ? 5.59 : 31.99;
2848            var _checkoutName = selectedPlan === 'lifetime' ? 'Lifetime License' : selectedPlan === 'monthly' ? 'Monthly Subscription' : 'Yearly Subscription';
2849            if (typeof fbq === 'function') {
2850                fbq('track', 'InitiateCheckout', {
2851                    value: _checkoutValue,
2852                    currency: 'USD',
2853                    num_items: 1,
2854                    content_name: _checkoutName
2855                });
2856            }
2857            if (typeof gtag === 'function') {
2858                gtag('event', 'begin_checkout', {
2859                    currency: 'USD',
2860                    value: _checkoutValue,
2861                    items: [{ item_name: _checkoutName, price: _checkoutValue, quantity: 1 }]
2862                });
2863            }
2864
2865            const priceId = selectedPlan === 'lifetime'
2866                ? 'price_1TVx6uAhAiOWG0pLmEGow064'
2867                : selectedPlan === 'monthly'
2868                    ? 'price_1Tcq7uAhAiOWG0pLn6hPHUM3'
2869                    : 'price_1TVx8IAhAiOWG0pLCx4lEkAt';
2870
2871            try {
2872                const token = await currentUser.getIdToken();
2873                // Include Rewardful referral ID if present (for affiliate tracking)
2874                var _referral = (window.Rewardful && window.Rewardful.referral) || null;
2875                const response = await fetch(CHECKOUT_FUNCTION_URL, {
2876                    method: 'POST',
2877                    headers: {
2878                        'Content-Type': 'application/json',
2879                        'Authorization': 'Bearer ' + token
2880                    },
2881                    body: JSON.stringify({
2882                        priceId: priceId,
2883                        plan: selectedPlan,
2884                        uid: currentUser.uid,
2885                        email: currentUser.email,
2886                        referral: _referral
2887                    })
2888                });
2889
2890                if (!response.ok) {
2891                    const errData = await response.json().catch(function () { return {}; });
2892                    throw new Error(errData.error || 'Server error. Please try again.');
2893                }
2894
2895                const data = await response.json();
2896                if (data.url) {
2897                    window.location.href = data.url;
2898                } else {
2899                    throw new Error('Invalid response from server.');
2900                }
2901            } catch (err) {
2902                console.error('Checkout error:', err);
2903                showState('checkout');
2904                showError('Could not start checkout: ' + (err.message || 'Please try again.'));
2905            }
2906        }
2907
2908        // ── Helpers ──
2909        function showError(msg, type) {
2910            const el = document.getElementById('modal-error');
2911            el.textContent = msg;
2912            el.style.display = 'block';
2913            if (type === 'success') {
2914                el.classList.add('success-msg');
2915            } else {
2916                el.classList.remove('success-msg');
2917            }
2918        }
2919
2920        function clearError() {
2921            const el = document.getElementById('modal-error');
2922            el.style.display = 'none';
2923            el.textContent = '';
2924        }
2925
2926        function setSubmitting(loading) {
2927            ['signup-btn', 'signin-btn', 'forgot-btn'].forEach(function (id) {
2928                const btn = document.getElementById(id);
2929                if (btn) btn.disabled = loading;
2930            });
2931        }
2932
2933        function getAuthErrorMessage(err) {
2934            switch (err.code) {
2935                case 'auth/invalid-email': return 'Invalid email address.';
2936                case 'auth/user-not-found': return 'No account found with this email. Please sign up.';
2937                case 'auth/wrong-password': return 'Incorrect password. Try again or reset your password.';
2938                case 'auth/too-many-requests': return 'Too many attempts. Please wait a few minutes and try again.';
2939                case 'auth/weak-password': return 'Password must be at least 6 characters.';
2940                case 'auth/network-request-failed': return 'Network error. Please check your connection.';
2941                default: return err.message || 'An error occurred. Please try again.';
2942            }
2943        }
2944
2945        function toggleFaq(btn) {
2946            const item = btn.parentElement;
2947            const isOpen = item.classList.contains('open');
2948            document.querySelectorAll('.faq-item').forEach(function (i) { i.classList.remove('open'); });
2949            if (!isOpen) item.classList.add('open');
2950        }
2951    </script>
2951
2952
2953    
2953<script>
2954        (function () {
2955            const slider = document.getElementById('heroSlider');
2956            if (!slider) return;
2957            const slidesEl = slider.querySelector('.slides');
2958            const prevBtn = document.getElementById('sliderPrev');
2959            const nextBtn = document.getElementById('sliderNext');
2960            const introVideo = document.getElementById('heroIntroVideo');
2961            const slideCount = slidesEl.children.length;
2962            let index = 0;
2963            let timer = null;
2964
2965            function syncIntroVideo() {
2966                if (!introVideo) return;
2967                if (index === 1) {
2968                    introVideo.controls = true;
2969                    introVideo.muted = true;
2970                    const playPromise = introVideo.play();
2971                    if (playPromise && typeof playPromise.catch === 'function') {
2972                        playPromise.catch(function () { });
2973                    }
2974                } else {
2975                    introVideo.controls = false;
2976                    introVideo.pause();
2977                }
2978            }
2979
2980            function goTo(i) {
2981                index = (i + slideCount) % slideCount;
2982                slidesEl.style.transform = 'translateX(' + (-index * 100) + '%)';
2983                syncIntroVideo();
2984                if (timer) resetTimer();
2985            }
2986
2987            function next() { goTo(index + 1); }
2988            function prev() { goTo(index - 1); }
2989
2990            prevBtn.addEventListener('click', function () { prev(); resetTimer(); });
2991            nextBtn.addEventListener('click', function () { next(); resetTimer(); });
2992
2993            function getCurrentIntervalMs() { return index === 1 ? 15000 : 3000; }
2994
2995            function startTimer() {
2996                if (shouldPauseCarousel()) return;
2997                timer = setInterval(next, getCurrentIntervalMs());
2998            }
2999
3000            function pauseTimer() {
3001                if (timer) { clearInterval(timer); timer = null; }
3002            }
3003
3004            function resetTimer() { pauseTimer(); startTimer(); }
3005
3006            function isIntroVideoUnmutedOnActiveSlide() {
3007                return !!introVideo && index === 1 && !introVideo.muted;
3008            }
3009
3010            function shouldPauseCarousel() {
3011                return isIntroVideoFullscreen() || isIntroVideoUnmutedOnActiveSlide();
3012            }
3013
3014            function isIntroVideoFullscreen() {
3015                return document.fullscreenElement === introVideo
3016                    || document.webkitFullscreenElement === introVideo
3017                    || document.msFullscreenElement === introVideo;
3018            }
3019
3020            function handleFullscreenChange() {
3021                if (!introVideo) return;
3022                if (shouldPauseCarousel()) { pauseTimer(); }
3023                else if (!timer) { startTimer(); }
3024            }
3025
3026            document.addEventListener('fullscreenchange', handleFullscreenChange);
3027            document.addEventListener('webkitfullscreenchange', handleFullscreenChange);
3028            document.addEventListener('MSFullscreenChange', handleFullscreenChange);
3029
3030            if (introVideo) {
3031                introVideo.addEventListener('volumechange', handleFullscreenChange);
3032            }
3033
3034            (function addSwipeHandlers() {
3035                let startX = 0;
3036                let deltaX = 0;
3037                let pointerDown = false;
3038                const threshold = 50;
3039
3040                function handleSwipeEnd() {
3041                    if (Math.abs(deltaX) > threshold) {
3042                        if (deltaX < 0) next(); else prev();
3043                        resetTimer();
3044                    }
3045                    deltaX = 0; startX = 0; pointerDown = false;
3046                }
3047
3048                function onTouchStart(e) { if (!e.touches || !e.touches.length) return; startX = e.touches[0].clientX; deltaX = 0; }
3049                function onTouchMove(e) { if (!e.touches || !e.touches.length) return; deltaX = e.touches[0].clientX - startX; }
3050                function onTouchEnd() { handleSwipeEnd(); }
3051
3052                function onPointerDown(e) { pointerDown = true; startX = e.clientX; deltaX = 0; if (slider.setPointerCapture) try { slider.setPointerCapture(e.pointerId); } catch (_) { } }
3053                function onPointerMove(e) { if (!pointerDown) return; deltaX = e.clientX - startX; }
3054                function onPointerUp(e) { if (pointerDown) handleSwipeEnd(); try { slider.releasePointerCapture && slider.releasePointerCapture(e.pointerId); } catch (_) { } }
3055
3056                slidesEl.addEventListener('touchstart', onTouchStart, { passive: true });
3057                slidesEl.addEventListener('touchmove', onTouchMove, { passive: true });
3058                slidesEl.addEventListener('touchend', onTouchEnd);
3059                slidesEl.addEventListener('pointerdown', onPointerDown);
3060                slidesEl.addEventListener('pointermove', onPointerMove);
3061                slidesEl.addEventListener('pointerup', onPointerUp);
3062                slidesEl.addEventListener('pointercancel', onPointerUp);
3063            })();
3064
3065            goTo(0);
3066            startTimer();
3067        })();
3068    </script>
3068
3069</body>
3070
3071</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.