From 14be38fe1184db59523c2e44b10ca1bb6c3ebfb5 Mon Sep 17 00:00:00 2001 From: Koala <6156589+Shik3i@users.noreply.github.com> Date: Mon, 1 Jun 2026 02:10:27 +0200 Subject: [PATCH] feat(website): add build-time minification and optimize meta descriptions --- website/build.js | 95 +- website/locales/de.json | 2 +- website/locales/es.json | 2 +- website/locales/fr.json | 2 +- website/locales/pt-BR.json | 2 +- website/locales/ru.json | 2 +- website/style.css | 2 +- website/www/app.js | 1281 +++++++++-------- website/www/de/index.html | 2 +- website/www/es/index.html | 2 +- website/www/fr/index.html | 2 +- website/www/lang-init.js | 121 +- website/www/pt-BR/index.html | 2 +- website/www/ru/index.html | 2 +- website/www/style.css | 2573 +--------------------------------- 15 files changed, 787 insertions(+), 3305 deletions(-) diff --git a/website/build.js b/website/build.js index 90cdca6..1f0e2ff 100644 --- a/website/build.js +++ b/website/build.js @@ -6,6 +6,82 @@ const fs = require('fs'); const path = require('path'); +// Minify CSS: strips comments, collapses whitespace, removes trailing semicolons +function minifyCSS(code) { + return code + .replace(/\/\*[\s\S]*?\*\//g, '') + .replace(/\s*([{}:;,])\s*/g, '$1') + .replace(/\s+/g, ' ') + .replace(/;\}/g, '}') + .trim(); +} + +// Minify JS: state-machine that tracks string context so +// // inside URLs (https://) inside strings is never mistaken for a comment. +function minifyJS(code) { + var out = ''; + var inSingle = false, inDouble = false, inTemplate = false; + var templateBrace = 0; + var i = 0; + + while (i < code.length) { + var ch = code[i]; + var next = code[i + 1] || ''; + + // --- Escape handling (must come before string toggle) --- + if (ch === '\\' && (inSingle || inDouble || inTemplate)) { + out += ch + next; + i += 2; + continue; + } + + // --- String toggle --- + if (!inDouble && !inTemplate && ch === "'") { inSingle = !inSingle; out += ch; i++; continue; } + if (!inSingle && !inTemplate && ch === '"') { inDouble = !inDouble; out += ch; i++; continue; } + if (!inSingle && !inDouble) { + if (ch === '`' && !inTemplate) { inTemplate = true; templateBrace = 0; out += ch; i++; continue; } + if (inTemplate && ch === '`' && templateBrace === 0) { inTemplate = false; out += ch; i++; continue; } + } + + // --- Template interpolation depth tracking --- + if (inTemplate && !inSingle && !inDouble) { + if (ch === '$' && next === '{') { templateBrace++; out += ch + next; i += 2; continue; } + if (ch === '}' && templateBrace > 0) { templateBrace--; out += ch; i++; continue; } + } + + // --- Inside a string / template literal → output as-is --- + if (inSingle || inDouble || inTemplate) { out += ch; i++; continue; } + + // --- Outside strings: handle comments --- + if (ch === '/' && next === '/') { + while (i < code.length && code[i] !== '\n') i++; + out += '\n'; + i++; + continue; + } + if (ch === '/' && next === '*') { + i += 2; + while (i < code.length - 1) { + if (code[i] === '*' && code[i + 1] === '/') { i += 2; break; } + if (code[i] === '\n') out += '\n'; + i++; + } + continue; + } + + out += ch; + i++; + } + + // Collapse horizontal whitespace (preserve newlines) + return out + .replace(/[^\S\n]+/g, ' ') + .replace(/^ +/gm, '') + .replace(/ +$/gm, '') + .replace(/\n{3,}/g, '\n\n') + .trim(); +} + // Helper to recursively copy directories function copyDirSync(src, dest) { fs.mkdirSync(dest, { recursive: true }); @@ -18,6 +94,7 @@ function copyDirSync(src, dest) { if (entry.isDirectory()) { copyDirSync(srcPath, destPath); } else { + // Binary assets (images, etc.) are copied as-is fs.copyFileSync(srcPath, destPath); } } @@ -105,8 +182,22 @@ function compile() { const srcPath = path.join(websiteDir, file); const destPath = path.join(wwwDir, file); if (fs.existsSync(srcPath)) { - fs.copyFileSync(srcPath, destPath); - console.log(`Copied: ${file}`); + if (file.endsWith('.css')) { + const raw = fs.readFileSync(srcPath, 'utf8'); + const minified = minifyCSS(raw); + fs.writeFileSync(destPath, minified, 'utf8'); + const saved = ((raw.length - minified.length) / raw.length * 100).toFixed(0); + console.log(`Minified: ${file} (-${saved}%)`); + } else if (file.endsWith('.js')) { + const raw = fs.readFileSync(srcPath, 'utf8'); + const minified = minifyJS(raw); + fs.writeFileSync(destPath, minified, 'utf8'); + const saved = ((raw.length - minified.length) / raw.length * 100).toFixed(0); + console.log(`Minified: ${file} (-${saved}%)`); + } else { + fs.copyFileSync(srcPath, destPath); + console.log(`Copied: ${file}`); + } } else { console.warn(`Warning: Static file ${file} not found.`); } diff --git a/website/locales/de.json b/website/locales/de.json index 26743b9..c1e6512 100644 --- a/website/locales/de.json +++ b/website/locales/de.json @@ -6,7 +6,7 @@ "LANG_TOGGLE_TEXT": "EN", "META_TITLE": "KoalaSync | Netflix, YouTube & jedes Video mit Freunden synchronisieren", - "META_DESCRIPTION": "Schaue Netflix, YouTube, Twitch und jedes HTML5-Video perfekt synchronisiert mit Freunden. Kostenlose, quelloffene Browser-Erweiterung für Chrome und Firefox. Keine Anmeldung erforderlich.", + "META_DESCRIPTION": "Schaue Netflix, YouTube, Twitch und jedes HTML5-Video synchron mit Freunden. Kostenlose, quelloffene Browser-Erweiterung. Keine Anmeldung erforderlich.", "OG_TITLE": "KoalaSync | Netflix, Emby, Jellyfin & fast jedes Video mit Freunden synchronisieren", "OG_DESCRIPTION": "Schaue Netflix, Emby, Jellyfin, YouTube, Twitch und fast jedes HTML5-Video perfekt synchronisiert. Quelloffene, datenschutzfreundliche Browser-Erweiterung für Chrome und Firefox.", "TWITTER_TITLE": "KoalaSync | Netflix, Emby, Jellyfin & fast jedes Video mit Freunden synchronisieren – Browser-Erweiterung", diff --git a/website/locales/es.json b/website/locales/es.json index cfa4a0c..570dce3 100644 --- a/website/locales/es.json +++ b/website/locales/es.json @@ -6,7 +6,7 @@ "LANG_TOGGLE_TEXT": "EN", "META_TITLE": "KoalaSync | Sincroniza Netflix, YouTube y cualquier video con amigos", - "META_DESCRIPTION": "Mira Netflix, YouTube, Twitch y cualquier video HTML5 en perfecta sincronización con amigos. Extensión de navegador gratuita y de código abierto para Chrome y Firefox. No se requiere registro.", + "META_DESCRIPTION": "Mira Netflix, YouTube, Twitch y cualquier video HTML5 en perfecta sincronización con amigos. Extensión de navegador gratuita y de código abierto. Sin registro.", "OG_TITLE": "KoalaSync | Sincroniza Netflix, Emby, Jellyfin y casi cualquier video con amigos", "OG_DESCRIPTION": "Mira Netflix, Emby, Jellyfin, YouTube, Twitch y casi cualquier video HTML5 en perfecta sincronización. Extensión de navegador de código abierto y respetuosa con la privacidad para Chrome y Firefox.", "TWITTER_TITLE": "KoalaSync | Sincroniza Netflix, Emby, Jellyfin y casi cualquier video con amigos – Extensión de navegador", diff --git a/website/locales/fr.json b/website/locales/fr.json index 241af42..08623ea 100644 --- a/website/locales/fr.json +++ b/website/locales/fr.json @@ -6,7 +6,7 @@ "LANG_TOGGLE_TEXT": "EN", "META_TITLE": "KoalaSync | Synchronisez Netflix, YouTube et n'importe quelle vidéo avec vos amis", - "META_DESCRIPTION": "Regardez Netflix, YouTube, Twitch et n'importe quelle vidéo HTML5 en parfaite synchronisation avec vos amis. Extension de navigateur gratuite et open-source pour Chrome et Firefox. Aucune inscription requise.", + "META_DESCRIPTION": "Regardez Netflix, YouTube, Twitch et des vidéos HTML5 en synchro avec vos amis. Extension de navigateur gratuite et open-source. Aucune inscription requise.", "OG_TITLE": "KoalaSync | Synchronisez Netflix, Emby, Jellyfin et presque toutes les vidéos avec vos amis", "OG_DESCRIPTION": "Regardez Netflix, Emby, Jellyfin, YouTube, Twitch et presque n'importe quelle vidéo HTML5 en parfaite synchronisation. Extension de navigateur open-source et respectueuse de la vie privée pour Chrome et Firefox.", "TWITTER_TITLE": "KoalaSync | Synchronisez Netflix, Emby, Jellyfin et presque toutes les vidéos avec vos amis – Extension de navigateur", diff --git a/website/locales/pt-BR.json b/website/locales/pt-BR.json index e209381..7019a01 100644 --- a/website/locales/pt-BR.json +++ b/website/locales/pt-BR.json @@ -6,7 +6,7 @@ "LANG_TOGGLE_TEXT": "EN", "META_TITLE": "KoalaSync | Sincronize Netflix, YouTube e qualquer vídeo com amigos", - "META_DESCRIPTION": "Assista à Netflix, YouTube, Twitch e qualquer vídeo HTML5 em perfeita sincronia com amigos. Extensão de navegador gratuita e de código aberto para Chrome e Firefox. Sem necessidade de registro.", + "META_DESCRIPTION": "Assista Netflix, YouTube, Twitch e qualquer vídeo HTML5 em perfeita sincronia com amigos. Extensão de navegador gratuita e de código aberto. Sem registro.", "OG_TITLE": "KoalaSync | Sincronize Netflix, Emby, Jellyfin e quase qualquer vídeo com amigos", "OG_DESCRIPTION": "Assista à Netflix, Emby, Jellyfin, YouTube, Twitch e quase qualquer vídeo HTML5 em perfeita sincronia. Extensão de navegador de código aberto e focada em privacidade para Chrome e Firefox.", "TWITTER_TITLE": "KoalaSync | Sincronize Netflix, Emby, Jellyfin e quase qualquer vídeo com amigos – Extensão de navegador", diff --git a/website/locales/ru.json b/website/locales/ru.json index 0e96901..bf2206a 100644 --- a/website/locales/ru.json +++ b/website/locales/ru.json @@ -6,7 +6,7 @@ "LANG_TOGGLE_TEXT": "EN", "META_TITLE": "KoalaSync | Синхронизация Netflix, YouTube и любого видео с друзьями", - "META_DESCRIPTION": "Смотрите Netflix, YouTube, Twitch и любые HTML5-видео в идеальной синхронизации с друзьями. Бесплатное расширение с открытым исходным кодом для Chrome и Firefox. Регистрация не требуется.", + "META_DESCRIPTION": "Смотрите Netflix, YouTube, Twitch и любые HTML5-видео в синхронизации с друзьями. Бесплатное расширение браузера с открытым кодом. Регистрация не требуется.", "OG_TITLE": "KoalaSync | Синхронизация Netflix, Emby, Jellyfin и почти любого видео с друзьями", "OG_DESCRIPTION": "Смотрите Netflix, Emby, Jellyfin, YouTube, Twitch и почти любое HTML5-видео в идеальной синхронизации. Открытое и ориентированное на конфиденциальность расширение для Chrome и Firefox.", "TWITTER_TITLE": "KoalaSync | Синхронизация Netflix, Emby, Jellyfin и почти любого видео с друзьями – Расширение", diff --git a/website/style.css b/website/style.css index 1216e4d..532fa76 100644 --- a/website/style.css +++ b/website/style.css @@ -114,7 +114,7 @@ section { #self-hosting, .comparison-section { content-visibility: auto; - contain-intrinsic-size: 700px; + contain-intrinsic-size: auto 1400px; } /* --- Navigation --- */ diff --git a/website/www/app.js b/website/www/app.js index 578dd29..7ddd12c 100644 --- a/website/www/app.js +++ b/website/www/app.js @@ -1,661 +1,628 @@ -// KoalaSync Landing Page Logic - document.addEventListener('DOMContentLoaded', () => { - // Scroll Reveal Logic (IntersectionObserver for performance) - const revealElements = document.querySelectorAll('[data-reveal]'); - - const revealObserver = new IntersectionObserver((entries) => { - entries.forEach(entry => { - if (entry.isIntersecting) { - entry.target.classList.add('revealed'); - revealObserver.unobserve(entry.target); - } - }); - }, { - rootMargin: '0px 0px -150px 0px', - threshold: 0.1 - }); - revealElements.forEach(el => revealObserver.observe(el)); +const revealElements = document.querySelectorAll('[data-reveal]'); - // Navbar scroll effect - const nav = document.querySelector('nav'); - window.addEventListener('scroll', () => { - if (window.scrollY > 50) { - nav.style.padding = '0.75rem 0'; - nav.style.background = 'rgba(15, 23, 42, 0.9)'; - } else { - nav.style.padding = '1rem 0'; - nav.style.background = 'rgba(30, 41, 59, 0.7)'; - } - }); - - // Smooth scroll for anchors - document.querySelectorAll('a[href^="#"]').forEach(anchor => { - anchor.addEventListener('click', function (e) { - e.preventDefault(); - const target = document.querySelector(this.getAttribute('href')); - if (target) { - target.scrollIntoView({ - behavior: 'smooth', - block: 'start' - }); - } - }); - }); - - // Invite Detection & Bridge - const checkInvite = () => { - const isJoinPage = window.location.pathname.includes('join'); - - // Dev Simulation Mode via URL Search Parameter (?dev=success) or Hash (#dev=success / #devsuccess) - const urlParams = new URLSearchParams(window.location.search); - let devMode = urlParams.get('dev'); - - if (!devMode) { - const hashClean = window.location.hash.startsWith('#') ? window.location.hash.substring(1) : window.location.hash; - const hashParams = new URLSearchParams(hashClean); - devMode = hashParams.get('dev'); - } - - if (!devMode) { - if (window.location.hash.includes('devsuccess') || window.location.search.includes('devsuccess')) devMode = 'success'; - if (window.location.hash.includes('devfailure') || window.location.search.includes('devfailure')) devMode = 'failure'; - } - - if (isJoinPage && devMode) { - setTimeout(() => { - const displayRoom = document.getElementById('display-room-id'); - const actions = document.getElementById('join-actions'); - if (displayRoom) displayRoom.textContent = 'DEV-ROOM'; - - if (actions) { - actions.innerHTML = ` -
-
-
- Simulating connection (DEV)...Verbindung wird simuliert (DEV)... -
-

- Simulating status event in 1.5 seconds.Status-Event wird in 1,5 Sekunden simuliert. -

-
- `; - setTimeout(() => { - window.dispatchEvent(new CustomEvent('KOALASYNC_STATUS', { - detail: { - success: devMode === 'success', - message: devMode === 'failure' ? 'Simulated Connection Timeout!' : '' - } - })); - }, 1500); - } - }, 600); - return; - } - - // Use a short timeout to let the bridge script initialize its dataset attribute - setTimeout(() => { - const isInstalled = document.documentElement.dataset.koalasyncInstalled === 'true'; - - if (window.location.hash.startsWith('#join:')) { - const parts = window.location.hash.split(':'); - if (parts.length >= 3) { - const roomId = parts[1]; - const password = parts[2]; - const serverFlag = parts[3] || '0'; - const serverUrl = parts[4] ? decodeURIComponent(parts[4]) : ''; - - if (isJoinPage) { - const displayRoom = document.getElementById('display-room-id'); - const actions = document.getElementById('join-actions'); - if (displayRoom) displayRoom.textContent = roomId; - - if (actions) { - if (!isInstalled) { - const isFirefox = navigator.userAgent.includes('Firefox'); - if (isFirefox) { - actions.innerHTML = ` -
- - Firefox - GET IT ON MOZILLA ADD-ONSIM FIREFOX ADD-ON STORE HERUNTERLADEN - - - - Download via GitHubÜber GitHub herunterladen - -
-

- The extension is required to join and sync videos. - Die Erweiterung ist erforderlich, um beizutreten und Videos zu synchronisieren. -

- `; - } else { - actions.innerHTML = ` -
- - Chrome - GET IT ON CHROME WEBSTOREIM CHROME WEB STORE HERUNTERLADEN - - - - Download via GitHubÜber GitHub herunterladen - -
-

- The extension is required to join and sync videos. - Die Erweiterung ist erforderlich, um beizutreten und Videos zu synchronisieren. -

- `; - } - } else { - actions.innerHTML = ` -
-
-
- Joining room automatically...Raum wird automatisch betreten... -
-

- Your extension is taking care of it.Deine Erweiterung kümmert sich darum. -

