From dae4c1880f5d35f214948b48fd6e90f278ab96d1 Mon Sep 17 00:00:00 2001 From: Cynda <84293227+FrCynda@users.noreply.github.com> Date: Thu, 19 Feb 2026 08:49:02 +0100 Subject: [PATCH 01/48] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4859a00..af0583f 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Paint - Professional (GBA & Retro Asset Suite) +# CDPaint - GBA Asset Suite A high-performance, WebGL-accelerated painting application designed for pixel artists and retro game developers. While it maintains the classic "Win32" aesthetic, it introduces professional image processing, active bit-depth enforcement, and specialized export tools for hardware-constrained environments like the Game Boy Advance (GBA). From 6664cea4ace57de1ed1f9e52f86984c87f9f6229 Mon Sep 17 00:00:00 2001 From: Cynda <84293227+FrCynda@users.noreply.github.com> Date: Thu, 19 Feb 2026 09:11:09 +0100 Subject: [PATCH 02/48] Update README.md Added Image --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index af0583f..ebee2bd 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,9 @@ A high-performance, WebGL-accelerated painting application designed for pixel artists and retro game developers. While it maintains the classic "Win32" aesthetic, it introduces professional image processing, active bit-depth enforcement, and specialized export tools for hardware-constrained environments like the Game Boy Advance (GBA). +image + + ## πŸš€ Key Features (Beyond Standard MS Paint) ### 1. Active Canvas-Wide Color Modes From 314531778ecb2365b881006401cdf222a15215a7 Mon Sep 17 00:00:00 2001 From: Cynda <84293227+FrCynda@users.noreply.github.com> Date: Thu, 19 Feb 2026 09:13:54 +0100 Subject: [PATCH 03/48] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ebee2bd..59805a8 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ A high-performance, WebGL-accelerated painting application designed for pixel artists and retro game developers. While it maintains the classic "Win32" aesthetic, it introduces professional image processing, active bit-depth enforcement, and specialized export tools for hardware-constrained environments like the Game Boy Advance (GBA). -image +image ## πŸš€ Key Features (Beyond Standard MS Paint) From 66b4a17c8af010b24d0ae59cdf81fa30ba9f2f0e Mon Sep 17 00:00:00 2001 From: Cynda <84293227+FrCynda@users.noreply.github.com> Date: Thu, 19 Feb 2026 09:25:48 +0100 Subject: [PATCH 04/48] Update README.md --- README.md | 166 +++++++++++++++++++++++------------------------------- 1 file changed, 69 insertions(+), 97 deletions(-) diff --git a/README.md b/README.md index 59805a8..0ba5c73 100644 --- a/README.md +++ b/README.md @@ -72,104 +72,76 @@ Tauri: - Tauri uses the dev server in development (`beforeDevCommand`: `npm run dev`) - Tauri uses `dist/` for production builds (`beforeBuildCommand`: `npm run build`) -## Full tutorial: build and run (novice-friendly) - -This section intentionally over-explains the setup so you can follow it even if you have never built a desktop app before. - -### 1. Install prerequisites (one-time setup) -You need three things: -- **Node.js (LTS)** for the frontend dev server and build. -- **Rust + Cargo** for the Tauri backend and bundling. -- **C++ build tools** on Windows for compiling native dependencies. - -Official download links (copy/paste into your browser): -```text -Node.js (LTS): https://nodejs.org/en/download -Rust (rustup): https://www.rust-lang.org/tools/install -Visual Studio Build Tools (C++): https://visualstudio.microsoft.com/visual-cpp-build-tools/ -Tauri prerequisites (Windows): https://tauri.app/v2/guides/prerequisites/ -``` - -Notes: -- For Rust, install via `rustup` when prompted. It sets up `cargo` automatically. -- For Visual Studio Build Tools, choose the **Desktop development with C++** workload. -- After installing, **close and re-open your terminal** so new commands are available. - -Verify installs (you should see version numbers, not errors): -```powershell -node -v -npm -v -rustc -V -cargo -V -``` - -If any command says β€œnot found,” the install did not finish correctly or the terminal needs a restart. - -### 2. Open a terminal in the project folder -You should be in: -`C:\Users\frenc\Desktop\CDPaint` - -In WebStorm: -1. Open the built-in Terminal tab. -2. Check the prompt path is the project folder. - -### 3. Install frontend dependencies (one-time per clone) -This downloads the Node packages listed in `package.json`: -```powershell -npm install -``` - -Expected result: -- It creates a `node_modules/` folder. -- No fatal errors. - -### 4. Run the app in development -This starts a local web server and opens the desktop window: -```powershell -npm run tauri dev -``` - -What happens: -1. `npm run dev` starts a tiny server at `http://localhost:1420`. -2. Tauri launches a native window that loads that URL. - -What you should see: -- A CDPaint window. -- The UI updates live when you edit files in `src/`. - -To stop dev mode: -- Close the app window. -- Press `Ctrl+C` in the terminal. - -### 5. Build a production desktop app -This creates release builds and installers: -```powershell -npm run tauri:build -``` - -What happens: -1. `npm run build` copies `src/` to `dist/`. -2. Tauri compiles Rust and bundles the desktop app. - -Output locations (common on Windows): -- Release binaries: `src-tauri/target/release/` -- Installers/bundles: `src-tauri/target/release/bundle/` - -If you don’t see output: -- Re-run the command and read the last 20 lines for errors. -- Most issues are missing C++ build tools or a failed Rust install. - -## Common problems - -### "command not found" for node, npm, rustc, or cargo -Install the missing tool and restart the terminal. - -### "failed to run beforeDevCommand" or "beforeBuildCommand" -Make sure: -- You ran `npm install` -- `npm run dev` works on its own -- `npm run build` works on its own +# CDPaint - Build & Run Guide +Welcome! This guide is written specifically for complete beginners. You do not need to be a programmer or have any special coding software installed to build this desktop app. Just follow these steps one by one. + +## 1. Install Prerequisites (One-Time Setup) + +You only need to install three standard tools to make this work. Download them using the official links below: + +* **Node.js** (Runs the visual interface) + * **Download:** Get the **LTS** version from [nodejs.org](https://nodejs.org/en/download) + * **Setup:** Click through the standard installation, accepting all the defaults. +* **Rust** (Runs the app's background engine) + * **Download:** Get the installer from [rust-lang.org](https://www.rust-lang.org/tools/install) + * **Setup:** When the black window pops up during installation, simply press `1` and hit **Enter** to accept the default installation. +* **Visual Studio Build Tools** (Helps Windows read the code) + * **Download:** Get it from [microsoft.com](https://visualstudio.microsoft.com/visual-cpp-build-tools/) + * **Setup:** During installation, you will see a screen with checkboxes. You **must** check the box that says **Desktop development with C++**. + +> **IMPORTANT:** Once all three are installed, **restart your computer** so Windows registers the new tools. + +--- + +## 2. Open the Command Prompt in Your Folder + +Instead of using complex coding software, use this standard Windows shortcut to open your command prompt exactly where it needs to be: + +1. Open your **CDPaint** folder (e.g., `C:\Users\frenc\Desktop\CDPaint`) normally using Windows File Explorer. +2. Click directly on the long address bar at the very top of the folder window. +3. Delete the text in the bar, type `cmd`, and press **Enter**. +4. A black Command Prompt window will pop up, already locked onto your project folder. Keep it open! + +--- + +## 3. Install the App Files (One-Time Setup) + +We need to download the specific files your app needs to run. + +In the black Command Prompt window you just opened, type the following command exactly as written and press **Enter**: + +`npm install` + +*Note: Wait for the progress bars to finish. When the text stops moving and you see a blinking cursor again, it is done.* + +--- + +## 4. Run the App (Test Mode) + +To launch your app so you can see it and test it, type this command and press **Enter**: + +`npm run tauri dev` + +* **What happens:** The black window will process some text, and after a few moments, your CDPaint desktop application will automatically open! +* **To stop it:** When you are done testing, close the CDPaint window normally. Then, click on your black Command Prompt window and press `Ctrl` + `C` to safely shut down the background process. + +--- + +## 5. Build the Final App (To Share or Install) + +When you are completely finished and want to create the final, clickable application file (like an `.exe` installer) that you can share with others, use this command and press **Enter**: + +`npm run tauri:build` + +* **What happens:** This process takes a few minutes. Once it finishes, open your CDPaint folder in File Explorer. You will find your final, ready-to-use application hidden inside this specific folder path: `src-tauri/target/release/bundle/` + +--- + +## Common Fixes + +* **"Command not found" error:** Your computer hasn't recognized the installations from Step 1. Make sure you fully restarted your computer after installing them. +* **White or Blank app window:** You likely skipped Step 3. Close the app, run `npm install` in your command prompt, and try again. ### White/blank window in dev Check the dev server is running: - Open `http://localhost:1420` in your browser From 07c28bf2950d528554cf29781fa90ded27f31b5a Mon Sep 17 00:00:00 2001 From: Cynda <84293227+FrCynda@users.noreply.github.com> Date: Thu, 19 Feb 2026 20:23:37 +0100 Subject: [PATCH 05/48] Update README.md --- README.md | 189 +++++++++++++++++++++++++++--------------------------- 1 file changed, 93 insertions(+), 96 deletions(-) diff --git a/README.md b/README.md index 0ba5c73..2881272 100644 --- a/README.md +++ b/README.md @@ -1,148 +1,145 @@ # CDPaint - GBA Asset Suite -A high-performance, WebGL-accelerated painting application designed for pixel artists and retro game developers. While it maintains the classic "Win32" aesthetic, it introduces professional image processing, active bit-depth enforcement, and specialized export tools for hardware-constrained environments like the Game Boy Advance (GBA). +[![Tauri](https://img.shields.io/badge/Tauri-Build-blue.svg)](https://tauri.app/) +[![Node.js](https://img.shields.io/badge/Node.js-LTS-green.svg)](https://nodejs.org/) +[![Rust](https://img.shields.io/badge/Rust-Ready-orange.svg)](https://www.rust-lang.org/) -image +A high-performance, WebGL-accelerated painting application designed for pixel artists and retro game developers. While it maintains a modern Windows aesthetic, it introduces useful image processing, active bit-depth enforcement, and specialized export tools for hardware-constrained environments like the Game Boy Advance (GBA). +CDPaint Interface -## πŸš€ Key Features (Beyond Standard MS Paint) +# Table of Contents -### 1. Active Canvas-Wide Color Modes +- [πŸš€ Key Features](#-key-features) +- [πŸ›  Technical Stack](#-technical-stack) +- [πŸ— Architecture](#-architecture) +- [πŸ’» Build & Run Guide](#-build--run-guide) +- [πŸ”§ Troubleshooting](#-troubleshooting) -Unlike standard editors that operate in a 24-bit space, this app allows you to lock the entire drawing experience to specific hardware limits: +--- -- **Active Quantization**: Every stroke you draw is automatically converted to the nearest valid color in your selected mode. -- **15bpp (RGB555)**: Constrains R, G, and B to 32 levels each (GBA native). -- **16bpp (RGB565)**: Constrains R and B to 32 levels and G to 64 levels. -- **8bpp (Indexed)**: Restricts the entire canvas to a 256-color palette. -- **Live Mode Switching**: Instantly convert existing artwork between bit-depths using GPU-accelerated quantization shaders. +# πŸš€ Key Features -### 2. GBA & Retro Export Studio +## 1. Active Canvas-Wide Color Modes +Unlike standard editors that operate in a 24-bit space, this app allows you to lock the entire drawing experience to specific hardware limits: +* **Active Quantization**: Every stroke you draw is automatically converted to the nearest valid color in your selected mode. +* **15bpp (RGB555)**: Constrains R, G, and B to 32 levels each (GBA native). +* **16bpp (RGB565)**: Constrains R and B to 32 levels and G to 64 levels. +* **8bpp (Indexed)**: Restricts the entire canvas to a 256-color palette. +* **Live Mode Switching**: Instantly convert existing artwork between bit-depths using GPU-accelerated quantization shaders. +## 2. GBA & Retro Export Studio A specialized workflow for generating game-ready assets: +* **Palette Index Reordering**: Drag-and-drop palette swatches to ensure specific colors (like transparency) are assigned to the correct indices (e.g., Slot 0). +* **Automated Sprite Splitting**: Automatically detects and splits 64x128 or 128x64 canvases into separate 64x64 files for "Front/Back" game sprites. +* **JASC-PAL Support**: Full import/export support for `.pal` files used in game decompilation projects and map editors like Porymap. +* **Hardware Preview**: Preview exactly how your image will look on 15-bit hardware before exporting. + +## 3. Image Adjustments +* **Precision Hue/Saturation**: A channel-based HSL adjustment tool (Master, R, Y, G, C, B, M) with a Split View slider to compare changes in real-time. +* **Decrease Color Depth**: Advanced quantization menu featuring Floyd-Steinberg dithering, OKLab color space accuracy, and seeded RNG for repeatable noise patterns. +* **Smart Edge Cleaner**: A GPU-accelerated filter designed to remove "stray" pixels from edges while protecting user-defined primary colors. + +## 4. Advanced Selection Engine +* **Magic Wand Tool**: Features a distance-based tolerance slider. Drag away from your click point to live-expand the selection. +* **Boolean Operations**: Shift (Add), Ctrl (Subtract), and Alt (Intersect) modifiers for all selection tools. +* **Lasso & Polyline Select**: Free-form and point-to-point selection paths for non-rectangular objects. +* **Transparent Selection**: Keyed transparency for floating selections and pasted content. + +## 5. Power-User Workflow +* **Custom Hotkeys**: Fully rebindable keyboard shortcuts for every tool and action. +* **Tiled Mode**: Live tiling for seamless pattern design. Draw in the center tile and see your strokes replicated across a 3Γ—3 grid. +* **Free Canvas Mode**: Toggle between an "Anchored" view and a "Free" floating canvas that can be moved and manipulated within the viewport. +* **Hover Preview**: A dedicated 20x magnification window showing the exact pixel grid under your cursor. -- **Palette Index Reordering**: Drag-and-drop palette swatches to ensure specific colors (like transparency) are assigned to the correct indices (e.g., Slot 0). -- **Automated Sprite Splitting**: Automatically detects and splits 64x128 or 128x64 canvases into separate 64x64 files for "Front/Back" game sprites. -- **JASC-PAL Support**: Full import/export support for .pal files used in game decompilation projects and map editors like Porymap. -- **Hardware Preview**: Preview exactly how your image will look on 15-bit hardware before exporting. - -### 3. Professional Image Adjustments - -- **Precision Hue/Saturation**: A channel-based HSL adjustment tool (Master, R, Y, G, C, B, M) with a Split View slider to compare changes in real-time. -- **Decrease Color Depth**: Advanced quantization menu featuring Floyd-Steinberg dithering, OKLab color space accuracy, and seeded RNG for repeatable noise patterns. -- **Smart Edge Cleaner**: A GPU-accelerated filter designed to remove "stray" pixels from edges while protecting user-defined primary colors. - -### 4. Advanced Selection Engine - -- **Magic Wand Tool**: Features a distance-based tolerance slider. Drag away from your click point to live-expand the selection. -- **Boolean Operations**: Shift (Add), Ctrl (Subtract), and Alt (Intersect) modifiers for all selection tools. -- **Lasso & Polyline Select**: Free-form and point-to-point selection paths for non-rectangular objects. -- **Transparent Selection**: Professional-grade keyed transparency for floating selections and pasted content. - -### 5. Power-User Workflow +--- -- **Custom Hotkeys**: Fully rebindable keyboard shortcuts for every tool and action. -- **Tiled Mode**: Live tiling for seamless pattern design. Draw in the center tile and see your strokes replicated across a 3Γ—3 grid. -- **Free Canvas Mode**: Toggle between an "Anchored" view and a "Free" floating canvas that can be moved and manipulated within the viewport. -- **Hover Preview**: A dedicated 20x magnification window showing the exact pixel grid under your cursor. +# πŸ›  Technical Stack -**Quick start (Windows)** -1. Install Node.js (LTS) and Rust. -2. From the project folder: - 1. `npm install` - 2. `npm run tauri dev` +* **Rendering**: Dual-layer HTML5 Canvas API with WebGL Fragment Shaders for strokes, transforms, and quantization. +* **Processing**: Web Workers for heavy lifting (K-means color clustering and HSL adjustments) to keep the UI thread responsive. +* **Architecture**: Vanilla JavaScript with a custom "modern Windows" UI component library. +* **Platform**: Optimized for standalone use or as a Tauri desktop application. -If you get stuck, read the full tutorial below. +--- -## πŸ›  Technical Stack +# πŸ— Architecture -- **Rendering**: Dual-layer HTML5 Canvas API with WebGL Fragment Shaders for strokes, transforms, and quantization. -- **Processing**: Web Workers for heavy lifting (K-means color clustering and HSL adjustments) to keep the UI thread responsive. -- **Architecture**: Vanilla JavaScript with a custom "Win32-style" UI component library. -- **Platform**: Optimized for standalone use or as a Tauri desktop application. +**Frontend:** +* Source files live in `src/` +* Dev server is a small Node HTTP server at `http://localhost:1420` (`scripts/dev.js`) +* Build step copies `src/` to `dist/` (`scripts/build.js`) -## How this project is wired -Frontend: -- Source files live in `src/` -- Dev server is a small Node HTTP server at `http://localhost:1420` (`scripts/dev.js`) -- Build step copies `src/` to `dist/` (`scripts/build.js`) +**Tauri:** +* Config is in `src-tauri/tauri.conf.json` +* Tauri uses the dev server in development (`beforeDevCommand`: `npm run dev`) +* Tauri uses `dist/` for production builds (`beforeBuildCommand`: `npm run build`) -Tauri: -- Config is in `src-tauri/tauri.conf.json` -- Tauri uses the dev server in development (`beforeDevCommand`: `npm run dev`) -- Tauri uses `dist/` for production builds (`beforeBuildCommand`: `npm run build`) +--- -# CDPaint - Build & Run Guide +# πŸ’» Build & Run Guide -Welcome! This guide is written specifically for complete beginners. You do not need to be a programmer or have any special coding software installed to build this desktop app. Just follow these steps one by one. +Welcome! This guide is written specifically for complete beginners. You do not need to be a programmer or have any special coding software installed to build this app. +Simply follow these instructions one by one. ## 1. Install Prerequisites (One-Time Setup) You only need to install three standard tools to make this work. Download them using the official links below: -* **Node.js** (Runs the visual interface) - * **Download:** Get the **LTS** version from [nodejs.org](https://nodejs.org/en/download) - * **Setup:** Click through the standard installation, accepting all the defaults. -* **Rust** (Runs the app's background engine) - * **Download:** Get the installer from [rust-lang.org](https://www.rust-lang.org/tools/install) - * **Setup:** When the black window pops up during installation, simply press `1` and hit **Enter** to accept the default installation. -* **Visual Studio Build Tools** (Helps Windows read the code) - * **Download:** Get it from [microsoft.com](https://visualstudio.microsoft.com/visual-cpp-build-tools/) - * **Setup:** During installation, you will see a screen with checkboxes. You **must** check the box that says **Desktop development with C++**. +1. **Node.js** (Runs the visual interface) + * **Download:** Get the **LTS** version from [nodejs.org](https://nodejs.org/en/download) + * **Setup:** Click through the standard installation, accepting all the defaults. +2. **Rust** (Runs the app's background engine) + * **Download:** Get the installer from [rust-lang.org](https://www.rust-lang.org/tools/install) + * **Setup:** When the black window pops up during installation, simply press `1` and hit **Enter** to accept the default installation. +3. **Visual Studio Build Tools** (Helps Windows read the code) + * **Download:** Get it from [visualstudio.microsoft.com](https://visualstudio.microsoft.com/visual-cpp-build-tools/) + * **Setup:** During installation, you will see a screen with checkboxes. You **must** check the box that says **Desktop development with C++**. > **IMPORTANT:** Once all three are installed, **restart your computer** so Windows registers the new tools. ---- - -## 2. Open the Command Prompt in Your Folder - -Instead of using complex coding software, use this standard Windows shortcut to open your command prompt exactly where it needs to be: +## 2. Open Command Prompt (The Easy Way) -1. Open your **CDPaint** folder (e.g., `C:\Users\frenc\Desktop\CDPaint`) normally using Windows File Explorer. -2. Click directly on the long address bar at the very top of the folder window. -3. Delete the text in the bar, type `cmd`, and press **Enter**. -4. A black Command Prompt window will pop up, already locked onto your project folder. Keep it open! - ---- +Instead of navigating through complex computer menus, use this standard Windows shortcut to open your command prompt exactly where it needs to be: -## 3. Install the App Files (One-Time Setup) +1. Open your **CDPaint** folder wherever you saved or extracted it (for example, in your Downloads or Documents folder) using the standard Windows File Explorer. +2. Click directly on the long address bar at the very top of the folder window (the bar that shows your current folder path). +3. Delete whatever text is there, type `cmd`, and press **Enter**. +4. A black Command Prompt window will pop up. Because you opened it this way, it automatically knows to look inside your CDPaint folder. Keep this window open! -We need to download the specific files your app needs to run. +## 3. Install Dependencies -In the black Command Prompt window you just opened, type the following command exactly as written and press **Enter**: +Now we just need to tell the computer to download the final pieces the app needs to run. In that black window you just opened, simply type the following and press **Enter**: `npm install` -*Note: Wait for the progress bars to finish. When the text stops moving and you see a blinking cursor again, it is done.* - ---- +*Note: You will see a lot of text scrolling by and some progress bars. Don't worry, it's just doing its job! When the text stops moving and you see a blinking cursor again, it is completely done.* ## 4. Run the App (Test Mode) -To launch your app so you can see it and test it, type this command and press **Enter**: +To launch the app so you can see it and test it out, type this into the same black window and press **Enter**: `npm run tauri dev` -* **What happens:** The black window will process some text, and after a few moments, your CDPaint desktop application will automatically open! -* **To stop it:** When you are done testing, close the CDPaint window normally. Then, click on your black Command Prompt window and press `Ctrl` + `C` to safely shut down the background process. +* **What happens:** The window will process some more text, and after a few moments, your CDPaint application will automatically pop open! +* **To stop it:** Close the CDPaint window like you would close any normal app. Then, click on your black Command Prompt window and press the `Ctrl` and `C` keys on your keyboard at the same time to safely shut down the background process. ---- +## 5. Build the Final App -## 5. Build the Final App (To Share or Install) - -When you are completely finished and want to create the final, clickable application file (like an `.exe` installer) that you can share with others, use this command and press **Enter**: +When you are completely finished testing and want to create a final, clickable application file (like an `.exe` installer) that you can easily open later or share with friends, run this command: `npm run tauri:build` -* **What happens:** This process takes a few minutes. Once it finishes, open your CDPaint folder in File Explorer. You will find your final, ready-to-use application hidden inside this specific folder path: `src-tauri/target/release/bundle/` +* **What happens:** This process takes a few minutes to pack everything tightly together. Once it finishes, open your CDPaint folder in File Explorer. You will find your final, ready-to-use application hidden inside this specific folder path: `src-tauri/target/release/bundle/` --- -## Common Fixes +# πŸ”§ Troubleshooting * **"Command not found" error:** Your computer hasn't recognized the installations from Step 1. Make sure you fully restarted your computer after installing them. -* **White or Blank app window:** You likely skipped Step 3. Close the app, run `npm install` in your command prompt, and try again. -### White/blank window in dev -Check the dev server is running: -- Open `http://localhost:1420` in your browser -- If it fails, run `npm run dev` and check for errors +* **White or Blank app window:** You likely skipped Step 3. Close the app, run `npm install` in your command prompt, and try running it again. + +## White/blank window in dev +Check if the dev server is running properly: +1. Open `http://localhost:1420` in your web browser. +2. If it fails to load, manually run `npm run dev` in your terminal and check the output for any specific errors. From cb82135fadbea54618cc5bb98710bedf1581131a Mon Sep 17 00:00:00 2001 From: FrCynda Date: Fri, 20 Feb 2026 02:58:14 +0100 Subject: [PATCH 06/48] Add LICENSE file --- LICENSE | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 LICENSE diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..0c8a5cf --- /dev/null +++ b/LICENSE @@ -0,0 +1,35 @@ +MIT License + +Copyright (c) 2026 FrCynda + +β€œThis license applies solely to the functional logic, algorithms, and source code architecture of this project. NOTICE: This project contains embedded graphical data (Base64/SVG strings) which are replicas/extractions of the Microsoft Paint UI. These specific data strings are EXCLUDED from this MIT License and remain the intellectual property of Microsoft Corporation. This project is a non-commercial educational tribute.” + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +Additional Notice (Split-License Clarification) +------------------------------------------------ +For clarity and avoidance of doubt, the MIT grant above applies only to +original programming logic and project architecture authored for this repository. +Any embedded third-party visual assets, including but not limited to legacy UI +icon replicas represented as Base64/SVG strings, are excluded from the MIT +license grant and retain their respective ownership rights. + +Redistributors and forkers are solely responsible for assessing and complying +with any third-party intellectual property rights that may apply to excluded +asset data bundled in source files or build outputs. From 322875df13a1969acec20049b069d7b367b3ec7c Mon Sep 17 00:00:00 2001 From: FrCynda Date: Fri, 20 Feb 2026 06:53:32 +0100 Subject: [PATCH 07/48] Fix exporting --- npm | 0 src/index.html | 115 +++++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 103 insertions(+), 12 deletions(-) delete mode 100644 npm diff --git a/npm b/npm deleted file mode 100644 index e69de29..0000000 diff --git a/src/index.html b/src/index.html index db4eca5..fc031ce 100644 --- a/src/index.html +++ b/src/index.html @@ -2378,12 +2378,10 @@
New...
Open
Save
+
Save As...
Export...
-
Export Palette (.pal)
-
Import Palette (.pal)
-
Properties
|
@@ -14224,6 +14222,73 @@

Color

} return out; } + joinPath(base, name) { + const left = String(base || ''); + const right = String(name || ''); + if (!left) return right; + const sep = left.includes('\\') ? '\\' : '/'; + if (left.endsWith('\\') || left.endsWith('/')) return `${left}${right}`; + return `${left}${sep}${right}`; + } + toUint8Array(data) { + if (data instanceof Uint8Array) return data; + if (data instanceof ArrayBuffer) return new Uint8Array(data); + if (ArrayBuffer.isView(data)) return new Uint8Array(data.buffer, data.byteOffset, data.byteLength); + return new TextEncoder().encode(String(data || '')); + } + async saveExportFiles(files) { + if (!Array.isArray(files) || files.length === 0) return true; + const tauri = window.__TAURI__; + const hasTauriDialog = !!(tauri && tauri.dialog && typeof tauri.dialog.open === 'function'); + const hasTauriWrite = !!(tauri && tauri.fs && typeof tauri.fs.writeFile === 'function'); + if (hasTauriDialog && hasTauriWrite) { + const selected = await tauri.dialog.open({ + title: 'Choose Export Folder', + directory: true, + multiple: false + }); + if (!selected) return null; + const dir = Array.isArray(selected) ? selected[0] : selected; + for (const file of files) { + const fullPath = this.joinPath(dir, file.name); + await tauri.fs.writeFile(fullPath, this.toUint8Array(file.bytes)); + } + return true; + } + if (window.showDirectoryPicker) { + try { + const dir = await window.showDirectoryPicker({ mode: 'readwrite' }); + for (const file of files) { + const handle = await dir.getFileHandle(file.name, { create: true }); + const writable = await handle.createWritable(); + await writable.write(this.toUint8Array(file.bytes)); + await writable.close(); + } + return true; + } catch (e) { + if (e && e.name === 'AbortError') return null; + throw e; + } + } + if (files.length === 1 && window.showSaveFilePicker) { + try { + const only = files[0]; + const isPal = /\.pal$/i.test(only.name); + const types = isPal + ? [{ description: 'Palette', accept: { 'text/plain': ['.pal'] } }] + : [{ description: 'PNG Image', accept: { 'image/png': ['.png'] } }]; + const handle = await window.showSaveFilePicker({ suggestedName: only.name, types }); + const writable = await handle.createWritable(); + await writable.write(this.toUint8Array(only.bytes)); + await writable.close(); + return true; + } catch (e) { + if (e && e.name === 'AbortError') return null; + throw e; + } + } + return false; + } async doAdvancedExport() { const pkmnName = document.getElementById('export-pkmn-name').value.trim() || 'pokemon'; const usePrefix = document.getElementById('export-use-prefix').checked; @@ -14265,13 +14330,21 @@

Color

indices[i] = bestIdx; } - const downloadFile = (data, filename, isText = false) => { - const blob = new Blob([data], { type: isText ? 'text/plain' : 'image/png' }); - const link = document.createElement('a'); - link.download = filename; - link.href = URL.createObjectURL(blob); - link.click(); - setTimeout(() => URL.revokeObjectURL(link.href), 100); + const queuedFiles = []; + const queueFile = (data, filename, isText = false) => { + const bytes = isText ? new TextEncoder().encode(String(data)) : this.toUint8Array(data); + queuedFiles.push({ name: filename, bytes }); + }; + const flushDownloads = () => { + queuedFiles.forEach((file) => { + const isPal = /\.pal$/i.test(file.name); + const blob = new Blob([file.bytes], { type: isPal ? 'text/plain' : 'image/png' }); + const link = document.createElement('a'); + link.download = file.name; + link.href = URL.createObjectURL(blob); + link.click(); + setTimeout(() => URL.revokeObjectURL(link.href), 100); + }); }; const savePng = (x, y, subW, subH, filename) => { @@ -14282,7 +14355,7 @@

Color

} } const pngBytes = this.generateIndexedPNG(subW, subH, subIndices, finalPalette, 4); // Assuming 4bpp for decomps - downloadFile(pngBytes, filename); + queueFile(pngBytes, filename); }; const shouldExport = (key) => { @@ -14308,9 +14381,13 @@

Color

const c = finalPalette[i] || { r: 0, g: 0, b: 0 }; palStr += `${c.r} ${c.g} ${c.b}\r\n`; } - downloadFile(palStr, `${prefix}${isShiny ? 'shiny' : 'normal'}.pal`, true); + queueFile(palStr, `${prefix}${isShiny ? 'shiny' : 'normal'}.pal`, true); } + const saveResult = await this.saveExportFiles(queuedFiles); + if (saveResult === null) return; + if (saveResult === false) flushDownloads(); + this.closeModals(); } catch (e) { console.error("Export Error:", e); @@ -15266,6 +15343,20 @@

Color

reader.readAsText(file); } + async saveAsFile() { + const prevHandle = this.state.fileHandle; + const prevPath = this.state.filePath; + this.state.fileHandle = null; + this.state.filePath = null; + try { + await this.saveFile(); + } catch (e) { + this.state.fileHandle = prevHandle; + this.state.filePath = prevPath; + throw e; + } + } + async saveFile() { this.state.isSaving = true; this.updateBusyIndicator(); From 5535cc4a2c7bf316c0840e82251d69102676a995 Mon Sep 17 00:00:00 2001 From: FrCynda Date: Tue, 24 Feb 2026 03:46:21 +0100 Subject: [PATCH 08/48] Fix bugs --- package-lock.json | 228 +------- src-tauri/Cargo.toml | 1 - src-tauri/capabilities/default.json | 13 +- src-tauri/src/lib.rs | 100 +++- src-tauri/tauri.conf.json | 2 +- src/index.html | 813 ++++++++++++++++++++++++---- 6 files changed, 794 insertions(+), 363 deletions(-) diff --git a/package-lock.json b/package-lock.json index 96e98db..d8934ed 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,232 +1,12 @@ { - "name": "cdpaint", - "version": "0.1.0", + "name": "CDPaint", + "version": "1.0.0", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "cdpaint", - "version": "0.1.0", - "devDependencies": { - "@tauri-apps/cli": "^2" - } - }, - "node_modules/@tauri-apps/cli": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli/-/cli-2.10.0.tgz", - "integrity": "sha512-ZwT0T+7bw4+DPCSWzmviwq5XbXlM0cNoleDKOYPFYqcZqeKY31KlpoMW/MOON/tOFBPgi31a2v3w9gliqwL2+Q==", - "dev": true, - "license": "Apache-2.0 OR MIT", - "bin": { - "tauri": "tauri.js" - }, - "engines": { - "node": ">= 10" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/tauri" - }, - "optionalDependencies": { - "@tauri-apps/cli-darwin-arm64": "2.10.0", - "@tauri-apps/cli-darwin-x64": "2.10.0", - "@tauri-apps/cli-linux-arm-gnueabihf": "2.10.0", - "@tauri-apps/cli-linux-arm64-gnu": "2.10.0", - "@tauri-apps/cli-linux-arm64-musl": "2.10.0", - "@tauri-apps/cli-linux-riscv64-gnu": "2.10.0", - "@tauri-apps/cli-linux-x64-gnu": "2.10.0", - "@tauri-apps/cli-linux-x64-musl": "2.10.0", - "@tauri-apps/cli-win32-arm64-msvc": "2.10.0", - "@tauri-apps/cli-win32-ia32-msvc": "2.10.0", - "@tauri-apps/cli-win32-x64-msvc": "2.10.0" - } - }, - "node_modules/@tauri-apps/cli-darwin-arm64": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-darwin-arm64/-/cli-darwin-arm64-2.10.0.tgz", - "integrity": "sha512-avqHD4HRjrMamE/7R/kzJPcAJnZs0IIS+1nkDP5b+TNBn3py7N2aIo9LIpy+VQq0AkN8G5dDpZtOOBkmWt/zjA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "Apache-2.0 OR MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@tauri-apps/cli-darwin-x64": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-darwin-x64/-/cli-darwin-x64-2.10.0.tgz", - "integrity": "sha512-keDmlvJRStzVFjZTd0xYkBONLtgBC9eMTpmXnBXzsHuawV2q9PvDo2x6D5mhuoMVrJ9QWjgaPKBBCFks4dK71Q==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "Apache-2.0 OR MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@tauri-apps/cli-linux-arm-gnueabihf": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm-gnueabihf/-/cli-linux-arm-gnueabihf-2.10.0.tgz", - "integrity": "sha512-e5u0VfLZsMAC9iHaOEANumgl6lfnJx0Dtjkd8IJpysZ8jp0tJ6wrIkto2OzQgzcYyRCKgX72aKE0PFgZputA8g==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "Apache-2.0 OR MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@tauri-apps/cli-linux-arm64-gnu": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm64-gnu/-/cli-linux-arm64-gnu-2.10.0.tgz", - "integrity": "sha512-YrYYk2dfmBs5m+OIMCrb+JH/oo+4FtlpcrTCgiFYc7vcs6m3QDd1TTyWu0u01ewsCtK2kOdluhr/zKku+KP7HA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "Apache-2.0 OR MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@tauri-apps/cli-linux-arm64-musl": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm64-musl/-/cli-linux-arm64-musl-2.10.0.tgz", - "integrity": "sha512-GUoPdVJmrJRIXFfW3Rkt+eGK9ygOdyISACZfC/bCSfOnGt8kNdQIQr5WRH9QUaTVFIwxMlQyV3m+yXYP+xhSVA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "Apache-2.0 OR MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@tauri-apps/cli-linux-riscv64-gnu": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-riscv64-gnu/-/cli-linux-riscv64-gnu-2.10.0.tgz", - "integrity": "sha512-JO7s3TlSxshwsoKNCDkyvsx5gw2QAs/Y2GbR5UE2d5kkU138ATKoPOtxn8G1fFT1aDW4LH0rYAAfBpGkDyJJnw==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "Apache-2.0 OR MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@tauri-apps/cli-linux-x64-gnu": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-x64-gnu/-/cli-linux-x64-gnu-2.10.0.tgz", - "integrity": "sha512-Uvh4SUUp4A6DVRSMWjelww0GnZI3PlVy7VS+DRF5napKuIehVjGl9XD0uKoCoxwAQBLctvipyEK+pDXpJeoHng==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "Apache-2.0 OR MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@tauri-apps/cli-linux-x64-musl": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-x64-musl/-/cli-linux-x64-musl-2.10.0.tgz", - "integrity": "sha512-AP0KRK6bJuTpQ8kMNWvhIpKUkQJfcPFeba7QshOQZjJ8wOS6emwTN4K5g/d3AbCMo0RRdnZWwu67MlmtJyxC1Q==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "Apache-2.0 OR MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@tauri-apps/cli-win32-arm64-msvc": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-arm64-msvc/-/cli-win32-arm64-msvc-2.10.0.tgz", - "integrity": "sha512-97DXVU3dJystrq7W41IX+82JEorLNY+3+ECYxvXWqkq7DBN6FsA08x/EFGE8N/b0LTOui9X2dvpGGoeZKKV08g==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "Apache-2.0 OR MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@tauri-apps/cli-win32-ia32-msvc": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-ia32-msvc/-/cli-win32-ia32-msvc-2.10.0.tgz", - "integrity": "sha512-EHyQ1iwrWy1CwMalEm9z2a6L5isQ121pe7FcA2xe4VWMJp+GHSDDGvbTv/OPdkt2Lyr7DAZBpZHM6nvlHXEc4A==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "Apache-2.0 OR MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@tauri-apps/cli-win32-x64-msvc": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-x64-msvc/-/cli-win32-x64-msvc-2.10.0.tgz", - "integrity": "sha512-NTpyQxkpzGmU6ceWBTY2xRIEaS0ZLbVx1HE1zTA3TY/pV3+cPoPPOs+7YScr4IMzXMtOw7tLw5LEXo5oIG3qaQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "Apache-2.0 OR MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } + "name": "CDPaint", + "version": "1.0.0" } } } diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index 8725ec0..7b6e83c 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -24,4 +24,3 @@ tauri-plugin-dialog = "2" serde = { version = "1", features = ["derive"] } serde_json = "1" tauri-plugin-single-instance = "2.4.0" -tauri-plugin-fs = "2.4.5" diff --git a/src-tauri/capabilities/default.json b/src-tauri/capabilities/default.json index 3463a6e..3422eef 100644 --- a/src-tauri/capabilities/default.json +++ b/src-tauri/capabilities/default.json @@ -12,17 +12,6 @@ "core:window:allow-toggle-maximize", "core:window:allow-close", "core:window:allow-start-dragging", - "core:window:allow-set-resizable", - "fs:allow-read", - "fs:allow-read-dir", - "fs:allow-read-file", - "fs:allow-write", - "fs:allow-write-file", - "fs:allow-write-text-file", - "fs:allow-create", - { - "identifier": "fs:scope", - "allow": ["**"] - } + "core:window:allow-set-resizable" ] } diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index 13f3af6..3be4bf0 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -1,7 +1,7 @@ // Learn more about Tauri commands at https://tauri.app/develop/calling-rust/ use std::collections::HashMap; use std::sync::atomic::{AtomicU64, Ordering}; -use std::path::Path; +use std::path::{Path, PathBuf}; use std::sync::Mutex; use std::thread; use std::time::Duration; @@ -31,7 +31,7 @@ where } candidates.push(s); } - // Prefer existing image files. + // Accept only existing image files passed on launch. for s in &candidates { if is_current_exe(s) { continue; @@ -41,28 +41,6 @@ where return Some(normalize_candidate(s)); } } - // Then any existing non-exe file. - for s in &candidates { - if is_current_exe(s) { - continue; - } - let p = Path::new(s); - if p.is_file() { - let ext = p.extension().and_then(|e| e.to_str()).unwrap_or("").to_ascii_lowercase(); - if ext != "exe" { - return Some(normalize_candidate(s)); - } - } - } - // Fallback: if it looks like an image path, accept it even if it doesn't exist yet. - for s in &candidates { - if is_current_exe(s) { - continue; - } - if is_image_path(s) { - return Some(s.to_string()); - } - } None } @@ -88,8 +66,68 @@ fn get_pending_file(window: tauri::Window, state: tauri::State<'_, PendingFiles> fn is_image_path(path: &str) -> bool { let p = Path::new(path); - let ext = p.extension().and_then(|e| e.to_str()).unwrap_or("").to_ascii_lowercase(); - matches!(ext.as_str(), "png" | "jpg" | "jpeg" | "bmp" | "gif" | "webp") + is_image_extension(p.extension().and_then(|e| e.to_str())) +} + +fn is_image_extension(ext: Option<&str>) -> bool { + matches!( + ext.unwrap_or("").to_ascii_lowercase().as_str(), + "png" | "jpg" | "jpeg" | "bmp" | "gif" | "webp" + ) +} + +fn normalize_device_path(path: &str) -> String { + let mut s = path.trim().to_string(); + if s.starts_with(r"\\?\UNC\") { + s = format!(r"\\{}", &s[r"\\?\UNC\".len()..]); + } else if s.starts_with(r"\\?\") { + s = s[r"\\?\".len()..].to_string(); + } + s +} + +fn normalize_to_absolute_path(path: &str) -> Result { + let normalized = normalize_device_path(path); + let p = PathBuf::from(normalized); + if !p.is_absolute() { + return Err("path must be absolute".into()); + } + Ok(p) +} + +fn is_allowed_write_extension(ext: Option<&str>) -> bool { + matches!( + ext.unwrap_or("").to_ascii_lowercase().as_str(), + "png" | "jpg" | "jpeg" | "bmp" | "gif" | "webp" | "pal" + ) +} + +#[tauri::command] +fn read_image_file(path: String) -> Result, String> { + let p = normalize_to_absolute_path(&path)?; + if !p.is_file() { + return Err("path is not an existing file".into()); + } + if !is_image_extension(p.extension().and_then(|e| e.to_str())) { + return Err("only image files can be read".into()); + } + std::fs::read(&p).map_err(|e| format!("read failed: {}", e)) +} + +#[tauri::command] +fn write_allowed_file(path: String, data: Vec) -> Result<(), String> { + let p = normalize_to_absolute_path(&path)?; + if !is_allowed_write_extension(p.extension().and_then(|e| e.to_str())) { + return Err("file extension not allowed".into()); + } + if let Some(parent) = p.parent() { + if !parent.exists() { + return Err("target directory does not exist".into()); + } + } else { + return Err("invalid target path".into()); + } + std::fs::write(&p, data).map_err(|e| format!("write failed: {}", e)) } fn normalize_candidate(path: &str) -> String { @@ -133,7 +171,7 @@ where if is_current_exe(&s) { continue; } - if is_image_path(&s) { + if is_image_path(&s) && Path::new(&s).is_file() { out.push(normalize_candidate(&s)); } } @@ -147,7 +185,6 @@ pub fn run() { .manage(PendingFiles(Mutex::new(HashMap::new()))) .plugin(tauri_plugin_opener::init()) .plugin(tauri_plugin_dialog::init()) - .plugin(tauri_plugin_fs::init()) .plugin(tauri_plugin_single_instance::init(|app, argv, _cwd| { let paths = collect_image_paths(argv.into_iter()); if paths.is_empty() { @@ -180,7 +217,12 @@ pub fn run() { } }); })) - .invoke_handler(tauri::generate_handler![greet, get_pending_file]) + .invoke_handler(tauri::generate_handler![ + greet, + get_pending_file, + read_image_file, + write_allowed_file + ]) .setup(|app| { let args: Vec = std::env::args().collect(); if let Some(path) = first_file_path(args.into_iter().skip(1)) { diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index f86ba5a..c23fc92 100644 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -10,7 +10,7 @@ "frontendDist": "../dist" }, "app": { - "withGlobalTauri": true, + "withGlobalTauri": false, "windows": [ { "decorations": false, diff --git a/src/index.html b/src/index.html index fc031ce..c4f46c3 100644 --- a/src/index.html +++ b/src/index.html @@ -213,9 +213,9 @@ .tab.file { background: var(--win-blue); color: white; } - .ribbon { height: 100px; background: var(--bg-ribbon); border-bottom: 1px solid var(--border-ribbon); display: flex; padding: 5px; gap: 5px; position: relative; z-index: 100; overflow-x: auto; } + .ribbon { height: 100px; min-height: 100px; max-height: 100px; background: var(--bg-ribbon); border-bottom: 1px solid var(--border-ribbon); display: flex; padding: 5px; gap: 5px; position: relative; z-index: 100; overflow: hidden; } - .section { display: flex; flex-direction: column; align-items: center; justify-content: space-between; border-right: 1px solid #e0e0e0; padding: 0 8px; height: 100%; min-width: max-content; } + .section { display: flex; flex-direction: column; align-items: center; justify-content: space-between; border-right: 1px solid #e0e0e0; padding: 0 8px; height: 100%; min-width: max-content; flex-shrink: 0; } .colors-section { align-items: flex-start; } .ribbon-draggable { transition: transform 160ms ease; } .ribbon-drag-handle { cursor: grab; } @@ -467,8 +467,9 @@ .threshold-row { width: 120px; } #wand-threshold { width: 120px; } .threshold-values { width: 120px; display: flex; justify-content: space-between; font-size: 10px; color: #444; } - .wand-icon { display: none; } + .wand-icon { display: none; font-size: 16px; line-height: 1; width: 16px; text-align: center; transform: translateX(-3px); } .wand-icon.show { display: inline-block; } + .wand-menu-icon { width: 14px; display: inline-flex; justify-content: center; align-items: center; font-size: 13px; line-height: 1; } .ribbon-toggle { display: flex; align-items: center; gap: 6px; font-size: 12px; padding: 0 4px; } .ribbon-toggle input { margin: 0; width: 14px; height: 14px; accent-color: #0078d7; } .toggle-btn { @@ -1700,6 +1701,17 @@ align-items: center; gap: 4px; } + #modal-colors .select-row { + display: flex; + align-items: center; + gap: 6px; + min-height: 22px; + } + #modal-colors .select-hint { + font-size: 11px; + color: #555; + line-height: 1.2; + } #modal-colors .preset-row { display: flex; align-items: center; @@ -1799,10 +1811,32 @@ padding: 0 6px; font-size: 10px; } + #modal-colors .theme-select-btn.is-on { + background-color: #0078d7; + border-color: #005a9e; + color: #fff; + } + #modal-colors .color-item.is-picked { + background: #eef6ff; + border: 1px solid #9fc4ea; + border-radius: 2px; + } .color-preview-highlight { outline: 2px dashed #0078d7 !important; outline-offset: 2px; } + body.theme-select-mode #title-bar, + body.theme-select-mode .tab-row, + body.theme-select-mode #ribbon, + body.theme-select-mode #ribbon-view, + body.theme-select-mode #ribbon-debug, + body.theme-select-mode #canvas-stage { + cursor: crosshair; + } + body.theme-select-mode .theme-select-candidate { + outline: 2px dashed #0078d7 !important; + outline-offset: 2px; + } /* Handles Container */ #selection-controls { position: absolute; z-index: 1000; pointer-events: none; display: none; } @@ -1891,6 +1925,22 @@ } #status-bar { height: 24px; background: #f0f0f0; border-top: 1px solid #ccc; display: flex; align-items: center; padding: 0 10px; gap: 15px; font-size: 11px; z-index: 100; } + #status-primary { display: flex; align-items: center; gap: 0; } + .status-segment { + width: 155px; + min-width: 155px; + max-width: 155px; + height: 18px; + padding: 0 6px; + display: flex; + align-items: center; + box-sizing: border-box; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + } + .status-segment + .status-segment { border-left: 1px solid #c8c8c8; } + #status-right { display: flex; align-items: center; gap: 15px; } #status-reminder { color: #a40000; font-weight: 600; } #grid-overlay { position: fixed; @@ -2053,8 +2103,8 @@ } #close-confirm-modal .body-text { margin: 0; - font-size: 17px; - color: #1e5aa8; + font-size: 16px; + color: #0057d8; font-weight: normal; } #close-confirm-modal .separator { @@ -2063,25 +2113,38 @@ } #close-confirm-modal .button-area { background: #eeeeee; - padding: 10px 12px; + height: 40px; + box-sizing: border-box; + padding: 0 11px 0 12px; + display: flex; + align-items: center; + justify-content: flex-end; } #close-confirm-modal .btn-row { display: flex; justify-content: flex-end; gap: 8px; margin-top: 0; } #close-confirm-modal .btn-row button { - padding: 3px 18px; + height: 21px; + padding: 0 18px; + box-sizing: border-box; border: 1px solid #b0b0b0; background: #ffffff; cursor: pointer; border-radius: 4px; color: #000; - font-size: 11px; + font-size: 12px; + font-family: "Segoe UI", Tahoma, sans-serif; + white-space: nowrap; } - #close-confirm-modal .btn-row button:hover { background: #e6e6e6; } - #close-confirm-modal .btn-primary { - background: #0078d7; - color: #fff; - border: 1px solid #005a9e; + #close-confirm-modal .btn-row button:nth-child(1) { width: 70px; min-width: 70px; max-width: 70px; } + #close-confirm-modal .btn-row button:nth-child(2) { width: 90px; min-width: 90px; max-width: 90px; text-align: center; padding-left: 16px; padding-right: 20px; } + #close-confirm-modal .btn-row button:nth-child(3) { width: 70px; min-width: 70px; max-width: 70px; } + #close-confirm-modal .btn-row button:hover:not(:disabled) { + background-color: #e5f1fb; + border-color: #0078d7; + } + #close-confirm-modal .btn-row button:focus { + outline: 1px solid #2b88d8; + outline-offset: -1px; } - #close-confirm-modal .btn-primary:hover { background: #0063b1; } #modal-info { position: fixed; @@ -2330,10 +2393,7 @@ z-index: 10; } - - - - + @@ -2381,6 +2441,8 @@
Save As...
Export...
+
Import Palette...
+
Export Palette...
Properties
@@ -2478,8 +2540,8 @@
- - + +
@@ -2864,12 +2926,12 @@ @@ -2977,14 +3039,17 @@
-
0, 0px
-
-
800 x 600px
+
+
0, 0px
+
-
+
800 x 600px
+
+
+
Colors: 0
+
-
-
100%
@@ -3176,6 +3241,10 @@
+
+ + Turn this on, then click a UI element to edit its color token. +
+
+ +
+
+
Size
+
+ +
+
+
Threshold
+
+ +
+
+ 0 + 0 + 255 +
+
+
Wand
+
+ +
+
+
+
+
+
+ Color + 1 +
+
+
+ Color + 2 +
+
+ + +
+ + +
+
+ +
+
+
+
+
+ +
+ + + Edit + colors +
+
+
Colors
+
+
+
+ + Hue/Sat +
+
Adjustments
+
+
+
+ Shape + +
+
+ Repeat + +
+
+ Options + + +
+ +
+ Midpoint +
+ + 50% +
+ +
+
+ Gradient + + +
+
Gradient
+
+
+
+ + Info +
+
Help
+
+ + + + + + + + + + + + + + + + + + + + + + + +
+ + + + +
+
+ + + + + + + + + + + + + + + + + +
+
+
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+ + +
+
+
0, 0px
+
-
+
Rot: 0.00Β°
+
800 x 600px
+
+
+
+
Colors: 0
+ +
+
+
100%
+
+ + +
+
+
+ Save reminder +
+
+
You haven't saved your file in a while, buddy. You might want to save your progress!
+
+ You can turn this off or customize it in the Misc tab. +
+
+ + +
+
+
+ +
+
+
+ CDpaint +
+
+
+
Do you want to save changes to your file?
+
+
+
+
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/backup/backup.html b/src/backup/backup.html new file mode 100644 index 0000000..0b87c88 --- /dev/null +++ b/src/backup/backup.html @@ -0,0 +1,29525 @@ + + + + + + Paint - Professional + + + + + + + + +
+
+ + + + + + + + Untitled +
+
+ + + +
+
+ +
+
File
+
Home
+
Misc
+
Themes
+
Debug
+
+ + +
|
+ +
+
+
+ + Paste +
+
Clipboard
+
+
+
+
+
+
+ + +
+ +
+ Select + +
+
+
+ +
+
Crop
+
Resize
+ +
+ + Rotate + +
+
+
+
Image
+
+ +
+
+ + + + + + + Depth... +
+
Index
+
+ +
+
+
24bpp
+
16bpp
+
15bpp
+
8bpp
+
4bpp
+
1bpp
+
+
Color Mode
+
+ +
+
+ +
+ + +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+ +
+
+
Tools
+
+
+
+ +
+ + +
+ +
+ + +
+
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + + + + +
+ +
+
Shapes
+
+
+ +
+ + + +
+ +
+
+
Size
+
+ +
+
+
Threshold
+
+ +
+
+ 0 + 0 + 255 +
+
+
Wand
+
+ +
+
+
+
+
+
+ Color + 1 +
+
+
+ Color + 2 +
+
+ + +
+ + +
+
+ +
+
+
+
+
+ +
+ + + Edit + colors +
+
+
Colors
+
+
+
+ + Hue/Sat +
+
Adjustments
+
+
+
+ Shape + +
+
+ Repeat + +
+
+ Options + + +
+ +
+ Midpoint +
+ + 50% +
+ +
+
+ Gradient + + +
+
Gradient
+
+
+
+ + Info +
+
Help
+
+ + + +
+ + + + + + + + + + + + + + + + + + + +
+ + + + +
+
+ + + + + + + + + + + + + + + + + +
+
+
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+ + +
+
+
0, 0px
+
-
+
Rot: 0.00Β°
+
800 x 600px
+
+
+
+
Colors: 0
+ +
+
+
100%
+
+ + +
+
+
+ Save reminder +
+
+
You haven't saved your file in a while, buddy. You might want to save your progress!
+
+ You can turn this off or customize it in the Misc tab. +
+
+ + +
+
+
+ +
+
+
+ CDpaint +
+
+
+
Do you want to save changes to your file?
+
+
+
+
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/brush-packs/revoy-extras/tips/2018-10_square-block_001.png b/src/brush-packs/revoy-extras/tips/2018-10_square-block_001.png new file mode 100644 index 0000000000000000000000000000000000000000..89b9e7b1d63260d4d9a14f75886655e11bfaf131 GIT binary patch literal 43495 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 literal 0 HcmV?d00001 diff --git a/src/brush-packs/revoy-extras/tips/flat-tip-dirty.png b/src/brush-packs/revoy-extras/tips/flat-tip-dirty.png new file mode 100644 index 0000000000000000000000000000000000000000..869e7fe6752c9c14f324a882a4eed8be9316fa28 GIT binary patch literal 3278 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 M07*qoM6N<$f^CLd;{X5v literal 0 HcmV?d00001 diff --git a/src/brush-packs/revoy-extras/tips/stars.png b/src/brush-packs/revoy-extras/tips/stars.png new file mode 100644 index 0000000000000000000000000000000000000000..c20d0a1478c0d2001761a9251597ee2f797ec30d GIT binary patch literal 1744 zcmY+EdoX=DKJRyqkM~J9Oa}&m zK;VFfJ8AcA*quftg3n-4WK6aq=%eP8V8+3)k|)vx>rqeMl5yYA=y z@ewtcY!WWGI&7Tiu{Z#smRwo(JYj8@529D20<8D7@u3sK_@x#PT zTa}%Ag04t2=jvMycW#!sRiWy+hh9v_tfZ4lS7zK2I6~;)sj8#0ElGUe+@-=Fqr>(i zy2>dv`J!WA=azZvnVeiB5vYOz8KWrD{OEnP#KPVa3IN)`^#n8u)8~@M4+-m$3E@)? zLu;7Sio1_%S?Px#`8H~L2mIGYeB_jJfW-#$GLJWtg?B84;Fv)hF~~POIkC;yHZFlL zwL+xIAI&T48Lq6u-yI7KoPj9CeG+~H>m`6bYfrCH^lJgHA!oF#;VF(#X@c_(e56$v z{xY?&6H`gKueva=B zZV~=OZWQ)B3z<4MKgRTT?o-{8H!yW36(Rqo2W)TuNHlbB-zCpUUtfPcV>5g(+Sfc9 z?TE*3EV!bte!Mi8|8DwfuVh&XcKDw^&I^Uwi@_=0x%$geX&@Gh4an@PcIpUu^1NUP z(Ja~CepK)_zN)sVsfmFUdFc3B8&Y-6%*mxyr?xnJ*3Af=hY=W!xwA?{($?4eG;1&BJXOZiBM+$% zNyE@YqlTd@@X6}Cce4dpN{*F9{tI*1#cc4&K?#O6!?ts|r1qE2|EbL-)PFCRalG47 zf9+}IjY`FR!$It#F9Z#9l{XBG!$tDgT1p)wOg@HKVc0&f{)=vo&Q3w)=J?CXgwO-H zBI{U5gtbmw$#|t07w5KMTH2ep=E->`~r1W@Nkb z_L|Z=XEvZ7DwpALL%p0>ST_YMob|HnKbYoKV6sikrDHT!?=!2a#D?P&6ZhKM+HhxR zP!-Jl5~6r@dAT{Zip%9TuCFK4C~b^1t(aCSTebRE4;XUF&MOmxN_vR^P>fH|P@rdG zejmY89IpY&%I@=30eX0X5=twGts5R#0TN4&!!4^yTswk85`0p+9HYqn&n4T zyy?x&&A8R>1pm{+r?ZPGL^Z}UV=P=@`s_62qH9$>csc1I9|bHMS^Xh<{kq19#2zQa zCMLG(sp|PYpfBzRa=#jUqfHY`PI8#)Hg1!dnVC|DI+ijZYh{zOUK zmnc{*m=hKATjIhUu$6oP75gQJX>V_zET6v=uV;&ezEwd{!wO2Rv-0ysqjdnBi!$x0 z*HEA}sOqvB$i&Ia<6TEsES8if5{d9F%7BXJChC0MqZFiO!kOV?UZ`gS>mN+uYtMYQmA+jm*`Jyh9gEf4CplLv5jaq-eW?q+$ z)5&k_?Ccba#f?sdQT?w+sklWFwb@s+iz$|O-)(H%TUc0# zKcwT!QTQ2s`#6dcJ9l%+k2k3T;|^QY8UHqGYHJ)773|HZwef8|2DidbfO#N>)}`6; z9~tW)AOvtBrT>e2rIQYRIARdxbcj2~l+LpFkln{X6?cU@XLi-b3&lVd1 literal 0 HcmV?d00001 diff --git a/src/css/styles.css b/src/css/styles.css new file mode 100644 index 0000000..07c6509 --- /dev/null +++ b/src/css/styles.css @@ -0,0 +1,5160 @@ + /* --- CSS STYLES --- */ + /* CSS custom properties for the entire app. Centralised here so themes only need to override this block. */ + :root { + --bg-ribbon: #f5f6f7; + --border-ribbon: #dadbdc; + --win-blue: #0078d7; + --app-text-color: #111111; + --app-bg: #ffffff; + --titlebar-bg: #ffffff; + --titlebar-action-icon: #8a8f98; + --titlebar-save-icon: #7b3ff2; + --titlebar-save-pixel-primary: #9c75ca; + --titlebar-save-pixel-shadow: #81679b; + --titlebar-save-pixel-sheet: #e6eaec; + --titlebar-save-pixel-sheet-shadow: #cccad5; + --titlebar-save-pixel-white: #ffffff; + --titlebar-save-pixel-accent: #835ac7; + --titlebar-save-pixel-accent-soft: #a191b3; + --titlebar-save-pixel-mid: #98999c; + --titlebar-undo-redo-enabled: #1b6fe5; + --titlebar-action-outline-hover: #9fc4ea; + --titlebar-action-hover-bg: #e5e5e5; + --titlebar-separator: #c8c8c8; + --titlebar-filename: #111111; + --titlebar-control-icon: #111111; + --titlebar-control-close-hover: #e81123; + --titlebar-control-close-hover-icon: #ffffff; + --tab-row-bg: #ffffff; + --tab-file-text: #ffffff; + --section-divider: #e0e0e0; + --section-title-color: #666666; + --btn-hover-bg: #eaf4ff; + --btn-hover-border: #9fc4ea; + --btn-hover-shadow: rgba(0,120,215,0.15); + --btn-active-bg: #cce8ff; + --btn-active-border: #66a7e8; + --btn-active-shadow: rgba(0,120,215,0.3); + --dropdown-bg: #ffffff; + --dropdown-border: #a0a0a0; + --dropdown-shadow: rgba(0,0,0,0.2); + --dropdown-item-hover-bg: #e8e8e8; + --dropdown-arrow-color: #666666; + --dropdown-separator: #e0e0e0; + --btn-small-bg: #f9f9f9; + --btn-small-border: #cccccc; + --threshold-label-color: #666666; + --threshold-values-color: #444444; + --toggle-icon-color: #0078d7; + --toggle-icon-color-dark: #ffffff; + --toggle-status-color: #666666; + --hotkeys-icon-color: #0078d7; + --hotkeys-icon-color-dark: #ffffff; + --anchor-toggle-icon-color: #0078d7; + --anchor-toggle-icon-color-dark: #ffffff; + --theme-mode-toggle-icon-color: #0078d7; + --theme-mode-toggle-icon-color-dark: #ffffff; + --select-menu-header-color: #5f5f5f; + --select-menu-header-bg: #f2f2f2; + --select-menu-icon-all-fill: #e6f0fa; + --select-menu-icon-all-fill-disabled: #f0f0f0; + --select-menu-icon-disabled-stroke: #a0a0a0; + --select-menu-icon-delete-stroke: #c00000; + --theme-colors-window-bg: #ffffff; + --theme-colors-titlebar-bg-start: #fbfbfb; + --theme-colors-titlebar-bg-end: #f1f1f1; + --theme-colors-titlebar-border: #d8d8d8; + --theme-colors-top-note-color: #5a5a5a; + --theme-colors-result-count-color: #666666; + --theme-colors-list-bg: #ffffff; + --theme-colors-editor-panel-bg-start: #fcfcfc; + --theme-colors-editor-panel-bg-end: #f5f5f5; + --theme-colors-editor-panel-border: #d3d3d3; + --theme-colors-editor-title-color: #444444; + --theme-colors-editor-key-color: #333333; + --theme-colors-editor-input-bg: #ffffff; + --theme-colors-editor-input-border: #bdbdbd; + --theme-colors-editor-swatch-border: #777777; + --theme-colors-editor-hint-color: #666666; + --theme-colors-mini-toggle-color: #444444; + --palette-mini-swatch-border: #a0a0a0; + --palette-mini-swatch-inner: #ffffff; + --palette-mini-swatch-hover-border: #0078d7; + --palette-mini-swatch-hover-inner: #bcdcff; + --view-center-icon-color: #0078d7; + --view-edgeclean-icon-color: #007bff; + --view-theme-icon-color: #0078d7; + --select-icon-free-color: #1a6aab; + --select-icon-poly-main-color: #1a6aab; + --select-icon-poly-accent-color: #4e8aba; + --bg-hover: #cce8ff; + --border-hover: #99d1ff; + --bg-selected: #e1f0ff; + --border-selected: #7da2ce; + --bg-canvas: #cce3f3; + --shape-icon-color: #000000; + --zoom: 1; + --zoom-inv: 1; + --sel-rotate-icon-color: #ffffff; + } + + /* Global box-model reset and font defaults. Disabling user-select everywhere prevents text highlighting during canvas drag operations. */ + * { box-sizing: border-box; user-select: none; } + + body { + margin: 0; + height: 100vh; + display: flex; + flex-direction: column; + font-family: 'Segoe UI', sans-serif; + font-size: 12px; + overflow: hidden; + background: var(--app-bg); + color: var(--app-text-color); + } + + input { user-select: auto !important; cursor: pointer; } + input[type="checkbox"] { accent-color: var(--win-blue); } + + /* LAYOUT */ + /* Layout for the title bar, tab row, and ribbon. Heights are fixed so the canvas area can fill the remaining viewport precisely. */ + + #title-bar { height: 21px; display: flex; align-items: center; padding: 0 10px 0 10px; background: var(--titlebar-bg); z-index: 101; } + #title-bar .title-left { display: flex; align-items: center; gap: 6px; flex: 1; min-width: 0; } + #title-bar .app-icon { width: 16px; height: 16px; image-rendering: pixelated; } + #title-bar .title-action { + width: 28px; + height: 24px; + border: 0; + background: transparent; + display: inline-flex; + align-items: center; + justify-content: center; + padding: 0; + cursor: pointer; + } + #title-bar .title-action svg { + width: 13px; + height: 13px; + fill: var(--titlebar-action-icon); + stroke: none; + } + #title-bar .title-action img { + width: 13px; + height: 13px; + min-width: 13px; + min-height: 13px; + max-width: 13px; + max-height: 13px; + display: block; + image-rendering: pixelated; + } + #title-bar .title-action.icon-undo img, + #title-bar .title-action.icon-redo img { + width: 16px; + height: 16px; + min-width: 16px; + min-height: 16px; + max-width: 16px; + max-height: 16px; + } + #title-bar .title-action.icon-save svg { + width: 14px; + height: 14px; + fill: var(--titlebar-save-icon); + stroke: var(--titlebar-save-icon); + stroke-width: 0; + } + #title-bar .title-action.icon-save svg rect, + #title-bar .title-action.icon-save svg circle { + fill: rgba(255,255,255,0.35); + } + #title-bar .title-action.icon-undo.is-enabled svg, + #title-bar .title-action.icon-redo.is-enabled svg { + fill: var(--titlebar-undo-redo-enabled); + } + #title-bar .title-action.icon-undo { + margin-left: -9px; + margin-right: -9px; + } + #title-bar .title-action.icon-save, + #title-bar .title-action.icon-undo, + #title-bar .title-action.icon-redo { + border: 1px solid transparent; + border-radius: 2px; + box-sizing: border-box; + position: relative; + } + #title-bar .title-action.icon-save::before, + #title-bar .title-action.icon-undo::before, + #title-bar .title-action.icon-redo::before { + content: ""; + position: absolute; + width: 20px; + height: 20px; + box-sizing: border-box; + left: 50%; + top: 50%; + transform: translate(-50%, -50%); + border: 1px solid transparent; + background: transparent; + box-shadow: none; + border-radius: 0; + pointer-events: none; + } + #title-bar .title-action.icon-save:hover, + #title-bar .title-action.icon-undo:hover, + #title-bar .title-action.icon-redo:hover { + background: transparent; + border-color: transparent; + box-shadow: none; + } + #title-bar .title-action.icon-save:hover::before, + #title-bar .title-action.icon-undo:hover::before, + #title-bar .title-action.icon-redo:hover::before { + background: transparent; + border-color: var(--titlebar-action-outline-hover); + box-shadow: none; + } + #title-bar .title-action.icon-undo:disabled:hover::before, + #title-bar .title-action.icon-redo:disabled:hover::before { + border-color: transparent; + box-shadow: none; + background: transparent; + } + #title-bar .title-action:disabled { + opacity: 0.5; + cursor: default; + } + /* Undo/Redo provide dedicated grey icons, so don't double-dim via opacity. */ + #title-bar .title-action.icon-undo:disabled, + #title-bar .title-action.icon-redo:disabled { + opacity: 1; + } + #title-bar .title-action:hover { background: var(--titlebar-action-hover-bg); } + #title-bar .title-sep { + width: 1px; + height: 18px; + background: var(--titlebar-separator); + margin: 0 2px; + } + #title-bar .title-filename { + font-weight: 600; + color: var(--titlebar-filename); + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + max-width: 240px; + } + #title-bar .title-controls { display: flex; align-items: stretch; height: 100%; margin-right: -10px; } + #title-bar .title-btn { + width: 46px; + border: 0; + background: transparent; + cursor: pointer; + position: relative; + } + #title-bar .title-btn::before { + position: absolute; + left: 50%; + top: 50%; + transform: translate(-50%, -50%); + font-size: 14px; + line-height: 1; + color: var(--titlebar-control-icon); + content: ""; + } + #title-bar #title-minimize::before { content: "_"; top: 27%; } + #title-bar #title-maximize { + position: relative; + overflow: visible; + } + #title-bar #title-maximize::before { + content: ""; + position: absolute; + left: 50%; + top: 50%; + transform: translate(-50%, -50%); + width: 10px; + height: 10px; + border: 1.5px solid var(--titlebar-control-icon); + box-sizing: border-box; + } + #title-bar #title-maximize::after { + content: ""; + position: absolute; + left: 50%; + top: 50%; + transform: translate(-50%, -50%); + width: 10px; + height: 10px; + box-sizing: border-box; + pointer-events: none; + } + #title-bar #title-maximize.is-maximized::before { + background: none; + border: 0; + width: 8px; + height: 8px; + transform: translate(calc(-50% + 3px), calc(-50% - 3px)); + border-top: 1.5px solid var(--titlebar-control-icon); + border-right: 1.5px solid var(--titlebar-control-icon); + } + #title-bar #title-maximize.is-maximized::after { + border: 1.5px solid var(--titlebar-control-icon); + width: 8px; + height: 8px; + } + #title-bar #title-close::before { content: "βœ•"; } + #title-bar .title-btn:hover { background: var(--titlebar-action-hover-bg); } + #title-bar .title-btn.close:hover { background: var(--titlebar-control-close-hover); } + #title-bar .title-btn.close:hover::before { color: var(--titlebar-control-close-hover-icon); } + .tab-row { display: flex; height: 24px; background: var(--tab-row-bg); border-bottom: 1px solid var(--border-ribbon); z-index: 101; } + .tab { padding: 4px 20px; cursor: pointer; border: 1px solid transparent; margin: 0 2px; position: relative; top: 1px; } + .tab:not(.file):not(.active):hover { background: var(--btn-hover-bg); border-color: var(--btn-hover-border); } + .tab.active { background: var(--bg-ribbon); border: 1px solid var(--border-ribbon); border-bottom: 1px solid var(--bg-ribbon); z-index: 102; } + .tab.file { background: var(--win-blue); color: var(--tab-file-text); } + + + .ribbon { height: 100px; min-height: 100px; max-height: 100px; background: var(--bg-ribbon); border-bottom: 1px solid var(--border-ribbon); display: flex; padding: 5px; gap: 5px; position: relative; z-index: 100; overflow: hidden; } + + + + .section { display: flex; flex-direction: column; align-items: center; justify-content: space-between; border-right: 1px solid var(--section-divider); padding: 0 8px; height: 100%; min-width: max-content; flex-shrink: 0; } + .colors-section { align-items: flex-start; } + .ribbon-draggable { transition: transform 160ms ease; } + .ribbon-drag-handle { cursor: grab; } + .ribbon-dragging { opacity: 0.6; cursor: grabbing; } + .section-title { color: var(--section-title-color); font-size: 11px; margin-bottom: 2px; text-align: center; width: 100%; } + .section-title { -webkit-user-drag: element; } + .section-hidden { display: none !important; } + .tools-grid { display: grid; grid-template-columns: repeat(3, 24px); gap: 2px; } + .shapes-grid { display: grid; grid-template-columns: repeat(4, 24px); gap: 2px; } + .shapes-grid .btn svg [stroke] { stroke: var(--shape-icon-color) !important; } + + /* BUTTONS */ + .btn { border: 1px solid transparent; cursor: pointer; display: flex; align-items: center; justify-content: center; } + .btn-text { justify-content: flex-start; gap: 4px; width: 72px; padding: 2px 4px; text-align: left; } + .btn-text .btn-label { flex: 1; text-align: left; } + .btn-text .btn-caret { margin-left: auto; } + .btn:hover, .btn-large:hover, .split-btn-bottom:hover { background: var(--btn-hover-bg); border-color: var(--btn-hover-border); box-shadow: inset 0 0 2px var(--btn-hover-shadow); } + /* Theme selection buttons: active state, no grey backdrop */ + .btn-large.theme-mode-btn { background: transparent; } + .btn-large.theme-mode-btn.is-on { + background: var(--btn-active-bg); + border-color: var(--btn-active-border); + box-shadow: inset 0 0 3px var(--btn-active-shadow); + } + .btn-large.theme-mode-btn:hover:not(.is-on) { background: var(--btn-hover-bg); border-color: var(--btn-hover-border); box-shadow: inset 0 0 2px var(--btn-hover-shadow); } + .btn-large.edit-colors-btn { position: relative; } + .btn-large.edit-colors-btn { width: 48px; height: 66px; padding: 4px; } + .btn-large.edit-colors-btn::before { + content: ""; + position: absolute; + left: 0; + right: 0; + top: 10px; + bottom: 1px; + background: transparent; + border-radius: 2px; + pointer-events: none; + z-index: -1; + } + .btn-large.edit-colors-btn { z-index: 0; } + .btn-large.edit-colors-btn:hover::before { + background: var(--btn-hover-bg); + box-shadow: inset 0 0 2px var(--btn-hover-shadow); + } + + .swap-colors-btn { position: relative; z-index: 1; pointer-events: auto; } + + .btn.active, .btn-large.active, .split-btn-container.active { + background: var(--btn-active-bg); + border-color: var(--btn-active-border); + box-shadow: inset 0 0 3px var(--btn-active-shadow); + } + + /* Resize and Skew modal (Win32 style) */ + /* Per-element position fine-tuning for the resize/skew modal. These are pixel nudges to align Win32-style form controls. */ + #modal-resize .window { + background-color: #f0f0f0; + width: 264px; + height: 396px; + box-shadow: 0 0 15px rgba(0,0,0,0.4); + display: flex; + flex-direction: column; + border: 1px solid #999; + } + #modal-resize .title-bar { + background-color: white; + height: 26px; + display: flex; + align-items: center; + justify-content: flex-start; + padding-left: 8px; + font-size: 11px; + } + #modal-resize .close-btn { + width: 40px; + height: 26px; + display: flex; + justify-content: center; + align-items: center; + cursor: pointer; + font-size: 13px; + color: #111; + margin-left: auto; + } + #modal-resize .close-btn:hover { + background-color: #e81123; + color: white; + } + #modal-resize .content { padding: 6px 8px 0px 8px; flex: 1; display: flex; flex-direction: column; gap: 6px; } + #modal-resize fieldset { + border: 1px solid #dfdfdf; + margin: 0; + padding: 12px 8px 16px 8px; + margin-bottom: 6px; + border-radius: 2px; + flex: 1; + } + #modal-resize legend { + font-size: 11px; + color: #000; + padding: 0 4px; + margin-left: -5px; + } + #modal-resize .row { display: flex; align-items: center; margin-bottom: 10px; } + #modal-resize .row:last-child { margin-bottom: 0; } + /* Manual nudge for the resize horizontal row position. */ + #modal-resize .rz-h-row { margin-top: -83px; } + #modal-resize .rz-v-row { margin-top: 23px; } + /* Pull the "By:" label left to line up with the radio group. */ + #modal-resize .rz-by-label { margin-left: -20px; } + #modal-resize .sk-h-row { margin-top: -80px; } + #modal-resize .sk-v-row { margin-top: 20px; } + /* Horizontal shift for the resize/skew value rows. */ + #modal-resize .rz-h-row, + #modal-resize .rz-v-row, + #modal-resize .sk-h-row, + #modal-resize .sk-v-row { margin-left: 13px; } + /* Fine-tune the aspect ratio checkbox position. */ + #modal-resize .rz-ratio-row { margin-top: 10px; margin-left: -22px; } + #modal-resize .col-icon { width: 48px; display: flex; justify-content: center; align-items: center; padding-top: 1px; } + #modal-resize .col-icon svg { width: auto; height: auto; display: block; } + #modal-resize .icon-stack-h { display: flex; flex-direction: column; align-items: center; gap: 2px; } + #modal-resize .icon-stack-v { display: flex; flex-direction: row; align-items: center; gap: 2px; } + #modal-resize .resize-icon-img { width: auto; height: auto; display: block; image-rendering: pixelated; } + #modal-resize .skew-icon-img { width: auto; height: auto; display: block; image-rendering: pixelated; } + #modal-resize .rz-hidden { display: none; } + #modal-resize .col-label { width: 62px; color: #000; font-size: 11px; } + #modal-resize .col-input { flex-grow: 1; } + #modal-resize .radio-container { display: flex; gap: 8px; } + #modal-resize .radio-label { display: flex; align-items: center; gap: 4px; cursor: default; font-size: 11px; } + #modal-resize input[type="radio"] { margin: 0; width: 14px; height: 14px; accent-color: var(--toggle-icon-color); transform: translateY(-1px); } + #modal-resize input[type="text"] { + width: 64px; + height: 20px; + box-sizing: border-box; + padding: 0 6px; + border: none; + border-bottom: 1px solid #7a7a7a; + background: #ffffff; + font-family: inherit; + font-size: 11px; + outline: none; + user-select: text; + } + #modal-resize input[type="text"]:hover { border-bottom-color: #3c3c3c; } + #modal-resize input[type="text"]:focus { border-bottom-color: var(--toggle-icon-color); } + #modal-resize .checkbox-row { margin-top: 14px; display: flex; align-items: center; } + #modal-resize .checkbox-indent { margin-left: 30px; display: flex; align-items: center; gap: 6px; font-size: 11px; } + #modal-resize input[type="checkbox"] { margin: 0; width: 12px; height: 12px; accent-color: var(--toggle-icon-color); border: 1px solid #777; } + #modal-resize .footer { + background-color: #f0f0f0; + padding: 8px 10px 10px 10px; + display: flex; + justify-content: flex-end; + gap: 6px; + } + #modal-resize .btn { + width: 64px; + height: 22px; + background-color: #ffffff; + border: 1px solid #adadad; + font-family: inherit; + font-size: 11px; + cursor: pointer; + border-radius: 2px; + outline: none; + } + #modal-resize .btn:hover { background-color: #e5f1fb; border-color: #0078d7; } + #modal-resize .btn:active { background-color: #cce4f7; border-color: #005499; } + #modal-resize .btn:focus-visible { box-shadow: 0 0 0 2px #0078d7; } + #modal-resize .btn-ok { background-color: #ffffff; border: 2px solid #0078d7; } + #modal-resize .btn-ok:hover { background-color: #e5f1fb; } + #modal-resize .btn-ok:active { background-color: #cce4f7; border-color: #005499; } + #modal-resize svg { overflow: visible; } + #modal-resize .shape-stroke { fill: none; stroke: black; stroke-width: 1px; shape-rendering: crispEdges; } + #modal-resize .red-arrow { fill: #ed1c24; } + #modal-props .window { + width: 620px; + max-width: calc(100vw - 34px); + max-height: calc(100vh - 48px); + background-color: #f2f2f2; + border: 1px solid #a8a8a8; + box-shadow: 0 8px 22px rgba(0,0,0,0.22); + position: absolute; + display: flex; + flex-direction: column; + font-family: "Segoe UI", "MS Sans Serif", sans-serif; + font-size: 12px; + } + #modal-props .title-bar { + height: 28px; + background: #ffffff; + border-bottom: 1px solid #d0d0d0; + display: flex; + align-items: center; + padding: 0 10px; + font-size: 12px; + color: #111; + } + #modal-props .close-btn { + margin-left: auto; + width: 32px; + height: 28px; + display: flex; + align-items: center; + justify-content: center; + font-size: 14px; + cursor: pointer; + } + #modal-props .close-btn:hover { background: #e81123; color: #fff; } + #modal-props .content { + padding: 10px; + overflow: auto; + display: flex; + flex-direction: column; + gap: 10px; + min-height: 0; + } + #modal-props .props-edit-panel { + background: #ffffff; + border: 1px solid #d0d0d0; + padding: 10px; + display: flex; + flex-direction: column; + gap: 8px; + } + #modal-props .props-edit-grid { + display: grid; + grid-template-columns: 100px 140px 100px 140px; + gap: 8px; + align-items: center; + } + #modal-props .props-edit-grid label { color: #333; font-size: 12px; } + #modal-props .props-edit-grid input { + height: 24px; + border: 1px solid #bcbcbc; + padding: 0 6px; + font-size: 12px; + background: #fff; + } + #modal-props .props-note { font-size: 11px; color: #616161; } + #modal-props .props-info-grid { + display: grid; + grid-template-columns: 1fr; + gap: 8px; + } + #modal-props .props-card { + background: #ffffff; + border: 1px solid #d0d0d0; + padding: 8px 10px; + min-height: 0; + } + #modal-props .props-card h4 { + margin: 0 0 6px 0; + font-size: 12px; + color: #2f2f2f; + font-weight: 600; + } + #modal-props .props-kv { + display: grid; + grid-template-columns: 170px 1fr; + gap: 4px 8px; + align-items: baseline; + } + #modal-props .props-k { color: #5e5e5e; white-space: nowrap; } + #modal-props .props-v { + color: #1f1f1f; + font-family: Consolas, "Courier New", monospace; + overflow-wrap: anywhere; + } + #modal-props .footer { + display: flex; + justify-content: flex-end; + gap: 8px; + padding: 0 10px 10px 10px; + } + #modal-props .footer .btn { + height: 24px; + padding: 0 14px; + border: 1px solid #adadad; + background-color: #e1e1e1; + font-family: inherit; + font-size: 12px; + cursor: pointer; + border-radius: 2px; + } + #modal-props .footer .btn:hover { background-color: #e5f1fb; border-color: var(--toggle-icon-color); } + #modal-props .footer .btn-ok { background: #fff; border: 1px solid #0078d7; box-shadow: inset 0 0 0 1px #0078d7; } + .btn * { pointer-events: none; } + + .btn-large { display: flex; flex-direction: column; align-items: center; min-width: 44px; padding: 4px; height: 100%; justify-content: center; border: 1px solid transparent; cursor: pointer; position: relative; background: transparent; } + .btn-large .ribbon-icon { width: auto; height: auto; max-width: none; max-height: none; display: block; image-rendering: pixelated; image-rendering: crisp-edges; } + .select-btn-wrap:hover { background: transparent; border-color: transparent; box-shadow: none; } + + .split-btn-container { display: flex; flex-direction: column; height: 100%; border: 1px solid transparent; } + .split-btn-top { flex: 1; display: flex; align-items: center; justify-content: center; cursor: pointer; } + + .split-btn-bottom { height: 18px; display: flex; align-items: center; justify-content: center; font-size: 10px; cursor: pointer; gap: 2px; } + .split-btn-container.select-split { + border: 1px solid transparent; + border-radius: 2px; + overflow: hidden; + } + .split-btn-container.select-split.selection-highlight { + border-color: #66a7e8; + } + .split-btn-container.select-split.selection-highlight .split-btn-top, + .split-btn-container.select-split.selection-highlight .split-btn-bottom.select-dropdown { + background: #cce8ff; + } + .split-btn-container.select-split .split-btn-bottom.select-dropdown { + margin: 0; + border: 0; + border-top: 1px solid transparent; + border-radius: 0; + background: transparent; + height: 24px; + flex-direction: column; + line-height: 1; + } + .split-btn-container.select-split .split-btn-bottom.select-dropdown.selection-highlight { + border-top-color: #66a7e8; + } + .split-btn-container.select-split .split-btn-bottom.select-dropdown span:first-child { + font-size: 11px; + } + .split-btn-container.select-split .split-btn-bottom.select-dropdown .caret { + display: block; + margin-top: -3px; + line-height: 1; + } + .rotate-caret { + display: inline-flex; + margin-top: -1px; + } + .split-btn-container.select-split:hover { + border-color: #9fc4ea; + background: var(--btn-hover-bg); + box-shadow: inset 0 0 2px var(--btn-hover-shadow); + } + .split-btn-container.select-split:hover .split-btn-bottom.select-dropdown { + border-top-color: #9fc4ea; + background: var(--btn-hover-bg); + box-shadow: inset 0 0 2px var(--btn-hover-shadow); + } + .btn-icon { width: 24px; height: 24px; } + .btn-icon img.toolbar-icon { + width: 24px; + height: 24px; + display: block; + margin: 0; + image-rendering: pixelated; + image-rendering: crisp-edges; + } + /* Allow icons with non-24x24 native sizes (ex: Triangle 18x26) to render without clipping. */ + [data-tool="tri"] img.toolbar-icon { + width: 24px; + height: 26px; + transform: translateY(0px); + } + [data-tool="gradient"] img.toolbar-icon { + width: 15px; + height: 17px; + } + #anchor-rotate-toggle-btn img.toolbar-icon { + width: auto; + height: auto; + max-width: 24px; + max-height: 24px; + } + /* Per-icon pixel nudges for visual alignment. */ + [data-tool="eraser"] img.toolbar-icon { transform: translateY(1px); } + [data-tool="picker"] img.toolbar-icon { transform: translate(1px, 1px); } + #wand-tool-btn .wand-icon-contig img.toolbar-icon { transform: translateX(2px); } + .btn-icon .pencil-icon { + width: 100%; + height: 100%; + align-items: center; + justify-content: center; + } + .btn-icon .pencil-icon img.toolbar-icon { + margin: 0; + } + .select-icon { display: none; } + .select-icon.show { display: block; } + img.select-icon { + image-rendering: pixelated; + image-rendering: crisp-edges; + } + + /* MENUS */ + + .dropdown-menu { position: absolute; background: var(--dropdown-bg); border: 1px solid var(--dropdown-border); box-shadow: 2px 2px 5px var(--dropdown-shadow); display: none; flex-direction: column; min-width: 150px; padding: 2px; z-index: 10001; } + + .dd-item { padding: 5px 5px 5px 5px; cursor: pointer; display: flex; align-items: center; gap: 8px; position: relative; } + .dd-item:hover { background: var(--dropdown-item-hover-bg); } + .pixel-perfect { + image-rendering: pixelated; + image-rendering: crisp-edges; + -ms-interpolation-mode: nearest-neighbor; + } + .dd-icon { margin-right: 3px; } + .submenu { position: absolute; left: 100%; top: -1px; display: none; flex-direction: column; background: var(--dropdown-bg); border: 1px solid var(--dropdown-border); box-shadow: 2px 2px 5px var(--dropdown-shadow); min-width: 150px; padding: 2px; z-index: 10002; } + .dd-item:hover > .submenu { display: flex; } + .dd-arrow { margin-left: auto; font-size: 10px; color: var(--dropdown-arrow-color); } + .dd-sep { height: 1px; background: var(--dropdown-separator); margin: 2px 0; } + .dd-check { width: 16px; visibility: hidden; } + .checked .dd-check { visibility: visible; } + + /* File menu template (left actions + right recent files) */ + #file-menu.file-menu-template { + position: absolute; + width: 337px; + min-width: 337px; + padding: 0; + border: 1px solid #b9c1d1; + box-shadow: 2px 2px 5px rgba(0,0,0,0.1); + overflow: visible; + flex-direction: row; + } + #file-menu.file-menu-template.recent-collapsed { + width: 216px; + min-width: 216px; + } + #file-menu .file-menu-left { + flex: 1 1 auto; + width: auto; + min-width: 0; + display: flex; + flex-direction: column; + border-right: 1px solid #e0e4ea; + background: #ffffff; + } + #file-menu .file-menu-item { + width: 100%; + max-width: 100%; + height: 44px; + display: flex; + align-items: center; + gap: 10px; + padding: 0 10px; + cursor: pointer; + color: #333333; + border: 1px solid transparent; + } + #file-menu .file-menu-item:hover { + background-color: #e5f3fb; + border-color: #d8eaf9; + } + #file-menu .file-menu-icon { + width: 32px; + height: 32px; + text-align: center; + flex-shrink: 0; + display: inline-flex; + align-items: center; + justify-content: center; + line-height: 1; + transform: translateZ(0); + } + #file-menu .file-menu-icon img { + width: 32px; + height: 32px; + display: block; + image-rendering: -webkit-optimize-contrast; + } + #file-menu .file-menu-label { + flex: 1; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } + #file-menu .file-menu-separator { + height: 1px; + background-color: #e0e4ea; + margin: 2px 0; + } + #file-menu .file-menu-right { + flex: 0 0 121px; + width: 121px; + margin-left: auto; + background-color: #f5f6f7; + display: flex; + flex-direction: column; + min-width: 0; + } + #file-menu.file-menu-template.recent-collapsed .file-menu-right { + display: none; + } + #file-menu.file-menu-template.recent-collapsed .file-menu-left { + flex: 1 1 auto; + width: auto; + border-right: none; + } + #file-menu .file-menu-recent-toggle { + position: absolute; + right: -1px; + top: -1px; + bottom: auto; + width: 14px; + height: 16px; + border: 1px solid #c3c9d1; + border-right: none; + border-radius: 1px 0 0 1px; + background: #f4f5f7; + color: #5b6168; + cursor: pointer; + display: inline-flex; + align-items: center; + justify-content: center; + padding: 0; + font-size: 9px; + line-height: 1; + z-index: 2; + } + #file-menu .file-menu-recent-toggle:hover { + background: #eceff3; + color: #39414a; + } + #file-menu.file-menu-template.recent-collapsed .file-menu-recent-toggle { + right: -13px; + top: -1px; + border-right: 1px solid #c3c9d1; + border-left: none; + border-radius: 0 1px 1px 0; + } + #file-menu .file-menu-recent-header { + padding: 8px 12px; + border-bottom: 1px solid #e0e4ea; + color: #555555; + font-weight: 600; + } + #file-menu .file-menu-recent-list { + list-style: none; + margin: 0; + padding: 0; + overflow: auto; + flex: 1; + min-height: 0; + } + #file-menu .file-menu-recent-item { + padding: 4px 12px; + cursor: default; + display: flex; + gap: 8px; + min-height: 24px; + align-items: center; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } + #file-menu .file-menu-recent-item span:last-child { + flex: 1; + min-width: 0; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + #file-menu .file-menu-recent-item:hover { + background-color: #e5f3fb; + } + #file-menu .file-menu-recent-item.is-empty { + font-size: 11px; + color: #6a6a6a; + } + #file-menu .file-menu-recent-number { + text-decoration: underline; + width: 12px; + flex-shrink: 0; + color: #2f2f2f; + } + body.dark-mode #file-menu.file-menu-template { + border-color: #4c5666; + box-shadow: 2px 2px 6px rgba(0,0,0,0.4); + } + body.dark-mode #file-menu .file-menu-left { + border-right-color: #465161; + background: #1f2731; + } + body.dark-mode #file-menu .file-menu-item { + color: #e6edf5; + } + body.dark-mode #file-menu .file-menu-item:hover { + background-color: #2a3c52; + border-color: #355474; + } + body.dark-mode #file-menu .file-menu-separator { + background-color: #465161; + } + body.dark-mode #file-menu .file-menu-right { + background-color: #25303b; + } + body.dark-mode #file-menu .file-menu-recent-toggle { + background: #2a3037; + border-color: #465161; + border-right: none; + color: #c9d2db; + } + body.dark-mode #file-menu .file-menu-recent-toggle:hover { + background: #353d47; + color: #eef4fb; + } + body.dark-mode #file-menu.file-menu-template.recent-collapsed .file-menu-recent-toggle { + border-right: 1px solid #465161; + border-left: none; + } + body.dark-mode #file-menu .file-menu-recent-header { + color: #d7e1ea; + border-bottom-color: #465161; + } + body.dark-mode #file-menu .file-menu-recent-item { + color: #d7e1ea; + } + body.dark-mode #file-menu .file-menu-recent-item:hover { + background-color: #2a3c52; + } + + .btn-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 2px; width: 140px; max-height: 90px; overflow-y: auto; } + + .btn-small { border: 1px solid var(--btn-small-border); background: var(--btn-small-bg); padding: 2px 4px; font-size: 10px; text-align: center; cursor: pointer; } + .btn-small.active { background: var(--bg-selected); border-color: var(--win-blue); font-weight: bold; } + #btn-grid-modes { width: 100px; gap: 1px; max-height: none; overflow: visible; } + #btn-grid-modes .btn-small { width: 48px; height: 20px; line-height: 20px; padding: 0; display: flex; align-items: center; justify-content: center; } + + + .threshold-controls { display: flex; flex-direction: column; align-items: center; justify-content: center; height: 60px; gap: 4px; } + .threshold-label { font-size: 10px; color: var(--threshold-label-color); } + .threshold-row { width: 120px; } + #wand-threshold { width: 120px; } + .threshold-values { width: 120px; display: flex; justify-content: space-between; font-size: 10px; color: var(--threshold-values-color); } + + /* FREEFEAND BRUSH SIDEBAR β€” fixed left panel */ + #freehand-sidebar { + position: fixed; top: 145px; bottom: 24px; left: -296px; + width: 280px; z-index: 9988; + background: var(--bg-ribbon, #f5f6f7); + border-right: 1px solid var(--border-ribbon, #dadbdc); + display: flex; flex-direction: column; + transition: left .22s cubic-bezier(.4,0,.2,1); + pointer-events: auto; + } + #freehand-sidebar * { pointer-events: auto; } + #freehand-sidebar.open { left: 0; } + #freehand-sidebar.hidden { display: none !important; } + #freehand-reopen-btn.hidden { display: none !important; } + #freehand-sidebar-header { + display: flex; align-items: center; justify-content: space-between; + padding: 6px 10px; font-size: 12px; font-weight: 600; + color: var(--app-text-color); border-bottom: 1px solid var(--section-divider); + flex-shrink: 0; + } + #freehand-collapse-btn { + background: none; border: none; cursor: pointer; font-size: 12px; + color: var(--section-title-color); padding: 2px 4px; line-height: 1; + transition: transform .15s ease; + } + #freehand-collapse-btn.collapsed { transform: rotate(-90deg); } + #freehand-sidebar-body { + flex: 1; overflow-y: auto; padding: 6px 8px; + min-height: 0; + } + display: flex; flex-direction: column; gap: 3px; + } + .fh-row { display: flex; align-items: center; gap: 4px; font-size: 11px; color: var(--threshold-label-color); } + .fh-row label { min-width: 72px; text-align: right; white-space: nowrap; } + .fh-row input[type="range"] { flex: 1; height: 14px; cursor: pointer; min-width: 40px; } + .fh-row input[type="number"] { width: 40px; text-align: center; font-size: 10px; padding: 1px 2px; border: 1px solid var(--btn-small-border); border-radius: 2px; background: var(--dropdown-bg); color: var(--app-text-color); } + .fh-row select { font-size: 10px; padding: 1px 2px; border: 1px solid var(--btn-small-border); border-radius: 2px; background: var(--dropdown-bg); color: var(--app-text-color); } + .fh-row input[type="checkbox"] { cursor: pointer; margin-left: 4px; } + .fh-row input[type="color"] { width: 24px; height: 24px; border: none; border-radius: 2px; cursor: pointer; flex-shrink: 0; } + .fh-color-wrap { display: flex; align-items: center; gap: 4px; flex: 1; } + .fh-color-edit { width: 24px; height: 24px; font-size: 12px; background: var(--btn-small-bg); border: 1px solid var(--btn-small-border); border-radius: 2px; cursor: pointer; color: var(--app-text-color); display: flex; align-items: center; justify-content: center; } + .fh-color-edit:hover { background: var(--btn-hover-bg); border-color: var(--btn-hover-border); } + .fh-val { min-width: 24px; text-align: center; } + .fh-separator { border-top: 1px solid var(--section-divider); margin: 4px 0; } + .fh-label { font-size: 10px; color: var(--section-title-color); text-align: center; font-weight: bold; } + + #freehand-reopen-btn { + position: fixed; left: 0; top: 145px; + z-index: 9987; width: 24px; height: 36px; + background: var(--bg-ribbon, #f5f6f7); + border: 1px solid var(--border-ribbon, #dadbdc); + border-left: none; border-radius: 0 6px 6px 0; + cursor: pointer; display: none; align-items: center; justify-content: center; + font-size: 14px; color: var(--app-text-color); + box-shadow: 2px 0 5px rgba(0,0,0,0.1); + } + #freehand-reopen-btn.show { display: flex; } + + .fh-reset-row { + display: flex; justify-content: center; padding: 8px 4px 4px; + } + #fh-reset-btn { + font-size: 11px; padding: 4px 14px; cursor: pointer; + border: 1px solid var(--btn-small-border, #ccc); + background: var(--btn-small-bg, #f9f9f9); + border-radius: 3px; color: var(--app-text-color); + transition: background .12s ease, border-color .12s ease; + } + #fh-reset-btn:hover { + background: var(--btn-hover-bg, #eaf4ff); + border-color: var(--btn-hover-border, #9fc4ea); + } + + .wand-icon { display: none; line-height: 1; width: 22px; height: 22px; align-items: center; justify-content: center; transform: translateX(-1px) translateZ(0); } + .wand-icon.show { display: inline-flex; } + .wand-icon img { + width: 22px; + height: 22px; + display: block; + } + .pencil-icon { display: none; line-height: 1; width: 22px; height: 22px; align-items: center; justify-content: center; transform: translateX(0px) translateZ(0); } + .pencil-icon.show { display: inline-flex; } + .pencil-icon img { + width: 22px; + height: 22px; + display: block; + } + .pencil-icon-standard img { + width: 17px; + height: 19px; + } + .wand-menu-icon { width: 20px; height: 20px; display: inline-flex; justify-content: center; align-items: center; line-height: 1; } + .wand-menu-icon img { + width: 20px; + height: 20px; + display: block; + } + .icon-wand-global { + transform: translateX(1px); + } + .ribbon-toggle { display: flex; align-items: center; gap: 6px; font-size: 12px; padding: 0 4px; } + .ribbon-toggle input { margin: 0; width: 14px; height: 14px; accent-color: var(--toggle-icon-color); } + .toggle-btn { + gap: 4px; + background: transparent; + border: 1px solid transparent; + } + .toggle-btn .toggle-icons { + width: 24px; + height: 24px; + display: inline-flex; + align-items: center; + justify-content: center; + color: var(--toggle-icon-color); + } + #anchor-toggle-btn .toggle-icons { color: var(--anchor-toggle-icon-color); } + #theme-mode-btn .toggle-icons { color: var(--theme-mode-toggle-icon-color); } + body.dark-mode .toggle-btn .toggle-icons { color: var(--toggle-icon-color-dark); } + body.dark-mode #anchor-toggle-btn .toggle-icons { color: var(--anchor-toggle-icon-color-dark); } + body.dark-mode #theme-mode-btn .toggle-icons { color: var(--theme-mode-toggle-icon-color-dark); } + body.dark-mode svg [fill="#0078d7"] { fill: #ffffff; } + body.dark-mode svg [stroke="#0078d7"] { stroke: #ffffff; } + .toggle-btn .toggle-icons svg { width: 24px; height: 24px; display: none; } + .toggle-btn .toggle-icons img { display: none; } + .toggle-btn.is-on .icon-on { display: block; } + .toggle-btn:not(.is-on) .icon-off { display: block; } + .toggle-status { + font-size: 11px; + color: var(--toggle-status-color); + } + .hotkeys-icon { color: var(--hotkeys-icon-color); } + body.dark-mode .hotkeys-icon { color: var(--hotkeys-icon-color-dark); } + + /* Selection dropdown (MS Paint style) */ + #select-menu { + --bg-color: #ffffff; + --border-outer: #8e8f8f; + --header-text: #1e395b; + --text-color: #1e1e1e; + --disabled-text: #8c8c8c; + --separator: #e0e0e0; + --item-hover-bg: #eaf6fd; + --item-hover-border: #a8d2f3; + --item-select-bg: #e2f1ff; + --item-select-border: #a4cef5; + --icon-stroke: #1d59aa; + background-color: var(--bg-color); + border: 1px solid var(--border-outer); + box-shadow: 2px 2px 3px rgba(0,0,0,0.2); + padding: 2px; + width: 170px; + height: 197px; + overflow: hidden; + flex-direction: column; + } + #select-menu .header { + color: var(--select-menu-header-color); + font-weight: 600; + padding: 2px 0 4px 15px; + letter-spacing: 0.2px; + background-color: var(--select-menu-header-bg); + } + #select-menu .item { + display: flex; + align-items: center; + height: 20px; + margin: 0 1px 1px; + border: 1px solid transparent; + position: relative; + color: var(--text-color); + } + #select-menu .item.active, + #select-menu .item.checked, + #select-menu .item.selection-highlight { + background-color: var(--item-select-bg); + border-color: var(--item-select-border); + } + #select-menu .item:not(.disabled):not(.active):not(.checked):hover { + background-color: var(--item-hover-bg); + border-color: var(--item-hover-border); + } + #select-menu .gutter { + width: 28px; + height: 100%; + display: flex; + justify-content: center; + align-items: center; + flex-shrink: 0; + } + #select-menu svg { + width: 16px; + height: 16px; + min-width: 16px; + min-height: 16px; + max-width: 16px; + max-height: 16px; + shape-rendering: crispEdges; + fill: none; + stroke: var(--icon-stroke); + stroke-width: 1; + } + #select-menu img { display: block; } + #select-menu .icon-poly { image-rendering: pixelated; image-rendering: crisp-edges; } + #select-menu .dashed { stroke-dasharray: 2 2; } + #select-menu .icon-all rect { fill: var(--select-menu-icon-all-fill); stroke: var(--icon-stroke); stroke-dasharray: 2 2; } + #select-menu .disabled svg { stroke: var(--select-menu-icon-disabled-stroke); } + #select-menu .disabled .icon-all rect { fill: var(--select-menu-icon-all-fill-disabled); } + #select-menu .icon-delete path { stroke: var(--select-menu-icon-delete-stroke); stroke-width: 2; shape-rendering: geometricPrecision; } + #select-menu .disabled .icon-delete path { stroke: var(--select-menu-icon-disabled-stroke); } + #select-menu .label { color: inherit; padding-left: 4px; white-space: nowrap; } + #select-menu .shortcut { text-decoration: underline; } + #select-menu .disabled { color: var(--disabled-text); pointer-events: none; } + #select-menu .separator { + height: 1px; + background-color: var(--separator); + margin: 4px 0 4px 30px; + width: calc(100% - 34px); + } + + #viewport { flex: 1; background: var(--bg-canvas); overflow: auto; position: relative; display: flex; padding: 10px; z-index: 0; } + #viewport.free-canvas { padding: 0; } + + #canvas-stage { position: relative; margin: 0; box-shadow: 3px 3px 5px rgba(0,0,0,0.2); background: white; cursor: crosshair; transform-origin: 0 0; flex-shrink: 0; image-rendering: pixelated; } + #canvas-stage.drop-highlight { + outline: 2px dashed #2a73d9; + outline-offset: 4px; + box-shadow: 0 0 0 4px rgba(42,115,217,0.18), 3px 3px 5px rgba(0,0,0,0.2); + } + + /* Hide default cursor when eraser is active so we only see the ghost */ + #canvas-stage.eraser-active { cursor: none !important; } + + canvas { display: block; position: absolute; top: 0; left: 0; image-rendering: pixelated; } + + #layer-main { z-index: 10; } + #layer-temp { z-index: 20; pointer-events: auto; } + #layer-lasso { z-index: 30; pointer-events: none; } + + /* SVG SELECTION OVERLAY */ + #global-overlay-svg { + position: absolute; + top: 0; left: 0; + width: 100%; height: 100%; + pointer-events: none; + z-index: 30; + overflow: visible; + mix-blend-mode: normal; + } + #global-overlay-svg.overlay-unscaled { + transform: scale(var(--zoom-inv)); + transform-origin: 0 0; + } + #global-overlay-svg.svg-marquee-invert-mode { + mix-blend-mode: difference; + } + + .svg-marquee-rect { + fill: none; + stroke-width: 1px; + stroke-dasharray: 4 4; + vector-effect: non-scaling-stroke; + shape-rendering: crispEdges; + } + .svg-marquee-rect#svg-ghost-rect { + stroke: #8a8a8a; + stroke-dasharray: 2 2; + opacity: 0.9; + } + .svg-marquee-rect.marquee-blue { stroke: #1b6fe5; } + .svg-marquee-rect.marquee-white { stroke: #ffffff; } + .svg-marquee-rect.svg-marquee-invert { + stroke: white; + } + .svg-ants-path { + fill: none; + stroke: white; + stroke-width: 1px; + stroke-dasharray: 15 15; + vector-effect: non-scaling-stroke; + shape-rendering: crispEdges; + animation: ants-march 3.5s linear infinite; + } + .svg-ants-path-back { + fill: none; + stroke: #000; + stroke-width: 1px; + vector-effect: non-scaling-stroke; + shape-rendering: crispEdges; + } + @keyframes ants-march { + to { stroke-dashoffset: -30; } + } + + /* ERASER GHOST CURSOR */ + #eraser-ghost { + position: fixed; + pointer-events: none; + z-index: 9999; + display: none; + outline: 1px solid black; + border: none; + background-color: white; + transform: none; + } + #save-indicator { + position: fixed; + right: 16px; + bottom: 16px; + width: 16px; + height: 16px; + border: 2px solid #3a8dde; + border-top-color: transparent; + border-radius: 50%; + animation: save-spin 0.7s linear infinite; + display: none; + z-index: 20000; + } + @keyframes save-spin { + to { transform: rotate(360deg); } + } + #modal-wincolor { + --win-bg: #f0f0f0; + --win-text: #000000; + --win-border-light: #ffffff; + --win-border-dark: #a0a0a0; + --win-border-darker: #696969; + --win-btn-hover: #e0e0e0; + --win-btn-active: #c0c0c0; + --win-highlight: #0078d7; + --input-border: #d9d9d9; + --input-border-focus: #0078d7; + } + + #modal-wincolor * { box-sizing: border-box; user-select: none; cursor: default !important; } + #modal-wincolor input { user-select: auto !important; cursor: pointer; } + + #modal-depth { + --win-bg: #f0f0f0; + --win-text: #000000; + --win-border-light: #ffffff; + --win-border-dark: #a0a0a0; + --win-highlight: #0078d7; + --border-outer: #d9d9d9; + --input-border: #7a7a7a; + --input-focus: #0078d7; + --btn-hover: #e5f1fb; + --btn-border: #adadad; + } + #modal-depth * { box-sizing: border-box; user-select: none; cursor: default; } + #modal-depth input { user-select: auto; cursor: pointer; } + body.busy-cursor #modal-depth *, + body.busy-cursor #modal-huesat *, + body.busy-cursor #modal-wincolor *, + body.busy-cursor .modal-window, + body.busy-cursor .modal-mask { + cursor: wait !important; + } + #modal-depth .window { + width: 330px; + background-color: var(--win-bg); + border: 1px solid #999; + box-shadow: 0 4px 12px rgba(0,0,0,0.15); + display: flex; + flex-direction: column; + } + #modal-depth .title-bar { + background-color: #fff; + height: 28px; + display: flex; + justify-content: flex-start; + align-items: center; + padding-left: 8px; + font-size: 12px; + color: #000; + } + #modal-depth .close-btn { + width: 40px; + height: 28px; + border: none; + background: transparent; + font-size: 14px; + display: flex; + justify-content: center; + align-items: center; + margin-left: auto; + } + #modal-depth .close-btn:hover { background-color: #e81123; color: white; } + #modal-depth .content { + padding: 12px 12px 16px 12px; + display: flex; + flex-direction: column; + gap: 12px; + } + #modal-depth .section-header { + font-weight: 600; + margin-bottom: 6px; + color: var(--win-text); + display: block; + } + #modal-depth .vertical-list { + display: flex; + flex-direction: column; + gap: 4px; + padding-left: 4px; + } + #modal-depth .depth-group-label { + display: block; + margin: 0 0 4px 0; + color: var(--win-text); + } + #modal-depth .depth-color-list { + padding-left: 8px; + } + #modal-depth .depth-color-list .control-item { + padding: 1px 0; + } + #modal-depth .depth-options-list { + gap: 5px; + } + #modal-depth .control-item { + display: flex; + align-items: center; + gap: 6px; + white-space: nowrap; + } + #modal-depth .depth-color-list input[type="radio"] { + position: absolute; + opacity: 0; + width: 1px; + height: 1px; + pointer-events: none; + } + #modal-depth .depth-radio { + width: 13px; + height: 13px; + flex: 0 0 13px; + border: 1px solid #707070; + border-radius: 50%; + background: #ffffff; + position: relative; + display: grid; + place-items: center; + cursor: default; + } + #modal-depth .depth-color-list input[type="radio"]:checked + .depth-radio { + border: 0; + background: #0078D7; + } + #modal-depth .depth-color-list .control-item:hover input[type="radio"]:checked + .depth-radio { + transform: none; + } + #modal-depth .depth-color-list input[type="radio"]:checked + .depth-radio::after { + content: ""; + width: 5px; + height: 5px; + border-radius: 50%; + background: #ffffff; + position: static; + transform-origin: center; + animation: depth-radio-pop 120ms ease-out; + } + #modal-depth .depth-color-list .control-item:hover input[type="radio"]:checked + .depth-radio::after { + width: 7px; + height: 7px; + } + #modal-depth .depth-color-list input[type="radio"]:focus { + outline: none; + } + #modal-depth #custom-depth-val { + border: 0; + border-bottom: 1px solid var(--input-border); + background: #ffffff; + text-align: center; + appearance: textfield; + -moz-appearance: textfield; + } + #modal-depth #custom-depth-val:focus { + border: 0; + border-bottom: 2px solid var(--input-focus); + padding: 0 4px; + } + #modal-depth #custom-depth-val::-webkit-outer-spin-button, + #modal-depth #custom-depth-val::-webkit-inner-spin-button { + -webkit-appearance: none; + margin: 0; + } + @keyframes depth-radio-pop { + from { transform: scale(0); } + to { transform: scale(1); } + } + #modal-depth .depth-hidden-legacy { + display: none !important; + } + #modal-depth input[type="text"], + #modal-depth input[type="number"] { + height: 22px; + border: 1px solid var(--input-border); + padding: 0 4px; + font-family: inherit; + font-size: 12px; + outline: none; + } + #modal-depth input[type="text"]:focus, + #modal-depth input[type="number"]:focus { + border-color: var(--input-focus); + border-width: 2px; + padding: 0 3px; + } + #modal-depth .divider { + height: 1px; + background-color: #d9d9d9; + width: 100%; + margin: 4px 0; + } + #modal-depth .param-row { + display: flex; + align-items: center; + height: 24px; + } + #modal-depth .param-icon { + width: 20px; + display: flex; + justify-content: center; + align-items: center; + margin-right: 8px; + } + #modal-depth .param-label { width: 70px; } + #modal-depth .param-input-group { flex: 1; display: flex; align-items: center; gap: 8px; } + #modal-depth input[type=range] { + -webkit-appearance: none; + width: 100%; + background: transparent; + } + #modal-depth input[type=range]:focus { outline: none; } + #modal-depth input[type=range]::-webkit-slider-runnable-track { + width: 100%; + height: 4px; + cursor: pointer; + background: #cdcdcd; + border-radius: 2px; + border: 1px solid #a6a6a6; + } + #modal-depth input[type=range]::-webkit-slider-thumb { + height: 16px; + width: 10px; + border-radius: 2px; + background: #0078d7; + cursor: pointer; + -webkit-appearance: none; + margin-top: -7px; + } + #modal-depth input[type=range]:hover::-webkit-slider-thumb { background: #005a9e; } + #modal-depth .footer { + padding: 0 12px 12px 12px; + display: flex; + justify-content: center; + gap: 8px; + } + #modal-depth .btn { + padding: 0 12px; + height: 23px; + font-family: inherit; + font-size: 9pt; + border: 1px solid #adadad; + background-color: #ffffff; + cursor: pointer; + white-space: nowrap; + border-radius: 3px; + min-width: 72px; + outline: none; + } + #modal-depth .btn:hover { background-color: #e5f1fb; border-color: #0078d7; } + #modal-depth .btn:active { background-color: #cce4f7; border-color: #005499; } + #modal-depth .btn:focus-visible { box-shadow: 0 0 0 2px #0078d7; } + #modal-depth .btn-primary { background-color: #ffffff; border: 2px solid #0078d7; } + #modal-depth .btn-primary:hover { background-color: #e5f1fb; } + #modal-depth .btn-primary:active { background-color: #cce4f7; border-color: #005499; } + #modal-depth .sm-icon { width: 16px; height: 16px; } + #modal-depth .stroke-black { stroke: #000; stroke-width: 1.5; fill: none; } + #modal-depth .fill-red { fill: #d00000; stroke: none; } + + + /* ── Stray Pixel Cleaner modal ─────────────────────────────────────────────── */ + #modal-gapstitch { --gs-win-bg: #f0f0f0; --gs-text: #000000; --gs-input-border: #7a7a7a; --gs-focus: #0078d7; --gs-btn-border: #adadad; --gs-btn-hover: #e5f1fb; } + #modal-gapstitch * { box-sizing: border-box; user-select: none; cursor: default; } + #modal-gapstitch input { user-select: auto; cursor: pointer; } + #modal-gapstitch .window { width: 310px; background-color: var(--gs-win-bg); border: 1px solid #999; box-shadow: 0 4px 14px rgba(0,0,0,0.22); position: absolute; display: flex; flex-direction: column; font-family: "Segoe UI", "MS Sans Serif", sans-serif; font-size: 11px; } + #modal-gapstitch .title-bar { height: 28px; background: #fff; border-bottom: 1px solid #e0e0e0; display: flex; align-items: center; padding: 0 0 0 8px; gap: 6px; } + #modal-gapstitch .title-bar-icon { flex-shrink: 0; } + #modal-gapstitch .title-bar-label { font-weight: 600; font-size: 11px; flex: 1; color: var(--gs-text); } + #modal-gapstitch .close-btn { margin-left: auto; width: 32px; height: 28px; display: flex; align-items: center; justify-content: center; font-size: 14px; cursor: pointer; } + #modal-gapstitch .close-btn:hover { background-color: #e81123; color: white; } + #modal-gapstitch .content { padding: 10px 12px 6px 12px; display: flex; flex-direction: column; gap: 0; } + #modal-gapstitch .gs-section-hdr { font-weight: 600; color: var(--gs-text); display: block; font-size: 11px; border-bottom: 1px solid #d8d8d8; padding-bottom: 4px; margin-bottom: 8px; letter-spacing: 0.01em; } + #modal-gapstitch .gs-rows { display: flex; flex-direction: column; gap: 5px; margin-bottom: 10px; } + #modal-gapstitch .gs-row { display: grid; grid-template-columns: 108px 1fr 40px; gap: 6px; align-items: center; } + #modal-gapstitch .gs-row-label-wrap { display: flex; align-items: center; gap: 4px; } + #modal-gapstitch .gs-row label { color: #222; font-size: 11px; cursor: default; } + #modal-gapstitch .gs-hint-icon { width: 13px; height: 13px; border-radius: 50%; background: #c8c8c8; color: #fff; font-size: 9px; font-weight: 700; display: inline-flex; align-items: center; justify-content: center; cursor: default; flex-shrink: 0; line-height: 1; position: relative; } + #modal-gapstitch .gs-hint-icon:hover .gs-tooltip { display: block; } + #modal-gapstitch .gs-tooltip { display: none; position: absolute; left: 18px; top: -2px; background: #1a1a1a; color: #f5f5f5; font-size: 10px; font-weight: 400; padding: 5px 7px; border-radius: 3px; white-space: normal; width: 170px; line-height: 1.45; z-index: 9999; box-shadow: 0 2px 6px rgba(0,0,0,0.35); pointer-events: none; } + #modal-gapstitch .gs-row input[type="number"] { width: 100%; padding: 2px 4px; border: 1px solid var(--gs-input-border); font-size: 11px; font-family: inherit; background: #fff; color: var(--gs-text); height: 22px; } + #modal-gapstitch .gs-row input[type="number"]:focus { outline: none; border-color: var(--gs-focus); box-shadow: 0 0 0 1px var(--gs-focus); } + #modal-gapstitch .gs-val { text-align: right; color: #666; font-size: 11px; min-width: 34px; } + #modal-gapstitch .gs-desc { font-size: 10px; color: #888; line-height: 1.5; margin-bottom: 10px; padding: 5px 7px; background: #e8eef4; border-left: 2px solid #a0bcd8; } + #modal-gapstitch .footer { padding: 7px 12px 10px 12px; display: flex; justify-content: flex-end; gap: 6px; border-top: 1px solid #ddd; } + #modal-gapstitch .btn { padding: 0 8px; height: 22px; min-width: 70px; font-family: inherit; font-size: 9pt; border: 1px solid #adadad; background-color: #ffffff; cursor: pointer; white-space: nowrap; border-radius: 3px; outline: none; } + #modal-gapstitch .btn:hover { background-color: #e5f1fb; border-color: #0078d7; } + #modal-gapstitch .btn:active { background-color: #cce4f7; border-color: #005499; } + #modal-gapstitch .btn:focus-visible { box-shadow: 0 0 0 2px #0078d7; } + #modal-gapstitch .btn-primary { background: #fff; border: 2px solid #0078d7; border-radius: 3px; } + #modal-gapstitch .btn-primary:hover { background: #e5f1fb; } + #modal-gapstitch .btn-primary:active { background: #cce4f7; border-color: #005499; } + + #modal-export { + --win-bg: #f0f0f0; + --win-text: #000000; + --input-border: #7a7a7a; + --input-focus: #0078d7; + --btn-border: #adadad; + --btn-hover: #e5f1fb; + } + #modal-export * { box-sizing: border-box; user-select: none; cursor: default; } + #modal-export input { user-select: auto; cursor: pointer; } + #modal-export .window { + background-color: var(--win-bg); + border: 1px solid #999; + box-shadow: 0 8px 24px rgba(0,0,0,0.3); + position: absolute; + display: flex; + flex-direction: column; + font-family: "Segoe UI", "MS Sans Serif", sans-serif; + font-size: 11px; + } + #modal-export .title-bar { + height: 28px; + background: #fff; + border-bottom: 1px solid #ccc; + display: flex; + align-items: center; + padding: 0 8px; + } + #modal-export .close-btn { + margin-left: auto; + width: 32px; + height: 28px; + display: flex; + align-items: center; + justify-content: center; + font-size: 14px; + cursor: pointer; + } + #modal-export .close-btn:hover { background-color: #e81123; color: white; } + #modal-export .content { padding: 8px 10px 10px 10px; } + #modal-export fieldset { + border: 1px solid #dfdfdf; + margin: 0; + padding: 10px 8px 12px 8px; + border-radius: 2px; + } + #modal-export legend { + font-size: 11px; + color: #000; + } + #modal-export .divider { + height: 1px; + background: #dcdcdc; + margin: 6px 0 8px 0; + } + #modal-export .checkbox-row { + display: flex; + align-items: center; + gap: 6px; + margin: 6px 0; + } + #modal-export .footer { + background-color: var(--win-bg); + padding: 8px 10px 10px 10px; + display: flex; + justify-content: flex-end; + gap: 8px; + } + #modal-export .btn { + padding: 0 12px; + height: 23px; + font-family: inherit; + font-size: 9pt; + border: 1px solid #adadad; + background-color: #ffffff; + cursor: pointer; + white-space: nowrap; + border-radius: 3px; + outline: none; + } + #modal-export .btn:hover { background-color: #e5f1fb; border-color: #0078d7; } + #modal-export .btn:active { background-color: #cce4f7; border-color: #005499; } + #modal-export .btn:focus-visible { box-shadow: 0 0 0 2px #0078d7; } + #modal-export .btn-primary { background: #ffffff; color: #000000; border: 2px solid #0078d7; } + #modal-export .btn-primary:hover { background-color: #e5f1fb; } + #modal-export .btn-primary:active { background-color: #cce4f7; border-color: #005499; } + + /* huesat floats over canvas β€” never dim the background so colors stay visible */ + #modal-huesat.modal-mask { background: transparent !important; } + + #modal-huesat { + --win-bg: #f0f0f0; + --win-text: #000000; + --input-border: #7a7a7a; + --input-focus: #0078d7; + --btn-border: #adadad; + --btn-hover: #e5f1fb; + } + #modal-huesat * { box-sizing: border-box; user-select: none; cursor: default; } + #modal-huesat input { user-select: auto; cursor: pointer; } + #modal-huesat .window { + width: 320px; + background-color: var(--win-bg); + border: 1px solid #999; + box-shadow: 0 10px 30px rgba(0,0,0,0.4); + position: absolute; + padding: 8px; + display: flex; + flex-direction: column; + font-family: "Segoe UI", "MS Sans Serif", sans-serif; + font-size: 11px; + } + #modal-huesat .title-bar { + height: 28px; + background: white; + border-bottom: 1px solid #ccc; + display: flex; + align-items: center; + padding-left: 8px; + margin: -8px -8px 8px -8px; + } + #modal-huesat .close-btn { + margin-left: auto; + width: 32px; + height: 28px; + display: flex; + align-items: center; + justify-content: center; + font-size: 14px; + cursor: pointer; + } + #modal-huesat .close-btn:hover { background-color: #e81123; color: white; } + #modal-huesat .content { padding: 4px 8px 8px 8px; } + #modal-huesat .row { + display: grid; + grid-template-columns: 70px 1fr 52px; + gap: 8px; + align-items: center; + margin-bottom: 8px; + } + #modal-huesat .channel-area { + --hs-area-bg: #f8f8f8; + border: 1px solid #e0e0e0; + background: #f8f8f8; + border-radius: 4px; + padding: 10px 8px 8px 8px; + margin: 4px 0 10px 0; + } + #modal-huesat .channel-label { font-size: 10px; color: #888; margin-bottom: 8px; letter-spacing: 0.04em; text-transform: uppercase; } + + /* Hexagonal colour wheel β€” absolute positioned around master */ + #modal-huesat .channel-wheel { + position: relative; + width: 210px; + height: 126px; + margin: 0 auto 6px auto; + } + #modal-huesat .channel-wrap { + width: 36px; + height: 24px; + position: absolute; + cursor: pointer; + } + #modal-huesat .channel-btn { + width: 36px; + height: 24px; + clip-path: polygon(18% 0%, 82% 0%, 100% 50%, 82% 100%, 18% 100%, 0% 50%); + cursor: pointer; + position: absolute; + top: 0; left: 0; + } + /* Selection halo β€” SVG stroked hexagon, perfectly transparent interior, no animation */ + #modal-huesat .channel-ring { + position: absolute; + top: -5px; left: -5px; + width: 46px; + height: 34px; + pointer-events: none; + opacity: 0; + overflow: visible; + } + #modal-huesat .channel-ring svg { + display: block; + width: 46px; + height: 34px; + overflow: visible; + } + #modal-huesat .channel-wrap.active .channel-ring { opacity: 1; } + #modal-huesat .channel-btn:hover { } + #modal-huesat .pos-r { top: 2px; left: 87px; } + #modal-huesat .pos-y { top: 30px; left: 22px; } + #modal-huesat .pos-m { top: 30px; right: 22px; } + #modal-huesat .pos-g { top: 72px; left: 22px; } + #modal-huesat .pos-b { top: 72px; right: 22px; } + #modal-huesat .pos-c { top: 100px; left: 87px; } + #modal-huesat .pos-r .channel-btn { background: #ff0000; } + #modal-huesat .pos-y .channel-btn { background: #ffff00; } + #modal-huesat .pos-m .channel-btn { background: #ff00ff; } + #modal-huesat .pos-g .channel-btn { background: #00ff00; } + #modal-huesat .pos-b .channel-btn { background: #0000ff; } + #modal-huesat .pos-c .channel-btn { background: #00ffff; } + + /* Master button in the centre */ + #modal-huesat .master-btn { + position: absolute; + top: 50px; + left: 50%; + transform: translateX(-50%); + background: #f0f0f0; + color: #222; + padding: 3px 12px; + border-radius: 2px; + cursor: pointer; + font-size: 11px; + font-family: 'Segoe UI', sans-serif; + border: 1px solid #adadad; + white-space: nowrap; + transition: background 0.08s, border-color 0.08s, color 0.08s, outline 0.08s; + outline: 1px solid transparent; + outline-offset: 1px; + box-shadow: 0 1px 2px rgba(0,0,0,0.08), inset 0 1px 0 rgba(255,255,255,0.7); + } + #modal-huesat .master-btn:hover { background: #e8e8e8; border-color: #888; } + #modal-huesat .master-btn.active { background: #f0f0f0; border-color: #0078d7; color: #222; font-weight: 600; outline: none; } + + /* Live preview strip */ + + #modal-huesat .hs-live-preview, + #modal-huesat #hs-prev-original, + #modal-huesat #hs-prev-adjusted, + #modal-huesat .hs-prev-divider { display: none; } + + #modal-huesat .sub-row { + display: flex; + justify-content: space-between; + align-items: center; + margin: 6px 0 4px 0; + } + #modal-huesat .sub-row label { font-size: 11px; color: #555; } + #modal-huesat input[type="range"] { + width: 100%; + height: 7px; + -webkit-appearance: none; + appearance: none; + border-radius: 3px; + outline: none; + cursor: pointer; + } + #modal-huesat input[type="range"]::-webkit-slider-runnable-track { + height: 7px; + background: transparent; + border-radius: 3px; + border: none; + } + #modal-huesat input[type="range"]::-webkit-slider-thumb { + -webkit-appearance: none; + width: 10px; + height: 19px; + border-radius: 2px; + background: rgba(255,255,255,0.92); + border: 1px solid rgba(0,0,0,0.28); + margin-top: -6px; + cursor: pointer; + } + #modal-huesat input[type="range"]::-moz-range-track { + height: 7px; + background: transparent; + border-radius: 3px; + border: none; + } + #modal-huesat input[type="range"]::-moz-range-progress { + height: 7px; + background: transparent; + border-radius: 3px; + } + #modal-huesat input[type="range"]::-moz-range-thumb { + width: 10px; + height: 19px; + border-radius: 2px; + background: rgba(255,255,255,0.92); + border: 1px solid rgba(0,0,0,0.28); + cursor: pointer; + } + #modal-huesat #hs-hue { background: linear-gradient(to right, hsl(0,100%,50%), hsl(30,100%,50%), hsl(60,100%,50%), hsl(90,100%,50%), hsl(120,100%,50%), hsl(150,100%,50%), hsl(180,100%,50%), hsl(210,100%,50%), hsl(240,100%,50%), hsl(270,100%,50%), hsl(300,100%,50%), hsl(330,100%,50%), hsl(360,100%,50%)); border-radius: 3px; } + #modal-huesat #hs-sat { background: linear-gradient(to right, #808080 0%, #ff0000 100%); border-radius: 3px; } + #modal-huesat #hs-light { background: linear-gradient(to right, #000 0%, #888 50%, #fff 100%); border-radius: 3px; } + #modal-huesat #hs-chroma { background: linear-gradient(to right, #888 0%, #e85e3a 100%); border-radius: 3px; } + #modal-huesat #hs-overlap { background: linear-gradient(to right, #bbb 0%, #0078d7 100%); border-radius: 3px; } + + #modal-huesat input[type="number"] { + height: 22px; + border: 1px solid var(--input-border); + padding: 0 4px; + font-family: inherit; + font-size: 11px; + width: 52px; + } + #modal-huesat input[type="number"]:focus { + outline: none; + border-color: var(--input-focus); + border-width: 2px; + padding: 0 3px; + } + #modal-huesat .footer { + display: flex; + justify-content: flex-end; + gap: 6px; + padding: 6px 8px 8px 8px; + border-top: 1px solid #d9d9d9; + } + #modal-huesat .btn { + height: 23px; + padding: 0 12px; + min-width: 64px; + background-color: #ffffff; + border: 1px solid #adadad; + border-radius: 3px; + cursor: pointer; + font-family: inherit; + font-size: 9pt; + color: var(--win-text); + white-space: nowrap; + outline: none; + } + #modal-huesat .btn:hover { background-color: #e5f1fb; border-color: #0078d7; } + #modal-huesat .btn:active { background-color: #cce4f7; border-color: #005499; } + #modal-huesat .btn:focus-visible { box-shadow: 0 0 0 2px #0078d7; } + #modal-huesat .btn-primary { background-color: #ffffff; border: 2px solid #0078d7; } + #modal-huesat .btn-primary:hover { background-color: #e5f1fb; } + #modal-huesat .btn-primary:active { background-color: #cce4f7; border-color: #005499; } + /* ── Hue/Sat sidebar mode ── */ + #modal-huesat.hs-sidebar-mode { + position: fixed !important; + top: 145px; left: 0; bottom: 0; + width: 320px !important; + z-index: 9000; + background: transparent; + display: flex !important; + align-items: stretch; + pointer-events: none; + } + #modal-huesat.hs-sidebar-mode .window { + position: relative !important; + width: 320px !important; + height: 100% !important; + border-radius: 0 !important; + border-left: none !important; + border-top: none !important; + border-bottom: none !important; + box-shadow: none !important; + overflow-y: auto; + overflow-x: hidden; + pointer-events: all; + display: flex; + flex-direction: column; + } + #modal-huesat.hs-sidebar-mode .content { + flex: 1; + overflow-y: auto; + } + /* Sidebar overlays the viewport β€” canvas does not shift */ + #modal-resize.utility-sidebar-mode, + #modal-depth.utility-sidebar-mode { + position: fixed !important; + top: 145px; left: 0; bottom: 0; + z-index: 9000; + background: transparent; + display: flex !important; + align-items: stretch; + pointer-events: none; + } + #modal-resize.utility-sidebar-mode { width: 264px !important; } + #modal-depth.utility-sidebar-mode { width: 330px !important; } + #modal-resize.utility-sidebar-mode .window, + #modal-depth.utility-sidebar-mode .window { + position: relative !important; + height: 100% !important; + border-radius: 0 !important; + border-left: none !important; + border-top: none !important; + border-bottom: none !important; + box-shadow: none !important; + overflow-y: auto; + overflow-x: hidden; + pointer-events: all; + display: flex; + flex-direction: column; + } + #modal-resize.utility-sidebar-mode .window { width: 264px !important; } + #modal-depth.utility-sidebar-mode .window { width: 330px !important; } + #modal-resize.utility-sidebar-mode .content, + #modal-depth.utility-sidebar-mode .content { + flex: 1; + overflow-y: auto; + } + body.huesat-sidebar-open #huesat-split-handle { + left: 320px !important; + top: 145px !important; + } + /* Sidebar dock/undock button */ + .hs-sidebar-toggle, + .utility-sidebar-toggle { + width: 26px; + height: 28px; + display: flex; + align-items: center; + justify-content: center; + cursor: pointer; + flex-shrink: 0; + color: #666; + font-size: 13px; + border-right: 1px solid #ddd; + margin-right: 6px; + transition: background 0.1s, color 0.1s; + user-select: none; + } + .hs-sidebar-toggle:hover, + .utility-sidebar-toggle:hover { + background: #e8f0fe; + color: #0078d7; + } + .hs-sidebar-toggle svg, + .utility-sidebar-toggle svg { + width: 14px; + height: 14px; + fill: currentColor; + } + + #huesat-split-handle { + position: fixed; + top: 0; + bottom: 0; + width: 4px; + background: rgba(255,255,255,0.8); + display: none; + cursor: col-resize; + z-index: 20000; + } + #huesat-split-handle .hs-circle { + width: 24px; + height: 24px; + background: #fff; + border-radius: 50%; + box-shadow: 0 2px 5px rgba(0,0,0,0.3); + display: flex; + align-items: center; + justify-content: center; + font-size: 12px; + color: #555; + position: absolute; + left: 50%; + top: 50%; + transform: translate(-50%, -50%); + } + + #modal-wincolor .window { + width: 447px; + height: 360px; + background-color: var(--win-bg); + border: 1px solid #999; + box-shadow: 0 10px 30px rgba(0,0,0,0.4); + position: absolute; + padding: 8px; + color: var(--win-text); + display: flex; + flex-direction: column; + font-family: "Segoe UI", "MS Sans Serif", sans-serif; + font-size: 9pt; + } + + #modal-wincolor .title-bar { + height: 30px; + background: white; + border-bottom: 1px solid #ccc; + display: flex; + align-items: center; + padding-left: 10px; + font-size: 12px; + color: #000; + margin: -8px -8px 8px -8px; + } + #modal-wincolor .close-btn { + margin-left: auto; + width: 32px; + height: 30px; + display: flex; + align-items: center; + justify-content: center; + font-size: 16px; + } + #modal-wincolor .close-btn span { transform: translateX(1px); display: inline-block; } + #modal-wincolor .close-btn:hover { background-color: #e81123; color: white; } + + #modal-wincolor .content-area { display: flex; gap: 8px; } + #modal-wincolor .left-pane { width: 189px; flex-shrink: 0; } + #modal-wincolor .right-pane { width: 230px; flex-grow: 1; display: flex; flex-direction: column; } + + #modal-wincolor .label { margin-bottom: 4px; display: block; } + #modal-wincolor #wincolor-custom { margin-top: 6px; } + + #modal-wincolor .swatch-grid { + display: grid; + grid-template-columns: repeat(8, 1fr); + gap: 4px; + margin-bottom: 10px; + } + #modal-wincolor .swatch { + width: 20px; + height: 17px; + border-top: 1px solid var(--win-border-dark); + border-left: 1px solid var(--win-border-dark); + border-bottom: 1px solid var(--win-border-light); + border-right: 1px solid var(--win-border-light); + background-color: #fff; + position: relative; + } + #modal-wincolor .swatch.selected::after { + content: ''; + position: absolute; + top: -1px; left: -1px; right: -1px; bottom: -1px; + border: 1px solid #000; + } + #modal-wincolor .swatch:hover { border-top: 1px solid var(--win-border-dark); border-left: 1px solid var(--win-border-dark); border-bottom: 1px solid var(--win-border-light); border-right: 1px solid var(--win-border-light); } + + #modal-wincolor button { + height: 22px; + padding: 0 8px; + background: #e1e1e1; + border: 1px solid #adadad; + border-radius: 3px; + font-family: inherit; + font-size: 9pt; + min-width: 70px; + } + #modal-wincolor button:hover:not(:disabled) { + background-color: #e5f1fb; + border-color: var(--toggle-icon-color); + } + #modal-wincolor button:active:not(:disabled) { + background-color: #cce4f7; + border-color: #005499; + } + #modal-wincolor button:disabled { + color: #838383; + background-color: #f0f0f0; + border-color: #d0d0d0; + } + #modal-wincolor .btn-define { width: 100%; margin-bottom: 8px; text-align: center; } + #modal-wincolor .bottom-actions { display: flex; gap: 8px; } + #modal-wincolor .btn-ok { border: 2px solid var(--win-highlight); border-radius: 4px; } + #modal-wincolor .wincolor-bottom-row { + display: flex; + align-items: center; + justify-content: flex-start; + gap: 12px; + margin-top: 4px; + padding-left: 4px; + } + #modal-wincolor .bottom-actions button { background: #fff; } + + #modal-wincolor .color-editor-top { display: flex; gap: 17px; margin-bottom: 8px; width: 230px; } + #modal-wincolor .spectrum-box { + width: 185px; + height: 188px; + border-top: 1px solid var(--win-border-dark); + border-left: 1px solid var(--win-border-dark); + border-right: 1px solid var(--win-border-light); + border-bottom: 1px solid var(--win-border-light); + position: relative; + cursor: default; + background: #fff; + padding: 1px; + box-sizing: border-box; + margin: 0; + } + #modal-wincolor #wincolor-spectrum { display: block; cursor: default; } + + #modal-wincolor .crosshair { + position: absolute; + width: 19px; + height: 19px; + pointer-events: none; + } + #modal-wincolor .crosshair::before, + #modal-wincolor .crosshair::after { + content: ''; + position: absolute; + } + #modal-wincolor .crosshair::before { + top: 8px; + left: 0; + width: 19px; + height: 3px; + background: linear-gradient(to right, #000 0 5px, transparent 5px 14px, #000 14px 19px); + } + #modal-wincolor .crosshair::after { + top: 0; + left: 8px; + width: 3px; + height: 19px; + background: linear-gradient(to bottom, #000 0 5px, transparent 5px 14px, #000 14px 19px); + } + + #modal-wincolor .lum-slider-container { position: relative; width: 24px; height: 188px; margin: 0; } + #modal-wincolor .lum-strip { + width: 12px; + height: 188px; + border-top: 1px solid var(--win-border-dark); + border-left: 1px solid var(--win-border-dark); + border-right: 1px solid var(--win-border-light); + border-bottom: 1px solid var(--win-border-light); + display: block; + position: absolute; + left: 0; + top: 0; + } + #modal-wincolor .lum-arrow { + width: 0; + height: 0; + border-top: 6px solid transparent; + border-bottom: 7px solid transparent; + border-right: 7px solid #000; + position: absolute; + left: 16px; + top: 0; + transform: translateY(-50%); + } + + #modal-wincolor .color-editor-bottom { display: flex; gap: 8px; } + #modal-wincolor .preview-box-container { display: flex; flex-direction: column; align-items: center; padding-top: 4px; } + #modal-wincolor .preview-box { + width: 58px; + height: 40px; + border-top: 1px solid var(--win-border-dark); + border-left: 1px solid var(--win-border-dark); + border-right: 1px solid var(--win-border-light); + border-bottom: 1px solid var(--win-border-light); + background-color: #000; + margin-bottom: 4px; + } + #modal-wincolor .preview-label { font-size: 11px; color: #000; } + #modal-wincolor .input-group { + display: grid; + grid-template-columns: 36px 30px 44px 30px; + column-gap: 4px; + row-gap: 4px; + align-items: center; + font-size: 9pt; + } + #modal-wincolor .input-label { text-align: right; } + #modal-wincolor input[type="text"] { + width: 100%; + height: 18px; + border: none; + border-bottom: 1px solid #7a7a7a; + padding: 0 3px; + font-family: inherit; + font-size: 9pt; + background: #fff; + } + #modal-wincolor input[type="text"]:focus { outline: none; border-bottom-color: var(--toggle-icon-color); } + #modal-wincolor .btn-add { width: 220px; margin-top: 0; margin-left: 31px; background: #fff; } + #modal-wincolor .tabs { + display: flex; + gap: 4px; + margin-bottom: 6px; + } + #modal-wincolor .tab-btn { + padding: 2px 8px; + border: 1px solid #999; + background: #e1e1e1; + font-size: 11px; + cursor: pointer; + border-radius: 2px; + } + #modal-wincolor .tab-btn.active { + background: #ffffff; + border-color: var(--toggle-icon-color); + box-shadow: inset 0 0 0 1px #0078d7; + } + #modal-wincolor .bpp-panel { + display: none; + padding: 6px; + border: 1px solid #d0d0d0; + background: #fff; + margin-bottom: 6px; + } + #modal-wincolor .bpp-row { + display: grid; + grid-template-columns: 24px 1fr 44px; + gap: 6px; + align-items: center; + margin-bottom: 6px; + font-size: 11px; + } + #modal-wincolor .bpp-row input[type="range"] { width: 100%; } + #modal-wincolor .bpp-preview { + height: 40px; + border: 1px solid #777; + background: #000; + } + + /* Hotkeys modal */ + #modal-hotkeys .window { + width: 700px; + height: 1600px; + background-color: #f0f0f0; + border: 1px solid #999; + box-shadow: 0 10px 30px rgba(0,0,0,0.4); + position: absolute; + padding: 8px; + display: flex; + flex-direction: column; + font-family: "Segoe UI", "MS Sans Serif", sans-serif; + font-size: 9pt; + } + #modal-hotkeys .title-bar { + height: 30px; + background: white; + border-bottom: 1px solid #ccc; + display: flex; + align-items: center; + padding-left: 10px; + font-size: 12px; + color: #000; + margin: -8px -8px 8px -8px; + } + #modal-hotkeys .close-btn { + margin-left: auto; + width: 32px; + height: 30px; + display: flex; + align-items: center; + justify-content: center; + font-size: 16px; + } + #modal-hotkeys .close-btn:hover { background-color: #e81123; color: white; } + #modal-hotkeys .content { + flex: 1; + display: flex; + flex-direction: column; + gap: 8px; + } + /* Toolbar customization modal */ + #modal-toolbar .window { + width: 430px; + background-color: #f0f0f0; + border: 1px solid #999; + box-shadow: 0 0 15px rgba(0,0,0,0.35); + display: flex; + flex-direction: column; + } + #modal-toolbar .title-bar { + height: 26px; + background-color: #ffffff; + display: flex; + align-items: center; + justify-content: space-between; + padding: 0 8px; + font-size: 11px; + border-bottom: 1px solid #cfcfcf; + } + #modal-toolbar .close-btn { + width: 36px; + height: 24px; + display: flex; + align-items: center; + justify-content: center; + cursor: pointer; + color: #111; + } + #modal-toolbar .close-btn:hover { + background-color: #e81123; + color: #fff; + } + #modal-toolbar .content { + padding: 6px 8px 8px 8px; + display: flex; + flex-direction: column; + gap: 6px; + } + #modal-toolbar .toolbar-subtitle { + font-size: 11px; + color: #555; + } + #modal-toolbar .toolbar-list { + border: 1px solid #d0d0d0; + background: #ffffff; + padding: 6px; + display: flex; + flex-direction: column; + gap: 6px; + max-height: 320px; + overflow: auto; + } + #modal-toolbar .toolbar-row { + display: grid; + grid-template-columns: 1fr 90px 70px; + gap: 8px; + align-items: center; + font-size: 11px; + padding: 2px 0; + } + #modal-toolbar .toolbar-header { + font-weight: 600; + color: #444; + border-bottom: 1px solid #e0e0e0; + padding-bottom: 4px; + } + #modal-toolbar select { + height: 20px; + font-size: 11px; + } + #modal-toolbar .toolbar-empty { + color: #666; + font-size: 11px; + padding: 6px 2px; + } + #modal-toolbar .footer { + display: flex; + justify-content: flex-end; + gap: 8px; + padding: 8px 10px 10px; + border-top: 1px solid #d9d9d9; + background-color: #f0f0f0; + } + /* Updates modal */ + #modal-update .window { + width: 520px; + max-width: calc(100vw - 34px); + max-height: calc(100vh - 48px); + background-color: #f0f0f0; + border: 1px solid #999; + box-shadow: 0 0 15px rgba(0,0,0,0.35); + display: flex; + flex-direction: column; + font-family: "Segoe UI", "MS Sans Serif", sans-serif; + font-size: 11px; + } + #modal-update .title-bar { + height: 26px; + background-color: #ffffff; + display: flex; + align-items: center; + justify-content: space-between; + padding: 0 8px; + font-size: 11px; + border-bottom: 1px solid #cfcfcf; + cursor: move; + user-select: none; + } + #modal-update .close-btn { + width: 36px; + height: 24px; + display: flex; + align-items: center; + justify-content: center; + cursor: pointer; + color: #111; + position: relative; + } + #modal-update .close-btn:hover { background-color: #e81123; color: #fff; } + #modal-update .close-btn .x { + width: 12px; + height: 12px; + display: block; + position: relative; + } + #modal-update .close-btn .x::before, + #modal-update .close-btn .x::after { + content: ""; + position: absolute; + left: 50%; + top: 50%; + width: 14px; + height: 2px; + background: currentColor; + transform-origin: center; + border-radius: 2px; + transform: translate(-50%, -50%) rotate(45deg); + } + #modal-update .close-btn .x::after { + transform: translate(-50%, -50%) rotate(-45deg); + } + #modal-update .content { + padding: 10px; + display: flex; + flex-direction: column; + gap: 10px; + min-height: 0; + } + #modal-update .update-status { + border: 1px solid #d0d0d0; + background: #ffffff; + padding: 8px 10px; + border-radius: 3px; + font-size: 12px; + color: #1f1f1f; + line-height: 1.25; + } + #modal-update .update-status.is-checking { background: #fffdf0; border-color: #e3d6a0; } + #modal-update .update-status.is-available { background: #f1fbf2; border-color: #9fd2a4; } + #modal-update .update-status.is-ok { background: #f2f7ff; border-color: #9abbe9; } + #modal-update .update-status.is-warn { background: #fff8e6; border-color: #e6c37a; } + #modal-update .update-status.is-error { background: #fff3f3; border-color: #e2a0a0; } + #modal-update .update-progress { + height: 3px; + background: #e6e6e6; + border-radius: 999px; + overflow: hidden; + } + #modal-update .update-progress .bar { + width: 35%; + height: 100%; + background: var(--toggle-icon-color); + animation: update-indeterminate 1.1s ease-in-out infinite; + } + @keyframes update-indeterminate { + 0% { transform: translateX(-120%); } + 100% { transform: translateX(320%); } + } + #modal-update .update-meta { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 10px; + } + #modal-update .update-card { + border: 1px solid #d0d0d0; + background: #ffffff; + padding: 8px 10px; + border-radius: 3px; + min-width: 0; + } + #modal-update .update-card-k { font-size: 11px; color: #666; } + #modal-update .update-card-v { + margin-top: 2px; + font-size: 13px; + font-weight: 700; + color: #222; + font-family: Consolas, "Courier New", monospace; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + #modal-update .update-notes-wrap { + border: 1px solid #d0d0d0; + background: #ffffff; + border-radius: 3px; + min-height: 0; + display: flex; + flex-direction: column; + } + #modal-update .update-notes-title { + padding: 7px 10px 6px; + border-bottom: 1px solid #e4e4e4; + color: #555; + font-size: 11px; + } + #modal-update .update-notes { + padding: 8px 10px; + height: 240px; + overflow: auto; + white-space: normal; + font-size: 12px; + line-height: 1.35; + color: #222; + overflow-wrap: anywhere; + } + #modal-update .update-notes .empty { + color: #666; + } + #modal-update .update-notes h1, + #modal-update .update-notes h2, + #modal-update .update-notes h3, + #modal-update .update-notes h4 { + margin: 10px 0 6px 0; + font-family: "Segoe UI", "MS Sans Serif", sans-serif; + color: #111; + line-height: 1.15; + } + #modal-update .update-notes h1 { font-size: 18px; } + #modal-update .update-notes h2 { font-size: 16px; } + #modal-update .update-notes h3 { font-size: 14px; } + #modal-update .update-notes h4 { font-size: 13px; } + #modal-update .update-notes p { margin: 6px 0; } + #modal-update .update-notes ul, + #modal-update .update-notes ol { margin: 6px 0 6px 18px; padding: 0; } + #modal-update .update-notes li { margin: 2px 0; } + #modal-update .update-notes a { color: #0b61c3; text-decoration: underline; } + #modal-update .update-notes code { + font-family: Consolas, "Courier New", monospace; + background: #f1f1f1; + border: 1px solid #e3e3e3; + border-radius: 3px; + padding: 0 4px; + font-size: 11px; + } + #modal-update .update-notes pre { + background: #f6f6f6; + border: 1px solid #e0e0e0; + border-radius: 4px; + padding: 8px 10px; + overflow: auto; + margin: 8px 0; + white-space: pre; + line-height: 1.35; + } + #modal-update .update-notes pre code { + background: transparent; + border: 0; + padding: 0; + font-size: 11px; + } + #modal-update .footer { + display: flex; + justify-content: flex-end; + align-items: center; + gap: 8px; + padding: 8px 10px 10px; + border-top: 1px solid #d9d9d9; + background-color: #f0f0f0; + } + #modal-update .footer .spacer { flex: 1; } + #modal-update .footer .btn { + height: 24px; + padding: 0 10px; + border: 1px solid #adadad; + background-color: #e1e1e1; + font-family: inherit; + font-size: 12px; + cursor: pointer; + border-radius: 2px; + } + #modal-update .footer .btn:hover { background-color: #e5f1fb; border-color: var(--toggle-icon-color); } + #modal-update .footer .btn.btn-primary { + background: #fff; + border: 1px solid #0078d7; + box-shadow: inset 0 0 0 1px #0078d7; + } + #modal-update .footer .btn.btn-primary:hover { background-color: #e5f1fb; border-color: #1084d9; } + @media (max-width: 560px) { + #modal-update .update-meta { grid-template-columns: 1fr; } + #modal-update .update-notes { height: 200px; } + } + .hotkey-toolbar { + display: flex; + gap: 8px; + align-items: center; + justify-content: space-between; + } + .hotkey-toolbar .btn { + height: 22px; + padding: 0 8px; + background: #e1e1e1; + border: 1px solid #adadad; + border-radius: 3px; + font-family: inherit; + font-size: 9pt; + } + .hotkey-list { + flex: 1; + overflow: auto; + border: 1px solid #d0d0d0; + background: white; + padding: 4px; + display: grid; + grid-template-columns: 1fr; + gap: 4px; + } + body.dark-mode .hotkey-list { + background: #0f1012; + border-color: #1f2124; + } + body.dark-mode .hotkey-row { + border-bottom-color: #1f2124; + } + .hotkey-row { + display: grid; + grid-template-columns: 1.2fr 1fr 1fr; + gap: 6px; + align-items: center; + border-bottom: 1px solid #eee; + padding-bottom: 4px; + } + .hotkey-label { color: #222; } + /* Clean, consistent sliders */ + input[type="range"] { + -webkit-appearance: none; + width: 100%; + height: 18px; + background: transparent; + } + input[type="range"]:focus { outline: none; } + input[type="range"]::-webkit-slider-runnable-track { + height: 4px; + background: #d6d6d6; + border-radius: 2px; + border: none; + } + input[type="range"]::-webkit-slider-thumb { + -webkit-appearance: none; + width: 12px; + height: 16px; + border-radius: 2px; + background: var(--win-blue); + border: none; + margin-top: -6px; + } + input[type="range"]::-moz-range-track { + height: 4px; + background: #d6d6d6; + border-radius: 2px; + border: none; + } + input[type="range"]::-moz-range-progress { + height: 4px; + background: #bcdcff; + border-radius: 2px; + } + input[type="range"]::-moz-range-thumb { + width: 12px; + height: 16px; + border-radius: 2px; + background: var(--win-blue); + border: none; + } + body.dark-mode input[type="range"]::-webkit-slider-runnable-track, + body.dark-mode input[type="range"]::-moz-range-track { + background: #2b2d31; + } + body.dark-mode input[type="range"]::-moz-range-progress { + background: #2f5f8f; + } + /* ═══════════════════════════════════════════════════════════════ + TEST MODE β€” proper dark theme + ═══════════════════════════════════════════════════════════════ */ + body.test-mode { + /* core surface scale β€” darkest to lightest */ + --tm-s0: #141414; /* deepest bg */ + --tm-s1: #1c1c1c; /* app bg */ + --tm-s2: #222222; /* titlebar / tab row */ + --tm-s3: #272727; /* ribbon */ + --tm-s4: #2e2e2e; /* panels / section bg */ + --tm-s5: #363636; /* hover bg */ + --tm-s6: #3e3e3e; /* active / selected */ + --tm-s7: #484848; /* borders */ + --tm-s8: #585858; /* lighter borders */ + /* text */ + --tm-t1: #e8e8e8; /* primary text */ + --tm-t2: #999999; /* secondary / labels */ + --tm-t3: #666666; /* muted */ + /* accent β€” neutral warm silver */ + --tm-a1: #a8a8a8; /* icons, highlights */ + --tm-a2: #505050; /* primary-button bg */ + --tm-hover-bg: rgba(255,255,255,0.06); + --tm-hover-border: rgba(255,255,255,0.18); + --tm-selected-bg: rgba(255,255,255,0.09); + --tm-selected-border: rgba(255,255,255,0.26); + } + + /* ── root variable overrides ── */ + body.test-mode { + --bg-ribbon: var(--tm-s3); + --border-ribbon: var(--tm-s7); + --app-text-color: var(--tm-t1); + --app-bg: var(--tm-s1); + --titlebar-bg: var(--tm-s2); + --titlebar-action-icon: var(--tm-t2); + --titlebar-action-hover-bg: var(--tm-s5); + --titlebar-separator: var(--tm-s7); + --titlebar-filename: var(--tm-t1); + --titlebar-control-icon: var(--tm-t1); + --tab-row-bg: var(--tm-s3); + --section-divider: var(--tm-s7); + --section-title-color: var(--tm-t2); + --btn-hover-bg: var(--tm-hover-bg); + --btn-hover-border: var(--tm-hover-border); + --btn-hover-shadow: rgba(255,255,255,0.06); + --btn-active-bg: var(--tm-selected-bg); + --btn-active-border: var(--tm-selected-border); + --btn-active-shadow: rgba(255,255,255,0.10); + --dropdown-bg: var(--tm-s4); + --dropdown-border: var(--tm-s8); + --dropdown-shadow: rgba(0,0,0,0.5); + --dropdown-item-hover-bg: var(--tm-s5); + --dropdown-arrow-color: var(--tm-t2); + --dropdown-separator: var(--tm-s7); + --btn-small-bg: var(--tm-s4); + --btn-small-border: var(--tm-s7); + --threshold-label-color: var(--tm-t2); + --threshold-values-color: var(--tm-t1); + --toggle-icon-color: var(--tm-a1); + --toggle-status-color: var(--tm-t2); + --hotkeys-icon-color: var(--tm-a1); + --anchor-toggle-icon-color: var(--tm-a1); + --theme-mode-toggle-icon-color: var(--tm-a1); + --select-menu-header-color: var(--tm-t2); + --select-menu-header-bg: var(--tm-s4); + --select-menu-icon-all-fill: rgba(255,255,255,0.10); + --select-menu-icon-all-fill-disabled: var(--tm-s5); + --select-menu-icon-disabled-stroke: var(--tm-t3); + --theme-colors-window-bg: var(--tm-s3); + --theme-colors-titlebar-bg-start: var(--tm-s4); + --theme-colors-titlebar-bg-end: var(--tm-s3); + --theme-colors-titlebar-border: var(--tm-s7); + --theme-colors-top-note-color: var(--tm-t2); + --theme-colors-result-count-color: var(--tm-t2); + --theme-colors-list-bg: var(--tm-s3); + --theme-colors-editor-panel-bg-start: var(--tm-s4); + --theme-colors-editor-panel-bg-end: var(--tm-s3); + --theme-colors-editor-panel-border: var(--tm-s7); + --theme-colors-editor-title-color: var(--tm-t1); + --theme-colors-editor-key-color: var(--tm-t1); + --theme-colors-editor-input-bg: var(--tm-s5); + --theme-colors-editor-input-border: var(--tm-s8); + --theme-colors-editor-swatch-border: var(--tm-s8); + --theme-colors-editor-hint-color: var(--tm-t3); + --theme-colors-mini-toggle-color: var(--tm-t1); + --palette-mini-swatch-border: #050505; + --palette-mini-swatch-inner: #ffffff; + --palette-mini-swatch-hover-border: var(--tm-a1); + --palette-mini-swatch-hover-inner: rgba(255,255,255,0.12); + --view-center-icon-color: var(--tm-a1); + --view-edgeclean-icon-color: var(--tm-a1); + --view-theme-icon-color: var(--tm-a1); + --select-icon-free-color: var(--tm-a1); + --select-icon-poly-main-color: var(--tm-a1); + --select-icon-poly-accent-color: #c0c0c0; + --bg-hover: var(--tm-hover-bg); + --border-hover: var(--tm-hover-border); + --bg-selected: var(--tm-selected-bg); + --border-selected: var(--tm-selected-border); + --bg-canvas: #3c3c3c; + --win-blue: var(--tm-a1); + } + + /* ── body + core layout ── */ + body.test-mode { background: var(--tm-s1); color: var(--tm-t1); } + + /* ── title bar ── */ + body.test-mode #title-bar { background: var(--tm-s2); border-bottom: none; } + body.test-mode .tab-row { background: var(--tm-s3); border-bottom-color: var(--tm-s7); border-top: 1px solid var(--tm-s1); color: var(--tm-t1); } + body.test-mode .tab { color: var(--tm-t2); border-color: transparent; } + body.test-mode .tab:not(.file):not(.active):hover { color: var(--tm-t1); background: var(--tm-s5); border-color: var(--tm-s7); } + body.test-mode .tab.active { background: var(--tm-s3); border-color: var(--tm-s7); border-bottom-color: var(--tm-s3); color: var(--tm-t1); } + body.test-mode .tab-row .dd-arrow { color: var(--tm-t1); } + body.test-mode .tab.file { background: var(--tm-s6); color: var(--tm-t1); border-color: var(--tm-s8); } + body.test-mode .tab.file:hover { background: var(--tm-s7); } + + /* ── ribbon ── */ + body.test-mode .ribbon { background: var(--tm-s3); border-bottom: 1px solid var(--tm-s7); } + body.test-mode .section { border-right-color: var(--tm-s7); } + body.test-mode .section-title { color: var(--tm-t3); } + body.test-mode .btn-large { color: var(--tm-t1); } + body.test-mode .btn-large:hover { background: var(--tm-s5); border-color: var(--tm-s7); } + body.test-mode .btn-large.active, + body.test-mode .btn-large.is-on { background: var(--tm-selected-bg); border-color: var(--tm-selected-border); } + body.test-mode .toggle-status { color: var(--tm-t2); } + body.test-mode .toggle-btn .toggle-icons { color: var(--tm-a1); } + body.test-mode #anchor-toggle-btn .toggle-icons { color: var(--tm-a1); } + body.test-mode #theme-mode-btn .toggle-icons { color: var(--tm-a1); } + body.test-mode #test-mode-btn .toggle-icons { color: var(--tm-a1); } + body.test-mode svg [fill="#0078d7"] { fill: var(--tm-a1); } + body.test-mode svg [stroke="#0078d7"] { stroke: var(--tm-a1); } + + /* ribbon card */ + body.test-mode .ribbon-card { background: var(--tm-s4); border-color: var(--tm-s7); color: var(--tm-t1); } + body.test-mode .ribbon-card .card-label { color: var(--tm-t1); } + body.test-mode .ribbon-card .mini-label { color: var(--tm-t2); } + body.test-mode .compact-input { background: var(--tm-s4); border-color: var(--tm-s8); color: var(--tm-t1); } + body.test-mode .ribbon-card.tile-compact .compact-input { background: var(--tm-s4); border-bottom-color: var(--tm-s8); color: var(--tm-t1); } + body.test-mode .ribbon-card.tile-compact .compact-input:focus { border-bottom-color: var(--tm-a1); } + body.test-mode .ribbon-card .compact-input:focus { border-bottom-color: var(--tm-a1); } + body.test-mode #pen-size-input { background: var(--tm-s4); border-bottom-color: var(--tm-s8); color: var(--tm-t1); } + body.test-mode #pen-size-input:focus { border-bottom-color: var(--tm-a1); } + body.test-mode #size-control-wrap label { color: var(--tm-t2) !important; } + + /* ── dropdown menus ── */ + body.test-mode .dropdown-panel, + body.test-mode .paint-dropdown { background: var(--tm-s4); border-color: var(--tm-s7); box-shadow: 0 4px 16px rgba(0,0,0,0.5); } + body.test-mode .dropdown-item, + body.test-mode .paint-dropdown-item { color: var(--tm-t1); } + body.test-mode .dropdown-item:hover, + body.test-mode .paint-dropdown-item:hover { background: var(--tm-s5); } + body.test-mode .dropdown-separator { background: var(--tm-s7); } + + /* ── modals β€” shared window chrome ── */ + body.test-mode .modal-mask { background: rgba(0,0,0,0.55); } + body.test-mode #modal-resize .window, + body.test-mode #modal-depth .window, + body.test-mode #modal-export .window, + body.test-mode #modal-huesat .window, + body.test-mode #modal-hotkeys .window, + body.test-mode #modal-info .window, + body.test-mode #modal-colors .window, + body.test-mode #modal-confirm-reset .window, + body.test-mode #modal-toolbar .window, + body.test-mode #modal-wincolor .window, + body.test-mode .modal-window { + background: var(--tm-s3); + border-color: var(--tm-s7); + color: var(--tm-t1); + box-shadow: 0 12px 40px rgba(0,0,0,0.6); + } + + /* modal title bars */ + body.test-mode #modal-resize .title-bar, + body.test-mode #modal-depth .title-bar, + body.test-mode #modal-export .title-bar, + body.test-mode #modal-huesat .title-bar, + body.test-mode #modal-hotkeys .title-bar, + body.test-mode #modal-info .title-bar, + body.test-mode #modal-colors .title-bar, + body.test-mode #modal-confirm-reset .title-bar, + body.test-mode #modal-toolbar .title-bar, + body.test-mode #modal-wincolor .title-bar { + background: var(--tm-s4); + border-bottom-color: var(--tm-s7); + color: var(--tm-t1); + } + body.test-mode .close-btn { color: var(--tm-t2); } + body.test-mode .close-btn:hover { background: #c42b1c; color: #fff; } + + /* modal footers */ + body.test-mode #modal-resize .footer, + body.test-mode #modal-depth .footer, + body.test-mode #modal-export .footer, + body.test-mode #modal-huesat .footer, + body.test-mode #modal-hotkeys .footer, + body.test-mode #modal-colors .footer { + border-top-color: var(--tm-s7); + } + + /* modal buttons */ + body.test-mode .modal-mask .btn, + body.test-mode .modal-mask button.btn { + background: var(--tm-s5); + border-color: var(--tm-s8); + color: var(--tm-t1); + } + body.test-mode .modal-mask .btn:hover { background: var(--tm-s6); border-color: var(--tm-s8); } + body.test-mode .modal-mask .btn-primary { background: var(--tm-s6); border-color: var(--tm-s8); color: var(--tm-t1); } + body.test-mode .modal-mask .btn-primary:hover { background: var(--tm-s7); border-color: var(--tm-a1); } + body.test-mode .modal-mask .btn-ok { background: var(--tm-s6); border-color: var(--tm-s8); color: var(--tm-t1); } + body.test-mode .modal-mask .btn-ok:hover { background: var(--tm-s7); border-color: var(--tm-a1); } + + /* modal inputs */ + body.test-mode .modal-mask input[type="text"], + body.test-mode .modal-mask input[type="number"], + body.test-mode .modal-mask select, + body.test-mode .modal-mask textarea { + background: var(--tm-s5); + border-color: var(--tm-s8); + color: var(--tm-t1); + } + body.test-mode .modal-mask input[type="text"]:focus, + body.test-mode .modal-mask input[type="number"]:focus, + body.test-mode .modal-mask select:focus { border-color: var(--tm-a1); outline: none; } + body.test-mode .modal-mask label, + body.test-mode .modal-mask .row label { color: var(--tm-t1); } + body.test-mode .modal-mask fieldset { border-color: var(--tm-s7); } + body.test-mode .modal-mask legend { color: var(--tm-t2); } + body.test-mode .modal-mask .section-header { color: var(--tm-t2); border-bottom-color: var(--tm-s7); } + + /* ── modal-depth specific ── */ + body.test-mode #modal-depth { --win-bg: var(--tm-s3); --win-text: var(--tm-t1); --input-border: var(--tm-s8); --input-focus: var(--tm-a1); --btn-border: var(--tm-s8); --btn-hover: var(--tm-s5); } + body.test-mode #modal-depth .btn { background: var(--tm-s5); border-color: var(--tm-s8); color: var(--tm-t1); } + body.test-mode #modal-depth .btn:hover { background: var(--tm-s6); border-color: var(--tm-a1); } + body.test-mode #modal-depth .btn-primary { background: var(--tm-s6); border-color: var(--tm-s8); color: var(--tm-t1); } + body.test-mode #modal-depth .btn-primary:hover { background: var(--tm-s7); border-color: var(--tm-a1); } + body.test-mode #modal-depth .depth-radio { background: var(--tm-s5); border-color: var(--tm-s8); color: var(--tm-t1); } + body.test-mode #modal-depth .depth-color-list input[type="radio"]:checked + .depth-radio { background: var(--tm-s6); border-color: var(--tm-a1); color: var(--tm-t1); } + body.test-mode #modal-depth .depth-group-label { color: var(--tm-t2); } + + /* ── modal-huesat specific ── */ + body.test-mode #modal-huesat { --win-bg: var(--tm-s3); --win-text: var(--tm-t1); --input-border: var(--tm-s8); --input-focus: var(--tm-a1); --btn-border: var(--tm-s8); --btn-hover: var(--tm-s5); } + body.test-mode #modal-huesat .channel-area { --hs-area-bg: var(--tm-s4); background: var(--tm-s4); border-color: var(--tm-s7); } + body.test-mode #modal-huesat .channel-label { color: var(--tm-t2); } + body.test-mode #modal-huesat .channel-btn { filter: brightness(0.9); } + body.test-mode #modal-huesat .channel-wrap.active { background: transparent; } + body.test-mode #modal-huesat .master-btn { background: var(--tm-s6); border-color: var(--tm-s8); color: var(--tm-t1); } + body.test-mode #modal-huesat .master-btn.active { background: var(--tm-t1); color: var(--tm-s1); border-color: var(--tm-t1); } + body.test-mode #modal-huesat .preset-row { background: var(--tm-s4); border-color: var(--tm-s7); } + body.test-mode #modal-huesat .preset-row label { color: var(--tm-t2); } + + /* ── modal-resize specific ── */ + body.test-mode #modal-resize { --win-bg: var(--tm-s3); --win-text: var(--tm-t1); } + body.test-mode #modal-resize .col-label { color: var(--tm-t1); } + + + /* ── modal-export specific ── */ + body.test-mode #modal-export { --win-bg: var(--tm-s3); --input-border: var(--tm-s8); --input-focus: var(--tm-a1); --btn-border: var(--tm-s8); --btn-hover: var(--tm-s5); } + body.test-mode #modal-export .export-format-btn { background: var(--tm-s5); border-color: var(--tm-s7); color: var(--tm-t1); } + body.test-mode #modal-export .export-format-btn.active { background: var(--tm-s6); border-color: var(--tm-a1); color: var(--tm-t1); } + + /* ── modal-colors (theme colors) specific ── */ + body.test-mode #modal-colors .window { border-color: var(--tm-s7); } + body.test-mode #modal-colors .close-btn { color: var(--tm-t1); } + body.test-mode #modal-colors .select-hint { color: var(--tm-t2); } + body.test-mode #modal-colors .color-list { border-color: var(--tm-s7); } + body.test-mode #modal-colors .color-item:hover { background: var(--tm-s5); border-color: var(--tm-s7); } + body.test-mode #modal-colors .color-item.is-active { background: var(--tm-selected-bg); border-color: var(--tm-selected-border); } + body.test-mode #modal-colors .color-label { color: var(--tm-t1); } + body.test-mode #modal-colors .color-element-label { color: var(--tm-t2); } + body.test-mode #modal-colors .color-input { background: var(--tm-s5); border-color: var(--tm-s8); color: var(--tm-t1); } + body.test-mode #modal-colors .color-input.invalid { border-color: #e81123; background: rgba(232,17,35,0.15); } + body.test-mode #modal-colors .preset-select, + body.test-mode #modal-colors .preset-input, + body.test-mode #modal-colors .search-input { background: var(--tm-s5); border-color: var(--tm-s8); color: var(--tm-t1); } + body.test-mode #modal-colors .btn { background: var(--tm-s5); border-color: var(--tm-s8); color: var(--tm-t1); } + body.test-mode #modal-colors .btn:hover { background: var(--tm-s6); border-color: var(--tm-a1); color: var(--tm-t1); } + body.test-mode #modal-colors .editor-grid label { color: var(--tm-t2); } + body.test-mode #modal-colors .editor-grid input[type="number"] { background: var(--tm-s5); border-color: var(--tm-s8); color: var(--tm-t1); } + body.test-mode #modal-colors .color-item { border-bottom-color: var(--tm-s7); } + body.test-mode #modal-colors .color-label { color: var(--tm-t1); } + body.test-mode #modal-colors .color-element-label { color: var(--tm-t2); } + body.test-mode #modal-colors .preset-row { background: var(--tm-s4); border-color: var(--tm-s7); } + body.test-mode #modal-colors .preset-select { background: var(--tm-s5); border-color: var(--tm-s8); color: var(--tm-t1); } + body.test-mode #modal-colors .preset-input { background: var(--tm-s5); border-color: var(--tm-s8); color: var(--tm-t1); } + + /* ── modal-hotkeys ── */ + body.test-mode .hotkey-list { background: var(--tm-s4); border-color: var(--tm-s7); } + body.test-mode .hotkey-row { border-bottom-color: var(--tm-s7); } + body.test-mode .hotkey-label { color: var(--tm-t1); } + body.test-mode .hotkeys-icon { color: var(--tm-a1); } + + /* ── modal-info ── */ + body.test-mode #modal-info .info-section { border-bottom-color: var(--tm-s7); } + body.test-mode #modal-info .info-title { color: var(--tm-a1); } + body.test-mode #modal-info li, + body.test-mode #modal-info p { color: var(--tm-t1); } + body.test-mode #modal-info .link-btn { color: var(--tm-a1); } + + /* ── file menu ── */ + body.test-mode #file-menu.file-menu-template { background: var(--tm-s3); border-color: var(--tm-s7); box-shadow: 2px 4px 16px rgba(0,0,0,0.5); } + body.test-mode #file-menu .file-menu-left { background: var(--tm-s4); border-right-color: var(--tm-s7); } + body.test-mode #file-menu .file-menu-item { color: var(--tm-t1); } + body.test-mode #file-menu .file-menu-item:hover { background: var(--tm-s5); border-color: var(--tm-s7); } + body.test-mode #file-menu .file-menu-separator { background: var(--tm-s7); } + body.test-mode #file-menu .file-menu-right { background: var(--tm-s3); } + body.test-mode #file-menu .file-menu-recent-toggle { background: var(--tm-s4); border-color: var(--tm-s7); color: var(--tm-t2); } + body.test-mode #file-menu .file-menu-recent-toggle:hover { background: var(--tm-s5); color: var(--tm-t1); } + body.test-mode #file-menu.file-menu-template.recent-collapsed .file-menu-recent-toggle { border-right: 1px solid var(--tm-s7); border-left: none; } + body.test-mode #file-menu .file-menu-recent-header { color: var(--tm-t1); border-bottom-color: var(--tm-s7); } + body.test-mode #file-menu .file-menu-recent-item { color: var(--tm-t2); } + body.test-mode #file-menu .file-menu-recent-item:hover { background: var(--tm-s5); color: var(--tm-t1); } + + /* ── select menu ── */ + body.test-mode .select-menu { background: var(--tm-s4); border-color: var(--tm-s7); box-shadow: 0 4px 16px rgba(0,0,0,0.5); } + body.test-mode .select-menu-header { background: var(--tm-s4); color: var(--tm-t2); border-bottom-color: var(--tm-s7); } + body.test-mode .select-menu-item { color: var(--tm-t1); } + body.test-mode .select-menu-item:hover { background: var(--tm-s5); } + + /* ── sliders ── */ + body.test-mode input[type="range"]::-webkit-slider-runnable-track, + body.test-mode input[type="range"]::-moz-range-track { background: var(--tm-s6); } + body.test-mode input[type="range"]::-moz-range-progress { background: var(--tm-a2); } + body.test-mode input[type="range"]::-webkit-slider-thumb { background: var(--tm-a1); } + body.test-mode input[type="range"]::-moz-range-thumb { background: var(--tm-a1); } + + /* ── save reminder / hotkey panel ── */ + body.test-mode #save-reminder-modal .window, + body.test-mode #close-confirm-modal .window { background: var(--tm-s3); border-color: var(--tm-s7); color: var(--tm-t1); } + + /* ── layer panel ── */ + body.test-mode #lsys-panel { background: var(--tm-s3); border-color: var(--tm-s7); } + body.test-mode #lsys-list { background: var(--tm-s4); } + body.test-mode .lsys-layer { background: var(--tm-s4); border-bottom-color: var(--tm-s7); color: var(--tm-t1); } + body.test-mode .lsys-layer.active { background: var(--tm-s5); } + body.test-mode .lsys-layer-name { color: var(--tm-t1); } + body.test-mode #lsys-toolbar { background: var(--tm-s3); border-top-color: var(--tm-s7); } + body.test-mode .lsys-btn { color: var(--tm-t1); } + body.test-mode .lsys-btn:hover { background: var(--tm-s5); } + + /* ── status bar / bottom bar ── */ + body.test-mode #status-bar, + body.test-mode .status-bar { background: var(--tm-s2); border-top-color: var(--tm-s7); color: var(--tm-t2); } + + /* ── palette area ── */ + body.test-mode .mini-swatch.empty { box-shadow: none; } + body.test-mode #palette-bar, + body.test-mode .palette-bar { background: var(--tm-s3); border-top-color: var(--tm-s7); } + + /* ── modal-wincolor ── */ + body.test-mode #modal-wincolor .window { background: var(--tm-s3); border-color: var(--tm-s7); } + body.test-mode #modal-wincolor .tab-btn { background: var(--tm-s5); border-color: var(--tm-s7); color: var(--tm-t1); } + body.test-mode #modal-wincolor .tab-btn.active { background: var(--tm-s6); border-color: var(--tm-a1); color: var(--tm-t1); } + + /* ── swap-colors button (inline styles override via specificity) ── */ + body.test-mode #swap-colors-btn { background: var(--tm-s4) !important; border-color: var(--tm-s7) !important; color: var(--tm-t1); } + body.test-mode #swap-colors-btn:hover { background: var(--tm-s5) !important; border-color: var(--tm-s8) !important; } + + /* ════════════════════════════════════════════════════════════════ + * DARK REFINED MODE β€” lighter, purple-grey tinted dark theme + * Ribbon: #43434A | Title bar: #1F1F22 + * ════════════════════════════════════════════════════════════════ */ + body.dark-refined-mode { + /* core surface scale */ + --dr-s0: #17171A; /* deepest bg */ + --dr-s1: #1A1A1E; /* app bg */ + --dr-s2: #1F1F22; /* titlebar */ + --dr-s3: #43434A; /* ribbon / tab row */ + --dr-s4: #4E4E56; /* panels / section bg */ + --dr-s5: #56565F; /* hover bg */ + --dr-s6: #5E5E68; /* active / selected */ + --dr-s7: #6A6A75; /* borders */ + --dr-s8: #7A7A86; /* lighter borders */ + /* text */ + --dr-t1: #EAEAEA; /* primary text */ + --dr-t2: #A0A0AE; /* secondary / labels */ + --dr-t3: #72727E; /* muted */ + /* accent β€” softer blue */ + --dr-a1: #6AADEE; /* links, highlights */ + --dr-a2: #2F68A4; /* active borders */ + --dr-hover-bg: rgba(106,173,238,0.10); + --dr-hover-border: rgba(106,173,238,0.30); + --dr-selected-bg: rgba(106,173,238,0.15); + --dr-selected-border: rgba(106,173,238,0.40); + } + + /* ── root variable overrides ── */ + body.dark-refined-mode { + --bg-ribbon: var(--dr-s3); + --border-ribbon: var(--dr-s7); + --app-text-color: var(--dr-t1); + --app-bg: var(--dr-s1); + --titlebar-bg: var(--dr-s2); + --titlebar-action-icon: var(--dr-t2); + --titlebar-action-hover-bg: var(--dr-s5); + --titlebar-separator: var(--dr-s7); + --titlebar-filename: var(--dr-t1); + --titlebar-control-icon: var(--dr-t1); + --tab-row-bg: var(--dr-s3); + --section-divider: var(--dr-s7); + --section-title-color: var(--dr-t2); + --btn-hover-bg: var(--dr-hover-bg); + --btn-hover-border: var(--dr-hover-border); + --btn-hover-shadow: rgba(106,173,238,0.15); + --btn-active-bg: var(--dr-selected-bg); + --btn-active-border: var(--dr-selected-border); + --btn-active-shadow: rgba(106,173,238,0.25); + --dropdown-bg: var(--dr-s4); + --dropdown-border: var(--dr-s8); + --dropdown-shadow: rgba(0,0,0,0.45); + --dropdown-item-hover-bg: var(--dr-s5); + --dropdown-arrow-color: var(--dr-t2); + --dropdown-separator: var(--dr-s7); + --btn-small-bg: var(--dr-s4); + --btn-small-border: var(--dr-s7); + --threshold-label-color: var(--dr-t2); + --threshold-values-color: var(--dr-t1); + --toggle-icon-color: var(--dr-a1); + --toggle-status-color: var(--dr-t2); + --hotkeys-icon-color: var(--dr-a1); + --anchor-toggle-icon-color: var(--dr-a1); + --theme-mode-toggle-icon-color: var(--dr-a1); + --select-menu-header-color: var(--dr-t2); + --select-menu-header-bg: var(--dr-s4); + --select-menu-icon-all-fill: rgba(106,173,238,0.18); + --select-menu-icon-all-fill-disabled: var(--dr-s5); + --select-menu-icon-disabled-stroke: var(--dr-t3); + --theme-colors-window-bg: var(--dr-s3); + --theme-colors-titlebar-bg-start: var(--dr-s4); + --theme-colors-titlebar-bg-end: var(--dr-s3); + --theme-colors-titlebar-border: var(--dr-s7); + --theme-colors-top-note-color: var(--dr-t2); + --theme-colors-result-count-color: var(--dr-t2); + --theme-colors-list-bg: var(--dr-s3); + --theme-colors-editor-panel-bg-start: var(--dr-s4); + --theme-colors-editor-panel-bg-end: var(--dr-s3); + --theme-colors-editor-panel-border: var(--dr-s7); + --theme-colors-editor-title-color: var(--dr-t1); + --theme-colors-editor-key-color: var(--dr-t1); + --theme-colors-editor-input-bg: var(--dr-s5); + --theme-colors-editor-input-border: var(--dr-s8); + --theme-colors-editor-swatch-border: var(--dr-s8); + --theme-colors-editor-hint-color: var(--dr-t3); + --theme-colors-mini-toggle-color: var(--dr-t1); + --palette-mini-swatch-border: #050507; + --palette-mini-swatch-inner: #ffffff; + --palette-mini-swatch-hover-border: var(--dr-a1); + --palette-mini-swatch-hover-inner: rgba(106,173,238,0.2); + --view-center-icon-color: var(--dr-a1); + --view-edgeclean-icon-color: var(--dr-a1); + --view-theme-icon-color: var(--dr-a1); + --select-icon-free-color: var(--dr-a1); + --select-icon-poly-main-color: var(--dr-a1); + --select-icon-poly-accent-color: #80c0f4; + --bg-hover: var(--dr-hover-bg); + --border-hover: var(--dr-hover-border); + --bg-selected: var(--dr-selected-bg); + --border-selected: var(--dr-selected-border); + --bg-canvas: #4a4a52; + --win-blue: var(--dr-a1); + } + + /* ── body + core layout ── */ + body.dark-refined-mode { background: var(--dr-s1); color: var(--dr-t1); } + + /* ── title bar ── */ + body.dark-refined-mode #title-bar { background: var(--dr-s2); border-bottom: none; } + body.dark-refined-mode .tab-row { background: var(--dr-s3); border-bottom-color: var(--dr-s7); border-top: 1px solid var(--dr-s2); color: var(--dr-t1); } + body.dark-refined-mode .tab { color: var(--dr-t2); border-color: transparent; } + body.dark-refined-mode .tab:not(.file):not(.active):hover { color: var(--dr-t1); background: var(--dr-s5); border-color: var(--dr-s7); } + body.dark-refined-mode .tab.active { background: var(--dr-s3); border-color: var(--dr-s7); border-bottom-color: var(--dr-s3); color: var(--dr-t1); } + body.dark-refined-mode .tab-row .dd-arrow { color: var(--dr-t1); } + + /* ── ribbon ── */ + body.dark-refined-mode .ribbon { background: var(--dr-s3); border-bottom: 1px solid var(--dr-s7); } + body.dark-refined-mode .section { border-right-color: var(--dr-s7); } + body.dark-refined-mode .section-title { color: var(--dr-t3); } + body.dark-refined-mode .btn-large { color: var(--dr-t1); } + body.dark-refined-mode .btn-large:hover { background: var(--dr-s5); border-color: var(--dr-s7); } + body.dark-refined-mode .btn-large.active, + body.dark-refined-mode .btn-large.is-on { background: var(--dr-selected-bg); border-color: var(--dr-selected-border); } + body.dark-refined-mode .toggle-status { color: var(--dr-t2); } + body.dark-refined-mode .toggle-btn .toggle-icons { color: var(--dr-a1); } + body.dark-refined-mode #anchor-toggle-btn .toggle-icons { color: var(--dr-a1); } + body.dark-refined-mode #theme-mode-btn .toggle-icons { color: var(--dr-a1); } + body.dark-refined-mode #test-mode-btn .toggle-icons { color: var(--dr-a1); } + body.dark-refined-mode #dark-refined-btn .toggle-icons { color: var(--dr-a1); } + body.dark-refined-mode svg [fill="#0078d7"] { fill: var(--dr-a1); } + body.dark-refined-mode svg [stroke="#0078d7"] { stroke: var(--dr-a1); } + + /* ribbon card */ + body.dark-refined-mode .ribbon-card { background: var(--dr-s4); border-color: var(--dr-s7); color: var(--dr-t1); } + body.dark-refined-mode .ribbon-card .card-label { color: var(--dr-t1); } + body.dark-refined-mode .ribbon-card .mini-label { color: var(--dr-t2); } + body.dark-refined-mode .compact-input { background: var(--dr-s5); border-color: var(--dr-s8); color: var(--dr-t1); } + + /* ── dropdown menus ── */ + body.dark-refined-mode .dropdown-panel, + body.dark-refined-mode .paint-dropdown { background: var(--dr-s4); border-color: var(--dr-s7); box-shadow: 0 4px 16px rgba(0,0,0,0.45); } + body.dark-refined-mode .dropdown-item, + body.dark-refined-mode .paint-dropdown-item { color: var(--dr-t1); } + body.dark-refined-mode .dropdown-item:hover, + body.dark-refined-mode .paint-dropdown-item:hover { background: var(--dr-s5); } + body.dark-refined-mode .dropdown-separator { background: var(--dr-s7); } + + /* ── modals β€” shared window chrome ── */ + body.dark-refined-mode .modal-mask { background: rgba(0,0,0,0.50); } + body.dark-refined-mode #modal-resize .window, + body.dark-refined-mode #modal-depth .window, + body.dark-refined-mode #modal-export .window, + body.dark-refined-mode #modal-huesat .window, + body.dark-refined-mode #modal-hotkeys .window, + body.dark-refined-mode #modal-info .window, + body.dark-refined-mode #modal-colors .window, + body.dark-refined-mode #modal-confirm-reset .window, + body.dark-refined-mode #modal-toolbar .window, + body.dark-refined-mode #modal-wincolor .window, + body.dark-refined-mode .modal-window { + background: var(--dr-s3); + border-color: var(--dr-s7); + color: var(--dr-t1); + box-shadow: 0 12px 40px rgba(0,0,0,0.5); + } + + /* modal title bars */ + body.dark-refined-mode #modal-resize .title-bar, + body.dark-refined-mode #modal-depth .title-bar, + body.dark-refined-mode #modal-export .title-bar, + body.dark-refined-mode #modal-huesat .title-bar, + body.dark-refined-mode #modal-hotkeys .title-bar, + body.dark-refined-mode #modal-info .title-bar, + body.dark-refined-mode #modal-colors .title-bar, + body.dark-refined-mode #modal-confirm-reset .title-bar, + body.dark-refined-mode #modal-toolbar .title-bar, + body.dark-refined-mode #modal-wincolor .title-bar { + background: var(--dr-s4); + border-bottom-color: var(--dr-s7); + color: var(--dr-t1); + } + body.dark-refined-mode .close-btn { color: var(--dr-t2); } + body.dark-refined-mode .close-btn:hover { background: #c42b1c; color: #fff; } + + /* modal footers */ + body.dark-refined-mode #modal-resize .footer, + body.dark-refined-mode #modal-depth .footer, + body.dark-refined-mode #modal-export .footer, + body.dark-refined-mode #modal-huesat .footer, + body.dark-refined-mode #modal-hotkeys .footer, + body.dark-refined-mode #modal-colors .footer { + border-top-color: var(--dr-s7); + } + + /* modal buttons */ + body.dark-refined-mode .modal-mask .btn, + body.dark-refined-mode .modal-mask button.btn { + background: var(--dr-s5); + border-color: var(--dr-s8); + color: var(--dr-t1); + } + body.dark-refined-mode .modal-mask .btn:hover { background: var(--dr-s6); border-color: var(--dr-a2); } + body.dark-refined-mode .modal-mask .btn-primary { background: var(--dr-a2); border-color: #1a5090; color: #fff; } + body.dark-refined-mode .modal-mask .btn-primary:hover { background: #2070b8; } + body.dark-refined-mode .modal-mask .btn-ok { background: var(--dr-a2); border-color: #1a5090; color: #fff; } + body.dark-refined-mode .modal-mask .btn-ok:hover { background: #2070b8; } + + /* modal inputs */ + body.dark-refined-mode .modal-mask input[type="text"], + body.dark-refined-mode .modal-mask input[type="number"], + body.dark-refined-mode .modal-mask select, + body.dark-refined-mode .modal-mask textarea { + background: var(--dr-s5); + border-color: var(--dr-s8); + color: var(--dr-t1); + } + body.dark-refined-mode .modal-mask input[type="text"]:focus, + body.dark-refined-mode .modal-mask input[type="number"]:focus, + body.dark-refined-mode .modal-mask select:focus { border-color: var(--dr-a1); outline: none; } + body.dark-refined-mode .modal-mask label, + body.dark-refined-mode .modal-mask .row label { color: var(--dr-t1); } + body.dark-refined-mode .modal-mask fieldset { border-color: var(--dr-s7); } + body.dark-refined-mode .modal-mask legend { color: var(--dr-t2); } + body.dark-refined-mode .modal-mask .section-header { color: var(--dr-t2); border-bottom-color: var(--dr-s7); } + + /* modal-depth */ + body.dark-refined-mode #modal-depth { --win-bg: var(--dr-s3); --win-text: var(--dr-t1); --input-border: var(--dr-s8); --input-focus: var(--dr-a1); --btn-border: var(--dr-s8); --btn-hover: var(--dr-s5); } + body.dark-refined-mode #modal-depth .btn { background: var(--dr-s5); border-color: var(--dr-s8); color: var(--dr-t1); } + body.dark-refined-mode #modal-depth .btn:hover { background: var(--dr-s6); border-color: var(--dr-a1); } + body.dark-refined-mode #modal-depth .btn-primary { background: var(--dr-a2); border-color: #1a5090; color: #fff; } + body.dark-refined-mode #modal-depth .btn-primary:hover { background: #2070b8; } + body.dark-refined-mode #modal-depth .depth-radio { background: var(--dr-s5); border-color: var(--dr-s8); color: var(--dr-t1); } + body.dark-refined-mode #modal-depth .depth-color-list input[type="radio"]:checked + .depth-radio { background: var(--dr-a2); border-color: var(--dr-a1); color: #fff; } + body.dark-refined-mode #modal-depth .depth-group-label { color: var(--dr-t2); } + + /* modal-huesat */ + body.dark-refined-mode #modal-huesat { --win-bg: var(--dr-s3); --win-text: var(--dr-t1); --input-border: var(--dr-s8); --input-focus: var(--dr-a1); --btn-border: var(--dr-s8); --btn-hover: var(--dr-s5); } + body.dark-refined-mode #modal-huesat .channel-area { --hs-area-bg: var(--dr-s4); background: var(--dr-s4); border-color: var(--dr-s7); } + body.dark-refined-mode #modal-huesat .channel-label { color: var(--dr-t2); } + body.dark-refined-mode #modal-huesat .channel-btn { filter: brightness(0.9); } + body.dark-refined-mode #modal-huesat .channel-wrap.active { background: transparent; } + body.dark-refined-mode #modal-huesat .master-btn { background: var(--dr-s6); border-color: var(--dr-s8); color: var(--dr-t1); } + body.dark-refined-mode #modal-huesat .master-btn.active { background: var(--dr-t1); color: var(--dr-s1); border-color: var(--dr-t1); } + body.dark-refined-mode #modal-huesat .preset-row { background: var(--dr-s4); border-color: var(--dr-s7); } + body.dark-refined-mode #modal-huesat .preset-row label { color: var(--dr-t2); } + body.dark-refined-mode #modal-huesat .btn { background: var(--dr-s5); border-color: var(--dr-s8); color: var(--dr-t1); } + body.dark-refined-mode #modal-huesat .btn:hover { background: var(--dr-s6); border-color: var(--dr-a1); } + body.dark-refined-mode #modal-huesat .btn-primary { background: var(--dr-a2); border-color: #1a5090; color: #fff; } + body.dark-refined-mode #modal-huesat .btn-primary:hover { background: #2070b8; } + + /* modal-resize */ + body.dark-refined-mode #modal-resize { --win-bg: var(--dr-s3); --win-text: var(--dr-t1); } + body.dark-refined-mode #modal-resize .col-label { color: var(--dr-t1); } + + + /* modal-export */ + body.dark-refined-mode #modal-export { --win-bg: var(--dr-s3); --input-border: var(--dr-s8); --input-focus: var(--dr-a1); --btn-border: var(--dr-s8); --btn-hover: var(--dr-s5); } + body.dark-refined-mode #modal-export .export-format-btn { background: var(--dr-s5); border-color: var(--dr-s7); color: var(--dr-t1); } + body.dark-refined-mode #modal-export .export-format-btn.active { background: var(--dr-a2); border-color: var(--dr-a1); color: #fff; } + + /* modal-colors */ + body.dark-refined-mode #modal-colors .window { border-color: var(--dr-s7); } + body.dark-refined-mode #modal-colors .close-btn { color: var(--dr-t1); } + body.dark-refined-mode #modal-colors .select-hint { color: var(--dr-t2); } + body.dark-refined-mode #modal-colors .color-list { border-color: var(--dr-s7); } + body.dark-refined-mode #modal-colors .color-item:hover { background: var(--dr-s5); border-color: var(--dr-s7); } + body.dark-refined-mode #modal-colors .color-item.is-active { background: var(--dr-selected-bg); border-color: var(--dr-selected-border); } + body.dark-refined-mode #modal-colors .color-label { color: var(--dr-t1); } + body.dark-refined-mode #modal-colors .color-element-label { color: var(--dr-t2); } + body.dark-refined-mode #modal-colors .color-input { background: var(--dr-s5); border-color: var(--dr-s8); color: var(--dr-t1); } + body.dark-refined-mode #modal-colors .color-input.invalid { border-color: #e81123; background: rgba(232,17,35,0.15); } + body.dark-refined-mode #modal-colors .preset-select, + body.dark-refined-mode #modal-colors .preset-input, + body.dark-refined-mode #modal-colors .search-input { background: var(--dr-s5); border-color: var(--dr-s8); color: var(--dr-t1); } + body.dark-refined-mode #modal-colors .btn { background: var(--dr-s5); border-color: var(--dr-s8); color: var(--dr-t1); } + body.dark-refined-mode #modal-colors .btn:hover { background: var(--dr-s6); border-color: var(--dr-a1); color: var(--dr-t1); } + body.dark-refined-mode #modal-colors .editor-grid label { color: var(--dr-t2); } + body.dark-refined-mode #modal-colors .editor-grid input[type="number"] { background: var(--dr-s5); border-color: var(--dr-s8); color: var(--dr-t1); } + body.dark-refined-mode #modal-colors .color-item { border-bottom-color: var(--dr-s7); } + body.dark-refined-mode #modal-colors .preset-row { background: var(--dr-s4); border-color: var(--dr-s7); } + body.dark-refined-mode #modal-colors .preset-select { background: var(--dr-s5); border-color: var(--dr-s8); color: var(--dr-t1); } + body.dark-refined-mode #modal-colors .preset-input { background: var(--dr-s5); border-color: var(--dr-s8); color: var(--dr-t1); } + + /* modal-hotkeys */ + body.dark-refined-mode .hotkey-list { background: var(--dr-s4); border-color: var(--dr-s7); } + body.dark-refined-mode .hotkey-row { border-bottom-color: var(--dr-s7); } + body.dark-refined-mode .hotkey-label { color: var(--dr-t1); } + body.dark-refined-mode .hotkeys-icon { color: var(--dr-a1); } + + /* modal-info */ + body.dark-refined-mode #modal-info .info-section { border-bottom-color: var(--dr-s7); } + body.dark-refined-mode #modal-info .info-title { color: var(--dr-a1); } + body.dark-refined-mode #modal-info li, + body.dark-refined-mode #modal-info p { color: var(--dr-t1); } + body.dark-refined-mode #modal-info .link-btn { color: var(--dr-a1); } + + /* file menu */ + body.dark-refined-mode #file-menu.file-menu-template { background: var(--dr-s3); border-color: var(--dr-s7); box-shadow: 2px 4px 16px rgba(0,0,0,0.45); } + body.dark-refined-mode #file-menu .file-menu-left { background: var(--dr-s4); border-right-color: var(--dr-s7); } + body.dark-refined-mode #file-menu .file-menu-item { color: var(--dr-t1); } + body.dark-refined-mode #file-menu .file-menu-item:hover { background: var(--dr-s5); border-color: var(--dr-s7); } + body.dark-refined-mode #file-menu .file-menu-separator { background: var(--dr-s7); } + body.dark-refined-mode #file-menu .file-menu-right { background: var(--dr-s3); } + body.dark-refined-mode #file-menu .file-menu-recent-toggle { background: var(--dr-s4); border-color: var(--dr-s7); color: var(--dr-t2); } + body.dark-refined-mode #file-menu .file-menu-recent-toggle:hover { background: var(--dr-s5); color: var(--dr-t1); } + body.dark-refined-mode #file-menu.file-menu-template.recent-collapsed .file-menu-recent-toggle { border-right: 1px solid var(--dr-s7); border-left: none; } + body.dark-refined-mode #file-menu .file-menu-recent-header { color: var(--dr-t1); border-bottom-color: var(--dr-s7); } + body.dark-refined-mode #file-menu .file-menu-recent-item { color: var(--dr-t2); } + body.dark-refined-mode #file-menu .file-menu-recent-item:hover { background: var(--dr-s5); color: var(--dr-t1); } + + /* select menu */ + body.dark-refined-mode .select-menu { background: var(--dr-s4); border-color: var(--dr-s7); box-shadow: 0 4px 16px rgba(0,0,0,0.45); } + body.dark-refined-mode .select-menu-header { background: var(--dr-s4); color: var(--dr-t2); border-bottom-color: var(--dr-s7); } + body.dark-refined-mode .select-menu-item { color: var(--dr-t1); } + body.dark-refined-mode .select-menu-item:hover { background: var(--dr-s5); } + + /* sliders */ + body.dark-refined-mode input[type="range"]::-webkit-slider-runnable-track, + body.dark-refined-mode input[type="range"]::-moz-range-track { background: var(--dr-s6); } + body.dark-refined-mode input[type="range"]::-moz-range-progress { background: var(--dr-a2); } + body.dark-refined-mode input[type="range"]::-webkit-slider-thumb { background: var(--dr-a1); } + body.dark-refined-mode input[type="range"]::-moz-range-thumb { background: var(--dr-a1); } + + /* save reminder / close confirm */ + body.dark-refined-mode #save-reminder-modal .window, + body.dark-refined-mode #close-confirm-modal .window { background: var(--dr-s3); border-color: var(--dr-s7); color: var(--dr-t1); } + + /* layer panel */ + body.dark-refined-mode #lsys-panel { background: var(--dr-s3); border-color: var(--dr-s7); } + body.dark-refined-mode #lsys-list { background: var(--dr-s4); } + body.dark-refined-mode .lsys-layer { background: var(--dr-s4); border-bottom-color: var(--dr-s7); color: var(--dr-t1); } + body.dark-refined-mode .lsys-layer.active { background: var(--dr-s5); } + body.dark-refined-mode .lsys-layer-name { color: var(--dr-t1); } + body.dark-refined-mode #lsys-toolbar { background: var(--dr-s3); border-top-color: var(--dr-s7); } + body.dark-refined-mode .lsys-btn { color: var(--dr-t1); } + body.dark-refined-mode .lsys-btn:hover { background: var(--dr-s5); } + + /* status bar */ + body.dark-refined-mode #status-bar, + body.dark-refined-mode .status-bar { background: var(--dr-s2); border-top-color: var(--dr-s7); color: var(--dr-t2); } + + /* palette area */ + body.dark-refined-mode .mini-swatch.empty { box-shadow: none; } + body.dark-refined-mode #palette-bar, + body.dark-refined-mode .palette-bar { background: var(--dr-s3); border-top-color: var(--dr-s7); } + + /* modal-wincolor */ + body.dark-refined-mode #modal-wincolor .window { background: var(--dr-s3); border-color: var(--dr-s7); } + body.dark-refined-mode #modal-wincolor .tab-btn { background: var(--dr-s5); border-color: var(--dr-s7); color: var(--dr-t1); } + body.dark-refined-mode #modal-wincolor .tab-btn.active { background: var(--dr-a2); color: #fff; } + + /* swap-colors button */ + body.dark-refined-mode #swap-colors-btn { background: var(--dr-s4) !important; border-color: var(--dr-s7) !important; color: var(--dr-t1); } + body.dark-refined-mode #swap-colors-btn:hover { background: var(--dr-s5) !important; border-color: var(--dr-s8) !important; } + + /* ── active color slot selection highlight ── */ + body.test-mode .active-color-col.selected { background: var(--tm-selected-bg); border-color: var(--tm-selected-border); } + body.test-mode .active-color-col:not(.selected):hover { background: var(--tm-hover-bg); border-color: var(--tm-hover-border); box-shadow: none; } + + /* ── select tool split button selection highlight ── */ + body.test-mode .split-btn-container.select-split.selection-highlight { border-color: var(--tm-selected-border); } + body.test-mode .split-btn-container.select-split.selection-highlight .split-btn-top, + body.test-mode .split-btn-container.select-split.selection-highlight .split-btn-bottom.select-dropdown { background: var(--tm-selected-bg); } + body.test-mode .split-btn-container.select-split .split-btn-bottom.select-dropdown.selection-highlight { border-top-color: var(--tm-selected-border); } + body.test-mode .split-btn-container.select-split:hover { border-color: var(--tm-hover-border); background: var(--tm-hover-bg); box-shadow: none; } + body.test-mode .split-btn-container.select-split:hover .split-btn-bottom.select-dropdown { border-top-color: var(--tm-hover-border); background: var(--tm-hover-bg); box-shadow: none; } + + /* ── select-menu dropdown (overrides its own local vars) ── */ + body.test-mode #select-menu .icon-free, + body.test-mode #select-menu .icon-poly, + body.test-mode #select-menu .icon-invert { filter: grayscale(1) brightness(1.4); } + body.test-mode #select-menu { --bg-color: var(--tm-s4); --border-outer: var(--tm-s7); --header-text: var(--tm-t2); --text-color: var(--tm-t1); --disabled-text: var(--tm-t3); --separator: var(--tm-s7); --item-hover-bg: var(--tm-s5); --item-hover-border: var(--tm-s8); --item-select-bg: var(--tm-selected-bg); --item-select-border: var(--tm-selected-border); --icon-stroke: var(--tm-a1); --select-menu-icon-delete-stroke: #c06060; box-shadow: 2px 2px 8px rgba(0,0,0,0.5); } + + /* ── depth reduction modal ── */ + body.test-mode #modal-depth .depth-radio { background: var(--tm-s5); border-color: var(--tm-s8); } + body.test-mode #modal-depth #custom-depth-val { background: transparent; color: var(--tm-t1); } + + /* ── hue/sat modal buttons ── */ + body.test-mode #modal-huesat .btn { background: var(--tm-s5); border-color: var(--tm-s8); color: var(--tm-t1); } + body.test-mode #modal-huesat .btn:hover { background: var(--tm-s6); border-color: var(--tm-a1); } + body.test-mode #modal-huesat .btn-primary { background: var(--tm-s6); border-color: var(--tm-s8); color: var(--tm-t1); } + body.test-mode #modal-huesat .btn-primary:hover { background: var(--tm-s7); border-color: var(--tm-a1); } + + /* ── modal-colors small buttons ── */ + body.test-mode #modal-colors .btn-small { background: var(--tm-s5); border-color: var(--tm-s8); color: var(--tm-t1); } + body.test-mode #modal-colors .btn-small:hover { background: var(--tm-s6); } + body.test-mode #modal-colors .theme-select-btn.is-on { background: var(--tm-s6); border-color: var(--tm-a1); color: var(--tm-t1); } + + .hotkey-field { + display: flex; + gap: 6px; + align-items: center; + } + .hotkey-input { + width: 120px; + height: 18px; + border: 1px solid #7a7a7a; + padding: 0 4px; + background: #fff; + font-family: inherit; + font-size: 9pt; + } + .hotkey-input.capture { + border-color: #7a7a7a; + box-shadow: none; + } + .hotkey-input-wrap { position: relative; display: inline-block; --capture-progress: 1; } + .hotkey-input-wrap.capture::after { + content: ""; + position: absolute; + inset: -1px; + border: 1px solid #0078d7; + transform-origin: right center; + transform: scaleX(var(--capture-progress)); + pointer-events: none; + } + .hotkey-btn { + height: 18px; + padding: 0 4px; + background: #ffffff; + border: 1px solid #adadad; + border-radius: 2px; + font-size: 9pt; + cursor: pointer; + } + .hotkey-btn.set:hover { background: #0078d7; border-color: var(--toggle-icon-color); color: #ffffff; } + .hotkey-btn.clear:hover { background: #d83b01; border-color: #d83b01; color: #ffffff; } + .hotkey-note { + color: #666; + font-size: 11px; + } + #modal-hotkeys.modal-mask { + align-items: flex-start; + overflow: auto; + padding: 10px 0; + } + #modal-colors .window { + position: relative; + width: 860px; + height: 600px; + display: flex; + flex-direction: column; + background: var(--theme-colors-window-bg); + border: 1px solid #999; + box-shadow: 0 12px 30px rgba(0,0,0,0.22); + pointer-events: auto; + } + #modal-colors.modal-mask { + align-items: center; + justify-content: center; + overflow: auto; + background: transparent; + pointer-events: none; + } + #modal-colors .title-bar { + background: linear-gradient(180deg, var(--theme-colors-titlebar-bg-start) 0%, var(--theme-colors-titlebar-bg-end) 100%); + border-bottom: 1px solid var(--theme-colors-titlebar-border); + height: 30px; + display: flex; + align-items: center; + justify-content: space-between; + padding-left: 10px; + font-size: 12px; + font-weight: 600; + } + #modal-colors .close-btn { + width: 40px; + height: 30px; + display: flex; + justify-content: center; + align-items: center; + cursor: pointer; + font-size: 13px; + color: #111; + } + #modal-colors .close-btn:hover { + background-color: #e81123; + color: white; + } + #modal-colors .content { + padding: 10px 12px 0 12px; + flex: 1; + display: flex; + flex-direction: column; + gap: 6px; + overflow: hidden; + min-height: 0; + } + #modal-colors .top-note { + font-size: 11px; + color: var(--theme-colors-top-note-color); + } + #modal-colors .search-row { + display: flex; + align-items: center; + gap: 6px; + } + #modal-colors .select-row { + display: flex; + align-items: center; + gap: 6px; + min-height: 22px; + } + #modal-colors .select-hint { + font-size: 11px; + color: #555; + line-height: 1.2; + } + #modal-colors .preset-row { + display: flex; + align-items: center; + gap: 6px; + flex-wrap: wrap; + } + #modal-colors .actions-row { + display: flex; + align-items: center; + gap: 8px; + flex-wrap: wrap; + min-height: 24px; + } + #modal-colors .actions-row .spacer { flex: 1; } + #modal-colors .main-layout { + flex: 1; + min-height: 0; + display: grid; + grid-template-columns: minmax(300px, 1fr) 270px; + gap: 10px; + } + #modal-colors .preset-select { + height: 22px; + padding: 0 6px; + border: 1px solid #bdbdbd; + font-size: 11px; + font-family: inherit; + min-width: 200px; + } + #modal-colors .preset-input { + height: 22px; + padding: 0 6px; + border: 1px solid #bdbdbd; + font-size: 11px; + font-family: inherit; + width: 130px; + } + #modal-colors .search-input { + flex: 1; + height: 24px; + padding: 0 6px; + border: 1px solid #bdbdbd; + font-size: 12px; + font-family: inherit; + } + #modal-colors .result-count { + font-size: 11px; + color: var(--theme-colors-result-count-color); + min-width: 56px; + text-align: right; + } + #modal-colors .color-list { + flex: 1; + overflow: auto; + border: 1px solid #d0d0d0; + background: var(--theme-colors-list-bg); + padding: 6px; + min-height: 0; + } + #modal-colors .color-item { + display: flex; + align-items: center; + gap: 4px; + padding: 5px 4px; + font-size: 11px; + flex-wrap: wrap; + border-radius: 4px; + border: 1px solid transparent; + transition: background-color 120ms ease, border-color 120ms ease; + } + #modal-colors .color-item:hover { + background: #f7fbff; + border-color: #d7e7fb; + } + #modal-colors .color-item.is-active { + background: #e8f3ff; + border-color: #93bce8; + } + #modal-colors .color-swatch { + width: 16px; + height: 16px; + border: 1px solid #666; + background: transparent; + flex-shrink: 0; + } + #modal-colors .color-label { + width: 86px; + font-family: Consolas, 'Courier New', monospace; + color: #333; + flex-shrink: 0; + } + #modal-colors .color-element-label { + flex: 1; + color: #555; + min-width: 110px; + } + #modal-colors .color-input { + width: 120px; + height: 20px; + padding: 0 6px; + border: 1px solid #bdbdbd; + font-size: 11px; + font-family: inherit; + background: #f9f9f9; + } + #modal-colors .color-input.invalid { + border-color: #e81123; + background: #fff4f4; + } + #modal-colors .footer { + padding: 8px 10px 10px 10px; + display: flex; + justify-content: space-between; + align-items: center; + gap: 6px; + } + #modal-colors .btn { + height: 22px; + padding: 0 10px; + background-color: #ffffff; + border: 1px solid #adadad; + font-family: inherit; + font-size: 9pt; + cursor: pointer; + border-radius: 2px; + outline: none; + } + #modal-colors .btn:hover { background-color: #e5f1fb; border-color: #0078d7; } + #modal-colors .btn:active { background-color: #cce4f7; border-color: #005499; } + #modal-colors .btn:focus-visible { box-shadow: 0 0 0 2px #0078d7; } + #modal-colors .btn-small { + height: 20px; + padding: 0 6px; + font-size: 10px; + } + #modal-colors .theme-select-btn.is-on { + background-color: var(--toggle-icon-color); + border-color: #005a9e; + color: #fff; + } + #modal-colors .editor-panel { + border: 1px solid var(--theme-colors-editor-panel-border); + background: linear-gradient(180deg, var(--theme-colors-editor-panel-bg-start) 0%, var(--theme-colors-editor-panel-bg-end) 100%); + padding: 8px; + min-height: 0; + display: flex; + flex-direction: column; + gap: 8px; + } + #modal-colors .editor-title { + display: flex; + align-items: center; + justify-content: space-between; + font-size: 11px; + color: var(--theme-colors-editor-title-color); + } + #modal-colors .editor-preview { + display: flex; + align-items: center; + gap: 8px; + } + #modal-colors .editor-swatch { + width: 38px; + height: 38px; + border: 1px solid var(--theme-colors-editor-swatch-border); + background: #ffffff; + box-shadow: inset 0 0 0 1px #ffffff; + flex-shrink: 0; + } + #modal-colors .editor-key { + font-size: 11px; + color: var(--theme-colors-editor-key-color); + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + #modal-colors .editor-input { + width: 100%; + height: 24px; + border: 1px solid var(--theme-colors-editor-input-border); + padding: 0 6px; + font-size: 12px; + font-family: Consolas, 'Courier New', monospace; + background: var(--theme-colors-editor-input-bg); + } + #modal-colors .editor-grid { + display: grid; + grid-template-columns: 22px 1fr 44px; + gap: 4px; + align-items: center; + } + #modal-colors .editor-grid label { + font-size: 11px; + color: #555; + text-align: right; + } + #modal-colors .editor-grid input[type="range"] { width: 100%; margin: 0; } + #modal-colors .editor-grid input[type="number"] { + width: 44px; + height: 20px; + border: 1px solid #bdbdbd; + font-size: 11px; + padding: 0 2px; + text-align: right; + background: #fff; + } + #modal-colors .kbd-hint { + font-size: 10px; + color: var(--theme-colors-editor-hint-color); + line-height: 1.35; + } + #modal-colors .mini-toggle { + font-size: 11px; + color: var(--theme-colors-mini-toggle-color); + display: inline-flex; + align-items: center; + gap: 4px; + } + #modal-colors .color-item.is-picked { + background: #eef6ff; + border: 1px solid #9fc4ea; + border-radius: 2px; + } + .color-preview-highlight { + outline: 2px dashed #0078d7 !important; + outline-offset: 2px; + } + body.theme-select-mode #title-bar, + body.theme-select-mode .tab-row, + body.theme-select-mode #ribbon, + body.theme-select-mode #ribbon-view, + body.theme-select-mode #ribbon-themes, + body.theme-select-mode #ribbon-debug, + body.theme-select-mode #canvas-stage { + cursor: crosshair; + } + body.theme-select-mode .theme-select-candidate { + outline: 2px dashed #0078d7 !important; + outline-offset: 2px; + } + + /* Handles Container */ + #selection-controls { position: absolute; z-index: 1000; pointer-events: none; display: none; } + + #sel-hit-area { + position: absolute; + top: 0; left: 0; width: 100%; height: 100%; + background: transparent; + pointer-events: auto; + cursor: move; + z-index: 999; + } + #sel-rot-border { + position: absolute; + left: 0; + top: 0; + width: 100%; + height: 100%; + pointer-events: none; + display: none; + z-index: 998; + --rot-border-thickness: 1px; + --rot-border-step: 4px; + background-image: + repeating-linear-gradient(90deg, #ffffff 0, #ffffff calc(var(--rot-border-step) / 2), #1b6fe5 calc(var(--rot-border-step) / 2), #1b6fe5 var(--rot-border-step)), + repeating-linear-gradient(90deg, #ffffff 0, #ffffff calc(var(--rot-border-step) / 2), #1b6fe5 calc(var(--rot-border-step) / 2), #1b6fe5 var(--rot-border-step)), + repeating-linear-gradient(0deg, #ffffff 0, #ffffff calc(var(--rot-border-step) / 2), #1b6fe5 calc(var(--rot-border-step) / 2), #1b6fe5 var(--rot-border-step)), + repeating-linear-gradient(0deg, #ffffff 0, #ffffff calc(var(--rot-border-step) / 2), #1b6fe5 calc(var(--rot-border-step) / 2), #1b6fe5 var(--rot-border-step)); + background-repeat: no-repeat; + background-size: + 100% var(--rot-border-thickness), + 100% var(--rot-border-thickness), + var(--rot-border-thickness) 100%, + var(--rot-border-thickness) 100%; + background-position: + left top, + left calc(100% - var(--rot-border-thickness)), + left top, + calc(100% - var(--rot-border-thickness)) top; + } + #selection-controls.selection-rotated #sel-rot-border { display: block; } + #sel-rot-center { + position: absolute; + left: 0; + top: 0; + width: 6px; + height: 6px; + background: #e81123; + border: 1px solid #ffffff; + border-radius: 50%; + pointer-events: none; + display: none; + z-index: 1001; + box-shadow: 0 0 0 1px rgba(0,0,0,0.25); + } + #selection-controls.selection-rotating #sel-rot-center { display: none; } + #picker-hotspot { + position: fixed; + width: 1px; + height: 1px; + background: #ff0000; + z-index: 10002; + pointer-events: none; + display: none; + } + + + .sel-handle { + position: absolute; + width: 6px; + height: 6px; + background: transparent; + border: none; + pointer-events: auto; + z-index: 1001; + overflow: hidden; + } + .sel-handle img { + width: 100%; + height: 100%; + display: block; + pointer-events: none; + image-rendering: pixelated; + image-rendering: crisp-edges; + -moz-image-rendering: crisp; + } + .sel-rotate-handle { + position: absolute; + top: 0; + left: 0; + width: 20px; + height: 20px; + display: flex; + align-items: center; + justify-content: center; + background: transparent; + border: none; + border-radius: 0; + pointer-events: auto; + cursor: grab; + z-index: 1002; + overflow: visible; + image-rendering: pixelated; + -moz-image-rendering: crisp; + } + .sel-rotate-handle:active { cursor: grabbing; } + .sel-rotate-handle.anchor-mode { + background: rgba(232, 17, 35, 0.18); + border-radius: 50%; + outline: 2px solid #e81123; + outline-offset: 1px; + cursor: grab; + } + .sel-rotate-handle.anchor-mode:active { cursor: grabbing; } + #selection-controls.sel-anchor-mode .sel-handle { pointer-events: none; opacity: 0.35; } + #selection-controls.sel-anchor-mode #sel-hit-area { pointer-events: none; cursor: default; } + .sel-rotate-handle img { + width: auto; + height: auto; + display: block; + pointer-events: none; + } + #selection-controls.no-handles .sel-handle, + #selection-controls.no-handles .sel-rotate-handle { display: none; } + #selection-controls.no-handles .path-handle { display: none; } + #selection-controls.no-handles #sel-hit-area { pointer-events: none; } + + .h-nw { top: 0; left: 0; cursor: nwse-resize; } .h-n { top: 0; left: 50%; cursor: ns-resize; } .h-ne { top: 0; left: 100%; cursor: nesw-resize; } + + .h-w { top: 50%; left: 0; cursor: ew-resize; } .h-e { top: 50%; left: 100%; cursor: ew-resize; } .h-sw { top: 100%; left: 0; cursor: nesw-resize; } + .h-s { top: 100%; left: 50%; cursor: ns-resize; } .h-se { top: 100%; left: 100%; cursor: nwse-resize; } + + .creating .sel-handle, + .creating .sel-rotate-handle, + .creating #sel-rot-border { display: none; } + .creating .path-handle { display: none; } + + .path-handle { + position: absolute; + width: 6px; + height: 6px; + background: #3aa0ff; + border: 1px solid #0b3d6d; + box-shadow: 0 0 0 1px rgba(255,255,255,0.6) inset; + pointer-events: auto; + z-index: 1002; + } + .path-handle.ctrl { + background: #ffffff; + border: 1px solid #3aa0ff; + box-shadow: none; + } + #path-handles { + position: absolute; + left: 0; + top: 0; + width: 100%; + height: 100%; + pointer-events: none; + } + + + #canvas-resize-handles { position: absolute; top: 0; left: 0; width: 100%; height: 100%; pointer-events: none; z-index: 1002; } + .resizer { position: absolute; width: 6px; height: 6px; background: white; border: 1px solid black; z-index: 40; pointer-events: auto; } + .r-right { cursor: ew-resize; } + .r-left { cursor: ew-resize; } + .r-top { cursor: ns-resize; } + .r-bottom { cursor: ns-resize; } + .r-corner { cursor: nwse-resize; } + .r-tl { cursor: nwse-resize; } + .r-tr { cursor: nesw-resize; } + .r-bl { cursor: nesw-resize; } + .resizer.free-only { display: none; } + #viewport.free-canvas .resizer.free-only { display: block; } + + /* Common */ + .color-area { display: flex; gap: 6px; height: 60px; align-items: flex-start; } + + .active-color-col { display: flex; flex-direction: column; align-items: center; gap: 0px; cursor: pointer; padding: 4px; border: 1px solid transparent; border-radius: 2px; width: 48px; height: 72px; } + + .active-color-col.selected { background: #cce8ff; border: 1px solid #66a7e8; } + .active-color-col:not(.selected):hover { background: #eaf4ff; border: 1px solid #9fc4ea; box-shadow: inset 0 0 2px rgba(0,120,215,0.15); } + .selection-highlight { background: #cce8ff; border-color: #66a7e8; } + .big-swatch { + width: 30px; + height: 30px; + border: 1px solid #a0a0a0; + box-shadow: inset 0 0 0 1px #ffffff; + background: black; + } + .palette-container { display:flex; flex-direction: column; gap:2px; margin-left: 4px; } + .palette-grid { display: grid; grid-template-columns: repeat(10, 16px); gap: 4px; } + #palette-std { margin-top: 5px; } + .mini-swatch { + width: 16px !important; + height: 16px !important; + background: white; + cursor: pointer; + border: 1px solid var(--palette-mini-swatch-border); + box-shadow: inset 0 0 0 1px var(--palette-mini-swatch-inner); + box-sizing: content-box; + } + .mini-swatch:hover { + border: 1px solid var(--palette-mini-swatch-hover-border); + box-shadow: inset 0 0 0 1px var(--palette-mini-swatch-hover-inner); + } + .mini-swatch.empty { + background: transparent; + pointer-events: none; + } + .mini-swatch.empty:hover { + border: 1px solid var(--palette-mini-swatch-border); + box-shadow: inset 0 0 0 1px var(--palette-mini-swatch-inner); + } + + #status-bar { height: 24px; background: #f0f0f0; border-top: 1px solid #ccc; display: flex; align-items: center; padding: 0 10px; gap: 15px; font-size: 11px; z-index: 9001; } + #status-primary { display: flex; align-items: center; gap: 0; } + .status-segment { + width: 155px; + min-width: 155px; + max-width: 155px; + height: 18px; + padding: 0 6px; + display: flex; + align-items: center; + box-sizing: border-box; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + } + .status-segment + .status-segment { border-left: 1px solid #c8c8c8; } + #status-right { display: flex; align-items: center; gap: 15px; } + #status-reminder { color: #a40000; font-weight: 600; } + #grid-overlay { + position: fixed; + left: 0; + top: 0; + width: 100vw; + height: 100vh; + pointer-events: none; + display: none; + z-index: 5; + } + #grid-overlay path { + fill: none; + stroke-width: 1px; + stroke-opacity: 1; + vector-effect: non-scaling-stroke; + shape-rendering: crispEdges; + } + #tile-overlay { + position: fixed; + left: 0; + top: 0; + width: 100vw; + height: 100vh; + pointer-events: none; + display: none; + z-index: 4; + } + .gridline-color-swatch { + width: 12px; + height: 12px; + border: 1px solid #666; + display: inline-block; + vertical-align: middle; + margin-left: 4px; + } + .gridline { + fill: none; + vector-effect: non-scaling-stroke; + shape-rendering: crispEdges; + } + #save-reminder-toast { + position: fixed; + right: 12px; + bottom: 36px; + padding: 8px 12px; + background: #fff3cd; + border: 1px solid #d4b106; + color: #5c4700; + font-size: 12px; + font-weight: 600; + box-shadow: 0 2px 6px rgba(0,0,0,0.2); + z-index: 12000; + display: none; + pointer-events: none; + } + #save-reminder-modal { + position: fixed; + inset: 0; + display: none; + align-items: center; + justify-content: center; + z-index: 12000; + background: rgba(0,0,0,0.15); + } + #save-reminder-modal .window { + width: 420px; + background: #f2f2f2; + border: 1px solid #b0b0b0; + box-shadow: 0 6px 16px rgba(0,0,0,0.25); + padding: 14px 16px 12px 16px; + position: absolute; + } + #save-reminder-modal .title-bar { + height: 28px; + background: #ffffff; + border-bottom: 1px solid #ccc; + display: flex; + align-items: center; + padding-left: 8px; + margin: -14px -16px 8px -16px; + font-weight: normal; + cursor: move; + } + #save-reminder-modal .close-btn { + margin-left: auto; + width: 32px; + height: 28px; + display: flex; + align-items: center; + justify-content: center; + font-size: 14px; + cursor: pointer; + } + #save-reminder-modal .close-btn:hover { + background: #e81123; + color: #fff; + } + #save-reminder-modal .body-text { margin: 8px 0 6px 0; font-size: 15px; padding: 4px 0; color: #8b0000; } + #save-reminder-modal .body-subtext { color: #777; font-size: 11px; } + #save-reminder-modal .btn-row { display: flex; justify-content: flex-end; gap: 8px; margin-top: 12px; } + #save-reminder-modal .btn-row button { + padding: 4px 12px; + border: 1px solid #b0b0b0; + background: #f5f5f5; + cursor: pointer; + border-radius: 4px; + color: #000; + } + #save-reminder-modal .btn-row button:hover { background: #e6e6e6; } + #save-reminder-modal .btn-primary { background: #0078d7; color: #fff; border: 1px solid #005a9e; } + #save-reminder-modal .btn-primary:hover { background: #0063b1; } + #save-reminder-modal .link-btn { color: #005a9e; text-decoration: underline; cursor: pointer; } + + #close-confirm-modal { + position: fixed; + inset: 0; + display: none; + align-items: center; + justify-content: center; + z-index: 13000; + background: transparent; + } + #close-confirm-modal .window { + width: 350px; + background: #f2f2f2; + border: 1px solid #b0b0b0; + box-shadow: 0 6px 16px rgba(0,0,0,0.25); + padding: 0; + position: absolute; + } + #close-confirm-modal .title-bar { + height: 30px; + background: #eeeeee; + display: flex; + align-items: center; + padding-left: 8px; + font-weight: normal; + } + #close-confirm-modal .close-btn { + margin-left: auto; + width: 32px; + height: 30px; + display: flex; + align-items: center; + justify-content: center; + font-size: 14px; + cursor: pointer; + } + #close-confirm-modal .close-btn:hover { + background: #e81123; + color: #fff; + } + #close-confirm-modal .message-area { + height: 61px; + background: #ffffff; + display: flex; + align-items: center; + padding: 0 16px; + } + #close-confirm-modal .body-text { + margin: 0; + font-size: 16px; + color: #0057d8; + font-weight: normal; + } + #close-confirm-modal .separator { + height: 1px; + background: #c8c8c8; + } + #close-confirm-modal .button-area { + background: #eeeeee; + height: 40px; + box-sizing: border-box; + padding: 0 11px 0 12px; + display: flex; + align-items: center; + justify-content: flex-end; + } + #close-confirm-modal .btn-row { display: flex; justify-content: flex-end; gap: 8px; margin-top: 0; } + #close-confirm-modal .btn-row button { + height: 21px; + padding: 0 18px; + box-sizing: border-box; + border: 1px solid #b0b0b0; + background: #ffffff; + cursor: pointer; + border-radius: 4px; + color: #000; + font-size: 12px; + font-family: "Segoe UI", Tahoma, sans-serif; + white-space: nowrap; + } + #close-confirm-modal .btn-row button:nth-child(1) { width: 70px; min-width: 70px; max-width: 70px; } + #close-confirm-modal .btn-row button:nth-child(2) { width: 90px; min-width: 90px; max-width: 90px; text-align: center; padding-left: 16px; padding-right: 20px; } + #close-confirm-modal .btn-row button:nth-child(3) { width: 70px; min-width: 70px; max-width: 70px; } + #close-confirm-modal .btn-row button:hover:not(:disabled) { + background-color: #e5f1fb; + border-color: var(--toggle-icon-color); + } + #close-confirm-modal .btn-row button:focus { + outline: 1px solid #2b88d8; + outline-offset: -1px; + } + + #modal-info { + position: fixed; + inset: 0; + display: none; + align-items: center; + justify-content: center; + z-index: 12000; + background: rgba(0,0,0,0.2); + } + #modal-info .window { + width: 720px; + max-width: calc(100vw - 40px); + height: 520px; + max-height: calc(100vh - 40px); + background: #f2f2f2; + border: 1px solid #b0b0b0; + box-shadow: 0 8px 18px rgba(0,0,0,0.25); + display: flex; + flex-direction: column; + } + #modal-info .title-bar { + height: 28px; + background: #ffffff; + border-bottom: 1px solid #ccc; + display: flex; + align-items: center; + padding-left: 10px; + font-size: 12px; + color: #000; + } + #modal-info .close-btn { + margin-left: auto; + width: 32px; + height: 28px; + display: flex; + align-items: center; + justify-content: center; + font-size: 14px; + cursor: pointer; + } + #modal-info .close-btn:hover { background: #e81123; color: white; } + #modal-info .content { + padding: 10px 12px; + overflow: auto; + display: flex; + flex-direction: column; + gap: 12px; + font-size: 12px; + color: #222; + } + #modal-info .info-section { + background: #ffffff; + border: 1px solid #d0d0d0; + padding: 8px 10px; + } + #modal-info .info-title { + font-weight: 600; + margin-bottom: 6px; + } + #modal-info .info-list { + margin: 0; + padding-left: 16px; + } + #modal-info .info-list li { margin-bottom: 4px; } + + + .modal-mask { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: transparent; z-index: 5000; display: none; align-items: center; justify-content: center; } + body.theme-colors-open .modal-mask { pointer-events: none; } + body.theme-colors-open .modal-mask .window, + body.theme-colors-open .modal-mask .modal-window { pointer-events: auto; } + + .modal-window { background: white; border: 1px solid var(--win-blue); box-shadow: 0 0 20px rgba(0,0,0,0.3); width: 380px; padding: 15px; } + .modal-btns { display: flex; justify-content: flex-end; gap: 10px; margin-top: 15px; } + button { padding: 4px 15px; cursor: pointer; } + + .resize-options { display: flex; gap: 10px; margin-bottom: 15px; align-items: center; } + .radio-group-row { display: flex; gap: 15px; } + .resize-grid { display: flex; flex-direction: column; gap: 8px; margin-bottom: 10px; } + .resize-row { display: flex; align-items: center; gap: 10px; } + + .icon-box { width: 32px; height: 32px; border: 1px solid #ccc; display: flex; align-items: center; justify-content: center; background: #f9f9f9; } + .resize-row label { width: 70px; } .resize-row input { width: 60px; } + .resize-footer { margin-top: 10px; padding-top: 5px; border-top: 1px solid #eee; } + + fieldset { border: 1px solid #ccc; margin: 0 0 10px 0; padding: 8px; border-radius: 2px; } + legend { color: var(--win-blue); font-weight: bold; font-size: 11px; } + .radio-group { display: flex; flex-direction: column; gap: 4px; } + .radio-row { display: flex; align-items: center; gap: 6px; cursor: pointer; } + + .advanced-row { display: flex; align-items: center; justify-content: space-between; margin-top: 10px; padding-top: 10px; border-top: 1px solid #eee; } + .slider-container { display: flex; align-items: center; gap: 5px; flex: 1; } + + .seed-container { display: flex; align-items: center; gap: 4px; border-left: 1px solid #ccc; padding-left: 8px; margin-left: 8px; } + .small-btn { min-width: 24px; padding: 0 4px; height: 22px; font-size: 11px; } + .disabled { opacity: 0.5; pointer-events: none; } + .form-group { margin-bottom: 10px; } + .form-group label { display: block; font-weight: bold; margin-bottom: 4px; } + .form-group select, .form-group input { width: 100%; padding: 4px; } + .ribbon-card { + display: flex; + flex-direction: column; + align-items: center; + gap: 3px; + padding: 4px 6px; + min-width: 130px; + border: 1px solid #d7d7d7; + border-radius: 3px; + background: #fafafa; + } + .ribbon-card.tile-compact { + flex-direction: column; + align-items: center; + padding: 10px 6px; + gap: 3px; + min-width: 160px; + } + .ribbon-card.tile-compact .card-icon svg { width: 18px; height: 18px; } + .ribbon-card.tile-compact .card-label { font-size: 9px; line-height: 1; white-space: nowrap; } + .ribbon-card.tile-compact .card-controls { gap: 3px; } + .ribbon-card.tile-compact .mini-label { font-size: 9px; } + .ribbon-card.tile-compact .compact-input { + width: 34px; + height: 16px; + padding: 0 3px; + border-left: 0; + border-right: 0; + border-top: 0; + border-bottom: 1px solid #b5b5b5; + border-radius: 0; + } + .ribbon-card.tile-compact .compact-input:focus { + outline: none; + border-bottom-color: #1b6fe5; + } + .ribbon-card .card-icon svg { + width: 22px; + height: 22px; + display: block; + } + .ribbon-card .card-label { + font-weight: 600; + color: #333; + font-size: 10px; + } + .ribbon-card .card-controls { + display: flex; + align-items: center; + justify-content: center; + gap: 4px; + flex-wrap: nowrap; + } + .ribbon-card .card-controls + .card-controls { + margin-top: 3px; + } + .ribbon-card .mini-label { font-size: 10px; color: #666; } + .ribbon-card .compact-input { + width: 36px; + height: 18px; + padding: 0 4px; + border-left: 0; + border-right: 0; + border-top: 0; + border-bottom: 1px solid #b5b5b5; + border-radius: 0; + text-align: center; + -moz-appearance: textfield; + -webkit-appearance: textfield; + appearance: textfield; + } + .ribbon-card .compact-input:focus { + outline: none; + border-bottom-color: #1b6fe5; + } + .ribbon-card .compact-input[type="number"]::-webkit-inner-spin-button, + .ribbon-card .compact-input[type="number"]::-webkit-outer-spin-button { + -webkit-appearance: none; + margin: 0; + } + #pen-size-input { + border-left: 0; + border-right: 0; + border-top: 0; + border-bottom: 1px solid #b5b5b5; + border-radius: 0; + text-align: center; + -moz-appearance: textfield; + -webkit-appearance: textfield; + appearance: textfield; + } + #pen-size-input:focus { + outline: none; + border-bottom-color: #1b6fe5; + } + #pen-size-input::-webkit-inner-spin-button, + #pen-size-input::-webkit-outer-spin-button { + -webkit-appearance: none; + margin: 0; + } + #line-width-menu.line-width-menu { + width: 132px; + height: 166px; + box-sizing: border-box; + border: 1px solid #d9d9d9; + background-color: #ffffff; + padding: 2px 1px; + display: none; + flex-direction: column; + min-width: 132px; + z-index: 10010; + } + #line-width-menu .line-width-item { + width: 128px; + height: 40px; + box-sizing: border-box; + border: 1px solid transparent; + display: flex; + justify-content: center; + align-items: center; + cursor: default; + } + #line-width-menu .line-width-item.selected { + background-color: #eef4fc; + border-color: #a0c5f5; + } + #line-width-menu .line-width-item:hover { + background-color: #cde3fa; + border-color: #72a9ea; + } + #line-width-menu .line-width-preview { + width: 108px; + background-color: #324254; + pointer-events: none; + } + #line-width-menu .line-width-1 { height: 1px; } + #line-width-menu .line-width-2 { height: 2px; } + #line-width-menu .line-width-3 { height: 3px; } + #line-width-menu .line-width-4 { height: 4px; } + .ribbon-card .compact-toggle { display: inline-flex; align-items: center; gap: 3px; font-weight: normal; } + .ribbon-card .compact-btn { padding: 1px 5px; font-size: 10px; } + svg { fill: none; } + + /* Export Studio Styles */ + .export-palette-grid { + display: grid; + grid-template-columns: repeat(8, 1fr); + gap: 4px; + margin-top: 4px; + max-height: 180px; + overflow-y: auto; + } + .export-swatch { + aspect-ratio: 1; + border: 1px solid #888; + border-radius: 2px; + cursor: grab; + position: relative; + box-shadow: inset 0 0 0 1px rgba(255,255,255,0.4); + } + .export-swatch:active { cursor: grabbing; } + .export-swatch[data-index="0"] { + border: 2px solid #ed1c24; + } + .export-swatch[data-index="0"]::after { + content: "T"; + position: absolute; + top: -2px; left: 1px; + font-size: 9px; + font-weight: 900; + color: white; + text-shadow: 0 1px 2px black; + pointer-events: none; + } + .export-swatch .swatch-idx { + position: absolute; + bottom: 1px; right: 2px; + font-size: 8px; + color: rgba(0,0,0,0.5); + pointer-events: none; + } + .export-swatch.dragging { + opacity: 0.4; + border: 2px dashed #333; + } + .export-swatch.drag-over { + border: 2px solid #0078d7; + transform: scale(1.1); + z-index: 10; + } + +/* ════════════════════════════════════════════════════════════════ + * PRIMEVAL FOREST - deep mossy green-teal dark theme + * ════════════════════════════════════════════════════════════════ */ +body.primeval-forest-mode { + --pf-s0:#090F0C;--pf-s1:#0D1610;--pf-s2:#0D1A14;--pf-s3:#1A2E22;--pf-s4:#1F3828;--pf-s5:#27452F;--pf-s6:#2E5238;--pf-s7:#3A6645;--pf-s8:#4A7A56; + --pf-t1:#D6EDD9;--pf-t2:#7AAE84;--pf-t3:#4A7055;--pf-a1:#5EC47A;--pf-a2:#1F6B3A; + --pf-hover-bg:rgba(94,196,122,0.10);--pf-hover-border:rgba(94,196,122,0.30); + --pf-selected-bg:rgba(94,196,122,0.15);--pf-selected-border:rgba(94,196,122,0.40); + --bg-ribbon:var(--pf-s3);--border-ribbon:var(--pf-s7);--app-text-color:var(--pf-t1);--app-bg:var(--pf-s1); + --titlebar-bg:var(--pf-s2);--titlebar-action-icon:var(--pf-t2);--titlebar-action-hover-bg:var(--pf-s5);--titlebar-separator:var(--pf-s7); + --titlebar-filename:var(--pf-t1);--titlebar-control-icon:var(--pf-t1);--tab-row-bg: var(--pf-s2);--section-divider:var(--pf-s7);--section-title-color:var(--pf-t2); + --btn-hover-bg:var(--pf-hover-bg);--btn-hover-border:var(--pf-hover-border);--btn-hover-shadow:rgba(94,196,122,0.15); + --btn-active-bg:var(--pf-selected-bg);--btn-active-border:var(--pf-selected-border);--btn-active-shadow:rgba(94,196,122,0.25); + --dropdown-bg:var(--pf-s4);--dropdown-border:var(--pf-s8);--dropdown-shadow:rgba(0,0,0,0.55);--dropdown-item-hover-bg:var(--pf-s5); + --dropdown-arrow-color:var(--pf-t2);--dropdown-separator:var(--pf-s7);--btn-small-bg:var(--pf-s4);--btn-small-border:var(--pf-s7); + --threshold-label-color:var(--pf-t2);--threshold-values-color:var(--pf-t1);--toggle-icon-color:var(--pf-a1);--toggle-status-color:var(--pf-t2); + --hotkeys-icon-color:var(--pf-a1);--anchor-toggle-icon-color:var(--pf-a1);--theme-mode-toggle-icon-color:var(--pf-a1); + --select-menu-header-color:var(--pf-t2);--select-menu-header-bg:var(--pf-s4);--select-menu-icon-all-fill:rgba(94,196,122,0.18); + --select-menu-icon-all-fill-disabled:var(--pf-s5);--select-menu-icon-disabled-stroke:var(--pf-t3); + --theme-colors-window-bg:var(--pf-s3);--theme-colors-titlebar-bg-start:var(--pf-s4);--theme-colors-titlebar-bg-end:var(--pf-s3); + --theme-colors-titlebar-border:var(--pf-s7);--theme-colors-top-note-color:var(--pf-t2);--theme-colors-result-count-color:var(--pf-t2); + --theme-colors-list-bg:var(--pf-s3);--theme-colors-editor-panel-bg-start:var(--pf-s4);--theme-colors-editor-panel-bg-end:var(--pf-s3); + --theme-colors-editor-panel-border:var(--pf-s7);--theme-colors-editor-title-color:var(--pf-t1);--theme-colors-editor-key-color:var(--pf-t1); + --theme-colors-editor-input-bg:var(--pf-s5);--theme-colors-editor-input-border:var(--pf-s8);--theme-colors-editor-swatch-border:var(--pf-s8); + --theme-colors-editor-hint-color:var(--pf-t3);--theme-colors-mini-toggle-color:var(--pf-t1); + --palette-mini-swatch-border:#020604;--palette-mini-swatch-inner:#fff; + --palette-mini-swatch-hover-border:var(--pf-a1);--palette-mini-swatch-hover-inner:rgba(94,196,122,0.2); + --view-center-icon-color:var(--pf-a1);--view-edgeclean-icon-color:var(--pf-a1);--view-theme-icon-color:var(--pf-a1); + --select-icon-free-color:var(--pf-a1);--select-icon-poly-main-color:var(--pf-a1);--select-icon-poly-accent-color:#80d898; + --bg-hover:var(--pf-hover-bg);--border-hover:var(--pf-hover-border);--bg-selected:var(--pf-selected-bg);--border-selected:var(--pf-selected-border); + --bg-canvas:#263D2C;--win-blue:var(--pf-a1); +} +body.primeval-forest-mode{background:var(--pf-s1);color:var(--pf-t1);} +body.primeval-forest-mode #title-bar{background:var(--pf-s2);border-bottom:none;} +body.primeval-forest-mode .tab-row{background:var(--pf-s2);border-bottom-color:var(--pf-s7);border-top:1px solid var(--pf-s2);color:var(--pf-t1);} +body.primeval-forest-mode .tab{color:var(--pf-t2);border-color:transparent;} +body.primeval-forest-mode .tab:not(.file):not(.active):hover{color:var(--pf-t1);background:var(--pf-s5);border-color:var(--pf-s7);} +body.primeval-forest-mode .tab.active{background:var(--pf-s3);border-color:var(--pf-s7);border-bottom-color:var(--pf-s3);color:var(--pf-t1);} +body.primeval-forest-mode .tab-row .dd-arrow{color:var(--pf-t1);} +body.primeval-forest-mode .ribbon{background:var(--pf-s3);border-bottom:1px solid var(--pf-s7);} +body.primeval-forest-mode .section{border-right-color:var(--pf-s7);} +body.primeval-forest-mode .section-title{color:var(--pf-t3);} +body.primeval-forest-mode .btn-large{color:var(--pf-t1);} +body.primeval-forest-mode .btn-large:hover{background:var(--pf-s5);border-color:var(--pf-s7);} +body.primeval-forest-mode .btn-large.active,body.primeval-forest-mode .btn-large.is-on{background:var(--pf-selected-bg);border-color:var(--pf-selected-border);} +body.primeval-forest-mode .toggle-status{color:var(--pf-t2);} +body.primeval-forest-mode .toggle-btn .toggle-icons,body.primeval-forest-mode #anchor-toggle-btn .toggle-icons,body.primeval-forest-mode #theme-mode-btn .toggle-icons{color:var(--pf-a1);} +body.primeval-forest-mode svg [fill="#0078d7"]{fill:var(--pf-a1);}body.primeval-forest-mode svg [stroke="#0078d7"]{stroke:var(--pf-a1);} +body.primeval-forest-mode .ribbon-card{background:var(--pf-s4);border-color:var(--pf-s7);color:var(--pf-t1);} +body.primeval-forest-mode .ribbon-card .card-label{color:var(--pf-t1);}body.primeval-forest-mode .ribbon-card .mini-label{color:var(--pf-t2);} +body.primeval-forest-mode .compact-input{background:var(--pf-s4);border-color:var(--pf-s8);color:var(--pf-t1);} +body.primeval-forest-mode .ribbon-card.tile-compact .compact-input{background:var(--pf-s4);border-bottom-color:var(--pf-s8);color:var(--pf-t1);} +body.primeval-forest-mode .ribbon-card.tile-compact .compact-input:focus{border-bottom-color:var(--pf-a1);} +body.primeval-forest-mode .ribbon-card .compact-input:focus{border-bottom-color:var(--pf-a1);} +body.primeval-forest-mode #pen-size-input{background:var(--pf-s4);border-bottom-color:var(--pf-s8);color:var(--pf-t1);} +body.primeval-forest-mode #pen-size-input:focus{border-bottom-color:var(--pf-a1);} +body.primeval-forest-mode #size-control-wrap label{color:var(--pf-t2) !important;} +/* ── C1/C2 active color slot β€” green highlight ── */ +body.primeval-forest-mode .active-color-col.selected{background:var(--pf-selected-bg);border-color:var(--pf-selected-border);} +body.primeval-forest-mode .active-color-col:not(.selected):hover{background:var(--pf-hover-bg);border-color:var(--pf-hover-border);box-shadow:none;} +/* ── select tool split button β€” green highlight ── */ +body.primeval-forest-mode .split-btn-container.select-split.selection-highlight{border-color:var(--pf-selected-border);} +body.primeval-forest-mode .split-btn-container.select-split.selection-highlight .split-btn-top, +body.primeval-forest-mode .split-btn-container.select-split.selection-highlight .split-btn-bottom.select-dropdown{background:var(--pf-selected-bg);} +body.primeval-forest-mode .split-btn-container.select-split .split-btn-bottom.select-dropdown.selection-highlight{border-top-color:var(--pf-selected-border);} +body.primeval-forest-mode .split-btn-container.select-split:hover{border-color:var(--pf-hover-border);background:var(--pf-hover-bg);box-shadow:none;} +body.primeval-forest-mode .split-btn-container.select-split:hover .split-btn-bottom.select-dropdown{border-top-color:var(--pf-hover-border);background:var(--pf-hover-bg);box-shadow:none;} +/* ── select-menu dropdown ── */ +body.primeval-forest-mode #select-menu .icon-free, +body.primeval-forest-mode #select-menu .icon-poly, +body.primeval-forest-mode #select-menu .icon-invert{filter:grayscale(1) brightness(1.2) sepia(1) saturate(2.5) hue-rotate(95deg);} +body.primeval-forest-mode #select-menu{--bg-color:var(--pf-s4);--border-outer:var(--pf-s7);--header-text:var(--pf-t2);--text-color:var(--pf-t1);--disabled-text:var(--pf-t3);--separator:var(--pf-s7);--item-hover-bg:var(--pf-s5);--item-hover-border:var(--pf-s8);--item-select-bg:var(--pf-selected-bg);--item-select-border:var(--pf-selected-border);--icon-stroke:var(--pf-a1);box-shadow:2px 2px 8px rgba(0,0,0,0.55);} +/* ── color-preview-highlight and theme-select-candidate β€” green outline ── */ +body.primeval-forest-mode .color-preview-highlight{outline-color:var(--pf-a1) !important;} +body.primeval-forest-mode .theme-select-candidate{outline-color:var(--pf-a1) !important;} +body.primeval-forest-mode .dropdown-panel,body.primeval-forest-mode .paint-dropdown{background:var(--pf-s4);border-color:var(--pf-s7);box-shadow:0 4px 16px rgba(0,0,0,0.55);} +body.primeval-forest-mode .dropdown-item,body.primeval-forest-mode .paint-dropdown-item{color:var(--pf-t1);} +body.primeval-forest-mode .dropdown-item:hover,body.primeval-forest-mode .paint-dropdown-item:hover{background:var(--pf-s5);} +body.primeval-forest-mode .dropdown-separator{background:var(--pf-s7);} +body.primeval-forest-mode .modal-mask{background:rgba(0,0,0,0.6);} +body.primeval-forest-mode #modal-resize .window,body.primeval-forest-mode #modal-depth .window,body.primeval-forest-mode #modal-export .window,body.primeval-forest-mode #modal-huesat .window,body.primeval-forest-mode #modal-hotkeys .window,body.primeval-forest-mode #modal-info .window,body.primeval-forest-mode #modal-colors .window,body.primeval-forest-mode #modal-confirm-reset .window,body.primeval-forest-mode #modal-toolbar .window,body.primeval-forest-mode #modal-wincolor .window,body.primeval-forest-mode .modal-window{background:var(--pf-s3);border-color:var(--pf-s7);color:var(--pf-t1);box-shadow:0 12px 40px rgba(0,0,0,0.65);} +body.primeval-forest-mode #modal-resize .title-bar,body.primeval-forest-mode #modal-depth .title-bar,body.primeval-forest-mode #modal-export .title-bar,body.primeval-forest-mode #modal-huesat .title-bar,body.primeval-forest-mode #modal-hotkeys .title-bar,body.primeval-forest-mode #modal-info .title-bar,body.primeval-forest-mode #modal-colors .title-bar,body.primeval-forest-mode #modal-confirm-reset .title-bar,body.primeval-forest-mode #modal-toolbar .title-bar,body.primeval-forest-mode #modal-wincolor .title-bar{background:var(--pf-s4);border-bottom-color:var(--pf-s7);color:var(--pf-t1);} +body.primeval-forest-mode .close-btn{color:var(--pf-t2);}body.primeval-forest-mode .close-btn:hover{background:#c42b1c;color:#fff;} +body.primeval-forest-mode #modal-resize .footer,body.primeval-forest-mode #modal-depth .footer,body.primeval-forest-mode #modal-export .footer,body.primeval-forest-mode #modal-huesat .footer,body.primeval-forest-mode #modal-hotkeys .footer,body.primeval-forest-mode #modal-colors .footer{border-top-color:var(--pf-s7);} +body.primeval-forest-mode .modal-mask .btn,body.primeval-forest-mode .modal-mask button.btn{background:var(--pf-s5);border-color:var(--pf-s8);color:var(--pf-t1);} +body.primeval-forest-mode .modal-mask .btn:hover{background:var(--pf-s6);border-color:var(--pf-a2);} +body.primeval-forest-mode .modal-mask .btn-primary,body.primeval-forest-mode .modal-mask .btn-ok{background:var(--pf-a2);border-color:#145C2E;color:#fff;} +body.primeval-forest-mode .modal-mask .btn-primary:hover,body.primeval-forest-mode .modal-mask .btn-ok:hover{background:#227A3E;} +body.primeval-forest-mode .modal-mask input[type="text"],body.primeval-forest-mode .modal-mask input[type="number"],body.primeval-forest-mode .modal-mask select,body.primeval-forest-mode .modal-mask textarea{background:var(--pf-s5);border-color:var(--pf-s8);color:var(--pf-t1);} +body.primeval-forest-mode .modal-mask input[type="text"]:focus,body.primeval-forest-mode .modal-mask input[type="number"]:focus,body.primeval-forest-mode .modal-mask select:focus{border-color:var(--pf-a1);outline:none;} +body.primeval-forest-mode .modal-mask label,body.primeval-forest-mode .modal-mask .row label{color:var(--pf-t1);} +body.primeval-forest-mode .modal-mask fieldset{border-color:var(--pf-s7);}body.primeval-forest-mode .modal-mask legend{color:var(--pf-t2);} +body.primeval-forest-mode .modal-mask .section-header{color:var(--pf-t2);border-bottom-color:var(--pf-s7);} +body.primeval-forest-mode .hotkey-list{background:var(--pf-s4);border-color:var(--pf-s7);}body.primeval-forest-mode .hotkey-row{border-bottom-color:var(--pf-s7);} +body.primeval-forest-mode .hotkey-label{color:var(--pf-t1);}body.primeval-forest-mode .hotkeys-icon{color:var(--pf-a1);} +body.primeval-forest-mode #modal-info .info-section{border-bottom-color:var(--pf-s7);}body.primeval-forest-mode #modal-info .info-title{color:var(--pf-a1);} +body.primeval-forest-mode #modal-info li,body.primeval-forest-mode #modal-info p{color:var(--pf-t1);}body.primeval-forest-mode #modal-info .link-btn{color:var(--pf-a1);} +body.primeval-forest-mode #modal-colors .color-item{border-bottom-color:var(--pf-s7);} +body.primeval-forest-mode #modal-colors .color-item:hover{background:var(--pf-s5);border-color:var(--pf-s7);} +body.primeval-forest-mode #modal-colors .color-item.is-active{background:var(--pf-selected-bg);border-color:var(--pf-selected-border);} +body.primeval-forest-mode #modal-colors .color-label,body.primeval-forest-mode #modal-colors .close-btn{color:var(--pf-t1);} +body.primeval-forest-mode #modal-colors .color-element-label,body.primeval-forest-mode #modal-colors .select-hint{color:var(--pf-t2);} +body.primeval-forest-mode #modal-colors .color-input,body.primeval-forest-mode #modal-colors .preset-select,body.primeval-forest-mode #modal-colors .preset-input,body.primeval-forest-mode #modal-colors .search-input{background:var(--pf-s5);border-color:var(--pf-s8);color:var(--pf-t1);} +body.primeval-forest-mode #modal-colors .color-input.invalid{border-color:#e81123;background:rgba(232,17,35,0.15);} +body.primeval-forest-mode #modal-colors .btn{background:var(--pf-s5);border-color:var(--pf-s8);color:var(--pf-t1);} +body.primeval-forest-mode #modal-colors .btn:hover{background:var(--pf-s6);border-color:var(--pf-a1);} +body.primeval-forest-mode #modal-colors .color-list{border-color:var(--pf-s7);}body.primeval-forest-mode #modal-colors .preset-row{background:var(--pf-s4);border-color:var(--pf-s7);} +body.primeval-forest-mode #modal-colors .editor-grid label{color:var(--pf-t2);}body.primeval-forest-mode #modal-colors .editor-grid input[type="number"]{background:var(--pf-s5);border-color:var(--pf-s8);color:var(--pf-t1);} +body.primeval-forest-mode #file-menu.file-menu-template{background:var(--pf-s3);border-color:var(--pf-s7);box-shadow:2px 4px 16px rgba(0,0,0,0.55);} +body.primeval-forest-mode #file-menu .file-menu-left{background:var(--pf-s4);border-right-color:var(--pf-s7);} +body.primeval-forest-mode #file-menu .file-menu-item{color:var(--pf-t1);}body.primeval-forest-mode #file-menu .file-menu-item:hover{background:var(--pf-s5);border-color:var(--pf-s7);} +body.primeval-forest-mode #file-menu .file-menu-separator{background:var(--pf-s7);}body.primeval-forest-mode #file-menu .file-menu-right{background:var(--pf-s3);} +body.primeval-forest-mode #file-menu .file-menu-recent-toggle{background:var(--pf-s4);border-color:var(--pf-s7);color:var(--pf-t2);} +body.primeval-forest-mode #file-menu .file-menu-recent-toggle:hover{background:var(--pf-s5);color:var(--pf-t1);} +body.primeval-forest-mode #file-menu .file-menu-recent-header{color:var(--pf-t1);border-bottom-color:var(--pf-s7);} +body.primeval-forest-mode #file-menu .file-menu-recent-item{color:var(--pf-t2);}body.primeval-forest-mode #file-menu .file-menu-recent-item:hover{background:var(--pf-s5);color:var(--pf-t1);} +body.primeval-forest-mode .select-menu{background:var(--pf-s4);border-color:var(--pf-s7);box-shadow:0 4px 16px rgba(0,0,0,0.55);} +body.primeval-forest-mode .select-menu-header{background:var(--pf-s4);color:var(--pf-t2);border-bottom-color:var(--pf-s7);} +body.primeval-forest-mode .select-menu-item{color:var(--pf-t1);}body.primeval-forest-mode .select-menu-item:hover{background:var(--pf-s5);} +body.primeval-forest-mode input[type="range"]::-webkit-slider-runnable-track,body.primeval-forest-mode input[type="range"]::-moz-range-track{background:var(--pf-s6);} +body.primeval-forest-mode input[type="range"]::-webkit-slider-thumb{background:var(--pf-a1);}body.primeval-forest-mode input[type="range"]::-moz-range-thumb{background:var(--pf-a1);} +body.primeval-forest-mode #save-reminder-modal .window,body.primeval-forest-mode #close-confirm-modal .window{background:var(--pf-s3);border-color:var(--pf-s7);color:var(--pf-t1);} +body.primeval-forest-mode #lsys-panel{background:var(--pf-s3);border-color:var(--pf-s7);}body.primeval-forest-mode #lsys-list{background:var(--pf-s4);} +body.primeval-forest-mode .lsys-layer{background:var(--pf-s4);border-bottom-color:var(--pf-s7);color:var(--pf-t1);}body.primeval-forest-mode .lsys-layer.active{background:var(--pf-s5);} +body.primeval-forest-mode .lsys-layer-name{color:var(--pf-t1);}body.primeval-forest-mode #lsys-toolbar{background:var(--pf-s3);border-top-color:var(--pf-s7);} +body.primeval-forest-mode .lsys-btn{color:var(--pf-t1);}body.primeval-forest-mode .lsys-btn:hover{background:var(--pf-s5);} +body.primeval-forest-mode #status-bar,body.primeval-forest-mode .status-bar{background:var(--pf-s2);border-top-color:var(--pf-s7);color:var(--pf-t2);} +body.primeval-forest-mode #palette-bar,body.primeval-forest-mode .palette-bar{background:var(--pf-s3);border-top-color:var(--pf-s7);} +body.primeval-forest-mode .mini-swatch.empty{box-shadow:none;} +body.primeval-forest-mode #modal-wincolor .tab-btn{background:var(--pf-s5);border-color:var(--pf-s7);color:var(--pf-t1);}body.primeval-forest-mode #modal-wincolor .tab-btn.active{background:var(--pf-a2);color:#fff;} +body.primeval-forest-mode #swap-colors-btn{background:var(--pf-s4) !important;border-color:var(--pf-s7) !important;color:var(--pf-t1);} +body.primeval-forest-mode #swap-colors-btn:hover{background:var(--pf-s5) !important;border-color:var(--pf-s8) !important;} + +/* ── sliders (Firefox fill track) ── */ +body.primeval-forest-mode input[type="range"]::-moz-range-progress{background:var(--pf-a2);} + +/* ── extra toggle buttons ── */ +body.primeval-forest-mode #test-mode-btn .toggle-icons{color:var(--pf-a1);} +body.primeval-forest-mode #dark-refined-btn .toggle-icons{color:var(--pf-a1);} + +/* ── modal-depth specific ── */ +body.primeval-forest-mode #modal-depth{--win-bg:var(--pf-s3);--win-text:var(--pf-t1);--input-border:var(--pf-s8);--input-focus:var(--pf-a1);--btn-border:var(--pf-s8);--btn-hover:var(--pf-s5);} +body.primeval-forest-mode #modal-depth .btn{background:var(--pf-s5);border-color:var(--pf-s8);color:var(--pf-t1);} +body.primeval-forest-mode #modal-depth .btn:hover{background:var(--pf-s6);border-color:var(--pf-a1);} +body.primeval-forest-mode #modal-depth .btn-primary{background:var(--pf-a2);border-color:#145C2E;color:#fff;} +body.primeval-forest-mode #modal-depth .btn-primary:hover{background:#227A3E;} +body.primeval-forest-mode #modal-depth .depth-radio{background:var(--pf-s5);border-color:var(--pf-s8);color:var(--pf-t1);} +body.primeval-forest-mode #modal-depth .depth-color-list input[type="radio"]:checked + .depth-radio{background:var(--pf-a2);border-color:var(--pf-a1);color:#fff;} +body.primeval-forest-mode #modal-depth .depth-group-label{color:var(--pf-t2);} + +/* ── modal-huesat specific ── */ +body.primeval-forest-mode #modal-huesat{--win-bg:var(--pf-s3);--win-text:var(--pf-t1);--input-border:var(--pf-s8);--input-focus:var(--pf-a1);--btn-border:var(--pf-s8);--btn-hover:var(--pf-s5);} +body.primeval-forest-mode #modal-huesat .channel-area{background:var(--pf-s4);border-color:var(--pf-s7);} +body.primeval-forest-mode #modal-huesat .channel-label{color:var(--pf-t2);} +body.primeval-forest-mode #modal-huesat .channel-btn{filter:brightness(0.88);} +body.primeval-forest-mode #modal-huesat .channel-wrap.active{background:transparent;} +body.primeval-forest-mode #modal-huesat .master-btn{background:var(--pf-s6);border-color:var(--pf-s8);color:var(--pf-t1);} +body.primeval-forest-mode #modal-huesat .master-btn.active{background:var(--pf-t1);color:var(--pf-s1);border-color:var(--pf-t1);} +body.primeval-forest-mode #modal-huesat .preset-row{background:var(--pf-s4);border-color:var(--pf-s7);} +body.primeval-forest-mode #modal-huesat .preset-row label{color:var(--pf-t2);} + +/* ── modal-resize specific ── */ +body.primeval-forest-mode #modal-resize{--win-bg:var(--pf-s3);--win-text:var(--pf-t1);} +body.primeval-forest-mode #modal-resize .col-label{color:var(--pf-t1);} + + +/* ── modal-export specific ── */ +body.primeval-forest-mode #modal-export{--win-bg:var(--pf-s3);--input-border:var(--pf-s8);--input-focus:var(--pf-a1);--btn-border:var(--pf-s8);--btn-hover:var(--pf-s5);} +body.primeval-forest-mode #modal-export .export-format-btn{background:var(--pf-s5);border-color:var(--pf-s7);color:var(--pf-t1);} +body.primeval-forest-mode #modal-export .export-format-btn.active{background:var(--pf-a2);border-color:var(--pf-a1);color:#fff;} + +/* ── modal-colors (theme colors editor) extended ── */ +body.primeval-forest-mode #modal-colors .window{border-color:var(--pf-s7);} +body.primeval-forest-mode #modal-colors .close-btn{color:var(--pf-t1);} +body.primeval-forest-mode #modal-colors .select-hint{color:var(--pf-t2);} +body.primeval-forest-mode #modal-colors .color-list{border-color:var(--pf-s7);} +body.primeval-forest-mode #modal-colors .color-item:hover{background:var(--pf-s5);border-color:var(--pf-s7);} +body.primeval-forest-mode #modal-colors .color-item.is-active{background:var(--pf-selected-bg);border-color:var(--pf-selected-border);} +body.primeval-forest-mode #modal-colors .color-label{color:var(--pf-t1);} +body.primeval-forest-mode #modal-colors .color-element-label{color:var(--pf-t2);} +body.primeval-forest-mode #modal-colors .color-input{background:var(--pf-s5);border-color:var(--pf-s8);color:var(--pf-t1);} +body.primeval-forest-mode #modal-colors .color-input.invalid{border-color:#e81123;background:rgba(232,17,35,0.15);} +body.primeval-forest-mode #modal-colors .preset-select, +body.primeval-forest-mode #modal-colors .preset-input, +body.primeval-forest-mode #modal-colors .search-input{background:var(--pf-s5);border-color:var(--pf-s8);color:var(--pf-t1);} +body.primeval-forest-mode #modal-colors .btn{background:var(--pf-s5);border-color:var(--pf-s8);color:var(--pf-t1);} +body.primeval-forest-mode #modal-colors .btn:hover{background:var(--pf-s6);border-color:var(--pf-a1);color:var(--pf-t1);} +body.primeval-forest-mode #modal-colors .editor-grid label{color:var(--pf-t2);} +body.primeval-forest-mode #modal-colors .editor-grid input[type="number"]{background:var(--pf-s5);border-color:var(--pf-s8);color:var(--pf-t1);} +body.primeval-forest-mode #modal-colors .color-item{border-bottom-color:var(--pf-s7);} +body.primeval-forest-mode #modal-colors .preset-row{background:var(--pf-s4);border-color:var(--pf-s7);} +body.primeval-forest-mode #modal-colors .preset-select{background:var(--pf-s5);border-color:var(--pf-s8);color:var(--pf-t1);} +body.primeval-forest-mode #modal-colors .preset-input{background:var(--pf-s5);border-color:var(--pf-s8);color:var(--pf-t1);} + +/* ── modal-wincolor extended ── */ +body.primeval-forest-mode #modal-wincolor .window{background:var(--pf-s3);border-color:var(--pf-s7);} +body.primeval-forest-mode #modal-wincolor .tab-btn{background:var(--pf-s5);border-color:var(--pf-s7);color:var(--pf-t1);} +body.primeval-forest-mode #modal-wincolor .tab-btn.active{background:var(--pf-a2);color:#fff;} + +/* ════════════════════════════════════════════════════════════════ + * ABYSSAL OCEAN - deep midnight navy dark theme + * ════════════════════════════════════════════════════════════════ */ +body.abyssal-ocean-mode { + --ao-s0:#060810;--ao-s1:#090D1A;--ao-s2:#0A0F1E;--ao-s3:#0F1E3A;--ao-s4:#132448;--ao-s5:#192D58;--ao-s6:#1F3668;--ao-s7:#2B487E;--ao-s8:#3A5E96; + --ao-t1:#C8D8F4;--ao-t2:#6888C0;--ao-t3:#3A5284;--ao-a1:#5AA8F0;--ao-a2:#1A4D8C; + --ao-hover-bg:rgba(90,168,240,0.10);--ao-hover-border:rgba(90,168,240,0.30); + --ao-selected-bg:rgba(90,168,240,0.15);--ao-selected-border:rgba(90,168,240,0.40); + --bg-ribbon:var(--ao-s3);--border-ribbon:var(--ao-s7);--app-text-color:var(--ao-t1);--app-bg:var(--ao-s1); + --titlebar-bg:var(--ao-s2);--titlebar-action-icon:var(--ao-t2);--titlebar-action-hover-bg:var(--ao-s5);--titlebar-separator:var(--ao-s7); + --titlebar-filename:var(--ao-t1);--titlebar-control-icon:var(--ao-t1);--tab-row-bg:var(--ao-s2);--section-divider:var(--ao-s7);--section-title-color:var(--ao-t2); + --btn-hover-bg:var(--ao-hover-bg);--btn-hover-border:var(--ao-hover-border);--btn-hover-shadow:rgba(90,168,240,0.15); + --btn-active-bg:var(--ao-selected-bg);--btn-active-border:var(--ao-selected-border);--btn-active-shadow:rgba(90,168,240,0.25); + --dropdown-bg:var(--ao-s4);--dropdown-border:var(--ao-s8);--dropdown-shadow:rgba(0,0,0,0.6);--dropdown-item-hover-bg:var(--ao-s5); + --dropdown-arrow-color:var(--ao-t2);--dropdown-separator:var(--ao-s7);--btn-small-bg:var(--ao-s4);--btn-small-border:var(--ao-s7); + --threshold-label-color:var(--ao-t2);--threshold-values-color:var(--ao-t1);--toggle-icon-color:var(--ao-a1);--toggle-status-color:var(--ao-t2); + --hotkeys-icon-color:var(--ao-a1);--anchor-toggle-icon-color:var(--ao-a1);--theme-mode-toggle-icon-color:var(--ao-a1); + --select-menu-header-color:var(--ao-t2);--select-menu-header-bg:var(--ao-s4);--select-menu-icon-all-fill:rgba(90,168,240,0.18); + --select-menu-icon-all-fill-disabled:var(--ao-s5);--select-menu-icon-disabled-stroke:var(--ao-t3); + --theme-colors-window-bg:var(--ao-s3);--theme-colors-titlebar-bg-start:var(--ao-s4);--theme-colors-titlebar-bg-end:var(--ao-s3); + --theme-colors-titlebar-border:var(--ao-s7);--theme-colors-top-note-color:var(--ao-t2);--theme-colors-result-count-color:var(--ao-t2); + --theme-colors-list-bg:var(--ao-s3);--theme-colors-editor-panel-bg-start:var(--ao-s4);--theme-colors-editor-panel-bg-end:var(--ao-s3); + --theme-colors-editor-panel-border:var(--ao-s7);--theme-colors-editor-title-color:var(--ao-t1);--theme-colors-editor-key-color:var(--ao-t1); + --theme-colors-editor-input-bg:var(--ao-s5);--theme-colors-editor-input-border:var(--ao-s8);--theme-colors-editor-swatch-border:var(--ao-s8); + --theme-colors-editor-hint-color:var(--ao-t3);--theme-colors-mini-toggle-color:var(--ao-t1); + --palette-mini-swatch-border:#02040A;--palette-mini-swatch-inner:#fff; + --palette-mini-swatch-hover-border:var(--ao-a1);--palette-mini-swatch-hover-inner:rgba(90,168,240,0.2); + --view-center-icon-color:var(--ao-a1);--view-edgeclean-icon-color:var(--ao-a1);--view-theme-icon-color:var(--ao-a1); + --select-icon-free-color:var(--ao-a1);--select-icon-poly-main-color:var(--ao-a1);--select-icon-poly-accent-color:#7AC4FF; + --bg-hover:var(--ao-hover-bg);--border-hover:var(--ao-hover-border);--bg-selected:var(--ao-selected-bg);--border-selected:var(--ao-selected-border); + --bg-canvas:#192A4E;--win-blue:var(--ao-a1); +} +body.abyssal-ocean-mode{background:var(--ao-s1);color:var(--ao-t1);} +body.abyssal-ocean-mode #title-bar{background:var(--ao-s2);border-bottom:none;} +body.abyssal-ocean-mode .tab-row{background:var(--ao-s2);border-bottom-color:var(--ao-s7);border-top:1px solid var(--ao-s2);color:var(--ao-t1);} +body.abyssal-ocean-mode .tab{color:var(--ao-t2);border-color:transparent;} +body.abyssal-ocean-mode .tab:not(.file):not(.active):hover{color:var(--ao-t1);background:var(--ao-s5);border-color:var(--ao-s7);} +body.abyssal-ocean-mode .tab.active{background:var(--ao-s3);border-color:var(--ao-s7);border-bottom-color:var(--ao-s3);color:var(--ao-t1);} +body.abyssal-ocean-mode .tab-row .dd-arrow{color:var(--ao-t1);} +body.abyssal-ocean-mode .ribbon{background:var(--ao-s3);border-bottom:1px solid var(--ao-s7);} +body.abyssal-ocean-mode .section{border-right-color:var(--ao-s7);}body.abyssal-ocean-mode .section-title{color:var(--ao-t3);} +body.abyssal-ocean-mode .btn-large{color:var(--ao-t1);}body.abyssal-ocean-mode .btn-large:hover{background:var(--ao-s5);border-color:var(--ao-s7);} +body.abyssal-ocean-mode .btn-large.active,body.abyssal-ocean-mode .btn-large.is-on{background:var(--ao-selected-bg);border-color:var(--ao-selected-border);} +body.abyssal-ocean-mode .toggle-status{color:var(--ao-t2);} +body.abyssal-ocean-mode .toggle-btn .toggle-icons,body.abyssal-ocean-mode #anchor-toggle-btn .toggle-icons,body.abyssal-ocean-mode #theme-mode-btn .toggle-icons{color:var(--ao-a1);} +body.abyssal-ocean-mode svg [fill="#0078d7"]{fill:var(--ao-a1);}body.abyssal-ocean-mode svg [stroke="#0078d7"]{stroke:var(--ao-a1);} +body.abyssal-ocean-mode .ribbon-card{background:var(--ao-s4);border-color:var(--ao-s7);color:var(--ao-t1);} +body.abyssal-ocean-mode .ribbon-card .card-label{color:var(--ao-t1);}body.abyssal-ocean-mode .ribbon-card .mini-label{color:var(--ao-t2);} +body.abyssal-ocean-mode .compact-input{background:var(--ao-s5);border-color:var(--ao-s8);color:var(--ao-t1);} +body.abyssal-ocean-mode .dropdown-panel,body.abyssal-ocean-mode .paint-dropdown{background:var(--ao-s4);border-color:var(--ao-s7);box-shadow:0 4px 16px rgba(0,0,0,0.6);} +body.abyssal-ocean-mode .dropdown-item,body.abyssal-ocean-mode .paint-dropdown-item{color:var(--ao-t1);} +body.abyssal-ocean-mode .dropdown-item:hover,body.abyssal-ocean-mode .paint-dropdown-item:hover{background:var(--ao-s5);} +body.abyssal-ocean-mode .dropdown-separator{background:var(--ao-s7);} +body.abyssal-ocean-mode .modal-mask{background:rgba(0,0,0,0.65);} +body.abyssal-ocean-mode #modal-resize .window,body.abyssal-ocean-mode #modal-depth .window,body.abyssal-ocean-mode #modal-export .window,body.abyssal-ocean-mode #modal-huesat .window,body.abyssal-ocean-mode #modal-hotkeys .window,body.abyssal-ocean-mode #modal-info .window,body.abyssal-ocean-mode #modal-colors .window,body.abyssal-ocean-mode #modal-confirm-reset .window,body.abyssal-ocean-mode #modal-toolbar .window,body.abyssal-ocean-mode #modal-wincolor .window,body.abyssal-ocean-mode .modal-window{background:var(--ao-s3);border-color:var(--ao-s7);color:var(--ao-t1);box-shadow:0 12px 40px rgba(0,0,0,0.7);} +body.abyssal-ocean-mode #modal-resize .title-bar,body.abyssal-ocean-mode #modal-depth .title-bar,body.abyssal-ocean-mode #modal-export .title-bar,body.abyssal-ocean-mode #modal-huesat .title-bar,body.abyssal-ocean-mode #modal-hotkeys .title-bar,body.abyssal-ocean-mode #modal-info .title-bar,body.abyssal-ocean-mode #modal-colors .title-bar,body.abyssal-ocean-mode #modal-confirm-reset .title-bar,body.abyssal-ocean-mode #modal-toolbar .title-bar,body.abyssal-ocean-mode #modal-wincolor .title-bar{background:var(--ao-s4);border-bottom-color:var(--ao-s7);color:var(--ao-t1);} +body.abyssal-ocean-mode .close-btn{color:var(--ao-t2);}body.abyssal-ocean-mode .close-btn:hover{background:#c42b1c;color:#fff;} +body.abyssal-ocean-mode #modal-resize .footer,body.abyssal-ocean-mode #modal-depth .footer,body.abyssal-ocean-mode #modal-export .footer,body.abyssal-ocean-mode #modal-huesat .footer,body.abyssal-ocean-mode #modal-hotkeys .footer,body.abyssal-ocean-mode #modal-colors .footer{border-top-color:var(--ao-s7);} +body.abyssal-ocean-mode .modal-mask .btn,body.abyssal-ocean-mode .modal-mask button.btn{background:var(--ao-s5);border-color:var(--ao-s8);color:var(--ao-t1);} +body.abyssal-ocean-mode .modal-mask .btn:hover{background:var(--ao-s6);border-color:var(--ao-a2);} +body.abyssal-ocean-mode .modal-mask .btn-primary,body.abyssal-ocean-mode .modal-mask .btn-ok{background:var(--ao-a2);border-color:#0E3870;color:#fff;} +body.abyssal-ocean-mode .modal-mask .btn-primary:hover,body.abyssal-ocean-mode .modal-mask .btn-ok:hover{background:#205898;} +body.abyssal-ocean-mode .modal-mask input[type="text"],body.abyssal-ocean-mode .modal-mask input[type="number"],body.abyssal-ocean-mode .modal-mask select,body.abyssal-ocean-mode .modal-mask textarea{background:var(--ao-s5);border-color:var(--ao-s8);color:var(--ao-t1);} +body.abyssal-ocean-mode .modal-mask input[type="text"]:focus,body.abyssal-ocean-mode .modal-mask input[type="number"]:focus,body.abyssal-ocean-mode .modal-mask select:focus{border-color:var(--ao-a1);outline:none;} +body.abyssal-ocean-mode .modal-mask label,body.abyssal-ocean-mode .modal-mask .row label{color:var(--ao-t1);} +body.abyssal-ocean-mode .modal-mask fieldset{border-color:var(--ao-s7);}body.abyssal-ocean-mode .modal-mask legend{color:var(--ao-t2);} +body.abyssal-ocean-mode .modal-mask .section-header{color:var(--ao-t2);border-bottom-color:var(--ao-s7);} +body.abyssal-ocean-mode .hotkey-list{background:var(--ao-s4);border-color:var(--ao-s7);}body.abyssal-ocean-mode .hotkey-row{border-bottom-color:var(--ao-s7);} +body.abyssal-ocean-mode .hotkey-label{color:var(--ao-t1);}body.abyssal-ocean-mode .hotkeys-icon{color:var(--ao-a1);} +body.abyssal-ocean-mode #modal-info .info-section{border-bottom-color:var(--ao-s7);}body.abyssal-ocean-mode #modal-info .info-title{color:var(--ao-a1);} +body.abyssal-ocean-mode #modal-info li,body.abyssal-ocean-mode #modal-info p{color:var(--ao-t1);}body.abyssal-ocean-mode #modal-info .link-btn{color:var(--ao-a1);} +body.abyssal-ocean-mode #modal-colors .color-item{border-bottom-color:var(--ao-s7);} +body.abyssal-ocean-mode #modal-colors .color-item:hover{background:var(--ao-s5);border-color:var(--ao-s7);} +body.abyssal-ocean-mode #modal-colors .color-item.is-active{background:var(--ao-selected-bg);border-color:var(--ao-selected-border);} +body.abyssal-ocean-mode #modal-colors .color-label,body.abyssal-ocean-mode #modal-colors .close-btn{color:var(--ao-t1);} +body.abyssal-ocean-mode #modal-colors .color-element-label,body.abyssal-ocean-mode #modal-colors .select-hint{color:var(--ao-t2);} +body.abyssal-ocean-mode #modal-colors .color-input,body.abyssal-ocean-mode .preset-select,body.abyssal-ocean-mode .preset-input,body.abyssal-ocean-mode .search-input{background:var(--ao-s5);border-color:var(--ao-s8);color:var(--ao-t1);} +body.abyssal-ocean-mode #modal-colors .color-input.invalid{border-color:#e81123;background:rgba(232,17,35,0.15);} +body.abyssal-ocean-mode #modal-colors .btn{background:var(--ao-s5);border-color:var(--ao-s8);color:var(--ao-t1);} +body.abyssal-ocean-mode #modal-colors .btn:hover{background:var(--ao-s6);border-color:var(--ao-a1);} +body.abyssal-ocean-mode #modal-colors .color-list{border-color:var(--ao-s7);}body.abyssal-ocean-mode #modal-colors .preset-row{background:var(--ao-s4);border-color:var(--ao-s7);} +body.abyssal-ocean-mode #modal-colors .editor-grid label{color:var(--ao-t2);}body.abyssal-ocean-mode #modal-colors .editor-grid input[type="number"]{background:var(--ao-s5);border-color:var(--ao-s8);color:var(--ao-t1);} +body.abyssal-ocean-mode #file-menu.file-menu-template{background:var(--ao-s3);border-color:var(--ao-s7);box-shadow:2px 4px 16px rgba(0,0,0,0.6);} +body.abyssal-ocean-mode #file-menu .file-menu-left{background:var(--ao-s4);border-right-color:var(--ao-s7);} +body.abyssal-ocean-mode #file-menu .file-menu-item{color:var(--ao-t1);}body.abyssal-ocean-mode #file-menu .file-menu-item:hover{background:var(--ao-s5);border-color:var(--ao-s7);} +body.abyssal-ocean-mode #file-menu .file-menu-separator{background:var(--ao-s7);}body.abyssal-ocean-mode #file-menu .file-menu-right{background:var(--ao-s3);} +body.abyssal-ocean-mode #file-menu .file-menu-recent-toggle{background:var(--ao-s4);border-color:var(--ao-s7);color:var(--ao-t2);} +body.abyssal-ocean-mode #file-menu .file-menu-recent-toggle:hover{background:var(--ao-s5);color:var(--ao-t1);} +body.abyssal-ocean-mode #file-menu .file-menu-recent-header{color:var(--ao-t1);border-bottom-color:var(--ao-s7);} +body.abyssal-ocean-mode #file-menu .file-menu-recent-item{color:var(--ao-t2);}body.abyssal-ocean-mode #file-menu .file-menu-recent-item:hover{background:var(--ao-s5);color:var(--ao-t1);} +body.abyssal-ocean-mode .select-menu{background:var(--ao-s4);border-color:var(--ao-s7);box-shadow:0 4px 16px rgba(0,0,0,0.6);} +body.abyssal-ocean-mode .select-menu-header{background:var(--ao-s4);color:var(--ao-t2);border-bottom-color:var(--ao-s7);} +body.abyssal-ocean-mode .select-menu-item{color:var(--ao-t1);}body.abyssal-ocean-mode .select-menu-item:hover{background:var(--ao-s5);} +body.abyssal-ocean-mode input[type="range"]::-webkit-slider-runnable-track,body.abyssal-ocean-mode input[type="range"]::-moz-range-track{background:var(--ao-s6);} +body.abyssal-ocean-mode input[type="range"]::-webkit-slider-thumb{background:var(--ao-a1);}body.abyssal-ocean-mode input[type="range"]::-moz-range-thumb{background:var(--ao-a1);} +body.abyssal-ocean-mode #save-reminder-modal .window,body.abyssal-ocean-mode #close-confirm-modal .window{background:var(--ao-s3);border-color:var(--ao-s7);color:var(--ao-t1);} +body.abyssal-ocean-mode #lsys-panel{background:var(--ao-s3);border-color:var(--ao-s7);}body.abyssal-ocean-mode #lsys-list{background:var(--ao-s4);} +body.abyssal-ocean-mode .lsys-layer{background:var(--ao-s4);border-bottom-color:var(--ao-s7);color:var(--ao-t1);}body.abyssal-ocean-mode .lsys-layer.active{background:var(--ao-s5);} +body.abyssal-ocean-mode .lsys-layer-name{color:var(--ao-t1);}body.abyssal-ocean-mode #lsys-toolbar{background:var(--ao-s3);border-top-color:var(--ao-s7);} +body.abyssal-ocean-mode .lsys-btn{color:var(--ao-t1);}body.abyssal-ocean-mode .lsys-btn:hover{background:var(--ao-s5);} +body.abyssal-ocean-mode #status-bar,body.abyssal-ocean-mode .status-bar{background:var(--ao-s2);border-top-color:var(--ao-s7);color:var(--ao-t2);} +body.abyssal-ocean-mode #palette-bar,body.abyssal-ocean-mode .palette-bar{background:var(--ao-s3);border-top-color:var(--ao-s7);} +body.abyssal-ocean-mode .mini-swatch.empty{box-shadow:none;} +body.abyssal-ocean-mode #modal-wincolor .tab-btn{background:var(--ao-s5);border-color:var(--ao-s7);color:var(--ao-t1);}body.abyssal-ocean-mode #modal-wincolor .tab-btn.active{background:var(--ao-a2);color:#fff;} +body.abyssal-ocean-mode #swap-colors-btn{background:var(--ao-s4) !important;border-color:var(--ao-s7) !important;color:var(--ao-t1);} +body.abyssal-ocean-mode #swap-colors-btn:hover{background:var(--ao-s5) !important;border-color:var(--ao-s8) !important;} + +/* ════════════════════════════════════════════════════════════════ + * CRIMSON DUSK - dark warm burgundy with deep ember accents + * ════════════════════════════════════════════════════════════════ */ +body.crimson-dusk-mode { + --cd-s0:#0F0707;--cd-s1:#180B0B;--cd-s2:#1E0E0E;--cd-s3:#321414;--cd-s4:#3D1818;--cd-s5:#4A1E1E;--cd-s6:#582424;--cd-s7:#6E3030;--cd-s8:#874040; + --cd-t1:#F0D8D8;--cd-t2:#B07070;--cd-t3:#784848;--cd-a1:#F07070;--cd-a2:#8C1C1C; + --cd-hover-bg:rgba(240,112,112,0.10);--cd-hover-border:rgba(240,112,112,0.30); + --cd-selected-bg:rgba(240,112,112,0.15);--cd-selected-border:rgba(240,112,112,0.40); + --bg-ribbon:var(--cd-s3);--border-ribbon:var(--cd-s7);--app-text-color:var(--cd-t1);--app-bg:var(--cd-s1); + --titlebar-bg:var(--cd-s2);--titlebar-action-icon:var(--cd-t2);--titlebar-action-hover-bg:var(--cd-s5);--titlebar-separator:var(--cd-s7); + --titlebar-filename:var(--cd-t1);--titlebar-control-icon:var(--cd-t1);--tab-row-bg:var(--cd-s2);--section-divider:var(--cd-s7);--section-title-color:var(--cd-t2); + --btn-hover-bg:var(--cd-hover-bg);--btn-hover-border:var(--cd-hover-border);--btn-hover-shadow:rgba(240,112,112,0.15); + --btn-active-bg:var(--cd-selected-bg);--btn-active-border:var(--cd-selected-border);--btn-active-shadow:rgba(240,112,112,0.25); + --dropdown-bg:var(--cd-s4);--dropdown-border:var(--cd-s8);--dropdown-shadow:rgba(0,0,0,0.6);--dropdown-item-hover-bg:var(--cd-s5); + --dropdown-arrow-color:var(--cd-t2);--dropdown-separator:var(--cd-s7);--btn-small-bg:var(--cd-s4);--btn-small-border:var(--cd-s7); + --threshold-label-color:var(--cd-t2);--threshold-values-color:var(--cd-t1);--toggle-icon-color:var(--cd-a1);--toggle-status-color:var(--cd-t2); + --hotkeys-icon-color:var(--cd-a1);--anchor-toggle-icon-color:var(--cd-a1);--theme-mode-toggle-icon-color:var(--cd-a1); + --select-menu-header-color:var(--cd-t2);--select-menu-header-bg:var(--cd-s4);--select-menu-icon-all-fill:rgba(240,112,112,0.18); + --select-menu-icon-all-fill-disabled:var(--cd-s5);--select-menu-icon-disabled-stroke:var(--cd-t3); + --theme-colors-window-bg:var(--cd-s3);--theme-colors-titlebar-bg-start:var(--cd-s4);--theme-colors-titlebar-bg-end:var(--cd-s3); + --theme-colors-titlebar-border:var(--cd-s7);--theme-colors-top-note-color:var(--cd-t2);--theme-colors-result-count-color:var(--cd-t2); + --theme-colors-list-bg:var(--cd-s3);--theme-colors-editor-panel-bg-start:var(--cd-s4);--theme-colors-editor-panel-bg-end:var(--cd-s3); + --theme-colors-editor-panel-border:var(--cd-s7);--theme-colors-editor-title-color:var(--cd-t1);--theme-colors-editor-key-color:var(--cd-t1); + --theme-colors-editor-input-bg:var(--cd-s5);--theme-colors-editor-input-border:var(--cd-s8);--theme-colors-editor-swatch-border:var(--cd-s8); + --theme-colors-editor-hint-color:var(--cd-t3);--theme-colors-mini-toggle-color:var(--cd-t1); + --palette-mini-swatch-border:#0A0303;--palette-mini-swatch-inner:#fff; + --palette-mini-swatch-hover-border:var(--cd-a1);--palette-mini-swatch-hover-inner:rgba(240,112,112,0.2); + --view-center-icon-color:var(--cd-a1);--view-edgeclean-icon-color:var(--cd-a1);--view-theme-icon-color:var(--cd-a1); + --select-icon-free-color:var(--cd-a1);--select-icon-poly-main-color:var(--cd-a1);--select-icon-poly-accent-color:#FF9090; + --bg-hover:var(--cd-hover-bg);--border-hover:var(--cd-hover-border);--bg-selected:var(--cd-selected-bg);--border-selected:var(--cd-selected-border); + --bg-canvas:#3E1E1E;--win-blue:var(--cd-a1); +} +body.crimson-dusk-mode{background:var(--cd-s1);color:var(--cd-t1);} +body.crimson-dusk-mode #title-bar{background:var(--cd-s2);border-bottom:none;} +body.crimson-dusk-mode .tab-row{background:var(--cd-s2);border-bottom-color:var(--cd-s7);border-top:1px solid var(--cd-s2);color:var(--cd-t1);} +body.crimson-dusk-mode .tab{color:var(--cd-t2);border-color:transparent;} +body.crimson-dusk-mode .tab:not(.file):not(.active):hover{color:var(--cd-t1);background:var(--cd-s5);border-color:var(--cd-s7);} +body.crimson-dusk-mode .tab.active{background:var(--cd-s3);border-color:var(--cd-s7);border-bottom-color:var(--cd-s3);color:var(--cd-t1);} +body.crimson-dusk-mode .tab-row .dd-arrow{color:var(--cd-t1);} +body.crimson-dusk-mode .ribbon{background:var(--cd-s3);border-bottom:1px solid var(--cd-s7);} +body.crimson-dusk-mode .section{border-right-color:var(--cd-s7);}body.crimson-dusk-mode .section-title{color:var(--cd-t3);} +body.crimson-dusk-mode .btn-large{color:var(--cd-t1);}body.crimson-dusk-mode .btn-large:hover{background:var(--cd-s5);border-color:var(--cd-s7);} +body.crimson-dusk-mode .btn-large.active,body.crimson-dusk-mode .btn-large.is-on{background:var(--cd-selected-bg);border-color:var(--cd-selected-border);} +body.crimson-dusk-mode .toggle-status{color:var(--cd-t2);} +body.crimson-dusk-mode .toggle-btn .toggle-icons,body.crimson-dusk-mode #anchor-toggle-btn .toggle-icons,body.crimson-dusk-mode #theme-mode-btn .toggle-icons{color:var(--cd-a1);} +body.crimson-dusk-mode svg [fill="#0078d7"]{fill:var(--cd-a1);}body.crimson-dusk-mode svg [stroke="#0078d7"]{stroke:var(--cd-a1);} +body.crimson-dusk-mode .ribbon-card{background:var(--cd-s4);border-color:var(--cd-s7);color:var(--cd-t1);} +body.crimson-dusk-mode .ribbon-card .card-label{color:var(--cd-t1);}body.crimson-dusk-mode .ribbon-card .mini-label{color:var(--cd-t2);} +body.crimson-dusk-mode .compact-input{background:var(--cd-s5);border-color:var(--cd-s8);color:var(--cd-t1);} +body.crimson-dusk-mode .dropdown-panel,body.crimson-dusk-mode .paint-dropdown{background:var(--cd-s4);border-color:var(--cd-s7);box-shadow:0 4px 16px rgba(0,0,0,0.6);} +body.crimson-dusk-mode .dropdown-item,body.crimson-dusk-mode .paint-dropdown-item{color:var(--cd-t1);} +body.crimson-dusk-mode .dropdown-item:hover,body.crimson-dusk-mode .paint-dropdown-item:hover{background:var(--cd-s5);} +body.crimson-dusk-mode .dropdown-separator{background:var(--cd-s7);} +body.crimson-dusk-mode .modal-mask{background:rgba(0,0,0,0.65);} +body.crimson-dusk-mode #modal-resize .window,body.crimson-dusk-mode #modal-depth .window,body.crimson-dusk-mode #modal-export .window,body.crimson-dusk-mode #modal-huesat .window,body.crimson-dusk-mode #modal-hotkeys .window,body.crimson-dusk-mode #modal-info .window,body.crimson-dusk-mode #modal-colors .window,body.crimson-dusk-mode #modal-confirm-reset .window,body.crimson-dusk-mode #modal-toolbar .window,body.crimson-dusk-mode #modal-wincolor .window,body.crimson-dusk-mode .modal-window{background:var(--cd-s3);border-color:var(--cd-s7);color:var(--cd-t1);box-shadow:0 12px 40px rgba(0,0,0,0.7);} +body.crimson-dusk-mode #modal-resize .title-bar,body.crimson-dusk-mode #modal-depth .title-bar,body.crimson-dusk-mode #modal-export .title-bar,body.crimson-dusk-mode #modal-huesat .title-bar,body.crimson-dusk-mode #modal-hotkeys .title-bar,body.crimson-dusk-mode #modal-info .title-bar,body.crimson-dusk-mode #modal-colors .title-bar,body.crimson-dusk-mode #modal-confirm-reset .title-bar,body.crimson-dusk-mode #modal-toolbar .title-bar,body.crimson-dusk-mode #modal-wincolor .title-bar{background:var(--cd-s4);border-bottom-color:var(--cd-s7);color:var(--cd-t1);} +body.crimson-dusk-mode .close-btn{color:var(--cd-t2);}body.crimson-dusk-mode .close-btn:hover{background:#c42b1c;color:#fff;} +body.crimson-dusk-mode #modal-resize .footer,body.crimson-dusk-mode #modal-depth .footer,body.crimson-dusk-mode #modal-export .footer,body.crimson-dusk-mode #modal-huesat .footer,body.crimson-dusk-mode #modal-hotkeys .footer,body.crimson-dusk-mode #modal-colors .footer{border-top-color:var(--cd-s7);} +body.crimson-dusk-mode .modal-mask .btn,body.crimson-dusk-mode .modal-mask button.btn{background:var(--cd-s5);border-color:var(--cd-s8);color:var(--cd-t1);} +body.crimson-dusk-mode .modal-mask .btn:hover{background:var(--cd-s6);border-color:var(--cd-a2);} +body.crimson-dusk-mode .modal-mask .btn-primary,body.crimson-dusk-mode .modal-mask .btn-ok{background:var(--cd-a2);border-color:#6A1010;color:#fff;} +body.crimson-dusk-mode .modal-mask .btn-primary:hover,body.crimson-dusk-mode .modal-mask .btn-ok:hover{background:#A82020;} +body.crimson-dusk-mode .modal-mask input[type="text"],body.crimson-dusk-mode .modal-mask input[type="number"],body.crimson-dusk-mode .modal-mask select,body.crimson-dusk-mode .modal-mask textarea{background:var(--cd-s5);border-color:var(--cd-s8);color:var(--cd-t1);} +body.crimson-dusk-mode .modal-mask input[type="text"]:focus,body.crimson-dusk-mode .modal-mask input[type="number"]:focus,body.crimson-dusk-mode .modal-mask select:focus{border-color:var(--cd-a1);outline:none;} +body.crimson-dusk-mode .modal-mask label,body.crimson-dusk-mode .modal-mask .row label{color:var(--cd-t1);} +body.crimson-dusk-mode .modal-mask fieldset{border-color:var(--cd-s7);}body.crimson-dusk-mode .modal-mask legend,body.crimson-dusk-mode .modal-mask .section-header{color:var(--cd-t2);} +body.crimson-dusk-mode .modal-mask .section-header{border-bottom-color:var(--cd-s7);} +body.crimson-dusk-mode .hotkey-list{background:var(--cd-s4);border-color:var(--cd-s7);}body.crimson-dusk-mode .hotkey-row{border-bottom-color:var(--cd-s7);} +body.crimson-dusk-mode .hotkey-label{color:var(--cd-t1);}body.crimson-dusk-mode .hotkeys-icon{color:var(--cd-a1);} +body.crimson-dusk-mode #modal-info .info-section{border-bottom-color:var(--cd-s7);}body.crimson-dusk-mode #modal-info .info-title{color:var(--cd-a1);} +body.crimson-dusk-mode #modal-info li,body.crimson-dusk-mode #modal-info p{color:var(--cd-t1);}body.crimson-dusk-mode #modal-info .link-btn{color:var(--cd-a1);} +body.crimson-dusk-mode #modal-colors .color-item{border-bottom-color:var(--cd-s7);} +body.crimson-dusk-mode #modal-colors .color-item:hover{background:var(--cd-s5);border-color:var(--cd-s7);} +body.crimson-dusk-mode #modal-colors .color-item.is-active{background:var(--cd-selected-bg);border-color:var(--cd-selected-border);} +body.crimson-dusk-mode #modal-colors .color-label,body.crimson-dusk-mode #modal-colors .close-btn{color:var(--cd-t1);} +body.crimson-dusk-mode #modal-colors .color-element-label,body.crimson-dusk-mode #modal-colors .select-hint{color:var(--cd-t2);} +body.crimson-dusk-mode #modal-colors .color-input,body.crimson-dusk-mode .preset-select,body.crimson-dusk-mode .preset-input,body.crimson-dusk-mode .search-input{background:var(--cd-s5);border-color:var(--cd-s8);color:var(--cd-t1);} +body.crimson-dusk-mode #modal-colors .color-input.invalid{border-color:#ff6060;background:rgba(255,96,96,0.15);} +body.crimson-dusk-mode #modal-colors .btn{background:var(--cd-s5);border-color:var(--cd-s8);color:var(--cd-t1);} +body.crimson-dusk-mode #modal-colors .btn:hover{background:var(--cd-s6);border-color:var(--cd-a1);} +body.crimson-dusk-mode #modal-colors .color-list{border-color:var(--cd-s7);}body.crimson-dusk-mode #modal-colors .preset-row{background:var(--cd-s4);border-color:var(--cd-s7);} +body.crimson-dusk-mode #modal-colors .editor-grid label{color:var(--cd-t2);}body.crimson-dusk-mode #modal-colors .editor-grid input[type="number"]{background:var(--cd-s5);border-color:var(--cd-s8);color:var(--cd-t1);} +body.crimson-dusk-mode #file-menu.file-menu-template{background:var(--cd-s3);border-color:var(--cd-s7);box-shadow:2px 4px 16px rgba(0,0,0,0.6);} +body.crimson-dusk-mode #file-menu .file-menu-left{background:var(--cd-s4);border-right-color:var(--cd-s7);} +body.crimson-dusk-mode #file-menu .file-menu-item{color:var(--cd-t1);}body.crimson-dusk-mode #file-menu .file-menu-item:hover{background:var(--cd-s5);border-color:var(--cd-s7);} +body.crimson-dusk-mode #file-menu .file-menu-separator{background:var(--cd-s7);}body.crimson-dusk-mode #file-menu .file-menu-right{background:var(--cd-s3);} +body.crimson-dusk-mode #file-menu .file-menu-recent-toggle{background:var(--cd-s4);border-color:var(--cd-s7);color:var(--cd-t2);} +body.crimson-dusk-mode #file-menu .file-menu-recent-toggle:hover{background:var(--cd-s5);color:var(--cd-t1);} +body.crimson-dusk-mode #file-menu .file-menu-recent-header{color:var(--cd-t1);border-bottom-color:var(--cd-s7);} +body.crimson-dusk-mode #file-menu .file-menu-recent-item{color:var(--cd-t2);}body.crimson-dusk-mode #file-menu .file-menu-recent-item:hover{background:var(--cd-s5);color:var(--cd-t1);} +body.crimson-dusk-mode .select-menu{background:var(--cd-s4);border-color:var(--cd-s7);box-shadow:0 4px 16px rgba(0,0,0,0.6);} +body.crimson-dusk-mode .select-menu-header{background:var(--cd-s4);color:var(--cd-t2);border-bottom-color:var(--cd-s7);} +body.crimson-dusk-mode .select-menu-item{color:var(--cd-t1);}body.crimson-dusk-mode .select-menu-item:hover{background:var(--cd-s5);} +body.crimson-dusk-mode input[type="range"]::-webkit-slider-runnable-track,body.crimson-dusk-mode input[type="range"]::-moz-range-track{background:var(--cd-s6);} +body.crimson-dusk-mode input[type="range"]::-webkit-slider-thumb{background:var(--cd-a1);}body.crimson-dusk-mode input[type="range"]::-moz-range-thumb{background:var(--cd-a1);} +body.crimson-dusk-mode #save-reminder-modal .window,body.crimson-dusk-mode #close-confirm-modal .window{background:var(--cd-s3);border-color:var(--cd-s7);color:var(--cd-t1);} +body.crimson-dusk-mode #lsys-panel{background:var(--cd-s3);border-color:var(--cd-s7);}body.crimson-dusk-mode #lsys-list{background:var(--cd-s4);} +body.crimson-dusk-mode .lsys-layer{background:var(--cd-s4);border-bottom-color:var(--cd-s7);color:var(--cd-t1);}body.crimson-dusk-mode .lsys-layer.active{background:var(--cd-s5);} +body.crimson-dusk-mode .lsys-layer-name{color:var(--cd-t1);}body.crimson-dusk-mode #lsys-toolbar{background:var(--cd-s3);border-top-color:var(--cd-s7);} +body.crimson-dusk-mode .lsys-btn{color:var(--cd-t1);}body.crimson-dusk-mode .lsys-btn:hover{background:var(--cd-s5);} +body.crimson-dusk-mode #status-bar,body.crimson-dusk-mode .status-bar{background:var(--cd-s2);border-top-color:var(--cd-s7);color:var(--cd-t2);} +body.crimson-dusk-mode #palette-bar,body.crimson-dusk-mode .palette-bar{background:var(--cd-s3);border-top-color:var(--cd-s7);} +body.crimson-dusk-mode .mini-swatch.empty{box-shadow:none;} +body.crimson-dusk-mode #modal-wincolor .tab-btn{background:var(--cd-s5);border-color:var(--cd-s7);color:var(--cd-t1);}body.crimson-dusk-mode #modal-wincolor .tab-btn.active{background:var(--cd-a2);color:#fff;} +body.crimson-dusk-mode #swap-colors-btn{background:var(--cd-s4) !important;border-color:var(--cd-s7) !important;color:var(--cd-t1);} +body.crimson-dusk-mode #swap-colors-btn:hover{background:var(--cd-s5) !important;border-color:var(--cd-s8) !important;} + +/* ════════════════════════════════════════════════════════════════ + * GILDED OBSIDIAN - near-black with warm amber-gold accents + * ════════════════════════════════════════════════════════════════ */ +body.gilded-obsidian-mode { + --go-s0:#0C0A06;--go-s1:#130F08;--go-s2:#1A140A;--go-s3:#26200F;--go-s4:#302813;--go-s5:#3C3018;--go-s6:#48391E;--go-s7:#5C4A28;--go-s8:#725E36; + --go-t1:#F2E6C8;--go-t2:#A88A50;--go-t3:#705C30;--go-a1:#D4A845;--go-a2:#7A5C18; + --go-hover-bg:rgba(212,168,69,0.10);--go-hover-border:rgba(212,168,69,0.30); + --go-selected-bg:rgba(212,168,69,0.15);--go-selected-border:rgba(212,168,69,0.40); + --bg-ribbon:var(--go-s3);--border-ribbon:var(--go-s7);--app-text-color:var(--go-t1);--app-bg:var(--go-s1); + --titlebar-bg:var(--go-s2);--titlebar-action-icon:var(--go-t2);--titlebar-action-hover-bg:var(--go-s5);--titlebar-separator:var(--go-s7); + --titlebar-filename:var(--go-t1);--titlebar-control-icon:var(--go-t1);--tab-row-bg:var(--go-s2);--section-divider:var(--go-s7);--section-title-color:var(--go-t2); + --btn-hover-bg:var(--go-hover-bg);--btn-hover-border:var(--go-hover-border);--btn-hover-shadow:rgba(212,168,69,0.15); + --btn-active-bg:var(--go-selected-bg);--btn-active-border:var(--go-selected-border);--btn-active-shadow:rgba(212,168,69,0.25); + --dropdown-bg:var(--go-s4);--dropdown-border:var(--go-s8);--dropdown-shadow:rgba(0,0,0,0.6);--dropdown-item-hover-bg:var(--go-s5); + --dropdown-arrow-color:var(--go-t2);--dropdown-separator:var(--go-s7);--btn-small-bg:var(--go-s4);--btn-small-border:var(--go-s7); + --threshold-label-color:var(--go-t2);--threshold-values-color:var(--go-t1);--toggle-icon-color:var(--go-a1);--toggle-status-color:var(--go-t2); + --hotkeys-icon-color:var(--go-a1);--anchor-toggle-icon-color:var(--go-a1);--theme-mode-toggle-icon-color:var(--go-a1); + --select-menu-header-color:var(--go-t2);--select-menu-header-bg:var(--go-s4);--select-menu-icon-all-fill:rgba(212,168,69,0.18); + --select-menu-icon-all-fill-disabled:var(--go-s5);--select-menu-icon-disabled-stroke:var(--go-t3); + --theme-colors-window-bg:var(--go-s3);--theme-colors-titlebar-bg-start:var(--go-s4);--theme-colors-titlebar-bg-end:var(--go-s3); + --theme-colors-titlebar-border:var(--go-s7);--theme-colors-top-note-color:var(--go-t2);--theme-colors-result-count-color:var(--go-t2); + --theme-colors-list-bg:var(--go-s3);--theme-colors-editor-panel-bg-start:var(--go-s4);--theme-colors-editor-panel-bg-end:var(--go-s3); + --theme-colors-editor-panel-border:var(--go-s7);--theme-colors-editor-title-color:var(--go-t1);--theme-colors-editor-key-color:var(--go-t1); + --theme-colors-editor-input-bg:var(--go-s5);--theme-colors-editor-input-border:var(--go-s8);--theme-colors-editor-swatch-border:var(--go-s8); + --theme-colors-editor-hint-color:var(--go-t3);--theme-colors-mini-toggle-color:var(--go-t1); + --palette-mini-swatch-border:#080604;--palette-mini-swatch-inner:#fff; + --palette-mini-swatch-hover-border:var(--go-a1);--palette-mini-swatch-hover-inner:rgba(212,168,69,0.2); + --view-center-icon-color:var(--go-a1);--view-edgeclean-icon-color:var(--go-a1);--view-theme-icon-color:var(--go-a1); + --select-icon-free-color:var(--go-a1);--select-icon-poly-main-color:var(--go-a1);--select-icon-poly-accent-color:#E8C870; + --bg-hover:var(--go-hover-bg);--border-hover:var(--go-hover-border);--bg-selected:var(--go-selected-bg);--border-selected:var(--go-selected-border); + --bg-canvas:#322A18;--win-blue:var(--go-a1); +} +body.gilded-obsidian-mode{background:var(--go-s1);color:var(--go-t1);} +body.gilded-obsidian-mode #title-bar{background:var(--go-s2);border-bottom:none;} +body.gilded-obsidian-mode .tab-row{background:var(--go-s2);border-bottom-color:var(--go-s7);border-top:1px solid var(--go-s2);color:var(--go-t1);} +body.gilded-obsidian-mode .tab{color:var(--go-t2);border-color:transparent;} +body.gilded-obsidian-mode .tab:not(.file):not(.active):hover{color:var(--go-t1);background:var(--go-s5);border-color:var(--go-s7);} +body.gilded-obsidian-mode .tab.active{background:var(--go-s3);border-color:var(--go-s7);border-bottom-color:var(--go-s3);color:var(--go-t1);} +body.gilded-obsidian-mode .tab-row .dd-arrow{color:var(--go-t1);} +body.gilded-obsidian-mode .ribbon{background:var(--go-s3);border-bottom:1px solid var(--go-s7);} +body.gilded-obsidian-mode .section{border-right-color:var(--go-s7);}body.gilded-obsidian-mode .section-title{color:var(--go-t3);} +body.gilded-obsidian-mode .btn-large{color:var(--go-t1);}body.gilded-obsidian-mode .btn-large:hover{background:var(--go-s5);border-color:var(--go-s7);} +body.gilded-obsidian-mode .btn-large.active,body.gilded-obsidian-mode .btn-large.is-on{background:var(--go-selected-bg);border-color:var(--go-selected-border);} +body.gilded-obsidian-mode .toggle-status{color:var(--go-t2);} +body.gilded-obsidian-mode .toggle-btn .toggle-icons,body.gilded-obsidian-mode #anchor-toggle-btn .toggle-icons,body.gilded-obsidian-mode #theme-mode-btn .toggle-icons{color:var(--go-a1);} +body.gilded-obsidian-mode svg [fill="#0078d7"]{fill:var(--go-a1);}body.gilded-obsidian-mode svg [stroke="#0078d7"]{stroke:var(--go-a1);} +body.gilded-obsidian-mode .ribbon-card{background:var(--go-s4);border-color:var(--go-s7);color:var(--go-t1);} +body.gilded-obsidian-mode .ribbon-card .card-label{color:var(--go-t1);}body.gilded-obsidian-mode .ribbon-card .mini-label{color:var(--go-t2);} +body.gilded-obsidian-mode .compact-input{background:var(--go-s5);border-color:var(--go-s8);color:var(--go-t1);} +body.gilded-obsidian-mode .dropdown-panel,body.gilded-obsidian-mode .paint-dropdown{background:var(--go-s4);border-color:var(--go-s7);box-shadow:0 4px 16px rgba(0,0,0,0.6);} +body.gilded-obsidian-mode .dropdown-item,body.gilded-obsidian-mode .paint-dropdown-item{color:var(--go-t1);} +body.gilded-obsidian-mode .dropdown-item:hover,body.gilded-obsidian-mode .paint-dropdown-item:hover{background:var(--go-s5);} +body.gilded-obsidian-mode .dropdown-separator{background:var(--go-s7);} +body.gilded-obsidian-mode .modal-mask{background:rgba(0,0,0,0.65);} +body.gilded-obsidian-mode #modal-resize .window,body.gilded-obsidian-mode #modal-depth .window,body.gilded-obsidian-mode #modal-export .window,body.gilded-obsidian-mode #modal-huesat .window,body.gilded-obsidian-mode #modal-hotkeys .window,body.gilded-obsidian-mode #modal-info .window,body.gilded-obsidian-mode #modal-colors .window,body.gilded-obsidian-mode #modal-confirm-reset .window,body.gilded-obsidian-mode #modal-toolbar .window,body.gilded-obsidian-mode #modal-wincolor .window,body.gilded-obsidian-mode .modal-window{background:var(--go-s3);border-color:var(--go-s7);color:var(--go-t1);box-shadow:0 12px 40px rgba(0,0,0,0.7);} +body.gilded-obsidian-mode #modal-resize .title-bar,body.gilded-obsidian-mode #modal-depth .title-bar,body.gilded-obsidian-mode #modal-export .title-bar,body.gilded-obsidian-mode #modal-huesat .title-bar,body.gilded-obsidian-mode #modal-hotkeys .title-bar,body.gilded-obsidian-mode #modal-info .title-bar,body.gilded-obsidian-mode #modal-colors .title-bar,body.gilded-obsidian-mode #modal-confirm-reset .title-bar,body.gilded-obsidian-mode #modal-toolbar .title-bar,body.gilded-obsidian-mode #modal-wincolor .title-bar{background:var(--go-s4);border-bottom-color:var(--go-s7);color:var(--go-t1);} +body.gilded-obsidian-mode .close-btn{color:var(--go-t2);}body.gilded-obsidian-mode .close-btn:hover{background:#c42b1c;color:#fff;} +body.gilded-obsidian-mode #modal-resize .footer,body.gilded-obsidian-mode #modal-depth .footer,body.gilded-obsidian-mode #modal-export .footer,body.gilded-obsidian-mode #modal-huesat .footer,body.gilded-obsidian-mode #modal-hotkeys .footer,body.gilded-obsidian-mode #modal-colors .footer{border-top-color:var(--go-s7);} +body.gilded-obsidian-mode .modal-mask .btn,body.gilded-obsidian-mode .modal-mask button.btn{background:var(--go-s5);border-color:var(--go-s8);color:var(--go-t1);} +body.gilded-obsidian-mode .modal-mask .btn:hover{background:var(--go-s6);border-color:var(--go-a2);} +body.gilded-obsidian-mode .modal-mask .btn-primary,body.gilded-obsidian-mode .modal-mask .btn-ok{background:var(--go-a2);border-color:#5A4010;color:#fff;} +body.gilded-obsidian-mode .modal-mask .btn-primary:hover,body.gilded-obsidian-mode .modal-mask .btn-ok:hover{background:#9A7820;} +body.gilded-obsidian-mode .modal-mask input[type="text"],body.gilded-obsidian-mode .modal-mask input[type="number"],body.gilded-obsidian-mode .modal-mask select,body.gilded-obsidian-mode .modal-mask textarea{background:var(--go-s5);border-color:var(--go-s8);color:var(--go-t1);} +body.gilded-obsidian-mode .modal-mask input[type="text"]:focus,body.gilded-obsidian-mode .modal-mask input[type="number"]:focus,body.gilded-obsidian-mode .modal-mask select:focus{border-color:var(--go-a1);outline:none;} +body.gilded-obsidian-mode .modal-mask label,body.gilded-obsidian-mode .modal-mask .row label{color:var(--go-t1);} +body.gilded-obsidian-mode .modal-mask fieldset{border-color:var(--go-s7);}body.gilded-obsidian-mode .modal-mask legend,body.gilded-obsidian-mode .modal-mask .section-header{color:var(--go-t2);} +body.gilded-obsidian-mode .modal-mask .section-header{border-bottom-color:var(--go-s7);} +body.gilded-obsidian-mode .hotkey-list{background:var(--go-s4);border-color:var(--go-s7);}body.gilded-obsidian-mode .hotkey-row{border-bottom-color:var(--go-s7);} +body.gilded-obsidian-mode .hotkey-label{color:var(--go-t1);}body.gilded-obsidian-mode .hotkeys-icon{color:var(--go-a1);} +body.gilded-obsidian-mode #modal-info .info-section{border-bottom-color:var(--go-s7);}body.gilded-obsidian-mode #modal-info .info-title{color:var(--go-a1);} +body.gilded-obsidian-mode #modal-info li,body.gilded-obsidian-mode #modal-info p{color:var(--go-t1);}body.gilded-obsidian-mode #modal-info .link-btn{color:var(--go-a1);} +body.gilded-obsidian-mode #modal-colors .color-item{border-bottom-color:var(--go-s7);} +body.gilded-obsidian-mode #modal-colors .color-item:hover{background:var(--go-s5);border-color:var(--go-s7);} +body.gilded-obsidian-mode #modal-colors .color-item.is-active{background:var(--go-selected-bg);border-color:var(--go-selected-border);} +body.gilded-obsidian-mode #modal-colors .color-label,body.gilded-obsidian-mode #modal-colors .close-btn{color:var(--go-t1);} +body.gilded-obsidian-mode #modal-colors .color-element-label,body.gilded-obsidian-mode #modal-colors .select-hint{color:var(--go-t2);} +body.gilded-obsidian-mode #modal-colors .color-input,body.gilded-obsidian-mode .preset-select,body.gilded-obsidian-mode .preset-input,body.gilded-obsidian-mode .search-input{background:var(--go-s5);border-color:var(--go-s8);color:var(--go-t1);} +body.gilded-obsidian-mode #modal-colors .color-input.invalid{border-color:#e81123;background:rgba(232,17,35,0.15);} +body.gilded-obsidian-mode #modal-colors .btn{background:var(--go-s5);border-color:var(--go-s8);color:var(--go-t1);} +body.gilded-obsidian-mode #modal-colors .btn:hover{background:var(--go-s6);border-color:var(--go-a1);} +body.gilded-obsidian-mode #modal-colors .color-list{border-color:var(--go-s7);}body.gilded-obsidian-mode #modal-colors .preset-row{background:var(--go-s4);border-color:var(--go-s7);} +body.gilded-obsidian-mode #modal-colors .editor-grid label{color:var(--go-t2);}body.gilded-obsidian-mode #modal-colors .editor-grid input[type="number"]{background:var(--go-s5);border-color:var(--go-s8);color:var(--go-t1);} +body.gilded-obsidian-mode #file-menu.file-menu-template{background:var(--go-s3);border-color:var(--go-s7);box-shadow:2px 4px 16px rgba(0,0,0,0.6);} +body.gilded-obsidian-mode #file-menu .file-menu-left{background:var(--go-s4);border-right-color:var(--go-s7);} +body.gilded-obsidian-mode #file-menu .file-menu-item{color:var(--go-t1);}body.gilded-obsidian-mode #file-menu .file-menu-item:hover{background:var(--go-s5);border-color:var(--go-s7);} +body.gilded-obsidian-mode #file-menu .file-menu-separator{background:var(--go-s7);}body.gilded-obsidian-mode #file-menu .file-menu-right{background:var(--go-s3);} +body.gilded-obsidian-mode #file-menu .file-menu-recent-toggle{background:var(--go-s4);border-color:var(--go-s7);color:var(--go-t2);} +body.gilded-obsidian-mode #file-menu .file-menu-recent-toggle:hover{background:var(--go-s5);color:var(--go-t1);} +body.gilded-obsidian-mode #file-menu .file-menu-recent-header{color:var(--go-t1);border-bottom-color:var(--go-s7);} +body.gilded-obsidian-mode #file-menu .file-menu-recent-item{color:var(--go-t2);}body.gilded-obsidian-mode #file-menu .file-menu-recent-item:hover{background:var(--go-s5);color:var(--go-t1);} +body.gilded-obsidian-mode .select-menu{background:var(--go-s4);border-color:var(--go-s7);box-shadow:0 4px 16px rgba(0,0,0,0.6);} +body.gilded-obsidian-mode .select-menu-header{background:var(--go-s4);color:var(--go-t2);border-bottom-color:var(--go-s7);} +body.gilded-obsidian-mode .select-menu-item{color:var(--go-t1);}body.gilded-obsidian-mode .select-menu-item:hover{background:var(--go-s5);} +body.gilded-obsidian-mode input[type="range"]::-webkit-slider-runnable-track,body.gilded-obsidian-mode input[type="range"]::-moz-range-track{background:var(--go-s6);} +body.gilded-obsidian-mode input[type="range"]::-webkit-slider-thumb{background:var(--go-a1);}body.gilded-obsidian-mode input[type="range"]::-moz-range-thumb{background:var(--go-a1);} +body.gilded-obsidian-mode #save-reminder-modal .window,body.gilded-obsidian-mode #close-confirm-modal .window{background:var(--go-s3);border-color:var(--go-s7);color:var(--go-t1);} +body.gilded-obsidian-mode #lsys-panel{background:var(--go-s3);border-color:var(--go-s7);}body.gilded-obsidian-mode #lsys-list{background:var(--go-s4);} +body.gilded-obsidian-mode .lsys-layer{background:var(--go-s4);border-bottom-color:var(--go-s7);color:var(--go-t1);}body.gilded-obsidian-mode .lsys-layer.active{background:var(--go-s5);} +body.gilded-obsidian-mode .lsys-layer-name{color:var(--go-t1);}body.gilded-obsidian-mode #lsys-toolbar{background:var(--go-s3);border-top-color:var(--go-s7);} +body.gilded-obsidian-mode .lsys-btn{color:var(--go-t1);}body.gilded-obsidian-mode .lsys-btn:hover{background:var(--go-s5);} +body.gilded-obsidian-mode #status-bar,body.gilded-obsidian-mode .status-bar{background:var(--go-s2);border-top-color:var(--go-s7);color:var(--go-t2);} +body.gilded-obsidian-mode #palette-bar,body.gilded-obsidian-mode .palette-bar{background:var(--go-s3);border-top-color:var(--go-s7);} +body.gilded-obsidian-mode .mini-swatch.empty{box-shadow:none;} +body.gilded-obsidian-mode #modal-wincolor .tab-btn{background:var(--go-s5);border-color:var(--go-s7);color:var(--go-t1);}body.gilded-obsidian-mode #modal-wincolor .tab-btn.active{background:var(--go-a2);color:#fff;} +body.gilded-obsidian-mode #swap-colors-btn{background:var(--go-s4) !important;border-color:var(--go-s7) !important;color:var(--go-t1);} +body.gilded-obsidian-mode #swap-colors-btn:hover{background:var(--go-s5) !important;border-color:var(--go-s8) !important;} + +/* ════════════════════════════════════════════════════════════════ + * VIOLET HAZE - deep purple-indigo with soft violet accents + * ════════════════════════════════════════════════════════════════ */ +body.violet-haze-mode { + --vh-s0:#0A0810;--vh-s1:#0E0B18;--vh-s2:#130E20;--vh-s3:#1E1635;--vh-s4:#251C42;--vh-s5:#2E2250;--vh-s6:#382860;--vh-s7:#4A3878;--vh-s8:#5E4C90; + --vh-t1:#E0D8F8;--vh-t2:#8878C0;--vh-t3:#584880;--vh-a1:#A888F0;--vh-a2:#4C2A9C; + --vh-hover-bg:rgba(168,136,240,0.10);--vh-hover-border:rgba(168,136,240,0.30); + --vh-selected-bg:rgba(168,136,240,0.15);--vh-selected-border:rgba(168,136,240,0.40); + --bg-ribbon:var(--vh-s3);--border-ribbon:var(--vh-s7);--app-text-color:var(--vh-t1);--app-bg:var(--vh-s1); + --titlebar-bg:var(--vh-s2);--titlebar-action-icon:var(--vh-t2);--titlebar-action-hover-bg:var(--vh-s5);--titlebar-separator:var(--vh-s7); + --titlebar-filename:var(--vh-t1);--titlebar-control-icon:var(--vh-t1);--tab-row-bg:var(--vh-s2);--section-divider:var(--vh-s7);--section-title-color:var(--vh-t2); + --btn-hover-bg:var(--vh-hover-bg);--btn-hover-border:var(--vh-hover-border);--btn-hover-shadow:rgba(168,136,240,0.15); + --btn-active-bg:var(--vh-selected-bg);--btn-active-border:var(--vh-selected-border);--btn-active-shadow:rgba(168,136,240,0.25); + --dropdown-bg:var(--vh-s4);--dropdown-border:var(--vh-s8);--dropdown-shadow:rgba(0,0,0,0.6);--dropdown-item-hover-bg:var(--vh-s5); + --dropdown-arrow-color:var(--vh-t2);--dropdown-separator:var(--vh-s7);--btn-small-bg:var(--vh-s4);--btn-small-border:var(--vh-s7); + --threshold-label-color:var(--vh-t2);--threshold-values-color:var(--vh-t1);--toggle-icon-color:var(--vh-a1);--toggle-status-color:var(--vh-t2); + --hotkeys-icon-color:var(--vh-a1);--anchor-toggle-icon-color:var(--vh-a1);--theme-mode-toggle-icon-color:var(--vh-a1); + --select-menu-header-color:var(--vh-t2);--select-menu-header-bg:var(--vh-s4);--select-menu-icon-all-fill:rgba(168,136,240,0.18); + --select-menu-icon-all-fill-disabled:var(--vh-s5);--select-menu-icon-disabled-stroke:var(--vh-t3); + --theme-colors-window-bg:var(--vh-s3);--theme-colors-titlebar-bg-start:var(--vh-s4);--theme-colors-titlebar-bg-end:var(--vh-s3); + --theme-colors-titlebar-border:var(--vh-s7);--theme-colors-top-note-color:var(--vh-t2);--theme-colors-result-count-color:var(--vh-t2); + --theme-colors-list-bg:var(--vh-s3);--theme-colors-editor-panel-bg-start:var(--vh-s4);--theme-colors-editor-panel-bg-end:var(--vh-s3); + --theme-colors-editor-panel-border:var(--vh-s7);--theme-colors-editor-title-color:var(--vh-t1);--theme-colors-editor-key-color:var(--vh-t1); + --theme-colors-editor-input-bg:var(--vh-s5);--theme-colors-editor-input-border:var(--vh-s8);--theme-colors-editor-swatch-border:var(--vh-s8); + --theme-colors-editor-hint-color:var(--vh-t3);--theme-colors-mini-toggle-color:var(--vh-t1); + --palette-mini-swatch-border:#06040C;--palette-mini-swatch-inner:#fff; + --palette-mini-swatch-hover-border:var(--vh-a1);--palette-mini-swatch-hover-inner:rgba(168,136,240,0.2); + --view-center-icon-color:var(--vh-a1);--view-edgeclean-icon-color:var(--vh-a1);--view-theme-icon-color:var(--vh-a1); + --select-icon-free-color:var(--vh-a1);--select-icon-poly-main-color:var(--vh-a1);--select-icon-poly-accent-color:#C4A8FF; + --bg-hover:var(--vh-hover-bg);--border-hover:var(--vh-hover-border);--bg-selected:var(--vh-selected-bg);--border-selected:var(--vh-selected-border); + --bg-canvas:#2A2047;--win-blue:var(--vh-a1); +} +body.violet-haze-mode{background:var(--vh-s1);color:var(--vh-t1);} +body.violet-haze-mode #title-bar{background:var(--vh-s2);border-bottom:none;} +body.violet-haze-mode .tab-row{background:var(--vh-s2);border-bottom-color:var(--vh-s7);border-top:1px solid var(--vh-s2);color:var(--vh-t1);} +body.violet-haze-mode .tab{color:var(--vh-t2);border-color:transparent;} +body.violet-haze-mode .tab:not(.file):not(.active):hover{color:var(--vh-t1);background:var(--vh-s5);border-color:var(--vh-s7);} +body.violet-haze-mode .tab.active{background:var(--vh-s3);border-color:var(--vh-s7);border-bottom-color:var(--vh-s3);color:var(--vh-t1);} +body.violet-haze-mode .tab-row .dd-arrow{color:var(--vh-t1);} +body.violet-haze-mode .ribbon{background:var(--vh-s3);border-bottom:1px solid var(--vh-s7);} +body.violet-haze-mode .section{border-right-color:var(--vh-s7);}body.violet-haze-mode .section-title{color:var(--vh-t3);} +body.violet-haze-mode .btn-large{color:var(--vh-t1);}body.violet-haze-mode .btn-large:hover{background:var(--vh-s5);border-color:var(--vh-s7);} +body.violet-haze-mode .btn-large.active,body.violet-haze-mode .btn-large.is-on{background:var(--vh-selected-bg);border-color:var(--vh-selected-border);} +body.violet-haze-mode .toggle-status{color:var(--vh-t2);} +body.violet-haze-mode .toggle-btn .toggle-icons,body.violet-haze-mode #anchor-toggle-btn .toggle-icons,body.violet-haze-mode #theme-mode-btn .toggle-icons{color:var(--vh-a1);} +body.violet-haze-mode svg [fill="#0078d7"]{fill:var(--vh-a1);}body.violet-haze-mode svg [stroke="#0078d7"]{stroke:var(--vh-a1);} +body.violet-haze-mode .ribbon-card{background:var(--vh-s4);border-color:var(--vh-s7);color:var(--vh-t1);} +body.violet-haze-mode .ribbon-card .card-label{color:var(--vh-t1);}body.violet-haze-mode .ribbon-card .mini-label{color:var(--vh-t2);} +body.violet-haze-mode .compact-input{background:var(--vh-s5);border-color:var(--vh-s8);color:var(--vh-t1);} +body.violet-haze-mode .dropdown-panel,body.violet-haze-mode .paint-dropdown{background:var(--vh-s4);border-color:var(--vh-s7);box-shadow:0 4px 16px rgba(0,0,0,0.6);} +body.violet-haze-mode .dropdown-item,body.violet-haze-mode .paint-dropdown-item{color:var(--vh-t1);} +body.violet-haze-mode .dropdown-item:hover,body.violet-haze-mode .paint-dropdown-item:hover{background:var(--vh-s5);} +body.violet-haze-mode .dropdown-separator{background:var(--vh-s7);} +body.violet-haze-mode .modal-mask{background:rgba(0,0,0,0.65);} +body.violet-haze-mode #modal-resize .window,body.violet-haze-mode #modal-depth .window,body.violet-haze-mode #modal-export .window,body.violet-haze-mode #modal-huesat .window,body.violet-haze-mode #modal-hotkeys .window,body.violet-haze-mode #modal-info .window,body.violet-haze-mode #modal-colors .window,body.violet-haze-mode #modal-confirm-reset .window,body.violet-haze-mode #modal-toolbar .window,body.violet-haze-mode #modal-wincolor .window,body.violet-haze-mode .modal-window{background:var(--vh-s3);border-color:var(--vh-s7);color:var(--vh-t1);box-shadow:0 12px 40px rgba(0,0,0,0.7);} +body.violet-haze-mode #modal-resize .title-bar,body.violet-haze-mode #modal-depth .title-bar,body.violet-haze-mode #modal-export .title-bar,body.violet-haze-mode #modal-huesat .title-bar,body.violet-haze-mode #modal-hotkeys .title-bar,body.violet-haze-mode #modal-info .title-bar,body.violet-haze-mode #modal-colors .title-bar,body.violet-haze-mode #modal-confirm-reset .title-bar,body.violet-haze-mode #modal-toolbar .title-bar,body.violet-haze-mode #modal-wincolor .title-bar{background:var(--vh-s4);border-bottom-color:var(--vh-s7);color:var(--vh-t1);} +body.violet-haze-mode .close-btn{color:var(--vh-t2);}body.violet-haze-mode .close-btn:hover{background:#c42b1c;color:#fff;} +body.violet-haze-mode #modal-resize .footer,body.violet-haze-mode #modal-depth .footer,body.violet-haze-mode #modal-export .footer,body.violet-haze-mode #modal-huesat .footer,body.violet-haze-mode #modal-hotkeys .footer,body.violet-haze-mode #modal-colors .footer{border-top-color:var(--vh-s7);} +body.violet-haze-mode .modal-mask .btn,body.violet-haze-mode .modal-mask button.btn{background:var(--vh-s5);border-color:var(--vh-s8);color:var(--vh-t1);} +body.violet-haze-mode .modal-mask .btn:hover{background:var(--vh-s6);border-color:var(--vh-a2);} +body.violet-haze-mode .modal-mask .btn-primary,body.violet-haze-mode .modal-mask .btn-ok{background:var(--vh-a2);border-color:#361A78;color:#fff;} +body.violet-haze-mode .modal-mask .btn-primary:hover,body.violet-haze-mode .modal-mask .btn-ok:hover{background:#6038C0;} +body.violet-haze-mode .modal-mask input[type="text"],body.violet-haze-mode .modal-mask input[type="number"],body.violet-haze-mode .modal-mask select,body.violet-haze-mode .modal-mask textarea{background:var(--vh-s5);border-color:var(--vh-s8);color:var(--vh-t1);} +body.violet-haze-mode .modal-mask input[type="text"]:focus,body.violet-haze-mode .modal-mask input[type="number"]:focus,body.violet-haze-mode .modal-mask select:focus{border-color:var(--vh-a1);outline:none;} +body.violet-haze-mode .modal-mask label,body.violet-haze-mode .modal-mask .row label{color:var(--vh-t1);} +body.violet-haze-mode .modal-mask fieldset{border-color:var(--vh-s7);}body.violet-haze-mode .modal-mask legend,body.violet-haze-mode .modal-mask .section-header{color:var(--vh-t2);} +body.violet-haze-mode .modal-mask .section-header{border-bottom-color:var(--vh-s7);} +body.violet-haze-mode .hotkey-list{background:var(--vh-s4);border-color:var(--vh-s7);}body.violet-haze-mode .hotkey-row{border-bottom-color:var(--vh-s7);} +body.violet-haze-mode .hotkey-label{color:var(--vh-t1);}body.violet-haze-mode .hotkeys-icon{color:var(--vh-a1);} +body.violet-haze-mode #modal-info .info-section{border-bottom-color:var(--vh-s7);}body.violet-haze-mode #modal-info .info-title{color:var(--vh-a1);} +body.violet-haze-mode #modal-info li,body.violet-haze-mode #modal-info p{color:var(--vh-t1);}body.violet-haze-mode #modal-info .link-btn{color:var(--vh-a1);} +body.violet-haze-mode #modal-colors .color-item{border-bottom-color:var(--vh-s7);} +body.violet-haze-mode #modal-colors .color-item:hover{background:var(--vh-s5);border-color:var(--vh-s7);} +body.violet-haze-mode #modal-colors .color-item.is-active{background:var(--vh-selected-bg);border-color:var(--vh-selected-border);} +body.violet-haze-mode #modal-colors .color-label,body.violet-haze-mode #modal-colors .close-btn{color:var(--vh-t1);} +body.violet-haze-mode #modal-colors .color-element-label,body.violet-haze-mode #modal-colors .select-hint{color:var(--vh-t2);} +body.violet-haze-mode #modal-colors .color-input,body.violet-haze-mode .preset-select,body.violet-haze-mode .preset-input,body.violet-haze-mode .search-input{background:var(--vh-s5);border-color:var(--vh-s8);color:var(--vh-t1);} +body.violet-haze-mode #modal-colors .color-input.invalid{border-color:#e81123;background:rgba(232,17,35,0.15);} +body.violet-haze-mode #modal-colors .btn{background:var(--vh-s5);border-color:var(--vh-s8);color:var(--vh-t1);} +body.violet-haze-mode #modal-colors .btn:hover{background:var(--vh-s6);border-color:var(--vh-a1);} +body.violet-haze-mode #modal-colors .color-list{border-color:var(--vh-s7);}body.violet-haze-mode #modal-colors .preset-row{background:var(--vh-s4);border-color:var(--vh-s7);} +body.violet-haze-mode #modal-colors .editor-grid label{color:var(--vh-t2);}body.violet-haze-mode #modal-colors .editor-grid input[type="number"]{background:var(--vh-s5);border-color:var(--vh-s8);color:var(--vh-t1);} +body.violet-haze-mode #file-menu.file-menu-template{background:var(--vh-s3);border-color:var(--vh-s7);box-shadow:2px 4px 16px rgba(0,0,0,0.6);} +body.violet-haze-mode #file-menu .file-menu-left{background:var(--vh-s4);border-right-color:var(--vh-s7);} +body.violet-haze-mode #file-menu .file-menu-item{color:var(--vh-t1);}body.violet-haze-mode #file-menu .file-menu-item:hover{background:var(--vh-s5);border-color:var(--vh-s7);} +body.violet-haze-mode #file-menu .file-menu-separator{background:var(--vh-s7);}body.violet-haze-mode #file-menu .file-menu-right{background:var(--vh-s3);} +body.violet-haze-mode #file-menu .file-menu-recent-toggle{background:var(--vh-s4);border-color:var(--vh-s7);color:var(--vh-t2);} +body.violet-haze-mode #file-menu .file-menu-recent-toggle:hover{background:var(--vh-s5);color:var(--vh-t1);} +body.violet-haze-mode #file-menu .file-menu-recent-header{color:var(--vh-t1);border-bottom-color:var(--vh-s7);} +body.violet-haze-mode #file-menu .file-menu-recent-item{color:var(--vh-t2);}body.violet-haze-mode #file-menu .file-menu-recent-item:hover{background:var(--vh-s5);color:var(--vh-t1);} +body.violet-haze-mode .select-menu{background:var(--vh-s4);border-color:var(--vh-s7);box-shadow:0 4px 16px rgba(0,0,0,0.6);} +body.violet-haze-mode .select-menu-header{background:var(--vh-s4);color:var(--vh-t2);border-bottom-color:var(--vh-s7);} +body.violet-haze-mode .select-menu-item{color:var(--vh-t1);}body.violet-haze-mode .select-menu-item:hover{background:var(--vh-s5);} +body.violet-haze-mode input[type="range"]::-webkit-slider-runnable-track,body.violet-haze-mode input[type="range"]::-moz-range-track{background:var(--vh-s6);} +body.violet-haze-mode input[type="range"]::-webkit-slider-thumb{background:var(--vh-a1);}body.violet-haze-mode input[type="range"]::-moz-range-thumb{background:var(--vh-a1);} +body.violet-haze-mode #save-reminder-modal .window,body.violet-haze-mode #close-confirm-modal .window{background:var(--vh-s3);border-color:var(--vh-s7);color:var(--vh-t1);} +body.violet-haze-mode #lsys-panel{background:var(--vh-s3);border-color:var(--vh-s7);}body.violet-haze-mode #lsys-list{background:var(--vh-s4);} +body.violet-haze-mode .lsys-layer{background:var(--vh-s4);border-bottom-color:var(--vh-s7);color:var(--vh-t1);}body.violet-haze-mode .lsys-layer.active{background:var(--vh-s5);} +body.violet-haze-mode .lsys-layer-name{color:var(--vh-t1);}body.violet-haze-mode #lsys-toolbar{background:var(--vh-s3);border-top-color:var(--vh-s7);} +body.violet-haze-mode .lsys-btn{color:var(--vh-t1);}body.violet-haze-mode .lsys-btn:hover{background:var(--vh-s5);} +body.violet-haze-mode #status-bar,body.violet-haze-mode .status-bar{background:var(--vh-s2);border-top-color:var(--vh-s7);color:var(--vh-t2);} +body.violet-haze-mode #palette-bar,body.violet-haze-mode .palette-bar{background:var(--vh-s3);border-top-color:var(--vh-s7);} +body.violet-haze-mode .mini-swatch.empty{box-shadow:none;} +body.violet-haze-mode #modal-wincolor .tab-btn{background:var(--vh-s5);border-color:var(--vh-s7);color:var(--vh-t1);}body.violet-haze-mode #modal-wincolor .tab-btn.active{background:var(--vh-a2);color:#fff;} +body.violet-haze-mode #swap-colors-btn{background:var(--vh-s4) !important;border-color:var(--vh-s7) !important;color:var(--vh-t1);} +body.violet-haze-mode #swap-colors-btn:hover{background:var(--vh-s5) !important;border-color:var(--vh-s8) !important;} diff --git a/src/freehand-path-engine.js b/src/freehand-path-engine.js new file mode 100644 index 0000000..8e5bb54 --- /dev/null +++ b/src/freehand-path-engine.js @@ -0,0 +1,571 @@ +// ─── Freehand Path Engine v2 ──────────────────────────────────────────────── +// +// Three-stage smoothing pipeline for high-quality freehand drawing: +// 1. Live draft preview β€” rAF-scheduled raw lineTo (zero perceptual latency) +// 2. RDP simplification β€” culls redundant collinear points +// 3. Centripetal CR fit β€” converts survivors to smooth cubic BΓ©ziers +// β€’ Ξ± = 0.5 eliminates cusps from uneven sampling rates +// β€’ Corner detection preserves intentional sharp turns +// +// Rendering: +// β€’ Uniform width β†’ single batched Path2D stroke (fast path) +// β€’ Variable width β†’ pressure-driven filled polygon with rounded end-caps +// +// Changes from v1: +// β€’ catmullRomToBezier() upgraded from uniform to centripetal parameterization. +// Uniform CR overshoots when drawing speed changes (pause β†’ fast sweep β†’ pause), +// producing visible cusps or loops. Centripetal weights knot intervals by √chord +// length, keeping the curve well-behaved regardless of input cadence. +// β€’ detectCorners() added β€” C0 joins at turns sharper than _cornerAngle (~72Β° default). +// Passed into catmullRomToBezier() so tangents are zeroed at hard corners; the +// user's intentional angle is preserved rather than smoothed away. +// β€’ _renderOutline() added β€” when minWidth β‰  lineWidth, the committed stroke is +// rendered as a filled polygon whose half-width at each sample is linearly +// interpolated from the stylus pressure of the two surrounding knot points. +// Rounded end-caps are added via arcs at stroke start and end. +// β€’ Draft rendering is rAF-throttled: N pointermove events in one display frame +// collapse to one clearRect + redraw instead of N redundant ones. +// β€’ _rawPoints capped at MAX_RAW_POINTS to prevent unbounded memory on very long +// strokes (4000 pts Γ— 3 px/pt β‰ˆ 12 m at 96 dpi β€” never hit in practice). +// β€’ onPointerUp fixed: rdpSimplify was called twice (once in _finalize, once to +// build the result object). Now called once; simplified points returned by _finalize. +// β€’ Uniform commit uses a single Path2D (one GPU draw call) instead of per-segment +// beginPath/stroke, which flushed the pipeline for every BΓ©zier segment. +// β€’ init() accepts minWidth, tension, cornerAngle, usePressure for fine-tuning. +// β€’ setPointerCapture(pointerId) should be called on pointerdown to ensure +// pointerup fires even when the cursor leaves the canvas element. +// +const FreehandPathEngine = (() => { + + // ── Tunables ───────────────────────────────────────────────────────── + const MIN_DISTANCE = 3; // px β€” micro-movement filter threshold + const RDP_TOLERANCE = 1.5; // px β€” max allowable perpendicular deviation + const MAX_RAW_POINTS = 4000; // hard cap on raw point buffer length + const ALPHA = 0.5; // CR knot exponent: 0=uniform, 0.5=centripetal, 1=chordal + const OUTLINE_SAMPLES = 10; // BΓ©zier samples per segment for variable-width outline + + // ── State ───────────────────────────────────────────────────────────── + let _isDrawing = false; + let _rawPoints = []; // { x, y, pressure } + let _draftCtx = null; + let _mainCtx = null; + let _color = '#000000'; + let _lineWidth = 4; // max stroke width (pressure = 1.0) + let _minWidth = 1; // min stroke width (pressure = 0.0) + let _tension = 0.7; // spline tightness; 1.0 = standard CR, lower = looser + let _cornerAngle = Math.PI * 0.4; // ~72Β° β€” turns sharper than this become hard corners + let _usePressure = true; // false β†’ uniform _lineWidth stroke, skip outline path + let _onCommit = null; + + // rAF draft state + let _draftDirty = false; + let _draftRafId = null; + + // ── Helper ──────────────────────────────────────────────────────────── + const clamp = (v, lo, hi) => (v < lo ? lo : v > hi ? hi : v); + + // ───────────────────────────────────────────────────────────────────── + // Stage 1: Ramer-Douglas-Peucker Simplification + // ───────────────────────────────────────────────────────────────────── + // Recursively culls collinear points while preserving true inflection + // points. The { x, y, pressure } payload is preserved on survivors so + // pressure data stays associated with the correct geometry. + // + function rdpSimplify(points, tolerance) { + if (points.length <= 2) return points.slice(); + + const first = points[0], last = points[points.length - 1]; + const dx = last.x - first.x, dy = last.y - first.y; + const den = Math.hypot(dx, dy); + + // Degenerate: all points coincide β€” collapse to endpoints + if (den < 1e-6) return [first, last]; + + let maxDist = 0, maxIdx = 0; + for (let i = 1; i < points.length - 1; i++) { + const p = points[i]; + const d = Math.abs(dy * p.x - dx * p.y + last.x * first.y - last.y * first.x) / den; + if (d > maxDist) { maxDist = d; maxIdx = i; } + } + + if (maxDist > tolerance) { + const left = rdpSimplify(points.slice(0, maxIdx + 1), tolerance); + const right = rdpSimplify(points.slice(maxIdx), tolerance); + left.pop(); // drop duplicate junction point + return left.concat(right); + } + return [first, last]; + } + + // ───────────────────────────────────────────────────────────────────── + // Stage 2a: Corner Detection + // ───────────────────────────────────────────────────────────────────── + // Returns a Set of point indices that should receive zero tangent (C0 + // continuity only). The endpoints are always included. An interior point + // is added when the angle between the incoming and outgoing chord vectors + // exceeds `threshold` radians. + // + // Typical threshold: Ο€ Γ— 0.4 β‰ˆ 72Β°. Krita's default is ~60Β°. + // + function detectCorners(points, threshold) { + const corners = new Set([0, points.length - 1]); + for (let i = 1; i < points.length - 1; i++) { + const ax = points[i].x - points[i-1].x, ay = points[i].y - points[i-1].y; + const bx = points[i+1].x - points[i].x, by = points[i+1].y - points[i].y; + const la = Math.hypot(ax, ay), lb = Math.hypot(bx, by); + if (la < 1e-6 || lb < 1e-6) continue; + const cos = clamp((ax*bx + ay*by) / (la * lb), -1, 1); + const angle = Math.acos(cos); // 0 = straight, Ο€ = hairpin U-turn + if (angle > threshold) corners.add(i); + } + return corners; + } + + // ───────────────────────────────────────────────────────────────────── + // Stage 2b: Centripetal Catmull-Rom β†’ Cubic BΓ©zier + // ───────────────────────────────────────────────────────────────────── + // + // WHY centripetal instead of uniform: + // Uniform CR assigns equal parameter intervals to all consecutive point + // pairs regardless of distance. When the user slows down, points bunch + // up; when they speed up, points spread out. In the bunched regions the + // control points overshoot badly, producing cusps or loops that are + // invisible in the raw lineTo draft but appear on commit. + // + // Centripetal CR (ALPHA = 0.5) weights each knot interval by √(chord + // length), which scales the tangent magnitude in proportion to the local + // density β€” exactly cancelling the overshoot. It is provably loop-free + // and cusp-free for any set of distinct input points. + // + // Tangent formula at Pα΅’ (centripetal parameterization): + // + // dβ‚‹ = |Pα΅’ βˆ’ Pᡒ₋₁|^Ξ± (knot interval before i) + // dβ‚Š = |Pα΅’β‚Šβ‚ βˆ’ Pα΅’|^Ξ± (knot interval after i) + // + // mα΅’ = [(Pα΅’βˆ’Pᡒ₋₁)/dβ‚‹ βˆ’ (Pα΅’β‚Šβ‚βˆ’Pᡒ₋₁)/(dβ‚‹+dβ‚Š) + (Pα΅’β‚Šβ‚βˆ’Pα΅’)/dβ‚Š] Β· dβ‚Š + // + // With Ξ± = 0 (uniform), this reduces exactly to the standard + // mα΅’ = (Pα΅’β‚Šβ‚ βˆ’ Pᡒ₋₁) / 2 + // confirming backward-compatibility. + // + // Endpoints use phantom-mirror neighbours so the same formula applies + // everywhere β€” no special-casing needed for i=0 or i=nβˆ’1. + // + // BΓ©zier control points for segment [Pα΅’, Pα΅’β‚Šβ‚]: + // CP1 = Pα΅’ + (tension/3) Β· mα΅’ + // CP2 = Pα΅’β‚Šβ‚ βˆ’ (tension/3) Β· mα΅’β‚Šβ‚ + // + // Hard corners (from detectCorners) receive mα΅’ = 0, giving a clean cusp + // (C0 join) rather than a smoothed approximation of the user's intent. + // + function catmullRomToBezier(points, tension, corners) { + tension = (tension != null) ? tension : _tension; + const n = points.length; + if (n < 2) return []; + + // Two-point degenerate: straight segment with collinear control points + if (n === 2) { + const p0 = points[0], p3 = points[1]; + const mx = (p3.x - p0.x) / 3, my = (p3.y - p0.y) / 3; + return [{ p0, + p1: { x: p0.x + mx, y: p0.y + my }, + p2: { x: p3.x - mx, y: p3.y - my }, + p3 }]; + } + + const EPS = 1e-5; + + // Precompute knot intervals for real inter-point spans + const kd = new Float64Array(n - 1); + for (let i = 0; i < n - 1; i++) { + kd[i] = Math.pow( + Math.hypot(points[i+1].x - points[i].x, + points[i+1].y - points[i].y), + ALPHA) || EPS; + } + + // Compute tangent vectors at every point + const tx = new Float64Array(n); + const ty = new Float64Array(n); + + for (let i = 0; i < n; i++) { + // Hard corners keep zero tangent β†’ clean C0 cusp + if (corners && corners.has(i)) continue; + + // Phantom-mirror neighbours for endpoint extrapolation: + // P_phantom_prev = 2Β·Pβ‚€ βˆ’ P₁ (mirrors P₁ through Pβ‚€) + // P_phantom_next = 2Β·Pₙ₋₁ βˆ’ Pβ‚™β‚‹β‚‚ + // This ensures the derivative formula is identical for all i. + const px = i > 0 ? points[i-1].x : 2 * points[0].x - points[1].x; + const py = i > 0 ? points[i-1].y : 2 * points[0].y - points[1].y; + const nx_ = i < n-1 ? points[i+1].x : 2 * points[n-1].x - points[n-2].x; + const ny_ = i < n-1 ? points[i+1].y : 2 * points[n-1].y - points[n-2].y; + + const dPx = points[i].x - px, dPy = points[i].y - py; // vector from prev to i + const dNx = nx_ - points[i].x, dNy = ny_ - points[i].y; // vector from i to next + const dFx = nx_ - px, dFy = ny_ - py; // full span prevβ†’next + + const dPrev = Math.pow(Math.hypot(dPx, dPy), ALPHA) || EPS; + const dCur = (i < n-1 ? kd[i] + : Math.pow(Math.hypot(dNx, dNy), ALPHA)) || EPS; + const dSum = dPrev + dCur; + + // Centripetal tangent formula, scaled by dCur for BΓ©zier CP distance + tx[i] = (dPx / dPrev - dFx / dSum + dNx / dCur) * dCur; + ty[i] = (dPy / dPrev - dFy / dSum + dNy / dCur) * dCur; + } + + // Emit cubic BΓ©zier segments + const t3 = tension / 3; + const segs = []; + for (let i = 0; i < n - 1; i++) { + segs.push({ + p0: points[i], + p1: { x: points[i].x + tx[i] * t3, + y: points[i].y + ty[i] * t3 }, + p2: { x: points[i+1].x - tx[i+1] * t3, + y: points[i+1].y - ty[i+1] * t3 }, + p3: points[i+1] + }); + } + return segs; + } + + // ───────────────────────────────────────────────────────────────────── + // Rendering β€” Uniform width (fast path) + // ───────────────────────────────────────────────────────────────────── + // Batches every BΓ©zier segment into one Path2D and issues a single + // ctx.stroke() call. v1 called beginPath/stroke per segment, flushing + // the GPU command buffer on every iteration. + // + function _renderUniform(ctx, segs, color, lineWidth) { + if (!segs.length) return; + const path = new Path2D(); + path.moveTo(segs[0].p0.x, segs[0].p0.y); + for (const s of segs) { + path.bezierCurveTo(s.p1.x, s.p1.y, s.p2.x, s.p2.y, s.p3.x, s.p3.y); + } + ctx.save(); + ctx.strokeStyle = color; + ctx.lineWidth = lineWidth; + ctx.lineCap = 'round'; + ctx.lineJoin = 'round'; + ctx.stroke(path); + ctx.restore(); + } + + // ───────────────────────────────────────────────────────────────────── + // Rendering β€” Variable width (pressure path) + // ───────────────────────────────────────────────────────────────────── + // Samples each BΓ©zier segment at OUTLINE_SAMPLES evenly-spaced t values. + // At each sample the perpendicular unit normal is computed from the curve + // tangent, then the centerline point is offset by Β±halfWidth to produce + // upper and lower edge vertices. halfWidth is linearly interpolated from + // the pressures of the two knot points that bracket each segment. + // + // The resulting polygon is: + // + // [start cap arc] β†’ upper edge β†’ [end cap arc] β†’ lower edge (reversed) + // β†’ closePath + // + // Arc geometry (canvas y-axis points DOWN): + // The normal vector (nx, ny) = (βˆ’dy, dx)/|tangent| points 90Β° left of + // travel. "upper" = centre + halfWΒ·(nx,ny), "lower" = centre βˆ’ halfWΒ·(nx,ny). + // + // Start cap: arc(centre, r, angle_to_lower, angle_to_upper, anticlockwise=true) + // β†’ sweeps counterclockwise through the angle behind the stroke start. + // End cap : arc(centre, r, angle_to_upper, angle_to_lower, anticlockwise=true) + // β†’ sweeps counterclockwise through the angle past the stroke end. + // + // Both caps use anticlockwise=true (decreasing angle in canvas coords). + // Verified correct for horizontal, vertical, and diagonal test strokes. + // + function _renderOutline(ctx, segs, simplified, color, minW, maxW) { + // Collect { x, y, nx, ny, halfW } for every outline sample + const pts = []; + + for (let si = 0; si < segs.length; si++) { + const seg = segs[si]; + const pressA = simplified[si] ?.pressure ?? 0.5; + const pressB = simplified[si+1] ?.pressure ?? 0.5; + const jStart = si === 0 ? 0 : 1; // skip duplicate junction on subsequent segs + + for (let j = jStart; j <= OUTLINE_SAMPLES; j++) { + const t = j / OUTLINE_SAMPLES; + const mt = 1 - t; + + // Cubic BΓ©zier position + const bx = mt*mt*mt*seg.p0.x + 3*mt*mt*t*seg.p1.x + + 3*mt*t*t*seg.p2.x + t*t*t*seg.p3.x; + const by = mt*mt*mt*seg.p0.y + 3*mt*mt*t*seg.p1.y + + 3*mt*t*t*seg.p2.y + t*t*t*seg.p3.y; + + // First derivative β€” tangent direction + const dx = 3 * ( mt*mt*(seg.p1.x - seg.p0.x) + + 2*mt*t*(seg.p2.x - seg.p1.x) + + t*t*(seg.p3.x - seg.p2.x) ); + const dy = 3 * ( mt*mt*(seg.p1.y - seg.p0.y) + + 2*mt*t*(seg.p2.y - seg.p1.y) + + t*t*(seg.p3.y - seg.p2.y) ); + const tlen = Math.hypot(dx, dy); + if (tlen < 1e-6) continue; // skip degenerate tangent (zero-length seg) + + // Unit normal (90Β° left of travel direction) + const nx = -dy / tlen; + const ny = dx / tlen; + + // Pressure-interpolated half-width; clamp to β‰₯ 0.5 px for arc stability + const press = pressA + (pressB - pressA) * t; + const halfW = Math.max(0.5, (minW + (maxW - minW) * press) * 0.5); + + pts.push({ x: bx, y: by, nx, ny, halfW }); + } + } + + if (pts.length < 2) return; + + const fp = pts[0]; + const lp = pts[pts.length - 1]; + + ctx.save(); + ctx.fillStyle = color; + ctx.beginPath(); + + // ── Start cap ──────────────────────────────────────────────────── + // moveTo lower[0], then arc anticlockwise through the angle "behind" + // the stroke start to upper[0]. + ctx.moveTo(fp.x - fp.nx * fp.halfW, + fp.y - fp.ny * fp.halfW); + ctx.arc(fp.x, fp.y, fp.halfW, + Math.atan2(-fp.ny, -fp.nx), // angle to lower[0] + Math.atan2( fp.ny, fp.nx), // angle to upper[0] + true); // anticlockwise β†’ wraps behind start + + // ── Upper edge (left-to-right along stroke) ─────────────────────── + for (let i = 1; i < pts.length; i++) { + ctx.lineTo(pts[i].x + pts[i].nx * pts[i].halfW, + pts[i].y + pts[i].ny * pts[i].halfW); + } + + // ── End cap ────────────────────────────────────────────────────── + // Arc anticlockwise from upper[-1] through the angle past the stroke + // end to lower[-1]. + ctx.arc(lp.x, lp.y, lp.halfW, + Math.atan2( lp.ny, lp.nx), // angle to upper[-1] + Math.atan2(-lp.ny, -lp.nx), // angle to lower[-1] + true); // anticlockwise β†’ wraps past end + + // ── Lower edge (right-to-left back to lower[0]) ─────────────────── + for (let i = pts.length - 2; i >= 0; i--) { + ctx.lineTo(pts[i].x - pts[i].nx * pts[i].halfW, + pts[i].y - pts[i].ny * pts[i].halfW); + } + + ctx.closePath(); + ctx.fill(); + ctx.restore(); + } + + // ───────────────────────────────────────────────────────────────────── + // Draft Render Pipeline + // ───────────────────────────────────────────────────────────────────── + // Raw lineTo preview on the overlay canvas. Scheduled via rAF so that N + // pointermove events arriving in the same display frame collapse into a + // single clearRect + stroke, not N redundant ones. + // + // The preview uses a fixed average width rather than attempting variable- + // width rendering on every frame β€” the final outline is committed on + // pointerup and is always accurate. + // + function _renderDraft() { + _draftDirty = false; + _draftRafId = null; + if (!_draftCtx || !_isDrawing) return; + + const ctx = _draftCtx, cvs = ctx.canvas; + ctx.clearRect(0, 0, cvs.width, cvs.height); + if (_rawPoints.length < 2) return; + + ctx.save(); + ctx.strokeStyle = _color; + ctx.lineWidth = _lineWidth; + ctx.lineCap = 'round'; + ctx.lineJoin = 'round'; + ctx.globalAlpha = 0.6; // slightly ghosted β€” signals "preview, not committed" + ctx.beginPath(); + ctx.moveTo(_rawPoints[0].x, _rawPoints[0].y); + for (let i = 1; i < _rawPoints.length; i++) { + ctx.lineTo(_rawPoints[i].x, _rawPoints[i].y); + } + ctx.stroke(); + ctx.restore(); + } + + function _scheduleDraft() { + if (_draftDirty) return; // already queued for this frame + _draftDirty = true; + _draftRafId = requestAnimationFrame(_renderDraft); + } + + function _cancelDraftRaf() { + if (_draftRafId !== null) { + cancelAnimationFrame(_draftRafId); + _draftRafId = null; + _draftDirty = false; + } + } + + function _clearDraft() { + if (_draftCtx) { + _draftCtx.clearRect(0, 0, _draftCtx.canvas.width, _draftCtx.canvas.height); + } + } + + // ───────────────────────────────────────────────────────────────────── + // Final Render Pipeline + // ───────────────────────────────────────────────────────────────────── + // Called on pointerup. Runs: RDP β†’ corner detection β†’ centripetal CR + // β†’ rendering β†’ draft clear. Returns { simplified, bezierSegs } or null + // if the stroke is too short to fit. + // + function _finalize() { + const simplified = rdpSimplify(_rawPoints, RDP_TOLERANCE); + if (simplified.length < 2) return null; + + const corners = detectCorners(simplified, _cornerAngle); + const bezierSegs = catmullRomToBezier(simplified, _tension, corners); + if (bezierSegs.length === 0) return null; + + if (_mainCtx) { + const doPressure = _usePressure && (_lineWidth !== _minWidth); + if (doPressure) { + _renderOutline(_mainCtx, bezierSegs, simplified, _color, _minWidth, _lineWidth); + } else { + _renderUniform(_mainCtx, bezierSegs, _color, _lineWidth); + } + } + + _clearDraft(); + return { simplified, bezierSegs }; + } + + // ── Public API ──────────────────────────────────────────────────────── + + /** + * @param {object} config + * @param {CanvasRenderingContext2D} config.draftCtx Overlay canvas (cleared each frame) + * @param {CanvasRenderingContext2D} config.mainCtx Persistent canvas (receives final stroke) + * @param {function} config.onCommit Called with { rawPoints, simplifiedPoints, bezierSegs } + * @param {string} config.color CSS color string + * @param {number} config.lineWidth Max stroke width in px (pressure=1.0) + * @param {number} config.minWidth Min stroke width in px (pressure=0.0) β€” enables outline path + * @param {number} config.tension Spline tightness, 0.0–1.0 (default 0.7) + * @param {number} config.cornerAngle Radians; turns sharper than this β†’ hard corner (default ~72Β°) + * @param {boolean} config.usePressure false β†’ always use uniform lineWidth stroke + */ + function init(config) { + _draftCtx = config.draftCtx ?? null; + _mainCtx = config.mainCtx ?? null; + _onCommit = config.onCommit ?? null; + _color = config.color ?? '#000000'; + _lineWidth = config.lineWidth ?? 4; + _minWidth = config.minWidth ?? 1; + _tension = config.tension ?? 0.7; + _cornerAngle = config.cornerAngle ?? Math.PI * 0.4; + _usePressure = config.usePressure ?? true; + } + + /** + * Call on 'pointerdown'. Also call canvas.setPointerCapture(e.pointerId) + * in the same handler to guarantee pointerup fires if the cursor leaves + * the canvas bounds. + */ + function onPointerDown(pos) { + _isDrawing = true; + _rawPoints = [{ x: pos.x, y: pos.y, pressure: pos.pressure ?? 0.5 }]; + _scheduleDraft(); + } + + /** + * Call on 'pointermove'. Pass e.getCoalescedEvents() as coalescedEvents + * when available (high-frequency stylus events faster than the JS loop). + */ + function onPointerMove(pos, coalescedEvents) { + if (!_isDrawing) return; + + // Inline helper: distance-filter before push; respects MAX_RAW_POINTS cap + const tryPush = (cx, cy, cp) => { + if (_rawPoints.length >= MAX_RAW_POINTS) return; + const last = _rawPoints[_rawPoints.length - 1]; + if (Math.hypot(cx - last.x, cy - last.y) > MIN_DISTANCE) { + _rawPoints.push({ x: cx, y: cy, pressure: cp ?? 0.5 }); + } + }; + + if (coalescedEvents && coalescedEvents.length > 0) { + for (const ce of coalescedEvents) tryPush(ce.x, ce.y, ce.pressure); + } else { + tryPush(pos.x, pos.y, pos.pressure); + } + + _scheduleDraft(); + } + + /** + * Call on 'pointerup' and 'pointercancel'. + * Returns { rawPoints, simplifiedPoints, bezierSegs } or null for a tap + * that produced fewer than 2 distinct points. + */ + function onPointerUp() { + if (!_isDrawing) return null; + _isDrawing = false; + _cancelDraftRaf(); + + if (_rawPoints.length < 2) { + _rawPoints = []; + _clearDraft(); + return null; + } + + const finalData = _finalize(); // single RDP call; also clears draft + + const result = { + rawPoints: _rawPoints.slice(), + simplifiedPoints: finalData?.simplified ?? [], + bezierSegs: finalData?.bezierSegs ?? [] + }; + + _rawPoints = []; + + if (_onCommit && finalData) _onCommit(result); + + return result; + } + + /** Abort the in-progress stroke without committing. */ + function cancel() { + if (!_isDrawing) return; + _isDrawing = false; + _cancelDraftRaf(); + _rawPoints = []; + _clearDraft(); + } + + // Convenience setters (allow per-stroke reconfiguration without full init()) + function setColor(c) { _color = c; } + function setLineWidth(w) { _lineWidth = w; } + function setMinWidth(w) { _minWidth = w; } + function setTension(t) { _tension = t; } + function setCornerAngle(a) { _cornerAngle = a; } + function isActive() { return _isDrawing; } + function getRawPoints() { return _rawPoints.slice(); } + + return { + init, onPointerDown, onPointerMove, onPointerUp, + cancel, onPointerCancel: cancel, // alias for pointercancel handler + setColor, setLineWidth, setMinWidth, setTension, setCornerAngle, + isActive, getRawPoints, + // Exposed for testing / external reuse: + rdpSimplify, catmullRomToBezier, detectCorners + }; +})(); diff --git a/src/index.html b/src/index.html index 4fe3f9c..aaecde1 100644 --- a/src/index.html +++ b/src/index.html @@ -1,2457 +1,107 @@ - +ο»Ώ Paint - Professional - - - + - -
-
- - - - - - - - Untitled -
-
- - - -
+ +
+
+ + + + + + + + Untitled +
+
+ + +
- +
+
File
Home
Misc
+
Themes
Debug
- -
|
- -
+ +
|
+ +
- + Paste
Clipboard
@@ -2460,10 +110,10 @@
-
- - -
+
+ + +
Select @@ -2485,10 +135,11 @@
-
Crop
-
Resize
+
Crop
+
Resize
-
+
+ Rotate