/**
 * DemoPortal — Main landing + dashboard page for the public demo.
 * Single scrollable page: personal intro, info tabs, entry row, game cards.
 * When logged in with an account (window.PLAYER), adds Game History / Feedback / Account tabs.
 * No separate player dashboard — everything in one place.
 */
var DemoPortal = (function() {
    'use strict';
    var h = React.createElement;
    var useState = React.useState;
    var useEffect = React.useEffect;

    var GAMES = [
        {
            id: 'rds2d',
            name: 'RDS Convergence',
            description: 'The core vergence therapy app. Random dot stereograms test and train binocular fusion \u2014 if you can\'t fuse, you can\'t see the hidden shape.',
            tag: 'production',
            tagLabel: 'In Production',
            color: '#1a3a2a',
            image: '/images/game-rds.png',
            meta: { type: '2D Stereogram', mode: 'Vergence Therapy' }
        },
        {
            id: 'base',
            name: 'Base Builder',
            description: 'Sort 3D shapes by matching them to their silhouettes. Perspective depth and anaglyph RDS rendering train vergence through gameplay.',
            tag: 'prototype',
            tagLabel: 'Prototype',
            color: '#2a2a1a',
            image: '/images/game-base.png',
            meta: { type: '3D Perspective', mode: 'Shape Sorting' }
        },
        {
            id: 'balloon',
            name: 'Balloon Pop',
            description: 'Match symbols on balloons floating at different depths. Silhouette-based RDS rendering makes fusion essential to identify targets.',
            tag: 'prototype',
            tagLabel: 'Prototype',
            color: '#2a1a2a',
            image: '/images/game-balloon.png',
            meta: { type: 'RDS Silhouette', mode: 'Symbol Matching' }
        },
        {
            id: 'animal',
            name: 'Animal Cart',
            description: 'Guess which animal is hidden behind the cart using depth cues. A playful guessing mechanic built on stereoscopic rendering.',
            tag: 'prototype',
            tagLabel: 'Prototype',
            color: '#1a2a3a',
            image: '/images/game-animal.png',
            meta: { type: 'RDS Depth', mode: 'Guessing Game' }
        }
    ];

    var INFO_TABS = [
        {
            id: 'project',
            label: 'My Project',
            rich: true
        },
        {
            id: 'nvi',
            label: 'NVI Institute',
            rich: true
        },
        {
            id: 'rds',
            label: 'How RDS Works',
            content: 'Random Dot Stereograms (RDS) are images made of random dots that look flat to each eye alone, ' +
                'but reveal a hidden 3D shape when both eyes fuse them together. This is the gold standard for testing ' +
                'true binocular depth perception \u2014 you literally cannot cheat it with monocular cues. ' +
                'Our games use this principle: if you can\u2019t fuse, you can\u2019t play.'
        },
        {
            id: 'positioning',
            label: 'Where We Sit',
            content: 'Most vision therapy software is clinical and repetitive \u2014 effective but not engaging for kids. ' +
                'Commercial "eye training" apps often lack clinical rigor. We sit in the middle: games that are fun enough ' +
                'to motivate daily practice, but grounded in real therapeutic protocols defined by optometrists. ' +
                'Every game mechanic maps to a specific clinical objective.'
        }
    ];

    function renderProjectTab() {
        return h('div', { className: 'dp-info-rich' },
            h('div', { className: 'dp-info-media' },
                h('img', {
                    src: 'https://images.squarespace-cdn.com/content/v1/5414cc37e4b06505bdaf2198/1519889088878-CD2E47PD0XUHPSKWG6VH/BoxScene_affixed_GIF_1.gif',
                    alt: 'Parallax depth illusion demo',
                    className: 'dp-info-gif'
                }),
                h('p', { className: 'dp-info-caption' },
                    'Stereoscopic depth perception: the same principle our games use to train binocular fusion.'
                )
            ),
            h('p', null,
                'This is my Master\u2019s thesis at the University of Washington Bothell (CSS 595). ' +
                'I\u2019m building interactive vision therapy games that use stereoscopic depth \u2014 random dot stereograms ' +
                'and 3D rendered scenes \u2014 to train binocular fusion in children with convergence insufficiency. ' +
                'The goal is to make prescribed therapy feel like play, so kids actually want to do their exercises.'
            ),
            h('p', null,
                'Convergence insufficiency affects roughly 5\u201313% of school-age children, causing headaches, ' +
                'double vision, and difficulty reading. Traditional therapy works but relies on repetitive clinical exercises ' +
                'that kids struggle to stay motivated with \u2014 especially for the at-home sessions that are critical for progress. ' +
                'By embedding the same therapeutic mechanisms into engaging games, we can improve compliance and potentially outcomes.'
            ),
            h('p', null,
                'My work spans the full stack \u2014 from 3D rendering with anaglyph stereograms, to a PHP/MySQL REST API, ' +
                'to a React clinician dashboard \u2014 all integrated with the Near Vision Institute\u2019s existing clinical platform. ' +
                'The games are already being evaluated alongside production therapy data.'
            ),
            h('div', { className: 'dp-info-cta' },
                h('a', {
                    href: 'https://1drv.ms/w/c/7cfd942d2c564c98/IQDS9_WrQg5tTpK77605SYKsAQFr8Gkp9IXtKjRxBjRf93E?e=wUsack',
                    target: '_blank',
                    rel: 'noopener',
                    className: 'dp-info-paper-link'
                },
                    '\uD83D\uDCC4 Read my thesis paper (draft) \u2014 comments welcome'
                )
            )
        );
    }

    function renderNviTab() {
        return h('div', { className: 'dp-info-rich' },
            h('div', { className: 'dp-nvi-team-wrap' },
                h('img', {
                    src: '/images/nvi-team.jpg',
                    alt: 'Near Vision Institute team',
                    className: 'dp-nvi-team-photo'
                }),
                h('p', { className: 'dp-info-caption' },
                    'The EYE Toolbox research group at the Near Vision Institute.'
                )
            ),
            h('div', { className: 'dp-nvi-header' },
                h('img', {
                    src: '/images/dr-pearson.png',
                    alt: 'Dr. Alan Pearson',
                    className: 'dp-nvi-photo'
                }),
                h('div', null,
                    h('p', null,
                        'The Near Vision Institute (NVI) is our clinical partner, led by ',
                        h('strong', null, 'Dr. Alan Pearson, OD, MEd, PhD, FCOVD'),
                        '. Dr. Pearson has decades of experience in developmental optometry and vision therapy, ' +
                        'and his expertise grounds every design decision in this project.'
                    ),
                    h('p', null,
                        'NVI defines the therapeutic objectives \u2014 vergence ranges, fusion demands, progression criteria \u2014 ' +
                        'and we build the technology to deliver them. Every game mechanic maps directly to a clinical protocol ' +
                        'that NVI uses with real patients.'
                    )
                )
            )
        );
    }

    var SURVEY_QUESTIONS = [
        { key: 'q1', text: 'How easy was it to understand what to do?', lo: 'Very hard', hi: 'Very easy' },
        { key: 'q2', text: 'How much did you enjoy the experience?', lo: 'Not at all', hi: 'A lot' },
        { key: 'q3', text: 'Would you use this again?', lo: 'Definitely not', hi: 'Definitely yes' },
        { key: 'q4', text: 'How clear were the visuals?', lo: 'Very unclear', hi: 'Very clear' }
    ];

    function gameNameLabel(id) {
        var match = GAMES.find(function(g) { return g.id === id; });
        return match ? match.name : id;
    }
    function formatDate(ts) {
        if (!ts) return '';
        var d = new Date(ts * 1000);
        return d.toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' });
    }
    function formatDuration(sec) {
        if (!sec || sec < 1) return '--';
        var m = Math.floor(sec / 60), s = sec % 60;
        return m + ':' + (s < 10 ? '0' : '') + s;
    }

    function DemoPortal() {
        var player = window.PLAYER || null;

        var userState = useState(window.DEMO_USER);
        var user = userState[0], setUser = userState[1];
        var nameInputState = useState('');
        var nameInput = nameInputState[0], setNameInput = nameInputState[1];
        var viewState = useState('portal');
        var view = viewState[0], setView = viewState[1];
        var gameState = useState(null);
        var activeGame = gameState[0], setActiveGame = gameState[1];
        var surveyState = useState({});
        var survey = surveyState[0], setSurvey = surveyState[1];
        var surveyComment = useState('');
        var surveyCommentVal = surveyComment[0], setSurveyComment = surveyComment[1];
        var registering = useState(false);
        var isRegistering = registering[0], setRegistering = registering[1];
        var regError = useState('');
        var regErrorMsg = regError[0], setRegError = regError[1];

        // Info tab expansion
        var activeInfoState = useState(null);
        var activeInfo = activeInfoState[0], setActiveInfo = activeInfoState[1];

        // Account tab (only for logged-in players)
        var acctTabState = useState(null);
        var acctTab = acctTabState[0], setAcctTab = acctTabState[1];

        // Account data
        var sessionsState = useState(null);
        var sessions = sessionsState[0], setSessions = sessionsState[1];
        var surveysState = useState(null);
        var surveys = surveysState[0], setSurveys = surveysState[1];
        var feedbacksState = useState(null);
        var feedbacks = feedbacksState[0], setFeedbacks = feedbacksState[1];

        // Nav dropdown
        var dropdownState = useState(false);
        var showDropdown = dropdownState[0], setShowDropdown = dropdownState[1];

        // (IP-based detection removed — same IP in incognito defeats the purpose)

        // Check for ?survey= param (returning from a game)
        useEffect(function() {
            var params = new URLSearchParams(window.location.search);
            var surveyGame = params.get('survey');
            if (surveyGame && (user || player)) {
                var match = GAMES.find(function(g) { return g.id === surveyGame; });
                if (match) {
                    setActiveGame(match);
                    setView('survey');
                    window.history.replaceState({}, '', '/demo-portal');
                }
            }
        }, [user]);

        // Try to resume from localStorage
        useEffect(function() {
            if (user || player) return;
            var token = localStorage.getItem('demo_token');
            if (token) {
                fetch(window.DEMO_API + '?action=resume', {
                    method: 'POST',
                    headers: { 'Content-Type': 'application/json' },
                    body: JSON.stringify({ token: token })
                })
                .then(function(r) { return r.ok ? r.json() : null; })
                .then(function(data) {
                    if (data) setUser(data);
                })
                .catch(function() {});
            }
        }, []);

        // (IP check removed — same IP in incognito prevented clean logged-out view)

        // Load account data when account tab opened
        useEffect(function() {
            if (!player && !user) return;
            if (acctTab === 'history' && sessions === null) {
                fetch(window.DEMO_API + '?action=player_sessions', {
                    method: 'POST',
                    headers: { 'Content-Type': 'application/json' },
                    body: JSON.stringify({})
                })
                .then(function(r) { return r.json(); })
                .then(function(data) { setSessions(data.sessions || []); })
                .catch(function() { setSessions([]); });
            }
            if (acctTab === 'feedback' && surveys === null) {
                fetch(window.DEMO_API + '?action=player_surveys', {
                    method: 'POST',
                    headers: { 'Content-Type': 'application/json' },
                    body: JSON.stringify({})
                })
                .then(function(r) { return r.json(); })
                .then(function(data) {
                    setSurveys(data.surveys || []);
                    setFeedbacks(data.feedback || []);
                })
                .catch(function() { setSurveys([]); setFeedbacks([]); });
            }
        }, [acctTab]);

        // Close dropdown when clicking outside
        useEffect(function() {
            if (!showDropdown) return;
            function close() { setShowDropdown(false); }
            document.addEventListener('click', close);
            return function() { document.removeEventListener('click', close); };
        }, [showDropdown]);

        function handleQuickRegister() {
            if (isRegistering) return;
            setRegistering(true);
            setRegError('');
            fetch(window.DEMO_API + '?action=register', {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({ name: nameInput.trim() })
            })
            .then(function(r) { return r.json(); })
            .then(function(data) {
                localStorage.setItem('demo_token', data.token);
                setUser(data);
                setRegistering(false);
            })
            .catch(function() { setRegistering(false); });
        }

        function launchGame(game) {
            if (!user && !player) {
                setRegistering(true);
                fetch(window.DEMO_API + '?action=register', {
                    method: 'POST',
                    headers: { 'Content-Type': 'application/json' },
                    body: JSON.stringify({ name: nameInput.trim() })
                })
                .then(function(r) { return r.json(); })
                .then(function(data) {
                    localStorage.setItem('demo_token', data.token);
                    setUser(data);
                    setRegistering(false);
                    fetch(window.DEMO_API + '?action=session_start', {
                        method: 'POST',
                        headers: { 'Content-Type': 'application/json' },
                        body: JSON.stringify({ gameName: game.id })
                    })
                    .then(function() { window.location.href = '/demo-game.php?game=' + game.id; })
                    .catch(function() { window.location.href = '/demo-game.php?game=' + game.id; });
                })
                .catch(function() {
                    setRegistering(false);
                    window.location.href = '/demo-game.php?game=' + game.id;
                });
                return;
            }
            setActiveGame(game);
            fetch(window.DEMO_API + '?action=session_start', {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({ gameName: game.id })
            })
            .then(function() { window.location.href = '/demo-game.php?game=' + game.id; })
            .catch(function() { window.location.href = '/demo-game.php?game=' + game.id; });
        }

        function handleSurveyAnswer(key, val) {
            var next = Object.assign({}, survey);
            next[key] = val;
            setSurvey(next);
        }

        function submitSurvey() {
            fetch(window.DEMO_API + '?action=survey', {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({
                    gameName: activeGame ? activeGame.id : '',
                    q1: survey.q1 || null, q2: survey.q2 || null,
                    q3: survey.q3 || null, q4: survey.q4 || null,
                    q5: surveyCommentVal
                })
            }).then(function() {
                setView('portal'); setActiveGame(null);
                setSurvey({}); setSurveyComment('');
            });
        }

        // ── Survey overlay ──
        if (view === 'survey' && activeGame) {
            return h('div', null,
                renderNav(user, player, showDropdown, setShowDropdown, setAcctTab),
                h('div', { className: 'dp-modal-overlay' },
                    h('div', { className: 'dp-modal dp-survey' },
                        h('h2', null, 'Quick Feedback'),
                        h('p', null, 'How was your experience with ' + activeGame.name + '?'),
                        SURVEY_QUESTIONS.map(function(q) {
                            return h('div', { key: q.key, className: 'dp-survey-q' },
                                h('p', null, q.text),
                                h('div', { className: 'dp-survey-scale' },
                                    [1, 2, 3, 4, 5].map(function(n) {
                                        return h('button', {
                                            key: n,
                                            className: survey[q.key] === n ? 'selected' : '',
                                            onClick: function() { handleSurveyAnswer(q.key, n); }
                                        }, n);
                                    })
                                ),
                                h('div', { className: 'dp-survey-labels' },
                                    h('span', null, q.lo), h('span', null, q.hi)
                                )
                            );
                        }),
                        h('div', { className: 'dp-survey-q' },
                            h('p', null, 'Any other thoughts?'),
                            h('textarea', {
                                style: {
                                    width: '100%', padding: '8px 10px', background: '#0f0f1a',
                                    border: '1px solid #2a2a3e', borderRadius: '6px', color: '#e0e0e0',
                                    fontSize: '13px', fontFamily: 'inherit', minHeight: '60px',
                                    outline: 'none', resize: 'vertical'
                                },
                                value: surveyCommentVal,
                                onChange: function(e) { setSurveyComment(e.target.value); },
                                placeholder: 'Optional...'
                            })
                        ),
                        h('div', { style: { display: 'flex', gap: '8px', marginTop: '8px' } },
                            h('button', {
                                className: 'dp-modal-btn', style: { flex: 1, background: '#333' },
                                onClick: function() { setView('portal'); setActiveGame(null); setSurvey({}); }
                            }, 'Skip'),
                            h('button', {
                                className: 'dp-modal-btn', style: { flex: 1 },
                                onClick: submitSurvey
                            }, 'Submit')
                        )
                    )
                ),
                h(FeedbackWidget, { gameName: activeGame.name })
            );
        }

        // ── Build account tab content ──
        var accountContent = null;
        if ((player || user) && acctTab) {
            if (acctTab === 'history') {
                if (sessions === null) {
                    accountContent = h('div', { className: 'dp-loading' }, 'Loading...');
                } else if (sessions.length === 0) {
                    accountContent = h('div', { className: 'dp-empty' }, 'No game sessions yet. Play a game to see your history!');
                } else {
                    accountContent = h('div', { className: 'dp-account-card' },
                        h('h3', null, 'Recent Sessions'),
                        sessions.map(function(s, i) {
                            return h('div', { key: i, className: 'dp-session-row' },
                                h('div', null,
                                    h('div', { className: 'dp-session-game' }, gameNameLabel(s.GameName)),
                                    h('div', { className: 'dp-session-meta' }, formatDate(s.StartTime))
                                ),
                                h('span', { className: 'dp-session-duration' }, formatDuration(s.Duration))
                            );
                        })
                    );
                }
            } else if (acctTab === 'feedback') {
                if (surveys === null) {
                    accountContent = h('div', { className: 'dp-loading' }, 'Loading...');
                } else if (surveys.length === 0 && (!feedbacks || feedbacks.length === 0)) {
                    accountContent = h('div', { className: 'dp-empty' }, 'No feedback submitted yet. Play a game and share your thoughts!');
                } else {
                    var parts = [];
                    if (feedbacks && feedbacks.length > 0) {
                        parts.push(h('h3', { key: 'fh' }, 'Feedback'));
                        feedbacks.forEach(function(f, i) {
                            parts.push(h('div', { key: 'f' + i, className: 'dp-survey-row' },
                                h('div', { className: 'dp-survey-header' },
                                    h('span', { className: 'dp-survey-game-label' },
                                        f.FeedbackType.charAt(0).toUpperCase() + f.FeedbackType.slice(1)
                                    ),
                                    h('span', { className: 'dp-survey-date' }, formatDate(f.Timestamp))
                                ),
                                f.Rating ? h('div', { className: 'dp-survey-scores' },
                                    h('span', { className: 'dp-survey-score' }, 'Rating: ' + f.Rating + '/5')
                                ) : null,
                                f.Comment ? h('div', { style: { fontSize: '12px', color: '#aaa', marginTop: '4px', fontStyle: 'italic' } },
                                    '"' + f.Comment + '"'
                                ) : null
                            ));
                        });
                    }
                    if (surveys.length > 0) {
                        parts.push(h('h3', { key: 'sh', style: feedbacks && feedbacks.length > 0 ? { marginTop: '16px' } : null }, 'Survey Responses'));
                        surveys.forEach(function(s, i) {
                            parts.push(h('div', { key: 's' + i, className: 'dp-survey-row' },
                                h('div', { className: 'dp-survey-header' },
                                    h('span', { className: 'dp-survey-game-label' }, gameNameLabel(s.GameName)),
                                    h('span', { className: 'dp-survey-date' }, formatDate(s.Timestamp))
                                ),
                                h('div', { className: 'dp-survey-scores' },
                                    s.Q1_Ease ? h('span', { className: 'dp-survey-score' }, 'Ease: ' + s.Q1_Ease + '/5') : null,
                                    s.Q2_Enjoyment ? h('span', { className: 'dp-survey-score' }, 'Enjoy: ' + s.Q2_Enjoyment + '/5') : null,
                                    s.Q3_Reuse ? h('span', { className: 'dp-survey-score' }, 'Reuse: ' + s.Q3_Reuse + '/5') : null,
                                    s.Q4_Visual ? h('span', { className: 'dp-survey-score' }, 'Visual: ' + s.Q4_Visual + '/5') : null
                                ),
                                s.Q5_Comment ? h('div', { style: { fontSize: '12px', color: '#aaa', marginTop: '4px', fontStyle: 'italic' } },
                                    '"' + s.Q5_Comment + '"'
                                ) : null
                            ));
                        });
                    }
                    accountContent = h('div', { className: 'dp-account-card' }, parts);
                }
            } else if (acctTab === 'account') {
                accountContent = h('div', { className: 'dp-account-card' },
                    h('h3', null, 'Account Details'),
                    h('div', { className: 'dp-account-row' },
                        h('span', { className: 'dp-account-label' }, 'Name'),
                        h('span', { className: 'dp-account-value' }, player.name)
                    ),
                    h('div', { className: 'dp-account-row' },
                        h('span', { className: 'dp-account-label' }, 'Email'),
                        h('span', { className: 'dp-account-value' }, player.email)
                    ),
                    h('div', { className: 'dp-account-row' },
                        h('span', { className: 'dp-account-label' }, 'Account ID'),
                        h('span', { className: 'dp-account-value' }, player.accountId)
                    )
                );
            }
        }

        // ── Info tab content ──
        var activeInfoContent = null;
        if (activeInfo) {
            var tabData = INFO_TABS.find(function(t) { return t.id === activeInfo; });
            if (tabData) {
                if (activeInfo === 'project') {
                    activeInfoContent = h('div', { className: 'dp-info-content' }, renderProjectTab());
                } else if (activeInfo === 'nvi') {
                    activeInfoContent = h('div', { className: 'dp-info-content' }, renderNviTab());
                } else {
                    activeInfoContent = h('div', { className: 'dp-info-content' },
                        h('p', null, tabData.content)
                    );
                }
            }
        }

        var displayName = player ? (player.firstName || player.name) :
                          (user ? (user.nickname || 'Guest') : null);

        return h('div', null,
            renderNav(user, player, showDropdown, setShowDropdown, setAcctTab),

            // ── Personal Intro ──
            h('div', { className: 'dp-intro' },
                h('div', { className: 'dp-intro-inner' },
                    h('img', { className: 'dp-intro-avatar', src: '/images/josiah.jpg', alt: 'Josiah Zacharias' }),
                    h('div', { className: 'dp-intro-text' },
                        h('p', null,
                            'Thank you for being willing to help me test my optometric tools to help expand vision therapy to kids who need it.'
                        ),
                        h('div', { className: 'dp-intro-byline' }, '\u2014 Josiah Zacharias, UW Bothell')
                    )
                )
            ),

            // ── Info Tabs ──
            h('div', { className: 'dp-info-section' },
                h('div', { className: 'dp-info-tabs' },
                    INFO_TABS.map(function(tab) {
                        return h('button', {
                            key: tab.id,
                            className: 'dp-info-tab' + (activeInfo === tab.id ? ' active' : ''),
                            onClick: function() { setActiveInfo(activeInfo === tab.id ? null : tab.id); }
                        }, tab.label);
                    })
                ),
                activeInfoContent
            ),

            // ── Explanatory paragraph ──
            h('div', { className: 'dp-explain' },
                h('p', null,
                    'This demo page lets you try the vision therapy games I\u2019m building for my thesis. ' +
                    'Your feedback helps fill in critical data gaps \u2014 every session you play and every survey you complete ' +
                    'contributes directly to the research. You can play as a guest or create an account to track your progress.'
                )
            ),

            // ── Entry Row (guests) or Welcome (logged in) ──
            !user && !player ? h('div', { className: 'dp-entry-section' },
                regErrorMsg ? h('div', { className: 'dp-welcome-error' }, regErrorMsg) : null,
                h('div', { className: 'dp-entry-row' },
                    h('input', {
                        type: 'text',
                        className: 'dp-entry-input',
                        placeholder: 'Name or email (optional)',
                        value: nameInput,
                        maxLength: 100,
                        onChange: function(e) { setNameInput(e.target.value); },
                        onKeyDown: function(e) { if (e.key === 'Enter') handleQuickRegister(); }
                    }),
                    h('a', {
                        href: '/public/httpdocs/about/NearVisionInstitute/Company/signup.php',
                        className: 'dp-entry-btn dp-entry-btn-create'
                    }, 'Create Account'),
                    h('a', {
                        href: '/public/httpdocs/about/NearVisionInstitute/Company/signin.php',
                        className: 'dp-entry-btn dp-entry-btn-login'
                    }, 'Login')
                ),
                h('p', { className: 'dp-entry-hint' },
                    'Or just click a game below to start playing immediately.'
                )
            ) : (user && !player) ? h('div', { className: 'dp-entry-section dp-entry-loggedin' },
                h('p', null,
                    'Playing as ', h('strong', null, displayName), '. ',
                    h('a', {
                        href: '/public/httpdocs/about/NearVisionInstitute/Company/signup.php',
                        className: 'dp-welcome-link'
                    }, 'Create a full account'),
                    ' to save your progress.'
                )
            ) : null,

            // ── Account Tabs (anyone with a session — guest or logged-in) ──
            (player || user) ? h('div', { className: 'dp-account-section' },
                h('div', { className: 'dp-account-tabs' },
                    [
                        { id: 'history', label: 'Game History' },
                        { id: 'feedback', label: 'My Feedback' },
                        player ? { id: 'account', label: 'Account' } : null
                    ].filter(Boolean).map(function(t) {
                        return h('button', {
                            key: t.id,
                            className: 'dp-account-tab' + (acctTab === t.id ? ' active' : ''),
                            onClick: function() { setAcctTab(acctTab === t.id ? null : t.id); }
                        }, t.label);
                    })
                ),
                accountContent
            ) : null,

            // ── Game Cards ──
            h('div', { className: 'dp-games-heading' },
                h('h2', null, 'Try the Games')
            ),
            h('div', { className: 'dp-games' },
                GAMES.map(function(game) {
                    return h('div', {
                        key: game.id,
                        className: 'dp-game-card',
                        onClick: function() { launchGame(game); }
                    },
                        h('div', {
                            className: 'dp-game-preview',
                            style: { background: game.color }
                        },
                            h('img', { src: game.image, alt: game.name, className: 'dp-game-screenshot' }),
                            h('span', {
                                className: 'dp-game-tag ' +
                                    (game.tag === 'production' ? 'dp-game-tag-production' : 'dp-game-tag-prototype')
                            }, game.tagLabel)
                        ),
                        h('div', { className: 'dp-game-info' },
                            h('h3', null, game.name),
                            h('p', null, game.description),
                            h('div', { className: 'dp-game-meta' },
                                h('span', null, '\u25C6 ' + game.meta.type),
                                h('span', null, '\u25B6 ' + game.meta.mode)
                            )
                        )
                    );
                })
            ),

            h('div', { className: 'dp-footer' },
                'EYE Toolbox \u00B7 University of Washington Bothell \u00B7 ',
                h('a', { href: 'https://www.uwb.edu', target: '_blank', rel: 'noopener' }, 'uwb.edu')
            ),
            h(FeedbackWidget, { gameName: '' })
        );
    }

    function renderNav(user, player, showDropdown, setShowDropdown, setAcctTab) {
        var loggedIn = player || (user && user.nickname);
        var name = player ? player.name : (user ? user.nickname : null);
        var initials = name ? name.charAt(0).toUpperCase() : null;

        return h('nav', { className: 'dp-nav' },
            h('a', { href: '/demo-portal', className: 'dp-nav-brand' },
                h('svg', { viewBox: '0 0 24 24', fill: 'none', stroke: 'currentColor', strokeWidth: '2' },
                    h('circle', { cx: '12', cy: '12', r: '3' }),
                    h('path', { d: 'M1 12s4-7 11-7 11 7 11 7-4 7-11 7-11-7-11-7' })
                ),
                'EYE Toolbox'
            ),
            h('div', { className: 'dp-nav-right' },
                loggedIn ? h('div', { className: 'dp-nav-user-wrap' },
                    h('div', {
                        className: 'dp-nav-user',
                        onClick: function(e) { e.stopPropagation(); setShowDropdown(!showDropdown); }
                    },
                        h('div', { className: 'dp-nav-avatar' }, initials),
                        h('strong', null, name)
                    ),
                    showDropdown ? h('div', { className: 'dp-nav-dropdown', onClick: function(e) { e.stopPropagation(); } },
                        player ? h('button', { onClick: function() { setAcctTab('history'); setShowDropdown(false); } }, 'Game History') : null,
                        player ? h('button', { onClick: function() { setAcctTab('feedback'); setShowDropdown(false); } }, 'My Feedback') : null,
                        player ? h('button', { onClick: function() { setAcctTab('account'); setShowDropdown(false); } }, 'Account') : null,
                        !player ? h('a', { href: '/public/httpdocs/about/NearVisionInstitute/Company/signup.php' }, 'Create Account') : null,
                        h('div', { className: 'dp-dropdown-divider' }),
                        h('a', { href: '/logout.php', className: 'dp-dropdown-signout' }, 'Sign Out')
                    ) : null
                ) : null
            )
        );
    }

    return DemoPortal;
})();