-
- `; - - // AUTO-TRIGGER JOIN - setTimeout(() => { - window.dispatchEvent(new CustomEvent('KOALASYNC_JOIN_REQUEST', { - detail: { - roomId, - password, - useCustomServer: serverFlag === '1', - serverUrl: serverUrl - } - })); - }, 500); - } - } - } else { - // Fallback banner for index.html - if (!document.getElementById('koala-banner')) { - const banner = document.createElement('div'); - banner.className = 'invite-banner'; - banner.id = 'koala-banner'; - - const container = document.createElement('div'); - container.className = 'container'; - container.style.cssText = 'display:flex; justify-content:space-between; align-items:center;'; - - const inviteSpan = document.createElement('span'); - inviteSpan.appendChild(document.createTextNode('🎫 Invitation for ')); - const boldRoom = document.createElement('b'); - boldRoom.textContent = roomId; - inviteSpan.appendChild(boldRoom); - inviteSpan.appendChild(document.createTextNode(' detected!')); - - const joinLink = document.createElement('a'); - joinLink.href = 'join' + window.location.hash; - joinLink.className = 'btn-banner'; - joinLink.textContent = 'OPEN JOIN PAGE'; - - container.appendChild(inviteSpan); - container.appendChild(joinLink); - banner.appendChild(container); - document.body.prepend(banner); - } - } - - // Global listener for Join Button - document.addEventListener('click', (e) => { - if (e.target && e.target.id === 'webJoinBtn') { - e.target.textContent = 'JOINING...'; - e.target.disabled = true; - window.dispatchEvent(new CustomEvent('KOALASYNC_JOIN_REQUEST', { - detail: { - roomId, - password, - useCustomServer: serverFlag === '1', - serverUrl: serverUrl - } - })); - } - }); - } - } - }, 600); // 600ms delay to ensure bridge.js has set the dataset - }; - - // Listen for status from Extension - window.addEventListener('KOALASYNC_STATUS', (e) => { - const { success, message } = e.detail; - const isJoinPage = window.location.pathname.includes('join'); - - if (isJoinPage) { - const icon = document.getElementById('join-status-icon'); - const title = document.getElementById('join-title'); - const actions = document.getElementById('join-actions'); - const desc = document.getElementById('join-desc'); - const ring = document.getElementById('status-ring'); - - if (success) { - if (ring) { - ring.classList.remove('active-pulse'); - ring.style.display = 'none'; - } - if (icon) { - icon.innerHTML = 'Success'; - icon.style.transform = 'scale(1)'; - } - const isDE = document.documentElement.classList.contains('lang-de'); - title.textContent = isDE ? 'Erfolgreich!' : 'Success!'; - desc.innerHTML = isDE - ? 'Verbunden!
Wähle jetzt einen Video-Tab in der Erweiterung aus.' - : 'Connected!
Now select a video tab in the extension.'; - - let count = 3; - const updateCountdown = () => { - if (count <= 0) { - window.close(); - desc.textContent = isDE ? 'Beitritt erfolgreich! Du kannst diesen Tab jetzt manuell schließen.' : 'Joined successfully! You can close this tab manually.'; - } else { - count--; - setTimeout(updateCountdown, 1000); - } - }; - setTimeout(updateCountdown, 1000); - - const closeLabel = isDE ? 'TAB JETZT SCHLIESSEN' : 'CLOSE TAB NOW'; - actions.innerHTML = ` -
- -
- `; - } else { - if (ring) { - ring.classList.remove('active-pulse'); - ring.style.display = 'none'; - } - if (icon) { - icon.innerHTML = 'Error'; - icon.style.transform = 'scale(1)'; - } - const isDE = document.documentElement.classList.contains('lang-de'); - title.textContent = isDE ? 'Fehler' : 'Error'; - desc.textContent = isDE ? `Beitritt fehlgeschlagen: ${message}` : `Join failed: ${message}`; - const retryLabel = isDE ? 'ERNEUT VERSUCHEN' : 'TRY AGAIN'; - actions.innerHTML = ` -
- -
- `; - } - } else { - const banner = document.getElementById('koala-banner'); - if (banner) { - if (success) { - banner.style.background = 'var(--success)'; - banner.innerHTML = '
✅ Joined! This tab will close in 2s...
'; - setTimeout(() => window.close(), 2000); - } else { - banner.style.background = 'var(--error)'; - banner.innerHTML = ''; - const errDiv = document.createElement('div'); - errDiv.className = 'container'; - errDiv.textContent = '❌ Error: ' + message; - banner.appendChild(errDiv); - } - } - } - }); - - const updateDynamicVersion = async () => { - try { - const versionPath = document.documentElement.lang === 'de' ? '../version.json' : 'version.json'; - const response = await fetch(versionPath); - if (!response.ok) return; - const data = await response.json(); - const { version, date } = data; - if (!version || !date) return; - - const releaseDate = new Date(date); - const now = new Date(); - const diffMs = now - releaseDate; - const diffDays = Math.floor(diffMs / (1000 * 60 * 60 * 24)); - const diffHours = Math.floor(diffMs / (1000 * 60 * 60)); - const diffMins = Math.floor(diffMs / (1000 * 60)); - - let relativeTimeEn = ''; - let relativeTimeDe = ''; - - if (diffDays > 0) { - relativeTimeEn = `${diffDays} ${diffDays === 1 ? 'day' : 'days'} ago`; - relativeTimeDe = `vor ${diffDays} ${diffDays === 1 ? 'Tag' : 'Tagen'}`; - } else if (diffHours > 0) { - relativeTimeEn = `${diffHours} ${diffHours === 1 ? 'hour' : 'hours'} ago`; - relativeTimeDe = `vor ${diffHours} ${diffHours === 1 ? 'Stunde' : 'Stunden'}`; - } else if (diffMins > 0) { - relativeTimeEn = `${diffMins} ${diffMins === 1 ? 'minute' : 'minutes'} ago`; - relativeTimeDe = `vor ${diffMins} ${diffMins === 1 ? 'Minute' : 'Minuten'}`; - } else { - relativeTimeEn = 'just now'; - relativeTimeDe = 'gerade eben'; - } - - const badgeEn = document.querySelector('.version-text-en'); - const badgeDe = document.querySelector('.version-text-de'); - - if (badgeEn) { - badgeEn.textContent = `v${version} OUT NOW • ${relativeTimeEn}`; - } - if (badgeDe) { - badgeDe.textContent = `v${version} JETZT VERFÜGBAR • ${relativeTimeDe}`; - } - - // Update Schema.org structured data dynamically - const schemaScript = document.getElementById('schema-software'); - if (schemaScript) { - try { - const schema = JSON.parse(schemaScript.textContent); - schema.softwareVersion = version; - schemaScript.textContent = JSON.stringify(schema, null, 2); - } catch (err) { - console.warn('Failed to dynamically update schema version:', err); - } - } - } catch (e) { - console.warn('Failed to fetch dynamic version info:', e); - } - }; - - // Extension Mockup Tab Switcher - const mockTabs = document.querySelectorAll('.mock-tab'); - const mockScreens = document.querySelectorAll('.mock-screen'); - - mockTabs.forEach(tab => { - tab.addEventListener('click', () => { - mockTabs.forEach(t => t.classList.remove('active')); - mockScreens.forEach(s => s.classList.remove('active')); - - tab.classList.add('active'); - const targetId = tab.getAttribute('data-target'); - const targetScreen = document.getElementById(targetId); - if (targetScreen) { - targetScreen.classList.add('active'); - } - }); - }); - - // Terminal Tab Switcher - const termTabBtns = document.querySelectorAll('.terminal-tab-btn'); - const termPanes = document.querySelectorAll('.terminal-pane'); - - termTabBtns.forEach(btn => { - btn.addEventListener('click', () => { - termTabBtns.forEach(b => b.classList.remove('active')); - termPanes.forEach(p => p.classList.remove('active')); - - btn.classList.add('active'); - const targetPaneId = btn.getAttribute('data-tab'); - const targetPane = document.getElementById(targetPaneId); - if (targetPane) { - targetPane.classList.add('active'); - } - }); - }); - - // Terminal Clipboard Copy - const copyBtn = document.querySelector('.terminal-copy-btn'); - if (copyBtn) { - copyBtn.addEventListener('click', () => { - const activePane = document.querySelector('.terminal-pane.active'); - if (!activePane) return; - const codeElement = activePane.querySelector('code'); - if (!codeElement) return; - - const textToCopy = codeElement.innerText || codeElement.textContent; - - navigator.clipboard.writeText(textToCopy).then(() => { - const isDE = document.documentElement.classList.contains('lang-de'); - const originalHTML = copyBtn.innerHTML; - - copyBtn.innerHTML = isDE ? '✅ Kopiert!' : '✅ Copied!'; - copyBtn.disabled = true; - - setTimeout(() => { - copyBtn.innerHTML = originalHTML; - copyBtn.disabled = false; - }, 2000); - }).catch(err => { - console.error('Failed to copy text: ', err); - }); - }); - } - - // Mobile Hamburger Menu Toggle - const hamburger = document.querySelector('.hamburger'); - const navLinks = document.querySelector('.nav-links'); - if (hamburger && navLinks) { - // Initialize accessibility attribute - hamburger.setAttribute('aria-expanded', 'false'); - - hamburger.addEventListener('click', () => { - const isOpen = navLinks.classList.toggle('open'); - hamburger.setAttribute('aria-expanded', isOpen ? 'true' : 'false'); - }); - } - - // Dynamically localize home links on root dynamic pages (impressum, datenschutz, join) - const localizeHomeLinks = () => { - const activeLang = localStorage.getItem('koala_lang') || (navigator.language.startsWith('de') ? 'de' : 'en'); - const path = window.location.pathname; - const pathSegments = path.split('/'); - const isSubdir = pathSegments.some(seg => ['de', 'fr', 'es', 'pt-BR', 'ru'].includes(seg)); - - // Only need to do this dynamic rewrite if we are NOT already inside a localized subdirectory - if (!isSubdir) { - const homeLinks = document.querySelectorAll('a[href="./"], a[href="de/"], a[href="fr/"], a[href="es/"], a[href="pt-BR/"], a[href="ru/"]'); - homeLinks.forEach(link => { - link.href = (activeLang === 'en') ? './' : `${activeLang}/`; - }); - } - }; - - // Modern Language Selector Navigation and State Toggling - const handleLanguageChange = (e) => { - const select = e.currentTarget; - const newLang = select.value; - const path = window.location.pathname; - - // Save the user's preference - localStorage.setItem('koala_lang', newLang); - - // Determine if we are on a static landing page versus a dynamic utility page - const isLegalOrJoin = path.includes('impressum') || path.includes('datenschutz') || path.includes('join'); - const isIndex = !isLegalOrJoin; - - if (isIndex) { - // Static navigation: Route to correct subdirectory - const pathSegments = path.split('/'); - const isSubdir = pathSegments.some(seg => ['de', 'fr', 'es', 'pt-BR', 'ru'].includes(seg)); - - let targetPath; - if (newLang === 'en') { - if (isSubdir) { - targetPath = '../'; - } else { - targetPath = './'; - } - } else { - if (isSubdir) { - // Switching from one language subdirectory to another (e.g., /de/ to /fr/) - targetPath = '../' + newLang + '/'; - } else { - // Switching from root (English) to a language subdirectory (e.g., / to /fr/) - targetPath = newLang + '/'; - } - } - - window.location.href = targetPath; - } else { - // Dynamic page: Toggle classes and update elements dynamically without navigating away - const html = document.documentElement; - html.classList.remove('lang-en', 'lang-de', 'lang-fr', 'lang-es', 'lang-pt-br', 'lang-ru'); - - // Fallback dynamic pages to 'en' if 'de' is not chosen (since fr/es markup is not present) - const activeDisplayLang = (newLang === 'de') ? 'de' : 'en'; - html.classList.add('lang-' + activeDisplayLang); - html.lang = activeDisplayLang; - - // Sync all selects on the page to the new value - document.querySelectorAll('.lang-dropdown').forEach(sel => { - sel.value = newLang; - }); - - // Update titles dynamically - const isJoin = path.includes('join'); - if (isJoin) { - const titles = { en: 'Join Room | KoalaSync', de: 'Raum beitreten | KoalaSync' }; - document.title = titles[activeDisplayLang] || titles.en; - } - - // Localize home links dynamically - localizeHomeLinks(); - } - }; - - // Register change event listener for the dropdowns - document.querySelectorAll('.lang-dropdown').forEach(select => { - select.addEventListener('change', handleLanguageChange); - }); - - // Initialize language select elements to show the current preferred language - const initLanguageSelectorValue = () => { - const savedLang = localStorage.getItem('koala_lang'); - const browserLang = navigator.language.startsWith('de') ? 'de' : 'en'; - const activePref = savedLang || browserLang; - - document.querySelectorAll('.lang-dropdown').forEach(select => { - select.value = activePref; - }); - }; - - // Impressum Email Obfuscation Click Reveal - document.querySelectorAll('.email-reveal').forEach(el => { - el.addEventListener('click', function() { - const user = this.getAttribute('data-user'); - const domain = this.getAttribute('data-domain'); - if (user && domain) { - this.innerHTML = `${user}@${domain}`; - } - }); - }); - - // Automated Store/Local Badge Linking based on User-Agent - const detectBrowserAndElevateBadge = () => { - const isFirefox = navigator.userAgent.includes('Firefox'); - const isChrome = navigator.userAgent.includes('Chrome') || navigator.userAgent.includes('Chromium'); - const chromeBtns = document.querySelectorAll('.btn-primary'); - const firefoxBtns = document.querySelectorAll('.btn-firefox'); - - if (isFirefox && chromeBtns.length > 0 && firefoxBtns.length > 0) { - // User is on Firefox: Elevate Firefox button to primary, make Chrome secondary - chromeBtns.forEach(btn => { - btn.classList.remove('btn-primary'); - btn.classList.add('btn-secondary'); - }); - - firefoxBtns.forEach(btn => { - // Put Firefox first in visual order - btn.style.order = '-1'; - - // Add subtle focus scale effect - btn.style.transform = 'scale(1.05)'; - btn.addEventListener('mouseleave', () => { - btn.style.transform = 'scale(1)'; - }); - btn.addEventListener('mouseenter', () => { - btn.style.transform = 'scale(1.05) translateY(-2px)'; - }); - }); - } else if (isChrome && chromeBtns.length > 0 && firefoxBtns.length > 0) { - // User is on Chrome: Make Firefox secondary - firefoxBtns.forEach(btn => { - btn.classList.remove('btn-firefox'); - btn.classList.add('btn-secondary'); - btn.style.color = 'var(--text)'; - btn.style.background = 'var(--card)'; - btn.style.border = '1px solid var(--glass-border)'; - btn.style.boxShadow = 'none'; - }); - } - - // Handle Step 1 Landing Page Download Badges & Nav Badge - setTimeout(() => { - const isInstalled = document.documentElement.dataset.koalasyncInstalled === 'true'; - - // Nav Badge Logic - const navBadge = document.getElementById('nav-extension-status'); - if (isInstalled && navBadge) { - navBadge.style.display = 'inline-flex'; - } - - const illusChrome = document.querySelectorAll('.illus-store-btn.chrome'); - const illusFirefox = document.querySelectorAll('.illus-store-btn.firefox'); - - if (isFirefox && illusFirefox.length > 0) { - illusFirefox.forEach(btn => { - btn.style.order = '-1'; - if (!isInstalled) { - btn.classList.add('install-breathe'); - btn.style.cursor = 'pointer'; - btn.onclick = () => window.open('https://addons.mozilla.org/de/firefox/addon/koalasync/', '_blank'); - } - }); - illusChrome.forEach(btn => { - btn.style.opacity = '0.5'; - btn.style.transform = 'scale(0.95)'; - }); - } else if (isChrome && illusChrome.length > 0) { - illusChrome.forEach(btn => { - btn.style.order = '-1'; - if (!isInstalled) { - btn.classList.add('install-breathe'); - btn.style.cursor = 'pointer'; - btn.onclick = () => window.open('https://chromewebstore.google.com/detail/koalasync/obbnmkmlaaddodakcbdljknjpagklifc', '_blank'); - } - }); - illusFirefox.forEach(btn => { - btn.style.opacity = '0.5'; - btn.style.transform = 'scale(0.95)'; - }); - } - - // Pulse main hero CTA buttons via Web Animations API - // (avoids CSS transition/inline-style conflicts from mouse handlers) - if (!isInstalled) { - const heroBtns = document.querySelectorAll(isFirefox ? '.btn-firefox' : (isChrome ? '.btn-primary' : null)); - if (heroBtns && heroBtns.length > 0) { - heroBtns.forEach(btn => { - const isFF = btn.classList.contains('btn-firefox'); - const glowColor = isFF ? 'rgba(249, 115, 22, ' : 'rgba(99, 102, 241, '; - btn.animate([ - { transform: 'scale(1)', boxShadow: `0 0 15px ${glowColor}0.2)` }, - { transform: 'scale(1.05)', boxShadow: `0 0 25px ${glowColor}0.5)` }, - { transform: 'scale(1)', boxShadow: `0 0 15px ${glowColor}0.2)` } - ], { - duration: 2500, - iterations: Infinity, - easing: 'ease-in-out' - }); - }); - } - } - }, 600); - }; - - detectBrowserAndElevateBadge(); - checkInvite(); - updateDynamicVersion(); - localizeHomeLinks(); - initLanguageSelectorValue(); +const revealObserver = new IntersectionObserver((entries) => { +entries.forEach(entry => { +if (entry.isIntersecting) { +entry.target.classList.add('revealed'); +revealObserver.unobserve(entry.target); +} }); +}, { +rootMargin: '0px 0px -150px 0px', +threshold: 0.1 +}); + +revealElements.forEach(el => revealObserver.observe(el)); + +const nav = document.querySelector('nav'); +window.addEventListener('scroll', () => { +if (window.scrollY > 50) { +nav.style.padding = '0.75rem 0'; +nav.style.background = 'rgba(15, 23, 42, 0.9)'; +} else { +nav.style.padding = '1rem 0'; +nav.style.background = 'rgba(30, 41, 59, 0.7)'; +} +}); + +document.querySelectorAll('a[href^="#"]').forEach(anchor => { +anchor.addEventListener('click', function (e) { +e.preventDefault(); +const target = document.querySelector(this.getAttribute('href')); +if (target) { +target.scrollIntoView({ +behavior: 'smooth', +block: 'start' +}); +} +}); +}); + +const checkInvite = () => { +const isJoinPage = window.location.pathname.includes('join'); + +const urlParams = new URLSearchParams(window.location.search); +let devMode = urlParams.get('dev'); + +if (!devMode) { +const hashClean = window.location.hash.startsWith('#') ? window.location.hash.substring(1) : window.location.hash; +const hashParams = new URLSearchParams(hashClean); +devMode = hashParams.get('dev'); +} + +if (!devMode) { +if (window.location.hash.includes('devsuccess') || window.location.search.includes('devsuccess')) devMode = 'success'; +if (window.location.hash.includes('devfailure') || window.location.search.includes('devfailure')) devMode = 'failure'; +} + +if (isJoinPage && devMode) { +setTimeout(() => { +const displayRoom = document.getElementById('display-room-id'); +const actions = document.getElementById('join-actions'); +if (displayRoom) displayRoom.textContent = 'DEV-ROOM'; + +if (actions) { +actions.innerHTML = ` +
+
+
+Simulating connection (DEV)...Verbindung wird simuliert (DEV)... +
+

+Simulating status event in 1.5 seconds.Status-Event wird in 1,5 Sekunden simuliert. +

+
+`; +setTimeout(() => { +window.dispatchEvent(new CustomEvent('KOALASYNC_STATUS', { +detail: { +success: devMode === 'success', +message: devMode === 'failure' ? 'Simulated Connection Timeout!' : '' +} +})); +}, 1500); +} +}, 600); +return; +} + +setTimeout(() => { +const isInstalled = document.documentElement.dataset.koalasyncInstalled === 'true'; + +if (window.location.hash.startsWith('#join:')) { +const parts = window.location.hash.split(':'); +if (parts.length >= 3) { +const roomId = parts[1]; +const password = parts[2]; +const serverFlag = parts[3] || '0'; +const serverUrl = parts[4] ? decodeURIComponent(parts[4]) : ''; + +if (isJoinPage) { +const displayRoom = document.getElementById('display-room-id'); +const actions = document.getElementById('join-actions'); +if (displayRoom) displayRoom.textContent = roomId; + +if (actions) { +if (!isInstalled) { +const isFirefox = navigator.userAgent.includes('Firefox'); +if (isFirefox) { +actions.innerHTML = ` +
+ +Firefox +GET IT ON MOZILLA ADD-ONSIM FIREFOX ADD-ON STORE HERUNTERLADEN + + + +Download via GitHubÜber GitHub herunterladen + +
+

+The extension is required to join and sync videos. +Die Erweiterung ist erforderlich, um beizutreten und Videos zu synchronisieren. +

+`; +} else { +actions.innerHTML = ` +
+ +Chrome +GET IT ON CHROME WEBSTOREIM CHROME WEB STORE HERUNTERLADEN + + + +Download via GitHubÜber GitHub herunterladen + +
+

+The extension is required to join and sync videos. +Die Erweiterung ist erforderlich, um beizutreten und Videos zu synchronisieren. +

+`; +} +} else { +actions.innerHTML = ` +
+
+
+Joining room automatically...Raum wird automatisch betreten... +
+

+Your extension is taking care of it.Deine Erweiterung kümmert sich darum. +

