Make this more robust, visually appealing, fast, reliable, effective, efficient, modern, smooth.

Improve and refine this further.

Don't forget to focus on ui improvements too.

Use dexie and save the extracted data only.

Don't compromise.

Use the full potential of dexie.

After the data( not html content ) is stored successfully in the db, For future sessions use only the data from the db if it's not corrupt or incomplete.

Find and all of those edge cases, bottlenecks, memory leaks, resources consumption, errors.

Send the fully working full codes in one html file.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Light Novels Gallery</title>
    <style>
        body {
            font-family: 'Arial', sans-serif;
            margin: 0;
            padding: 20px;
            background-color: #f5f5f5;
            display: flex;
            flex-direction: column;
            align-items: center;
        }

        .section-title {
            text-align: center;
            font-size: 2em;
            margin: 20px 0;
            color: #333;
            border-bottom: 2px solid #ff6600;
            padding-bottom: 10px;
            width: 80%; /* Added width for better centering */
        }

        .container {
            max-width: 1200px;
            width: 90%; /* Added width for responsiveness */
            margin: 0 auto;
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
            grid-gap: 30px;
        }

        .novel-card {
            background-color: white;
            border-radius: 8px;
            padding: 15px;
            box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
            transition: transform 0.2s ease-in-out; /* Smoother transition */
            overflow: hidden; /* Prevents image overflow */
        }

        .novel-card:hover {
            transform: translateY(-5px);
            box-shadow: 0 5px 15px rgba(0, 0, 0, 0.2);
        }

        .novel-card img {
            width: 100%;
            height: auto;
            border-radius: 8px 8px 0 0; /* Rounded top corners only */
            object-fit: cover; /* Ensures image covers the container */
        }

        .novel-title {
            color: #ff6600;
            text-decoration: none;
            font-size: 1.2em;
            margin: 10px 0;
            display: block;
            overflow: hidden;
            text-overflow: ellipsis;
            display: -webkit-box;
            -webkit-line-clamp: 2;
            -webkit-box-orient: vertical;
        }

        .post-meta {
            font-size: 0.9em;
            color: #666;
            margin-top: 5px;
        }

        .loading {
            text-align: center;
            font-size: 1.5em;
            padding: 20px;
            width: 80%;
            margin: 20px auto; /* Center the loading message */
        }

        .download-links {
            margin-top: 10px;
            display: flex;
            flex-wrap: wrap; /* Allows links to wrap onto multiple lines */
            gap: 5px;
        }

        .download-link {
            background-color: #ff6600;
            color: white;
            padding: 5px 10px;
            border-radius: 4px;
            text-decoration: none;
            font-size: 0.9em;
            transition: background-color 0.2s ease-in-out; /* Smoother transition */
        }

        .download-link:hover {
            background-color: #ff8533;
        }


        /* Responsive Design */
        @media (max-width: 768px) {
            .container {
                grid-template-columns: 1fr; /* Single column layout on smaller screens */
            }
        }
    </style>
</head>
<body>
    <div id="loading" class="loading">Loading...</div>  <!-- Loading indicator -->
    <h2 class="section-title">New Updates</h2>
    <div id="updates" class="container"></div>
        <h2 class="section-title">Popular Light Novels</h2>
    <div id="popular" class="container"></div>

    <script>
        const PROXY_URL = 'https://api.codetabs.com/v1/proxy?quest=';
        const UPDATES_URL = 'https://jnovels.com/0m-light-novels/?a=light-novels';
        const POPULAR_URL = 'https://jnovels.com/top-light-novels-to-read/';

        function parseUpdatePost(element) {
            const title = element.querySelector('.post-title a')?.textContent.trim() || '';
            const link = element.querySelector('.post-title a')?.href || '';
            const imageUrl = element.querySelector('.featured-media img')?.src || '';
            const date = element.querySelector('.post-date')?.textContent.trim() || '';
            const downloadLinks = Array.from(element.querySelectorAll('.post-content p a'))
                .filter(a => a.textContent.includes('VOLUME') || a.textContent.includes('PDF') || a.textContent.includes('Download'))
                
                .map(a => ({ href: a.href, text: a.textContent.trim() }));

            return { title, link, imageUrl, date, downloadLinks };
        }

        function renderUpdates(updates) {
            const container = document.getElementById('updates');
            container.innerHTML = updates.map(update => `
                <div class="novel-card">
                    <a href="${update.link}" target="_blank" rel="noopener noreferrer">
                        <img src="${update.imageUrl}" alt="${update.title}" loading="lazy">
                        <span class="novel-title">${update.title}</span>
                    </a>
                    <div class="post-meta">${update.date}</div>
                    <div class="download-links">
                        ${update.downloadLinks.length > 0 ? update.downloadLinks.map(link =>
                            `<a href="${link.href}" target="_blank" rel="noopener noreferrer" class="download-link">${link.text}</a>`
                        ).join('') : 'No download links found'}
                    </div>
                </div>
            `).join('');
        }

        function renderPopular(novels) {
            const container = document.getElementById('popular');
            container.innerHTML = novels.map(novel => `
                <div class="novel-card">
                    <a href="${novel.link}" target="_blank" rel="noopener noreferrer">
                        <img src="${novel.imageUrl}" alt="${novel.title}" loading="lazy">
                        <span class="novel-title">${novel.title}</span>
                    </a>
                </div>
            `).join('');
        }

        async function fetchData(url, isUpdates) {
            try {
                const response = await fetch(PROXY_URL + url);
                if (!response.ok) {
                    throw new Error(`HTTP error! status: ${response.status}`);
                }
                return await response.text();
            } catch (error) {
                console.error('Fetch error:', error);
                return null;
            }
        }


        async function fetchAndParseData(url, isUpdates = false) {
            const html = await fetchData(url, isUpdates);
            if (!html) return []; //Handle fetch failures

            const parser = new DOMParser();
            const doc = parser.parseFromString(html, 'text/html');

            if (isUpdates) {
                const posts = doc.querySelectorAll('article');
                return Array.from(posts).map(parseUpdatePost);
            } else {
                const novelElements = doc.querySelectorAll('h3 a[href*="jnovels.com"]');
                return Array.from(novelElements).map(element => ({
                    title: element.textContent.trim(),
                    link: element.href,
                    imageUrl: element.parentElement.nextElementSibling?.querySelector('img')?.src || '' //Handle missing images gracefully
                })).filter(novel => novel.title && novel.link); //Filter out incomplete entries
            }
        }

        // Initialize
        document.addEventListener('DOMContentLoaded', async () => {
            const loadingIndicator = document.getElementById('loading');
            const updatesPromise = fetchAndParseData(UPDATES_URL, true);
            const popularPromise = fetchAndParseData(POPULAR_URL);

            Promise.all([updatesPromise, popularPromise])
              .then(([updates, popular]) => {
                loadingIndicator.style.display = 'none'; //Hide loading indicator once data is fetched
                if (updates.length > 0) renderUpdates(updates);
                if (popular.length > 0) renderPopular(popular);
            })
              .catch(error => {
                loadingIndicator.style.display = 'none';
                loadingIndicator.textContent = 'Error loading data. Please try again later.';
                console.error('Error fetching or parsing data:', error);
              });
        });
    </script>
</body>
</html>