<!--
    Global Settings Modal — Lumenworks rack-panel layout.

    Anatomy:
    - Left rail (settings-rail) replaces the old icon-only top tab strip.
    - Each tab body is a stack of .ds-section panels, channel-coded.
    - Element IDs are preserved verbatim so settings.ts handlers continue to
      work (saveExternalUrl, saveAutoBackupSettings, restartServer, etc.).
-->
<div id="settings-modal" class="modal" role="dialog" aria-modal="true" aria-labelledby="settings-modal-title">
    <div class="modal-content">
        <div class="modal-header">
            <h2 id="settings-modal-title">
                <svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="M9.671 4.136a2.34 2.34 0 0 1 4.659 0 2.34 2.34 0 0 0 3.319 1.915 2.34 2.34 0 0 1 2.33 4.033 2.34 2.34 0 0 0 0 3.831 2.34 2.34 0 0 1-2.33 4.033 2.34 2.34 0 0 0-3.319 1.915 2.34 2.34 0 0 1-4.659 0 2.34 2.34 0 0 0-3.32-1.915 2.34 2.34 0 0 1-2.33-4.033 2.34 2.34 0 0 0 0-3.831A2.34 2.34 0 0 1 6.35 6.051a2.34 2.34 0 0 0 3.319-1.915"/><circle cx="12" cy="12" r="3"/></svg>
                <span data-i18n="settings.title">Settings</span>
            </h2>
            <button class="modal-close-btn" onclick="closeSettingsModal()" title="Close" data-i18n-aria-label="aria.close">&#x2715;</button>
        </div>

        <div class="settings-layout">

            <!-- ───────────── LEFT RAIL ───────────── -->
            <nav class="settings-rail" role="tablist" aria-label="Settings sections">
                <div class="settings-rail-group" data-i18n="settings.rail.group.workspace">Workspace</div>

                <button class="settings-rail-btn active" data-settings-tab="general" data-rail-ch="amber" onclick="switchSettingsTab('general')" role="tab" aria-label="General" data-i18n-aria-label="settings.tab.general">
                    <svg class="icon" viewBox="0 0 24 24"><path d="M9.671 4.136a2.34 2.34 0 0 1 4.659 0 2.34 2.34 0 0 0 3.319 1.915 2.34 2.34 0 0 1 2.33 4.033 2.34 2.34 0 0 0 0 3.831 2.34 2.34 0 0 1-2.33 4.033 2.34 2.34 0 0 0-3.319 1.915 2.34 2.34 0 0 1-4.659 0 2.34 2.34 0 0 0-3.32-1.915 2.34 2.34 0 0 1-2.33-4.033 2.34 2.34 0 0 0 0-3.831A2.34 2.34 0 0 1 6.35 6.051a2.34 2.34 0 0 0 3.319-1.915"/><circle cx="12" cy="12" r="3"/></svg>
                    <span class="settings-rail-label" data-i18n="settings.tab.general">General</span>
                    <span class="settings-rail-dot" aria-hidden="true"></span>
                </button>

                <button class="settings-rail-btn" data-settings-tab="backup" data-rail-ch="cyan" onclick="switchSettingsTab('backup')" role="tab" aria-label="Backup" data-i18n-aria-label="settings.tab.backup">
                    <svg class="icon" viewBox="0 0 24 24"><line x1="22" x2="2" y1="12" y2="12"/><path d="M5.45 5.11 2 12v6a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2v-6l-3.45-6.89A2 2 0 0 0 16.76 4H7.24a2 2 0 0 0-1.79 1.11z"/><line x1="6" x2="6.01" y1="16" y2="16"/><line x1="10" x2="10.01" y1="16" y2="16"/></svg>
                    <span class="settings-rail-label" data-i18n="settings.tab.backup">Backup</span>
                    <span class="settings-rail-dot" aria-hidden="true"></span>
                </button>

                <button class="settings-rail-btn" data-settings-tab="notifications" data-rail-ch="violet" onclick="switchSettingsTab('notifications')" role="tab" aria-label="Notifications" data-i18n-aria-label="settings.tab.notifications">
                    <svg class="icon" viewBox="0 0 24 24"><path d="M6 8a6 6 0 0 1 12 0c0 7 3 9 3 9H3s3-2 3-9"/><path d="M10.3 21a1.94 1.94 0 0 0 3.4 0"/></svg>
                    <span class="settings-rail-label" data-i18n="settings.tab.notifications">Notifications</span>
                    <span class="settings-rail-dot" aria-hidden="true"></span>
                </button>

                <button class="settings-rail-btn" data-settings-tab="appearance" data-rail-ch="magenta" onclick="switchSettingsTab('appearance')" role="tab" aria-label="Appearance" data-i18n-aria-label="settings.tab.appearance">
                    <svg class="icon" viewBox="0 0 24 24"><path d="M12 22a1 1 0 0 1 0-20 10 9 0 0 1 10 9 5 5 0 0 1-5 5h-2.25a1.75 1.75 0 0 0-1.4 2.8l.3.4a1.75 1.75 0 0 1-1.4 2.8z"/><circle cx="13.5" cy="6.5" r=".5" fill="currentColor"/><circle cx="17.5" cy="10.5" r=".5" fill="currentColor"/><circle cx="6.5" cy="12.5" r=".5" fill="currentColor"/><circle cx="8.5" cy="7.5" r=".5" fill="currentColor"/></svg>
                    <span class="settings-rail-label" data-i18n="settings.tab.appearance">Appearance</span>
                    <span class="settings-rail-dot" aria-hidden="true"></span>
                </button>

                <div class="settings-rail-group" data-i18n="settings.rail.group.system">System</div>

                <button class="settings-rail-btn" data-settings-tab="updates" data-rail-ch="signal" onclick="switchSettingsTab('updates')" role="tab" aria-label="Updates" data-i18n-aria-label="settings.tab.updates">
                    <svg class="icon" viewBox="0 0 24 24"><path d="M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8"/><path d="M21 3v5h-5"/><path d="M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16"/><path d="M8 16H3v5"/></svg>
                    <span class="settings-rail-label" data-i18n="settings.tab.updates">Updates</span>
                    <span class="settings-rail-badge" id="settings-rail-update-badge" hidden>1</span>
                    <span class="settings-rail-dot" aria-hidden="true"></span>
                </button>

                <button class="settings-rail-btn" data-settings-tab="about" data-rail-ch="amber" onclick="switchSettingsTab('about')" role="tab" aria-label="About" data-i18n-aria-label="settings.tab.about">
                    <svg class="icon" viewBox="0 0 24 24"><circle cx="12" cy="12" r="10"/><path d="M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3"/><path d="M12 17h.01"/></svg>
                    <span class="settings-rail-label" data-i18n="settings.tab.about">About</span>
                    <span class="settings-rail-dot" aria-hidden="true"></span>
                </button>

                <div class="settings-rail-footer" id="settings-rail-build" aria-hidden="true"></div>
            </nav>

            <!-- ───────────── PANEL BODY ───────────── -->
            <div class="modal-body settings-body">

                <!-- ═══ General tab ═══ -->
                <div id="settings-panel-general" class="settings-panel active">

                    <section class="ds-section" data-ch="amber">
                        <div class="ds-section-header">
                            <span class="ds-section-dot" aria-hidden="true"></span>
                            <span class="ds-section-title" data-i18n="settings.section.api_keys">API Keys</span>
                            <span class="ds-section-meta" id="settings-api-keys-meta" hidden></span>
                            <span class="ds-section-index" aria-hidden="true">01</span>
                        </div>
                        <div class="ds-section-body">
                            <div class="form-group">
                                <div class="label-row">
                                    <label data-i18n="settings.api_keys.label">API Keys</label>
                                    <button type="button" class="hint-toggle" onclick="toggleHint(this)" title="?">?</button>
                                </div>
                                <small class="input-hint" style="display:none" data-i18n="settings.api_keys.hint">API keys are defined in the server config file (config.yaml). Restart the server after editing the file to apply changes.</small>
                                <div id="settings-api-keys-list" class="api-key-list"></div>
                            </div>
                        </div>
                    </section>

                    <section class="ds-section" data-ch="cyan">
                        <div class="ds-section-header">
                            <span class="ds-section-dot" aria-hidden="true"></span>
                            <span class="ds-section-title" data-i18n="settings.section.server">Server</span>
                            <span class="ds-section-index" aria-hidden="true">02</span>
                        </div>
                        <div class="ds-section-body">

                            <div class="form-group" id="settings-external-url-group">
                                <div class="label-row">
                                    <label data-i18n="settings.external_url.label">External URL</label>
                                    <button type="button" class="hint-toggle" onclick="toggleHint(this)" title="?">?</button>
                                </div>
                                <small class="input-hint" style="display:none" data-i18n="settings.external_url.hint">If set, this base URL is used in webhook URLs and other user-visible links instead of the auto-detected local IP. Example: https://myserver.example.com:8080</small>
                                <input type="text" id="settings-external-url" placeholder="https://myserver.example.com:8080" data-i18n-placeholder="settings.external_url.placeholder">
                            </div>

                            <div class="ds-pair-row">
                                <div class="form-group">
                                    <div class="label-row">
                                        <label data-i18n="settings.log_level.label">Log Level</label>
                                        <button type="button" class="hint-toggle" onclick="toggleHint(this)" title="?">?</button>
                                    </div>
                                    <small class="input-hint" style="display:none" data-i18n="settings.log_level.hint">Change the server log verbosity at runtime. DEBUG shows the most detail; CRITICAL shows only fatal errors.</small>
                                    <select id="settings-log-level">
                                        <option value="DEBUG">DEBUG</option>
                                        <option value="INFO">INFO</option>
                                        <option value="WARNING">WARNING</option>
                                        <option value="ERROR">ERROR</option>
                                        <option value="CRITICAL">CRITICAL</option>
                                    </select>
                                </div>

                                <div class="form-group">
                                    <div class="label-row">
                                        <label data-i18n="settings.shutdown_action.label">Shutdown action</label>
                                        <button type="button" class="hint-toggle" onclick="toggleHint(this)" title="?">?</button>
                                    </div>
                                    <small class="input-hint" style="display:none" data-i18n="settings.shutdown_action.hint">What happens to LED targets when the server shuts down. "Stop targets" runs the normal stop sequence so devices with auto-restore restore their prior state. "Nothing" leaves the lights showing the last frame.</small>
                                    <select id="settings-shutdown-action">
                                        <option value="stop_targets">Stop targets</option>
                                        <option value="nothing">Nothing</option>
                                    </select>
                                </div>
                            </div>

                            <div class="form-group">
                                <div class="label-row">
                                    <label for="settings-daylight-timezone" data-i18n="settings.daylight_timezone.label">Daylight timezone</label>
                                    <button type="button" class="hint-toggle" onclick="toggleHint(this)" title="?">?</button>
                                </div>
                                <small class="input-hint" style="display:none" data-i18n="settings.daylight_timezone.hint">IANA timezone every "real-time" daylight cycle reads its wall clock in. Empty (default) uses the server's system timezone.</small>
                                <div class="tz-picker-wrap">
                                    <select id="settings-daylight-timezone"></select>
                                </div>
                            </div>

                            <div class="save-bar" id="settings-external-url-save-bar" hidden>
                                <div class="save-bar-msg">
                                    <span data-i18n="settings.save_bar.unsaved">Unsaved changes in</span>
                                    <strong data-i18n="settings.external_url.label">External URL</strong>
                                </div>
                                <div class="save-bar-actions">
                                    <button class="btn btn-ghost btn-sm" onclick="revertExternalUrl()" data-i18n="settings.save_bar.revert">Revert</button>
                                    <button class="btn btn-primary btn-sm" onclick="saveExternalUrl()">
                                        <svg class="icon" viewBox="0 0 24 24"><path d="M20 6 9 17l-5-5"/></svg>
                                        <span data-i18n="settings.save_bar.save">Save</span>
                                    </button>
                                </div>
                            </div>

                        </div>
                    </section>

                    <section class="ds-section" data-ch="coral">
                        <div class="ds-section-header">
                            <span class="ds-section-dot" aria-hidden="true"></span>
                            <span class="ds-section-title" data-i18n="settings.section.lifecycle">Lifecycle</span>
                            <span class="ds-section-meta" data-i18n="settings.section.destructive">DESTRUCTIVE</span>
                            <span class="ds-section-index" aria-hidden="true">03</span>
                        </div>
                        <div class="ds-section-body">

                            <div class="ds-toggle-row">
                                <div class="ds-toggle-text">
                                    <div class="ds-toggle-title" data-i18n="settings.logs.label">Server Logs</div>
                                    <div class="ds-toggle-sub" data-i18n="settings.logs.sub">Live tail of server log output, filterable by level. Opens in a full-screen overlay.</div>
                                </div>
                                <button class="btn btn-secondary" onclick="openLogOverlay()" data-i18n="settings.logs.open_viewer">Open Log Viewer</button>
                            </div>

                            <div class="ds-toggle-row ds-toggle-row--danger">
                                <div class="ds-toggle-text">
                                    <div class="ds-toggle-title" data-i18n="settings.restart_server">Restart Server</div>
                                    <div class="ds-toggle-sub" data-i18n="settings.restart.sub">Bounce the LedGrab process. Active capture and connected devices will pause for ~3 seconds.</div>
                                </div>
                                <button class="btn btn-danger" onclick="restartServer()">
                                    <svg class="icon" viewBox="0 0 24 24"><path d="M3 12a9 9 0 1 0 9-9"/><polyline points="3 4 3 10 9 10"/></svg>
                                    <span data-i18n="settings.restart.button">Restart</span>
                                </button>
                            </div>

                        </div>
                    </section>
                </div>

                <!-- ═══ Backup tab ═══ -->
                <div id="settings-panel-backup" class="settings-panel">

                    <section class="ds-section" data-ch="cyan">
                        <div class="ds-section-header">
                            <span class="ds-section-dot" aria-hidden="true"></span>
                            <span class="ds-section-title" data-i18n="settings.section.manual">Manual</span>
                            <span class="ds-section-index" aria-hidden="true">01</span>
                        </div>
                        <div class="ds-section-body">

                            <div class="ds-toggle-row">
                                <div class="ds-toggle-text">
                                    <div class="ds-toggle-title" data-i18n="settings.backup.label">Download Backup</div>
                                    <div class="ds-toggle-sub" data-i18n="settings.backup.hint">Download all configuration (devices, targets, streams, templates, automations) as a single JSON file.</div>
                                </div>
                                <button class="btn btn-primary" onclick="downloadBackup()">
                                    <svg class="icon" viewBox="0 0 24 24"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="7 10 12 15 17 10"/><line x1="12" x2="12" y1="15" y2="3"/></svg>
                                    <span data-i18n="settings.backup.button">Download</span>
                                </button>
                            </div>

                            <div class="ds-toggle-row ds-toggle-row--danger">
                                <div class="ds-toggle-text">
                                    <div class="ds-toggle-title" data-i18n="settings.restore.label">Restore Configuration</div>
                                    <div class="ds-toggle-sub" data-i18n="settings.restore.hint">Upload a previously downloaded backup file to replace all configuration. The server will restart automatically.</div>
                                </div>
                                <input type="file" id="settings-restore-input" accept=".db" style="display:none" onchange="handleRestoreFileSelected(this)">
                                <button class="btn btn-danger" onclick="document.getElementById('settings-restore-input').click()">
                                    <svg class="icon" viewBox="0 0 24 24"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="17 8 12 3 7 8"/><line x1="12" x2="12" y1="3" y2="15"/></svg>
                                    <span data-i18n="settings.restore.button">Restore</span>
                                </button>
                            </div>

                        </div>
                    </section>

                    <section class="ds-section" data-ch="amber">
                        <div class="ds-section-header">
                            <span class="ds-section-dot" aria-hidden="true"></span>
                            <span class="ds-section-title" data-i18n="settings.auto_backup.label">Auto-Backup</span>
                            <span class="ds-section-meta" id="auto-backup-status-pill" hidden></span>
                            <span class="ds-section-index" aria-hidden="true">02</span>
                        </div>
                        <div class="ds-section-body">

                            <div class="ds-toggle-row">
                                <div class="ds-toggle-text">
                                    <div class="ds-toggle-title" data-i18n="settings.auto_backup.enable">Enable auto-backup</div>
                                    <div class="ds-toggle-sub" id="auto-backup-status">&nbsp;</div>
                                </div>
                                <label class="settings-switch">
                                    <input type="checkbox" id="auto-backup-enabled">
                                    <span class="settings-switch-track" aria-hidden="true"></span>
                                </label>
                            </div>

                            <div class="ds-pair-row">
                                <div class="form-group">
                                    <div class="label-row">
                                        <label for="auto-backup-interval" data-i18n="settings.auto_backup.interval_label">Interval</label>
                                    </div>
                                    <select id="auto-backup-interval">
                                        <option value="1">1h</option>
                                        <option value="6">6h</option>
                                        <option value="12">12h</option>
                                        <option value="24">24h</option>
                                        <option value="48">48h</option>
                                        <option value="168">7d</option>
                                    </select>
                                </div>
                                <div class="form-group">
                                    <div class="label-row">
                                        <label for="auto-backup-max" data-i18n="settings.auto_backup.max_label">Max backups</label>
                                    </div>
                                    <input type="number" id="auto-backup-max" min="1" max="100" value="10">
                                </div>
                            </div>

                            <div class="inline-row inline-row--actions">
                                <button class="btn btn-secondary" onclick="triggerBackupNow()" style="flex:1">
                                    <svg class="icon" viewBox="0 0 24 24"><path d="M3 12a9 9 0 1 0 9-9"/><polyline points="3 4 3 10 9 10"/></svg>
                                    <span data-i18n="settings.auto_backup.backup_now">Backup Now</span>
                                </button>
                            </div>

                        </div>
                    </section>

                    <section class="ds-section" data-ch="cyan">
                        <div class="ds-section-header">
                            <span class="ds-section-dot" aria-hidden="true"></span>
                            <span class="ds-section-title" data-i18n="settings.saved_backups.label">Saved Backups</span>
                            <span class="ds-section-meta" id="saved-backups-meta" hidden></span>
                            <span class="ds-section-index" aria-hidden="true">03</span>
                        </div>
                        <div class="ds-section-body">
                            <small class="input-hint" data-i18n="settings.saved_backups.hint">Auto-backup files stored on the server. Download to save locally, or delete to free space.</small>
                            <div id="saved-backups-list" class="backup-list"></div>
                        </div>
                    </section>
                </div>

                <!-- ═══ Notifications tab ═══ -->
                <div id="settings-panel-notifications" class="settings-panel">

                    <section class="ds-section" data-ch="violet">
                        <div class="ds-section-header">
                            <span class="ds-section-dot" aria-hidden="true"></span>
                            <span class="ds-section-title" data-i18n="settings.section.notif_channels">Channels</span>
                            <span class="ds-section-meta" data-i18n="settings.notif_matrix.event_count">4 EVENTS</span>
                            <span class="ds-section-index" aria-hidden="true">01</span>
                        </div>
                        <div class="ds-section-body">

                            <small class="input-hint" style="display:block; margin-bottom:10px" data-i18n="settings.notifications.intro_hint">Pick how each device event reaches you. "Snack" shows an in-app toast, "OS" shows a system notification (browser must be granted permission), "Both" shows both, "None" silences the event entirely.</small>

                            <!-- Visual matrix — synced both ways with the hidden <select>s below. -->
                            <div class="notif-matrix" id="settings-notif-matrix" role="grid" aria-label="Notification preferences matrix">
                                <div class="notif-matrix-cell notif-matrix-head" role="columnheader" data-i18n="settings.notif_matrix.col.event">Event</div>
                                <div class="notif-matrix-cell notif-matrix-head" role="columnheader" data-i18n="settings.notifications.channel.snack.label">Snack</div>
                                <div class="notif-matrix-cell notif-matrix-head" role="columnheader" data-i18n="settings.notifications.channel.os.label">OS</div>
                                <div class="notif-matrix-cell notif-matrix-head" role="columnheader" data-i18n="settings.notifications.channel.both.label">Both</div>
                                <div class="notif-matrix-cell notif-matrix-head" role="columnheader" data-i18n="settings.notifications.channel.none.label">None</div>

                                <div class="notif-matrix-cell notif-matrix-row-label" role="rowheader">
                                    <svg class="icon" viewBox="0 0 24 24"><path d="M22 12h-4l-3 9L9 3l-3 9H2"/></svg>
                                    <span data-i18n="settings.notifications.row.online">Device came online</span>
                                </div>
                                <div class="notif-matrix-cell notif-matrix-opt" role="gridcell" data-event="device_online" data-channel="snack" tabindex="0"><span class="notif-matrix-dot"></span></div>
                                <div class="notif-matrix-cell notif-matrix-opt" role="gridcell" data-event="device_online" data-channel="os" tabindex="0"><span class="notif-matrix-dot"></span></div>
                                <div class="notif-matrix-cell notif-matrix-opt" role="gridcell" data-event="device_online" data-channel="both" tabindex="0"><span class="notif-matrix-dot"></span></div>
                                <div class="notif-matrix-cell notif-matrix-opt" role="gridcell" data-event="device_online" data-channel="none" tabindex="0"><span class="notif-matrix-dot"></span></div>

                                <div class="notif-matrix-cell notif-matrix-row-label" role="rowheader">
                                    <svg class="icon" viewBox="0 0 24 24"><circle cx="12" cy="12" r="10"/><line x1="4.93" y1="4.93" x2="19.07" y2="19.07"/></svg>
                                    <span data-i18n="settings.notifications.row.offline">Device went offline</span>
                                </div>
                                <div class="notif-matrix-cell notif-matrix-opt" role="gridcell" data-event="device_offline" data-channel="snack" tabindex="0"><span class="notif-matrix-dot"></span></div>
                                <div class="notif-matrix-cell notif-matrix-opt" role="gridcell" data-event="device_offline" data-channel="os" tabindex="0"><span class="notif-matrix-dot"></span></div>
                                <div class="notif-matrix-cell notif-matrix-opt" role="gridcell" data-event="device_offline" data-channel="both" tabindex="0"><span class="notif-matrix-dot"></span></div>
                                <div class="notif-matrix-cell notif-matrix-opt" role="gridcell" data-event="device_offline" data-channel="none" tabindex="0"><span class="notif-matrix-dot"></span></div>

                                <div class="notif-matrix-cell notif-matrix-row-label" role="rowheader">
                                    <svg class="icon" viewBox="0 0 24 24"><path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"/></svg>
                                    <span data-i18n="settings.notifications.row.discovered">New device found</span>
                                </div>
                                <div class="notif-matrix-cell notif-matrix-opt" role="gridcell" data-event="device_discovered" data-channel="snack" tabindex="0"><span class="notif-matrix-dot"></span></div>
                                <div class="notif-matrix-cell notif-matrix-opt" role="gridcell" data-event="device_discovered" data-channel="os" tabindex="0"><span class="notif-matrix-dot"></span></div>
                                <div class="notif-matrix-cell notif-matrix-opt" role="gridcell" data-event="device_discovered" data-channel="both" tabindex="0"><span class="notif-matrix-dot"></span></div>
                                <div class="notif-matrix-cell notif-matrix-opt" role="gridcell" data-event="device_discovered" data-channel="none" tabindex="0"><span class="notif-matrix-dot"></span></div>

                                <div class="notif-matrix-cell notif-matrix-row-label" role="rowheader">
                                    <svg class="icon" viewBox="0 0 24 24"><path d="M21 12a9 9 0 1 1-6.22-8.56"/></svg>
                                    <span data-i18n="settings.notifications.row.lost">Discovered device lost</span>
                                </div>
                                <div class="notif-matrix-cell notif-matrix-opt" role="gridcell" data-event="device_lost" data-channel="snack" tabindex="0"><span class="notif-matrix-dot"></span></div>
                                <div class="notif-matrix-cell notif-matrix-opt" role="gridcell" data-event="device_lost" data-channel="os" tabindex="0"><span class="notif-matrix-dot"></span></div>
                                <div class="notif-matrix-cell notif-matrix-opt" role="gridcell" data-event="device_lost" data-channel="both" tabindex="0"><span class="notif-matrix-dot"></span></div>
                                <div class="notif-matrix-cell notif-matrix-opt" role="gridcell" data-event="device_lost" data-channel="none" tabindex="0"><span class="notif-matrix-dot"></span></div>
                            </div>

                            <!-- Hidden underlying <select>s — settings.ts attaches IconSelect AND
                                 our matrix wiring keeps both in sync. Kept in DOM for backwards
                                 compat with notifications-watcher.ts. -->
                            <div class="notif-hidden-selects" hidden>
                                <select id="settings-notif-device-online" data-notif-event="device_online"></select>
                                <select id="settings-notif-device-offline" data-notif-event="device_offline"></select>
                                <select id="settings-notif-device-discovered" data-notif-event="device_discovered"></select>
                                <select id="settings-notif-device-lost" data-notif-event="device_lost"></select>
                            </div>
                        </div>
                    </section>

                    <section class="ds-section" data-ch="cyan">
                        <div class="ds-section-header">
                            <span class="ds-section-dot" aria-hidden="true"></span>
                            <span class="ds-section-title" data-i18n="settings.section.notif_discovery">Discovery</span>
                            <span class="ds-section-index" aria-hidden="true">02</span>
                        </div>
                        <div class="ds-section-body">
                            <div class="ds-toggle-row">
                                <div class="ds-toggle-text">
                                    <div class="ds-toggle-title" data-i18n="settings.notifications.background.label">Background discovery</div>
                                    <div class="ds-toggle-sub" data-i18n="settings.notifications.background.hint">Continuously scan the LAN (mDNS) and serial bus for new LED devices. Disable to silence "device discovered/lost" events at the source. Restart the server to apply.</div>
                                </div>
                                <label class="settings-switch">
                                    <input type="checkbox" id="settings-notif-background" checked>
                                    <span class="settings-switch-track" aria-hidden="true"></span>
                                </label>
                            </div>
                        </div>
                    </section>

                    <section class="ds-section" data-ch="amber">
                        <div class="ds-section-header">
                            <span class="ds-section-dot" aria-hidden="true"></span>
                            <span class="ds-section-title" data-i18n="settings.section.notif_permission">OS Permission</span>
                            <span class="ds-section-meta" id="settings-notif-permission-pill" hidden></span>
                            <span class="ds-section-index" aria-hidden="true">03</span>
                        </div>
                        <div class="ds-section-body">
                            <div class="ds-toggle-row" id="settings-notif-permission-row">
                                <div class="ds-toggle-text">
                                    <div class="label-row">
                                        <div class="ds-toggle-title" data-i18n="settings.notifications.permission.label">OS notification permission</div>
                                        <button type="button" class="hint-toggle" onclick="toggleHint(this)" title="?">?</button>
                                    </div>
                                    <small class="input-hint" style="display:none" data-i18n="settings.notifications.permission.hint">The browser controls OS notification permission per site. Once denied, LedGrab can no longer ask again — you need to clear it in the browser. Click the site icon (lock) in the address bar → Site settings → Notifications → Allow, then reload.</small>
                                    <div class="ds-toggle-sub" id="settings-notif-permission-state">&nbsp;</div>
                                </div>
                                <button class="btn btn-secondary" onclick="requestNotifPermissionFromSettings()" data-i18n="settings.notifications.permission.grant">Grant permission</button>
                            </div>

                            <div class="inline-row inline-row--actions">
                                <button class="btn btn-secondary" onclick="testNotifFromSettings()" style="flex:1" data-i18n="settings.notifications.test_button">Send a test notification</button>
                            </div>
                        </div>
                    </section>
                </div>

                <!-- ═══ Appearance tab ═══ -->
                <div id="settings-panel-appearance" class="settings-panel">
                    <!-- Rendered dynamically by renderAppearanceTab() -->
                </div>

                <!-- ═══ Updates tab ═══ -->
                <div id="settings-panel-updates" class="settings-panel">

                    <section class="ds-section" id="update-status-section" data-ch="signal">
                        <div class="ds-section-header">
                            <span class="ds-section-dot" aria-hidden="true"></span>
                            <span class="ds-section-title" data-i18n="update.status_label">Update Status</span>
                            <span class="ds-section-meta" id="update-status-meta" hidden></span>
                            <span class="ds-section-index" aria-hidden="true">01</span>
                        </div>
                        <div class="ds-section-body">

                            <div class="status-card" id="update-status-card">
                                <div class="status-card-icon" aria-hidden="true">
                                    <svg class="icon" viewBox="0 0 24 24"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="7 10 12 15 17 10"/><line x1="12" x2="12" y1="15" y2="3"/></svg>
                                </div>
                                <div class="status-card-text">
                                    <div class="status-card-main" id="update-status-text"></div>
                                    <div class="status-card-sub">
                                        <div class="status-card-line">
                                            <span data-i18n="update.current_version">Current version:</span>
                                            <strong id="update-current-version"></strong>
                                        </div>
                                        <div class="status-card-line">
                                            <span data-i18n="update.install_type_label">Install type:</span>
                                            <span id="update-install-type"></span>
                                        </div>
                                        <div class="status-card-line" id="update-last-check"></div>
                                    </div>
                                </div>
                                <div class="status-card-actions">
                                    <button id="update-check-btn" class="btn btn-secondary" onclick="checkForUpdates()">
                                        <span data-i18n="update.check_now">Check for Updates</span>
                                        <span id="update-check-spinner" class="spinner-inline" style="display:none"></span>
                                    </button>
                                    <button id="update-apply-btn" class="btn btn-primary" onclick="applyUpdate()" style="display:none" data-i18n="update.apply_now">Update Now</button>
                                </div>
                            </div>

                            <!-- Download progress bar -->
                            <div class="update-progress" id="update-progress-wrap" style="display:none">
                                <div id="update-progress-bar"></div>
                            </div>

                            <!-- Release notes — surfaced as a rack-style toggle-row -->
                            <div class="ds-toggle-row" id="update-release-notes-group" style="display:none">
                                <div class="ds-toggle-text">
                                    <div class="ds-toggle-title" data-i18n="update.view_release_notes">View Release Notes</div>
                                    <div class="ds-toggle-sub" data-i18n="update.release_notes_hint">What's new in the available version — read the changelog before applying.</div>
                                </div>
                                <button class="btn btn-secondary" onclick="openReleaseNotes()">
                                    <svg class="icon" viewBox="0 0 24 24"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/></svg>
                                    <span data-i18n="update.release_notes_open">Open</span>
                                </button>
                            </div>

                        </div>
                    </section>

                    <section class="ds-section" data-ch="amber">
                        <div class="ds-section-header">
                            <span class="ds-section-dot" aria-hidden="true"></span>
                            <span class="ds-section-title" data-i18n="update.auto_check_label">Auto-Check Settings</span>
                            <span class="ds-section-index" aria-hidden="true">02</span>
                        </div>
                        <div class="ds-section-body">

                            <div class="ds-toggle-row">
                                <div class="ds-toggle-text">
                                    <div class="ds-toggle-title" data-i18n="update.enable">Enable auto-check</div>
                                    <div class="ds-toggle-sub" data-i18n="update.auto_check_hint">Periodically check for new releases in the background.</div>
                                </div>
                                <label class="settings-switch">
                                    <input type="checkbox" id="update-enabled">
                                    <span class="settings-switch-track" aria-hidden="true"></span>
                                </label>
                            </div>

                            <div class="ds-pair-row">
                                <div class="form-group">
                                    <div class="label-row">
                                        <label for="update-interval" data-i18n="update.interval_label">Check interval</label>
                                    </div>
                                    <select id="update-interval">
                                        <option value="1">1h</option>
                                        <option value="6">6h</option>
                                        <option value="12">12h</option>
                                        <option value="24">24h</option>
                                        <option value="48">48h</option>
                                        <option value="168">7d</option>
                                    </select>
                                </div>
                                <div class="form-group">
                                    <div class="label-row">
                                        <label for="update-channel" data-i18n="update.channel_label">Channel</label>
                                    </div>
                                    <select id="update-channel">
                                        <option value="false">Stable</option>
                                        <option value="true">Pre-release</option>
                                    </select>
                                </div>
                            </div>

                        </div>
                    </section>
                </div>

                <!-- ═══ About tab ═══ -->
                <div id="settings-panel-about" class="settings-panel">
                    <div id="about-panel-content"></div>
                </div>

                <div id="settings-error" class="error-message" style="display:none;"></div>
            </div>
        </div>
    </div>
