diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index 2870475..9aacc60 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -2,7 +2,7 @@ name: Coverage on: push: - branches: [main, feature/*] + branches: ["main"] jobs: coverage: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index fcd3fc7..0550bfc 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -50,5 +50,6 @@ jobs: with: files: | target/release/PauseCat_Installer.msi + assets/default.webm env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/assets/overlay.html b/assets/overlay.html index 27fdf07..1275bd8 100644 --- a/assets/overlay.html +++ b/assets/overlay.html @@ -143,12 +143,68 @@ } .hidden { display: none !important; } + + /* 3D Text Fallback */ + .fallback-text-container { + position: fixed; + top: 0; + left: 0; + width: 100vw; + height: 100vh; + display: flex; + justify-content: center; + align-items: center; + z-index: -1; + perspective: 1000px; + background: linear-gradient(135deg, #1a1a1a 0%, #000 100%); + } + + .fallback-text-3d { + font-size: 15vw; + font-weight: 900; + color: var(--text-color, #fff); + text-transform: uppercase; + letter-spacing: -0.05em; + transform: rotateX(var(--rot-x, 20deg)) rotateY(var(--rot-y, -20deg)) rotateZ(var(--rot-z, 0deg)); + + /* High-Fidelity Shadow / Extrusion / Glow */ + text-shadow: var(--text-3d-shadow); + filter: var(--text-glow-filter, none); + + opacity: var(--text-opacity, 0.15); + user-select: none; + pointer-events: none; + text-align: center; + } + + @keyframes textFloat { + 0%, 100% { transform: rotateX(var(--rot-x, 20deg)) rotateY(var(--rot-y, -20deg)) rotateZ(var(--rot-z, 0deg)) translateZ(0); } + 50% { transform: rotateX(calc(var(--rot-x, 20deg) + 5deg)) rotateY(calc(var(--rot-y, -20deg) + 5deg)) rotateZ(var(--rot-z, 0deg)) translateZ(50px); } + } + + @keyframes textRotate { + 0% { transform: rotateX(var(--rot-x, 20deg)) rotateY(0deg) rotateZ(var(--rot-z, 0deg)); } + 100% { transform: rotateX(var(--rot-x, 20deg)) rotateY(360deg) rotateZ(var(--rot-z, 0deg)); } + } + + @keyframes textSwing { + 0%, 100% { transform: rotateX(var(--rot-x, 20deg)) rotateY(-40deg) rotateZ(var(--rot-z, 0deg)); } + 50% { transform: rotateX(var(--rot-x, 20deg)) rotateY(40deg) rotateZ(var(--rot-z, 0deg)); } + } + + @keyframes textPulse { + 0%, 100% { transform: rotateX(var(--rot-x, 20deg)) rotateY(var(--rot-y, -20deg)) rotateZ(var(--rot-z, 0deg)) scale(1); opacity: var(--text-opacity, 0.15); } + 50% { transform: rotateX(var(--rot-x, 20deg)) rotateY(var(--rot-y, -20deg)) rotateZ(var(--rot-z, 0deg)) scale(1.1); opacity: calc(var(--text-opacity, 0.15) + 0.1); } + }
+ - +
@@ -200,6 +256,32 @@ }, 500); } + function generate3DShadow(color, depth) { + let shadows = []; + for (let i = 1; i <= depth; i++) { + // Heavier extrusion with gradual darkening + let shadowColor = adjustColor(color, -i * 6); + shadows.push(`${i}px ${i}px 0px ${shadowColor}`); + } + shadows.push(`0 ${depth + 1}px 15px rgba(0,0,0,0.5)`); + shadows.push(`0 ${depth + 8}px 30px rgba(0,0,0,0.3)`); + return shadows.join(', '); + } + + function adjustColor(hex, amount) { + if (hex === 'transparent' || hex === 'none') return hex; + let usePound = false; + if (hex[0] == "#") { hex = hex.slice(1); usePound = true; } + let num = parseInt(hex, 16); + let r = (num >> 16) + amount; + if (r > 255) r = 255; else if (r < 0) r = 0; + let b = ((num >> 8) & 0x00FF) + amount; + if (b > 255) b = 255; else if (b < 0) b = 0; + let g = (num & 0x0000FF) + amount; + if (g > 255) g = 255; else if (g < 0) g = 0; + return (usePound ? "#" : "") + (g | (b << 8) | (r << 16)).toString(16).padStart(6, '0'); + } + window.chrome.webview.addEventListener('message', event => { if (event.data.action === "init") { seconds = event.data.duration; @@ -219,7 +301,7 @@ root.style.setProperty('--bubble-size', event.data.bubbleSize + 'px'); root.style.setProperty('--glass-bg', `rgba(${event.data.isDark ? '0,0,0' : '255,255,255'}, ${event.data.bubbleOpacity})`); - // Smart Position: Account for bubble size so it doesn't clip off edge at 100% + // Smart Position bubble.style.left = `calc(${event.data.bubblePosX}% - ${event.data.bubbleSize * (event.data.bubblePosX/100)}px)`; bubble.style.top = `calc(${event.data.bubblePosY}% - ${event.data.bubbleSize * (event.data.bubblePosY/100)}px)`; @@ -227,6 +309,55 @@ bubble.style.animation = `${event.data.animationStyle} 6s ease-in-out infinite`; } + // Custom 3D Text Logic + const fallback = document.getElementById('fallback-ui'); + const fallbackText = fallback.querySelector('.fallback-text-3d'); + if (event.data.customText) { + fallbackText.innerText = event.data.customText; + } + + // Adaptive Color Logic + let finalColor = event.data.textColor || '#ffffff'; + if (event.data.adaptiveTextColor) { + finalColor = event.data.isDark ? '#ffffff' : '#000000'; + } + + // Apply advanced text styles + root.style.setProperty('--text-color', finalColor); + root.style.setProperty('--text-opacity', event.data.textOpacity ?? 0.15); + root.style.setProperty('--rot-x', (event.data.textRotationX ?? 20) + 'deg'); + root.style.setProperty('--rot-y', (event.data.textRotationY ?? -20) + 'deg'); + root.style.setProperty('--rot-z', (event.data.textRotationZ ?? 0) + 'deg'); + + // Glow Logic + if (event.data.textGlowEnabled) { + const glowColor = event.data.textGlowColor || finalColor; + root.style.setProperty('--text-glow-filter', `drop-shadow(0 0 ${(event.data.textGlow ?? 10)}px ${glowColor})`); + } else { + root.style.setProperty('--text-glow-filter', 'none'); + } + + root.style.setProperty('--text-3d-shadow', generate3DShadow(finalColor, event.data.textDepth ?? 5)); + + const textAnim = event.data.textAnimation || 'float'; + if (textAnim === 'float') { + fallbackText.style.animation = 'textFloat 8s ease-in-out infinite'; + } else if (textAnim === 'rotate') { + fallbackText.style.animation = 'textRotate 10s linear infinite'; + } else if (textAnim === 'swing') { + fallbackText.style.animation = 'textSwing 6s ease-in-out infinite'; + } else if (textAnim === 'pulse') { + fallbackText.style.animation = 'textPulse 4s ease-in-out infinite'; + } else { + fallbackText.style.animation = 'none'; + } + + if (event.data.breakStyle === 'text') { + fallback.classList.remove('hidden'); + } else { + fallback.classList.add('hidden'); + } + // Break Messages if (event.data.breakMessages && event.data.breakMessages.length > 0) { breakMessages = event.data.breakMessages; @@ -236,7 +367,7 @@ } } - // Work Duration Status (Smart Formatting) + // Work Duration Status if (event.data.showWorkStatus) { const workStatusEl = document.getElementById('work-status-text'); workStatusEl.classList.remove('hidden'); @@ -253,14 +384,29 @@ } } - if (event.data.mediaPath) { + if (event.data.mediaPath && event.data.breakStyle !== 'text') { const img = document.getElementById('bg-image'); const video = document.getElementById('bg-video'); + const fallback = document.getElementById('fallback-ui'); const ext = event.data.mediaPath.split('.').pop().toLowerCase(); + + video.onerror = () => { + console.warn("Video load failed, showing fallback UI"); + video.classList.add('hidden'); + fallback.classList.remove('hidden'); + }; + + // Set Volume + video.volume = event.data.videoVolume ?? 0.0; + if (['mp4', 'webm', 'ogg'].includes(ext)) { video.src = event.data.mediaPath; video.classList.remove('hidden'); - video.play().catch(e => console.error(e)); + video.play().catch(e => { + console.error(e); + video.classList.add('hidden'); + fallback.classList.remove('hidden'); + }); } else { img.src = event.data.mediaPath; img.classList.remove('hidden'); diff --git a/assets/settings.html b/assets/settings.html index f6beec9..b8f0828 100644 --- a/assets/settings.html +++ b/assets/settings.html @@ -16,13 +16,6 @@ --ring: #f4ebff; --card-bg: #ffffff; --header-bg: #ffffff; - --glass-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -2px rgba(0, 0, 0, 0.1); - --update-bg: #ecfdf3; - --update-text: #027a48; - --update-border: #abfdfd; - --danger-bg: #fef2f2; - --danger-text: #b91c1c; - --danger-border: #fecaca; } body.dark { @@ -36,191 +29,196 @@ --ring: #2d1d5a; --card-bg: #1a1a1a; --header-bg: #121212; - --update-bg: #052e16; - --update-text: #6ee7b7; - --update-border: #064e3b; - --danger-bg: #450a0a; - --danger-text: #fca5a5; - --danger-border: #7f1d1d; } - html, body { - overflow: hidden; - touch-action: none; - user-select: none; - -webkit-user-drag: none; - } + html, body { overflow: hidden; touch-action: none; user-select: none; } body { font-family: 'Inter', system-ui, -apple-system, sans-serif; - background-color: var(--bg-color); - color: var(--text-main); - margin: 0; - padding: 0; - height: 100vh; - display: flex; - flex-direction: column; + background-color: var(--bg-color); color: var(--text-main); + margin: 0; padding: 0; height: 100vh; + display: flex; flex-direction: column; transition: background-color 0.3s, color 0.3s; } .header { - padding: 16px 24px; - display: flex; - align-items: center; gap: 12px; - border-bottom: 1px solid var(--border); - background: var(--header-bg); - z-index: 10; flex-shrink: 0; + padding: 16px 24px; display: flex; align-items: center; gap: 12px; + border-bottom: 1px solid var(--border); background: var(--header-bg); flex-shrink: 0; } - .header h1 { font-size: 1.125rem; font-weight: 600; margin: 0; } - .header img { width: 28px; height: 28px; border-radius: 6px; object-fit: contain; } + .header img { width: 28px; height: 28px; border-radius: 6px; } .scroll-container { flex: 1; overflow-y: auto; padding: 20px 24px; - background: var(--secondary-bg); - scrollbar-width: none; -ms-overflow-style: none; + background: var(--secondary-bg); scrollbar-width: none; } .scroll-container::-webkit-scrollbar { display: none; } .section-title { - font-size: 0.7rem; font-weight: 600; - color: var(--text-secondary); text-transform: uppercase; - letter-spacing: 0.05em; margin-bottom: 10px; margin-top: 10px; + font-size: 0.7rem; font-weight: 600; color: var(--text-secondary); + text-transform: uppercase; letter-spacing: 0.05em; margin: 12px 0 8px 0; } .card { - background: var(--card-bg); - border: 1px solid var(--border); - border-radius: 12px; padding: 16px; - margin-bottom: 20px; box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); - } - - /* Modal / Popup Styles */ - .modal-overlay { - position: fixed; top: 0; left: 0; right: 0; bottom: 0; - background: rgba(0, 0, 0, 0.5); - display: flex; justify-content: center; align-items: center; - z-index: 1000; animation: fadeIn 0.3s ease; - } - - .modal-content { - background: var(--bg-color); - width: 85%; max-width: 400px; - border-radius: 16px; padding: 24px; - box-shadow: 0 20px 25px -5px rgba(0,0,0,0.2); - border: 1px solid var(--border); - text-align: center; - } - - .modal-title { font-size: 1.25rem; font-weight: 700; margin-bottom: 12px; display: block; } - .modal-desc { font-size: 0.9rem; color: var(--text-secondary); margin-bottom: 24px; line-height: 1.5; display: block; } - - /* Progress Bar for Update */ - .progress-container { - width: 100%; height: 8px; - background: var(--secondary-bg); - border-radius: 4px; overflow: hidden; - margin-bottom: 12px; border: 1px solid var(--border); - } - .progress-bar { - height: 100%; background: var(--accent); - width: 0%; transition: width 0.2s ease; + background: var(--card-bg); border: 1px solid var(--border); + border-radius: 12px; padding: 16px; margin-bottom: 24px; + box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); } .setting-row { - display: flex; justify-content: space-between; - align-items: center; margin-bottom: 16px; gap: 12px; + display: flex; justify-content: space-between; align-items: center; + margin-bottom: 16px; gap: 16px; } .setting-row:last-child { margin-bottom: 0; } - .setting-info { display: flex; flex-direction: column; gap: 2px; flex: 1; } - .setting-label { font-size: 0.875rem; font-weight: 500; } - .setting-description { font-size: 0.75rem; color: var(--text-secondary); } + .setting-info { display: flex; flex-direction: column; gap: 2px; flex: 1; min-width: 0; } + .setting-label { font-size: 0.9rem; font-weight: 600; white-space: nowrap; } + .setting-description { font-size: 0.75rem; color: var(--text-secondary); overflow: hidden; text-overflow: ellipsis; } + + .setting-control { display: flex; align-items: center; justify-content: flex-end; min-width: 140px; gap: 8px; } input[type="number"], input[type="text"], select { - padding: 6px 10px; border: 1px solid var(--border); - border-radius: 6px; font-size: 0.85rem; outline: none; - transition: all 0.2s; background: var(--card-bg); - color: var(--text-main); font-family: inherit; + padding: 8px 12px; border: 1px solid var(--border); + border-radius: 8px; font-size: 0.85rem; outline: none; + background: var(--card-bg); color: var(--text-main); transition: border-color 0.2s; + } + input[type="number"] { width: 70px; } + select { width: 130px; } + input[type="text"] { width: 100%; box-sizing: border-box; } + + input[type="range"] { + -webkit-appearance: none; width: 100px; height: 4px; + background: var(--border); border-radius: 2px; outline: none; + accent-color: var(--accent); cursor: pointer; } - input[type="number"] { width: 65px; } - select { width: 110px; } - input[type="range"] { width: 120px; accent-color: var(--accent); cursor: pointer; } - select option { background-color: var(--card-bg); color: var(--text-main); } - input:focus, select:focus { border-color: var(--accent); box-shadow: 0 0 0 3px var(--ring); } .preview-container { - width: 100%; height: 160px; background: #000; - border-radius: 10px; position: relative; overflow: hidden; - margin-bottom: 20px; border: 1px solid var(--border); flex-shrink: 0; + width: 100%; aspect-ratio: 16 / 9; background: #000; + border-radius: 12px; position: relative; overflow: hidden; + margin-bottom: 12px; border: 1px solid var(--border); flex-shrink: 0; + perspective: 1000px; + } + .preview-bg { width: 100%; height: 100%; object-fit: cover; opacity: 0.5; position: absolute; top:0; left:0; z-index: 0; } + + .preview-text-3d-container { + position: absolute; top: 0; left: 0; width: 100%; height: 100%; + display: flex; justify-content: center; align-items: center; + pointer-events: none; z-index: 1; } - .preview-bg { width: 100%; height: 100%; object-fit: cover; opacity: 0.5; } + .preview-text-3d { + font-size: 5vw; font-weight: 950; color: var(--text-color, #fff); + text-transform: uppercase; text-align: center; line-height: 1; + transform: rotateX(var(--rot-x, 20deg)) rotateY(var(--rot-y, -20deg)) rotateZ(var(--rot-z, 0deg)); + text-shadow: var(--text-3d-shadow); opacity: var(--text-opacity, 0.2); + animation: previewFloat 5s ease-in-out infinite; + filter: var(--text-glow-filter, none); + } + @keyframes previewFloat { + 0%, 100% { transform: rotateX(var(--rot-x, 20deg)) rotateY(var(--rot-y, -20deg)) rotateZ(var(--rot-z, 0deg)) translateZ(0); } + 50% { transform: rotateX(calc(var(--rot-x, 20deg) + 5deg)) rotateY(calc(var(--rot-y, -20deg) + 5deg)) rotateZ(var(--rot-z, 0deg)) translateZ(20px); } + } + .preview-bubble { position: absolute; background: rgba(255, 255, 255, 0.1); backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px); border: 1px solid rgba(255, 255, 255, 0.2); border-radius: 50%; display: flex; justify-content: center; align-items: center; color: white; font-weight: 700; pointer-events: none; - box-shadow: 0 8px 16px rgba(0,0,0,0.3); - transition: all 0.2s ease; + box-shadow: 0 8px 16px rgba(0,0,0,0.3); z-index: 2; + transition: all 0.3s ease; } - .media-preview-area { position: relative; margin-top: 10px; } - .media-preview { - width: 100%; height: 140px; border: 2px dashed var(--border); - border-radius: 10px; display: flex; flex-direction: column; - justify-content: center; align-items: center; background: var(--card-bg); - cursor: pointer; transition: all 0.2s; overflow: hidden; + .status-footer { + margin-bottom: 24px; padding: 0 4px; display: flex; justify-content: space-between; align-items: center; + font-size: 0.75rem; font-weight: 500; color: var(--text-secondary); } - .media-preview:hover { border-color: var(--accent); background: var(--secondary-bg); } - .media-preview img, .media-preview video { width: 100%; height: 100%; object-fit: cover; } - .media-placeholder { display: flex; flex-direction: column; align-items: center; gap: 6px; color: var(--text-secondary); font-size: 0.8rem; } + .status-dot { width: 8px; height: 8px; border-radius: 50%; display: inline-block; margin-right: 4px; } + .dot-ready { background: #22c55e; box-shadow: 0 0 8px #22c55e; } + .dot-missing { background: #eab308; box-shadow: 0 0 8px #eab308; } + .dot-error { background: #ef4444; box-shadow: 0 0 8px #ef4444; } - .reset-media { - position: absolute; top: 6px; right: 6px; background: rgba(16, 24, 40, 0.7); - color: white; border: none; border-radius: 6px; padding: 3px 6px; - font-size: 0.7rem; font-weight: 500; cursor: pointer; backdrop-filter: blur(4px); + .asset-progress-container { + width: 80px; height: 4px; background: var(--border); + border-radius: 2px; overflow: hidden; margin-left: 8px; + display: inline-block; vertical-align: middle; } + .asset-progress-bar { height: 100%; background: var(--accent); width: 0%; transition: width 0.3s ease; } - .list-container { margin-top: 10px; display: flex; flex-wrap: wrap; gap: 6px; } - .tag { - background: var(--ring); color: var(--accent); padding: 3px 8px; - border-radius: 12px; font-size: 0.7rem; font-weight: 600; - display: flex; align-items: center; gap: 4px; border: 1px solid var(--accent); + .retry-btn { + background: none; border: 1px solid var(--accent); color: var(--accent); + padding: 2px 6px; border-radius: 4px; font-size: 0.65rem; cursor: pointer; + margin-left: 8px; } - .tag span { cursor: pointer; font-size: 0.9rem; line-height: 1; } - .add-row { display: flex; gap: 6px; margin-top: 12px; } - .add-row input, .add-row select { flex: 1; width: auto; } + .media-preview-area { margin-top: 12px; } + .media-preview { + width: 100%; height: 160px; border: 2px dashed var(--border); + border-radius: 12px; display: flex; justify-content: center; align-items: center; + background: var(--card-bg); cursor: pointer; overflow: hidden; position: relative; + transition: all 0.2s; + } + .media-preview:hover { border-color: var(--accent); background: var(--secondary-bg); } + .media-preview img, .media-preview video { width: 100%; height: 100%; object-fit: cover; position: absolute; top:0; left:0; } + .media-placeholder { display: flex; flex-direction: column; align-items: center; color: var(--text-secondary); font-size: 0.85rem; z-index: 1; } - .footer { - padding: 12px 24px; background: var(--header-bg); border-top: 1px solid var(--border); - display: flex; justify-content: flex-end; gap: 10px; flex-shrink: 0; + .list-container { margin-top: 12px; display: flex; flex-wrap: wrap; gap: 8px; } + .tag { + background: var(--ring); color: var(--accent); padding: 4px 10px; + border-radius: 12px; font-size: 0.75rem; font-weight: 600; + display: flex; align-items: center; gap: 6px; border: 1px solid var(--accent); } + .tag span { cursor: pointer; font-size: 1rem; line-height: 1; } + + .add-row { display: flex; gap: 8px; margin-top: 14px; } - button { - padding: 8px 14px; border-radius: 6px; font-size: 0.85rem; - font-weight: 600; cursor: pointer; transition: all 0.2s; border: 1px solid transparent; + .footer { + padding: 16px 24px; background: var(--header-bg); border-top: 1px solid var(--border); + display: flex; justify-content: flex-end; gap: 12px; flex-shrink: 0; } - .btn-primary { background-color: var(--accent); color: white; border-color: var(--accent); } - .btn-primary:hover { background-color: var(--accent-hover); } - .btn-secondary { background-color: var(--bg-color); color: var(--text-main); border-color: var(--border); } - .btn-secondary:hover { background-color: var(--secondary-bg); } + button { padding: 10px 18px; border-radius: 8px; font-size: 0.85rem; font-weight: 600; cursor: pointer; border: 1px solid transparent; transition: all 0.2s; } + .btn-primary { background: var(--accent); color: white; } + .btn-primary:hover { background: var(--accent-hover); transform: translateY(-1px); } + .btn-secondary { background: var(--bg-color); color: var(--text-main); border-color: var(--border); } + .btn-secondary:hover { background: var(--secondary-bg); } - .switch { position: relative; display: inline-block; width: 36px; height: 18px; } + .switch { position: relative; display: inline-block; width: 40px; height: 20px; } .switch input { opacity: 0; width: 0; height: 0; } - .slider { position: absolute; cursor: pointer; top: 0; left: 0; right: 0; bottom: 0; background-color: var(--border); transition: .3s; border-radius: 18px; } - .slider:before { position: absolute; content: ""; height: 14px; width: 14px; left: 2px; bottom: 2px; background-color: white; transition: .3s; border-radius: 50%; } + .slider { position: absolute; cursor: pointer; top: 0; left: 0; right: 0; bottom: 0; background-color: var(--border); transition: .3s; border-radius: 20px; } + .slider:before { position: absolute; content: ""; height: 16px; width: 16px; left: 2px; bottom: 2px; background-color: white; transition: .3s; border-radius: 50%; } input:checked + .slider { background-color: var(--accent); } - input:checked + .slider:before { transform: translateX(18px); } + input:checked + .slider:before { transform: translateX(20px); } - .hidden { display: none !important; } + /* Modal / Popup Styles */ + .modal-overlay { + position: fixed; top: 0; left: 0; right: 0; bottom: 0; + background: rgba(0, 0, 0, 0.5); + display: flex; justify-content: center; align-items: center; + z-index: 1000; animation: fadeIn 0.3s ease; + } - @keyframes float { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-10px); } } - @keyframes bounce { 0%, 100% { transform: scale(1); } 50% { transform: scale(1.08); } } - @keyframes pulse { 0%, 100% { transform: scale(1); opacity: var(--pulse-opacity-start); } 50% { transform: scale(1.05); opacity: var(--pulse-opacity-end); } } - @keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } } + .modal-content { + background: var(--bg-color); + width: 85%; max-width: 400px; + border-radius: 16px; padding: 24px; + box-shadow: 0 20px 25px -5px rgba(0,0,0,0.2); + border: 1px solid var(--border); + text-align: center; + } + + .modal-title { font-size: 1.25rem; font-weight: 700; margin-bottom: 12px; display: block; } + .modal-desc { font-size: 0.9rem; color: var(--text-secondary); margin-bottom: 24px; line-height: 1.5; display: block; } + + .progress-container { + width: 100%; height: 8px; + background: var(--secondary-bg); + border-radius: 4px; overflow: hidden; + margin-bottom: 12px; border: 1px solid var(--border); + } + .progress-bar { + height: 100%; background: var(--accent); + width: 0%; transition: width 0.2s ease; + } .notification { position: fixed; bottom: 24px; left: 24px; right: 24px; padding: 16px; @@ -228,29 +226,29 @@ box-shadow: 0 12px 24px rgba(0,0,0,0.15); z-index: 1100; display: flex; flex-direction: column; gap: 8px; animation: slideUp 0.4s cubic-bezier(0.16, 1, 0.3, 1); } - @keyframes slideUp { from { transform: translateY(100%) opacity: 0; } to { transform: translateY(0) opacity: 1; } } + + @keyframes slideUp { from { transform: translateY(100%); opacity: 0; } to { transform: translateY(0); opacity: 1; } } + @keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } } + + .hidden { display: none !important; }
- PauseCat +

PauseCat Settings

- +