+
+`; + +setTimeout(() => { +window.dispatchEvent(new CustomEvent('KOALASYNC_JOIN_REQUEST', { +detail: { +roomId, +password, +useCustomServer: serverFlag === '1', +serverUrl: serverUrl +} +})); +}, 500); +} +} +} else { + +if (!document.getElementById('koala-banner')) { +const banner = document.createElement('div'); +banner.className = 'invite-banner'; +banner.id = 'koala-banner'; + +const container = document.createElement('div'); +container.className = 'container'; +container.style.cssText = 'display:flex; justify-content:space-between; align-items:center;'; + +const inviteSpan = document.createElement('span'); +inviteSpan.appendChild(document.createTextNode('🎫 Invitation for ')); +const boldRoom = document.createElement('b'); +boldRoom.textContent = roomId; +inviteSpan.appendChild(boldRoom); +inviteSpan.appendChild(document.createTextNode(' detected!')); + +const joinLink = document.createElement('a'); +joinLink.href = 'join' + window.location.hash; +joinLink.className = 'btn-banner'; +joinLink.textContent = 'OPEN JOIN PAGE'; + +container.appendChild(inviteSpan); +container.appendChild(joinLink); +banner.appendChild(container); +document.body.prepend(banner); +} +} + +document.addEventListener('click', (e) => { +if (e.target && e.target.id === 'webJoinBtn') { +e.target.textContent = 'JOINING...'; +e.target.disabled = true; +window.dispatchEvent(new CustomEvent('KOALASYNC_JOIN_REQUEST', { +detail: { +roomId, +password, +useCustomServer: serverFlag === '1', +serverUrl: serverUrl +} +})); +} +}); +} +} +}, 600); +}; + +window.addEventListener('KOALASYNC_STATUS', (e) => { +const { success, message } = e.detail; +const isJoinPage = window.location.pathname.includes('join'); + +if (isJoinPage) { +const icon = document.getElementById('join-status-icon'); +const title = document.getElementById('join-title'); +const actions = document.getElementById('join-actions'); +const desc = document.getElementById('join-desc'); +const ring = document.getElementById('status-ring'); + +if (success) { +if (ring) { +ring.classList.remove('active-pulse'); +ring.style.display = 'none'; +} +if (icon) { +icon.innerHTML = 'Success'; +icon.style.transform = 'scale(1)'; +} +const isDE = document.documentElement.classList.contains('lang-de'); +title.textContent = isDE ? 'Erfolgreich!' : 'Success!'; +desc.innerHTML = isDE +? 'Verbunden!
Wähle jetzt einen Video-Tab in der Erweiterung aus.' +: 'Connected!
Now select a video tab in the extension.'; + +let count = 3; +const updateCountdown = () => { +if (count <= 0) { +window.close(); +desc.textContent = isDE ? 'Beitritt erfolgreich! Du kannst diesen Tab jetzt manuell schließen.' : 'Joined successfully! You can close this tab manually.'; +} else { +count--; +setTimeout(updateCountdown, 1000); +} +}; +setTimeout(updateCountdown, 1000); + +const closeLabel = isDE ? 'TAB JETZT SCHLIESSEN' : 'CLOSE TAB NOW'; +actions.innerHTML = ` +
+ +
+`; +} else { +if (ring) { +ring.classList.remove('active-pulse'); +ring.style.display = 'none'; +} +if (icon) { +icon.innerHTML = 'Error'; +icon.style.transform = 'scale(1)'; +} +const isDE = document.documentElement.classList.contains('lang-de'); +title.textContent = isDE ? 'Fehler' : 'Error'; +desc.textContent = isDE ? `Beitritt fehlgeschlagen: ${message}` : `Join failed: ${message}`; +const retryLabel = isDE ? 'ERNEUT VERSUCHEN' : 'TRY AGAIN'; +actions.innerHTML = ` +
+ +
+`; +} +} else { +const banner = document.getElementById('koala-banner'); +if (banner) { +if (success) { +banner.style.background = 'var(--success)'; +banner.innerHTML = '
✅ Joined! This tab will close in 2s...
'; +setTimeout(() => window.close(), 2000); +} else { +banner.style.background = 'var(--error)'; +banner.innerHTML = ''; +const errDiv = document.createElement('div'); +errDiv.className = 'container'; +errDiv.textContent = '❌ Error: ' + message; +banner.appendChild(errDiv); +} +} +} +}); + +const updateDynamicVersion = async () => { +try { +const versionPath = document.documentElement.lang === 'de' ? '../version.json' : 'version.json'; +const response = await fetch(versionPath); +if (!response.ok) return; +const data = await response.json(); +const { version, date } = data; +if (!version || !date) return; + +const releaseDate = new Date(date); +const now = new Date(); +const diffMs = now - releaseDate; +const diffDays = Math.floor(diffMs / (1000 * 60 * 60 * 24)); +const diffHours = Math.floor(diffMs / (1000 * 60 * 60)); +const diffMins = Math.floor(diffMs / (1000 * 60)); + +let relativeTimeEn = ''; +let relativeTimeDe = ''; + +if (diffDays > 0) { +relativeTimeEn = `${diffDays} ${diffDays === 1 ? 'day' : 'days'} ago`; +relativeTimeDe = `vor ${diffDays} ${diffDays === 1 ? 'Tag' : 'Tagen'}`; +} else if (diffHours > 0) { +relativeTimeEn = `${diffHours} ${diffHours === 1 ? 'hour' : 'hours'} ago`; +relativeTimeDe = `vor ${diffHours} ${diffHours === 1 ? 'Stunde' : 'Stunden'}`; +} else if (diffMins > 0) { +relativeTimeEn = `${diffMins} ${diffMins === 1 ? 'minute' : 'minutes'} ago`; +relativeTimeDe = `vor ${diffMins} ${diffMins === 1 ? 'Minute' : 'Minuten'}`; +} else { +relativeTimeEn = 'just now'; +relativeTimeDe = 'gerade eben'; +} + +const badgeEn = document.querySelector('.version-text-en'); +const badgeDe = document.querySelector('.version-text-de'); + +if (badgeEn) { +badgeEn.textContent = `v${version} OUT NOW • ${relativeTimeEn}`; +} +if (badgeDe) { +badgeDe.textContent = `v${version} JETZT VERFÜGBAR • ${relativeTimeDe}`; +} + +const schemaScript = document.getElementById('schema-software'); +if (schemaScript) { +try { +const schema = JSON.parse(schemaScript.textContent); +schema.softwareVersion = version; +schemaScript.textContent = JSON.stringify(schema, null, 2); +} catch (err) { +console.warn('Failed to dynamically update schema version:', err); +} +} +} catch (e) { +console.warn('Failed to fetch dynamic version info:', e); +} +}; + +const mockTabs = document.querySelectorAll('.mock-tab'); +const mockScreens = document.querySelectorAll('.mock-screen'); + +mockTabs.forEach(tab => { +tab.addEventListener('click', () => { +mockTabs.forEach(t => t.classList.remove('active')); +mockScreens.forEach(s => s.classList.remove('active')); + +tab.classList.add('active'); +const targetId = tab.getAttribute('data-target'); +const targetScreen = document.getElementById(targetId); +if (targetScreen) { +targetScreen.classList.add('active'); +} +}); +}); + +const termTabBtns = document.querySelectorAll('.terminal-tab-btn'); +const termPanes = document.querySelectorAll('.terminal-pane'); + +termTabBtns.forEach(btn => { +btn.addEventListener('click', () => { +termTabBtns.forEach(b => b.classList.remove('active')); +termPanes.forEach(p => p.classList.remove('active')); + +btn.classList.add('active'); +const targetPaneId = btn.getAttribute('data-tab'); +const targetPane = document.getElementById(targetPaneId); +if (targetPane) { +targetPane.classList.add('active'); +} +}); +}); + +const copyBtn = document.querySelector('.terminal-copy-btn'); +if (copyBtn) { +copyBtn.addEventListener('click', () => { +const activePane = document.querySelector('.terminal-pane.active'); +if (!activePane) return; +const codeElement = activePane.querySelector('code'); +if (!codeElement) return; + +const textToCopy = codeElement.innerText || codeElement.textContent; + +navigator.clipboard.writeText(textToCopy).then(() => { +const isDE = document.documentElement.classList.contains('lang-de'); +const originalHTML = copyBtn.innerHTML; + +copyBtn.innerHTML = isDE ? '✅ Kopiert!' : '✅ Copied!'; +copyBtn.disabled = true; + +setTimeout(() => { +copyBtn.innerHTML = originalHTML; +copyBtn.disabled = false; +}, 2000); +}).catch(err => { +console.error('Failed to copy text: ', err); +}); +}); +} + +const hamburger = document.querySelector('.hamburger'); +const navLinks = document.querySelector('.nav-links'); +if (hamburger && navLinks) { + +hamburger.setAttribute('aria-expanded', 'false'); + +hamburger.addEventListener('click', () => { +const isOpen = navLinks.classList.toggle('open'); +hamburger.setAttribute('aria-expanded', isOpen ? 'true' : 'false'); +}); +} + +const localizeHomeLinks = () => { +const activeLang = localStorage.getItem('koala_lang') || (navigator.language.startsWith('de') ? 'de' : 'en'); +const path = window.location.pathname; +const pathSegments = path.split('/'); +const isSubdir = pathSegments.some(seg => ['de', 'fr', 'es', 'pt-BR', 'ru'].includes(seg)); + +if (!isSubdir) { +const homeLinks = document.querySelectorAll('a[href="./"], a[href="de/"], a[href="fr/"], a[href="es/"], a[href="pt-BR/"], a[href="ru/"]'); +homeLinks.forEach(link => { +link.href = (activeLang === 'en') ? './' : `${activeLang}/`; +}); +} +}; + +const handleLanguageChange = (e) => { +const select = e.currentTarget; +const newLang = select.value; +const path = window.location.pathname; + +localStorage.setItem('koala_lang', newLang); + +const isLegalOrJoin = path.includes('impressum') || path.includes('datenschutz') || path.includes('join'); +const isIndex = !isLegalOrJoin; + +if (isIndex) { + +const pathSegments = path.split('/'); +const isSubdir = pathSegments.some(seg => ['de', 'fr', 'es', 'pt-BR', 'ru'].includes(seg)); + +let targetPath; +if (newLang === 'en') { +if (isSubdir) { +targetPath = '../'; +} else { +targetPath = './'; +} +} else { +if (isSubdir) { + +targetPath = '../' + newLang + '/'; +} else { + +targetPath = newLang + '/'; +} +} + +window.location.href = targetPath; +} else { + +const html = document.documentElement; +html.classList.remove('lang-en', 'lang-de', 'lang-fr', 'lang-es', 'lang-pt-br', 'lang-ru'); + +const activeDisplayLang = (newLang === 'de') ? 'de' : 'en'; +html.classList.add('lang-' + activeDisplayLang); +html.lang = activeDisplayLang; + +document.querySelectorAll('.lang-dropdown').forEach(sel => { +sel.value = newLang; +}); + +const isJoin = path.includes('join'); +if (isJoin) { +const titles = { en: 'Join Room | KoalaSync', de: 'Raum beitreten | KoalaSync' }; +document.title = titles[activeDisplayLang] || titles.en; +} + +localizeHomeLinks(); +} +}; + +document.querySelectorAll('.lang-dropdown').forEach(select => { +select.addEventListener('change', handleLanguageChange); +}); + +const initLanguageSelectorValue = () => { +const savedLang = localStorage.getItem('koala_lang'); +const browserLang = navigator.language.startsWith('de') ? 'de' : 'en'; +const activePref = savedLang || browserLang; + +document.querySelectorAll('.lang-dropdown').forEach(select => { +select.value = activePref; +}); +}; + +document.querySelectorAll('.email-reveal').forEach(el => { +el.addEventListener('click', function() { +const user = this.getAttribute('data-user'); +const domain = this.getAttribute('data-domain'); +if (user && domain) { +this.innerHTML = `${user}@${domain}`; +} +}); +}); + +const detectBrowserAndElevateBadge = () => { +const isFirefox = navigator.userAgent.includes('Firefox'); +const isChrome = navigator.userAgent.includes('Chrome') || navigator.userAgent.includes('Chromium'); +const chromeBtns = document.querySelectorAll('.btn-primary'); +const firefoxBtns = document.querySelectorAll('.btn-firefox'); + +if (isFirefox && chromeBtns.length > 0 && firefoxBtns.length > 0) { + +chromeBtns.forEach(btn => { +btn.classList.remove('btn-primary'); +btn.classList.add('btn-secondary'); +}); + +firefoxBtns.forEach(btn => { + +btn.style.order = '-1'; + +btn.style.transform = 'scale(1.05)'; +btn.addEventListener('mouseleave', () => { +btn.style.transform = 'scale(1)'; +}); +btn.addEventListener('mouseenter', () => { +btn.style.transform = 'scale(1.05) translateY(-2px)'; +}); +}); +} else if (isChrome && chromeBtns.length > 0 && firefoxBtns.length > 0) { + +firefoxBtns.forEach(btn => { +btn.classList.remove('btn-firefox'); +btn.classList.add('btn-secondary'); +btn.style.color = 'var(--text)'; +btn.style.background = 'var(--card)'; +btn.style.border = '1px solid var(--glass-border)'; +btn.style.boxShadow = 'none'; +}); +} + +setTimeout(() => { +const isInstalled = document.documentElement.dataset.koalasyncInstalled === 'true'; + +const navBadge = document.getElementById('nav-extension-status'); +if (isInstalled && navBadge) { +navBadge.style.display = 'inline-flex'; +} + +const illusChrome = document.querySelectorAll('.illus-store-btn.chrome'); +const illusFirefox = document.querySelectorAll('.illus-store-btn.firefox'); + +if (isFirefox && illusFirefox.length > 0) { +illusFirefox.forEach(btn => { +btn.style.order = '-1'; +if (!isInstalled) { +btn.classList.add('install-breathe'); +btn.style.cursor = 'pointer'; +btn.onclick = () => window.open('https://addons.mozilla.org/de/firefox/addon/koalasync/', '_blank'); +} +}); +illusChrome.forEach(btn => { +btn.style.opacity = '0.5'; +btn.style.transform = 'scale(0.95)'; +}); +} else if (isChrome && illusChrome.length > 0) { +illusChrome.forEach(btn => { +btn.style.order = '-1'; +if (!isInstalled) { +btn.classList.add('install-breathe'); +btn.style.cursor = 'pointer'; +btn.onclick = () => window.open('https://chromewebstore.google.com/detail/koalasync/obbnmkmlaaddodakcbdljknjpagklifc', '_blank'); +} +}); +illusFirefox.forEach(btn => { +btn.style.opacity = '0.5'; +btn.style.transform = 'scale(0.95)'; +}); +} + +if (!isInstalled) { +const heroBtns = document.querySelectorAll(isFirefox ? '.btn-firefox' : (isChrome ? '.btn-primary' : null)); +if (heroBtns && heroBtns.length > 0) { +heroBtns.forEach(btn => { +const isFF = btn.classList.contains('btn-firefox'); +const glowColor = isFF ? 'rgba(249, 115, 22, ' : 'rgba(99, 102, 241, '; +btn.animate([ +{ transform: 'scale(1)', boxShadow: `0 0 15px ${glowColor}0.2)` }, +{ transform: 'scale(1.05)', boxShadow: `0 0 25px ${glowColor}0.5)` }, +{ transform: 'scale(1)', boxShadow: `0 0 15px ${glowColor}0.2)` } +], { +duration: 2500, +iterations: Infinity, +easing: 'ease-in-out' +}); +}); +} +} +}, 600); +}; + +detectBrowserAndElevateBadge(); +checkInvite(); +updateDynamicVersion(); +localizeHomeLinks(); +initLanguageSelectorValue(); +}); \ No newline at end of file diff --git a/website/www/de/index.html b/website/www/de/index.html index 92b0a91..7417f9f 100644 --- a/website/www/de/index.html +++ b/website/www/de/index.html @@ -4,7 +4,7 @@ KoalaSync | Netflix, YouTube & jedes Video mit Freunden synchronisieren - + diff --git a/website/www/es/index.html b/website/www/es/index.html index 854afe9..4e43f1a 100644 --- a/website/www/es/index.html +++ b/website/www/es/index.html @@ -4,7 +4,7 @@ KoalaSync | Sincroniza Netflix, YouTube y cualquier video con amigos - + diff --git a/website/www/fr/index.html b/website/www/fr/index.html index 21428e3..2e31e31 100644 --- a/website/www/fr/index.html +++ b/website/www/fr/index.html @@ -4,7 +4,7 @@ KoalaSync | Synchronisez Netflix, YouTube et n'importe quelle vidéo avec vos amis - + diff --git a/website/www/lang-init.js b/website/www/lang-init.js index d1172ce..f354498 100644 --- a/website/www/lang-init.js +++ b/website/www/lang-init.js @@ -1,74 +1,69 @@ (function() { - var html = document.documentElement; - var path = window.location.pathname; +var html = document.documentElement; +var path = window.location.pathname; - // Mapping of browser language codes to KoalaSync locale directories - var langMap = { - 'de': 'de', - 'fr': 'fr', - 'es': 'es', - 'pt': 'pt-BR', - 'ru': 'ru' - }; +var langMap = { +'de': 'de', +'fr': 'fr', +'es': 'es', +'pt': 'pt-BR', +'ru': 'ru' +}; - // Check if we are on the root index page (either "/" or "/index.html" at the root) - var isRootIndex = path === '/' || path === '/index.html' || path === ''; +var isRootIndex = path === '/' || path === '/index.html' || path === ''; - if (isRootIndex) { - var savedLang = localStorage.getItem('koala_lang'); - var browserLang = navigator.language.split('-')[0]; - var preferredLang = savedLang || langMap[browserLang] || 'en'; +if (isRootIndex) { +var savedLang = localStorage.getItem('koala_lang'); +var browserLang = navigator.language.split('-')[0]; +var preferredLang = savedLang || langMap[browserLang] || 'en'; - if (preferredLang !== 'en') { - window.location.replace(preferredLang + '/'); - return; - } - } +if (preferredLang !== 'en') { +window.location.replace(preferredLang + '/'); +return; +} +} - var htmlClasses = html.className.split(' '); - var activeLang = null; - var hasStaticLang = false; - for (var i = 0; i < htmlClasses.length; i++) { - if (htmlClasses[i].indexOf('lang-') === 0) { - hasStaticLang = true; - var langPart = htmlClasses[i].substring(5); - activeLang = langPart === 'pt-br' ? 'pt-BR' : langPart; - break; - } - } +var htmlClasses = html.className.split(' '); +var activeLang = null; +var hasStaticLang = false; +for (var i = 0; i < htmlClasses.length; i++) { +if (htmlClasses[i].indexOf('lang-') === 0) { +hasStaticLang = true; +var langPart = htmlClasses[i].substring(5); +activeLang = langPart === 'pt-br' ? 'pt-BR' : langPart; +break; +} +} - if (hasStaticLang) { - localStorage.setItem('koala_lang', activeLang); - } else { - var savedLang = localStorage.getItem('koala_lang'); - var browserLang = navigator.language.split('-')[0]; - activeLang = savedLang || langMap[browserLang] || 'en'; +if (hasStaticLang) { +localStorage.setItem('koala_lang', activeLang); +} else { +var savedLang = localStorage.getItem('koala_lang'); +var browserLang = navigator.language.split('-')[0]; +activeLang = savedLang || langMap[browserLang] || 'en'; - // Dynamic utility pages currently only support English and German markup. - // Fallback to English for any other language to avoid bilingual text duplication. - if (activeLang !== 'de') { - activeLang = 'en'; - } +if (activeLang !== 'de') { +activeLang = 'en'; +} - html.classList.add('lang-' + activeLang); - html.lang = activeLang; - } +html.classList.add('lang-' + activeLang); +html.lang = activeLang; +} - // Update titles dynamically based on page - var isIndex = path === '/' || path.endsWith('index.html') || path.split('/').pop() === ''; - var isJoin = path.includes('join'); +var isIndex = path === '/' || path.endsWith('index.html') || path.split('/').pop() === ''; +var isJoin = path.includes('join'); - if (isIndex) { - var titles = { - en: 'KoalaSync | Real-time Video Synchronization for Friends', - de: 'KoalaSync | Echtzeit-Video-Synchronisation für Freunde' - }; - document.title = titles[activeLang] || titles.en; - } else if (isJoin) { - var titles = { - en: 'Join Room | KoalaSync', - de: 'Raum beitreten | KoalaSync' - }; - document.title = titles[activeLang] || titles.en; - } -})(); +if (isIndex) { +var titles = { +en: 'KoalaSync | Real-time Video Synchronization for Friends', +de: 'KoalaSync | Echtzeit-Video-Synchronisation für Freunde' +}; +document.title = titles[activeLang] || titles.en; +} else if (isJoin) { +var titles = { +en: 'Join Room | KoalaSync', +de: 'Raum beitreten | KoalaSync' +}; +document.title = titles[activeLang] || titles.en; +} +})(); \ No newline at end of file diff --git a/website/www/pt-BR/index.html b/website/www/pt-BR/index.html index bfbe62a..6b80226 100644 --- a/website/www/pt-BR/index.html +++ b/website/www/pt-BR/index.html @@ -4,7 +4,7 @@ KoalaSync | Sincronize Netflix, YouTube e qualquer vídeo com amigos - + diff --git a/website/www/ru/index.html b/website/www/ru/index.html index 41ac899..c8b635e 100644 --- a/website/www/ru/index.html +++ b/website/www/ru/index.html @@ -4,7 +4,7 @@ KoalaSync | Синхронизация Netflix, YouTube и любого видео с друзьями - + diff --git a/website/www/style.css b/website/www/style.css index 1216e4d..861229d 100644 --- a/website/www/style.css +++ b/website/www/style.css @@ -1,2572 +1 @@ -/* KoalaSync Design System - Privacy-Focused (No External Assets) */ - -:root { - --bg: #0f172a; - --card: #1e293b; - --accent: #6366f1; - --accent-glow: rgba(99, 102, 241, 0.3); - --text: #f8fafc; - --text-muted: #cbd5e1; /* Increased contrast for WCAG AA (6.28:1 contrast ratio) */ - --success: #22c55e; - --glass: rgba(30, 41, 59, 0.4); - --glass-border: rgba(255, 255, 255, 0.05); -} - -.invite-banner { - background: var(--accent); - color: white; - padding: 0.75rem 0; - text-align: center; - font-weight: 600; - font-size: 0.9rem; - position: relative; - z-index: 2000; - box-shadow: 0 4px 12px rgba(0,0,0,0.3); -} - -.btn-banner { - background: white; - color: var(--accent); - padding: 4px 12px; - border-radius: 6px; - text-decoration: none; - font-size: 0.8rem; - font-weight: 700; - margin-left: 12px; - cursor: pointer; - border: none; - transition: transform 0.2s; -} - -.btn-banner:hover { - transform: scale(1.05); -} - -* { - margin: 0; - padding: 0; - box-sizing: border-box; -} - -:focus-visible { - outline: 2px solid var(--accent); - outline-offset: 2px; - border-radius: 6px; -} - -body { - font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji"; - background-color: var(--bg); - color: var(--text); - line-height: 1.6; - overflow-x: hidden; - position: relative; -} - -/* --- Animated Background --- */ -.bg-blobs { - position: fixed; - top: 0; - left: 0; - width: 100%; - height: 100%; - z-index: -1; - overflow: hidden; - background: radial-gradient(circle at 50% 50%, #1e1b4b 0%, #0f172a 100%); -} - -.blob { - position: absolute; - width: 600px; - height: 600px; - background: radial-gradient(circle, var(--accent-glow) 0%, transparent 70%); - filter: blur(80px); - border-radius: 50%; - opacity: 0.5; - animation: move 25s infinite alternate ease-in-out; -} - -.blob-1 { top: -100px; left: -100px; animation-delay: 0s; } -.blob-2 { bottom: -100px; right: -100px; animation-delay: -5s; background: radial-gradient(circle, rgba(139, 92, 246, 0.2) 0%, transparent 70%); } -.blob-3 { top: 40%; left: 30%; animation-duration: 35s; animation-delay: -10s; } - -@keyframes move { - 0% { transform: translate(0, 0) scale(1); } - 33% { transform: translate(100px, 100px) scale(1.2); } - 66% { transform: translate(-50px, 200px) scale(0.8); } - 100% { transform: translate(0, 0) scale(1); } -} - -/* --- Layout --- */ -.container { - max-width: 1100px; - margin: 0 auto; - padding: 0 2rem; -} - -section { - padding: 6rem 0; -} - -/* Content-visibility for offscreen sections to improve INP */ -.use-cases-section, -#features, -#self-hosting, -.comparison-section { - content-visibility: auto; - contain-intrinsic-size: 700px; -} - -/* --- Navigation --- */ -nav { - position: fixed; - top: 0; - width: 100%; - z-index: 1000; - background: var(--glass); - backdrop-filter: blur(12px); - border-bottom: 1px solid var(--glass-border); - padding: 1rem 0; -} - -.nav-content { - display: flex; - justify-content: space-between; - align-items: center; -} - -.logo-area { - display: flex; - align-items: center; - gap: 0.75rem; - font-weight: 800; - font-size: 1.5rem; - letter-spacing: -0.5px; -} - -.logo-area img { - height: 40px; - width: 40px; -} - -.nav-ext-status { - display: inline-flex; - align-items: center; - gap: 4px; - padding: 3px 8px; - background: rgba(16, 185, 129, 0.15); - border: 1px solid rgba(16, 185, 129, 0.3); - color: #10b981; - border-radius: 12px; - font-size: 0.55rem; - font-weight: 700; - text-transform: uppercase; - letter-spacing: 0.05em; - box-shadow: 0 0 10px rgba(16, 185, 129, 0.1); - animation: fade-in 0.4s ease-out; - margin-left: 0.2rem; -} - -@keyframes fade-in { - from { opacity: 0; transform: translateY(-5px); } - to { opacity: 1; transform: translateY(0); } -} - -.nav-links { - display: flex; - gap: 2rem; -} - -.nav-links a { - color: var(--text-muted); - text-decoration: none; - font-weight: 500; - transition: color 0.3s; -} - -.nav-links a:hover { - color: var(--accent); -} - -/* --- Hero Section --- */ -.hero { - min-height: 100vh; - display: flex; - align-items: center; - padding-top: 8rem; - padding-bottom: 4rem; -} - -.hero-grid { - display: grid; - grid-template-columns: 1.2fr 1fr; - align-items: center; - gap: 4rem; - text-align: left; - width: 100%; -} - -.hero-text h1 { - font-size: 4.5rem; - font-weight: 800; - line-height: 1.1; - margin-bottom: 1.5rem; - background: linear-gradient(to bottom, #fff 40%, #6366f1); - -webkit-background-clip: text; - -webkit-text-fill-color: transparent; -} - -.hero-text p, .hero-subtitle { - font-size: 1.25rem; - color: var(--text-muted); - margin-bottom: 2.5rem; - max-width: 600px; - font-weight: 400; - line-height: 1.6; -} -.hero-mascot-container { - display: block; - margin-bottom: -0.5rem; - margin-left: 2.2rem; -} - -.hero-lookdown-mascot { - display: block; - width: 90px; - height: auto; -} - -@media (max-width: 768px) { - .hero-mascot-container { - margin-left: 0; - display: flex; - justify-content: center; - } -} - -.cta-group { - display: flex; - gap: 1rem; - flex-wrap: wrap; -} - -.btn { - padding: 0.85rem 1.75rem; - border-radius: 12px; - font-weight: 600; - text-decoration: none; - transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); - display: inline-flex; - align-items: center; - gap: 0.5rem; - font-size: 0.95rem; -} - -.btn-primary { - background: var(--accent); - color: white; - box-shadow: 0 10px 15px -3px var(--accent-glow); -} - -.btn-primary:hover { - transform: translateY(-2px); - box-shadow: 0 20px 25px -5px var(--accent-glow); -} - -.btn-firefox { - background: #e66000; - color: white; - box-shadow: 0 10px 15px -3px rgba(230, 96, 0, 0.3); -} - -.btn-firefox:hover { - background: #ff7300; - transform: translateY(-2px); - box-shadow: 0 20px 25px -5px rgba(230, 96, 0, 0.4); -} - -.btn-secondary { - background: var(--card); - color: var(--text); - border: 1px solid var(--glass-border); -} - -.btn-secondary:hover { - background: #2d3748; - transform: translateY(-2px); -} - -.version-badge { - display: inline-block; - background: rgba(99, 102, 241, 0.1); - color: var(--accent); - padding: 0.4rem 1rem; - border-radius: 99px; - font-size: 0.8rem; - font-weight: 700; - margin-bottom: 1.5rem; - border: 1px solid rgba(99, 102, 241, 0.3); - letter-spacing: 0.05em; - text-transform: uppercase; -} - -/* --- Interactive CSS Extension Mockup --- */ -.hero-mockup-wrapper { - display: flex; - justify-content: center; - align-items: center; - width: 100%; -} - -.extension-mockup { - width: 320px; - height: 520px; - background: #0f172a; - border-radius: 20px; - border: 1px solid rgba(255, 255, 255, 0.08); - box-shadow: 0 20px 40px rgba(0, 0, 0, 0.4), 0 0 20px rgba(99, 102, 241, 0.15); - display: flex; - flex-direction: column; - font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; - overflow: hidden; - position: relative; - user-select: none; - padding: 16px; - padding-bottom: 0; - box-sizing: border-box; -} - -.mock-header-row { - display: flex; - align-items: center; - margin-bottom: 16px; - flex-shrink: 0; -} - -.mock-header-title { - font-size: 18px; - margin: 0; - color: var(--accent); - letter-spacing: 1px; - text-transform: uppercase; - display: inline-flex; - align-items: center; - gap: 8px; - font-weight: 800; -} - -.mock-header-title img { - width: 24px; - height: 24px; - object-fit: contain; - border-radius: 4px; -} - -.mock-version-link { - margin-left: auto; - display: flex; - align-items: center; - gap: 4px; - font-size: 10px; - color: var(--text-muted); - text-decoration: none; - opacity: 0.5; - transition: opacity 0.2s, color 0.2s; - cursor: pointer; -} - -.mock-version-link:hover { - opacity: 1; - color: var(--accent); -} - -.mock-tabs { - display: flex; - gap: 4px; - background: #1e293b; - padding: 4px; - border-radius: 12px; - margin-bottom: 20px; - flex-shrink: 0; -} - -.mock-tab { - flex: 1; - background: none; - border: none; - color: var(--text-muted); - font-size: 0.75rem; - font-weight: 600; - padding: 8px 4px; - cursor: pointer; - border-radius: 8px; - transition: all 0.2s; - text-align: center; -} - -.mock-tab:hover { - color: var(--text); -} - -.mock-tab.active { - background: var(--accent); - color: white; -} - -.mock-body { - flex: 1; - overflow-y: auto; - padding: 0; - padding-bottom: 16px; - display: flex; - flex-direction: column; - font-size: 0.8rem; - scrollbar-width: none; /* Firefox */ -} - -.mock-body::-webkit-scrollbar { - display: none; /* Chrome, Safari, Opera */ -} - -.mock-screen { - display: none; - flex-direction: column; - gap: 12px; -} - -.mock-screen.active { - display: flex; -} - -/* Common Mockup Components */ -.mock-card { - background: #1e293b; - border: 1px solid #334155; - border-radius: 8px; - padding: 12px; -} - -.mock-label { - font-size: 0.65rem; - font-weight: 700; - color: var(--text-muted); - text-transform: uppercase; - letter-spacing: 0.05em; - margin-bottom: 0.4rem; -} - -.mock-input { - background: #1e293b; - border: 1px solid #334155; - border-radius: 8px; - color: white; - padding: 8px 10px; - font-size: 0.75rem; - width: 100%; - outline: none; -} - -.mock-btn { - background: var(--accent); - color: white; - border: none; - border-radius: 6px; - padding: 0.5rem; - font-weight: 600; - font-size: 0.75rem; - cursor: pointer; - transition: background 0.2s; - text-align: center; -} - -.mock-btn:hover { - background: #4f46e5; -} - -/* Room Tab Details */ -.mock-joined-room { - display: flex; - justify-content: space-between; - align-items: center; - background: rgba(99, 102, 241, 0.1); - border: 1px solid rgba(99, 102, 241, 0.2); - border-radius: 8px; - padding: 0.6rem 0.75rem; -} - -.mock-room-name { - font-weight: 700; - color: var(--accent); - font-size: 0.85rem; -} - -.mock-server-badge { - background: rgba(99, 102, 241, 0.2); - color: var(--accent); - font-size: 0.6rem; - font-weight: 700; - padding: 2px 6px; - border-radius: 4px; -} - -.mock-invite-box { - display: flex; - gap: 0.4rem; -} - -.mock-invite-box input { - flex: 1; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; -} - -.mock-peer-list { - display: flex; - flex-direction: column; - gap: 0.5rem; -} - -.mock-peer-item { - display: flex; - flex-direction: column; - background: rgba(255, 255, 255, 0.02); - border: 1px solid rgba(255, 255, 255, 0.03); - border-radius: 8px; - padding: 0.5rem 0.6rem; -} - -.mock-peer-header { - display: flex; - justify-content: space-between; - align-items: center; - margin-bottom: 0.25rem; -} - -.mock-peer-name { - font-weight: 700; - color: var(--text); -} - -.mock-peer-meta { - font-size: 0.65rem; - color: var(--text-muted); -} - -.mock-peer-tab { - font-size: 0.7rem; - color: var(--accent); - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; -} - -.mock-peer-status { - font-size: 0.65rem; - color: var(--text-muted); - display: flex; - align-items: center; - gap: 0.25rem; -} - -/* Sync Tab Details */ -.mock-target-box { - display: flex; - align-items: center; - gap: 0.4rem; - background: rgba(234, 179, 8, 0.1); - border: 1px solid rgba(234, 179, 8, 0.2); - color: #facc15; - padding: 0.5rem 0.6rem; - border-radius: 8px; - font-weight: 600; - font-size: 0.7rem; -} - -.mock-ctrl-buttons { - display: grid; - grid-template-columns: 1fr 1fr; - gap: 0.5rem; -} - -.mock-btn-play { background: #22c55e; } -.mock-btn-play:hover { background: #16a34a; } -.mock-btn-pause { background: #ef4444; } -.mock-btn-pause:hover { background: #dc2626; } -.mock-btn-force { background: var(--accent); grid-column: span 2; } - -.mock-status-display { - display: flex; - align-items: center; - justify-content: space-between; -} - -.mock-status-pill { - display: inline-flex; - align-items: center; - gap: 0.3rem; - background: rgba(34, 197, 94, 0.1); - border: 1px solid rgba(34, 197, 94, 0.2); - color: #22c55e; - padding: 2px 8px; - border-radius: 99px; - font-size: 0.65rem; - font-weight: 700; -} - -.mock-log-item { - font-size: 0.7rem; - color: var(--text-muted); - border-left: 2px solid var(--accent); - padding-left: 0.4rem; - margin-top: 0.4rem; -} - -/* Settings Tab Details */ -.mock-settings-row { - display: flex; - align-items: flex-start; - gap: 0.5rem; - margin-bottom: 0.6rem; -} - -.mock-settings-row input[type="checkbox"] { - margin-top: 0.2rem; - cursor: pointer; -} - -.mock-settings-row label { - cursor: pointer; - font-weight: 600; -} - -.mock-settings-row p { - font-size: 0.65rem; - color: var(--text-muted); - margin-top: 0.1rem; -} - -/* Mock Toggle Switch Details */ -.mock-toggle-switch { - position: relative; - display: inline-block; - width: 36px; - height: 20px; - flex-shrink: 0; -} - -.mock-toggle-switch input { - opacity: 0; - width: 0; - height: 0; -} - -.mock-slider { - position: absolute; - cursor: default; - top: 0; left: 0; right: 0; bottom: 0; - background-color: #334155; - transition: .3s; - border-radius: 20px; -} - -.mock-slider:before { - position: absolute; - content: ""; - height: 14px; - width: 14px; - left: 3px; - bottom: 3px; - background-color: #94a3b8; - transition: .3s; - border-radius: 50%; -} - -input:checked + .mock-slider { - background-color: var(--accent); -} - -input:checked + .mock-slider:before { - transform: translateX(16px); - background-color: white; -} - -/* Dev Tab Details */ -.mock-diagnostic-grid { - display: grid; - grid-template-columns: 1fr 1fr; - gap: 0.4rem; -} - -.mock-diag-box { - background: rgba(255, 255, 255, 0.02); - border: 1px solid rgba(255, 255, 255, 0.04); - border-radius: 6px; - padding: 0.4rem; -} - -.mock-diag-box .diag-val { - font-family: monospace; - font-weight: 700; - color: var(--accent); - font-size: 0.75rem; -} - -/* --- Features --- */ -/* Bento Grid Layout Configuration */ -.features-grid { - display: grid; - grid-template-columns: repeat(3, 1fr); - gap: 1.5rem; - margin-top: 4rem; -} - -.feature-card { - background: rgba(30, 41, 59, 0.45); - backdrop-filter: blur(16px) saturate(120%); - -webkit-backdrop-filter: blur(16px) saturate(120%); - padding: 2.5rem; - border-radius: 24px; - border: 1px solid rgba(255, 255, 255, 0.08); - box-shadow: 0 8px 32px 0 rgba(0, 0, 0, 0.3); - transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); - position: relative; - overflow: hidden; -} - -.feature-card::before { - content: ''; - position: absolute; - top: 0; left: 0; right: 0; bottom: 0; - border-radius: 24px; - padding: 1px; - background: linear-gradient(to bottom right, rgba(255, 255, 255, 0.12), transparent); - -webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0); - -webkit-mask-composite: xor; - mask-composite: exclude; - pointer-events: none; -} - -.feature-card:hover { - transform: translateY(-5px); - box-shadow: 0 15px 30px rgba(99, 102, 241, 0.2); - border-color: rgba(99, 102, 241, 0.3); -} - -.feature-card:hover::before { - background: linear-gradient(to bottom right, rgba(99, 102, 241, 0.3), transparent); -} - -/* Feature Icon with Inline SVG Wrapper */ -.feature-icon-svg { - display: flex; - flex-shrink: 0; - align-items: center; - justify-content: center; - width: 44px; - height: 44px; - background: rgba(99, 102, 241, 0.12); - color: var(--accent); - border-radius: 12px; - margin-right: 14px; - transition: all 0.3s ease; -} - -.feature-card:hover .feature-icon-svg { - background: var(--accent); - color: white; - box-shadow: 0 0 15px var(--accent-glow); - transform: scale(1.05); -} - -.bento-icon { - width: 22px; - height: 22px; - display: block; - flex-shrink: 0; -} - -.feature-card h3 { - margin-bottom: 1rem; - font-size: 1.25rem; - font-weight: 700; - display: flex; - align-items: center; -} - -.feature-card p { - color: var(--text-muted); - font-size: 0.95rem; - line-height: 1.6; -} - -/* Bento Asymmetric Spanning */ -.feature-card.bento-large { - grid-column: span 2; - background: linear-gradient(135deg, rgba(30, 41, 59, 0.45) 0%, rgba(99, 102, 241, 0.08) 100%); - padding: 3rem 3.5rem; - display: grid; - grid-template-columns: 1fr 2fr; - gap: 3rem; - align-items: center; -} - -.feature-card.bento-large h3 { - flex-direction: column; - align-items: center; - text-align: center; - gap: 1rem; - margin-bottom: 0; - font-size: 1.25rem; -} - -.feature-card.bento-large .feature-icon, -.feature-card.bento-large .feature-icon-svg { - width: 52px; - height: 52px; - border-radius: 14px; - margin-right: 0; - flex-shrink: 0; -} - -.feature-card.bento-large .bento-icon { - width: 24px; - height: 24px; -} - -.feature-card.bento-large p { - font-size: 1rem; - line-height: 1.7; - margin: 0; -} - -.feature-card.bento-large::after { - content: ''; - position: absolute; - top: 0; - left: 2.5rem; - right: 2.5rem; - height: 2px; - background: linear-gradient(90deg, transparent, rgba(99, 102, 241, 0.4), transparent); - opacity: 0; - transition: opacity 0.3s ease; -} - -.feature-card.bento-large:hover::after { - opacity: 1; -} - -@media (max-width: 900px) { - .features-grid { - grid-template-columns: repeat(2, 1fr); - gap: 1.25rem; - } - .feature-card.bento-large { - grid-column: span 2; - padding: 2.5rem; - gap: 2rem; - } - .feature-card.bento-large h3 { - font-size: 1.15rem; - } -} - -@media (max-width: 600px) { - .features-grid { - grid-template-columns: 1fr; - gap: 1rem; - } - .feature-card.bento-large { - grid-column: span 1; - display: flex; - flex-direction: column; - padding: 1.75rem; - gap: 1rem; - } - .feature-card.bento-large h3 { - flex-direction: row; - align-items: center; - text-align: left; - gap: 0.75rem; - margin-bottom: 0; - font-size: 1.15rem; - } - .feature-card.bento-large .feature-icon, - .feature-card.bento-large .feature-icon-svg { - width: 40px; - height: 40px; - border-radius: 10px; - margin-right: 0; - } - .feature-card.bento-large .bento-icon { - width: 18px; - height: 18px; - } - .feature-card.bento-large p { - font-size: 0.9rem; - line-height: 1.6; - } - .feature-card.bento-large::after { - display: none; - } - .feature-card { - padding: 1.75rem; - } - .feature-card h3 { - font-size: 1.1rem; - } - .feature-icon-svg { - width: 40px; - height: 40px; - border-radius: 10px; - margin-right: 12px; - } - .bento-icon { - width: 18px; - height: 18px; - } -} - -/* --- How it works --- */ -.steps { - display: flex; - flex-direction: column; - gap: 6rem; -} - -.step { - display: grid; - grid-template-columns: 1fr 1.1fr; - gap: 6rem; - align-items: center; -} - -.step:nth-child(even) .step-text { - order: 2; -} - -.step-num { - font-size: 4rem; - font-weight: 800; - color: rgba(99, 102, 241, 0.15); - line-height: 1; - margin-bottom: 0.5rem; -} - -.step-text h3 { - font-size: 1.85rem; - margin-bottom: 1rem; - font-weight: 800; -} - -.step-text p { - color: var(--text-muted); - font-size: 1.05rem; - line-height: 1.6; -} - -/* Custom CSS Mockups for step illustrations */ -.step-illustration-1, .step-illustration-2, .step-illustration-3 { - background: radial-gradient(circle at top left, #1e293b, #0f172a); - height: 280px; /* Slightly taller for more detail and breathing room */ - border-radius: 24px; - border: 1px solid var(--glass-border); - position: relative; - overflow: hidden; - display: flex; - align-items: center; - justify-content: center; - box-shadow: 0 20px 40px rgba(0, 0, 0, 0.4), inset 0 1px 0 rgba(255, 255, 255, 0.05); - transition: all 0.4s cubic-bezier(0.16, 1, 0.3, 1); -} - -.step-illustration-1:hover, .step-illustration-2:hover, .step-illustration-3:hover { - transform: translateY(-6px) scale(1.02); - border-color: rgba(99, 102, 241, 0.25); - box-shadow: 0 25px 50px rgba(99, 102, 241, 0.15), inset 0 1px 0 rgba(255, 255, 255, 0.1); -} - -/* ========================================================================== - Step 1 Illustration: Browser & Installed Success Popup - ========================================================================== */ -.illus-browser-container { - width: 90%; - height: 80%; - background: #090d16; - border: 1px solid rgba(255, 255, 255, 0.05); - border-radius: 12px; - overflow: hidden; - box-shadow: 0 15px 30px rgba(0, 0, 0, 0.5); - display: flex; - flex-direction: column; -} - -.illus-browser-header { - background: #131924; - padding: 0.6rem 0.8rem; - display: flex; - align-items: center; - border-bottom: 1px solid rgba(255, 255, 255, 0.05); -} - -.illus-browser-dots { - display: flex; - gap: 6px; - margin-right: 1.5rem; -} - -.illus-browser-dot { - width: 8px; - height: 8px; - border-radius: 50%; - opacity: 0.6; -} -.illus-browser-dot:nth-child(1) { background: #ef4444; } -.illus-browser-dot:nth-child(2) { background: #fbbf24; } -.illus-browser-dot:nth-child(3) { background: #22c55e; } - -.illus-browser-address-bar { - background: #090d16; - border: 1px solid rgba(255, 255, 255, 0.08); - border-radius: 6px; - color: var(--text-muted); - font-size: 0.68rem; - padding: 3px 12px; - flex-grow: 1; - max-width: 60%; - text-align: center; - font-family: monospace; - letter-spacing: 0.2px; -} - -.illus-browser-address-bar .url-protocol { - color: #22c55e; - font-weight: 600; -} - -.illus-browser-toolbar { - display: flex; - margin-left: auto; -} - -.illus-extension-btn { - width: 22px; - height: 22px; - border-radius: 6px; - display: flex; - align-items: center; - justify-content: center; - transition: all 0.3s; -} - -.illus-extension-btn.active { - background: rgba(99, 102, 241, 0.2); - border: 1px solid var(--accent); - box-shadow: 0 0 10px rgba(99, 102, 241, 0.4); - animation: active-pulse 2s infinite alternate; -} - -@keyframes active-pulse { - 0% { transform: scale(1); box-shadow: 0 0 5px rgba(99, 102, 241, 0.4); } - 100% { transform: scale(1.08); box-shadow: 0 0 12px rgba(99, 102, 241, 0.7); } -} - -.illus-browser-content { - flex-grow: 1; - padding: 1rem; - position: relative; - display: flex; - align-items: flex-start; -} - -.illus-store-card { - background: rgba(255, 255, 255, 0.02); - border: 1px solid rgba(255, 255, 255, 0.04); - border-radius: 12px; - padding: 0.8rem; - width: 65%; - display: flex; - flex-direction: column; - gap: 10px; -} - -.illus-store-card-header { - display: flex; - align-items: center; - gap: 8px; -} - -.illus-large-logo { - width: 30px; - height: 30px; - object-fit: contain; - border-radius: 6px; - box-shadow: 0 0 10px rgba(99, 102, 241, 0.2); -} - -.illus-store-info { - display: flex; - flex-direction: column; -} - -.illus-store-title { - font-size: 0.88rem; - font-weight: 800; - color: var(--text); - line-height: 1.1; -} - -.illus-store-desc { - font-size: 0.58rem; - color: var(--text-muted); - line-height: 1.2; - margin-top: 2px; -} - -.illus-store-buttons { - display: flex; - flex-direction: column; - gap: 6px; -} - -.illus-store-btn { - display: inline-flex; - align-items: center; - gap: 6px; - padding: 5px 8px; - border-radius: 8px; - font-size: 0.58rem; - font-weight: 700; - color: white; - border: 1px solid rgba(255, 255, 255, 0.05); - background: rgba(255, 255, 255, 0.03); - box-shadow: 0 2px 5px rgba(0,0,0,0.2); - cursor: default; - transition: all 0.2s; -} - -.illus-store-btn img { - width: 11px; - height: 11px; - display: block; -} - -.illus-store-btn.chrome { - border-color: rgba(99, 102, 241, 0.25); - background: rgba(99, 102, 241, 0.08); - box-shadow: 0 0 10px rgba(99, 102, 241, 0.05); -} - -.illus-store-btn.firefox { - border-color: rgba(249, 115, 22, 0.25); - background: rgba(249, 115, 22, 0.08); - box-shadow: 0 0 10px rgba(249, 115, 22, 0.05); -} - -.install-breathe { - animation: install-breathe 2.5s ease-in-out infinite; - z-index: 2; - position: relative; -} - -@keyframes install-breathe { - 0%, 100% { - transform: scale(1); - box-shadow: 0 0 15px rgba(99, 102, 241, 0.2); - } - 50% { - transform: scale(1.05); - box-shadow: 0 0 25px rgba(99, 102, 241, 0.5); - } -} - -.install-breathe.firefox, -.btn-firefox.install-breathe { - animation-name: install-breathe-ff; -} - -@keyframes install-breathe-ff { - 0%, 100% { - transform: scale(1); - box-shadow: 0 0 15px rgba(249, 115, 22, 0.2); - } - 50% { - transform: scale(1.05); - box-shadow: 0 0 25px rgba(249, 115, 22, 0.5); - } -} - -/* Glassmorphic Dropping Success Card */ -.illus-extension-popup { - position: absolute; - top: 0.6rem; - right: 0.6rem; - width: 145px; - background: rgba(30, 41, 59, 0.75); - backdrop-filter: blur(10px); - -webkit-backdrop-filter: blur(10px); - border: 1px solid rgba(255, 255, 255, 0.12); - border-radius: 12px; - padding: 0.6rem 0.8rem; - box-shadow: 0 10px 25px rgba(0, 0, 0, 0.5), inset 0 1px 0 rgba(255, 255, 255, 0.1); - animation: popup-float 4s ease-in-out infinite; - z-index: 5; -} - -@keyframes popup-float { - 0%, 100% { transform: translateY(0); } - 50% { transform: translateY(-4px); } -} - -.illus-extension-popup .popup-title { - display: flex; - align-items: center; - gap: 5px; - font-size: 0.72rem; - font-weight: 700; - color: var(--text); - margin-bottom: 6px; - border-bottom: 1px solid rgba(255, 255, 255, 0.08); - padding-bottom: 4px; -} - -.illus-extension-popup .popup-title img { - width: 12px; - height: 12px; -} - -.illus-extension-popup .popup-status { - margin-bottom: 4px; -} - -.status-badge-success { - background: rgba(34, 197, 94, 0.12); - color: #22c55e; - font-size: 0.6rem; - font-weight: 700; - padding: 2px 6px; - border-radius: 4px; - border: 1px solid rgba(34, 197, 94, 0.2); - display: inline-flex; - align-items: center; - gap: 3px; - animation: status-glow 2s infinite alternate; -} - -@keyframes status-glow { - 0% { box-shadow: 0 0 0 rgba(34, 197, 94, 0); } - 100% { box-shadow: 0 0 6px rgba(34, 197, 94, 0.3); } -} - -.illus-extension-popup .popup-quick-start { - font-size: 0.55rem; - color: var(--text-muted); - font-weight: 500; - line-height: 1.2; -} - - -/* ========================================================================== - Step 2 Illustration: Highly Realistic Extension Popup (Create Room View) - ========================================================================== */ -.illus-popup-card { - width: 220px; /* Scaled up 16% for a bigger, much more detailed view */ - background: rgba(30, 41, 59, 0.75); - backdrop-filter: blur(12px); - -webkit-backdrop-filter: blur(12px); - border: 1px solid rgba(255, 255, 255, 0.08); - border-radius: 16px; - padding: 0.95rem; /* Slightly larger padding */ - box-shadow: 0 15px 35px rgba(0, 0, 0, 0.5), inset 0 1px 0 rgba(255, 255, 255, 0.1); - display: flex; - flex-direction: column; - gap: 0.75rem; /* Tighter vertical layout rhythm */ - animation: popup-float 4s ease-in-out infinite; - animation-delay: -1s; -} - -.illus-popup-header { - display: flex; - justify-content: space-between; - align-items: center; - border-bottom: 1px solid rgba(255, 255, 255, 0.06); - padding-bottom: 8px; -} - -.illus-popup-brand { - display: flex; - align-items: center; - gap: 6px; - font-size: 0.82rem; /* Scaled up font */ - font-weight: 800; - letter-spacing: -0.2px; -} - -.illus-popup-version { - font-size: 0.58rem; - color: var(--text-muted); -} - -.illus-popup-tabs { - display: flex; - gap: 4px; - background: rgba(9, 13, 22, 0.4); - padding: 3px; - border-radius: 8px; - border: 1px solid rgba(255, 255, 255, 0.03); -} - -.illus-popup-tab { - flex: 1; - text-align: center; - font-size: 0.62rem; /* Scaled up font */ - padding: 4px 0; - border-radius: 6px; - color: var(--text-muted); - font-weight: 600; -} - -.illus-popup-tab.active { - background: var(--card); - color: var(--accent); - box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2); -} - -.illus-popup-body { - display: flex; - flex-direction: column; - gap: 0.75rem; - position: relative; -} - -.illus-popup-btn { - background: linear-gradient(135deg, var(--accent), #8b5cf6); - border-radius: 8px; - padding: 9px; /* Scaled up padding */ - color: white; - font-weight: 700; - font-size: 0.7rem; /* Scaled up font */ - text-align: center; - box-shadow: 0 4px 12px rgba(99, 102, 241, 0.3); - position: relative; - overflow: hidden; - cursor: default; - animation: create-btn-pulse 2s infinite alternate; -} - -@keyframes create-btn-pulse { - 0% { transform: scale(1); box-shadow: 0 4px 12px rgba(99, 102, 241, 0.3); } - 100% { transform: scale(1.03); box-shadow: 0 6px 16px rgba(99, 102, 241, 0.5); } -} - -.illus-btn-shine { - position: absolute; - top: 0; - left: -100%; - width: 50%; - height: 100%; - background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.25), transparent); - transform: skewX(-20deg); - animation: shimmer-sweep 3s infinite ease-in-out; -} - -@keyframes shimmer-sweep { - 0% { left: -100%; } - 50%, 100% { left: 150%; } -} - -.illus-collapsed-details { - background: rgba(9, 13, 22, 0.4); - border: 1px solid rgba(255, 255, 255, 0.05); - border-radius: 8px; - padding: 7px 12px; /* Scaled up padding */ - font-size: 0.56rem; /* Scaled up font */ - color: var(--text-muted); - font-weight: 700; - text-transform: uppercase; - display: flex; - align-items: center; - gap: 6px; - letter-spacing: 0.2px; -} - -.details-arrow { - font-size: 0.48rem; - color: var(--text-muted); - opacity: 0.7; -} - -/* Floating Success Badge */ -.illus-floating-success { - position: absolute; - bottom: -1.2rem; - left: 50%; - transform: translateX(-50%); - background: rgba(9, 13, 22, 0.9); - border: 1px solid rgba(34, 197, 94, 0.3); - border-radius: 20px; - padding: 3px 10px; - display: flex; - align-items: center; - gap: 4px; - box-shadow: 0 4px 10px rgba(0,0,0,0.4); - animation: floating-success-fade 5s infinite; - white-space: nowrap; - z-index: 10; -} - -@keyframes floating-success-fade { - 0%, 100%, 75% { opacity: 0; transform: translate(-50%, 5px) scale(0.9); } - 15%, 60% { opacity: 1; transform: translate(-50%, 0) scale(1); } -} - -.illus-floating-success .success-icon { - font-size: 0.65rem; -} - -.illus-floating-success span[lang] { - font-size: 0.58rem; - color: #22c55e; - font-weight: 700; -} - - -/* ========================================================================== - Step 3 Illustration: Dual Screen Theater Sync Setup - ========================================================================= */ -.illus-sync-theater { - width: 95%; - display: flex; - align-items: center; - justify-content: center; - position: relative; - gap: 0.6rem; -} - -.illus-player-card { - width: 145px; - background: rgba(15, 23, 42, 0.7); - border: 1px solid rgba(255, 255, 255, 0.05); - border-radius: 12px; - padding: 6px; - box-shadow: 0 10px 25px rgba(0,0,0,0.4); - display: flex; - flex-direction: column; - gap: 4px; - position: relative; - z-index: 2; -} - -.illus-player-card.player-a { - animation: popup-float 4s ease-in-out infinite; - animation-delay: -2s; -} - -.illus-player-card.player-b { - animation: popup-float 4s ease-in-out infinite; - animation-delay: -3s; -} - -.player-header { - display: flex; - justify-content: space-between; - align-items: center; - font-size: 0.55rem; -} - -.player-user { - font-weight: 700; - color: var(--text); -} - -.player-badge { - font-size: 0.42rem; - font-weight: 800; - padding: 1px 3px; - border-radius: 3px; -} - -.player-badge.active { - background: rgba(34, 197, 94, 0.15); - color: #22c55e; - border: 1px solid rgba(34, 197, 94, 0.25); -} - -.player-video-canvas { - height: 70px; - border-radius: 8px; - background: linear-gradient(135deg, #1e1b4b, #311042); - position: relative; - overflow: hidden; - display: flex; - align-items: center; - justify-content: center; - border: 1px solid rgba(255, 255, 255, 0.02); -} - -.player-video-overlay { - position: absolute; - top: 0; left: 0; width: 100%; height: 100%; - background: radial-gradient(circle at center, rgba(139, 92, 246, 0.1) 0%, transparent 80%); -} - -.player-play-pulse { - width: 24px; - height: 24px; - border-radius: 50%; - background: rgba(99, 102, 241, 0.85); - color: white; - font-size: 0.65rem; - display: flex; - align-items: center; - justify-content: center; - box-shadow: 0 0 10px rgba(99, 102, 241, 0.5); - z-index: 3; - animation: play-pulse 2s infinite alternate; -} - -@keyframes play-pulse { - 0% { transform: scale(1); box-shadow: 0 0 6px rgba(99, 102, 241, 0.4); } - 100% { transform: scale(1.15); box-shadow: 0 0 15px rgba(99, 102, 241, 0.8); } -} - -.player-controls { - display: flex; - align-items: center; - gap: 4px; - padding: 2px 2px 0 2px; -} - -.control-btn { - font-size: 0.58rem; - color: var(--accent); -} - -.player-timeline { - flex-grow: 1; - height: 3px; - background: rgba(255, 255, 255, 0.1); - border-radius: 2px; - position: relative; -} - -.timeline-fill { - position: absolute; - top: 0; left: 0; - height: 100%; - background: var(--accent); - border-radius: 2px; - width: 60%; - animation: theater-grow 6s infinite linear; -} - -.timeline-knob { - position: absolute; - top: -2px; - left: 60%; - width: 7px; - height: 7px; - border-radius: 50%; - background: white; - box-shadow: 0 0 4px rgba(0,0,0,0.5); - transform: translateX(-50%); - animation: theater-knob-grow 6s infinite linear; -} - -@keyframes theater-grow { - 0% { width: 0%; } - 100% { width: 100%; } -} - -@keyframes theater-knob-grow { - 0% { left: 0%; } - 100% { left: 100%; } -} - -.control-time { - font-size: 0.5rem; - color: var(--text-muted); - font-family: monospace; -} - -/* Glowing Connection Sync Bridge */ -.illus-sync-bridge { - flex-grow: 1; - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - gap: 6px; - position: relative; - z-index: 1; -} - -.illus-sync-bridge .sync-line { - width: 100%; - height: 2px; - background: rgba(255,255,255,0.06); - position: relative; - overflow: hidden; -} - -.illus-sync-bridge .sync-beam { - position: absolute; - top: 0; - left: -100%; - width: 50px; - height: 100%; - background: linear-gradient(90deg, transparent, var(--accent), var(--success), transparent); - animation: sync-flow 2.5s infinite linear; -} - -@keyframes sync-flow { - 0% { left: -100%; } - 100% { left: 100%; } -} - -.sync-status-badge { - background: rgba(34, 197, 94, 0.12); - border: 1px solid rgba(34, 197, 94, 0.25); - color: #22c55e; - font-size: 0.5rem; - font-weight: 800; - letter-spacing: 0.5px; - padding: 2px 6px; - border-radius: 6px; - white-space: nowrap; - animation: active-pulse-green 2s infinite alternate; -} - -@keyframes active-pulse-green { - 0% { box-shadow: 0 0 3px rgba(34, 197, 94, 0.1); } - 100% { box-shadow: 0 0 8px rgba(34, 197, 94, 0.4); } -} - -/* --- Self Hosters Terminal --- */ -.terminal-container { - max-width: 850px; - margin: 3rem auto 0 auto; - background: #0f172a; - border: 1px solid rgba(255, 255, 255, 0.08); - border-radius: 16px; - overflow: hidden; - box-shadow: 0 20px 45px rgba(0,0,0,0.5); - text-align: left; -} - -.terminal-header { - background: #1e293b; - padding: 0.85rem 1.25rem; - display: flex; - justify-content: space-between; - align-items: center; - border-bottom: 1px solid rgba(255,255,255,0.06); -} - -.terminal-dots { - display: flex; - gap: 6px; -} - -.terminal-dot { - width: 10px; - height: 10px; - border-radius: 50%; -} - -.terminal-dot.red { background: #ef4444; } -.terminal-dot.yellow { background: #f59e0b; } -.terminal-dot.green { background: #10b981; } - -.terminal-tabs { - display: flex; - gap: 0.5rem; -} - -.terminal-tab-btn { - background: none; - border: none; - color: var(--text-muted); - font-weight: 600; - font-size: 0.8rem; - padding: 0.35rem 0.75rem; - border-radius: 6px; - cursor: pointer; - transition: all 0.2s; -} - -.terminal-tab-btn:hover { - color: var(--text); - background: rgba(255, 255, 255, 0.03); -} - -.terminal-tab-btn.active { - color: var(--accent); - background: rgba(99, 102, 241, 0.1); - border: 1px solid rgba(99, 102, 241, 0.2); -} - -.terminal-body { - position: relative; - padding: 1.5rem; -} - -.terminal-pane { - display: none; - margin: 0; -} - -.terminal-pane.active { - display: block; -} - -.terminal-pane pre { - margin: 0; - overflow-x: auto; -} - -.terminal-pane code { - font-family: Consolas, Monaco, "Andale Mono", "Ubuntu Mono", monospace; - font-size: 0.85rem; - line-height: 1.6; - color: #e2e8f0; -} - -/* Syntax Highlighting */ -.t-comment { color: #64748b; font-style: italic; } -.t-key { color: #f472b6; } -.t-val { color: #38bdf8; } -.t-str { color: #34d399; } -.t-num { color: #fbbf24; } - -.terminal-copy-btn { - position: absolute; - top: 1rem; - right: 1.5rem; - background: rgba(255, 255, 255, 0.04); - border: 1px solid rgba(255, 255, 255, 0.08); - color: var(--text-muted); - padding: 0.35rem 0.75rem; - font-size: 0.75rem; - font-weight: 600; - border-radius: 6px; - cursor: pointer; - transition: all 0.2s; - display: flex; - align-items: center; - gap: 0.3rem; -} - -.terminal-copy-btn:hover { - background: rgba(255, 255, 255, 0.08); - color: var(--text); - border-color: rgba(255, 255, 255, 0.15); -} - -.terminal-copy-btn:active { - transform: scale(0.97); -} - -/* --- Footer --- */ -footer { - padding: 4rem 0; - border-top: 1px solid var(--glass-border); - text-align: center; - color: var(--text-muted); -} - -/* --- Animations --- */ -[data-reveal] { - opacity: 0; - transform: translateY(30px); - transition: all 0.8s cubic-bezier(0.4, 0, 0.2, 1); -} - -[data-reveal].revealed { - opacity: 1; - transform: translateY(0); -} - - -/* --- Legal Pages --- */ -.legal-content { - max-width: 800px; - margin: 8rem auto 4rem auto; - padding: 0 2rem; -} - -.legal-card { - background: var(--card); - padding: 3rem; - border-radius: 24px; - border: 1px solid var(--glass-border); -} - -.legal-card h1 { - font-size: 2.5rem; - margin-bottom: 2rem; - text-align: center; -} - -.legal-card h2 { - font-size: 1.25rem; - margin-top: 1rem; - margin-bottom: 0.5rem; - color: var(--accent); -} - -.legal-card p { - color: var(--text-muted); - margin-bottom: 0.5rem; - font-size: 0.95rem; -} - -/* Reset global section padding for legal sections specifically */ -.legal-card section { - padding: 0 !important; - margin-bottom: 0.75rem; -} - -/* --- Join Page Specifics --- */ -.join-card { - max-width: 450px; - margin: 6rem auto; - text-align: center; -} - -.room-badge { - display: inline-block; - background: rgba(99, 102, 241, 0.1); - color: var(--accent); - padding: 0.5rem 1rem; - border-radius: 99px; - font-size: 0.8rem; - font-weight: 700; - margin-bottom: 1rem; - border: 1px solid rgba(99, 102, 241, 0.2); -} - -@media (max-width: 768px) { - .hero-grid, .step { - grid-template-columns: 1fr; - text-align: center; - } - .hero-text h1 { - font-size: 2.5rem; - } - .cta-group { - justify-content: center; - flex-wrap: wrap; - } - .nav-links { - display: none; - position: absolute; - top: 100%; - left: 0; - right: 0; - flex-direction: column; - background: rgba(15, 23, 42, 0.95); - backdrop-filter: blur(12px); - padding: 1rem 2rem; - gap: 1rem; - border-bottom: 1px solid var(--glass-border); - } - .nav-links.open { - display: flex; - } - .hamburger { - display: flex; - } - .legal-card { - padding: 1.5rem; - } -} - -/* --- Language Toggle --- */ -html.lang-de [lang="en"] { - display: none !important; -} -html:not(.lang-de) [lang="de"] { - display: none !important; -} - -/* --- Modern Glassmorphic Language Selector --- */ -.lang-select-container { - position: relative; - display: inline-flex; - align-items: center; - gap: 8px; - background: rgba(30, 41, 59, 0.4); - backdrop-filter: blur(12px); - -webkit-backdrop-filter: blur(12px); - border: 1px solid rgba(255, 255, 255, 0.08); - border-radius: 9999px; - padding: 6px 14px 6px 12px; - transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); - color: var(--text-muted); -} - -.lang-select-container:hover { - background: rgba(30, 41, 59, 0.6); - border-color: rgba(99, 102, 241, 0.3); - color: var(--text); - box-shadow: 0 0 15px rgba(99, 102, 241, 0.1); -} - -.lang-select-container .globe-icon { - width: 16px; - height: 16px; - flex-shrink: 0; - opacity: 0.8; - transition: transform 0.5s ease; -} - -.lang-select-container:hover .globe-icon { - transform: rotate(15deg); - opacity: 1; -} - -.lang-select-container .chevron-icon { - width: 12px; - height: 12px; - flex-shrink: 0; - pointer-events: none; - opacity: 0.6; - margin-left: -2px; -} - -.lang-select-container:hover .chevron-icon { - opacity: 1; -} - -.lang-dropdown { - appearance: none; - -webkit-appearance: none; - -moz-appearance: none; - background: transparent; - border: none; - outline: none; - font-family: inherit; - font-size: 0.8rem; - font-weight: 600; - color: currentColor; - cursor: pointer; - padding: 0 12px 0 0; - margin: 0; - width: auto; -} - -.lang-dropdown option { - background: #0f172a; - color: white; - font-family: inherit; - font-size: 0.9rem; -} - -/* --- Hamburger Menu --- */ -.hamburger { - display: none; - align-items: center; - justify-content: center; - background: none; - border: none; - color: var(--text); - font-size: 1.5rem; - cursor: pointer; - padding: 0.25rem; - line-height: 1; -} - -/* --- Feature Cards: subtle differentiation --- */ -.feature-card:nth-child(1) { --card-accent: rgba(99, 102, 241, 0.06); } -.feature-card:nth-child(2) { --card-accent: rgba(139, 92, 246, 0.06); } -.feature-card:nth-child(3) { --card-accent: rgba(34, 197, 94, 0.06); } -.feature-card:nth-child(4) { --card-accent: rgba(56, 189, 248, 0.06); } -.feature-card:nth-child(5) { --card-accent: rgba(245, 158, 11, 0.06); } -.feature-card:nth-child(6) { --card-accent: rgba(236, 72, 153, 0.06); } - -.feature-card { - background: linear-gradient(135deg, var(--card-accent, transparent), var(--card)); -} - -/* --- Compatibility Section --- */ -.compat-section { - padding: 1rem 0 3.5rem 0; - text-align: center; - background: rgba(255,255,255,0.01); - border-bottom: 1px solid var(--glass-border); -} - -.compat-mascot { - display: block; - margin: 0 auto 0.5rem auto; - max-width: 368px; - width: 100%; - height: auto; - transition: transform 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275); -} - -.compat-mascot:hover { - transform: scale(1.05) translateY(-5px) rotate(1deg); -} - -.compat-heading { - font-size: 1rem; - font-weight: 600; - color: var(--text-muted); - letter-spacing: 0.08em; - text-transform: uppercase; - margin-bottom: 2rem; -} - -.compat-row { - display: flex; - justify-content: center; - align-items: center; - gap: 3rem; - flex-wrap: wrap; -} - -.compat-logo { - display: flex; - flex-direction: column; - align-items: center; - gap: 0.5rem; - font-size: 0.75rem; - font-weight: 700; - color: var(--text-muted); - transition: opacity 0.3s; - opacity: 0.55; -} - -.compat-logo:hover { - opacity: 0.85; -} - -.compat-logo img { - width: 28px; - height: 28px; - display: block; -} - -.compat-more { - opacity: 0.4; - cursor: help; - flex-direction: row; - gap: 0.35rem; - position: relative; -} - -.compat-more:hover { - opacity: 0.6; -} - -.compat-more-icon { - font-size: 1.1rem; - font-weight: 700; - color: var(--accent); - line-height: 1; -} - -.compat-tooltip { - display: none; - position: absolute; - bottom: calc(100% + 10px); - left: 50%; - transform: translateX(-50%); - background: var(--card); - color: var(--text-muted); - padding: 0.6rem 0.9rem; - border-radius: 8px; - font-size: 0.72rem; - font-weight: 500; - white-space: nowrap; - border: 1px solid var(--glass-border); - box-shadow: 0 8px 20px rgba(0,0,0,0.4); - z-index: 10; - line-height: 1.4; -} - -.compat-tooltip::after { - content: ''; - position: absolute; - top: 100%; - left: 50%; - transform: translateX(-50%); - border: 6px solid transparent; - border-top-color: var(--glass-border); -} - -.compat-more:hover .compat-tooltip { - display: block; -} - -/* --- Join Page Loading Spinner --- */ -.join-spinner { - width: 36px; - height: 36px; - border: 3px solid rgba(99, 102, 241, 0.2); - border-top-color: var(--accent); - border-radius: 50%; - animation: spin 0.8s linear infinite; - margin: 0 auto 0.75rem; -} - -@keyframes spin { - to { transform: rotate(360deg); } -} - -/* --- Reduced Motion --- */ -@media (prefers-reduced-motion: reduce) { - *, *::before, *::after { - animation-duration: 0.01ms !important; - animation-iteration-count: 1 !important; - transition-duration: 0.01ms !important; - } - [data-reveal] { - opacity: 1; - transform: none; - } - .blob { - animation: none; - } - .illus-typing-text::after { - animation: none; - } - .illus-timeline-progress { - animation: none; - width: 60%; - } - .illus-sync-pulse { - animation: none; - } - .illus-extension-icon { - animation: none; - } -} - -/* --- Use Cases / Anwendungsszenarien Section --- */ -.use-cases-section { - padding: 6rem 0; - position: relative; - border-bottom: 1px solid var(--glass-border); -} - -.use-cases-grid { - display: grid; - grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); - gap: 2rem; - margin-top: 1rem; -} - -.use-case-card { - background: rgba(30, 41, 59, 0.4); - border: 1px solid var(--glass-border); - border-radius: 16px; - padding: 1.2rem 1.6rem 1.7rem 1.6rem; - text-align: left; - transition: transform 0.3s cubic-bezier(0.16, 1, 0.3, 1), box-shadow 0.3s ease; - backdrop-filter: blur(8px); - -webkit-backdrop-filter: blur(8px); - display: flex; - flex-direction: column; - gap: 0.8rem; - position: relative; - overflow: hidden; -} - -.use-case-card::before { - content: ''; - position: absolute; - top: 0; - left: 0; - right: 0; - height: 3px; - background: linear-gradient(90deg, transparent, var(--card-accent-border, var(--accent)), transparent); - opacity: 0; - transition: opacity 0.3s ease; -} - -.use-case-card:nth-child(1) { --card-accent-border: #f59e0b; } -.use-case-card:nth-child(2) { --card-accent-border: #38bdf8; } -.use-case-card:nth-child(3) { --card-accent-border: #ec4899; } - - -.use-case-card:hover { - transform: translateY(-5px); - box-shadow: 0 12px 30px rgba(0, 0, 0, 0.35); - border-color: rgba(255, 255, 255, 0.15); -} - -.use-case-card:hover::before { - opacity: 1; -} - -.use-case-image { - display: block; - width: 100%; - max-width: 272px; - height: 150px; - object-fit: contain; - border-radius: 8px; - margin: 0 auto 0 auto; -} - -.cta-github-mascot { - display: block; - width: 100%; - max-width: 250px; - height: auto; - margin: 1.5rem auto; -} - -.features-questions-mascot { - display: block; - width: 100%; - max-width: 250px; - height: auto; - margin: -1.5rem auto 0.2rem auto; - transition: transform 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275); -} - -.features-questions-mascot:hover { - transform: scale(1.05) translateY(-4px) rotate(-1.5deg); -} - -.comparison-mascot { - display: block; - width: 100%; - max-width: 260px; - height: auto; - margin: -2.2rem auto 0.2rem auto; - transition: transform 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275); -} - -.comparison-mascot:hover { - transform: scale(1.05) translateY(-4px) rotate(1deg); -} - -.use-case-icon { - font-size: 1.6rem; - margin-right: 0.6rem; - display: inline-block; - vertical-align: middle; - filter: drop-shadow(0 2px 8px rgba(0,0,0,0.2)); -} - -.use-case-card h3 { - font-size: 1.25rem; - font-weight: 700; - margin: 0; - color: white; -} - -.use-case-card p { - font-size: 0.9rem; - line-height: 1.6; - color: var(--text-muted); - margin: 0; -} - -/* --- Comparison Section --- */ -.comparison-section { - padding: 6rem 0; - background: rgba(255, 255, 255, 0.01); - border-bottom: 1px solid var(--glass-border); -} - -.comparison-table-wrapper { - overflow-x: auto; - background: rgba(30, 41, 59, 0.35); - border: 1px solid var(--glass-border); - border-radius: 16px; - box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2); - backdrop-filter: blur(10px); - -webkit-backdrop-filter: blur(10px); - margin-top: 1rem; -} - -.comparison-table { - width: 100%; - border-collapse: collapse; - text-align: left; - font-size: 0.95rem; -} - -.comparison-table th, -.comparison-table td { - padding: 1.25rem 1.5rem; - border-bottom: 1px solid rgba(255, 255, 255, 0.06); -} - -.comparison-table th { - background: rgba(15, 23, 42, 0.6); - font-weight: 700; - color: white; - text-transform: uppercase; - font-size: 0.8rem; - letter-spacing: 0.08em; -} - -.comparison-table th.highlight, -.comparison-table td.highlight { - background: rgba(99, 102, 241, 0.08); -} - -.comparison-table tbody tr:hover { - background: rgba(255, 255, 255, 0.02); -} - -.comparison-table tbody tr:last-child td { - border-bottom: none; -} - -.feat-name { - display: flex; - flex-direction: column; - gap: 0.25rem; -} - -.feat-name strong { - color: white; - font-weight: 600; -} - -.feat-desc { - font-size: 0.8rem; - color: var(--text-muted); -} - -.check { - color: #22c55e; - font-weight: 700; -} - -.cross { - color: #ef4444; - font-weight: 500; - opacity: 0.8; -} - -@media (max-width: 768px) { - .comparison-table th, - .comparison-table td { - padding: 1rem; - font-size: 0.85rem; - } - .feat-desc { - display: none; - } -} - -/* --- Footnotes & Source Links --- */ -.source-link { - color: var(--accent); - text-decoration: none; - font-size: 0.72rem; - font-weight: 700; - margin-left: 0.25rem; - display: inline-flex; - align-items: center; - vertical-align: super; - opacity: 0.6; - transition: opacity 0.2s ease, color 0.2s ease, transform 0.2s ease; -} - -.source-link:hover { - opacity: 1; - color: #38bdf8; - transform: translateY(-1px); -} - -.table-footnotes { - padding: 0.8rem 1.25rem; - background: rgba(15, 23, 42, 0.45); - border-top: 1px solid rgba(255, 255, 255, 0.05); - font-size: 0.72rem; - color: var(--text-muted); - line-height: 1.5; - opacity: 0.65; - transition: opacity 0.2s ease; -} - -.table-footnotes:hover { - opacity: 0.95; -} - -.table-footnotes p { - margin: 0; - display: flex; - align-items: baseline; - gap: 0.4rem; -} - -.table-footnotes p:not(:last-child) { - margin-bottom: 0.4rem; -} - -.table-footnotes a { - color: var(--accent); - text-decoration: none; - font-weight: 500; - transition: color 0.2s ease, text-decoration 0.2s ease; -} - -.table-footnotes a:hover { - color: #38bdf8; - text-decoration: underline; -} - -.table-footnotes sup { - font-weight: 700; - color: var(--accent); -} - -@media (max-width: 768px) { - .table-footnotes { - padding: 0.75rem 1rem; - font-size: 0.68rem; - } -} - -/* --- Join & Invitation Page Visuals --- */ -.join-status-visual { - margin-bottom: 2rem; - position: relative; - height: 200px; - display: flex; - align-items: center; - justify-content: center; -} - -.join-status-mascot { - display: block; - width: 140px; - height: auto; - z-index: 2; - filter: drop-shadow(0 4px 12px rgba(0,0,0,0.15)); -} - -.join-status-mascot.searching-mascot { - width: 175px; /* Slightly wider due to antenna to keep main body scale identical */ -} - -.join-status-pulse { - animation: mascot-gentle-pulse 2s ease-in-out infinite; -} - -@keyframes mascot-gentle-pulse { - 0% { - transform: scale(0.96); - filter: drop-shadow(0 4px 10px rgba(99, 102, 241, 0.15)); - } - 50% { - transform: scale(1.04); - filter: drop-shadow(0 8px 20px rgba(99, 102, 241, 0.35)); - } - 100% { - transform: scale(0.96); - filter: drop-shadow(0 4px 10px rgba(99, 102, 241, 0.15)); - } -} - -.legal-mascot { - display: block; - width: 180px; - height: auto; - margin: -0.75rem auto 0.4rem auto; - filter: drop-shadow(0 4px 12px rgba(0,0,0,0.15)); - transition: transform 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275); -} - -.legal-mascot:hover { - transform: scale(1.06) translateY(-4px) rotate(1.5deg); -} - -.selfhost-mascot { - display: block; - width: 300px; - height: auto; - margin: 0 auto; - filter: drop-shadow(0 4px 12px rgba(0,0,0,0.15)); - transition: transform 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275); -} - -.selfhost-mascot:hover { - transform: scale(1.05) translateY(-4px) rotate(-1deg); -} - -.status-ring { - position: absolute; - width: 90px; - height: 90px; - border-radius: 50%; - background: rgba(99, 102, 241, 0.05); - border: 2px dashed rgba(99, 102, 241, 0.25); - z-index: 1; -} - -.status-ring.active-pulse { - animation: radar-pulse 3s cubic-bezier(0.25, 0.8, 0.25, 1) infinite; -} - -@keyframes radar-pulse { - 0% { - transform: scale(0.85); - opacity: 0.9; - border-color: rgba(99, 102, 241, 0.3); - box-shadow: 0 0 0 0px rgba(99, 102, 241, 0.15); - } - 50% { - transform: scale(1.18); - opacity: 0.35; - border-color: rgba(56, 189, 248, 0.2); - box-shadow: 0 0 0 15px rgba(56, 189, 248, 0); - } - 100% { - transform: scale(0.85); - opacity: 0.9; - border-color: rgba(99, 102, 241, 0.3); - box-shadow: 0 0 0 0px rgba(99, 102, 241, 0.15); - } -} - -.join-card-actions { - display: flex; - flex-direction: column; - gap: 0.75rem; - width: 100%; -} - -.join-card-actions .btn { - width: 100%; - justify-content: center; - padding: 1.1rem; - font-size: 0.88rem; - font-weight: 700; - letter-spacing: 0.04em; - text-transform: uppercase; -} - -.join-card-actions .btn svg { - margin-right: 0.3rem; - flex-shrink: 0; -} - -.join-card-actions .btn img { - margin-right: 0.3rem; - flex-shrink: 0; -} - -.btn-success { - background: #22c55e; - color: white !important; - box-shadow: 0 10px 15px -3px rgba(34, 197, 94, 0.3); -} - -.btn-success:hover { - background: #16a34a; - transform: translateY(-2px); - box-shadow: 0 20px 25px -5px rgba(34, 197, 94, 0.4); -} - +:root{--bg:#0f172a;--card:#1e293b;--accent:#6366f1;--accent-glow:rgba(99,102,241,0.3);--text:#f8fafc;--text-muted:#cbd5e1;--success:#22c55e;--glass:rgba(30,41,59,0.4);--glass-border:rgba(255,255,255,0.05)}.invite-banner{background:var(--accent);color:white;padding:0.75rem 0;text-align:center;font-weight:600;font-size:0.9rem;position:relative;z-index:2000;box-shadow:0 4px 12px rgba(0,0,0,0.3)}.btn-banner{background:white;color:var(--accent);padding:4px 12px;border-radius:6px;text-decoration:none;font-size:0.8rem;font-weight:700;margin-left:12px;cursor:pointer;border:none;transition:transform 0.2s}.btn-banner:hover{transform:scale(1.05)}*{margin:0;padding:0;box-sizing:border-box}:focus-visible{outline:2px solid var(--accent);outline-offset:2px;border-radius:6px}body{font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji";background-color:var(--bg);color:var(--text);line-height:1.6;overflow-x:hidden;position:relative}.bg-blobs{position:fixed;top:0;left:0;width:100%;height:100%;z-index:-1;overflow:hidden;background:radial-gradient(circle at 50% 50%,#1e1b4b 0%,#0f172a 100%)}.blob{position:absolute;width:600px;height:600px;background:radial-gradient(circle,var(--accent-glow) 0%,transparent 70%);filter:blur(80px);border-radius:50%;opacity:0.5;animation:move 25s infinite alternate ease-in-out}.blob-1{top:-100px;left:-100px;animation-delay:0s}.blob-2{bottom:-100px;right:-100px;animation-delay:-5s;background:radial-gradient(circle,rgba(139,92,246,0.2) 0%,transparent 70%)}.blob-3{top:40%;left:30%;animation-duration:35s;animation-delay:-10s}@keyframes move{0%{transform:translate(0,0) scale(1)}33%{transform:translate(100px,100px) scale(1.2)}66%{transform:translate(-50px,200px) scale(0.8)}100%{transform:translate(0,0) scale(1)}}.container{max-width:1100px;margin:0 auto;padding:0 2rem}section{padding:6rem 0}.use-cases-section,#features,#self-hosting,.comparison-section{content-visibility:auto;contain-intrinsic-size:auto 1400px}nav{position:fixed;top:0;width:100%;z-index:1000;background:var(--glass);backdrop-filter:blur(12px);border-bottom:1px solid var(--glass-border);padding:1rem 0}.nav-content{display:flex;justify-content:space-between;align-items:center}.logo-area{display:flex;align-items:center;gap:0.75rem;font-weight:800;font-size:1.5rem;letter-spacing:-0.5px}.logo-area img{height:40px;width:40px}.nav-ext-status{display:inline-flex;align-items:center;gap:4px;padding:3px 8px;background:rgba(16,185,129,0.15);border:1px solid rgba(16,185,129,0.3);color:#10b981;border-radius:12px;font-size:0.55rem;font-weight:700;text-transform:uppercase;letter-spacing:0.05em;box-shadow:0 0 10px rgba(16,185,129,0.1);animation:fade-in 0.4s ease-out;margin-left:0.2rem}@keyframes fade-in{from{opacity:0;transform:translateY(-5px)}to{opacity:1;transform:translateY(0)}}.nav-links{display:flex;gap:2rem}.nav-links a{color:var(--text-muted);text-decoration:none;font-weight:500;transition:color 0.3s}.nav-links a:hover{color:var(--accent)}.hero{min-height:100vh;display:flex;align-items:center;padding-top:8rem;padding-bottom:4rem}.hero-grid{display:grid;grid-template-columns:1.2fr 1fr;align-items:center;gap:4rem;text-align:left;width:100%}.hero-text h1{font-size:4.5rem;font-weight:800;line-height:1.1;margin-bottom:1.5rem;background:linear-gradient(to bottom,#fff 40%,#6366f1);-webkit-background-clip:text;-webkit-text-fill-color:transparent}.hero-text p,.hero-subtitle{font-size:1.25rem;color:var(--text-muted);margin-bottom:2.5rem;max-width:600px;font-weight:400;line-height:1.6}.hero-mascot-container{display:block;margin-bottom:-0.5rem;margin-left:2.2rem}.hero-lookdown-mascot{display:block;width:90px;height:auto}@media (max-width:768px){.hero-mascot-container{margin-left:0;display:flex;justify-content:center}}.cta-group{display:flex;gap:1rem;flex-wrap:wrap}.btn{padding:0.85rem 1.75rem;border-radius:12px;font-weight:600;text-decoration:none;transition:all 0.3s cubic-bezier(0.4,0,0.2,1);display:inline-flex;align-items:center;gap:0.5rem;font-size:0.95rem}.btn-primary{background:var(--accent);color:white;box-shadow:0 10px 15px -3px var(--accent-glow)}.btn-primary:hover{transform:translateY(-2px);box-shadow:0 20px 25px -5px var(--accent-glow)}.btn-firefox{background:#e66000;color:white;box-shadow:0 10px 15px -3px rgba(230,96,0,0.3)}.btn-firefox:hover{background:#ff7300;transform:translateY(-2px);box-shadow:0 20px 25px -5px rgba(230,96,0,0.4)}.btn-secondary{background:var(--card);color:var(--text);border:1px solid var(--glass-border)}.btn-secondary:hover{background:#2d3748;transform:translateY(-2px)}.version-badge{display:inline-block;background:rgba(99,102,241,0.1);color:var(--accent);padding:0.4rem 1rem;border-radius:99px;font-size:0.8rem;font-weight:700;margin-bottom:1.5rem;border:1px solid rgba(99,102,241,0.3);letter-spacing:0.05em;text-transform:uppercase}.hero-mockup-wrapper{display:flex;justify-content:center;align-items:center;width:100%}.extension-mockup{width:320px;height:520px;background:#0f172a;border-radius:20px;border:1px solid rgba(255,255,255,0.08);box-shadow:0 20px 40px rgba(0,0,0,0.4),0 0 20px rgba(99,102,241,0.15);display:flex;flex-direction:column;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif;overflow:hidden;position:relative;user-select:none;padding:16px;padding-bottom:0;box-sizing:border-box}.mock-header-row{display:flex;align-items:center;margin-bottom:16px;flex-shrink:0}.mock-header-title{font-size:18px;margin:0;color:var(--accent);letter-spacing:1px;text-transform:uppercase;display:inline-flex;align-items:center;gap:8px;font-weight:800}.mock-header-title img{width:24px;height:24px;object-fit:contain;border-radius:4px}.mock-version-link{margin-left:auto;display:flex;align-items:center;gap:4px;font-size:10px;color:var(--text-muted);text-decoration:none;opacity:0.5;transition:opacity 0.2s,color 0.2s;cursor:pointer}.mock-version-link:hover{opacity:1;color:var(--accent)}.mock-tabs{display:flex;gap:4px;background:#1e293b;padding:4px;border-radius:12px;margin-bottom:20px;flex-shrink:0}.mock-tab{flex:1;background:none;border:none;color:var(--text-muted);font-size:0.75rem;font-weight:600;padding:8px 4px;cursor:pointer;border-radius:8px;transition:all 0.2s;text-align:center}.mock-tab:hover{color:var(--text)}.mock-tab.active{background:var(--accent);color:white}.mock-body{flex:1;overflow-y:auto;padding:0;padding-bottom:16px;display:flex;flex-direction:column;font-size:0.8rem;scrollbar-width:none}.mock-body::-webkit-scrollbar{display:none}.mock-screen{display:none;flex-direction:column;gap:12px}.mock-screen.active{display:flex}.mock-card{background:#1e293b;border:1px solid #334155;border-radius:8px;padding:12px}.mock-label{font-size:0.65rem;font-weight:700;color:var(--text-muted);text-transform:uppercase;letter-spacing:0.05em;margin-bottom:0.4rem}.mock-input{background:#1e293b;border:1px solid #334155;border-radius:8px;color:white;padding:8px 10px;font-size:0.75rem;width:100%;outline:none}.mock-btn{background:var(--accent);color:white;border:none;border-radius:6px;padding:0.5rem;font-weight:600;font-size:0.75rem;cursor:pointer;transition:background 0.2s;text-align:center}.mock-btn:hover{background:#4f46e5}.mock-joined-room{display:flex;justify-content:space-between;align-items:center;background:rgba(99,102,241,0.1);border:1px solid rgba(99,102,241,0.2);border-radius:8px;padding:0.6rem 0.75rem}.mock-room-name{font-weight:700;color:var(--accent);font-size:0.85rem}.mock-server-badge{background:rgba(99,102,241,0.2);color:var(--accent);font-size:0.6rem;font-weight:700;padding:2px 6px;border-radius:4px}.mock-invite-box{display:flex;gap:0.4rem}.mock-invite-box input{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.mock-peer-list{display:flex;flex-direction:column;gap:0.5rem}.mock-peer-item{display:flex;flex-direction:column;background:rgba(255,255,255,0.02);border:1px solid rgba(255,255,255,0.03);border-radius:8px;padding:0.5rem 0.6rem}.mock-peer-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:0.25rem}.mock-peer-name{font-weight:700;color:var(--text)}.mock-peer-meta{font-size:0.65rem;color:var(--text-muted)}.mock-peer-tab{font-size:0.7rem;color:var(--accent);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.mock-peer-status{font-size:0.65rem;color:var(--text-muted);display:flex;align-items:center;gap:0.25rem}.mock-target-box{display:flex;align-items:center;gap:0.4rem;background:rgba(234,179,8,0.1);border:1px solid rgba(234,179,8,0.2);color:#facc15;padding:0.5rem 0.6rem;border-radius:8px;font-weight:600;font-size:0.7rem}.mock-ctrl-buttons{display:grid;grid-template-columns:1fr 1fr;gap:0.5rem}.mock-btn-play{background:#22c55e}.mock-btn-play:hover{background:#16a34a}.mock-btn-pause{background:#ef4444}.mock-btn-pause:hover{background:#dc2626}.mock-btn-force{background:var(--accent);grid-column:span 2}.mock-status-display{display:flex;align-items:center;justify-content:space-between}.mock-status-pill{display:inline-flex;align-items:center;gap:0.3rem;background:rgba(34,197,94,0.1);border:1px solid rgba(34,197,94,0.2);color:#22c55e;padding:2px 8px;border-radius:99px;font-size:0.65rem;font-weight:700}.mock-log-item{font-size:0.7rem;color:var(--text-muted);border-left:2px solid var(--accent);padding-left:0.4rem;margin-top:0.4rem}.mock-settings-row{display:flex;align-items:flex-start;gap:0.5rem;margin-bottom:0.6rem}.mock-settings-row input[type="checkbox"]{margin-top:0.2rem;cursor:pointer}.mock-settings-row label{cursor:pointer;font-weight:600}.mock-settings-row p{font-size:0.65rem;color:var(--text-muted);margin-top:0.1rem}.mock-toggle-switch{position:relative;display:inline-block;width:36px;height:20px;flex-shrink:0}.mock-toggle-switch input{opacity:0;width:0;height:0}.mock-slider{position:absolute;cursor:default;top:0;left:0;right:0;bottom:0;background-color:#334155;transition:.3s;border-radius:20px}.mock-slider:before{position:absolute;content:"";height:14px;width:14px;left:3px;bottom:3px;background-color:#94a3b8;transition:.3s;border-radius:50%}input:checked + .mock-slider{background-color:var(--accent)}input:checked + .mock-slider:before{transform:translateX(16px);background-color:white}.mock-diagnostic-grid{display:grid;grid-template-columns:1fr 1fr;gap:0.4rem}.mock-diag-box{background:rgba(255,255,255,0.02);border:1px solid rgba(255,255,255,0.04);border-radius:6px;padding:0.4rem}.mock-diag-box .diag-val{font-family:monospace;font-weight:700;color:var(--accent);font-size:0.75rem}.features-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:1.5rem;margin-top:4rem}.feature-card{background:rgba(30,41,59,0.45);backdrop-filter:blur(16px) saturate(120%);-webkit-backdrop-filter:blur(16px) saturate(120%);padding:2.5rem;border-radius:24px;border:1px solid rgba(255,255,255,0.08);box-shadow:0 8px 32px 0 rgba(0,0,0,0.3);transition:all 0.3s cubic-bezier(0.4,0,0.2,1);position:relative;overflow:hidden}.feature-card::before{content:'';position:absolute;top:0;left:0;right:0;bottom:0;border-radius:24px;padding:1px;background:linear-gradient(to bottom right,rgba(255,255,255,0.12),transparent);-webkit-mask:linear-gradient(#fff 0 0) content-box,linear-gradient(#fff 0 0);-webkit-mask-composite:xor;mask-composite:exclude;pointer-events:none}.feature-card:hover{transform:translateY(-5px);box-shadow:0 15px 30px rgba(99,102,241,0.2);border-color:rgba(99,102,241,0.3)}.feature-card:hover::before{background:linear-gradient(to bottom right,rgba(99,102,241,0.3),transparent)}.feature-icon-svg{display:flex;flex-shrink:0;align-items:center;justify-content:center;width:44px;height:44px;background:rgba(99,102,241,0.12);color:var(--accent);border-radius:12px;margin-right:14px;transition:all 0.3s ease}.feature-card:hover .feature-icon-svg{background:var(--accent);color:white;box-shadow:0 0 15px var(--accent-glow);transform:scale(1.05)}.bento-icon{width:22px;height:22px;display:block;flex-shrink:0}.feature-card h3{margin-bottom:1rem;font-size:1.25rem;font-weight:700;display:flex;align-items:center}.feature-card p{color:var(--text-muted);font-size:0.95rem;line-height:1.6}.feature-card.bento-large{grid-column:span 2;background:linear-gradient(135deg,rgba(30,41,59,0.45) 0%,rgba(99,102,241,0.08) 100%);padding:3rem 3.5rem;display:grid;grid-template-columns:1fr 2fr;gap:3rem;align-items:center}.feature-card.bento-large h3{flex-direction:column;align-items:center;text-align:center;gap:1rem;margin-bottom:0;font-size:1.25rem}.feature-card.bento-large .feature-icon,.feature-card.bento-large .feature-icon-svg{width:52px;height:52px;border-radius:14px;margin-right:0;flex-shrink:0}.feature-card.bento-large .bento-icon{width:24px;height:24px}.feature-card.bento-large p{font-size:1rem;line-height:1.7;margin:0}.feature-card.bento-large::after{content:'';position:absolute;top:0;left:2.5rem;right:2.5rem;height:2px;background:linear-gradient(90deg,transparent,rgba(99,102,241,0.4),transparent);opacity:0;transition:opacity 0.3s ease}.feature-card.bento-large:hover::after{opacity:1}@media (max-width:900px){.features-grid{grid-template-columns:repeat(2,1fr);gap:1.25rem}.feature-card.bento-large{grid-column:span 2;padding:2.5rem;gap:2rem}.feature-card.bento-large h3{font-size:1.15rem}}@media (max-width:600px){.features-grid{grid-template-columns:1fr;gap:1rem}.feature-card.bento-large{grid-column:span 1;display:flex;flex-direction:column;padding:1.75rem;gap:1rem}.feature-card.bento-large h3{flex-direction:row;align-items:center;text-align:left;gap:0.75rem;margin-bottom:0;font-size:1.15rem}.feature-card.bento-large .feature-icon,.feature-card.bento-large .feature-icon-svg{width:40px;height:40px;border-radius:10px;margin-right:0}.feature-card.bento-large .bento-icon{width:18px;height:18px}.feature-card.bento-large p{font-size:0.9rem;line-height:1.6}.feature-card.bento-large::after{display:none}.feature-card{padding:1.75rem}.feature-card h3{font-size:1.1rem}.feature-icon-svg{width:40px;height:40px;border-radius:10px;margin-right:12px}.bento-icon{width:18px;height:18px}}.steps{display:flex;flex-direction:column;gap:6rem}.step{display:grid;grid-template-columns:1fr 1.1fr;gap:6rem;align-items:center}.step:nth-child(even) .step-text{order:2}.step-num{font-size:4rem;font-weight:800;color:rgba(99,102,241,0.15);line-height:1;margin-bottom:0.5rem}.step-text h3{font-size:1.85rem;margin-bottom:1rem;font-weight:800}.step-text p{color:var(--text-muted);font-size:1.05rem;line-height:1.6}.step-illustration-1,.step-illustration-2,.step-illustration-3{background:radial-gradient(circle at top left,#1e293b,#0f172a);height:280px;border-radius:24px;border:1px solid var(--glass-border);position:relative;overflow:hidden;display:flex;align-items:center;justify-content:center;box-shadow:0 20px 40px rgba(0,0,0,0.4),inset 0 1px 0 rgba(255,255,255,0.05);transition:all 0.4s cubic-bezier(0.16,1,0.3,1)}.step-illustration-1:hover,.step-illustration-2:hover,.step-illustration-3:hover{transform:translateY(-6px) scale(1.02);border-color:rgba(99,102,241,0.25);box-shadow:0 25px 50px rgba(99,102,241,0.15),inset 0 1px 0 rgba(255,255,255,0.1)}.illus-browser-container{width:90%;height:80%;background:#090d16;border:1px solid rgba(255,255,255,0.05);border-radius:12px;overflow:hidden;box-shadow:0 15px 30px rgba(0,0,0,0.5);display:flex;flex-direction:column}.illus-browser-header{background:#131924;padding:0.6rem 0.8rem;display:flex;align-items:center;border-bottom:1px solid rgba(255,255,255,0.05)}.illus-browser-dots{display:flex;gap:6px;margin-right:1.5rem}.illus-browser-dot{width:8px;height:8px;border-radius:50%;opacity:0.6}.illus-browser-dot:nth-child(1){background:#ef4444}.illus-browser-dot:nth-child(2){background:#fbbf24}.illus-browser-dot:nth-child(3){background:#22c55e}.illus-browser-address-bar{background:#090d16;border:1px solid rgba(255,255,255,0.08);border-radius:6px;color:var(--text-muted);font-size:0.68rem;padding:3px 12px;flex-grow:1;max-width:60%;text-align:center;font-family:monospace;letter-spacing:0.2px}.illus-browser-address-bar .url-protocol{color:#22c55e;font-weight:600}.illus-browser-toolbar{display:flex;margin-left:auto}.illus-extension-btn{width:22px;height:22px;border-radius:6px;display:flex;align-items:center;justify-content:center;transition:all 0.3s}.illus-extension-btn.active{background:rgba(99,102,241,0.2);border:1px solid var(--accent);box-shadow:0 0 10px rgba(99,102,241,0.4);animation:active-pulse 2s infinite alternate}@keyframes active-pulse{0%{transform:scale(1);box-shadow:0 0 5px rgba(99,102,241,0.4)}100%{transform:scale(1.08);box-shadow:0 0 12px rgba(99,102,241,0.7)}}.illus-browser-content{flex-grow:1;padding:1rem;position:relative;display:flex;align-items:flex-start}.illus-store-card{background:rgba(255,255,255,0.02);border:1px solid rgba(255,255,255,0.04);border-radius:12px;padding:0.8rem;width:65%;display:flex;flex-direction:column;gap:10px}.illus-store-card-header{display:flex;align-items:center;gap:8px}.illus-large-logo{width:30px;height:30px;object-fit:contain;border-radius:6px;box-shadow:0 0 10px rgba(99,102,241,0.2)}.illus-store-info{display:flex;flex-direction:column}.illus-store-title{font-size:0.88rem;font-weight:800;color:var(--text);line-height:1.1}.illus-store-desc{font-size:0.58rem;color:var(--text-muted);line-height:1.2;margin-top:2px}.illus-store-buttons{display:flex;flex-direction:column;gap:6px}.illus-store-btn{display:inline-flex;align-items:center;gap:6px;padding:5px 8px;border-radius:8px;font-size:0.58rem;font-weight:700;color:white;border:1px solid rgba(255,255,255,0.05);background:rgba(255,255,255,0.03);box-shadow:0 2px 5px rgba(0,0,0,0.2);cursor:default;transition:all 0.2s}.illus-store-btn img{width:11px;height:11px;display:block}.illus-store-btn.chrome{border-color:rgba(99,102,241,0.25);background:rgba(99,102,241,0.08);box-shadow:0 0 10px rgba(99,102,241,0.05)}.illus-store-btn.firefox{border-color:rgba(249,115,22,0.25);background:rgba(249,115,22,0.08);box-shadow:0 0 10px rgba(249,115,22,0.05)}.install-breathe{animation:install-breathe 2.5s ease-in-out infinite;z-index:2;position:relative}@keyframes install-breathe{0%,100%{transform:scale(1);box-shadow:0 0 15px rgba(99,102,241,0.2)}50%{transform:scale(1.05);box-shadow:0 0 25px rgba(99,102,241,0.5)}}.install-breathe.firefox,.btn-firefox.install-breathe{animation-name:install-breathe-ff}@keyframes install-breathe-ff{0%,100%{transform:scale(1);box-shadow:0 0 15px rgba(249,115,22,0.2)}50%{transform:scale(1.05);box-shadow:0 0 25px rgba(249,115,22,0.5)}}.illus-extension-popup{position:absolute;top:0.6rem;right:0.6rem;width:145px;background:rgba(30,41,59,0.75);backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px);border:1px solid rgba(255,255,255,0.12);border-radius:12px;padding:0.6rem 0.8rem;box-shadow:0 10px 25px rgba(0,0,0,0.5),inset 0 1px 0 rgba(255,255,255,0.1);animation:popup-float 4s ease-in-out infinite;z-index:5}@keyframes popup-float{0%,100%{transform:translateY(0)}50%{transform:translateY(-4px)}}.illus-extension-popup .popup-title{display:flex;align-items:center;gap:5px;font-size:0.72rem;font-weight:700;color:var(--text);margin-bottom:6px;border-bottom:1px solid rgba(255,255,255,0.08);padding-bottom:4px}.illus-extension-popup .popup-title img{width:12px;height:12px}.illus-extension-popup .popup-status{margin-bottom:4px}.status-badge-success{background:rgba(34,197,94,0.12);color:#22c55e;font-size:0.6rem;font-weight:700;padding:2px 6px;border-radius:4px;border:1px solid rgba(34,197,94,0.2);display:inline-flex;align-items:center;gap:3px;animation:status-glow 2s infinite alternate}@keyframes status-glow{0%{box-shadow:0 0 0 rgba(34,197,94,0)}100%{box-shadow:0 0 6px rgba(34,197,94,0.3)}}.illus-extension-popup .popup-quick-start{font-size:0.55rem;color:var(--text-muted);font-weight:500;line-height:1.2}.illus-popup-card{width:220px;background:rgba(30,41,59,0.75);backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);border:1px solid rgba(255,255,255,0.08);border-radius:16px;padding:0.95rem;box-shadow:0 15px 35px rgba(0,0,0,0.5),inset 0 1px 0 rgba(255,255,255,0.1);display:flex;flex-direction:column;gap:0.75rem;animation:popup-float 4s ease-in-out infinite;animation-delay:-1s}.illus-popup-header{display:flex;justify-content:space-between;align-items:center;border-bottom:1px solid rgba(255,255,255,0.06);padding-bottom:8px}.illus-popup-brand{display:flex;align-items:center;gap:6px;font-size:0.82rem;font-weight:800;letter-spacing:-0.2px}.illus-popup-version{font-size:0.58rem;color:var(--text-muted)}.illus-popup-tabs{display:flex;gap:4px;background:rgba(9,13,22,0.4);padding:3px;border-radius:8px;border:1px solid rgba(255,255,255,0.03)}.illus-popup-tab{flex:1;text-align:center;font-size:0.62rem;padding:4px 0;border-radius:6px;color:var(--text-muted);font-weight:600}.illus-popup-tab.active{background:var(--card);color:var(--accent);box-shadow:0 2px 5px rgba(0,0,0,0.2)}.illus-popup-body{display:flex;flex-direction:column;gap:0.75rem;position:relative}.illus-popup-btn{background:linear-gradient(135deg,var(--accent),#8b5cf6);border-radius:8px;padding:9px;color:white;font-weight:700;font-size:0.7rem;text-align:center;box-shadow:0 4px 12px rgba(99,102,241,0.3);position:relative;overflow:hidden;cursor:default;animation:create-btn-pulse 2s infinite alternate}@keyframes create-btn-pulse{0%{transform:scale(1);box-shadow:0 4px 12px rgba(99,102,241,0.3)}100%{transform:scale(1.03);box-shadow:0 6px 16px rgba(99,102,241,0.5)}}.illus-btn-shine{position:absolute;top:0;left:-100%;width:50%;height:100%;background:linear-gradient(90deg,transparent,rgba(255,255,255,0.25),transparent);transform:skewX(-20deg);animation:shimmer-sweep 3s infinite ease-in-out}@keyframes shimmer-sweep{0%{left:-100%}50%,100%{left:150%}}.illus-collapsed-details{background:rgba(9,13,22,0.4);border:1px solid rgba(255,255,255,0.05);border-radius:8px;padding:7px 12px;font-size:0.56rem;color:var(--text-muted);font-weight:700;text-transform:uppercase;display:flex;align-items:center;gap:6px;letter-spacing:0.2px}.details-arrow{font-size:0.48rem;color:var(--text-muted);opacity:0.7}.illus-floating-success{position:absolute;bottom:-1.2rem;left:50%;transform:translateX(-50%);background:rgba(9,13,22,0.9);border:1px solid rgba(34,197,94,0.3);border-radius:20px;padding:3px 10px;display:flex;align-items:center;gap:4px;box-shadow:0 4px 10px rgba(0,0,0,0.4);animation:floating-success-fade 5s infinite;white-space:nowrap;z-index:10}@keyframes floating-success-fade{0%,100%,75%{opacity:0;transform:translate(-50%,5px) scale(0.9)}15%,60%{opacity:1;transform:translate(-50%,0) scale(1)}}.illus-floating-success .success-icon{font-size:0.65rem}.illus-floating-success span[lang]{font-size:0.58rem;color:#22c55e;font-weight:700}.illus-sync-theater{width:95%;display:flex;align-items:center;justify-content:center;position:relative;gap:0.6rem}.illus-player-card{width:145px;background:rgba(15,23,42,0.7);border:1px solid rgba(255,255,255,0.05);border-radius:12px;padding:6px;box-shadow:0 10px 25px rgba(0,0,0,0.4);display:flex;flex-direction:column;gap:4px;position:relative;z-index:2}.illus-player-card.player-a{animation:popup-float 4s ease-in-out infinite;animation-delay:-2s}.illus-player-card.player-b{animation:popup-float 4s ease-in-out infinite;animation-delay:-3s}.player-header{display:flex;justify-content:space-between;align-items:center;font-size:0.55rem}.player-user{font-weight:700;color:var(--text)}.player-badge{font-size:0.42rem;font-weight:800;padding:1px 3px;border-radius:3px}.player-badge.active{background:rgba(34,197,94,0.15);color:#22c55e;border:1px solid rgba(34,197,94,0.25)}.player-video-canvas{height:70px;border-radius:8px;background:linear-gradient(135deg,#1e1b4b,#311042);position:relative;overflow:hidden;display:flex;align-items:center;justify-content:center;border:1px solid rgba(255,255,255,0.02)}.player-video-overlay{position:absolute;top:0;left:0;width:100%;height:100%;background:radial-gradient(circle at center,rgba(139,92,246,0.1) 0%,transparent 80%)}.player-play-pulse{width:24px;height:24px;border-radius:50%;background:rgba(99,102,241,0.85);color:white;font-size:0.65rem;display:flex;align-items:center;justify-content:center;box-shadow:0 0 10px rgba(99,102,241,0.5);z-index:3;animation:play-pulse 2s infinite alternate}@keyframes play-pulse{0%{transform:scale(1);box-shadow:0 0 6px rgba(99,102,241,0.4)}100%{transform:scale(1.15);box-shadow:0 0 15px rgba(99,102,241,0.8)}}.player-controls{display:flex;align-items:center;gap:4px;padding:2px 2px 0 2px}.control-btn{font-size:0.58rem;color:var(--accent)}.player-timeline{flex-grow:1;height:3px;background:rgba(255,255,255,0.1);border-radius:2px;position:relative}.timeline-fill{position:absolute;top:0;left:0;height:100%;background:var(--accent);border-radius:2px;width:60%;animation:theater-grow 6s infinite linear}.timeline-knob{position:absolute;top:-2px;left:60%;width:7px;height:7px;border-radius:50%;background:white;box-shadow:0 0 4px rgba(0,0,0,0.5);transform:translateX(-50%);animation:theater-knob-grow 6s infinite linear}@keyframes theater-grow{0%{width:0%}100%{width:100%}}@keyframes theater-knob-grow{0%{left:0%}100%{left:100%}}.control-time{font-size:0.5rem;color:var(--text-muted);font-family:monospace}.illus-sync-bridge{flex-grow:1;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:6px;position:relative;z-index:1}.illus-sync-bridge .sync-line{width:100%;height:2px;background:rgba(255,255,255,0.06);position:relative;overflow:hidden}.illus-sync-bridge .sync-beam{position:absolute;top:0;left:-100%;width:50px;height:100%;background:linear-gradient(90deg,transparent,var(--accent),var(--success),transparent);animation:sync-flow 2.5s infinite linear}@keyframes sync-flow{0%{left:-100%}100%{left:100%}}.sync-status-badge{background:rgba(34,197,94,0.12);border:1px solid rgba(34,197,94,0.25);color:#22c55e;font-size:0.5rem;font-weight:800;letter-spacing:0.5px;padding:2px 6px;border-radius:6px;white-space:nowrap;animation:active-pulse-green 2s infinite alternate}@keyframes active-pulse-green{0%{box-shadow:0 0 3px rgba(34,197,94,0.1)}100%{box-shadow:0 0 8px rgba(34,197,94,0.4)}}.terminal-container{max-width:850px;margin:3rem auto 0 auto;background:#0f172a;border:1px solid rgba(255,255,255,0.08);border-radius:16px;overflow:hidden;box-shadow:0 20px 45px rgba(0,0,0,0.5);text-align:left}.terminal-header{background:#1e293b;padding:0.85rem 1.25rem;display:flex;justify-content:space-between;align-items:center;border-bottom:1px solid rgba(255,255,255,0.06)}.terminal-dots{display:flex;gap:6px}.terminal-dot{width:10px;height:10px;border-radius:50%}.terminal-dot.red{background:#ef4444}.terminal-dot.yellow{background:#f59e0b}.terminal-dot.green{background:#10b981}.terminal-tabs{display:flex;gap:0.5rem}.terminal-tab-btn{background:none;border:none;color:var(--text-muted);font-weight:600;font-size:0.8rem;padding:0.35rem 0.75rem;border-radius:6px;cursor:pointer;transition:all 0.2s}.terminal-tab-btn:hover{color:var(--text);background:rgba(255,255,255,0.03)}.terminal-tab-btn.active{color:var(--accent);background:rgba(99,102,241,0.1);border:1px solid rgba(99,102,241,0.2)}.terminal-body{position:relative;padding:1.5rem}.terminal-pane{display:none;margin:0}.terminal-pane.active{display:block}.terminal-pane pre{margin:0;overflow-x:auto}.terminal-pane code{font-family:Consolas,Monaco,"Andale Mono","Ubuntu Mono",monospace;font-size:0.85rem;line-height:1.6;color:#e2e8f0}.t-comment{color:#64748b;font-style:italic}.t-key{color:#f472b6}.t-val{color:#38bdf8}.t-str{color:#34d399}.t-num{color:#fbbf24}.terminal-copy-btn{position:absolute;top:1rem;right:1.5rem;background:rgba(255,255,255,0.04);border:1px solid rgba(255,255,255,0.08);color:var(--text-muted);padding:0.35rem 0.75rem;font-size:0.75rem;font-weight:600;border-radius:6px;cursor:pointer;transition:all 0.2s;display:flex;align-items:center;gap:0.3rem}.terminal-copy-btn:hover{background:rgba(255,255,255,0.08);color:var(--text);border-color:rgba(255,255,255,0.15)}.terminal-copy-btn:active{transform:scale(0.97)}footer{padding:4rem 0;border-top:1px solid var(--glass-border);text-align:center;color:var(--text-muted)}[data-reveal]{opacity:0;transform:translateY(30px);transition:all 0.8s cubic-bezier(0.4,0,0.2,1)}[data-reveal].revealed{opacity:1;transform:translateY(0)}.legal-content{max-width:800px;margin:8rem auto 4rem auto;padding:0 2rem}.legal-card{background:var(--card);padding:3rem;border-radius:24px;border:1px solid var(--glass-border)}.legal-card h1{font-size:2.5rem;margin-bottom:2rem;text-align:center}.legal-card h2{font-size:1.25rem;margin-top:1rem;margin-bottom:0.5rem;color:var(--accent)}.legal-card p{color:var(--text-muted);margin-bottom:0.5rem;font-size:0.95rem}.legal-card section{padding:0 !important;margin-bottom:0.75rem}.join-card{max-width:450px;margin:6rem auto;text-align:center}.room-badge{display:inline-block;background:rgba(99,102,241,0.1);color:var(--accent);padding:0.5rem 1rem;border-radius:99px;font-size:0.8rem;font-weight:700;margin-bottom:1rem;border:1px solid rgba(99,102,241,0.2)}@media (max-width:768px){.hero-grid,.step{grid-template-columns:1fr;text-align:center}.hero-text h1{font-size:2.5rem}.cta-group{justify-content:center;flex-wrap:wrap}.nav-links{display:none;position:absolute;top:100%;left:0;right:0;flex-direction:column;background:rgba(15,23,42,0.95);backdrop-filter:blur(12px);padding:1rem 2rem;gap:1rem;border-bottom:1px solid var(--glass-border)}.nav-links.open{display:flex}.hamburger{display:flex}.legal-card{padding:1.5rem}}html.lang-de [lang="en"]{display:none !important}html:not(.lang-de) [lang="de"]{display:none !important}.lang-select-container{position:relative;display:inline-flex;align-items:center;gap:8px;background:rgba(30,41,59,0.4);backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);border:1px solid rgba(255,255,255,0.08);border-radius:9999px;padding:6px 14px 6px 12px;transition:all 0.3s cubic-bezier(0.4,0,0.2,1);color:var(--text-muted)}.lang-select-container:hover{background:rgba(30,41,59,0.6);border-color:rgba(99,102,241,0.3);color:var(--text);box-shadow:0 0 15px rgba(99,102,241,0.1)}.lang-select-container .globe-icon{width:16px;height:16px;flex-shrink:0;opacity:0.8;transition:transform 0.5s ease}.lang-select-container:hover .globe-icon{transform:rotate(15deg);opacity:1}.lang-select-container .chevron-icon{width:12px;height:12px;flex-shrink:0;pointer-events:none;opacity:0.6;margin-left:-2px}.lang-select-container:hover .chevron-icon{opacity:1}.lang-dropdown{appearance:none;-webkit-appearance:none;-moz-appearance:none;background:transparent;border:none;outline:none;font-family:inherit;font-size:0.8rem;font-weight:600;color:currentColor;cursor:pointer;padding:0 12px 0 0;margin:0;width:auto}.lang-dropdown option{background:#0f172a;color:white;font-family:inherit;font-size:0.9rem}.hamburger{display:none;align-items:center;justify-content:center;background:none;border:none;color:var(--text);font-size:1.5rem;cursor:pointer;padding:0.25rem;line-height:1}.feature-card:nth-child(1){--card-accent:rgba(99,102,241,0.06)}.feature-card:nth-child(2){--card-accent:rgba(139,92,246,0.06)}.feature-card:nth-child(3){--card-accent:rgba(34,197,94,0.06)}.feature-card:nth-child(4){--card-accent:rgba(56,189,248,0.06)}.feature-card:nth-child(5){--card-accent:rgba(245,158,11,0.06)}.feature-card:nth-child(6){--card-accent:rgba(236,72,153,0.06)}.feature-card{background:linear-gradient(135deg,var(--card-accent,transparent),var(--card))}.compat-section{padding:1rem 0 3.5rem 0;text-align:center;background:rgba(255,255,255,0.01);border-bottom:1px solid var(--glass-border)}.compat-mascot{display:block;margin:0 auto 0.5rem auto;max-width:368px;width:100%;height:auto;transition:transform 0.3s cubic-bezier(0.175,0.885,0.32,1.275)}.compat-mascot:hover{transform:scale(1.05) translateY(-5px) rotate(1deg)}.compat-heading{font-size:1rem;font-weight:600;color:var(--text-muted);letter-spacing:0.08em;text-transform:uppercase;margin-bottom:2rem}.compat-row{display:flex;justify-content:center;align-items:center;gap:3rem;flex-wrap:wrap}.compat-logo{display:flex;flex-direction:column;align-items:center;gap:0.5rem;font-size:0.75rem;font-weight:700;color:var(--text-muted);transition:opacity 0.3s;opacity:0.55}.compat-logo:hover{opacity:0.85}.compat-logo img{width:28px;height:28px;display:block}.compat-more{opacity:0.4;cursor:help;flex-direction:row;gap:0.35rem;position:relative}.compat-more:hover{opacity:0.6}.compat-more-icon{font-size:1.1rem;font-weight:700;color:var(--accent);line-height:1}.compat-tooltip{display:none;position:absolute;bottom:calc(100% + 10px);left:50%;transform:translateX(-50%);background:var(--card);color:var(--text-muted);padding:0.6rem 0.9rem;border-radius:8px;font-size:0.72rem;font-weight:500;white-space:nowrap;border:1px solid var(--glass-border);box-shadow:0 8px 20px rgba(0,0,0,0.4);z-index:10;line-height:1.4}.compat-tooltip::after{content:'';position:absolute;top:100%;left:50%;transform:translateX(-50%);border:6px solid transparent;border-top-color:var(--glass-border)}.compat-more:hover .compat-tooltip{display:block}.join-spinner{width:36px;height:36px;border:3px solid rgba(99,102,241,0.2);border-top-color:var(--accent);border-radius:50%;animation:spin 0.8s linear infinite;margin:0 auto 0.75rem}@keyframes spin{to{transform:rotate(360deg)}}@media (prefers-reduced-motion:reduce){*,*::before,*::after{animation-duration:0.01ms !important;animation-iteration-count:1 !important;transition-duration:0.01ms !important}[data-reveal]{opacity:1;transform:none}.blob{animation:none}.illus-typing-text::after{animation:none}.illus-timeline-progress{animation:none;width:60%}.illus-sync-pulse{animation:none}.illus-extension-icon{animation:none}}.use-cases-section{padding:6rem 0;position:relative;border-bottom:1px solid var(--glass-border)}.use-cases-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(260px,1fr));gap:2rem;margin-top:1rem}.use-case-card{background:rgba(30,41,59,0.4);border:1px solid var(--glass-border);border-radius:16px;padding:1.2rem 1.6rem 1.7rem 1.6rem;text-align:left;transition:transform 0.3s cubic-bezier(0.16,1,0.3,1),box-shadow 0.3s ease;backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px);display:flex;flex-direction:column;gap:0.8rem;position:relative;overflow:hidden}.use-case-card::before{content:'';position:absolute;top:0;left:0;right:0;height:3px;background:linear-gradient(90deg,transparent,var(--card-accent-border,var(--accent)),transparent);opacity:0;transition:opacity 0.3s ease}.use-case-card:nth-child(1){--card-accent-border:#f59e0b}.use-case-card:nth-child(2){--card-accent-border:#38bdf8}.use-case-card:nth-child(3){--card-accent-border:#ec4899}.use-case-card:hover{transform:translateY(-5px);box-shadow:0 12px 30px rgba(0,0,0,0.35);border-color:rgba(255,255,255,0.15)}.use-case-card:hover::before{opacity:1}.use-case-image{display:block;width:100%;max-width:272px;height:150px;object-fit:contain;border-radius:8px;margin:0 auto 0 auto}.cta-github-mascot{display:block;width:100%;max-width:250px;height:auto;margin:1.5rem auto}.features-questions-mascot{display:block;width:100%;max-width:250px;height:auto;margin:-1.5rem auto 0.2rem auto;transition:transform 0.3s cubic-bezier(0.175,0.885,0.32,1.275)}.features-questions-mascot:hover{transform:scale(1.05) translateY(-4px) rotate(-1.5deg)}.comparison-mascot{display:block;width:100%;max-width:260px;height:auto;margin:-2.2rem auto 0.2rem auto;transition:transform 0.3s cubic-bezier(0.175,0.885,0.32,1.275)}.comparison-mascot:hover{transform:scale(1.05) translateY(-4px) rotate(1deg)}.use-case-icon{font-size:1.6rem;margin-right:0.6rem;display:inline-block;vertical-align:middle;filter:drop-shadow(0 2px 8px rgba(0,0,0,0.2))}.use-case-card h3{font-size:1.25rem;font-weight:700;margin:0;color:white}.use-case-card p{font-size:0.9rem;line-height:1.6;color:var(--text-muted);margin:0}.comparison-section{padding:6rem 0;background:rgba(255,255,255,0.01);border-bottom:1px solid var(--glass-border)}.comparison-table-wrapper{overflow-x:auto;background:rgba(30,41,59,0.35);border:1px solid var(--glass-border);border-radius:16px;box-shadow:0 10px 30px rgba(0,0,0,0.2);backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px);margin-top:1rem}.comparison-table{width:100%;border-collapse:collapse;text-align:left;font-size:0.95rem}.comparison-table th,.comparison-table td{padding:1.25rem 1.5rem;border-bottom:1px solid rgba(255,255,255,0.06)}.comparison-table th{background:rgba(15,23,42,0.6);font-weight:700;color:white;text-transform:uppercase;font-size:0.8rem;letter-spacing:0.08em}.comparison-table th.highlight,.comparison-table td.highlight{background:rgba(99,102,241,0.08)}.comparison-table tbody tr:hover{background:rgba(255,255,255,0.02)}.comparison-table tbody tr:last-child td{border-bottom:none}.feat-name{display:flex;flex-direction:column;gap:0.25rem}.feat-name strong{color:white;font-weight:600}.feat-desc{font-size:0.8rem;color:var(--text-muted)}.check{color:#22c55e;font-weight:700}.cross{color:#ef4444;font-weight:500;opacity:0.8}@media (max-width:768px){.comparison-table th,.comparison-table td{padding:1rem;font-size:0.85rem}.feat-desc{display:none}}.source-link{color:var(--accent);text-decoration:none;font-size:0.72rem;font-weight:700;margin-left:0.25rem;display:inline-flex;align-items:center;vertical-align:super;opacity:0.6;transition:opacity 0.2s ease,color 0.2s ease,transform 0.2s ease}.source-link:hover{opacity:1;color:#38bdf8;transform:translateY(-1px)}.table-footnotes{padding:0.8rem 1.25rem;background:rgba(15,23,42,0.45);border-top:1px solid rgba(255,255,255,0.05);font-size:0.72rem;color:var(--text-muted);line-height:1.5;opacity:0.65;transition:opacity 0.2s ease}.table-footnotes:hover{opacity:0.95}.table-footnotes p{margin:0;display:flex;align-items:baseline;gap:0.4rem}.table-footnotes p:not(:last-child){margin-bottom:0.4rem}.table-footnotes a{color:var(--accent);text-decoration:none;font-weight:500;transition:color 0.2s ease,text-decoration 0.2s ease}.table-footnotes a:hover{color:#38bdf8;text-decoration:underline}.table-footnotes sup{font-weight:700;color:var(--accent)}@media (max-width:768px){.table-footnotes{padding:0.75rem 1rem;font-size:0.68rem}}.join-status-visual{margin-bottom:2rem;position:relative;height:200px;display:flex;align-items:center;justify-content:center}.join-status-mascot{display:block;width:140px;height:auto;z-index:2;filter:drop-shadow(0 4px 12px rgba(0,0,0,0.15))}.join-status-mascot.searching-mascot{width:175px}.join-status-pulse{animation:mascot-gentle-pulse 2s ease-in-out infinite}@keyframes mascot-gentle-pulse{0%{transform:scale(0.96);filter:drop-shadow(0 4px 10px rgba(99,102,241,0.15))}50%{transform:scale(1.04);filter:drop-shadow(0 8px 20px rgba(99,102,241,0.35))}100%{transform:scale(0.96);filter:drop-shadow(0 4px 10px rgba(99,102,241,0.15))}}.legal-mascot{display:block;width:180px;height:auto;margin:-0.75rem auto 0.4rem auto;filter:drop-shadow(0 4px 12px rgba(0,0,0,0.15));transition:transform 0.3s cubic-bezier(0.175,0.885,0.32,1.275)}.legal-mascot:hover{transform:scale(1.06) translateY(-4px) rotate(1.5deg)}.selfhost-mascot{display:block;width:300px;height:auto;margin:0 auto;filter:drop-shadow(0 4px 12px rgba(0,0,0,0.15));transition:transform 0.3s cubic-bezier(0.175,0.885,0.32,1.275)}.selfhost-mascot:hover{transform:scale(1.05) translateY(-4px) rotate(-1deg)}.status-ring{position:absolute;width:90px;height:90px;border-radius:50%;background:rgba(99,102,241,0.05);border:2px dashed rgba(99,102,241,0.25);z-index:1}.status-ring.active-pulse{animation:radar-pulse 3s cubic-bezier(0.25,0.8,0.25,1) infinite}@keyframes radar-pulse{0%{transform:scale(0.85);opacity:0.9;border-color:rgba(99,102,241,0.3);box-shadow:0 0 0 0px rgba(99,102,241,0.15)}50%{transform:scale(1.18);opacity:0.35;border-color:rgba(56,189,248,0.2);box-shadow:0 0 0 15px rgba(56,189,248,0)}100%{transform:scale(0.85);opacity:0.9;border-color:rgba(99,102,241,0.3);box-shadow:0 0 0 0px rgba(99,102,241,0.15)}}.join-card-actions{display:flex;flex-direction:column;gap:0.75rem;width:100%}.join-card-actions .btn{width:100%;justify-content:center;padding:1.1rem;font-size:0.88rem;font-weight:700;letter-spacing:0.04em;text-transform:uppercase}.join-card-actions .btn svg{margin-right:0.3rem;flex-shrink:0}.join-card-actions .btn img{margin-right:0.3rem;flex-shrink:0}.btn-success{background:#22c55e;color:white !important;box-shadow:0 10px 15px -3px rgba(34,197,94,0.3)}.btn-success:hover{background:#16a34a;transform:translateY(-2px);box-shadow:0 20px 25px -5px rgba(34,197,94,0.4)} \ No newline at end of file