</div>

<!-- Log Viewer Overlay (full-screen, independent of settings modal) -->
<div id="log-overlay" class="log-overlay" style="display:none;" data-ch="cyan">
    <button class="log-overlay-close" onclick="closeLogOverlay()" title="Close" data-i18n-aria-label="aria.close" aria-label="Close">
        <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>
    </button>

    <article class="module log-module" data-ch="cyan">
        <div class="mod-head">
            <div class="mod-id">
                <span class="mod-badge">LOG · STREAM</span>
                <div class="mod-name"><span data-i18n="settings.logs.label">Server Logs</span></div>
                <div class="mod-meta">WebSocket · /api/v1/system/logs/ws</div>
            </div>
            <div class="mod-leds" id="log-viewer-leds" aria-hidden="true">
                <span class="led" data-role="link"></span>
                <span class="led" data-role="data"></span>
                <span class="led" data-role="data"></span>
            </div>
        </div>
        <div class="mod-metrics">
            <div class="mod-metric">
                <div class="k" data-i18n="settings.logs.stat.lines">LINES</div>
                <div class="v" id="log-stat-total">0</div>
            </div>
            <div class="mod-metric" id="log-stat-warn-cell">
                <div class="k">
                    <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M10.29 3.86 1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"/><line x1="12" y1="9" x2="12" y2="13"/><line x1="12" y1="17" x2="12.01" y2="17"/></svg>
                    <span data-i18n="settings.logs.stat.warn">WARN</span>
                </div>
                <div class="v" id="log-stat-warn">0</div>
            </div>
            <div class="mod-metric" id="log-stat-err-cell">
                <div class="k">
                    <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><line x1="12" y1="8" x2="12" y2="12"/><line x1="12" y1="16" x2="12.01" y2="16"/></svg>
                    <span data-i18n="settings.logs.stat.err">ERR</span>
                </div>
                <div class="v" id="log-stat-err">0</div>
            </div>
        </div>
        <div class="mod-foot log-mod-foot">
            <div class="mod-patch" id="log-patch-indicator">
                <span class="patch-dot"></span>
                <span id="log-patch-label" data-i18n="settings.logs.patch.idle">STANDBY</span>
            </div>
            <select id="log-viewer-filter" onchange="applyLogFilter()" class="log-filter-select">
                <option value="all" data-i18n="settings.logs.filter.all">All levels</option>
                <option value="INFO" data-i18n="settings.logs.filter.info">Info+</option>
                <option value="WARNING" data-i18n="settings.logs.filter.warning">Warning+</option>
                <option value="ERROR" data-i18n="settings.logs.filter.error">Error only</option>
            </select>
            <button id="log-viewer-connect-btn" class="mod-btn mod-btn-go" onclick="connectLogViewer()">
                <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polygon points="5 3 19 12 5 21 5 3"/></svg>
                <span data-i18n="settings.logs.connect">Connect</span>
            </button>
            <button class="mod-btn" onclick="clearLogViewer()" title="Clear">
                <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="3 6 5 6 21 6"/><path d="M19 6l-1 14a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2L5 6"/></svg>
                <span data-i18n="settings.logs.clear">Clear</span>
            </button>
        </div>
    </article>

    <div class="log-console" data-ch="cyan">
        <div class="log-console__rail" aria-hidden="true">
            <span class="log-console__caret">&#x25B8;</span>
            <span class="log-console__rail-label">TAIL</span>
        </div>
        <pre id="log-viewer-output" class="log-viewer-output"></pre>
        <div class="log-console__empty" id="log-viewer-empty">
            <div class="log-console__empty-mark" aria-hidden="true"></div>
            <div class="log-console__empty-title" data-i18n="settings.logs.empty.title">Awaiting log frames</div>
            <div class="log-console__empty-sub" data-i18n="settings.logs.empty.sub">Connect the WebSocket stream to begin tailing.</div>
        </div>
    </div>
