Changes to flowscroll.pub.scroll.pub

Breck Yunits
Breck Yunits
6 days ago
updated index.scroll
index.scroll
Changed around line 21: main
- label
+ label Session Length (minutes):
- Session Length (minutes):
- label
+ label Keystroke Interval (seconds):
- Keystroke Interval (seconds):
Breck Yunits
Breck Yunits
6 days ago
updated index.scroll
index.scroll
Changed around line 39: main
- button
+ button Save Settings
- Save Settings
Breck Yunits
Breck Yunits
6 days ago
updated index.scroll
index.scroll
Changed around line 79: footer
- p
+ p 0 words
- 0 words
root
root
6 days ago
Initial commit
index.scroll
Changed around line 1
+ buildHtml
+ baseUrl https://flowscroll.pub
+ metaTags
+ title FlowScroll - Focused Writing Zone
+ style.css
+
+ header
+ class header
+ div
+ class container
+ h1 FlowScroll
+ button
+ id settingsBtn
+ aria-label Settings
+ class icon-btn
+ โ˜ฐ
+ main
+ class container
+ div
+ class settings-panel hidden
+ h2 Focus Settings
+ form
+ id settingsForm
+ label
+ for sessionTime
+ Session Length (minutes):
+ input
+ type number
+ id sessionTime
+ name sessionTime
+ min 1
+ value 30
+ label
+ for keystrokeInterval
+ Keystroke Interval (seconds):
+ input
+ type number
+ id keystrokeInterval
+ name keystrokeInterval
+ min 5
+ value 10
+ button
+ type submit
+ class primary-button
+ Save Settings
+ div
+ class editor-container
+ div
+ class energy-bar hidden
+ textarea
+ id editor
+ placeholder Start writing here...
+ aria-label Writing area
+ spellcheck true
+ div
+ class controls
+ button
+ id fullscreenBtn
+ aria-label Toggle fullscreen
+ class icon-button
+ โคข
+ button
+ id themeToggle
+ aria-label Toggle theme
+ class icon-button
+ ๐ŸŒ“
+ input
+ type range
+ id lineWidth
+ name lineWidth
+ min 40
+ max 120
+ value 70
+ aria-label Adjust line width
+ footer
+ class footer
+ div
+ class container
+ p
+ id sessionTimer
+ class timer
+ p
+ id wordCount
+ class counter
+ 0 words
+
+ script.js
prompt.json
Changed around line 1
+ {
+ "id": "ec980ddd-bc40-4035-8d3b-22a0c5bb400b",
+ "object": "chat.completion",
+ "created": 1739712637,
+ "model": "deepseek-reasoner",
+ "choices": [
+ {
+ "index": 0,
+ "message": {
+ "role": "assistant",
+ "content": "---domain---\nflowscroll.pub\n---index.scroll---\nbuildHtml\nbaseUrl https://flowscroll.pub\nmetaTags\ntitle FlowScroll - Focused Writing Zone\nstyle.css\n\nheader\n class header\n div\n class container\n h1 FlowScroll\n button\n id settingsBtn\n aria-label Settings\n class icon-btn\n โ˜ฐ\nmain\n class container\n div\n class settings-panel hidden\n h2 Focus Settings\n form\n id settingsForm\n label\n for sessionTime\n Session Length (minutes):\n input\n type number\n id sessionTime\n name sessionTime\n min 1\n value 30\n label\n for keystrokeInterval\n Keystroke Interval (seconds):\n input\n type number\n id keystrokeInterval\n name keystrokeInterval\n min 5\n value 10\n button\n type submit\n class primary-button\n Save Settings\n div\n class editor-container\n div\n class energy-bar hidden\n textarea\n id editor\n placeholder Start writing here...\n aria-label Writing area\n spellcheck true\ndiv\n class controls\n button\n id fullscreenBtn\n aria-label Toggle fullscreen\n class icon-button\n โคข\n button\n id themeToggle\n aria-label Toggle theme\n class icon-button\n ๐ŸŒ“\n input\n type range\n id lineWidth\n name lineWidth\n min 40\n max 120\n value 70\n aria-label Adjust line width\nfooter\n class footer\n div\n class container\n p\n id sessionTimer\n class timer\n p\n id wordCount\n class counter\n 0 words\n\nscript.js\n---style.css---\n:root {\n --bg: #ffffff;\n --text: #333333;\n --primary: #2196f3;\n --container: 70ch;\n --border: #e0e0e0;\n}\n\n[data-theme=\"dark\"] {\n --bg: #1a1a1a;\n --text: #e0e0e0;\n --border: #404040;\n}\n\n* {\n box-sizing: border-box;\n margin: 0;\n padding: 0;\n}\n\nbody {\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, Oxygen, Ubuntu, Cantarell;\n background: var(--bg);\n color: var(--text);\n line-height: 1.6;\n transition: background 0.3s, color 0.3s;\n min-height: 100vh;\n display: flex;\n flex-direction: column;\n}\n\n.container {\n width: min(90%, var(--container));\n margin: 0 auto;\n}\n\n.header {\n padding: 1rem 0;\n border-bottom: 1px solid var(--border);\n}\n\n.editor-container {\n position: relative;\n flex-grow: 1;\n margin: 2rem 0;\n}\n\n#editor {\n width: 100%;\n min-height: 70vh;\n padding: 2rem;\n border: none;\n resize: none;\n background: transparent;\n color: inherit;\n font: inherit;\n line-height: 1.8;\n font-size: 1.1rem;\n}\n\n#editor:focus {\n outline: none;\n box-shadow: 0 0 0 2px var(--primary);\n}\n\n.energy-bar {\n position: fixed;\n top: 0;\n left: 0;\n height: 4px;\n background: linear-gradient(90deg, #ff6b6b, #ff5252);\n transition: width 0.1s linear;\n z-index: 1000;\n}\n\n.settings-panel {\n position: fixed;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n background: var(--bg);\n padding: 2rem;\n border-radius: 8px;\n box-shadow: 0 4px 12px rgba(0,0,0,0.2);\n z-index: 1000;\n}\n\n.controls {\n position: fixed;\n bottom: 2rem;\n right: 2rem;\n display: flex;\n gap: 0.5rem;\n background: var(--bg);\n padding: 0.5rem;\n border-radius: 8px;\n box-shadow: 0 2px 8px rgba(0,0,0,0.1);\n}\n\n.icon-button {\n width: 40px;\n height: 40px;\n border: none;\n background: transparent;\n color: var(--text);\n cursor: pointer;\n border-radius: 50%;\n display: grid;\n place-items: center;\n}\n\n.icon-button:hover {\n background: rgba(0,0,0,0.05);\n}\n\ninput[type=\"range\"] {\n width: 120px;\n height: 4px;\n background: var(--border);\n border-radius: 2px;\n}\n\n@media (max-width: 768px) {\n .container {\n width: 95%;\n }\n \n #editor {\n min-height: 60vh;\n padding: 1rem;\n }\n}\n---script.js---\nconst editor = document.getElementById('editor');\nconst themeToggle = document.getElementById('themeToggle');\nconst lineWidth = document.getElementById('lineWidth');\nconst energyBar = document.querySelector('.energy-bar');\nconst settingsForm = document.getElementById('settingsForm');\nconst sessionTimer = document.getElementById('sessionTimer');\nconst wordCount = document.getElementById('wordCount');\n\nlet lastKeyTime = Date.now();\nlet sessionEndTime = 0;\nlet keystrokeInterval = 10;\nlet checkInterval;\n\n// Load saved state\neditor.value = localStorage.getItem('content') || '';\nupdateWordCount();\n\nconst savedTheme = localStorage.getItem('theme') || 'light';\ndocument.documentElement.setAttribute('data-theme', savedTheme);\nthemeToggle.textContent = savedTheme === 'dark' ? '๐ŸŒž' : '๐ŸŒ™';\n\nlineWidth.value = localStorage.getItem('lineWidth') || 70;\ndocument.documentElement.style.setProperty('--container', `${lineWidth.value}ch`);\n\n// Theme toggle\nthemeToggle.addEventListener('click', () => {\n const newTheme = document.documentElement.getAttribute('data-theme') === 'dark' ? 'light' : 'dark';\n document.documentElement.setAttribute('data-theme', newTheme);\n themeToggle.textContent = newTheme === 'dark' ? '๐ŸŒž' : '๐ŸŒ™';\n localStorage.setItem('theme', newTheme);\n});\n\n// Line width\nlineWidth.addEventListener('input', (e) => {\n document.documentElement.style.setProperty('--container', `${e.target.value}ch`);\n localStorage.setItem('lineWidth', e.target.value);\n});\n\n// Fullscreen\ndocument.getElementById('fullscreenBtn').addEventListener('click', () => {\n if (!document.fullscreenElement) {\n document.documentElement.requestFullscreen();\n } else {\n document.exitFullscreen();\n }\n});\n\n// Auto-save\neditor.addEventListener('input', () => {\n localStorage.setItem('content', editor.value);\n updateWordCount();\n lastKeyTime = Date.now();\n});\n\n// Keystroke monitoring\ndocument.addEventListener('keydown', () => lastKeyTime = Date.now());\n\n// Energy bar system\nfunction startMonitoring() {\n checkInterval = setInterval(() => {\n const timeSinceLastKey = (Date.now() - lastKeyTime) / 1000;\n const warningThreshold = keystrokeInterval / 2;\n \n if (timeSinceLastKey > warningThreshold) {\n energyBar.classList.remove('hidden');\n const progress = Math.min(100, (timeSinceLastKey - warningThreshold) / (keystrokeInterval / 2) * 100);\n energyBar.style.width = `${100 - progress}%`;\n } else {\n energyBar.classList.add('hidden');\n }\n }, 100);\n}\n\n// Session timer\nfunction updateSessionTimer() {\n const remaining = Math.max(0, sessionEndTime - Date.now());\n if (remaining > 0) {\n const mins = Math.floor(remaining / 60000);\n const secs = Math.floor((remaining % 60000) / 1000);\n sessionTimer.textContent = `${mins}:${secs.toString().padStart(2, '0')} remaining`;\n }\n}\n\n// Settings form\nsettingsForm.addEventListener('submit', (e) => {\n e.preventDefault();\n keystrokeInterval = parseInt(document.getElementById('keystrokeInterval').value);\n const sessionMinutes = parseInt(document.getElementById('sessionTime').value);\n sessionEndTime = Date.now() + sessionMinutes * 60000;\n startMonitoring();\n setInterval(updateSessionTimer, 1000);\n document.querySelector('.settings-panel').classList.add('hidden');\n});\n\n// Toggle settings panel\ndocument.getElementById('settingsBtn').addEventListener('click', () => {\n document.querySelector('.settings-panel').classList.toggle('hidden');\n});\n\n// Word count\nfunction updateWordCount() {\n const count = editor.value.trim().split(/\\s+/).filter(w => w).length;\n wordCount.textContent = `${count} ${count === 1 ? 'word' : 'words'}`;\n}\n\n// Initialize\nstartMonitoring();\n---end---",
+ "reasoning_content": "Alright, let's tackle this problem. The user wants a writing environment with several specific features. Let me go through each requirement and figure out how to implement them using only HTML, CSS, and JavaScript without any frameworks.\n\nFirst, the domain name. It should end with scroll.pub and be memorable. Since it's a writing app focused on urgency and energy, maybe something like \"energyscroll.pub\" or \"flowscroll.pub\". \"Flow\" is good because it relates to writing flow. Let's go with flowscroll.pub.\n\nNext, the structure. The main elements needed are a textarea for input, controls for settings, and an energy bar. Since the user wants no chrome, the UI should be minimal. The textarea should take up most of the screen, with settings accessible via a menu that's hidden by default but can be toggled.\n\nDark and light mode can be handled with CSS variables and a class on the body. Local storage will save the theme preference. For saving the text, we'll use localStorage and listen for input events on the textarea.\n\nFull screen can be achieved with the Fullscreen API. A button to toggle fullscreen, and we'll need to style the body accordingly when in fullscreen mode.\n\nAdjusting line width can be done with a slider that changes a CSS variable for max-width on the container. Again, save this preference in localStorage.\n\nThe keystroke requirement is tricky. We need to track the last keypress time. If N seconds pass without a keypress, start showing the energy bar. If N/2 seconds pass, the bar starts depleting. So, setInterval to check the time since the last keypress. If it's past N/2, calculate the remaining time and update the energy bar's width. If it reaches zero, maybe flash or alert, but the user just wants to scare the user into typing, so visual feedback with the bar depleting should suffice.\n\nForcing a Y-minute writing session would require a timer that starts when the user begins typing. We can have a start session button that, when clicked, starts a countdown for Y minutes. During this time, the user can't exit without losing progress? Or maybe just track the time and notify when done. But the user didn't specify preventing exit, just forcing a session. So perhaps a timer that counts down and shows the remaining time.\n\nAccessibility is important. Use semantic HTML elements, aria-labels for buttons, and ensure keyboard navigability.\n\nMobile responsiveness: Use media queries to adjust font sizes and padding on smaller screens. Ensure the textarea and controls are usable on mobile.\n\nNow, putting it all together in Scroll syntax. The HTML structure will have a header with the app name and settings button, a main area with the textarea, and a footer with session info. The settings panel will be a hidden div that appears when the settings button is clicked.\n\nIn CSS, variables for light and dark themes. Use transitions for smooth theme switching. The energy bar is a fixed element at the top, hidden by default, with a transition on its width to show depletion.\n\nJavaScript will handle event listeners for keypresses, saving to localStorage, toggling themes, fullscreen, and managing the energy bar and session timer. The settings form will allow inputting N and Y values, saved to localStorage.\n\nTesting edge cases: what if N is set to a very small value? Ensure the energy bar doesn't cause layout issues. Also, when in fullscreen, the energy bar should adjust accordingly. LocalStorage values should be parsed correctly, with fallbacks if they don't exist.\n\nFinally, make sure all elements are styled beautifully with advanced CSS: gradients, shadows, smooth transitions. The typography should use system fonts but look clean and professional.\n\nI think that covers all the requirements. Now, structuring the Scroll markup, CSS, and JS accordingly."
+ },
+ "logprobs": null,
+ "finish_reason": "stop"
+ }
+ ],
+ "usage": {
+ "prompt_tokens": 952,
+ "completion_tokens": 2843,
+ "total_tokens": 3795,
+ "prompt_tokens_details": {
+ "cached_tokens": 0
+ },
+ "completion_tokens_details": {
+ "reasoning_tokens": 797
+ },
+ "prompt_cache_hit_tokens": 0,
+ "prompt_cache_miss_tokens": 952
+ },
+ "system_fingerprint": "fp_5417b77867"
+ }
readme.scroll
Changed around line 1
+ # flowscroll.pub.scroll.pub
+
+ Prompt: website
+ Agent: deepseekreasoner
+ Model: deepseek-reasoner
+
+ ## User prompt
+ Give me a writing environment. Should have dark mode and light mode. Should save to local storage so I dont lose work. Should have nice typography. Should allow going full screen. And allow adjusting the line width. There should be no chrome at all. It should have a setting that I can require a keystroke every N seconds, and also force me to have an Y minute long writing session. If I dont hit a keystroke after N/2 seconds, show an energy bar that is running out of energy to scare me to hit a key and keep going.
+
+ ## System prompt
+ You are an expert web developer. Create a website based on this request: "Give me a writing environment. Should have dark mode and light mode. Should save to local storage so I dont lose work. Should have nice typography. Should allow going full screen. And allow adjusting the line width. There should be no chrome at all. It should have a setting that I can require a keystroke every N seconds, and also force me to have an Y minute long writing session. If I dont hit a keystroke after N/2 seconds, show an energy bar that is running out of energy to scare me to hit a key and keep going."
+
+ Requirements:
+ - Use only Scroll, CSS, and JavaScript (NO frameworks, NO external dependencies)
+ - Create clean, semantic HTML5
+ - Make it mobile-responsive
+ - Follow modern best practices and accessibility guidelines
+ - Keep it simple but professional
+ - Use only relative links and no external resources
+ - Do not put a copyright symbol or all rights reserved in the footer.
+ - Make it beautiful. Dazzling. Advanced used of CSS.
+
+ As a refresher, for doing the html body, Scroll is a whitespace based language that uses a single indented space to mark a line (aka particle) as a subparticle of a parent line.
+
+ For example:
+
+ header
+ class hero
+ nav
+ div Scroll
+ class logo
+ div
+ class nav-links
+ a Features
+ href #features
+ a Examples
+ href #examples
+ a Edit
+ href edit.html
+ a GitHub
+ class cta-button
+ href https://github.com/breck7/scroll
+ div
+ class hero-content
+ h1 Write Better with Scroll
+ p The extendible markup language that makes source beautiful and compiles to anything
+ a Get Started
+ class primary-button
+ href https://hub.scroll.pub/
+ main
+ section
+ id features
+ class features
+ h2 Why Scroll?
+ div
+ class feature-grid
+ div
+ class feature-card
+ div โšก
+ class feature-icon
+ h3 Simple Syntax
+ p Like Markdown, but more powerful. No parentheses needed.
+ div
+ class feature-card
+ div ๐Ÿงฉ
+ class feature-icon
+ h3 Extendible
+ p Build your own custom parsers.
+ div
+ class feature-card
+ div ๐ŸŽจ
+ class feature-icon
+ h3 Beautiful Output
+ p Create stunning documents with minimal effort.
+ div
+ class feature-card
+ div ๐Ÿš€
+ class feature-icon
+ h3 Fast & Light
+ p Built on the efficient PPS Stack.
+ section
+ id examples
+ class code-demo
+ h2 See It In Action
+ div
+ class code-container
+ pre
+ class code-example
+ div
+ class code-output
+ footer
+ div
+ class footer-content
+ div
+ class footer-links
+ a Documentation
+ href https://scroll.pub/tutorial.html
+ a Community
+ href https://www.reddit.com/r/WorldWideScroll/
+ a Blog
+ href https://scroll.pub/blog
+ p Started by Breck Yunits. Evolved by a community.
+ https://twitter.com/breckyunits Breck Yunits
+ https://github.com/breck7/scroll/graphs/contributors community
+
+
+ First suggest a short, memorable domain name ending in scroll.pub that represents this website. Then provide the website files. Use this exact format:
+
+ ---domain---
+ (domainscroll.pub here)
+ ---index.scroll---
+ buildHtml
+ baseUrl https://(domainscroll.pub here)
+ metaTags
+ editButton /edit.html
+ title (Title here)
+ style.css
+
+ (body content here. no blank lines please.)
+
+ script.js
+ ---style.css---
+ (CSS content here)
+ ---script.js---
+ (JavaScript content here)
+ ---end---
script.js
Changed around line 1
+ const editor = document.getElementById('editor');
+ const themeToggle = document.getElementById('themeToggle');
+ const lineWidth = document.getElementById('lineWidth');
+ const energyBar = document.querySelector('.energy-bar');
+ const settingsForm = document.getElementById('settingsForm');
+ const sessionTimer = document.getElementById('sessionTimer');
+ const wordCount = document.getElementById('wordCount');
+
+ let lastKeyTime = Date.now();
+ let sessionEndTime = 0;
+ let keystrokeInterval = 10;
+ let checkInterval;
+
+ // Load saved state
+ editor.value = localStorage.getItem('content') || '';
+ updateWordCount();
+
+ const savedTheme = localStorage.getItem('theme') || 'light';
+ document.documentElement.setAttribute('data-theme', savedTheme);
+ themeToggle.textContent = savedTheme === 'dark' ? '๐ŸŒž' : '๐ŸŒ™';
+
+ lineWidth.value = localStorage.getItem('lineWidth') || 70;
+ document.documentElement.style.setProperty('--container', `${lineWidth.value}ch`);
+
+ // Theme toggle
+ themeToggle.addEventListener('click', () => {
+ const newTheme = document.documentElement.getAttribute('data-theme') === 'dark' ? 'light' : 'dark';
+ document.documentElement.setAttribute('data-theme', newTheme);
+ themeToggle.textContent = newTheme === 'dark' ? '๐ŸŒž' : '๐ŸŒ™';
+ localStorage.setItem('theme', newTheme);
+ });
+
+ // Line width
+ lineWidth.addEventListener('input', (e) => {
+ document.documentElement.style.setProperty('--container', `${e.target.value}ch`);
+ localStorage.setItem('lineWidth', e.target.value);
+ });
+
+ // Fullscreen
+ document.getElementById('fullscreenBtn').addEventListener('click', () => {
+ if (!document.fullscreenElement) {
+ document.documentElement.requestFullscreen();
+ } else {
+ document.exitFullscreen();
+ }
+ });
+
+ // Auto-save
+ editor.addEventListener('input', () => {
+ localStorage.setItem('content', editor.value);
+ updateWordCount();
+ lastKeyTime = Date.now();
+ });
+
+ // Keystroke monitoring
+ document.addEventListener('keydown', () => lastKeyTime = Date.now());
+
+ // Energy bar system
+ function startMonitoring() {
+ checkInterval = setInterval(() => {
+ const timeSinceLastKey = (Date.now() - lastKeyTime) / 1000;
+ const warningThreshold = keystrokeInterval / 2;
+
+ if (timeSinceLastKey > warningThreshold) {
+ energyBar.classList.remove('hidden');
+ const progress = Math.min(100, (timeSinceLastKey - warningThreshold) / (keystrokeInterval / 2) * 100);
+ energyBar.style.width = `${100 - progress}%`;
+ } else {
+ energyBar.classList.add('hidden');
+ }
+ }, 100);
+ }
+
+ // Session timer
+ function updateSessionTimer() {
+ const remaining = Math.max(0, sessionEndTime - Date.now());
+ if (remaining > 0) {
+ const mins = Math.floor(remaining / 60000);
+ const secs = Math.floor((remaining % 60000) / 1000);
+ sessionTimer.textContent = `${mins}:${secs.toString().padStart(2, '0')} remaining`;
+ }
+ }
+
+ // Settings form
+ settingsForm.addEventListener('submit', (e) => {
+ e.preventDefault();
+ keystrokeInterval = parseInt(document.getElementById('keystrokeInterval').value);
+ const sessionMinutes = parseInt(document.getElementById('sessionTime').value);
+ sessionEndTime = Date.now() + sessionMinutes * 60000;
+ startMonitoring();
+ setInterval(updateSessionTimer, 1000);
+ document.querySelector('.settings-panel').classList.add('hidden');
+ });
+
+ // Toggle settings panel
+ document.getElementById('settingsBtn').addEventListener('click', () => {
+ document.querySelector('.settings-panel').classList.toggle('hidden');
+ });
+
+ // Word count
+ function updateWordCount() {
+ const count = editor.value.trim().split(/\s+/).filter(w => w).length;
+ wordCount.textContent = `${count} ${count === 1 ? 'word' : 'words'}`;
+ }
+
+ // Initialize
+ startMonitoring();
style.css
Changed around line 1
+ :root {
+ --bg: #ffffff;
+ --text: #333333;
+ --primary: #2196f3;
+ --container: 70ch;
+ --border: #e0e0e0;
+ }
+
+ [data-theme="dark"] {
+ --bg: #1a1a1a;
+ --text: #e0e0e0;
+ --border: #404040;
+ }
+
+ * {
+ box-sizing: border-box;
+ margin: 0;
+ padding: 0;
+ }
+
+ body {
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell;
+ background: var(--bg);
+ color: var(--text);
+ line-height: 1.6;
+ transition: background 0.3s, color 0.3s;
+ min-height: 100vh;
+ display: flex;
+ flex-direction: column;
+ }
+
+ .container {
+ width: min(90%, var(--container));
+ margin: 0 auto;
+ }
+
+ .header {
+ padding: 1rem 0;
+ border-bottom: 1px solid var(--border);
+ }
+
+ .editor-container {
+ position: relative;
+ flex-grow: 1;
+ margin: 2rem 0;
+ }
+
+ #editor {
+ width: 100%;
+ min-height: 70vh;
+ padding: 2rem;
+ border: none;
+ resize: none;
+ background: transparent;
+ color: inherit;
+ font: inherit;
+ line-height: 1.8;
+ font-size: 1.1rem;
+ }
+
+ #editor:focus {
+ outline: none;
+ box-shadow: 0 0 0 2px var(--primary);
+ }
+
+ .energy-bar {
+ position: fixed;
+ top: 0;
+ left: 0;
+ height: 4px;
+ background: linear-gradient(90deg, #ff6b6b, #ff5252);
+ transition: width 0.1s linear;
+ z-index: 1000;
+ }
+
+ .settings-panel {
+ position: fixed;
+ top: 50%;
+ left: 50%;
+ transform: translate(-50%, -50%);
+ background: var(--bg);
+ padding: 2rem;
+ border-radius: 8px;
+ box-shadow: 0 4px 12px rgba(0,0,0,0.2);
+ z-index: 1000;
+ }
+
+ .controls {
+ position: fixed;
+ bottom: 2rem;
+ right: 2rem;
+ display: flex;
+ gap: 0.5rem;
+ background: var(--bg);
+ padding: 0.5rem;
+ border-radius: 8px;
+ box-shadow: 0 2px 8px rgba(0,0,0,0.1);
+ }
+
+ .icon-button {
+ width: 40px;
+ height: 40px;
+ border: none;
+ background: transparent;
+ color: var(--text);
+ cursor: pointer;
+ border-radius: 50%;
+ display: grid;
+ place-items: center;
+ }
+
+ .icon-button:hover {
+ background: rgba(0,0,0,0.05);
+ }
+
+ input[type="range"] {
+ width: 120px;
+ height: 4px;
+ background: var(--border);
+ border-radius: 2px;
+ }
+
+ @media (max-width: 768px) {
+ .container {
+ width: 95%;
+ }
+
+ #editor {
+ min-height: 60vh;
+ padding: 1rem;
+ }
+ }