<!--
Copyright (C) 2026 by WallyHackenslacker wallyhackenslacker@noreply.git.hackenslacker.space

Permission to use, copy, modify, and/or distribute this software for any purpose with or without
fee is hereby granted.

THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
OF THIS SOFTWARE.
-->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Lutris Playtime Report</title>
    <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
    <style>
        @font-face {
            font-family: 'Charcoal';
            src: url('__FONT_CHARCOAL__') format('truetype');
        }
        @font-face {
            font-family: 'Monaco';
            src: url('__FONT_MONACO__') format('truetype');
        }
        :root {
            --mac-bg: #DDDDDD;
            --mac-window-bg: #DDDDDD;
            --mac-border-dark: #888888;
            --mac-border-light: #FFFFFF;
            --mac-text: #000000;
            --mac-text-muted: #555555;
            --mac-selection: #316AC5;
            --mac-selection-text: #FFFFFF;
        }
        * {
            box-sizing: border-box;
        }
        body {
            font-family: 'Charcoal', 'Chicago', Geneva, sans-serif;
            font-size: 12px;
            max-width: 1200px;
            margin: 0 auto;
            padding: 20px;
            background-color: var(--mac-bg);
            background-image: url('__BACKGROUND_IMAGE__');
            background-repeat: repeat;
            min-height: 100vh;
            color: var(--mac-text);
        }
        h1 {
            font-family: 'Charcoal', 'Chicago', Geneva, sans-serif;
            text-align: center;
            font-size: 14px;
            font-weight: bold;
            margin: 0;
            color: var(--mac-text);
        }
        h2 {
            font-family: 'Charcoal', 'Chicago', Geneva, sans-serif;
            font-size: 12px;
            font-weight: bold;
            margin: 0 0 10px 0;
            color: var(--mac-text);
        }

        /* Mac OS 9 Window Style */
        .window {
            background: var(--mac-window-bg);
            border-style: solid;
            border-color: #000000;
            border-width: 1px 2px 2px 1px;
            box-shadow:
                inset -1px -1px 0 var(--mac-border-dark),
                inset 1px 1px 0 var(--mac-border-light);
            margin-bottom: 20px;
        }
        .window-titlebar {
            background: #BBBBBB;
            background-image: url('__TITLEBAR_BG__');
            background-repeat: repeat-x;
            height: 22px;
            display: flex;
            align-items: center;
            padding: 0 5px;
            border-bottom: 1px solid var(--mac-border-dark);
            position: relative;
        }
        .window-titlebar::before {
            content: '';
            position: absolute;
            left: 25px;
            right: 25px;
            top: 4px;
            bottom: 4px;
            background-image: url('__TITLE_STRIPES__');
            background-repeat: repeat-x;
            background-position: center;
        }
        .window-close {
            width: 13px;
            height: 13px;
            background-image: url('__CLOSE_BTN__');
            background-size: contain;
            background-repeat: no-repeat;
            flex-shrink: 0;
            position: relative;
            z-index: 1;
        }
        .window-hide {
            width: 13px;
            height: 13px;
            background-image: url('__HIDE_BTN__');
            background-size: contain;
            background-repeat: no-repeat;
            flex-shrink: 0;
            position: relative;
            z-index: 1;
        }
        .window-shade {
            width: 13px;
            height: 13px;
            background-image: url('__SHADE_BTN__');
            background-size: contain;
            background-repeat: no-repeat;
            flex-shrink: 0;
            position: relative;
            z-index: 1;
            margin-left: 4px;
        }
        .window-title {
            flex: 1;
            text-align: center;
            font-family: 'Charcoal', 'Chicago', Geneva, sans-serif;
            font-size: 12px;
            font-weight: bold;
            color: var(--mac-text);
            position: relative;
            z-index: 1;
            background: #BBBBBB;
            padding: 0 8px;
            margin: 0 auto;
            max-width: fit-content;
        }
        .window-content {
            padding: 15px;
        }

        /* Filters styled as Mac checkboxes */
        .filters {
            display: flex;
            justify-content: center;
            gap: 15px;
            flex-wrap: wrap;
        }
        .filter-label {
            display: flex;
            align-items: center;
            gap: 4px;
            cursor: pointer;
            user-select: none;
            font-family: 'Charcoal', 'Chicago', Geneva, sans-serif;
            font-size: 12px;
        }
        .filter-label input[type="checkbox"] {
            appearance: none;
            -webkit-appearance: none;
            width: 12px;
            height: 12px;
            background-image: url('__CHECK_OFF__');
            background-size: contain;
            background-repeat: no-repeat;
            cursor: pointer;
            margin: 0;
        }
        .filter-label input[type="checkbox"]:checked {
            background-image: url('__CHECK_ON__');
        }
        .filter-label .service-name {
            text-transform: capitalize;
        }
        .filter-label .service-count {
            color: var(--mac-text-muted);
        }

        /* Stats in embossed boxes */
        .stats {
            display: flex;
            justify-content: center;
            gap: 30px;
            flex-wrap: wrap;
        }
        .stat {
            text-align: center;
            padding: 10px 20px;
            background: var(--mac-window-bg);
            border: 1px solid;
            border-color: var(--mac-border-dark) var(--mac-border-light) var(--mac-border-light) var(--mac-border-dark);
            box-shadow: inset 1px 1px 0 var(--mac-border-dark), inset -1px -1px 0 var(--mac-border-light);
        }
        .stat-value {
            font-family: 'Monaco', 'Courier New', monospace;
            font-size: 18px;
            font-weight: bold;
            color: var(--mac-text);
        }
        .stat-label {
            font-family: 'Charcoal', 'Chicago', Geneva, sans-serif;
            font-size: 10px;
            color: var(--mac-text-muted);
            margin-top: 4px;
        }

        /* Chart containers */
        .charts-wrapper {
            display: grid;
            grid-auto-columns: minmax(280px, 450px);
            grid-template-columns: repeat(auto-fill, minmax(280px, 450px));
            grid-gap: 20px;
            justify-content: center;
            flex-wrap: wrap;
        }
        .chart-container {
            position: relative;
            min-width: 280px;
            max-width: 450px;
            padding: 10px;
            background: #FFFFFF;
            border: 1px solid;
            border-color: var(--mac-border-dark) var(--mac-border-light) var(--mac-border-light) var(--mac-border-dark);
            box-shadow: inset 1px 1px 0 var(--mac-border-dark);
        }
        .chart-title {
            font-family: 'Charcoal', 'Chicago', Geneva, sans-serif;
            font-size: 11px;
            font-weight: bold;
            text-align: center;
            margin-bottom: 8px;
            color: var(--mac-text);
        }
        @media (max-width: 700px) {
            .charts-wrapper {
                flex-direction: column;
                align-items: center;
            }
            .chart-container {
                max-width: 100%;
            }
        }

        /* Tables styled like Mac OS 9 lists */
        table {
            width: 100%;
            border-collapse: collapse;
            font-family: 'Charcoal', 'Chicago', Geneva, sans-serif;
            font-size: 11px;
            background: #FFFFFF;
            border: 1px solid var(--mac-border-dark);
        }
        th {
            background: linear-gradient(to bottom, #EEEEEE 0%, #CCCCCC 100%);
            padding: 4px 8px;
            text-align: left;
            border-bottom: 1px solid var(--mac-border-dark);
            border-right: 1px solid var(--mac-border-light);
            font-weight: bold;
            color: var(--mac-text);
        }
        th:last-child {
            border-right: none;
        }
        td {
            padding: 3px 8px;
            border-bottom: 1px solid #CCCCCC;
            color: var(--mac-text);
        }
        tr:hover td {
            background: var(--mac-selection);
            color: var(--mac-selection-text);
        }
        tr:hover .service-badge {
            background: rgba(255,255,255,0.3);
            color: var(--mac-selection-text);
        }
        .time {
            font-family: 'Monaco', 'Courier New', monospace;
            font-size: 10px;
        }
        .percent {
            font-family: 'Monaco', 'Courier New', monospace;
            font-size: 10px;
            text-align: right;
        }
        .color-box {
            display: inline-block;
            width: 10px;
            height: 10px;
            margin-right: 6px;
            vertical-align: middle;
            border: 1px solid var(--mac-border-dark);
        }
        .service-badge {
            display: inline-block;
            font-size: 9px;
            padding: 1px 4px;
            background: #EEEEEE;
            border: 1px solid #CCCCCC;
            color: var(--mac-text-muted);
            margin-left: 6px;
            text-transform: capitalize;
        }
        .category-badge {
            display: inline-block;
            font-size: 9px;
            padding: 1px 4px;
            background: #D4E4FF;
            border: 1px solid #A8C8FF;
            color: #2d5a9f;
            margin-left: 4px;
            text-transform: capitalize;
        }
        .no-data {
            text-align: center;
            padding: 20px;
            color: var(--mac-text-muted);
            font-style: italic;
        }

        /* Others row expansion */
        .others-row {
            cursor: pointer;
        }
        .others-row td:first-child::before {
            content: '';
            display: inline-block;
            width: 0;
            height: 0;
            border-left: 5px solid var(--mac-text);
            border-top: 3px solid transparent;
            border-bottom: 3px solid transparent;
            margin-right: 5px;
            transition: transform 0.15s;
        }
        .others-row:hover td:first-child::before {
            border-left-color: var(--mac-selection-text);
        }
        .others-row.expanded td:first-child::before {
            transform: rotate(90deg);
        }
        .others-detail {
            display: none;
            background: #F5F5F5;
        }
        .others-detail.visible {
            display: table-row;
        }
        .others-detail td {
            padding-left: 25px;
        }

        /* Mac OS 9 Tabs */
        .tabs {
            display: flex;
            gap: 0;
            margin-bottom: 0;
            position: relative;
            z-index: 1;
            padding-left: 10px;
        }
        .tab {
            font-family: 'Charcoal', 'Chicago', Geneva, sans-serif;
            font-size: 11px;
            padding: 3px 15px 2px 15px;
            cursor: pointer;
            color: var(--mac-text);
            position: relative;
            border: none;
            background: transparent;
            margin-right: -1px;
            border-style: solid;
            border-width: 10px 11px 2px 11px;
            border-image: url('__TAB_INACTIVE__') 10 11 2 11 fill stretch;
        }
        .tab:hover {
            opacity: 0.9;
        }
        .tab.active {
            border-image: url('__TAB_ACTIVE__') 10 11 2 11 fill stretch;
            font-weight: bold;
            z-index: 2;
            margin-bottom: -1px;
            padding-bottom: 3px;
        }
        .tab-content {
            background: #f3f3f3;
            border: 1px solid #000000;
            border-top: 1px solid #888888;
            padding: 10px;
            box-shadow: inset 1px 1px 0 #FFFFFF, inset -1px -1px 0 #888888;
        }
        .tab-panel {
            display: none;
        }
        .tab-panel.active {
            display: block;
        }
        .table-wrapper {
            overflow-y: visible;
        }

        /* Mac OS 9 Scrollbars */
        ::-webkit-scrollbar {
            width: 16px;
            height: 16px;
        }
        ::-webkit-scrollbar-track {
            background-image: url('__SCROLLBAR_TROUGH_V__');
            background-repeat: repeat-y;
            background-color: #CCCCCC;
            border-left: 1px solid #888888;
        }
        ::-webkit-scrollbar-thumb {
            background-image: url('__SCROLLBAR_THUMB_V__');
            background-repeat: repeat-y;
            background-size: contain;
            border: 1px solid;
            border-color: #FFFFFF #888888 #888888 #FFFFFF;
            background-color: #DDDDDD;
            min-height: 20px;
        }
        ::-webkit-scrollbar-thumb:hover {
            background-color: #EEEEEE;
        }
        ::-webkit-scrollbar-thumb:active {
            background-color: #CCCCCC;
        }
        ::-webkit-scrollbar-button:vertical:start:decrement {
            background-image: url('__SCROLLBAR_UP__');
            background-size: contain;
            background-repeat: no-repeat;
            background-position: center;
            background-color: #DDDDDD;
            border: 1px solid;
            border-color: #FFFFFF #888888 #888888 #FFFFFF;
            height: 16px;
        }
        ::-webkit-scrollbar-button:vertical:end:increment {
            background-image: url('__SCROLLBAR_DOWN__');
            background-size: contain;
            background-repeat: no-repeat;
            background-position: center;
            background-color: #DDDDDD;
            border: 1px solid;
            border-color: #FFFFFF #888888 #888888 #FFFFFF;
            height: 16px;
        }
        ::-webkit-scrollbar-button:vertical:start:decrement:hover,
        ::-webkit-scrollbar-button:vertical:end:increment:hover {
            background-color: #EEEEEE;
        }
        ::-webkit-scrollbar-button:vertical:start:decrement:active,
        ::-webkit-scrollbar-button:vertical:end:increment:active {
            background-color: #BBBBBB;
            border-color: #888888 #FFFFFF #FFFFFF #888888;
        }
        ::-webkit-scrollbar-corner {
            background-color: #DDDDDD;
        }

        /* Firefox scrollbar */
        * {
            scrollbar-width: auto;
            scrollbar-color: #DDDDDD #CCCCCC;
        }

        /* Scroll to Top Button */
        .scroll-top {
            position: fixed;
            bottom: 20px;
            right: 20px;
            z-index: 1000;
            width: 32px;
            height: 32px;
            background: var(--mac-window-bg);
            border: 1px solid;
            border-color: var(--mac-border-light) var(--mac-border-dark) var(--mac-border-dark) var(--mac-border-light);
            box-shadow: inset -1px -1px 0 var(--mac-border-dark), inset 1px 1px 0 var(--mac-border-light);
            cursor: pointer;
            display: flex;
            align-items: center;
            justify-content: center;
            opacity: 0;
            visibility: hidden;
            transition: opacity 0.3s ease, visibility 0.3s ease;
        }

        .scroll-top.visible {
            opacity: 1;
            visibility: visible;
        }

        .scroll-top:hover {
            background: #EEEEEE;
        }

        .scroll-top:active {
            border-color: var(--mac-border-dark) var(--mac-border-light) var(--mac-border-light) var(--mac-border-dark);
            box-shadow: inset 1px 1px 0 var(--mac-border-dark), inset -1px -1px 0 var(--mac-border-light);
        }

        .scroll-top-arrow {
            width: 0;
            height: 0;
            border-left: 6px solid transparent;
            border-right: 6px solid transparent;
            border-bottom: 8px solid var(--mac-text);
        }
    </style>
</head>
<body>
    <!-- Scroll to Top Button -->
    <button class="scroll-top" id="scroll-top" title="Scroll to top">
        <div class="scroll-top-arrow"></div>
    </button>

    <div class="window">
        <div class="window-titlebar">
            <div class="window-close"></div>
            <div class="window-title">Lutris Playtime Report</div>
            <div class="window-hide"></div>
            <div class="window-shade"></div>
        </div>
        <div class="window-content">
            <div class="filters" id="filters"></div>
        </div>
    </div>

    <div class="window">
        <div class="window-titlebar">
            <div class="window-close"></div>
            <div class="window-title">Statistics</div>
            <div class="window-hide"></div>
            <div class="window-shade"></div>
        </div>
        <div class="window-content">
            <div class="stats">
                <div class="stat">
                    <div class="stat-value" id="total-library">__TOTAL_LIBRARY__</div>
                    <div class="stat-label">Games in Library</div>
                </div>
                <div class="stat">
                    <div class="stat-value" id="total-games">0</div>
                    <div class="stat-label">Games Played</div>
                </div>
                <div class="stat">
                    <div class="stat-value" id="total-time">0h</div>
                    <div class="stat-label">Total Playtime</div>
                </div>
            </div>
        </div>
    </div>

    <div class="window">
        <div class="window-titlebar">
            <div class="window-close"></div>
            <div class="window-title">Playtime Distribution</div>
            <div class="window-hide"></div>
            <div class="window-shade"></div>
        </div>
        <div class="window-content">
            <div class="charts-wrapper">
                <div class="chart-container">
                    <div class="chart-title">Top Games</div>
                    <canvas id="playtime-chart"></canvas>
                </div>
                <div class="chart-container">
                    <div class="chart-title">By Category</div>
                    <canvas id="categories-chart"></canvas>
                </div>
                <div class="chart-container">
                    <div class="chart-title">By Runner</div>
                    <canvas id="runners-chart"></canvas>
                </div>
                <div class="chart-container">
                    <div class="chart-title">By Source</div>
                    <canvas id="sources-chart"></canvas>
                </div>
            </div>
        </div>
    </div>

    <div class="window">
        <div class="window-titlebar">
            <div class="window-close"></div>
            <div class="window-title">Summaries</div>
            <div class="window-hide"></div>
            <div class="window-shade"></div>
        </div>
        <div class="window-content">
            <div class="tabs">
                <div class="tab active" data-tab="games">Top Games</div>
                <div class="tab" data-tab="categories">By Category</div>
                <div class="tab" data-tab="runners">By Runner</div>
            </div>
            <div class="tab-content">
                <div class="tab-panel active" id="tab-games">
                    <div class="table-wrapper">
                        <table>
                            <thead>
                                <tr>
                                    <th>#</th>
                                    <th>Game</th>
                                    <th>Playtime</th>
                                    <th style="text-align: right">%</th>
                                </tr>
                            </thead>
                            <tbody id="games-table"></tbody>
                        </table>
                    </div>
                </div>
                <div class="tab-panel" id="tab-categories">
                    <div class="table-wrapper">
                        <table>
                            <thead>
                                <tr>
                                    <th>#</th>
                                    <th>Category</th>
                                    <th>Playtime</th>
                                    <th style="text-align: right">%</th>
                                </tr>
                            </thead>
                            <tbody id="categories-table"></tbody>
                        </table>
                    </div>
                </div>
                <div class="tab-panel" id="tab-runners">
                    <div class="table-wrapper">
                        <table>
                            <thead>
                                <tr>
                                    <th>#</th>
                                    <th>Runner</th>
                                    <th>Playtime</th>
                                    <th style="text-align: right">%</th>
                                </tr>
                            </thead>
                            <tbody id="runners-table"></tbody>
                        </table>
                    </div>
                </div>
            </div>
        </div>
    </div>

    <script>
        const allGames = __ALL_GAMES__;
        const topN = __TOP_N__;

        // Mac OS 9 inspired colors
        const colors = [
            '#336699', '#993366', '#669933', '#CC6633', '#663399',
            '#339966', '#996633', '#336666', '#993333', '#666699',
            '#888888'
        ];

        function formatTime(hours) {
            const h = Math.floor(hours);
            const m = Math.round((hours - h) * 60);
            if (h === 0) return m + 'm';
            if (m === 0) return h + 'h';
            return h + 'h ' + m + 'm';
        }

        function getServices() {
            const services = {};
            allGames.forEach(g => {
                const s = g.service;
                if (!services[s]) services[s] = { count: 0, playtime: 0 };
                services[s].count++;
                services[s].playtime += g.playtime;
            });
            return Object.entries(services)
                .sort((a, b) => b[1].playtime - a[1].playtime)
                .map(([name, data]) => ({ name, ...data }));
        }

        const services = getServices();
        const filtersDiv = document.getElementById('filters');
        services.forEach(service => {
            const label = document.createElement('label');
            label.className = 'filter-label';
            label.innerHTML = `
                <input type="checkbox" value="${service.name}" checked>
                <span class="service-name">${service.name}</span>
                <span class="service-count">(${service.count})</span>
            `;
            filtersDiv.appendChild(label);
        });

        let chart = null;
        let categoriesChart = null;
        let runnersChart = null;
        let sourcesChart = null;
        const ctx = document.getElementById('playtime-chart').getContext('2d');
        const ctxCategories = document.getElementById('categories-chart').getContext('2d');
        const ctxRunners = document.getElementById('runners-chart').getContext('2d');
        const ctxSources = document.getElementById('sources-chart').getContext('2d');

        function getSelectedServices() {
            const checkboxes = filtersDiv.querySelectorAll('input[type="checkbox"]');
            return Array.from(checkboxes)
                .filter(cb => cb.checked)
                .map(cb => cb.value);
        }

        function getFilteredData(selectedServices) {
            const filtered = allGames
                .filter(g => selectedServices.includes(g.service))
                .sort((a, b) => b.playtime - a.playtime);

            if (filtered.length === 0) {
                return { chartData: [], othersGames: [], categoriesData: [], totalPlaytime: 0, totalGames: 0 };
            }

            const totalPlaytime = filtered.reduce((sum, g) => sum + g.playtime, 0);
            const totalGames = filtered.length;

            const topGames = filtered.slice(0, topN).map(g => ({
                name: g.name,
                playtime: g.playtime,
                service: g.service,
                categories: g.categories || []
            }));

            let othersGames = [];

            if (filtered.length > topN) {
                othersGames = filtered.slice(topN).map(g => ({
                    name: g.name,
                    playtime: g.playtime,
                    service: g.service,
                    categories: g.categories || []
                }));
                const othersPlaytime = othersGames.reduce((sum, g) => sum + g.playtime, 0);
                const othersCount = othersGames.length;
                topGames.push({
                    name: `Others (${othersCount} games)`,
                    playtime: othersPlaytime,
                    service: 'others'
                });
            }

            const categoryMap = {};
            filtered.forEach(g => {
                if (g.categories && g.categories.length > 0) {
                    g.categories.forEach(cat => {
                        if (cat === '.hidden' || cat === 'favorite') return;
                        if (!categoryMap[cat]) {
                            categoryMap[cat] = { name: cat, playtime: 0, gameCount: 0 };
                        }
                        categoryMap[cat].playtime += g.playtime;
                        categoryMap[cat].gameCount++;
                    });
                }
            });
            const categoriesData = Object.values(categoryMap)
                .sort((a, b) => b.playtime - a.playtime);

            const runnerMap = {};
            filtered.forEach(g => {
                const runner = g.runner || 'unknown';
                if (!runnerMap[runner]) {
                    runnerMap[runner] = { name: runner, playtime: 0, gameCount: 0 };
                }
                runnerMap[runner].playtime += g.playtime;
                runnerMap[runner].gameCount++;
            });
            const runnersData = Object.values(runnerMap)
                .sort((a, b) => b.playtime - a.playtime);

            const sourceMap = {};
            filtered.forEach(g => {
                const source = g.service || 'unknown';
                if (!sourceMap[source]) {
                    sourceMap[source] = { name: source, playtime: 0, gameCount: 0 };
                }
                sourceMap[source].playtime += g.playtime;
                sourceMap[source].gameCount++;
            });
            const sourcesData = Object.values(sourceMap)
                .sort((a, b) => b.playtime - a.playtime);

            return { chartData: topGames, othersGames, categoriesData, runnersData, sourcesData, totalPlaytime, totalGames };
        }

        function updateDisplay() {
            const selectedServices = getSelectedServices();
            const { chartData, othersGames, categoriesData, runnersData, sourcesData, totalPlaytime, totalGames } = getFilteredData(selectedServices);

            document.getElementById('total-games').textContent = totalGames;
            document.getElementById('total-time').textContent = formatTime(totalPlaytime);

            if (chart) {
                chart.destroy();
            }
            if (categoriesChart) {
                categoriesChart.destroy();
            }
            if (runnersChart) {
                runnersChart.destroy();
            }
            if (sourcesChart) {
                sourcesChart.destroy();
            }

            if (chartData.length === 0) {
                document.getElementById('games-table').innerHTML =
                    '<tr><td colspan="4" class="no-data">No games match the selected filters</td></tr>';
                document.getElementById('categories-table').innerHTML =
                    '<tr><td colspan="4" class="no-data">No categories found</td></tr>';
                document.getElementById('runners-table').innerHTML =
                    '<tr><td colspan="4" class="no-data">No runners found</td></tr>';
                return;
            }

            chart = new Chart(ctx, {
                type: 'doughnut',
                data: {
                    labels: chartData.map(g => g.name),
                    datasets: [{
                        data: chartData.map(g => g.playtime),
                        backgroundColor: colors.slice(0, chartData.length),
                        borderColor: '#FFFFFF',
                        borderWidth: 1
                    }]
                },
                options: {
                    responsive: true,
                    plugins: {
                        legend: {
                            position: 'bottom',
                            labels: {
                                color: '#000000',
                                font: {
                                    family: "'Charcoal', 'Chicago', Geneva, sans-serif",
                                    size: 10
                                },
                                padding: 10
                            }
                        },
                        tooltip: {
                            titleFont: {
                                weight: 'bold'
                            },
                            bodyFont: {
                                weight: 'normal'
                            },
                            callbacks: {
                                title: function(context) {
                                    return context[0].label;
                                },
                                beforeBody: function(context) {
                                    const index = context[0].dataIndex;
                                    const service = chartData[index].service;
                                    if (service && service !== 'others') {
                                        return service.charAt(0).toUpperCase() + service.slice(1);
                                    }
                                    return '';
                                },
                                label: function(context) {
                                    const value = context.raw;
                                    const percent = ((value / totalPlaytime) * 100).toFixed(1);
                                    return formatTime(value) + ' (' + percent + '%)';
                                }
                            }
                        }
                    }
                }
            });

            // Categories chart data
            const topCategoriesChart = categoriesData.slice(0, topN);
            const otherCategoriesChart = categoriesData.slice(topN);
            const categoriesChartData = topCategoriesChart.map(c => ({
                name: c.name,
                playtime: c.playtime
            }));
            if (otherCategoriesChart.length > 0) {
                const othersPlaytime = otherCategoriesChart.reduce((sum, c) => sum + c.playtime, 0);
                categoriesChartData.push({
                    name: `Others (${otherCategoriesChart.length} categories)`,
                    playtime: othersPlaytime
                });
            }

            if (categoriesChartData.length > 0) {
                categoriesChart = new Chart(ctxCategories, {
                    type: 'doughnut',
                    data: {
                        labels: categoriesChartData.map(c => c.name),
                        datasets: [{
                            data: categoriesChartData.map(c => c.playtime),
                            backgroundColor: colors.slice(0, categoriesChartData.length),
                            borderColor: '#FFFFFF',
                            borderWidth: 1
                        }]
                    },
                    options: {
                        responsive: true,
                        plugins: {
                            legend: {
                                position: 'bottom',
                                labels: {
                                    color: '#000000',
                                    font: {
                                        family: "'Charcoal', 'Chicago', Geneva, sans-serif",
                                        size: 10
                                    },
                                    padding: 10
                                }
                            },
                            tooltip: {
                                callbacks: {
                                    label: function(context) {
                                        const value = context.raw;
                                        const percent = ((value / totalPlaytime) * 100).toFixed(1);
                                        return ' ' + formatTime(value) + ' (' + percent + '%)';
                                    }
                                }
                            }
                        }
                    }
                });
            }

            // Runners Chart
            const topRunnersChart = runnersData.slice(0, topN);
            const otherRunnersChart = runnersData.slice(topN);
            const runnersChartData = topRunnersChart.map(r => ({
                name: r.name,
                playtime: r.playtime
            }));
            if (otherRunnersChart.length > 0) {
                const othersPlaytime = otherRunnersChart.reduce((sum, r) => sum + r.playtime, 0);
                runnersChartData.push({
                    name: `Others (${otherRunnersChart.length} runners)`,
                    playtime: othersPlaytime
                });
            }

            if (runnersChartData.length > 0) {
                runnersChart = new Chart(ctxRunners, {
                    type: 'doughnut',
                    data: {
                        labels: runnersChartData.map(r => r.name),
                        datasets: [{
                            data: runnersChartData.map(r => r.playtime),
                            backgroundColor: colors.slice(0, runnersChartData.length),
                            borderColor: '#FFFFFF',
                            borderWidth: 1
                        }]
                    },
                    options: {
                        responsive: true,
                        plugins: {
                            legend: {
                                position: 'bottom',
                                labels: {
                                    color: '#000000',
                                    font: {
                                        family: "'Charcoal', 'Chicago', Geneva, sans-serif",
                                        size: 10
                                    },
                                    padding: 10
                                }
                            },
                            tooltip: {
                                callbacks: {
                                    label: function(context) {
                                        const value = context.raw;
                                        const percent = ((value / totalPlaytime) * 100).toFixed(1);
                                        return ' ' + formatTime(value) + ' (' + percent + '%)';
                                    }
                                }
                            }
                        }
                    }
                });
            }

            // Sources Chart
            const topSourcesChart = sourcesData.slice(0, topN);
            const otherSourcesChart = sourcesData.slice(topN);
            const sourcesChartData = topSourcesChart.map(s => ({
                name: s.name,
                playtime: s.playtime
            }));
            if (otherSourcesChart.length > 0) {
                const othersPlaytime = otherSourcesChart.reduce((sum, s) => sum + s.playtime, 0);
                sourcesChartData.push({
                    name: `Others (${otherSourcesChart.length} sources)`,
                    playtime: othersPlaytime
                });
            }

            if (sourcesChartData.length > 0) {
                sourcesChart = new Chart(ctxSources, {
                    type: 'doughnut',
                    data: {
                        labels: sourcesChartData.map(s => s.name),
                        datasets: [{
                            data: sourcesChartData.map(s => s.playtime),
                            backgroundColor: colors.slice(0, sourcesChartData.length),
                            borderColor: '#FFFFFF',
                            borderWidth: 1
                        }]
                    },
                    options: {
                        responsive: true,
                        plugins: {
                            legend: {
                                position: 'bottom',
                                labels: {
                                    color: '#000000',
                                    font: {
                                        family: "'Charcoal', 'Chicago', Geneva, sans-serif",
                                        size: 10
                                    },
                                    padding: 10
                                }
                            },
                            tooltip: {
                                callbacks: {
                                    label: function(context) {
                                        const value = context.raw;
                                        const percent = ((value / totalPlaytime) * 100).toFixed(1);
                                        return ' ' + formatTime(value) + ' (' + percent + '%)';
                                    }
                                }
                            }
                        }
                    }
                });
            }

            const tbody = document.getElementById('games-table');
            tbody.innerHTML = '';
            chartData.forEach((game, index) => {
                const percent = ((game.playtime / totalPlaytime) * 100).toFixed(1);
                const isOthers = game.service === 'others';
                const serviceBadge = !isOthers
                    ? `<span class="service-badge">${game.service}</span>`
                    : '';
                const categoriesBadges = !isOthers && game.categories && game.categories.length > 0
                    ? game.categories
                        .filter(cat => cat !== '.hidden' && cat !== 'favorite')
                        .map(cat => `<span class="category-badge">${cat}</span>`)
                        .join('')
                    : '';
                const row = document.createElement('tr');
                if (isOthers) {
                    row.className = 'others-row';
                }
                row.innerHTML = `
                    <td>${index + 1}</td>
                    <td>
                        <span class="color-box" style="background: ${colors[index]}"></span>
                        ${game.name}${serviceBadge}${categoriesBadges}
                    </td>
                    <td class="time">${formatTime(game.playtime)}</td>
                    <td class="percent">${percent}%</td>
                `;
                tbody.appendChild(row);

                if (isOthers && othersGames.length > 0) {
                    const detailRows = [];
                    othersGames.forEach((otherGame, otherIndex) => {
                        const otherPercent = ((otherGame.playtime / totalPlaytime) * 100).toFixed(1);
                        const otherCategoriesBadges = otherGame.categories && otherGame.categories.length > 0
                            ? otherGame.categories
                                .filter(cat => cat !== '.hidden' && cat !== 'favorite')
                                .map(cat => `<span class="category-badge">${cat}</span>`)
                                .join('')
                            : '';
                        const detailRow = document.createElement('tr');
                        detailRow.className = 'others-detail';
                        detailRow.innerHTML = `
                            <td>${index + 1}.${otherIndex + 1}</td>
                            <td>
                                ${otherGame.name}
                                <span class="service-badge">${otherGame.service}</span>${otherCategoriesBadges}
                            </td>
                            <td class="time">${formatTime(otherGame.playtime)}</td>
                            <td class="percent">${otherPercent}%</td>
                        `;
                        tbody.appendChild(detailRow);
                        detailRows.push(detailRow);
                    });

                    row.addEventListener('click', () => {
                        row.classList.toggle('expanded');
                        detailRows.forEach(dr => dr.classList.toggle('visible'));
                    });
                }
            });

            const catTbody = document.getElementById('categories-table');
            catTbody.innerHTML = '';
            if (categoriesData.length === 0) {
                catTbody.innerHTML = '<tr><td colspan="4" class="no-data">No categories found</td></tr>';
            } else {
                const topCategories = categoriesData.slice(0, topN);
                const otherCategories = categoriesData.slice(topN);

                topCategories.forEach((cat, index) => {
                    const percent = ((cat.playtime / totalPlaytime) * 100).toFixed(1);
                    const row = document.createElement('tr');
                    row.innerHTML = `
                        <td>${index + 1}</td>
                        <td>
                            <span class="color-box" style="background: ${colors[index]}"></span>
                            ${cat.name} <span class="service-badge">${cat.gameCount} games</span>
                        </td>
                        <td class="time">${formatTime(cat.playtime)}</td>
                        <td class="percent">${percent}%</td>
                    `;
                    catTbody.appendChild(row);
                });

                if (otherCategories.length > 0) {
                    const othersPlaytime = otherCategories.reduce((sum, c) => sum + c.playtime, 0);
                    const othersPercent = ((othersPlaytime / totalPlaytime) * 100).toFixed(1);
                    const othersIndex = topCategories.length;

                    const othersRow = document.createElement('tr');
                    othersRow.className = 'others-row';
                    othersRow.innerHTML = `
                        <td>${othersIndex + 1}</td>
                        <td>
                            <span class="color-box" style="background: ${colors[othersIndex]}"></span>
                            Others (${otherCategories.length} categories)
                        </td>
                        <td class="time">${formatTime(othersPlaytime)}</td>
                        <td class="percent">${othersPercent}%</td>
                    `;
                    catTbody.appendChild(othersRow);

                    const detailRows = [];
                    otherCategories.forEach((otherCat, otherIndex) => {
                        const otherPercent = ((otherCat.playtime / totalPlaytime) * 100).toFixed(1);
                        const detailRow = document.createElement('tr');
                        detailRow.className = 'others-detail';
                        detailRow.innerHTML = `
                            <td>${othersIndex + 1}.${otherIndex + 1}</td>
                            <td>
                                ${otherCat.name} <span class="service-badge">${otherCat.gameCount} games</span>
                            </td>
                            <td class="time">${formatTime(otherCat.playtime)}</td>
                            <td class="percent">${otherPercent}%</td>
                        `;
                        catTbody.appendChild(detailRow);
                        detailRows.push(detailRow);
                    });

                    othersRow.addEventListener('click', () => {
                        othersRow.classList.toggle('expanded');
                        detailRows.forEach(dr => dr.classList.toggle('visible'));
                    });
                }
            }

            const runnersTbody = document.getElementById('runners-table');
            runnersTbody.innerHTML = '';
            if (runnersData.length === 0) {
                runnersTbody.innerHTML = '<tr><td colspan="4" class="no-data">No runners found</td></tr>';
            } else {
                const topRunners = runnersData.slice(0, topN);
                const otherRunners = runnersData.slice(topN);

                topRunners.forEach((runner, index) => {
                    const percent = ((runner.playtime / totalPlaytime) * 100).toFixed(1);
                    const row = document.createElement('tr');
                    row.innerHTML = `
                        <td>${index + 1}</td>
                        <td>
                            <span class="color-box" style="background: ${colors[index]}"></span>
                            ${runner.name} <span class="service-badge">${runner.gameCount} games</span>
                        </td>
                        <td class="time">${formatTime(runner.playtime)}</td>
                        <td class="percent">${percent}%</td>
                    `;
                    runnersTbody.appendChild(row);
                });

                if (otherRunners.length > 0) {
                    const othersPlaytime = otherRunners.reduce((sum, r) => sum + r.playtime, 0);
                    const othersPercent = ((othersPlaytime / totalPlaytime) * 100).toFixed(1);
                    const othersIndex = topRunners.length;

                    const othersRow = document.createElement('tr');
                    othersRow.className = 'others-row';
                    othersRow.innerHTML = `
                        <td>${othersIndex + 1}</td>
                        <td>
                            <span class="color-box" style="background: ${colors[othersIndex]}"></span>
                            Others (${otherRunners.length} runners)
                        </td>
                        <td class="time">${formatTime(othersPlaytime)}</td>
                        <td class="percent">${othersPercent}%</td>
                    `;
                    runnersTbody.appendChild(othersRow);

                    const detailRows = [];
                    otherRunners.forEach((otherRunner, otherIndex) => {
                        const otherPercent = ((otherRunner.playtime / totalPlaytime) * 100).toFixed(1);
                        const detailRow = document.createElement('tr');
                        detailRow.className = 'others-detail';
                        detailRow.innerHTML = `
                            <td>${othersIndex + 1}.${otherIndex + 1}</td>
                            <td>
                                ${otherRunner.name} <span class="service-badge">${otherRunner.gameCount} games</span>
                            </td>
                            <td class="time">${formatTime(otherRunner.playtime)}</td>
                            <td class="percent">${otherPercent}%</td>
                        `;
                        runnersTbody.appendChild(detailRow);
                        detailRows.push(detailRow);
                    });

                    othersRow.addEventListener('click', () => {
                        othersRow.classList.toggle('expanded');
                        detailRows.forEach(dr => dr.classList.toggle('visible'));
                    });
                }
            }
        }

        filtersDiv.addEventListener('change', updateDisplay);
        updateDisplay();

        // Tab switching
        document.querySelectorAll('.tab').forEach(tab => {
            tab.addEventListener('click', () => {
                const tabId = tab.dataset.tab;
                document.querySelectorAll('.tab').forEach(t => t.classList.remove('active'));
                tab.classList.add('active');
                document.querySelectorAll('.tab-panel').forEach(p => p.classList.remove('active'));
                document.getElementById('tab-' + tabId).classList.add('active');
            });
        });

        // Scroll to top button
        const scrollTopBtn = document.getElementById('scroll-top');

        function updateScrollTopVisibility() {
            if (window.scrollY > 100) {
                scrollTopBtn.classList.add('visible');
            } else {
                scrollTopBtn.classList.remove('visible');
            }
        }

        window.addEventListener('scroll', updateScrollTopVisibility);
        updateScrollTopVisibility();

        scrollTopBtn.addEventListener('click', () => {
            window.scrollTo({
                top: 0,
                behavior: 'smooth'
            });
        });
    </script>
</body>
</html>
