{"id":1860,"date":"2025-06-26T22:01:38","date_gmt":"2025-06-26T16:31:38","guid":{"rendered":"https:\/\/devenv1.golfai.in\/golf-library\/"},"modified":"2026-06-10T15:25:15","modified_gmt":"2026-06-10T09:55:15","slug":"golf-library","status":"publish","type":"page","link":"https:\/\/devenv1.golfai.in\/hi\/golf-library\/","title":{"rendered":"\u090f\u0906\u0908 \u0938\u094d\u0935\u093f\u0902\u0917 \u0935\u093f\u0936\u094d\u0932\u0947\u0937\u0923"},"content":{"rendered":"            <!-- Unified inlined CSS -->\n            <style>\n            @import url('https:\/\/fonts.googleapis.com\/css2?family=Plus+Jakarta+Sans:wght@400;500;600;700&family=Poppins:wght@400;500;600;700&display=swap');\n\n            :root {\n                --pomelise-green: #2cc374;\n                --pomelise-green-hover: #23a661;\n                --pomelise-white: #f8f8f4;\n                --pomelise-black: #000000;\n                --pomelise-yellow: #f8bc20;\n                --pomelise-gray-green: #c9dbcf;\n                --pomelise-dark-gray: #1f2937;\n                --pomelise-light-gray: #f3f4f6;\n                --pomelise-border: #e5e7eb;\n\n                \/* AI Standalone variables *\/\n                --bg: #f2f5ec;\n                --surface: #ffffff;\n                --ink: #13180f;\n                --ink-2: #3a423a;\n                --muted: #737d72;\n                --faint: #9aa49a;\n                --green: #2cc374;\n                --green-d: #23a661;\n                --green-soft: #e7f4ec;\n                --line: #e7eae1;\n                --line-2: #eef1ea;\n                --search: #ebeee7;\n                --shadow: 0 1px 2px rgba(20,30,15,.04), 0 8px 24px rgba(20,30,15,.05);\n                --shadow-lg: 0 12px 40px rgba(20,30,15,.14);\n                --r: 16px;\n            }\n\n            #golf-library-root {\n                font-family: 'Poppins', 'Plus Jakarta Sans', -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\n                color: var(--pomelise-dark-gray);\n                background-color: var(--pomelise-white);\n                min-height: 100vh;\n                padding: 0;\n                margin: 0;\n            }\n\n            \/* Authentication Screen *\/\n            .auth-container {\n                display: flex;\n                justify-content: center;\n                align-items: center;\n                min-height: 80vh;\n                padding: 20px;\n            }\n\n            .auth-card {\n                background: #ffffff;\n                border: 1px solid var(--pomelise-border);\n                border-radius: 24px;\n                padding: 48px;\n                max-width: 480px;\n                width: 100%;\n                text-align: center;\n                box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.05), 0 8px 10px -6px rgba(0, 0, 0, 0.05);\n            }\n\n            .auth-logo {\n                font-size: 32px;\n                font-weight: 700;\n                color: var(--pomelise-green);\n                margin-bottom: 24px;\n            }\n\n            .auth-title {\n                font-size: 24px;\n                font-weight: 700;\n                color: var(--pomelise-black);\n                margin-bottom: 12px;\n                line-height: 1.25;\n            }\n\n            .auth-subtitle {\n                font-size: 14px;\n                color: #6b7280;\n                margin-bottom: 32px;\n                line-height: 1.6;\n            }\n\n            .auth-error {\n                background-color: #fef2f2;\n                border: 1px solid #fca5a5;\n                color: #b91c1c;\n                padding: 12px;\n                border-radius: 12px;\n                font-size: 14px;\n                margin-bottom: 20px;\n            }\n\n            .auth-btn-wrapper {\n                display: flex;\n                justify-content: center;\n                margin-top: 20px;\n            }\n\n            \/* Layout and Header *\/\n            .library-layout {\n                max-width: 1280px;\n                margin: 0 auto;\n                padding: 40px 24px;\n            }\n\n            .library-header {\n                margin-bottom: 40px;\n                border-bottom: 1px solid var(--pomelise-border);\n                padding-bottom: 24px;\n            }\n\n            .library-header-content {\n                display: flex;\n                justify-content: space-between;\n                align-items: center;\n                flex-wrap: wrap;\n                gap: 16px;\n            }\n\n            .library-title {\n                font-size: 32px;\n                font-weight: 700;\n                color: var(--pomelise-black);\n                margin: 0;\n            }\n\n            .header-actions {\n                display: flex;\n                align-items: center;\n                gap: 16px;\n            }\n\n            .user-profile-badge {\n                display: flex;\n                align-items: center;\n                gap: 8px;\n                background: #ffffff;\n                border: 1px solid var(--pomelise-border);\n                padding: 6px 14px;\n                border-radius: 100px;\n                font-size: 14px;\n                font-weight: 500;\n            }\n\n            .user-profile-badge img {\n                width: 28px;\n                height: 28px;\n                border-radius: 50%;\n                object-fit: cover;\n            }\n\n            .nav-upload-btn, .submit-upload-btn {\n                display: inline-flex;\n                align-items: center;\n                gap: 8px;\n                background-color: var(--pomelise-green);\n                color: #ffffff !important;\n                font-weight: 600;\n                padding: 12px 24px;\n                border-radius: 100px;\n                border: none;\n                cursor: pointer;\n                box-shadow: 0 4px 14px 0 rgba(44, 195, 116, 0.3);\n                transition: all 0.2s ease;\n            }\n\n            .nav-upload-btn:hover, .submit-upload-btn:hover {\n                background-color: var(--pomelise-green-hover);\n                transform: translateY(-1px);\n                box-shadow: 0 6px 20px 0 rgba(44, 195, 116, 0.4);\n            }\n\n            .submit-upload-btn {\n                width: 100%;\n                justify-content: center;\n                border-radius: 16px;\n                padding: 16px;\n                font-size: 16px;\n            }\n\n            \/* Filters & Search *\/\n            .filters-wrapper {\n                display: flex;\n                flex-direction: column;\n                gap: 20px;\n                margin-bottom: 32px;\n            }\n\n            .search-box {\n                display: flex;\n                align-items: center;\n                position: relative;\n                width: 100%;\n            }\n\n            .search-box svg {\n                position: absolute;\n                left: 16px;\n                color: #9ca3af;\n            }\n\n            .search-box input {\n                width: 100%;\n                padding: 14px 16px 14px 48px;\n                border: 1px solid var(--pomelise-border);\n                border-radius: 16px;\n                background-color: #ffffff;\n                font-size: 16px;\n                transition: all 0.2s ease;\n            }\n\n            .search-box input:focus {\n                outline: none;\n                border-color: var(--pomelise-green);\n                box-shadow: 0 0 0 4px rgba(44, 195, 116, 0.1);\n            }\n\n            .coach-filter-bar {\n                display: flex;\n                flex-wrap: wrap;\n                gap: 8px;\n            }\n\n            .coach-filter-tab {\n                background-color: #ffffff;\n                border: 1px solid var(--pomelise-border);\n                color: #4b5563;\n                padding: 8px 18px;\n                border-radius: 100px;\n                font-weight: 500;\n                cursor: pointer;\n                transition: all 0.2s ease;\n            }\n\n            .coach-filter-tab:hover {\n                border-color: var(--pomelise-green);\n                color: var(--pomelise-green);\n                background-color: rgba(44, 195, 116, 0.02);\n            }\n\n            .coach-filter-tab.active {\n                background-color: var(--pomelise-green);\n                border-color: var(--pomelise-green);\n                color: #ffffff;\n                box-shadow: 0 4px 10px rgba(44, 195, 116, 0.2);\n            }\n\n            \/* Video Grid and Cards *\/\n            .video-grid {\n                display: grid;\n                grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));\n                gap: 24px;\n            }\n\n            .video-card {\n                background-color: #ffffff;\n                border: 1px solid var(--pomelise-border);\n                border-radius: 20px;\n                overflow: hidden;\n                cursor: pointer;\n                transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n            }\n\n            .video-card:hover {\n                transform: translateY(-4px);\n                box-shadow: 0 12px 20px -8px rgba(0, 0, 0, 0.08), 0 4px 12px -2px rgba(0, 0, 0, 0.03);\n                border-color: var(--pomelise-green);\n            }\n\n            .demo-video-card {\n                border: 2px solid var(--pomelise-green) !important;\n                box-shadow: 0 4px 12px rgba(44, 195, 116, 0.15) !important;\n                position: relative;\n            }\n            \n            .demo-video-card:hover {\n                box-shadow: 0 12px 24px rgba(44, 195, 116, 0.25) !important;\n            }\n\n            .demo-badge {\n                position: absolute;\n                top: 12px;\n                left: 12px;\n                background-color: var(--pomelise-green);\n                color: #ffffff;\n                font-size: 11px;\n                font-weight: 700;\n                text-transform: uppercase;\n                padding: 4px 10px;\n                border-radius: 12px;\n                letter-spacing: 0.5px;\n                box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);\n                z-index: 5;\n            }\n\n            .empty-placeholder-card {\n                display: flex;\n                flex-direction: column;\n                justify-content: center;\n                align-items: center;\n                padding: 32px 24px;\n                border: 2px dashed var(--pomelise-border);\n                border-radius: 20px;\n                background-color: rgba(0, 0, 0, 0.01);\n                text-align: center;\n                min-height: 280px;\n                transition: all 0.3s ease;\n            }\n\n            .empty-placeholder-card:hover {\n                border-color: var(--pomelise-green);\n                background-color: rgba(44, 195, 116, 0.02);\n            }\n\n            .ep-icon {\n                font-size: 40px;\n                margin-bottom: 16px;\n            }\n\n            .ep-text {\n                font-size: 14px;\n                color: var(--pomelise-black);\n                font-weight: 500;\n                line-height: 1.5;\n                margin: 0;\n            }\n\n            .video-thumbnail-wrapper {\n                position: relative;\n                height: 180px;\n                background-color: #000;\n            }\n\n            .video-thumbnail {\n                width: 100%;\n                height: 100%;\n                object-fit: cover;\n                opacity: 0.9;\n                transition: opacity 0.2s ease;\n            }\n\n            .video-card:hover .video-thumbnail {\n                opacity: 0.8;\n            }\n\n            .video-play-overlay {\n                position: absolute;\n                top: 50%;\n                left: 50%;\n                transform: translate(-50%, -50%) scale(0.9);\n                background-color: rgba(255, 255, 255, 0.9);\n                color: var(--pomelise-black);\n                width: 48px;\n                height: 48px;\n                border-radius: 50%;\n                display: flex;\n                justify-content: center;\n                align-items: center;\n                opacity: 0;\n                transition: all 0.2s ease;\n            }\n\n            .video-card:hover .video-play-overlay {\n                opacity: 1;\n                transform: translate(-50%, -50%) scale(1);\n            }\n\n            .video-duration-badge {\n                position: absolute;\n                bottom: 12px;\n                right: 12px;\n                background-color: rgba(0, 0, 0, 0.75);\n                color: #ffffff;\n                padding: 4px 8px;\n                border-radius: 6px;\n                font-size: 11px;\n                font-weight: 500;\n                display: flex;\n                align-items: center;\n                gap: 4px;\n            }\n\n            .video-card-info {\n                padding: 16px;\n            }\n\n            .video-card-title {\n                font-size: 16px;\n                font-weight: 600;\n                color: var(--pomelise-black);\n                margin: 0 0 8px 0;\n                white-space: nowrap;\n                overflow: hidden;\n                text-overflow: ellipsis;\n            }\n\n            .video-card-meta {\n                display: flex;\n                justify-content: space-between;\n                font-size: 12px;\n                color: #6b7280;\n            }\n\n            .video-card-meta span {\n                display: flex;\n                align-items: center;\n                gap: 4px;\n            }\n\n            \/* Empty & Loading States *\/\n            .empty-state, .loading-state {\n                text-align: center;\n                padding: 80px 24px;\n                background-color: #ffffff;\n                border: 1px dashed var(--pomelise-border);\n                border-radius: 24px;\n            }\n\n            .empty-icon {\n                font-size: 48px;\n                margin-bottom: 16px;\n            }\n\n            .empty-title {\n                font-size: 18px;\n                font-weight: 600;\n                margin: 0 0 6px 0;\n                color: var(--pomelise-black);\n            }\n\n            .empty-sub {\n                font-size: 14px;\n                color: #6b7280;\n                margin: 0;\n            }\n\n            .loading-state {\n                display: flex;\n                flex-direction: column;\n                justify-content: center;\n                align-items: center;\n                gap: 16px;\n                font-weight: 500;\n                color: #6b7280;\n            }\n\n            .golf-loading-spinner {\n                width: 32px;\n                height: 32px;\n                border: 3px solid rgba(44, 195, 116, 0.1);\n                border-top: 3px solid var(--pomelise-green);\n                border-radius: 50%;\n                animation: spinner-spin 0.8s linear infinite;\n            }\n\n            @keyframes spinner-spin {\n                0% { transform: rotate(0deg); }\n                100% { transform: rotate(360deg); }\n            }\n\n            \/* Video Uploader Form *\/\n            .uploader-wrapper {\n                max-width: 680px;\n                margin: 0 auto;\n                background-color: #ffffff;\n                border: 1px solid var(--pomelise-border);\n                border-radius: 24px;\n                padding: 32px;\n                box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.05);\n            }\n\n            .uploader-header {\n                display: flex;\n                flex-direction: column;\n                gap: 12px;\n                margin-bottom: 28px;\n            }\n\n            .back-btn {\n                display: inline-flex;\n                align-items: center;\n                gap: 6px;\n                background: none;\n                border: none;\n                color: #4b5563;\n                font-weight: 500;\n                cursor: pointer;\n                padding: 0;\n                align-self: flex-start;\n            }\n\n            .back-btn:hover {\n                color: var(--pomelise-green);\n            }\n\n            .uploader-title {\n                font-size: 24px;\n                font-weight: 700;\n                color: var(--pomelise-black);\n                margin: 0;\n            }\n\n            .uploader-form {\n                display: flex;\n                flex-direction: column;\n                gap: 20px;\n            }\n\n            .upload-error-banner {\n                background-color: #fef2f2;\n                border: 1px solid #fca5a5;\n                color: #b91c1c;\n                padding: 12px 16px;\n                border-radius: 12px;\n                font-size: 14px;\n                font-weight: 500;\n            }\n\n            .drag-drop-area {\n                border: 2px dashed #d1d5db;\n                background-color: #fafaf9;\n                border-radius: 16px;\n                padding: 40px 24px;\n                text-align: center;\n                cursor: pointer;\n                transition: all 0.2s ease;\n            }\n\n            .drag-drop-area:hover, .drag-drop-area.has-file {\n                border-color: var(--pomelise-green);\n                background-color: rgba(44, 195, 116, 0.01);\n            }\n\n            .upload-icon {\n                font-size: 40px;\n                margin-bottom: 12px;\n            }\n\n            .upload-text-main {\n                font-size: 16px;\n                font-weight: 600;\n                color: #374151;\n                margin: 0 0 6px 0;\n            }\n\n            .upload-text-sub {\n                font-size: 12px;\n                color: #6b7280;\n                margin: 0;\n            }\n\n            .upload-fields {\n                display: flex;\n                flex-direction: column;\n                gap: 16px;\n            }\n\n            .input-group {\n                display: flex;\n                flex-direction: column;\n                gap: 6px;\n            }\n\n            .input-group label {\n                font-size: 14px;\n                font-weight: 600;\n                color: #374151;\n            }\n\n            .input-group input, .input-group select, .input-group textarea {\n                padding: 12px;\n                border: 1px solid var(--pomelise-border);\n                border-radius: 12px;\n                font-size: 15px;\n                background-color: #ffffff;\n                transition: border-color 0.2s ease;\n            }\n\n            .input-group input:focus, .input-group select:focus, .input-group textarea:focus {\n                outline: none;\n                border-color: var(--pomelise-green);\n            }\n\n            \/* Upload Progress Bar *\/\n            .progress-bar-container {\n                background-color: var(--pomelise-light-gray);\n                border-radius: 100px;\n                height: 24px;\n                position: relative;\n                overflow: hidden;\n                margin-top: 10px;\n            }\n\n            .progress-bar-fill {\n                background-color: var(--pomelise-green);\n                height: 100%;\n                border-radius: 100px;\n                transition: width 0.3s ease;\n            }\n\n            .progress-text {\n                position: absolute;\n                top: 50%;\n                left: 50%;\n                transform: translate(-50%, -50%);\n                font-size: 12px;\n                font-weight: 600;\n                color: var(--pomelise-black);\n            }\n\n            \/* Video Player Modal *\/\n            .video-modal-overlay {\n                position: fixed;\n                top: 0; left: 0; right: 0; bottom: 0;\n                background-color: rgba(0, 0, 0, 0.75);\n                display: flex;\n                justify-content: center;\n                align-items: center;\n                z-index: 99999;\n                padding: 24px;\n                backdrop-filter: blur(4px);\n            }\n\n            .video-modal-container {\n                background-color: #ffffff;\n                border-radius: 24px;\n                max-width: 680px;\n                width: 100%;\n                max-height: 95vh;\n                display: flex;\n                flex-direction: column;\n                overflow: hidden;\n                position: relative;\n                box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);\n            }\n\n            .modal-close-btn {\n                position: absolute;\n                top: 16px;\n                right: 16px;\n                background-color: rgba(0, 0, 0, 0.5);\n                color: #ffffff;\n                border: none;\n                width: 36px;\n                height: 36px;\n                border-radius: 50%;\n                font-size: 18px;\n                cursor: pointer;\n                display: flex;\n                justify-content: center;\n                align-items: center;\n                transition: background-color 0.2s ease;\n                z-index: 10;\n            }\n\n            .modal-close-btn:hover {\n                background-color: rgba(0, 0, 0, 0.8);\n            }\n\n            .modal-video-title {\n                font-size: 20px;\n                font-weight: 700;\n                color: var(--pomelise-black);\n                margin: 0;\n                padding: 24px 64px 16px 24px;\n                border-bottom: 1px solid var(--pomelise-border);\n                flex-shrink: 0;\n            }\n\n            .modal-video-player-wrapper {\n                background-color: #000000;\n                display: flex;\n                justify-content: center;\n                align-items: center;\n                flex: 1 1 auto;\n                min-height: 0;\n                overflow: hidden;\n            }\n\n            .modal-preview-video-player {\n                max-width: 100%;\n                max-height: 60vh;\n                width: auto;\n                height: auto;\n                display: block;\n            }\n\n            .modal-video-player {\n                width: 100%;\n                max-height: 450px;\n                background-color: #000;\n                display: block;\n            }\n\n            .modal-video-meta {\n                padding: 20px 24px;\n                font-size: 14px;\n                color: #4b5563;\n                display: flex;\n                flex-direction: column;\n                gap: 8px;\n                flex-shrink: 0;\n                overflow-y: auto;\n            }\n\n            .modal-video-meta p {\n                margin: 0;\n            }\n\n            .modal-video-desc {\n                background-color: var(--pomelise-light-gray);\n                padding: 12px 16px;\n                border-radius: 12px;\n                margin-top: 8px !important;\n                font-size: 13px;\n                line-height: 1.5;\n            }\n\n            \/* ============ NEW AI RUN & ANALYSIS STYLING ============ *\/\n            .card-sep {\n                height: 1px;\n                background: #f3f4f6;\n                margin: 15px 0 10px;\n            }\n\n            .ai-a {\n                display: flex;\n                align-items: center;\n                justify-content: center;\n                gap: 9px;\n                width: 100%;\n                background: var(--green);\n                color: #fff !important;\n                border-radius: 11px;\n                padding: 12px;\n                font-size: 15px;\n                font-weight: 600;\n                transition: .16s;\n                border: none;\n                cursor: pointer;\n            }\n            .ai-a:hover {\n                background: var(--green-d);\n            }\n            .ai-a svg.sparkle {\n                width: 18px;\n                height: 18px;\n                color: #fff;\n            }\n\n            \/* ============ LOADING OVERLAY ============ *\/\n            .overlay {\n                position: fixed;\n                inset: 0;\n                z-index: 99999;\n                display: none;\n                align-items: center;\n                justify-content: center;\n                background: rgba(18, 24, 16, 0.45);\n                backdrop-filter: blur(6px);\n            }\n            .overlay.show {\n                display: flex;\n                animation: fade .2s ease;\n            }\n            @keyframes fade { from { opacity: 0 } to { opacity: 1 } }\n\n            .load-card {\n                background: var(--surface);\n                border-radius: 22px;\n                padding: 38px 40px;\n                width: 440px;\n                max-width: 92vw;\n                box-shadow: var(--shadow-lg);\n                text-align: left;\n            }\n            .scan {\n                position: relative;\n                width: 100%;\n                height: 150px;\n                border-radius: 14px;\n                overflow: hidden;\n                margin-bottom: 26px;\n                background: linear-gradient(135deg, #10160f, #1d2a1c);\n            }\n            .scan .grid-bg {\n                position: absolute;\n                inset: 0;\n                background-image: linear-gradient(rgba(26, 168, 90, .16) 1px, transparent 1px), linear-gradient(90deg, rgba(26, 168, 90, .16) 1px, transparent 1px);\n                background-size: 26px 26px;\n            }\n            .scan .beam {\n                position: absolute;\n                top: 0;\n                left: 0;\n                width: 100%;\n                height: 38px;\n                background: linear-gradient(180deg, rgba(26, 168, 90, 0), rgba(26, 168, 90, .55), rgba(26, 168, 90, 0));\n                animation: beam 1.5s ease-in-out infinite;\n            }\n            @keyframes beam { 0% { top: -40px } 100% { top: 150px } }\n            .scan .dot {\n                position: absolute;\n                width: 9px;\n                height: 9px;\n                border-radius: 50%;\n                background: #5fe39b;\n                box-shadow: 0 0 12px #5fe39b;\n            }\n\n            .load-card h2 {\n                font-size: 21px;\n                font-weight: 600;\n                margin: 0 0 4px;\n                color: #13180f;\n            }\n            .load-card p {\n                font-size: 14.5px;\n                color: var(--muted);\n                margin: 0 0 22px;\n            }\n            .steps {\n                display: flex;\n                flex-direction: column;\n                gap: 13px;\n            }\n            .step {\n                display: flex;\n                align-items: center;\n                gap: 12px;\n                font-size: 15px;\n                color: var(--faint);\n                transition: .3s;\n            }\n            .step .ic {\n                width: 22px;\n                height: 22px;\n                border-radius: 50%;\n                border: 2px solid var(--line);\n                display: flex;\n                align-items: center;\n                justify-content: center;\n                flex: none;\n                transition: .3s;\n            }\n            .step .ic svg {\n                width: 12px;\n                height: 12px;\n                opacity: 0;\n                transition: .2s;\n                fill: none;\n                stroke: currentColor;\n                stroke-width: 3;\n                stroke-linecap: round;\n                stroke-linejoin: round;\n            }\n            .step.active {\n                color: var(--ink);\n            }\n            .step.active .ic {\n                border-color: var(--green);\n            }\n            .step.done {\n                color: var(--ink-2);\n            }\n            .step.done .ic {\n                background: var(--green);\n                border-color: var(--green);\n            }\n            .step.done .ic svg {\n                opacity: 1;\n                color: #fff;\n            }\n\n            .pbar {\n                height: 6px;\n                background: var(--line-2);\n                border-radius: 999px;\n                margin-top: 24px;\n                overflow: hidden;\n            }\n            .pbar i {\n                display: block;\n                height: 100%;\n                width: 0;\n                background: var(--green);\n                border-radius: 999px;\n                transition: width .4s ease;\n            }\n\n            \/* ============ ANALYSIS VIEW ============ *\/\n            .an-top {\n                display: flex;\n                align-items: center;\n                justify-content: space-between;\n                gap: 20px;\n                padding: 22px 0;\n                border-bottom: 1px solid var(--line);\n            }\n            .back {\n                display: flex;\n                align-items: center;\n                gap: 10px;\n                font-size: 16px;\n                font-weight: 500;\n                color: var(--ink-2);\n                padding: 10px 16px;\n                border-radius: 10px;\n                transition: .14s;\n                border: none;\n                background: none;\n                cursor: pointer;\n            }\n            .back:hover {\n                background: #e9ece3;\n            }\n            .back svg {\n                width: 18px;\n                height: 18px;\n            }\n            .an-title {\n                display: flex;\n                flex-direction: column;\n                gap: 3px;\n                flex: 1;\n                margin-left: 6px;\n            }\n            .an-title b {\n                font-size: 18px;\n                font-weight: 600;\n                letter-spacing: -.01em;\n                color: #13180f;\n            }\n            .an-title span {\n                font-size: 13.5px;\n                color: var(--muted);\n            }\n\n            .an-body {\n                display: grid;\n                grid-template-columns: 1.32fr .9fr;\n                gap: 26px;\n                padding: 26px 0 60px;\n                align-items: start;\n            }\n\n            .stage {\n                background: #0c100c;\n                border-radius: 18px;\n                overflow: hidden;\n                border: 1px solid #1c241b;\n                box-shadow: var(--shadow);\n            }\n            .video-area {\n                position: relative;\n                aspect-ratio: 16\/10;\n                background: #0c100c;\n            }\n\n            .badge {\n                position: absolute;\n                top: 14px;\n                left: 14px;\n                display: flex;\n                align-items: center;\n                gap: 8px;\n                background: rgba(12, 16, 12, .7);\n                backdrop-filter: blur(4px);\n                border: 1px solid rgba(95, 227, 155, .3);\n                color: #bdf3d4;\n                border-radius: 999px;\n                padding: 7px 14px;\n                font-size: 12.5px;\n                font-weight: 600;\n                font-family: monospace;\n                z-index: 4;\n            }\n            .badge .pulse {\n                width: 8px;\n                height: 8px;\n                border-radius: 50%;\n                background: #5fe39b;\n                animation: pulse 1.2s infinite;\n            }\n            @keyframes pulse { 0%, 100% { opacity: 1 } 50% { opacity: .3 } }\n\n            .panel {\n                display: flex;\n                flex-direction: column;\n                gap: 18px;\n            }\n            .pcard {\n                background: var(--surface);\n                border: 1px solid var(--line);\n                border-radius: 16px;\n                box-shadow: var(--shadow);\n                overflow: hidden;\n            }\n            .pcard .ph {\n                display: flex;\n                align-items: center;\n                justify-content: space-between;\n                padding: 18px 20px;\n                border-bottom: 1px solid var(--line-2);\n            }\n            .pcard .ph h4 {\n                margin: 0;\n                font-size: 16px;\n                font-weight: 600;\n                display: flex;\n                align-items: center;\n                gap: 9px;\n                color: #13180f;\n            }\n            .pcard .ph h4 .ai-ic {\n                width: 20px;\n                height: 20px;\n                color: var(--green);\n            }\n            .status {\n                display: flex;\n                align-items: center;\n                gap: 7px;\n                font-size: 12.5px;\n                font-weight: 600;\n                font-family: monospace;\n                color: var(--green);\n            }\n            .status .pulse {\n                width: 7px;\n                height: 7px;\n                border-radius: 50%;\n                background: var(--green);\n                animation: pulse 1.2s infinite;\n            }\n            .status.done .pulse {\n                animation: none;\n            }\n\n            .score-wrap {\n                display: flex;\n                align-items: center;\n                gap: 20px;\n                padding: 20px;\n            }\n            .ring {\n                position: relative;\n                width: 96px;\n                height: 96px;\n                flex: none;\n            }\n            .ring svg {\n                transform: rotate(-90deg);\n            }\n            .ring .val {\n                position: absolute;\n                inset: 0;\n                display: flex;\n                flex-direction: column;\n                align-items: center;\n                justify-content: center;\n            }\n            .ring .val b {\n                font-size: 28px;\n                font-weight: 700;\n                line-height: 1;\n                color: #13180f;\n            }\n            .ring .val span {\n                font-size: 11px;\n                color: var(--muted);\n                font-family: monospace;\n                margin-top: 2px;\n            }\n            .score-txt h5 {\n                margin: 0 0 4px;\n                font-size: 17px;\n                font-weight: 600;\n                color: #13180f;\n            }\n            .score-txt p {\n                margin: 0;\n                font-size: 13.5px;\n                color: var(--muted);\n                line-height: 1.5;\n            }\n            .grade {\n                display: inline-block;\n                background: var(--green-soft);\n                color: var(--green-d);\n                font-weight: 700;\n                font-size: 13px;\n                border-radius: 7px;\n                padding: 3px 10px;\n                margin-top: 8px;\n                font-family: monospace;\n            }\n\n            .ai-coach-feedback-text {\n                padding: 18px 20px;\n                font-size: 15px;\n                line-height: 1.62;\n                color: #3a423a !important;\n                opacity: 1 !important;\n                visibility: visible !important;\n            }\n            .ai-coach-feedback-text p {\n                margin: 0 0 10px !important;\n                color: #3a423a !important;\n                opacity: 1 !important;\n                visibility: visible !important;\n            }\n            .ai-coach-feedback-text .ln {\n                margin: 0 0 13px;\n                opacity: 0;\n                transform: translateY(4px);\n                animation: fin .5s ease forwards;\n            }\n            .ai-coach-feedback-text .ln strong {\n                color: var(--ink);\n                font-weight: 600;\n            }\n            .ai-coach-feedback-text .tag {\n                display: inline-flex;\n                align-items: center;\n                gap: 6px;\n                font-family: monospace;\n                font-size: 11px;\n                font-weight: 600;\n                letter-spacing: .04em;\n                text-transform: uppercase;\n                border-radius: 6px;\n                padding: 3px 9px;\n                margin-right: 7px;\n                vertical-align: 1px;\n            }\n            .ai-coach-feedback-text .tag.good {\n                background: var(--green-soft);\n                color: var(--green-d);\n            }\n            .ai-coach-feedback-text .tag.watch {\n                background: #fdf0d8;\n                color: #a9781c;\n            }\n\n            .bio-grid {\n                display: grid;\n                grid-template-columns: 1fr 1fr;\n                gap: 1px;\n                background: var(--line-2);\n                border-radius: 0 0 16px 16px;\n                overflow: hidden;\n            }\n            .bio {\n                background: var(--surface);\n                padding: 16px 18px;\n                display: flex;\n                flex-direction: column;\n                gap: 6px;\n            }\n            .bio .top {\n                display: flex;\n                align-items: center;\n                justify-content: space-between;\n            }\n            .bio .name {\n                font-size: 12.5px;\n                color: var(--muted);\n                font-weight: 500;\n            }\n            .bio .st {\n                width: 8px;\n                height: 8px;\n                border-radius: 50%;\n            }\n            .bio .st.good {\n                background: var(--green);\n            }\n            .bio .st.watch {\n                background: #e6a82a;\n            }\n            .bio .num {\n                font-size: 24px;\n                font-weight: 700;\n                letter-spacing: -.02em;\n                color: #13180f;\n            }\n            .bio .num small {\n                font-size: 13px;\n                font-weight: 500;\n                color: var(--faint);\n            }\n            .bio .meter {\n                height: 5px;\n                background: var(--line-2);\n                border-radius: 999px;\n                overflow: hidden;\n                margin-top: 2px;\n            }\n            .bio .meter i {\n                display: block;\n                height: 100%;\n                width: 0;\n                border-radius: 999px;\n                background: var(--green);\n                transition: width 1s ease;\n            }\n            .bio .meter i.watch {\n                background: #e6a82a;\n            }\n            .pcard .ph.bio-h {\n                border-bottom: none;\n            }\n\n            .fadein {\n                opacity: 0;\n                animation: fin .5s ease forwards;\n            }\n            @keyframes fin { to { opacity: 1; transform: none; } }\n\n            .typing-cursor {\n                display: inline-block;\n                width: 2px;\n                background-color: var(--green);\n                animation: blink 0.8s infinite;\n                vertical-align: middle;\n            }\n            @keyframes blink {\n                0%, 100% { opacity: 1; }\n                50% { opacity: 0; }\n            }\n            \/* Coach text typewriter reveal per paragraph *\/\n            .feed-para {\n                overflow: hidden;\n                opacity: 0;\n                animation: fin 0.5s ease forwards;\n            }\n\n            }\n\n            \/* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n               Guest Login Landing Page Styles\n            \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 *\/\n            #golf-library-root #gl-login-view {\n                min-height: 60vh;\n                background: var(--bg);\n                display: flex !important;\n                flex-direction: column;\n                align-items: center;\n                justify-content: center;\n                padding: 40px 24px;\n            }\n            #golf-library-root .gl-hero {\n                display: flex !important;\n                gap: 56px;\n                align-items: flex-start;\n                max-width: 1060px;\n                width: 100%;\n            }\n            #golf-library-root .gl-sample-side {\n                flex: 1;\n                min-width: 0;\n            }\n            #golf-library-root .gl-eyebrow {\n                display: flex !important;\n                align-items: center;\n                gap: 8px;\n                font-size: 11.5px;\n                font-weight: 700;\n                letter-spacing: .08em;\n                color: var(--green);\n                text-transform: uppercase;\n                margin-bottom: 16px;\n            }\n            #golf-library-root .gl-eyebrow .gl-dot {\n                width: 8px; height: 8px;\n                background: var(--green);\n                border-radius: 50%;\n                animation: pulse 1.4s infinite;\n            }\n            #golf-library-root .gl-sample-side h2 {\n                font-size: clamp(24px, 3vw, 34px);\n                font-weight: 700;\n                color: var(--ink);\n                line-height: 1.2;\n                margin: 0 0 14px 0;\n            }\n            #golf-library-root .gl-sample-side h2 em {\n                font-style: normal;\n                color: var(--green);\n            }\n            #golf-library-root .gl-lead {\n                font-size: 15px;\n                color: var(--ink-2);\n                line-height: 1.65;\n                margin: 0 0 24px 0;\n            }\n            #golf-library-root .gl-sample-card {\n                position: relative;\n                border-radius: 16px;\n                overflow: hidden;\n                cursor: pointer;\n                aspect-ratio: 16\/10;\n                background: #0c100c;\n                box-shadow: var(--shadow-lg);\n                transition: transform .22s, box-shadow .22s;\n                margin-bottom: 18px;\n            }\n            #golf-library-root .gl-sample-card:hover { transform: translateY(-4px); box-shadow: 0 20px 56px rgba(20,30,15,.2); }\n            #golf-library-root .gl-sample-card .gl-media {\n                position: absolute;\n                inset: 0;\n            }\n            #golf-library-root .gl-demo-bg {\n                position: absolute;\n                inset: 0;\n                background: linear-gradient(135deg,#0c100c 0%,#1a2a1a 100%);\n                z-index: 0;\n            }\n            #golf-library-root .gl-demo-bg .gl-grid {\n                position: absolute;\n                inset: 0;\n                background:\n                    linear-gradient(90deg, rgba(44,195,116,.04) 1px, transparent 1px),\n                    linear-gradient(180deg, rgba(44,195,116,.04) 1px, transparent 1px);\n                background-size: 28px 28px;\n            }\n            #golf-library-root .gl-sample-card img {\n                position: absolute;\n                inset: 0;\n                width: 100%; height: 100%;\n                object-fit: cover;\n                opacity: 0.75;\n                display: block;\n                z-index: 1;\n            }\n            #golf-library-root .gl-sample-card .gl-ribbon {\n                position: absolute;\n                top: 14px; left: 14px;\n                z-index: 4;\n                background: rgba(26,168,90,.92);\n                color: #fff;\n                font-size: 11px;\n                font-weight: 700;\n                letter-spacing: .07em;\n                padding: 5px 10px;\n                border-radius: 8px;\n                display: flex;\n                align-items: center;\n                backdrop-filter: blur(4px);\n            }\n            #golf-library-root .gl-sample-card .gl-dur {\n                position: absolute;\n                top: 14px; right: 14px;\n                z-index: 4;\n                background: rgba(0,0,0,.6);\n                color: #fff;\n                font-size: 11px;\n                font-weight: 600;\n                padding: 5px 10px;\n                border-radius: 8px;\n                display: flex;\n                align-items: center;\n                backdrop-filter: blur(6px);\n            }\n            #golf-library-root .gl-sample-card .gl-scrim {\n                position: absolute;\n                bottom: 0; left: 0; right: 0;\n                z-index: 4;\n                background: linear-gradient(to top, rgba(0,0,0,.85) 0%, transparent 100%);\n                padding: 24px 16px 16px;\n                display: flex;\n                align-items: center;\n                gap: 12px;\n            }\n            #golf-library-root .gl-sample-card .gl-scrim .gl-playbtn {\n                width: 42px; height: 42px;\n                background: rgba(255,255,255,.15);\n                border-radius: 50%;\n                display: flex;\n                align-items: center;\n                justify-content: center;\n                flex-shrink: 0;\n                backdrop-filter: blur(4px);\n                border: 1px solid rgba(255,255,255,.25);\n                transition: background .18s;\n            }\n            #golf-library-root .gl-sample-card:hover .gl-scrim .gl-playbtn { background: rgba(44,195,116,.8); }\n            #golf-library-root .gl-sample-card .gl-scrim b {\n                font-size: 13.5px;\n                color: #fff;\n                font-weight: 600;\n            }\n            #golf-library-root .gl-sample-meta {\n                display: flex;\n                align-items: center;\n                gap: 12px;\n                flex-wrap: wrap;\n                font-size: 13px;\n                color: var(--muted);\n                margin-bottom: 22px;\n            }\n            #golf-library-root .gl-sample-meta .gl-nofee {\n                display: flex;\n                align-items: center;\n                color: var(--green-d);\n                font-weight: 600;\n            }\n            #golf-library-root .gl-cta-sample {\n                display: flex;\n                align-items: center;\n                gap: 10px;\n                background: var(--green);\n                color: #fff;\n                border: none;\n                border-radius: 12px;\n                padding: 13px 28px;\n                font-size: 15px;\n                font-weight: 700;\n                cursor: pointer;\n                font-family: inherit;\n                transition: background .18s, transform .18s;\n                box-shadow: 0 4px 16px rgba(44,195,116,.35);\n            }\n            #golf-library-root .gl-cta-sample:hover { background: var(--green-d); transform: translateY(-2px); }\n            #golf-library-root .gl-auth-shell {\n                flex-shrink: 0;\n                width: 380px;\n            }\n            #golf-library-root .gl-auth-card {\n                background: #ffffff;\n                border: 1px solid var(--line);\n                border-radius: 20px;\n                padding: 36px 32px;\n                box-shadow: var(--shadow);\n                text-align: center;\n            }\n            #golf-library-root .gl-logo-row {\n                font-size: 18px;\n                font-weight: 700;\n                color: var(--green);\n                margin-bottom: 20px;\n                display: flex !important;\n                align-items: center;\n                justify-content: center;\n                gap: 8px;\n            }\n            #golf-library-root .gl-auth-card h2 {\n                font-size: 20px;\n                font-weight: 700;\n                color: var(--ink);\n                margin: 0 0 8px 0;\n                line-height: 1.25;\n            }\n            #golf-library-root .gl-auth-sub {\n                font-size: 13.5px;\n                color: var(--muted);\n                margin: 0 0 24px 0;\n                line-height: 1.6;\n            }\n            #golf-library-root .gl-social-login-container { text-align: center; }\n\n            \/* Demo Header Banner styles *\/\n            #golf-library-root .demo-banner {\n                background: linear-gradient(135deg, #fef7e0 0%, #fef3d1 100%);\n                border: 1px solid #fde08c;\n                border-radius: 12px;\n                padding: 14px 20px;\n                margin-bottom: 24px;\n                display: flex;\n                justify-content: space-between;\n                align-items: center;\n                gap: 16px;\n                flex-wrap: wrap;\n            }\n            #golf-library-root .demo-banner .dl {\n                display: flex;\n                align-items: center;\n                gap: 12px;\n                color: #856404;\n                font-size: 14.5px;\n            }\n            #golf-library-root .demo-banner .dl svg {\n                color: #b58900;\n            }\n            #golf-library-root .demo-banner .dcta {\n                background: #b58900;\n                color: #ffffff;\n                border: none;\n                border-radius: 8px;\n                padding: 8px 16px;\n                font-size: 13.5px;\n                font-weight: 700;\n                cursor: pointer;\n                transition: background 0.18s;\n            }\n            #golf-library-root .demo-banner .dcta:hover {\n                background: #967100;\n            }\n\n            @media (max-width: 860px) {\n                #golf-library-root .gl-hero { flex-direction: column-reverse !important; gap: 32px; }\n                #golf-library-root .gl-auth-shell { width: 100%; }\n            }\n            @media (max-width: 520px) {\n                #golf-library-root #gl-login-view { padding: 24px 16px; }\n            }\n            <\/style>\n\n            <div id=\"golf-library-root\" style=\"min-height: 100vh;\">\n                <div style=\"display: flex; justify-content: center; align-items: center; min-height: 200px; color: #6b7280; font-family: 'Plus Jakarta Sans', -apple-system, BlinkMacSystemFont, sans-serif;\">\n                    <div style=\"text-align: center;\">\n                        <div style=\"width: 40px; height: 40px; border: 3px solid #e5e7eb; border-top: 3px solid #2cc374; border-radius: 50%; animation: golf-spin 1s linear infinite; margin: 0 auto 16px;\"><\/div>\n                        Loading AI Swing Analysis...\n                    <\/div>\n                <\/div>\n            <\/div>\n            <script>\n            window.golfLibraryConfig = {\"rootUrl\":\"https:\\\/\\\/devenv1.golfai.in\\\/hi\\\/wp-json\\\/golf-library\\\/v1\",\"homeUrl\":\"https:\\\/\\\/devenv1.golfai.in\\\/hi\\\/\",\"nonce\":\"e48a4e224e\",\"isLoggedIn\":false,\"socialLoginHtml\":\"<div class=\\\"hp-social-links\\\"><a href=\\\"https:\\\/\\\/accounts.google.com\\\/o\\\/oauth2\\\/v2\\\/auth?state=%7B%22provider%22%3A%22google%22%2C%22redirect%22%3A%22https%3A%5C%2F%5C%2Fdevenv1.golfai.in%5C%2Fhi%5C%2Fwp-json%5C%2Fwp%5C%2Fv2%5C%2Fpages%5C%2F1860%5C%2F%22%7D&#038;prompt=select_account&#038;scope=openid%20email%20profile&#038;response_type=code&#038;redirect_uri=https%3A%2F%2Fdevenv1.golfai.in%2Fhi%2Faccount%2Fauthenticate%2F&#038;client_id=275965544085-vl94jvqdbalccjtnbdih2p9kcqojdakn.apps.googleusercontent.com\\\" class=\\\"gsi-material-button\\\">\\n\\t\\t\\t\\t\\t\\t\\t<div class=\\\"gsi-material-button-state\\\"><\\\/div>\\n\\t\\t\\t\\t\\t\\t\\t<div class=\\\"gsi-material-button-content-wrapper\\\">\\n\\t\\t\\t\\t\\t\\t\\t\\t<div class=\\\"gsi-material-button-icon\\\">\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t<svg version=\\\"1.1\\\" xmlns=\\\"http:\\\/\\\/www.w3.org\\\/2000\\\/svg\\\" viewBox=\\\"0 0 48 48\\\" xmlns:xlink=\\\"http:\\\/\\\/www.w3.org\\\/1999\\\/xlink\\\" style=\\\"display: block;\\\">\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t<path fill=\\\"#EA4335\\\" d=\\\"M24 9.5c3.54 0 6.71 1.22 9.21 3.6l6.85-6.85C35.9 2.38 30.47 0 24 0 14.62 0 6.51 5.38 2.56 13.22l7.98 6.19C12.43 13.72 17.74 9.5 24 9.5z\\\"><\\\/path>\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t<path fill=\\\"#4285F4\\\" d=\\\"M46.98 24.55c0-1.57-.15-3.09-.38-4.55H24v9.02h12.94c-.58 2.96-2.26 5.48-4.78 7.18l7.73 6c4.51-4.18 7.09-10.36 7.09-17.65z\\\"><\\\/path>\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t<path fill=\\\"#FBBC05\\\" d=\\\"M10.53 28.59c-.48-1.45-.76-2.99-.76-4.59s.27-3.14.76-4.59l-7.98-6.19C.92 16.46 0 20.12 0 24c0 3.88.92 7.54 2.56 10.78l7.97-6.19z\\\"><\\\/path>\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t<path fill=\\\"#34A853\\\" d=\\\"M24 48c6.48 0 11.93-2.13 15.89-5.81l-7.73-6c-2.15 1.45-4.92 2.3-8.16 2.3-6.26 0-11.57-4.22-13.47-9.91l-7.98 6.19C6.51 42.62 14.62 48 24 48z\\\"><\\\/path>\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t<path fill=\\\"none\\\" d=\\\"M0 0h48v48H0z\\\"><\\\/path>\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t<\\\/svg>\\n\\t\\t\\t\\t\\t\\t\\t\\t<\\\/div>\\n\\t\\t\\t\\t\\t\\t\\t\\t<span class=\\\"gsi-material-button-contents\\\">Sign in with Google<\\\/span>\\n\\t\\t\\t\\t\\t\\t\\t<\\\/div>\\n\\t\\t\\t\\t\\t\\t<\\\/a><a href=\\\"https:\\\/\\\/www.linkedin.com\\\/oauth\\\/v2\\\/authorization?state=%7B%22provider%22%3A%22linkedin%22%2C%22redirect%22%3A%22https%3A%5C%2F%5C%2Fdevenv1.golfai.in%5C%2Fhi%5C%2Fwp-json%5C%2Fwp%5C%2Fv2%5C%2Fpages%5C%2F1860%5C%2F%22%7D&#038;scope=openid%20profile%20email&#038;response_type=code&#038;approval_prompt=auto&#038;redirect_uri=https%3A%2F%2Fdevenv1.golfai.in%2Fhi%2Faccount%2Fauthenticate%2F&#038;client_id=86xlc3szzrfk3t\\\" rel=\\\"nofollow\\\" class=\\\"hp-social-links__item hp-social-links__item--linkedin button button--large button--primary alt\\\"><img src=\\\"\\\/wp-content\\\/plugins\\\/hivepress-social-login\\\/assets\\\/images\\\/icons\\\/linkedin.svg\\\" alt=\\\"LinkedIn\\\" \\\/><span>Sign in with LinkedIn<\\\/span><\\\/a><\\\/div>\",\"currentUser\":null};\n            <\/script>\n\n            <!-- React client logic parsed through Babel Standalone -->\n            <script type=\"text\/babel\">\n            (function() {\n                'use strict';\n                \n                window.initGolfLibrary = function() {\n                    const container = document.getElementById('golf-library-root');\n                    if (!container) return;\n                    \n                    const { useState, useEffect, useRef, createElement: h } = React;\n                    \n                    \/\/ Configuration localized from WordPress\n                    const config = window.golfLibraryConfig || {\n                        rootUrl: '\/wp-json\/golf-library\/v1',\n                        homeUrl: '\/',\n                        nonce: '',\n                        isLoggedIn: false,\n                        socialLoginHtml: '',\n                        currentUser: null\n                    };\n                    \n                    \/\/ SVGs as React components\n                    const Search = () => h('svg', { width: 18, height: 18, viewBox: '0 0 24 24', fill: 'none', stroke: 'currentColor', strokeWidth: 2, strokeLinecap: 'round', strokeLinejoin: 'round' }, \n                        h('circle', { cx: 11, cy: 11, r: 8 }),\n                        h('path', { d: 'm21 21-4.35-4.35' })\n                    );\n                    \n                    const Plus = () => h('svg', { width: 18, height: 18, viewBox: '0 0 24 24', fill: 'none', stroke: 'currentColor', strokeWidth: 2, strokeLinecap: 'round', strokeLinejoin: 'round' },\n                        h('path', { d: 'M5 12h14' }),\n                        h('path', { d: 'm12 5 0 14' })\n                    );\n                    \n                    const ArrowLeft = () => h('svg', { width: 20, height: 20, viewBox: '0 0 24 24', fill: 'none', stroke: 'currentColor', strokeWidth: 2, strokeLinecap: 'round', strokeLinejoin: 'round' },\n                        h('path', { d: 'M19 12H5' }),\n                        h('path', { d: 'm12 19-7-7 7-7' })\n                    );\n                    \n                    const Play = () => h('svg', { width: 24, height: 24, viewBox: '0 0 24 24', fill: 'currentColor', stroke: 'none' },\n                        h('path', { d: 'M8 5v14l11-7z' })\n                    );\n                    \n                    const Clock = () => h('svg', { width: 14, height: 14, viewBox: '0 0 24 24', fill: 'none', stroke: 'currentColor', strokeWidth: 2, strokeLinecap: 'round', strokeLinejoin: 'round' },\n                        h('circle', { cx: 12, cy: 12, r: 10 }),\n                        h('polyline', { points: '12 6 12 12 16 14' })\n                    );\n\n                    const UserIcon = () => h('svg', { width: 14, height: 14, viewBox: '0 0 24 24', fill: 'none', stroke: 'currentColor', strokeWidth: 2, strokeLinecap: 'round', strokeLinejoin: 'round' },\n                        h('path', { d: 'M19 21v-2a4 4 0 0 0-4-4H9a4 4 0 0 0-4 4v2' }),\n                        h('circle', { cx: 12, cy: 7, r: 4 })\n                    );\n                    \n                    const Loader = () => h('div', { className: 'golf-loading-spinner' });\n\n                    \/\/ Video Card Component\n                    const VideoCard = ({ video, onClick, onAiClick }) => {\n                        const formatDuration = (secs) => {\n                            const s = Math.round(secs);\n                            const m = Math.floor(s \/ 60);\n                            const r = s % 60;\n                            return `${m}:${r < 10 ? '0' : ''}${r}`;\n                        };\n\n                        const formatDate = (dateStr) => {\n                            const d = new Date(dateStr.replace(' ', 'T'));\n                            return d.toLocaleDateString(undefined, { month: 'short', day: 'numeric', year: 'numeric' });\n                        };\n\n                        const isDemo = video.id === 'demo';\n\n                        \/\/ Probe real duration from actual video stream (fixes stale DB values)\n                        const [realDuration, setRealDuration] = React.useState(video.video_duration || 0);\n                        React.useEffect(() => {\n                            if (!video.video_url) return;\n                            const probe = document.createElement('video');\n                            probe.preload = 'metadata';\n                            probe.muted = true;\n                            probe.src = video.video_url;\n                            probe.onloadedmetadata = () => {\n                                if (!isNaN(probe.duration) && probe.duration > 0 && probe.duration !== Infinity) {\n                                    setRealDuration(probe.duration);\n                                }\n                                probe.src = '';\n                            };\n                            probe.onerror = () => { probe.src = ''; };\n                            return () => { probe.src = ''; };\n                        }, [video.video_url]);\n\n                        return h('div', { className: `video-card ${isDemo ? 'demo-video-card' : ''}`, onClick: () => onClick(video) },\n                            h('div', { className: 'video-thumbnail-wrapper' },\n                                isDemo && h('span', { className: 'demo-badge' }, 'Demo Video'),\n                                h('img', { \n                                    src: video.thumbnail_url || 'https:\/\/images.pexels.com\/photos\/1325735\/pexels-photo-1325735.jpeg?auto=compress&cs=tinysrgb&w=400&h=300&fit=crop', \n                                    alt: video.original_filename,\n                                    className: 'video-thumbnail' \n                                }),\n                                h('div', { className: 'video-play-overlay' },\n                                    h(Play)\n                                ),\n                                h('span', { className: 'video-duration-badge' }, \n                                    h(Clock), ' ', formatDuration(realDuration)\n                                )\n                            ),\n                            h('div', { className: 'video-card-info' },\n                                h('h3', { className: 'video-card-title' }, video.original_filename),\n                                h('div', { className: 'video-card-meta' },\n                                    h('span', null, h(UserIcon), ' Coach: ', video.coach),\n                                    h('span', null, formatDate(video.upload_timestamp))\n                                ),\n                                h('div', { className: 'card-sep' }),\n                                h('button', { \n                                    className: 'ai-a', \n                                    onClick: (e) => {\n                                        e.stopPropagation();\n                                        onAiClick(video);\n                                    },\n                                    style: { marginTop: '12px' }\n                                },\n                                    h('svg', { className: 'sparkle', viewBox: '0 0 24 24', fill: 'currentColor', style: { width: 18, height: 18, marginRight: 8, verticalAlign: 'middle' } },\n                                        h('path', { d: 'M12 2l1.7 4.9L18.6 8.6 13.7 10.3 12 15.2 10.3 10.3 5.4 8.6 10.3 6.9z' }),\n                                        h('path', { d: 'M19 14l.8 2.3 2.2.8-2.2.8-.8 2.3-.8-2.3-2.2-.8 2.2-.8z' })\n                                    ),\n                                    'Run AI Analysis'\n                                )\n                            )\n                        );\n                    };\n\n                    \/\/ Uploader Component\n                    const Uploader = ({ onBackClick, onUploadComplete }) => {\n                        const [title, setTitle] = useState('');\n                        const [description, setDescription] = useState('');\n                        const [selectedCoach, setSelectedCoach] = useState('John Doe');\n                        const [file, setFile] = useState(null);\n                        const [thumbnailBlob, setThumbnailBlob] = useState(null);\n                        const [duration, setDuration] = useState(0);\n                        const [generatingThumbnail, setGeneratingThumbnail] = useState(false);\n                        const [progress, setProgress] = useState(0);\n                        const [uploading, setUploading] = useState(false);\n                        const [error, setError] = useState('');\n\n                        const coaches = ['John Doe', 'Anand Sharma', 'Sarah Johnson', 'Mike Williams', 'Lisa Chen'];\n\n                        const handleFile = (selectedFile) => {\n                            setError('');\n                            setFile(selectedFile);\n                            setTitle(selectedFile.name.split('.').slice(0, -1).join('.'));\n                            setThumbnailBlob(null);\n                            setDuration(0);\n                            setGeneratingThumbnail(true);\n\n                            const video = document.createElement('video');\n                            video.style.display = 'none';\n                            document.body.appendChild(video); \/\/ Mount to DOM for hardware decoding support\n                            \n                            video.muted = true;\n                            video.playsInline = true;\n                            \n                            const objectUrl = URL.createObjectURL(selectedFile);\n\n                            const cleanup = () => {\n                                try {\n                                    if (video.parentNode) {\n                                        document.body.removeChild(video);\n                                    }\n                                    window.URL.revokeObjectURL(objectUrl);\n                                } catch (e) {}\n                            };\n\n                            video.onloadedmetadata = () => {\n                                const dur = video.duration;\n                                if (isNaN(dur) || dur === Infinity || dur <= 0) {\n                                    setDuration(8.0);\n                                    video.currentTime = 0.5;\n                                } else if (dur > 35) {\n                                    setError('Video must be 30 seconds or less.');\n                                    setFile(null);\n                                    setGeneratingThumbnail(false);\n                                    cleanup();\n                                } else {\n                                    setDuration(dur);\n                                    \/\/ Seek to 1s mark (or half duration if very short)\n                                    video.currentTime = Math.min(1.0, dur \/ 2);\n                                }\n                            };\n\n                            video.onseeked = () => {\n                                try {\n                                    const canvas = document.createElement('canvas');\n                                    canvas.width = 640;\n                                    canvas.height = 360;\n                                    const ctx = canvas.getContext('2d');\n                                    ctx.drawImage(video, 0, 0, canvas.width, canvas.height);\n                                    canvas.toBlob((blob) => {\n                                        if (blob) {\n                                            setThumbnailBlob(blob);\n                                        }\n                                        setGeneratingThumbnail(false);\n                                        cleanup();\n                                    }, 'image\/jpeg', 0.85);\n                                } catch (e) {\n                                    console.error(\"GOLF_LIBRARY: Thumbnail extraction error\", e);\n                                    setGeneratingThumbnail(false);\n                                    cleanup();\n                                }\n                            };\n\n                            video.onerror = (e) => {\n                                console.error(\"GOLF_LIBRARY: Video load error\", e);\n                                setError('Unable to process this video file.');\n                                setFile(null);\n                                setGeneratingThumbnail(false);\n                                cleanup();\n                            };\n\n                            video.src = objectUrl;\n                        };\n\n                        const handleSubmit = (e) => {\n                            e.preventDefault();\n                            if (!file) {\n                                setError('Please select a video file to upload.');\n                                return;\n                            }\n\n                            setUploading(true);\n                            setProgress(0);\n\n                            const formData = new FormData();\n                            formData.append('video', file);\n                            formData.append('title', title);\n                            formData.append('description', description);\n                            formData.append('coach', selectedCoach);\n                            formData.append('duration', duration);\n                            if (thumbnailBlob) {\n                                formData.append('thumbnail', thumbnailBlob, 'thumbnail.jpg');\n                            }\n\n                            \/\/ Use XMLHttpRequest to track progress\n                            const xhr = new XMLHttpRequest();\n                            xhr.open('POST', `${config.rootUrl}\/videos\/upload`);\n                            xhr.setRequestHeader('X-WP-Nonce', config.nonce);\n\n                            let progressInterval = null;\n\n                            const startServerProgressSimulation = () => {\n                                if (progressInterval) return;\n                                let currentProgress = 40;\n                                progressInterval = setInterval(() => {\n                                    \/\/ Incrementally add 1% to 3% every second to show life\n                                    currentProgress += Math.floor(Math.random() * 3) + 1;\n                                    if (currentProgress >= 95) {\n                                        currentProgress = 95;\n                                        clearInterval(progressInterval);\n                                    }\n                                    setProgress(currentProgress);\n                                }, 1000);\n                            };\n\n                            xhr.upload.onprogress = (event) => {\n                                if (event.lengthComputable) {\n                                    \/\/ Map local\/client upload to first 40%\n                                    const percent = Math.round((event.loaded \/ event.total) * 40);\n                                    setProgress(percent);\n                                    \n                                    if (event.loaded === event.total) {\n                                        startServerProgressSimulation();\n                                    }\n                                }\n                            };\n\n                            xhr.onload = () => {\n                                if (progressInterval) clearInterval(progressInterval);\n                                setProgress(100);\n                                \n                                \/\/ Small delay so user sees 100% completion\n                                setTimeout(() => {\n                                    try {\n                                        const response = JSON.parse(xhr.responseText);\n                                        if (xhr.status === 200) {\n                                            onUploadComplete(response);\n                                        } else {\n                                            setError(response.message || 'Upload failed. Please try again.');\n                                            setUploading(false);\n                                        }\n                                    } catch (e) {\n                                        setError(`Server error (${xhr.status}). Please check your server logs.`);\n                                        setUploading(false);\n                                    }\n                                }, 600);\n                            };\n\n                            xhr.onerror = () => {\n                                if (progressInterval) clearInterval(progressInterval);\n                                setError('Network error occurred during upload.');\n                                setProgress(0);\n                                setUploading(false);\n                            };\n\n                            xhr.send(formData);\n                        };\n\n                        return h('div', { className: 'uploader-wrapper' },\n                            h('div', { className: 'uploader-header' },\n                                h('button', { onClick: onBackClick, className: 'back-btn' },\n                                    h(ArrowLeft), ' Back to Library'\n                                ),\n                                h('h2', { className: 'uploader-title' }, 'Upload Swing Video')\n                            ),\n                            h('form', { onSubmit: handleSubmit, className: 'uploader-form' },\n                                error && h('div', { className: 'upload-error-banner' }, error),\n                                \n                                \/\/ Drag and Drop Area\n                                h('div', {\n                                    className: `drag-drop-area ${file ? 'has-file' : ''}`,\n                                    onDragOver: (e) => e.preventDefault(),\n                                    onDrop: (e) => {\n                                        e.preventDefault();\n                                        if (e.dataTransfer.files?.[0]) handleFile(e.dataTransfer.files[0]);\n                                    },\n                                    onClick: () => document.getElementById('file-input').click()\n                                },\n                                    h('input', {\n                                        id: 'file-input',\n                                        type: 'file',\n                                        accept: 'video\/*',\n                                        style: { display: 'none' },\n                                        onChange: (e) => e.target.files?.[0] && handleFile(e.target.files[0])\n                                    }),\n                                    h('div', { className: 'upload-icon' }, '\ud83d\udcf9'),\n                                    h('p', { className: 'upload-text-main' }, \n                                        file ? file.name : 'Drag & drop video or click to browse'\n                                    ),\n                                    h('p', { className: 'upload-text-sub' }, 'Supports MP4, MOV, AVI, WEBM (Max 30s, Max 500MB)')\n                                ),\n\n                                file && h('div', { className: 'upload-fields' },\n                                    \/\/ Title Input\n                                    h('div', { className: 'input-group' },\n                                        h('label', null, 'Video Title'),\n                                        h('input', {\n                                            type: 'text',\n                                            value: title,\n                                            onChange: (e) => setTitle(e.target.value),\n                                            required: true\n                                        })\n                                    ),\n\n                                    \/\/ Coach Selection\n                                    h('div', { className: 'input-group' },\n                                        h('label', null, 'Assign to Coach'),\n                                        h('select', {\n                                            value: selectedCoach,\n                                            onChange: (e) => setSelectedCoach(e.target.value)\n                                        },\n                                            coaches.map(c => h('option', { key: c, value: c }, c))\n                                        )\n                                    ),\n\n                                    \/\/ Description Input\n                                    h('div', { className: 'input-group' },\n                                        h('label', null, 'Notes \/ Description'),\n                                        h('textarea', {\n                                            value: description,\n                                            onChange: (e) => setDescription(e.target.value),\n                                            placeholder: 'Describe your swing, what feel you were trying, or any issues you are facing...',\n                                            rows: 4\n                                        })\n                                    )\n                                ),\n\n                                \/\/ Progress Bar\n                                uploading && h('div', { className: 'progress-bar-container' },\n                                    h('div', { className: 'progress-bar-fill', style: { width: `${progress}%` } }),\n                                    h('span', { className: 'progress-text' }, `Uploading: ${progress}%`)\n                                ),\n\n                                file && !uploading && (\n                                    generatingThumbnail ? h('button', { type: 'button', disabled: true, className: 'submit-upload-btn', style: { opacity: 0.6, cursor: 'not-allowed' } }, 'Processing Video...') :\n                                    h('button', { type: 'submit', className: 'submit-upload-btn' }, 'Send to GCS & Process')\n                                )\n                            )\n                        );\n                    };\n\n                    \/\/ Loading Overlay Component\n                    const AiLoadingOverlay = ({ show, progress, activeStep }) => {\n                        if (!show) return null;\n\n                        const steps = [\n                            'Detecting body pose',\n                            'Tracking club path',\n                            'Measuring joint angles',\n                            'Generating coach feedback'\n                        ];\n\n                        return h('div', { className: 'overlay show' },\n                            h('div', { className: 'load-card' },\n                                h('div', { className: 'scan' },\n                                    h('div', { className: 'grid-bg' }),\n                                    h('div', { className: 'beam' }),\n                                    h('div', { className: 'dot', style: { top: '40%', left: '30%' } }),\n                                    h('div', { className: 'dot', style: { top: '55%', left: '46%' } }),\n                                    h('div', { className: 'dot', style: { top: '35%', left: '62%' } }),\n                                    h('div', { className: 'dot', style: { top: '70%', left: '52%' } })\n                                ),\n                                h('h2', null, 'Analyzing swing\u2026'),\n                                h('p', null, 'Our model is breaking down the motion frame by frame.'),\n                                h('div', { className: 'steps' },\n                                    steps.map((step, idx) => {\n                                        let stepClass = 'step';\n                                        if (idx < activeStep) stepClass += ' done';\n                                        else if (idx === activeStep) stepClass += ' active';\n\n                                        return h('div', { key: idx, className: stepClass },\n                                            h('span', { className: 'ic' },\n                                                h('svg', { viewBox: '0 0 24 24' },\n                                                    h('path', { d: 'M20 6 9 17l-5-5' })\n                                                )\n                                            ),\n                                            step\n                                        );\n                                    })\n                                ),\n                                h('div', { className: 'pbar' },\n                                    h('i', { style: { width: `${progress}%` } })\n                                ),\n                                h('div', { style: { display: 'flex', justifyContent: 'space-between', marginTop: 12, fontSize: 13, color: '#737d72', fontFamily: 'inherit' } },\n                                    h('span', null, `Progress: ${Math.round(progress)}%`),\n                                    h('span', null, progress >= 95 ? 'Finalizing results...' : 'Completing any moment...')\n                                )\n                            )\n                        );\n                    };\n\n                    \/\/ Welcome \/ Sign-in \/ Try Demo Landing View Component\n                    const LoginView = ({ socialLoginHtml, onTryDemoClick, demoVideo }) => {\n                        const thumbUrl = (demoVideo && demoVideo.thumbnail_url) \n                            ? demoVideo.thumbnail_url \n                            : `${config.homeUrl}?golf_stream_file=thumbnails%2Fdemo_user%2Fswing1_thumb.jpg`;\n                        const durationSec = demoVideo ? demoVideo.video_duration : 6.0;\n                        const durationStr = `0:0${Math.round(durationSec)}`;\n\n                        return h('div', { id: 'gl-login-view', className: 'show' },\n                            h('div', { className: 'gl-hero' },\n                                \/\/ Marketing side\n                                h('div', { className: 'gl-sample-side' },\n                                    h('span', { className: 'gl-eyebrow' },\n                                        h('span', { className: 'gl-dot' }),\n                                        'SEE IT BEFORE YOU SIGN IN'\n                                    ),\n                                    h('h2', null, 'Watch the AI break down a ', h('em', null, 'real swing'), ` in ${Math.round(durationSec)} seconds.`),\n                                    h('p', { className: 'gl-lead' }, 'Pose tracking, club path, swing plane and coach-grade feedback \u2014 exactly what you\\'ll get on your own video.'),\n                                    \n                                    h('div', { className: 'gl-sample-card', onClick: onTryDemoClick },\n                                        h('div', { className: 'gl-media' },\n                                            h('div', { className: 'gl-demo-bg' }, h('div', { className: 'gl-grid' })),\n                                            h('img', { \n                                                src: thumbUrl, \n                                                style: { width: '100%', height: '100%', objectFit: 'cover', opacity: 0.8, display: 'block' } \n                                            }),\n                                            h('div', { className: 'gl-ribbon' }, \n                                                h('svg', { viewBox: '0 0 24 24', fill: 'currentColor', style: { width: 13, height: 13, marginRight: 6 } }, \n                                                    h('path', { d: 'M12 2l1.7 4.9L18.6 8.6 13.7 10.3 12 15.2 10.3 10.3 5.4 8.6 10.3 6.9z' })\n                                                ),\n                                                'SAMPLE ANALYSIS'\n                                            ),\n                                            h('div', { className: 'gl-dur' }, \n                                                h('svg', { viewBox: '0 0 24 24', fill: 'none', stroke: 'currentColor', strokeWidth: 2.2, style: { width: 13, height: 13, marginRight: 6, verticalAlign: 'middle' } },\n                                                    h('circle', { cx: 12, cy: 12, r: 9 }),\n                                                    h('path', { d: 'M12 8v4l3 2', strokeLinecap: 'round' })\n                                                ),\n                                                durationStr\n                                            ),\n                                            h('div', { className: 'gl-scrim' },\n                                                h('div', { className: 'gl-playbtn' }, h(Play)),\n                                                h('b', null, 'Driver swing \u00b7 full AI breakdown')\n                                            )\n                                        )\n                                    ),\n                                    \n                                    h('div', { className: 'gl-sample-meta' },\n                                        h('span', { className: 'gl-nofee' },\n                                            h('svg', { viewBox: '0 0 24 24', fill: 'none', stroke: 'currentColor', strokeWidth: '2.4', strokeLinecap: 'round', strokeLinejoin: 'round', style: { width: 16, height: 16, marginRight: 8 } },\n                                                h('path', { d: 'M20 6 9 17l-5-5' })\n                                            ),\n                                            'No account needed to watch'\n                                        ),\n                                        h('span', null, '\u00b7'),\n                                        h('span', null, 'See score, biomarkers & coach notes')\n                                    ),\n                                    h('button', { className: 'gl-cta-sample', onClick: onTryDemoClick },\n                                        h(Play),\n                                        'Play sample analysis'\n                                    )\n                                ),\n                                \n                                \/\/ Sign-in side\n                                h('div', { className: 'gl-auth-shell' },\n                                    h('div', { className: 'gl-auth-card' },\n                                        h('div', { className: 'gl-logo-row' }, h('span', null, '\u26f3'), 'GolfAI'),\n                                        h('h2', null, 'Welcome to AI Swing analysis'),\n                                        h('p', { className: 'gl-auth-sub' }, 'Sign in to record, upload, and share golf swing analytics with your coaches.'),\n                                        h('div', { \n                                            className: 'gl-social-login-container',\n                                            dangerouslySetInnerHTML: { __html: socialLoginHtml } \n                                        }),\n                                        h('p', { className: 'legal' }, 'By continuing you agree to our Terms & Privacy Policy.')\n                                    )\n                                )\n                            )\n                        );\n                    };\n\n                    \/\/ Analysis Screen View Component\n                    const AnalysisView = ({ analysisData, onBackClick, onSignInClick }) => {\n                        \/\/ Support both raw array format and new schema with 'cards' key\n                        const rawBiomarkersData = analysisData.biomarkers;\n                        const biomarkersList = Array.isArray(rawBiomarkersData)\n                            ? rawBiomarkersData\n                            : (rawBiomarkersData && Array.isArray(rawBiomarkersData.cards) ? rawBiomarkersData.cards : []);\n\n                        const coachText = analysisData.coach_text;\n                        const coachFullText = typeof coachText === 'string' ? coachText : '';\n\n                        \/\/ Determine if we have any real AI data to show\n                        const hasBiomarkers = biomarkersList.length > 0 && !(rawBiomarkersData && rawBiomarkersData.raw);\n                        const hasRawBiomarkers = !!(rawBiomarkersData && rawBiomarkersData.raw);\n                        const hasCoachText = !!coachText;\n                        const hasAnyAiData = hasBiomarkers || hasRawBiomarkers || hasCoachText;\n\n                        \/\/ State for displayed HTML - React owns it, no reconciliation conflicts\n                        const [feedHtml, setFeedHtml] = useState('');\n\n                        \/\/ setTimeout chain - time-based so throttling just adds more chars per tick\n                        useEffect(() => {\n                            if (!coachFullText) return;\n                            let current = 0;\n                            let lastTime = performance.now();\n                            const MS_PER_CHAR = 20;\n                            let timerId = null;\n\n                            function formatMarkdown(text) {\n                                if (!text) return '';\n                                let html = text;\n                                \/\/ Escape simple HTML characters to prevent rendering problems\n                                html = html\n                                    .replace(\/&\/g, '&amp;')\n                                    .replace(\/<\/g, '&lt;')\n                                    .replace(\/>\/g, '&gt;');\n                                \n                                \/\/ Headers: e.g. # Header\n                                html = html.replace(\/^#\\s+(.*?)$\/gm, '<h3 style=\"margin:0 0 12px 0; color:var(--pomelise-dark-gray); font-size:16px; font-weight:700; font-family:inherit;\">$1<\/h3>');\n                                \n                                \/\/ Bold: **text**\n                                html = html.replace(\/\\*\\*(.*?)\\*\\*\/g, '<strong>$1<\/strong>');\n                                \n                                \/\/ Italics: _text_\n                                html = html.replace(\/_(.*?)_\/g, '<em>$1<\/em>');\n                                \n                                \/\/ Split by double newlines, wrap in styled paragraphs\n                                const paragraphs = html.split(\/\\n\\s*\\n\/)\n                                    .map(p => {\n                                        p = p.trim();\n                                        if (!p) return '';\n                                        if (p.startsWith('<h3')) return p;\n                                        return '<p style=\"margin:0 0 10px 0; color:#3a423a !important; opacity:1 !important; display:block !important; visibility:visible !important; line-height:1.6; font-family:inherit;\">' + p.replace(\/\\n\/g, '<br\/>') + '<\/p>';\n                                    })\n                                    .filter(p => p !== '')\n                                    .join('');\n                                    \n                                return paragraphs;\n                            }\n\n                            function step() {\n                                const now = performance.now();\n                                const elapsed = now - lastTime;\n                                \/\/ Add at least 1 char, more if throttled\n                                const add = Math.max(1, Math.floor(elapsed \/ MS_PER_CHAR));\n                                current = Math.min(current + add, coachFullText.length);\n                                lastTime = now;\n                                setFeedHtml(formatMarkdown(coachFullText.slice(0, current)));\n                                if (current < coachFullText.length) {\n                                    timerId = setTimeout(step, MS_PER_CHAR);\n                                }\n                            }\n\n                            timerId = setTimeout(step, 80);\n                            return () => clearTimeout(timerId);\n                        }, [coachFullText]);\n\n                        \/\/ Calculate score ONLY from real biomarker data (never hardcoded)\n                        let score = 0;\n                        let grade = '';\n                        let summaryText = '';\n                        let detailText = '';\n\n                        if (hasBiomarkers) {\n                            const totalPct = biomarkersList.reduce((sum, b) => sum + (parseInt(b.pct) !== undefined ? (parseInt(b.pct) || 0) : 0), 0);\n                            score = Math.round(totalPct \/ biomarkersList.length);\n                            if (score >= 90) {\n                                grade = 'A';\n                                summaryText = 'Excellent swing mechanics';\n                                detailText = 'Your swing plane and sequencing are matching professional benchmarks.';\n                            } else if (score >= 80) {\n                                grade = 'B+';\n                                summaryText = 'Consistent swing path';\n                                detailText = 'Good tempo. Work on early extension to gain more distance.';\n                            } else if (score >= 70) {\n                                grade = 'B';\n                                summaryText = 'Solid fundamentals';\n                                detailText = 'Keep practicing rotation and maintaining your spine angle through impact.';\n                            } else {\n                                grade = 'C+';\n                                summaryText = 'Developing swing path';\n                                detailText = 'Focus on consistent setup and tempo before adding power.';\n                            }\n                        }\n\n                        const renderCoachFeedback = () => {\n                            if (!coachText) return null;\n                            if (typeof coachText === 'string') {\n                                \/\/ React owns the innerHTML via dangerouslySetInnerHTML - no conflicts\n                                return h('div', {\n                                    className: 'ai-coach-feedback-text',\n                                    dangerouslySetInnerHTML: { __html: feedHtml }\n                                });\n                            }\n                            if (Array.isArray(coachText)) {\n                                return h('div', { className: 'ai-coach-feedback-text' },\n                                    coachText.map((item, idx) => h('div', { key: idx, className: 'ln in' },\n                                        item.tag && h('span', { className: `tag ${item.st || item.tag}` }, item.tag),\n                                        h('span', { dangerouslySetInnerHTML: { __html: item.html || item.text } })\n                                    ))\n                                );\n                            }\n                            return null;\n                        };\n\n                        return h('div', { className: 'analysis-view-wrapper fadein' },\n                            \/\/ Demo Banner\n                            analysisData.video_id === 'demo' && !config.isLoggedIn && h('div', { className: 'demo-banner' },\n                                h('div', { className: 'dl' },\n                                    h('svg', { viewBox: '0 0 24 24', fill: 'none', stroke: 'currentColor', strokeWidth: 2, style: { width: 20, height: 20, flexShrink: 0 } },\n                                        h('path', { d: 'M12 2l1.7 4.9L18.6 8.6 13.7 10.3 12 15.2 10.3 10.3 5.4 8.6 10.3 6.9z', fill: 'currentColor', stroke: 'none' })\n                                    ),\n                                    h('span', null,\n                                        h('b', null, 'You\\'re viewing a sample analysis. '),\n                                        'Sign in to run this on your own swings \u2014 score, biomarkers and coach notes included.'\n                                    )\n                                ),\n                                h('button', { \n                                    className: 'dcta', \n                                    onClick: () => {\n                                        if (onSignInClick) {\n                                            onSignInClick();\n                                        } else {\n                                            onBackClick();\n                                        }\n                                    } \n                                }, 'Sign in to analyze my swing')\n                            ),\n                            \/\/ Topbar\n                            h('div', { className: 'an-top' },\n                                h('button', { onClick: onBackClick, className: 'back' },\n                                    h('svg', { viewBox: '0 0 24 24', fill: 'none', stroke: 'currentColor', strokeWidth: '2.2', strokeLinecap: 'round', strokeLinejoin: 'round', style: { width: 18, height: 18 } },\n                                        h('path', { d: 'M19 12H5M11 18l-6-6 6-6' })\n                                    ),\n                                    config.isLoggedIn ? 'Library' : 'Back'\n                                ),\n                                h('div', { className: 'an-title' },\n                                    h('b', null, analysisData.video_id === 'demo' ? 'Sample \u2014 Driver swing' : analysisData.original_filename),\n                                    h('span', null, analysisData.video_id === 'demo' ? `GolfAI Demo \u00b7 0:0${Math.round(analysisData.duration || 6)} \u00b7 Driver \u00b7 Example analysis` : `Coach: ${analysisData.coach_name} \u00b7 ${analysisData.duration}s \u00b7 Analyzed on ${new Date(analysisData.upload_timestamp).toLocaleDateString()}`)\n                                )\n                            ),\n\n                            \/\/ Body\n                            h('div', { className: 'an-body' },\n                                \/\/ Left Panel (Video Stage)\n                                h('div', { className: 'stage' },\n                                    h('div', { className: 'video-area' },\n                                        analysisData.is_fallback_video && h('div', { className: 'badge', style: { borderColor: '#ffd24a', color: '#ffd24a' } },\n                                            h('span', { className: 'pulse', style: { background: '#ffd24a' } }),\n                                            'Original Video (AI Processing Pending)'\n                                        ),\n                                        !analysisData.is_fallback_video && h('div', { className: 'badge' },\n                                            h('span', { className: 'pulse' }),\n                                            'AI POSE TRACKED'\n                                        ),\n                                        h('video', {\n                                            src: analysisData.ai_video_url,\n                                            controls: true,\n                                            autoPlay: true,\n                                            className: 'modal-video-player',\n                                            style: { width: '100%', display: 'block', aspectRatio: '16\/10', objectFit: 'contain' }\n                                        })\n                                    )\n                                ),\n\n                                \/\/ Right Panel (Data Cards)\n                                h('div', { className: 'panel' },\n                                    \/\/ \u2500\u2500 NO AI DATA: show a single \"pending\" card \u2500\u2500\n                                    !hasAnyAiData && h('div', { className: 'pcard' },\n                                        h('div', { className: 'ph' },\n                                            h('h4', null,\n                                                h('svg', { className: 'ai-ic', viewBox: '0 0 24 24', fill: 'currentColor', style: { width: 20, height: 20, marginRight: 8, verticalAlign: 'middle' } },\n                                                    h('path', { d: 'M12 2l1.7 4.9L18.6 8.6 13.7 10.3 12 15.2 10.3 10.3 5.4 8.6 10.3 6.9z' }),\n                                                    h('path', { d: 'M19 14l.8 2.3 2.2.8-2.2.8-.8 2.3-.8-2.3-2.2-.8 2.2-.8z' })\n                                                ),\n                                                'AI Analysis'\n                                            ),\n                                            h('div', { className: 'status', style: { color: '#e6a82a' } },\n                                                h('span', { className: 'pulse', style: { background: '#e6a82a', animation: 'pulse 1.2s infinite' } }),\n                                                'PENDING'\n                                            )\n                                        ),\n                                        h('div', { style: { padding: '28px 20px', textAlign: 'center' } },\n                                            h('div', { style: { fontSize: 42, marginBottom: 14 } }, '\u23f3'),\n                                            h('h5', { style: { margin: '0 0 10px', fontSize: 16, fontWeight: 600, color: '#13180f' } }, 'AI processing not yet complete'),\n                                            h('p', { style: { margin: 0, fontSize: 13.5, color: '#737d72', lineHeight: 1.65 } },\n                                                'The AI-processed video, biomarkers, and coaching feedback will appear here once the analysis pipeline finishes processing this video.'\n                                            )\n                                        )\n                                    ),\n\n                                    \/\/ \u2500\u2500 SWING SCORE CARD \u2014 only when biomarkers are available \u2500\u2500\n                                    hasBiomarkers && h('div', { className: 'pcard' },\n                                        h('div', { className: 'ph' },\n                                            h('h4', null, \n                                                h('svg', { className: 'ai-ic', viewBox: '0 0 24 24', fill: 'currentColor', style: { width: 20, height: 20, marginRight: 8, verticalAlign: 'middle' } },\n                                                    h('path', { d: 'M12 2l1.7 4.9L18.6 8.6 13.7 10.3 12 15.2 10.3 10.3 5.4 8.6 10.3 6.9z' }),\n                                                    h('path', { d: 'M19 14l.8 2.3 2.2.8-2.2.8-.8 2.3-.8-2.3-2.2-.8 2.2-.8z' })\n                                                ),\n                                                'Swing Score'\n                                            ),\n                                            h('div', { className: 'status done' }, \n                                                h('span', { className: 'pulse' }),\n                                                'ANALYZED'\n                                            )\n                                        ),\n                                        h('div', { className: 'score-wrap' },\n                                            h('div', { className: 'ring' },\n                                                h('svg', { width: 96, height: 96 },\n                                                    h('circle', { cx: 48, cy: 48, r: 42, fill: 'none', stroke: '#eef1ea', strokeWidth: 8 }),\n                                                    h('circle', {\n                                                        cx: 48,\n                                                        cy: 48,\n                                                        r: 42,\n                                                        fill: 'none',\n                                                        stroke: '#1aa85a',\n                                                        strokeWidth: 8,\n                                                        strokeLinecap: 'round',\n                                                        strokeDasharray: 264,\n                                                        strokeDashoffset: 264 - (264 * score) \/ 100\n                                                    })\n                                                ),\n                                                h('div', { className: 'val' },\n                                                    h('b', null, score),\n                                                    h('span', null, '\/ 100')\n                                                )\n                                            ),\n                                            h('div', { className: 'score-txt' },\n                                                h('h5', null, summaryText),\n                                                h('p', null, detailText),\n                                                h('span', { className: 'grade' }, `GRADE ${grade}`)\n                                            )\n                                        )\n                                    ),\n\n                                    \/\/ \u2500\u2500 AI COACH FEEDBACK CARD \u2014 only when coach text is available \u2500\u2500\n                                    hasCoachText && h('div', { className: 'pcard' },\n                                        h('div', { className: 'ph' },\n                                            h('h4', null, \n                                                h('svg', { className: 'ai-ic', viewBox: '0 0 24 24', fill: 'none', stroke: 'currentColor', strokeWidth: 2, style: { width: 20, height: 20, marginRight: 8, verticalAlign: 'middle' } },\n                                                    h('path', { d: 'M12 3a9 9 0 0 0-9 9 9 9 0 0 0 4 7.5L7 21l3-1.2a9 9 0 1 0 2-16.8z', strokeLinejoin: 'round' })\n                                                ),\n                                                'AI Coach Feedback'\n                                            )\n                                        ),\n                                        renderCoachFeedback()\n                                    ),\n\n                                    \/\/ \u2500\u2500 BIOMARKERS CARD \u2014 only when structured biomarker data is available \u2500\u2500\n                                    hasBiomarkers && h('div', { className: 'pcard' },\n                                        h('div', { className: 'ph bio-h' },\n                                            h('h4', null, \n                                                h('svg', { className: 'ai-ic', viewBox: '0 0 24 24', fill: 'none', stroke: 'currentColor', strokeWidth: 2, style: { width: 20, height: 20, marginRight: 8, verticalAlign: 'middle' } },\n                                                    h('path', { d: 'M3 12h4l3 8 4-16 3 8h4', strokeLinecap: 'round', strokeLinejoin: 'round' })\n                                                ),\n                                                'Biomarkers'\n                                            )\n                                        ),\n                                        h('div', { className: 'bio-grid' },\n                                            biomarkersList.map((b, idx) => {\n                                                const status = b.status || b.st || 'good';\n                                                const val = b.display || b.val || (b.value !== undefined ? b.value : '');\n                                                const unit = b.display ? '' : (b.unit || '');\n                                                const pct = b.pct !== undefined ? b.pct : 100;\n                                                return h('div', { key: idx, className: 'bio' },\n                                                    h('div', { className: 'top' },\n                                                        h('span', { className: 'name' }, b.name),\n                                                        h('span', { className: `st ${status}` })\n                                                    ),\n                                                    h('div', { className: 'num' }, \n                                                        val,\n                                                        unit && h('small', null, unit)\n                                                    ),\n                                                    h('div', { className: 'meter' },\n                                                        h('i', { \n                                                            className: status === 'watch' ? 'watch' : '',\n                                                            style: { width: `${pct}%` }\n                                                        })\n                                                    )\n                                                );\n                                            })\n                                        )\n                                    ),\n\n                                    \/\/ \u2500\u2500 RAW BIOMARKERS \u2014 fallback text if JSON is not standard \u2500\u2500\n                                    hasRawBiomarkers && h('div', { className: 'pcard' },\n                                        h('div', { className: 'ph' },\n                                            h('h4', null, 'Biomarkers Data')\n                                        ),\n                                        h('div', { className: 'ai-coach-feedback-text', style: { fontFamily: 'monospace', fontSize: 13 } }, \n                                            h('pre', null, rawBiomarkersData.text)\n                                        )\n                                    )\n                                )\n                            )\n                        );\n                    };\n\n                    \/\/ Main App Wrapper\n                    const App = () => {\n                        const [user, setUser] = useState(config.currentUser);\n                        const [view, setView] = useState(!config.isLoggedIn ? 'login' : 'library'); \/\/ library, upload, analysis, login\n                        const [videos, setVideos] = useState([]);\n                        const [loading, setLoading] = useState(false);\n                        const [activeCoach, setActiveCoach] = useState('All');\n                        const [search, setSearch] = useState('');\n                        const [activeVideo, setActiveVideo] = useState(null);\n\n                        \/\/ AI Analysis States\n                        const [aiLoading, setAiLoading] = useState(false);\n                        const [aiProgress, setAiProgress] = useState(0);\n                        const [aiStep, setAiStep] = useState(0);\n                        const [currentAnalysis, setCurrentAnalysis] = useState(null);\n\n                        const progressIntervalRef = useRef(null);\n                        const pollIntervalRef = useRef(null);\n                        const limitTimeoutRef = useRef(null);\n\n                        useEffect(() => {\n                            return () => {\n                                if (progressIntervalRef.current) clearInterval(progressIntervalRef.current);\n                                if (pollIntervalRef.current) clearInterval(pollIntervalRef.current);\n                                if (limitTimeoutRef.current) clearTimeout(limitTimeoutRef.current);\n                            };\n                        }, []);\n\n                        const coaches = ['All', 'John Doe', 'Anand Sharma', 'Sarah Johnson', 'Mike Williams', 'Lisa Chen'];\n\n                        const getDemoVideoItem = () => ({\n                            id: 'demo',\n                            user_id: 0,\n                            user_name: 'GolfAI Demo',\n                            user_email: 'demo@golfai.com',\n                            upload_timestamp: new Date().toISOString(),\n                            original_filename: 'Demo \u2014 Driver swing',\n                            storage_filename: 'swing1.mp4',\n                            file_size: 888358,\n                            mime_type: 'video\/mp4',\n                            video_duration: 6.0,\n                            thumbnail_url: `${config.homeUrl}?golf_stream_file=thumbnails%2Fdemo_user%2Fswing1_thumb.jpg`,\n                            video_url: `${config.homeUrl}?golf_stream_file=videos%2Fdemo_user%2Fswing1.mp4`,\n                            coach: 'GolfAI Demo',\n                            description: 'Shared demo golf swing analysis'\n                        });\n\n                        const fetchVideos = () => {\n                            if (!config.isLoggedIn) {\n                                setLoading(true);\n                                fetch(`${config.rootUrl}\/videos\/demo`)\n                                    .then(res => res.json())\n                                    .then(data => {\n                                        setVideos(data && data.id === 'demo' ? [data] : [getDemoVideoItem()]);\n                                        setLoading(false);\n                                    })\n                                    .catch(() => {\n                                        setVideos([getDemoVideoItem()]);\n                                        setLoading(false);\n                                    });\n                                return;\n                            }\n                            setLoading(true);\n                            fetch(`${config.rootUrl}\/videos`, {\n                                headers: {\n                                    'X-WP-Nonce': config.nonce\n                                }\n                            })\n                            .then(res => res.json())\n                            .then(data => {\n                                const items = Array.isArray(data) ? data : [];\n                                const hasDemo = items.some(v => v && v.id === 'demo');\n                                setVideos(hasDemo ? items : [getDemoVideoItem(), ...items]);\n                                setLoading(false);\n                            })\n                            .catch(() => {\n                                fetch(`${config.rootUrl}\/videos\/demo`)\n                                    .then(res => res.json())\n                                    .then(data => {\n                                        setVideos(data && data.id === 'demo' ? [data] : [getDemoVideoItem()]);\n                                        setLoading(false);\n                                    })\n                                    .catch(() => {\n                                        setVideos([getDemoVideoItem()]);\n                                        setLoading(false);\n                                    });\n                            });\n                        };\n\n                        useEffect(() => {\n                            fetchVideos();\n                        }, [user]);\n\n                        const startAiAnalysis = (video) => {\n                            if (progressIntervalRef.current) clearInterval(progressIntervalRef.current);\n                            if (pollIntervalRef.current) clearInterval(pollIntervalRef.current);\n                            if (limitTimeoutRef.current) clearTimeout(limitTimeoutRef.current);\n\n                            setAiLoading(true);\n                            setAiProgress(0);\n                            setAiStep(0);\n                            setCurrentAnalysis(null);\n                            setActiveVideo(video);\n\n                            const url = video.id === 'demo'\n                                ? `${config.rootUrl}\/videos\/demo\/analysis`\n                                : `${config.rootUrl}\/videos\/${video.id}\/analysis`;\n\n                            let lastFetchedData = null;\n                            const isDemo = video.id === 'demo';\n\n                            const triggerFallback = (fallbackData) => {\n                                if (progressIntervalRef.current) clearInterval(progressIntervalRef.current);\n                                if (pollIntervalRef.current) clearInterval(pollIntervalRef.current);\n                                if (limitTimeoutRef.current) clearTimeout(limitTimeoutRef.current);\n\n                                setAiLoading(false);\n                                \n                                if (fallbackData) {\n                                    setCurrentAnalysis(fallbackData);\n                                    setView('analysis');\n                                } else {\n                                    \/\/ Construct basic fallback analysis object if we don't have one\n                                    const basicFallback = {\n                                        video_id: video.id,\n                                        original_filename: video.original_filename,\n                                        coach_name: video.coach,\n                                        upload_timestamp: video.upload_timestamp || new Date().toISOString(),\n                                        duration: video.video_duration || 6.0,\n                                        ai_video_url: video.video_url || '',\n                                        is_fallback_video: true,\n                                        biomarkers: null,\n                                        coach_text: null\n                                    };\n                                    setCurrentAnalysis(basicFallback);\n                                    setView('analysis');\n                                }\n                            };\n\n                            if (isDemo) {\n                                \/\/ For demo video: load fast (3 seconds progress animation, total ~5 seconds)\n                                let apiFinished = false;\n                                let apiData = null;\n                                let apiError = null;\n\n                                fetch(url, {\n                                    headers: {\n                                        'X-WP-Nonce': config.nonce\n                                    }\n                                })\n                                .then(res => {\n                                    if (!res.ok) throw new Error('Failed to load analysis');\n                                    return res.json();\n                                })\n                                .then(data => {\n                                    apiData = data;\n                                    apiFinished = true;\n                                })\n                                .catch(err => {\n                                    apiError = err.message;\n                                    apiFinished = true;\n                                });\n\n                                 let currentPct = 0;\n                                 progressIntervalRef.current = setInterval(() => {\n                                     currentPct += 5; \/\/ 20 steps to reach 100% (at 80ms per step = 1600ms total)\n                                     if (currentPct >= 100) {\n                                         currentPct = 100;\n                                         clearInterval(progressIntervalRef.current);\n\n                                         \/\/ Wait for API to finish if it hasn't yet, then transition\n                                         const checkFinish = setInterval(() => {\n                                             if (apiFinished) {\n                                                clearInterval(checkFinish);\n                                                setAiLoading(false);\n                                                if (apiError) {\n                                                    alert(`Error running analysis: ${apiError}`);\n                                                } else if (apiData) {\n                                                    setCurrentAnalysis(apiData);\n                                                    setView('analysis');\n                                                }\n                                             }\n                                         }, 50);\n                                     }\n\n                                     setAiProgress(currentPct);\n\n                                     if (currentPct < 25) {\n                                         setAiStep(0);\n                                     } else if (currentPct < 50) {\n                                         setAiStep(1);\n                                     } else if (currentPct < 75) {\n                                         setAiStep(2);\n                                     } else {\n                                         setAiStep(3);\n                                     }\n                                 }, 80);\n\n                            } else {\n                                \/\/ For custom user videos: slow 10-minute loader with 15s GCS polling\n                                const checkAnalysisStatus = (isFinalTimeout = false) => {\n                                    fetch(url, {\n                                        headers: {\n                                            'X-WP-Nonce': config.nonce\n                                        }\n                                    })\n                                    .then(res => {\n                                        if (!res.ok) throw new Error('Failed to load analysis');\n                                        return res.json();\n                                    })\n                                    .then(data => {\n                                        lastFetchedData = data;\n                                        \/\/ If analysis has loaded (is_fallback_video === false means actual AI results exist)\n                                        if (data && !data.is_fallback_video) {\n                                            if (progressIntervalRef.current) clearInterval(progressIntervalRef.current);\n                                            if (pollIntervalRef.current) clearInterval(pollIntervalRef.current);\n                                            if (limitTimeoutRef.current) clearTimeout(limitTimeoutRef.current);\n\n                                            setAiProgress(100);\n                                            setAiStep(4); \/\/ Mark all steps (0-3) completed\/done\n                                            \n                                            setTimeout(() => {\n                                                setAiLoading(false);\n                                                setCurrentAnalysis(data);\n                                                setView('analysis');\n                                            }, 600);\n                                        } else if (isFinalTimeout) {\n                                            triggerFallback(data || lastFetchedData);\n                                        }\n                                    })\n                                    .catch(err => {\n                                        console.error('Error polling analysis:', err);\n                                        if (isFinalTimeout) {\n                                            triggerFallback(lastFetchedData);\n                                        }\n                                    });\n                                };\n\n                                \/\/ Check immediately first (useful if already cached\/analyzed)\n                                checkAnalysisStatus(false);\n\n                                \/\/ Slow progress animation: go from 0% to 95% over 10 minutes (600 seconds)\n                                let elapsedSeconds = 0;\n                                progressIntervalRef.current = setInterval(() => {\n                                    elapsedSeconds++;\n                                    if (elapsedSeconds >= 600) {\n                                        clearInterval(progressIntervalRef.current);\n                                        return;\n                                    }\n\n                                    const baseProgress = elapsedSeconds * (95 \/ 600);\n                                    \/\/ Small fluctuations to make it feel natural\n                                    const fluctuation = Math.sin(elapsedSeconds * 0.1) * 0.4;\n                                    const currentPct = Math.min(95, Math.max(0, baseProgress + fluctuation));\n\n                                    setAiProgress(currentPct);\n\n                                    if (currentPct < 25) {\n                                        setAiStep(0);\n                                    } else if (currentPct < 50) {\n                                        setAiStep(1);\n                                    } else if (currentPct < 75) {\n                                        setAiStep(2);\n                                    } else {\n                                        setAiStep(3);\n                                    }\n                                }, 1000);\n\n                                \/\/ Background job checking GCS (polling status every 15 seconds)\n                                pollIntervalRef.current = setInterval(() => {\n                                    checkAnalysisStatus(false);\n                                }, 15000);\n\n                                \/\/ 10 minutes absolute timeout fallback\n                                limitTimeoutRef.current = setTimeout(() => {\n                                    checkAnalysisStatus(true);\n                                }, 600000);\n                            }\n                        };\n\n                        const filteredVideos = videos.filter(v => {\n                            const matchCoach = activeCoach === 'All' || v.coach === activeCoach;\n                            const matchSearch = v.original_filename.toLowerCase().includes(search.toLowerCase());\n                            return matchCoach && matchSearch;\n                        });\n\n                        if (config.isLoggedIn && !user) {\n                            return h('div', { className: 'auth-container' },\n                                h('div', { className: 'auth-card', style: { textAlign: 'center', padding: '40px' } },\n                                    h('div', { className: 'auth-logo' }, '\u26f3 GolfAI'),\n                                    h('h2', { className: 'auth-title' }, 'Session Expired'),\n                                    h('p', { className: 'auth-subtitle' }, 'Please log in again or reload the page to access your AI Swing analysis.'),\n                                    h('button', { \n                                        onClick: () => window.location.reload(),\n                                        className: 'submit-upload-btn',\n                                        style: { marginTop: '16px' }\n                                    }, 'Reload Page')\n                                )\n                            );\n                        }\n\n                        if (view === 'analysis' && currentAnalysis) {\n                            return h('div', { className: 'library-layout' },\n                                h(AnalysisView, {\n                                    analysisData: currentAnalysis,\n                                    onBackClick: () => {\n                                        setView(config.isLoggedIn ? 'library' : 'login');\n                                        setActiveVideo(null);\n                                    },\n                                    onSignInClick: () => {\n                                        setView('login');\n                                        setActiveVideo(null);\n                                    }\n                                })\n                            );\n                        }\n\n                        return h('div', { className: 'library-layout' },\n                            \/\/ Header \/ Navbar\n                            view !== 'login' && h('div', { className: 'library-header' },\n                                h('div', { className: 'library-header-content' },\n                                    h('h1', { className: 'library-title' }, '\ud83d\udcda AI Swing analysis'),\n                                    h('div', { className: 'header-actions' },\n                                        config.isLoggedIn\n                                            ? h(React.Fragment, null,\n                                                h('div', { className: 'user-profile-badge' },\n                                                    user && user.picture && h('img', { src: user.picture, alt: user.name }),\n                                                    h('span', null, user && user.name)\n                                                ),\n                                                view === 'library' && h('button', {\n                                                    onClick: () => setView('upload'),\n                                                    className: 'nav-upload-btn'\n                                                }, h(Plus), ' Upload Video')\n                                            )\n                                            : (view === 'library'\n                                                ? h(React.Fragment, null,\n                                                    h('button', {\n                                                        onClick: () => setView('login'),\n                                                        className: 'nav-upload-btn'\n                                                    }, h(Plus), ' Upload Video'),\n                                                    h('button', {\n                                                        onClick: () => setView('login'),\n                                                        className: 'nav-upload-btn nav-signin-btn'\n                                                    }, 'Sign In')\n                                                )\n                                                : h('button', {\n                                                    onClick: () => setView('library'),\n                                                    className: 'nav-upload-btn nav-signin-btn'\n                                                }, 'Back to Gallery')\n                                            )\n                                    )\n                                )\n                            ),\n\n                            view === 'login' && h(LoginView, {\n                                socialLoginHtml: config.socialLoginHtml,\n                                onTryDemoClick: () => startAiAnalysis(getDemoVideoItem()),\n                                demoVideo: videos.find(v => v.id === 'demo') || getDemoVideoItem()\n                            }),\n\n                            view === 'upload' && h(Uploader, {\n                                onBackClick: () => setView('library'),\n                                onUploadComplete: (newVideo) => {\n                                    setVideos([newVideo, ...videos]);\n                                    setView('library');\n                                }\n                            }),\n\n                            view === 'library' && h('div', { className: 'library-content' },\n                                \/\/ Filters & Search\n                                h('div', { className: 'filters-wrapper' },\n                                    \/\/ Search\n                                    h('div', { className: 'search-box' },\n                                        h(Search),\n                                        h('input', {\n                                            type: 'text',\n                                            placeholder: 'Search videos...',\n                                            value: search,\n                                            onChange: (e) => setSearch(e.target.value)\n                                        })\n                                    ),\n                                    \/\/ Coaches\n                                    h('div', { className: 'coach-filter-bar' },\n                                        coaches.map(c => h('button', {\n                                            key: c,\n                                            onClick: () => setActiveCoach(c),\n                                            className: `coach-filter-tab ${activeCoach === c ? 'active' : ''}`\n                                        }, c))\n                                    )\n                                ),\n\n                                \/\/ Grid\n                                loading ? h('div', { className: 'loading-state' }, h(Loader), ' Fetching videos...') :\n                                filteredVideos.length > 0 ? h('div', { className: 'video-grid' },\n                                    [\n                                        ...filteredVideos.map(v => h(VideoCard, {\n                                            key: v.id,\n                                            video: v,\n                                            onClick: setActiveVideo,\n                                            onAiClick: startAiAnalysis\n                                        })),\n                                        (config.isLoggedIn && videos.filter(v => v && v.id !== 'demo').length === 0) && h('div', { key: 'empty-placeholder', className: 'empty-placeholder-card' },\n                                            h('div', { className: 'ep-icon' }, '\ud83c\udfcc\ufe0f\u200d\u2642\ufe0f'),\n                                            h('p', { className: 'ep-text' }, 'No videos yet : upload a video to get personalised AI analysis')\n                                        )\n                                    ]\n                                ) : h('div', { className: 'empty-state' },\n                                    h('div', { className: 'empty-icon' }, '\ud83d\udcc2'),\n                                    h('p', { className: 'empty-title' }, 'No videos found'),\n                                    h('p', { className: 'empty-sub' }, 'Upload a video to assign it to your coach and get feedback.')\n                                )\n                            ),\n\n                            \/\/ Video Overlay Modal Player (Normal Interaction)\n                            activeVideo && !aiLoading && h('div', { className: 'video-modal-overlay', onClick: () => setActiveVideo(null) },\n                                h('div', { className: 'video-modal-container', onClick: (e) => e.stopPropagation() },\n                                    h('button', { className: 'modal-close-btn', onClick: () => setActiveVideo(null) }, '\u2715'),\n                                    h('h3', { className: 'modal-video-title' }, activeVideo.original_filename),\n                                    h('div', { className: 'modal-video-player-wrapper' },\n                                        h('video', {\n                                            src: activeVideo.video_url,\n                                            controls: true,\n                                            autoPlay: true,\n                                            className: 'modal-preview-video-player'\n                                        })\n                                    ),\n                                    h('div', { className: 'modal-video-meta' },\n                                        h('p', null, h('strong', null, 'Coach:'), ' ', activeVideo.coach),\n                                        h('p', null, h('strong', null, 'Uploaded:'), ' ', new Date(activeVideo.upload_timestamp.replace(' ', 'T')).toLocaleString()),\n                                        activeVideo.description && h('p', { className: 'modal-video-desc' }, \n                                            h('strong', null, 'Description:'), ' ', activeVideo.description\n                                        )\n                                    )\n                                )\n                            ),\n\n                            \/\/ AI Loading Overlay\n                            h(AiLoadingOverlay, {\n                                show: aiLoading,\n                                progress: aiProgress,\n                                activeStep: aiStep\n                            })\n                        );\n                    };\n                    \n                    \/\/ Mount App\n                    if (window.React && window.ReactDOM) {\n                        const root = ReactDOM.createRoot(container);\n                        root.render(h(App));\n                    }\n                };\n                \n                \/\/ Auto-init\n                if (document.readyState === 'loading') {\n                    document.addEventListener('DOMContentLoaded', function() {\n                        if (window.React && window.ReactDOM) {\n                            window.initGolfLibrary();\n                        }\n                    });\n                } else {\n                    if (window.React && window.ReactDOM) {\n                        window.initGolfLibrary();\n                    }\n                }\n            })();\n            <\/script>\n            \n","protected":false},"excerpt":{"rendered":"","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"footnotes":""},"class_list":["post-1860","page","type-page","status-publish","hentry"],"_links":{"self":[{"href":"https:\/\/devenv1.golfai.in\/hi\/wp-json\/wp\/v2\/pages\/1860","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devenv1.golfai.in\/hi\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/devenv1.golfai.in\/hi\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/devenv1.golfai.in\/hi\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/devenv1.golfai.in\/hi\/wp-json\/wp\/v2\/comments?post=1860"}],"version-history":[{"count":1,"href":"https:\/\/devenv1.golfai.in\/hi\/wp-json\/wp\/v2\/pages\/1860\/revisions"}],"predecessor-version":[{"id":2106,"href":"https:\/\/devenv1.golfai.in\/hi\/wp-json\/wp\/v2\/pages\/1860\/revisions\/2106"}],"wp:attachment":[{"href":"https:\/\/devenv1.golfai.in\/hi\/wp-json\/wp\/v2\/media?parent=1860"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}