</div>

<!-- Release Notes Overlay — v2 "instrument readout" aesthetic, scoped via .release-notes-shell -->
<div id="release-notes-overlay" class="log-overlay release-notes-shell" style="display:none;" data-ch="signal">
    <span class="rn-shell__stripe" aria-hidden="true"></span>
    <span class="rn-shell__bracket rn-shell__bracket--tl" aria-hidden="true"></span>
    <span class="rn-shell__bracket rn-shell__bracket--br" aria-hidden="true"></span>

    <header class="rn-head">
        <div class="rn-head__lede">
            <div class="rn-eyebrow">
                <span class="rn-eyebrow__dot" aria-hidden="true"></span>
                <span class="rn-eyebrow__text" data-i18n="update.release_notes">Release Notes</span>
                <span class="rn-eyebrow__sep" aria-hidden="true"></span>
                <span class="rn-eyebrow__channel" id="release-notes-channel">CHANGELOG</span>
            </div>
            <div class="rn-meta" id="release-notes-meta" hidden>
                <span class="rn-chip" id="release-notes-tag-chip" hidden>
                    <span class="rn-chip__dot" aria-hidden="true"></span>
                    <span class="rn-chip__k">TAG</span>
                    <span class="rn-chip__v" id="release-notes-tag">—</span>
                </span>
                <span class="rn-chip" id="release-notes-date-chip" hidden>
                    <span class="rn-chip__k">PUBLISHED</span>
                    <span class="rn-chip__v" id="release-notes-date">—</span>
                </span>
                <span class="rn-chip rn-chip--pre" id="release-notes-pre-chip" hidden>
                    <span class="rn-chip__k" data-i18n="update.prerelease">PRE-RELEASE</span>
                </span>
            </div>
        </div>

        <div class="rn-head__actions">
            <a class="rn-act rn-act--link" id="release-notes-external" href="#" target="_blank" rel="noopener"
               hidden data-i18n-title="update.view_release" title="View Release">
                <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"
                     stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
                    <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/>
                    <polyline points="15 3 21 3 21 9"/>
                    <line x1="10" y1="14" x2="21" y2="3"/>
                </svg>
            </a>
            <button class="rn-act rn-act--close" type="button" onclick="closeReleaseNotes()"
                    data-i18n-aria-label="aria.close" aria-label="Close">
                <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"
                     stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
                    <line x1="18" y1="6" x2="6" y2="18"/>
                    <line x1="6" y1="6" x2="18" y2="18"/>
                </svg>
            </button>
        </div>
    </header>

    <div class="rn-body">
        <div id="release-notes-content" class="release-notes-content"></div>
    </div>
</div>
