```javascript
const textarea = document.getElementById('code');
const previewFrame = document.getElementById('previewFrame');
const errorMessage = document.getElementById('error-message');

/**
 * Compiles custom code to HTML.
 * @param {string} customCode - The custom code to compile.
 * @returns {Object} - An object containing the compiled HTML and any errors.
 */
function compileToHTML(customCode) {
    const lines = customCode.split('\n');
    let html = '';
    let errors = [];
    let i = 0;
    const totalLines = lines.length;
    let inBlockComment = false;

    while (i < totalLines) {
        let line = lines[i].trim();

        if (inBlockComment) {
            if (line.endsWith('#}')) {
                inBlockComment = false;
            }
            i++;
            continue;
        }

        if (line.startsWith('#{')) {
            inBlockComment = true;
            i++;
            continue;
        }

        if (line.startsWith('#') && !line.startsWith('#{')) {
            i++;
            continue;
        }

        if (line === '\\}') {
            errors.push(`Unexpected block closure '\\}' at line ${i + 1}.`);
            i++;
            continue;
        }

        const blockStartMatch = line.match(/^(\w+)(\[[^\]]+\])?(#[\w\-]+)?((?:\.[\w\-]+)*?)\\\{$/);
        if (blockStartMatch) {
            const tag = blockStartMatch[1].toLowerCase();
            const attrs = blockStartMatch[2] ? replaceIndexPlaceholders(blockStartMatch[2].slice(1, -1), 1) : '';
            const id = blockStartMatch[3] ? replaceIndexPlaceholders(blockStartMatch[3].slice(1), 1) : '';
            const classesRaw = blockStartMatch[4] ? blockStartMatch[4] : '';
            const classes = classesRaw.split('.').filter(cls => cls !== '');

            let blockContent = '';
            i++;
            let openBlocks = 1;

            while (i < totalLines && openBlocks > 0) {
                let currentLine = lines[i].trim();

                if (currentLine.endsWith('\\{')) {
                    openBlocks++;
                }

                if (currentLine === '\\}') {
                    openBlocks--;
                    if (openBlocks === 0) {
                        i++;
                        break;
                    }
                }

                if (openBlocks > 0) {
                    blockContent += lines[i] + '\n';
                }

                i++;
            }

            if (openBlocks > 0) {
                errors.push(`Unclosed block starting with <${tag}>.`);
                break;
            }

            let innerHTML = '';

            if (tag === 'script' || tag === 'style' || tag === 'html') {
                innerHTML = blockContent;
            } else if (tag === 'raw') {
                // Handle raw blocks by escaping content
                innerHTML = escapeHTML(blockContent);
                html += `${innerHTML}\n`;
                continue; // Skip the rest of the loop to avoid wrapping in a tag
            } else {
                let compiledBlock;
                try {
                    compiledBlock = compileToHTML(blockContent);
                } catch (error) {
                    errors.push(`Line ${i + 1}: Unexpected error: ${error.message}`);
                    compiledBlock = { html: '', errors: [`Line ${i + 1}: Unexpected error: ${error.message}`] };
                }

                if (compiledBlock.errors.length > 0) {
                    errors = errors.concat(compiledBlock.errors);
                }
                innerHTML = compiledBlock.html;
            }

            let attrString = '';
            if (attrs) attrString += ` ${attrs}`;
            if (id) attrString += ` id="${id}"`;
            if (classes.length > 0) attrString += ` class="${classes.join(' ')}"`;

            html += `<${tag}${attrString}>\n${innerHTML}</${tag}>\n`;

            continue;
        }

        const inlineMatch = line.match(/^(\w+)(\[[^\]]+\])?(#[\w\-]+)?((?:\.[\w\-]+)*?)(?:\{([^}]*)\})?(?:\*(\d+))?$/);
        if (inlineMatch) {
            try {
                const tag = inlineMatch[1].toLowerCase();
                const attrs = inlineMatch[2] ? replaceIndexPlaceholders(inlineMatch[2].slice(1, -1), 1) : '';
                const id = inlineMatch[3] ? replaceIndexPlaceholders(inlineMatch[3].slice(1), 1) : '';
                const classesRaw = inlineMatch[4] ? inlineMatch[4] : '';
                const classes = classesRaw.split('.').filter(cls => cls !== '');
                const content = inlineMatch[5] || '';
                const repeat = inlineMatch[6] ? parseInt(inlineMatch[6]) : 1;

                let finalAttrString = '';
                if (attrs) finalAttrString += ` ${attrs}`;
                if (id) finalAttrString += ` id="${id}"`;
                if (classes.length > 0) finalAttrString += ` class="${classes.join(' ')}"`;

                for (let j = 1; j <= repeat; j++) {
                    const currentContent = replaceIndexPlaceholders(content, j);
                    const currentAttrString = replaceIndexPlaceholders(finalAttrString, j);
                    html += `<${tag}${currentAttrString}>${currentContent}</${tag}>\n`;
                }

                i++;
            } catch (err) {
                errors.push(`Line ${i + 1}: ${err.message}`);
            }
            continue;
        }

        const siblingTokens = splitRespectingBlocks(line, '+');
        siblingTokens.forEach(token => {
            const nestingTokens = splitRespectingBlocks(token, '>');
            const nestedHTML = processNesting(nestingTokens, 0, errors, i + 1);
            html += nestedHTML;
        });

        const textLineMatch = line.match(/^[^+\>]+$/);
        if (!blockStartMatch && !inlineMatch && textLineMatch) {
            html += `${escapeHTML(line)}\n`;
        }

        i++;
    }

    try {
        html = processInlineJS(html, errors);
    } catch (error) {
        errors.push(`Inline JS Error: ${error.message}`);
    }

    return { html, errors };

    /**
     * Processes and replaces inline JavaScript expressions within the HTML.
     * @param {string} htmlContent - The HTML content to process.
     * @param {Array} errors - The array to collect any errors.
     * @returns {string} - The HTML with inline JavaScript expressions evaluated.
     */
    function processInlineJS(htmlContent, errors) {
        const jsRegex = /<\$\s*([\s\S]+?)\s*\$>/g;
        return htmlContent.replace(jsRegex, (match, p1) => {
            try {
                const result = window.eval(p1);
                return result !== undefined ? escapeHTML(result.toString()) : '';
            } catch (err) {
                errors.push(`Inline JS Evaluation Error: ${err.message} in expression "${p1}"`);
                return `<span style="color: red;">Error</span>`;
            }
        });
    }

    /**
     * Recursive function to process nested tokens.
     * @param {Array} nestingTokens - Array of tokens split by '>'.
     * @param {number} index - Current index in the nestingTokens array.
     * @param {Array} errors - Array to collect error messages.
     * @param {number} lineNumber - Current line number for error reporting.
     * @returns {string} - The generated HTML string after processing nesting.
     */
    function processNesting(nestingTokens, index, errors, lineNumber) {
        if (index >= nestingTokens.length) return '';

        const nestedToken = nestingTokens[index].trim();
        const isLast = index === nestingTokens.length - 1;

        if (nestedToken === '') return '';

        let generatedHTML = '';

        try {
            const { tag, attributes, id, classes, content, repeat } = parseElement(nestedToken, lineNumber);
            let attrString = '';
            if (attributes) attrString += ` ${attributes}`;
            if (id) attrString += ` id="${id}"`;
            if (classes.length > 0) attrString += ` class="${classes.join(' ')}"`;

            for (let j = 1; j <= repeat; j++) {
                let finalContent = replaceIndexPlaceholders(content, j);
                let finalAttrString = replaceIndexPlaceholders(attrString, j);
                let finalId = replaceIndexPlaceholders(id, j);
                let finalClasses = classes.map(cls => replaceIndexPlaceholders(cls, j));

                if (finalId) {
                    finalAttrString = finalAttrString.replace(` id="${id}"`, ` id="${finalId}"`);
                }

                if (finalClasses.length > 0) {
                    const classRegex = /class="([^"]+)"/;
                    const match = finalAttrString.match(classRegex);
                    if (match) {
                        const existingClasses = match[1].split(' ');
                        const updatedClasses = [...new Set([...existingClasses, ...finalClasses])];
                        finalAttrString = finalAttrString.replace(classRegex, `class="${updatedClasses.join(' ')}"`);
                    } else {
                        finalAttrString += ` class="${finalClasses.join(' ')}"`;
                    }
                }

                generatedHTML += `<${tag}${finalAttrString}>`;

                if (finalContent) {
                    generatedHTML += finalContent;
                }

                if (!isLast) {
                    generatedHTML += '\n';
                    generatedHTML += processNesting(nestingTokens, index + 1, errors, lineNumber);
                    generatedHTML += `</${tag}>\n`;
                } else {
                    generatedHTML += `</${tag}>\n`;
                }
            }
        } catch (err) {
            if (nestedToken.startsWith('\\}')) {
                return '';
            } else {
                errors.push(`Line ${lineNumber}: ${err.message}`);
                generatedHTML += `${escapeHTML(nestedToken)}\n`;
            }
        }

        return generatedHTML;
    }
}

/**
 * Splits a string by a delimiter but ignores delimiters inside quotes or blocks.
 * @param {string} str - The string to split.
 * @param {string} delimiter - The delimiter to split by.
 * @returns {Array} - Array of split tokens.
 */
function splitRespectingBlocks(str, delimiter) {
    const tokens = [];
    let current = '';
    let inQuotes = false;
    let quoteChar = '';
    let escape = false;
    let blockDepth = 0;

    for (let i = 0; i < str.length; i++) {
        let char = str[i];

        if (escape) {
            current += char;
            escape = false;
            continue;
        }

        if (char === '\\') {
            escape = true;
            current += char;
            continue;
        }

        if ((char === '"' || char === "'") && !inQuotes) {
            inQuotes = true;
            quoteChar = char;
            current += char;
            continue;
        }

        if (char === quoteChar && inQuotes) {
            inQuotes = false;
            quoteChar = '';
            current += char;
            continue;
        }

        if (!inQuotes && char === '{') {
            blockDepth++;
            current += char;
            continue;
        }

        if (!inQuotes && char === '}') {
            blockDepth = Math.max(blockDepth - 1, 0);
            current += char;
            continue;
        }

        if (!inQuotes && blockDepth === 0 && char === delimiter) {
            tokens.push(current);
            current = '';
            continue;
        }

        current += char;
    }

    if (current !== '') {
        tokens.push(current);
    }

    return tokens;
}

/**
 * Replaces all instances of &index; with the provided index number.
 * @param {string} str - The string to process.
 * @param {number} index - The index to replace &index; with.
 * @returns {string} - The processed string.
 */
function replaceIndexPlaceholders(str, index) {
    return str.replace(/&index;/g, index);
}

/**
 * Parses an element definition from the custom syntax.
 * @param {string} token - A token from the custom code.
 * @param {number} lineNumber - The line number for error reporting.
 * @returns {Object} - Parsed element details.
 */
function parseElement(token, lineNumber) {
    const regex = /^(\w+)(\[[^\]]+\])?(#[\w\-]+)?((?:\.[\w\-]+)*?)(?:\{([^}]*)\})?(?:\*(\d+))?$/;
    const match = token.match(regex);

    if (!match) {
        throw { message: `Invalid syntax near "${token}".`, line: lineNumber };
    }

    const [, tag, attrs, id, classNames, content, repeat] = match;
    let attributes = '';
    let classes = [];

    if (attrs) {
        const attrContent = attrs.slice(1, -1);
        const attrRegex = /(\w+)="([^"]*)"/g;
        let attrMatch;
        while ((attrMatch = attrRegex.exec(attrContent)) !== null) {
            const [, attrName, attrValue] = attrMatch;
            attributes += ` ${attrName}="${attrValue}"`;
        }
    }

    if (classNames) {
        classes = classNames.split('.').filter(cls => cls !== '').map(cls => cls.trim());
    }

    const element = {
        tag: tag,
        attributes: attributes,
        id: id ? id.slice(1) : '',
        classes: classes,
        content: content ? content : '',
        repeat: repeat ? parseInt(repeat) : 1
    };

    return element;
}

/**
 * Escapes HTML special characters in a string.
 * @param {string} str - The string to escape.
 * @returns {string} - The escaped string.
 */
function escapeHTML(str) {
    const replacements = {
        '&': '&amp;',
        '<': '&lt;',
        '>': '&gt;',
        '"': '&quot;',
        "'": '&#039;'
    };
    return str.replace(/[&<>"']/g, match => replacements[match]);
}

function updatePreview() {
    const textarea = document.getElementById('code');
    const previewFrame = document.getElementById('previewFrame');
    const errorMessage = document.getElementById('error-message');

    const customCode = textarea.value;
    let compilationResult;
    try {
        compilationResult = compileToHTML(customCode);
    } catch (error) {
        compilationResult = { html: '', errors: [`Unexpected error: ${error.message}`] };
    }

    const { html, errors } = compilationResult;

    if (errors && errors.length > 0) {
        errorMessage.textContent = errors.join(' | ');
        errorMessage.style.display = 'block';
        previewFrame.srcdoc = '';
    } else {
        errorMessage.textContent = '';
        errorMessage.style.display = 'none';
        const fullHTML = `
        <!DOCTYPE html>
        <html lang="en">
        <head>
            <meta charset="UTF-8">
            <title>Preview</title>
            <style>
                body {
                    background-color: #1e1e1e;
                    color: #cccccc;
                    font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
                    padding: 20px;
                }
                h1, h2, h3, h4, h5, h6 {
                    color: #ffffff;
                }
                p {
                    color: #dcdcdc;
                    margin-bottom: 10px;
                }
                button {
                    padding: 10px 20px;
                    background-color: #3498db;
                    color: #fff;
                    border: none;
                    cursor: pointer;
                    border-radius: 4px;
                    margin-top: 10px;
                }
                button:hover {
                    background-color: #2980b9;
                }
                a {
                    color: #9b59b6;
                }
                a:hover {
                    color: #8e44ad;
                }
                /* Additional styles for various elements */
                ul {
                    list-style-type: disc;
                    padding-left: 20px;
                    margin-bottom: 10px;
                }
                li {
                    margin-bottom: 5px;
                }
                input, textarea {
                    background-color: #333333;
                    color: #ffffff;
                    border: 1px solid #555555;
                    padding: 8px;
                    border-radius: 4px;
                    margin-top: 5px;
                }
                input:focus, textarea:focus {
                    border-color: #3498db;
                    outline: none;
                }
                table {
                    width: 100%;
                    border-collapse: collapse;
                    margin-top: 10px;
                }
                th, td {
                    border: 1px solid #555555;
                    padding: 8px;
                    text-align: left;
                }
                th {
                    background-color: #444444;
                }
                tr:nth-child(even) {
                    background-color: #2d2d2d;
                }
                /* Embedded Styles */
                ${extractEmbeddedStyles(html)}
            </style>
        </head>
        <body>
        ${html}
        </body>
        </html>`;
        previewFrame.srcdoc = fullHTML;
    }
}

/**
 * Extracts embedded <style> blocks from the generated HTML to include in the preview's head.
 * @param {string} html - The generated HTML content.
 * @returns {string} - Extracted CSS from <style> blocks.
 */
function extractEmbeddedStyles(html) {
    const styleRegex = /<style[^>]*>([\s\S]*?)<\/style>/gi;
    let styles = '';
    let match;
    while ((match = styleRegex.exec(html)) !== null) {
        styles += match[1] + '\n';
    }
    return styles;
}

updatePreview();

let timeout;
const textareaElement = document.getElementById('code');

textareaElement.addEventListener('input', () => {
    clearTimeout(timeout);
    timeout = setTimeout(updatePreview, 300);
});

const tabEditor = document.getElementById('tab-editor');
const tabPreview = document.getElementById('tab-preview');
const editor = document.querySelector('.editor');
const preview = document.querySelector('.preview');

/**
 * Activates the specified tab and deactivates the other.
 * @param {string} tab - The tab to activate ('editor' or 'preview').
 */
function activateTab(tab) {
    tabEditor.classList.remove('active');
    tabPreview.classList.remove('active');

    editor.classList.remove('active');
    preview.classList.remove('active');

    if (tab === 'editor') {
        tabEditor.classList.add('active');
        editor.classList.add('active');
    } else if (tab === 'preview') {
        tabPreview.classList.add('active');
        preview.classList.add('active');
    }

    handleResponsiveTabs();
}

function handleResponsiveTabs() {
    const isMobile = window.innerWidth <= 768;

    if (isMobile) {
        if (!editor.classList.contains('active') && !preview.classList.contains('active')) {
            editor.classList.add('active');
        }
    } else {
        editor.classList.add('active');
        preview.classList.add('active');
    }
}

handleResponsiveTabs();

window.addEventListener('resize', handleResponsiveTabs);

tabEditor.addEventListener('click', () => activateTab('editor'));
tabPreview.addEventListener('click', () => activateTab('preview'));

textareaElement.addEventListener('keydown', e => {
    const openingChars = {
        '"': '"',
        "'": "'",
        '(': ')',
        '{': '}',
        '[': ']',
        '<': '>'
    };

    const closingChars = Object.values(openingChars);

    if (e.key === 'Backspace') {
        const cursorPos = textareaElement.selectionStart;
        const textBeforeCursor = textareaElement.value.substring(0, cursorPos);
        const lastTwoChars = textBeforeCursor.slice(-2);
        return;
    }

    if (e.key === '"' || e.key === "'") {
        const closingChar = openingChars[e.key];
        const cursorPos = textareaElement.selectionStart;
        const beforeCursor = textareaElement.value.substring(0, cursorPos);
        const afterCursor = textareaElement.value.substring(cursorPos);

        if (afterCursor.startsWith(closingChar)) {
            e.preventDefault();
            textareaElement.setSelectionRange(cursorPos + 1, cursorPos + 1);
        } else {
            e.preventDefault();
            textareaElement.value = beforeCursor + e.key + closingChar + afterCursor;
            setTimeout(() => {
                textareaElement.setSelectionRange(cursorPos + 1, cursorPos + 1);
                textareaElement.dispatchEvent(new Event('input'));
            }, 0);
        }
        return;
    }

    if (e.key in openingChars) {
        e.preventDefault();
        const closingChar = openingChars[e.key];
        const cursorPos = textareaElement.selectionStart;
        const beforeCursor = textareaElement.value.substring(0, cursorPos);
        const afterCursor = textareaElement.value.substring(cursorPos);

        textareaElement.value = beforeCursor + e.key + closingChar + afterCursor;
        setTimeout(() => {
            textareaElement.setSelectionRange(cursorPos + e.key.length, cursorPos + e.key.length);
            textareaElement.dispatchEvent(new Event('input'));
        }, 0);
    }

    if (e.key === 'Tab') {
        e.preventDefault();

        const start = textareaElement.selectionStart;
        const end = textareaElement.selectionEnd;

        const value = textareaElement.value;
        const newValue = value.substring(0, start) + '  ' + value.substring(end);

        textareaElement.value = newValue;

        textareaElement.selectionStart = textareaElement.selectionEnd = start + 2;

        textareaElement.dispatchEvent(new Event('input'));
    }

    if (closingChars.includes(e.key)) {
        const cursorPos = textareaElement.selectionStart;
        const nextChar = textareaElement.value.substring(cursorPos, cursorPos + 1);
        if (e.key === nextChar) {
            e.preventDefault();
            textareaElement.setSelectionRange(cursorPos + 1, cursorPos + 1);
        }
    }
});
```

Make changes to the processInlineJS function, it currently evaluates the code to the window, which could be dangerous... instead, let's evaluate the code to the preview frame's window, the iframe is sandboxed, which wouldn't affect the actual website