From 0482744090d267191fc6bb2ae28966d06d4920ac Mon Sep 17 00:00:00 2001 From: TheRaiwy Date: Fri, 3 Jul 2026 11:39:33 +0300 Subject: [PATCH] =?UTF-8?q?Initial=20commit=20=E2=80=94=20ProxMorph=20with?= =?UTF-8?q?=20TheRaiwy=20Dark=20cyber=20theme?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/FUNDING.yml | 3 + .github/workflows/release.yml | 62 + .gitignore | 55 + CHANGELOG.md | 417 +++ README.md | 175 + THEMES.md | 401 ++ install.sh | 1757 +++++++++ patch_theme_map.sh | 20 + themes/original-proxmox-dark.css | 1 + themes/patches/github-dark-init.js | 59 + themes/patches/pdm-theme-selector.js | 296 ++ themes/patches/proxmorph-sensors.js | 468 +++ themes/patches/unifi-charts.js | 139 + themes/patches/unifi-light-charts.js | 143 + themes/pdm/.gitkeep | 0 themes/pdm/proxmorph-pdm-base.css | 215 ++ themes/pdm/theme-blue-slate.css | 180 + themes/pdm/theme-catppuccin-frappe.css | 180 + themes/pdm/theme-catppuccin-latte.css | 195 + themes/pdm/theme-catppuccin-macchiato.css | 180 + themes/pdm/theme-catppuccin-mocha-teal.css | 185 + themes/pdm/theme-catppuccin-mocha.css | 185 + themes/pdm/theme-dracula-cyan.css | 181 + themes/pdm/theme-dracula-green.css | 181 + themes/pdm/theme-dracula-midnight.css | 182 + themes/pdm/theme-dracula-orange.css | 181 + themes/pdm/theme-dracula-pink.css | 181 + themes/pdm/theme-dracula.css | 189 + themes/pdm/theme-github-dark.css | 183 + themes/pdm/theme-gruvbox-dark.css | 181 + themes/pdm/theme-gruvbox-light.css | 194 + themes/pdm/theme-nord-dark.css | 181 + themes/pdm/theme-nord-light.css | 194 + themes/pdm/theme-solarized-dark.css | 184 + themes/pdm/theme-solarized-light.css | 194 + themes/pdm/theme-theraiwy-dark.css | 182 + themes/pdm/theme-tokyo-night.css | 181 + themes/pdm/theme-unifi-light.css | 194 + themes/pdm/theme-unifi.css | 192 + themes/theme-blue-slate.css | 1965 ++++++++++ themes/theme-catppuccin-frappe.css | 2382 ++++++++++++ themes/theme-catppuccin-latte.css | 2386 ++++++++++++ themes/theme-catppuccin-macchiato.css | 2382 ++++++++++++ themes/theme-catppuccin-mocha-teal.css | 2382 ++++++++++++ themes/theme-catppuccin-mocha.css | 2410 ++++++++++++ themes/theme-dracula-cyan.css | 2378 ++++++++++++ themes/theme-dracula-green.css | 2378 ++++++++++++ themes/theme-dracula-midnight.css | 2378 ++++++++++++ themes/theme-dracula-orange.css | 2378 ++++++++++++ themes/theme-dracula-pink.css | 2378 ++++++++++++ themes/theme-dracula.css | 2378 ++++++++++++ themes/theme-github-dark.css | 2494 ++++++++++++ themes/theme-gruvbox-dark.css | 2340 ++++++++++++ themes/theme-gruvbox-light.css | 2237 +++++++++++ themes/theme-nord-dark.css | 2340 ++++++++++++ themes/theme-nord-light.css | 2237 +++++++++++ themes/theme-solarized-dark.css | 2340 ++++++++++++ themes/theme-solarized-light.css | 2237 +++++++++++ themes/theme-theraiwy-dark.css | 2444 ++++++++++++ themes/theme-tokyo-night.css | 2340 ++++++++++++ themes/theme-unifi-light.css | 3913 +++++++++++++++++++ themes/theme-unifi.css | 3951 ++++++++++++++++++++ 62 files changed, 65519 insertions(+) create mode 100644 .github/FUNDING.yml create mode 100644 .github/workflows/release.yml create mode 100644 .gitignore create mode 100644 CHANGELOG.md create mode 100644 README.md create mode 100644 THEMES.md create mode 100644 install.sh create mode 100644 patch_theme_map.sh create mode 100644 themes/original-proxmox-dark.css create mode 100644 themes/patches/github-dark-init.js create mode 100644 themes/patches/pdm-theme-selector.js create mode 100644 themes/patches/proxmorph-sensors.js create mode 100644 themes/patches/unifi-charts.js create mode 100644 themes/patches/unifi-light-charts.js create mode 100644 themes/pdm/.gitkeep create mode 100644 themes/pdm/proxmorph-pdm-base.css create mode 100644 themes/pdm/theme-blue-slate.css create mode 100644 themes/pdm/theme-catppuccin-frappe.css create mode 100644 themes/pdm/theme-catppuccin-latte.css create mode 100644 themes/pdm/theme-catppuccin-macchiato.css create mode 100644 themes/pdm/theme-catppuccin-mocha-teal.css create mode 100644 themes/pdm/theme-catppuccin-mocha.css create mode 100644 themes/pdm/theme-dracula-cyan.css create mode 100644 themes/pdm/theme-dracula-green.css create mode 100644 themes/pdm/theme-dracula-midnight.css create mode 100644 themes/pdm/theme-dracula-orange.css create mode 100644 themes/pdm/theme-dracula-pink.css create mode 100644 themes/pdm/theme-dracula.css create mode 100644 themes/pdm/theme-github-dark.css create mode 100644 themes/pdm/theme-gruvbox-dark.css create mode 100644 themes/pdm/theme-gruvbox-light.css create mode 100644 themes/pdm/theme-nord-dark.css create mode 100644 themes/pdm/theme-nord-light.css create mode 100644 themes/pdm/theme-solarized-dark.css create mode 100644 themes/pdm/theme-solarized-light.css create mode 100644 themes/pdm/theme-theraiwy-dark.css create mode 100644 themes/pdm/theme-tokyo-night.css create mode 100644 themes/pdm/theme-unifi-light.css create mode 100644 themes/pdm/theme-unifi.css create mode 100644 themes/theme-blue-slate.css create mode 100644 themes/theme-catppuccin-frappe.css create mode 100644 themes/theme-catppuccin-latte.css create mode 100644 themes/theme-catppuccin-macchiato.css create mode 100644 themes/theme-catppuccin-mocha-teal.css create mode 100644 themes/theme-catppuccin-mocha.css create mode 100644 themes/theme-dracula-cyan.css create mode 100644 themes/theme-dracula-green.css create mode 100644 themes/theme-dracula-midnight.css create mode 100644 themes/theme-dracula-orange.css create mode 100644 themes/theme-dracula-pink.css create mode 100644 themes/theme-dracula.css create mode 100644 themes/theme-github-dark.css create mode 100644 themes/theme-gruvbox-dark.css create mode 100644 themes/theme-gruvbox-light.css create mode 100644 themes/theme-nord-dark.css create mode 100644 themes/theme-nord-light.css create mode 100644 themes/theme-solarized-dark.css create mode 100644 themes/theme-solarized-light.css create mode 100644 themes/theme-theraiwy-dark.css create mode 100644 themes/theme-tokyo-night.css create mode 100644 themes/theme-unifi-light.css create mode 100644 themes/theme-unifi.css diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 0000000..b49da2f --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,3 @@ +github: [IT-BAER] +buy_me_a_coffee: itbaer +custom: ["paypal.com/donate/?hosted_button_id=5XXRC7THMTRRS"] diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..77cfb00 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,62 @@ +name: Create Release + +on: + push: + tags: + - 'v*' + +permissions: + contents: write + +jobs: + release: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Extract version from tag + id: version + run: echo "VERSION=${GITHUB_REF#refs/tags/v}" >> $GITHUB_OUTPUT + + - name: Extract changelog for this version + id: changelog + run: | + # Extract the changelog section for this version + VERSION="${{ steps.version.outputs.VERSION }}" + + # Use awk with index() for exact string match (avoids regex bracket issues) + CHANGELOG=$(awk -v ver="$VERSION" ' + /^## \[/ { + if (found) exit + if (index($0, "[" ver "]") > 0) { found=1; next } + } + found { print } + ' CHANGELOG.md) + + # Handle multiline output + { + echo "BODY<> $GITHUB_OUTPUT + + - name: Create release archive + run: | + mkdir -p release + cp install.sh release/ + cp patch_theme_map.sh release/ + cp -r themes release/ + cp README.md release/ + cp CHANGELOG.md release/ + cd release && tar -czvf ../proxmorph-${{ steps.version.outputs.VERSION }}.tar.gz . + cd .. && zip -r proxmorph-${{ steps.version.outputs.VERSION }}.zip release/ + + - name: Create GitHub Release + uses: softprops/action-gh-release@v2 + with: + name: v${{ steps.version.outputs.VERSION }} + body: ${{ steps.changelog.outputs.BODY }} + files: | + proxmorph-${{ steps.version.outputs.VERSION }}.tar.gz + proxmorph-${{ steps.version.outputs.VERSION }}.zip diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..bc5fefb --- /dev/null +++ b/.gitignore @@ -0,0 +1,55 @@ +# ProxMorph .gitignore + +# Context/conversation files +context.md +references/ + +# Archive folder - old theme versions +themes/_archive/ + +# OS generated files +.DS_Store +.DS_Store? +._* +.Spotlight-V100 +.Trashes +Thumbs.db +ehthumbs.db +Desktop.ini + +# Editor/IDE files (VS Code settings are kept) +*.swp +*.swo +*~ +.idea/ +.vscode/ +.github/instructions/ +.github/*.md + +# Compiled SASS (if any) +*.css.map +sass/.sass-cache/ + +# Logs +*.log +npm-debug.log* + +# Node.js (if ever used for build) +node_modules/ +package-lock.json + +# Backup files +*.bak +*.backup +*.orig + +# Temporary files +*.tmp +*.temp +.cache/ + +# Test files +test-*.css +*-test.css +generate-variants.ps1 +docs/component-inventory.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..9bba995 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,417 @@ +# Changelog + +All notable changes to ProxMorph will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [Unreleased] + +## [2.7.3] - 2026-06-12 + +### Fixed +- **All themes** — Task Viewer window no longer loses its scrollbar. The blanket `.x-window .x-panel-body { overflow: visible !important }` rule was overriding ExtJS's own inline `overflow: auto` on scrollable panel bodies (`.x-scroller`). Fixed by scoping the rule to `:not(.x-scroller)`. Issue [#49](https://github.com/IT-BAER/proxmorph/issues/49) +- **All themes** — CT and VM creation dialog tabs are no longer pushed off-screen. `position: relative !important` on `.x-tab` was overriding ExtJS box layout's absolute positioning, causing each tab's offset to double-count (natural flow position + intended left = tabs spreading ~1.5× wider than the container). Removed the offending declaration. Issue [#50](https://github.com/IT-BAER/proxmorph/issues/50) +- **Catppuccin Latte** — Text on colored elements (progress bar fill, active buttons, badges) is now visible. `--ctp-on-accent` was set to `var(--ctp-base)` (`#eff1f5`, near-white), which is invisible on the light Latte background. Changed to `#ffffff` for proper contrast against vivid Latte accent fills (mauve, red, yellow). Issue [#51](https://github.com/IT-BAER/proxmorph/issues/51) + +## [2.7.2] - 2026-04-16 + +### Fixed +- **Sensors** — Added pre-patch Perl syntax check on Nodes.pm before applying the sensor patch. If Nodes.pm is already broken (e.g. from the v2.7.0 APT-hook heredoc bug), the user now gets an actionable error: *"Run 'apt install --reinstall pve-manager' to restore it, then re-run ProxMorph install."* instead of a misleading post-patch rollback message. Issue [#47](https://github.com/IT-BAER/proxmorph/issues/47) +- **Sensors** — Rollback on post-patch syntax failure now restores from `Nodes.pm.original` backup when available, falling back to sed marker removal only if no backup exists. + +## [2.7.1] - 2026-04-05 + +### Fixed +- **APT Hook** — Fixed broken heredoc escaping in `post-update.sh` that caused the Nodes.pm sensor patch to be injected as a single malformed line, breaking Perl syntax and preventing `pveproxy` from starting after a PVE update. Issue [#45](https://github.com/IT-BAER/proxmorph/issues/45) + - Added Perl syntax check (`perl -c`) after patching with automatic rollback if validation fails + +## [2.7.0] - 2026-04-01 + +### Added +- **Sensor Selector** — Interactive per-sensor filtering for hardware monitoring. Issue [#44](https://github.com/IT-BAER/proxmorph/issues/44) + - `enumerate_sensors()` discovers all available sensors (CPU, NVMe, HDD, Fan) via `sensors -j` + - `configure_sensor_filter()` interactive multi-select menu to choose which sensors to display + - Filter stored in `/opt/proxmorph/.sensors-filter` (chip:label format), synced to cluster nodes + - `manage-sensors` menu gains option 4) Configure sensor selection + - `sensors configure` CLI subcommand for non-interactive reconfiguration + - Backwards-compatible: missing/empty filter file shows all sensors +- **proxmorph-sensors.js** (v1.2.0) — Client-side sensor filtering + - Reads `sensorsFilter` from API on each render (no first-load flash) + - CPU cores shown individually when filter selects specific cores without Package sensor + - APT hook updated to persist filter across PVE updates + +## [2.6.0] - 2026-03-16 + +### Added +- **Proxmox Datacenter Manager (PDM) Support** — Full theme support for PDM 1.x: + - New `install.sh` product detection: auto-detects PDM alongside PVE and PBS + - 22 PDM-specific CSS override themes injected as `` tags into `index.hbs`, activated via JavaScript based on `localStorage` selection + - `proxmorph-pdm-base.css` — always-on component styling (rounded corners, shadows, button/panel/grid refinements) + - `pdm-theme-selector.js` — MutationObserver-based patch that injects ProxMorph themes into PDM's native Theme dialog dropdown alongside built-in Desktop/Crisp options + - PDM themes use CSS custom property overrides to remap `--pwt-color-*` tokens from the WASM-loaded base theme + - Inline `" + fi + done + script_tags="${script_tags}\n${JS_PATCH_MARKER_END}" + + # Insert before + sed -i "s||${script_tags}\n|" "$INDEX_TEMPLATE" + print_status "Patched $(basename "$INDEX_TEMPLATE") with JS loader" + } + else + print_warning "$(basename "$INDEX_TEMPLATE") not found - JS patches may not load" + fi +} + +# Remove JavaScript patches +remove_js_patches() { + if [[ -d "$JS_PATCHES_DIR" ]]; then + rm -rf "$JS_PATCHES_DIR" + print_info "Removed JS patches directory" + fi + + if [[ -f "$INDEX_TEMPLATE" ]] && grep -q "$JS_PATCH_MARKER" "$INDEX_TEMPLATE"; then + local escaped_start=$(printf '%s\n' "$JS_PATCH_MARKER" | sed 's/[]\/$*.^[]/\\&/g') + local escaped_end=$(printf '%s\n' "$JS_PATCH_MARKER_END" | sed 's/[]\/$*.^[]/\\&/g') + sed -i "\|${escaped_start}|,\|${escaped_end}|d" "$INDEX_TEMPLATE" + print_info "Removed JS patch from $(basename "$INDEX_TEMPLATE")" + fi +} + +# Install PDM CSS theme overrides into index.hbs +# PDM themes work by injecting a tag that overrides --pwt-color-* tokens +# from the WASM-loaded base theme (Crisp/Desktop/Material) +install_pdm_themes() { + local themes_source="$1" + + print_info "Installing PDM theme overrides..." + + mkdir -p "$PDM_THEMES_DIR" + mkdir -p "$PDM_JS_PATCHES_DIR" + + # Copy base component CSS (always-on styling: rounded corners, shadows, etc.) + local base_css="${themes_source}/proxmorph-pdm-base.css" + if [[ -f "$base_css" ]]; then + cp "$base_css" "${PDM_THEMES_DIR}/" + chmod 644 "${PDM_THEMES_DIR}/proxmorph-pdm-base.css" + print_info "Installed PDM base component styles" + fi + + local theme_count=0 + for css_file in "$themes_source"/theme-*.css; do + if [[ -f "$css_file" ]]; then + cp "$css_file" "${PDM_THEMES_DIR}/" + chmod 644 "${PDM_THEMES_DIR}/$(basename "$css_file")" + local title=$(get_theme_title "$css_file") + print_theme "Installed: ${title}" + theme_count=$((theme_count + 1)) + fi + done + + if [[ $theme_count -eq 0 ]]; then + print_warning "No PDM theme files found" + return 1 + fi + + # Copy theme selector JS patch + # themes_source is either .../themes/pdm or /opt/proxmorph/themes/pdm + # The JS patch lives in .../themes/patches/ (sibling to pdm/) + local patches_dir="$(dirname "$themes_source")/patches" + local selector_js="${patches_dir}/pdm-theme-selector.js" + if [[ -f "$selector_js" ]]; then + cp "$selector_js" "${PDM_JS_PATCHES_DIR}/" + chmod 644 "${PDM_JS_PATCHES_DIR}/pdm-theme-selector.js" + print_info "Installed PDM theme selector patch" + fi + + # Inject CSS tags + JS into index.hbs + if [[ -f "$INDEX_TEMPLATE" ]]; then + # Remove old block if present + if grep -q "$PDM_CSS_MARKER" "$INDEX_TEMPLATE"; then + local esc_start=$(printf '%s\n' "$PDM_CSS_MARKER" | sed 's/[]\/$*.^[]/\\&/g') + local esc_end=$(printf '%s\n' "$PDM_CSS_MARKER_END" | sed 's/[]\/$*.^[]/\\&/g') + sed -i "\|${esc_start}|,\|${esc_end}|d" "$INDEX_TEMPLATE" + print_info "Refreshing PDM theme links in $(basename "$INDEX_TEMPLATE")" + fi + + # Build injection block as a temp file (avoids sed multiline issues) + local tmpblock=$(mktemp) + echo "$PDM_CSS_MARKER" > "$tmpblock" + + # Base CSS — always enabled (component styles) + echo "" >> "$tmpblock" + + # Theme CSS links — disabled by default, activated by JS + for css_file in "${PDM_THEMES_DIR}"/theme-*.css; do + if [[ -f "$css_file" ]]; then + local css_name=$(basename "$css_file") + echo "" >> "$tmpblock" + fi + done + + # Inline activation script (runs before WASM loads) + cat >> "$tmpblock" << 'JSBLOCK' + +JSBLOCK + + # Theme selector patch (injects themes into native PDM Theme dialog) + echo "" >> "$tmpblock" + + echo "$PDM_CSS_MARKER_END" >> "$tmpblock" + + # Insert block before first using awk + local tmpout=$(mktemp) + awk -v blockfile="$tmpblock" 'BEGIN{done=0; while((getline line < blockfile)>0) block=block (block?"\n":"") line} !done && /<\/head>/{print block; done=1} {print}' "$INDEX_TEMPLATE" > "$tmpout" + mv "$tmpout" "$INDEX_TEMPLATE" + chmod 644 "$INDEX_TEMPLATE" + rm -f "$tmpblock" + + print_status "Injected ${theme_count} theme(s) + base styles + selector patch into $(basename "$INDEX_TEMPLATE")" + else + print_warning "$(basename "$INDEX_TEMPLATE") not found — PDM themes may not load" + fi + + print_status "PDM themes installed — ${theme_count} theme(s)" +} + +# Remove PDM CSS theme overrides +remove_pdm_themes() { + if [[ -d "$PDM_THEMES_DIR" ]]; then + rm -rf "$PDM_THEMES_DIR" + print_info "Removed PDM theme overrides directory" + fi + if [[ -d "$PDM_JS_PATCHES_DIR" ]]; then + rm -rf "$PDM_JS_PATCHES_DIR" + print_info "Removed PDM JS patches directory" + fi + if [[ -f "$INDEX_TEMPLATE" ]] && grep -q "$PDM_CSS_MARKER" "$INDEX_TEMPLATE"; then + local esc_start=$(printf '%s\n' "$PDM_CSS_MARKER" | sed 's/[]\/$*.^[]/\\&/g') + local esc_end=$(printf '%s\n' "$PDM_CSS_MARKER_END" | sed 's/[]\/$*.^[]/\\&/g') + sed -i "\|${esc_start}|,\|${esc_end}|d" "$INDEX_TEMPLATE" + print_info "Removed PDM theme links from $(basename "$INDEX_TEMPLATE")" + fi +} + +# APT hook configuration for persistence across updates +APT_HOOK_FILE="/etc/apt/apt.conf.d/99proxmorph" +POST_INVOKE_SCRIPT="${INSTALL_DIR}/post-update.sh" + +# Install apt hook for automatic re-patching after updates +install_apt_hook() { + print_info "Installing apt hook for automatic re-patching..." + + mkdir -p "${INSTALL_DIR}" + cat > "${POST_INVOKE_SCRIPT}" << SCRIPT +#!/bin/bash +# ProxMorph post-update hook - automatically re-patches after updates + +PRODUCT="${PRODUCT}" +INSTALL_DIR="${INSTALL_DIR}" +PROXMOXLIB_JS="${PROXMOXLIB_JS}" +WIDGET_TOOLKIT_DIR="${WIDGET_TOOLKIT_DIR}" +INDEX_TEMPLATE="${INDEX_TEMPLATE}" +JS_PATCHES_DIR="${JS_PATCHES_DIR}" +PROXY_SERVICE="${PROXY_SERVICE}" +LOG_FILE="/var/log/proxmorph.log" +JS_PATCH_MARKER="${JS_PATCH_MARKER}" +JS_PATCH_MARKER_END="${JS_PATCH_MARKER_END}" +PDM_CSS_MARKER="${PDM_CSS_MARKER}" +PDM_CSS_MARKER_END="${PDM_CSS_MARKER_END}" +PDM_THEMES_DIR="${PDM_THEMES_DIR}" + +# Set themes source based on product +if [ "\$PRODUCT" = "PDM" ]; then + THEMES_SOURCE="\${INSTALL_DIR}/themes/pdm" +else + THEMES_SOURCE="\${INSTALL_DIR}/themes" +fi + +log() { + echo "[\$(date '+%Y-%m-%d %H:%M:%S')] \$1" >> "\$LOG_FILE" +} + +# Only proceed if themes are installed +if [ ! -d "\$THEMES_SOURCE" ]; then + exit 0 +fi + +needs_repatch=false + +# PDM repatch check: see if CSS injection is still in index.hbs +if [ "\$PRODUCT" = "PDM" ]; then + if ! grep -q "\$PDM_CSS_MARKER" "\$INDEX_TEMPLATE" 2>/dev/null; then + needs_repatch=true + fi +else + # PVE/PBS: check if proxmoxlib.js needs patching + for css_file in "\${THEMES_SOURCE}"/theme-*.css; do + if [ -f "\$css_file" ]; then + theme_key=\$(basename "\$css_file" .css | sed 's/^theme-//') + if ! grep -q "\"\${theme_key}\":" "\$PROXMOXLIB_JS" 2>/dev/null; then + needs_repatch=true + fi + break + fi + done +fi + +# Check if template needs JS patch (PVE/PBS only) +if [ "\$PRODUCT" != "PDM" ] && [ -d "\${THEMES_SOURCE}/patches" ] && ! grep -q "\$JS_PATCH_MARKER" "\$INDEX_TEMPLATE" 2>/dev/null; then + needs_repatch=true +fi + +if [ "\$needs_repatch" = "true" ]; then + log "Detected \$PRODUCT update, re-applying ProxMorph patches..." + + if [ "\$PRODUCT" = "PDM" ]; then + # PDM: Re-inject CSS overrides into index.hbs + mkdir -p "\$PDM_THEMES_DIR" + mkdir -p "\$PDM_JS_PATCHES_DIR" + + # Copy base component CSS + base_css="\${THEMES_SOURCE}/proxmorph-pdm-base.css" + if [ -f "\$base_css" ]; then + cp "\$base_css" "\${PDM_THEMES_DIR}/" + chmod 644 "\${PDM_THEMES_DIR}/proxmorph-pdm-base.css" + fi + + for css_file in "\${THEMES_SOURCE}"/theme-*.css; do + if [ -f "\$css_file" ]; then + cp "\$css_file" "\${PDM_THEMES_DIR}/" + chmod 644 "\${PDM_THEMES_DIR}/\$(basename "\$css_file")" + log "Installed PDM theme: \$(basename "\$css_file")" + fi + done + + # Copy theme selector JS patch + selector_js="\${INSTALL_DIR}/themes/patches/pdm-theme-selector.js" + if [ -f "\$selector_js" ]; then + cp "\$selector_js" "\${PDM_JS_PATCHES_DIR}/" + chmod 644 "\${PDM_JS_PATCHES_DIR}/pdm-theme-selector.js" + fi + + # Re-inject CSS link tags + JS + if [ -f "\$INDEX_TEMPLATE" ] && ! grep -q "\$PDM_CSS_MARKER" "\$INDEX_TEMPLATE"; then + tmpblock=\$(mktemp) + echo "\$PDM_CSS_MARKER" > "\$tmpblock" + + # Base CSS (always enabled when theme active) + echo "" >> "\$tmpblock" + + for css_file in "\${PDM_THEMES_DIR}"/theme-*.css; do + if [ -f "\$css_file" ]; then + css_name=\$(basename "\$css_file") + echo "" >> "\$tmpblock" + fi + done + cat >> "\$tmpblock" << 'JSBLK' + +JSBLK + echo "" >> "\$tmpblock" + echo "\$PDM_CSS_MARKER_END" >> "\$tmpblock" + tmpout=\$(mktemp) + awk -v blockfile="\$tmpblock" 'BEGIN{done=0; while((getline line < blockfile)>0) block=block (block?"\n":"") line} !done && /<\/head>/{print block; done=1} {print}' "\$INDEX_TEMPLATE" > "\$tmpout" + mv "\$tmpout" "\$INDEX_TEMPLATE" + chmod 644 "\$INDEX_TEMPLATE" + rm -f "\$tmpblock" + log "Re-injected PDM theme CSS into \$(basename "\$INDEX_TEMPLATE")" + fi + else + # PVE/PBS: Re-register all themes in proxmoxlib.js + for css_file in "\${THEMES_SOURCE}"/theme-*.css; do + if [ -f "\$css_file" ]; then + theme_key=\$(basename "\$css_file" .css | sed 's/^theme-//') + theme_title=\$(head -1 "\$css_file" | sed -n 's|^/\*!\(.*\)\*/.*|\1|p') + if [ -z "\$theme_title" ]; then + theme_title=\$(echo "\$theme_key" | sed 's/-/ /g' | sed 's/\b\(.\)/\u\1/g') + fi + + if ! grep -q "\"\${theme_key}\":" "\$PROXMOXLIB_JS"; then + sed -i "s/theme_map: {/theme_map: {\n\t\"\${theme_key}\": \"\${theme_title}\",/" "\$PROXMOXLIB_JS" + log "Registered theme: \${theme_title}" + fi + fi + done + + # Re-apply JavaScript patches + if [ -d "\${THEMES_SOURCE}/patches" ]; then + mkdir -p "\$JS_PATCHES_DIR" + for js_file in "\${THEMES_SOURCE}/patches"/*.js; do + if [ -f "\$js_file" ]; then + cp "\$js_file" "\$JS_PATCHES_DIR/" + chmod 644 "\$JS_PATCHES_DIR/\$(basename "\$js_file")" + log "Installed JS patch: \$(basename "\$js_file")" + fi + done + + # Patch template if needed + if [ -f "\$INDEX_TEMPLATE" ] && ! grep -q "\$JS_PATCH_MARKER" "\$INDEX_TEMPLATE"; then + script_tags="\$JS_PATCH_MARKER" + js_web_path="" + if [ "\$PRODUCT" = "PVE" ]; then + js_web_path="/pve2/js/proxmorph" + else + js_web_path="/js/proxmorph" + fi + + for js_file in "\$JS_PATCHES_DIR"/*.js; do + if [ -f "\$js_file" ]; then + js_name=\$(basename "\$js_file") + script_tags="\${script_tags}\n" + fi + done + script_tags="\${script_tags}\n\$JS_PATCH_MARKER_END" + + sed -i "s||\${script_tags}\n|" "\$INDEX_TEMPLATE" + log "Patched \$(basename "\$INDEX_TEMPLATE") with JS loader" + fi + fi + + # Re-apply Nodes.pm sensor patch if enabled + SENSORS_CONFIG="\${INSTALL_DIR}/.sensors-enabled" + SENSORS_FILTER="\${INSTALL_DIR}/.sensors-filter" + NODES_PM="/usr/share/perl5/PVE/API2/Nodes.pm" + SENSORS_PATCH_MARKER="# ProxMorph Sensors" + if [ -f "\$SENSORS_CONFIG" ] && [ -f "\$NODES_PM" ]; then + sensor_needs_patch=false + if ! grep -q "\$SENSORS_PATCH_MARKER" "\$NODES_PM" 2>/dev/null; then + sensor_needs_patch=true + elif ! grep -q "safe_ups_name" "\$NODES_PM" 2>/dev/null || ! grep -q "/usr/bin/timeout -k 1 3 /usr/bin/upsc" "\$NODES_PM" 2>/dev/null; then + sed -i "/\${SENSORS_PATCH_MARKER}/,/\${SENSORS_PATCH_MARKER} END/d" "\$NODES_PM" + sensor_needs_patch=true + log "Detected legacy Nodes.pm sensor patch, refreshing" + fi + + if [ "\$sensor_needs_patch" = "true" ]; then + sed -i "/^[[:space:]]*my \\\$dinfo = df/i\\\\ + \${SENSORS_PATCH_MARKER}\\\\ + local \\\$ENV{PATH} = '/usr/bin:/bin';\\\\ + \\\$res->{sensorsOutput} = \\\`sensors -j 2>/dev/null\\\`;\\\\ + if (-e '\${SENSORS_FILTER}') {\\\\ + if (open(my \\\$fh, '<', '\${SENSORS_FILTER}')) {\\\\ + local \\\$/;\\\\ + \\\$res->{sensorsFilter} = <\\\$fh>;\\\\ + close(\\\$fh);\\\\ + }\\\\ + }\\\\ + if (-x '/usr/bin/upsc') {\\\\ + my \@ups_list = \\\`if [ -x /usr/bin/timeout ]; then /usr/bin/timeout -k 1 3 /usr/bin/upsc -l; else /usr/bin/upsc -l; fi 2>/dev/null\\\`;\\\\ + if (\@ups_list) {\\\\ + chomp(my \\\$ups_name = \\\$ups_list[0]);\\\\ + if (\\\$ups_name && \\\$ups_name =~ /^([A-Za-z0-9_.:-]+)\\\$/) {\\\\ + my \\\$safe_ups_name = \\\$1;\\\\ + \\\$res->{upsData} = \\\`if [ -x /usr/bin/timeout ]; then /usr/bin/timeout -k 1 3 /usr/bin/upsc \\\$safe_ups_name; else /usr/bin/upsc \\\$safe_ups_name; fi 2>/dev/null\\\`;\\\\ + }\\\\ + }\\\\ + }\\\\ + \${SENSORS_PATCH_MARKER} END" "\$NODES_PM" + if perl -c "\$NODES_PM" 2>/dev/null; then + log "Re-patched Nodes.pm for sensor data" + else + log "ERROR: Nodes.pm syntax broken after sensor patch, rolling back" + sed -i "/\${SENSORS_PATCH_MARKER}/,/\${SENSORS_PATCH_MARKER} END/d" "\$NODES_PM" + fi + fi + fi + fi # end PVE/PBS else branch + + # Restart proxy service to apply changes + systemctl restart "\$PROXY_SERVICE" 2>/dev/null || true + log "ProxMorph patches re-applied successfully" +fi +SCRIPT + chmod +x "${POST_INVOKE_SCRIPT}" + + # Create apt hook + cat > "${APT_HOOK_FILE}" << HOOK +// ProxMorph: Automatically re-patch after updates +DPkg::Post-Invoke { "if [ -x ${POST_INVOKE_SCRIPT} ]; then ${POST_INVOKE_SCRIPT}; fi"; }; +HOOK + + print_status "Apt hook installed - themes will persist across ${PRODUCT} updates" +} + +# Remove apt hook +remove_apt_hook() { + if [[ -f "${APT_HOOK_FILE}" ]]; then + rm -f "${APT_HOOK_FILE}" + print_info "Removed apt hook" + fi + if [[ -f "${POST_INVOKE_SCRIPT}" ]]; then + rm -f "${POST_INVOKE_SCRIPT}" + fi +} + +# Check if apt hook is installed +check_apt_hook() { + if [[ -f "${APT_HOOK_FILE}" ]] && [[ -f "${POST_INVOKE_SCRIPT}" ]]; then + return 0 + fi + return 1 +} + +# ─── Hardware Sensor Support (PVE only) ───────────────────────── + +# Check if lm-sensors is available and what sensors exist +detect_sensors() { + if [[ "$PRODUCT" != "PVE" ]]; then + print_warning "Hardware sensor support is only available for Proxmox VE" + return 1 + fi + + if ! command -v sensors &> /dev/null; then + print_warning "lm-sensors is not installed" + print_info "Install with: apt install lm-sensors && sensors-detect" + return 1 + fi + + local sensor_output + sensor_output=$(sensors -j 2>/dev/null) || true + + if [[ -z "$sensor_output" ]]; then + print_warning "No sensor data available. Run 'sensors-detect' first." + return 1 + fi + + # Report detected sensors + local has_cpu=false has_nvme=false has_hdd=false has_fan=false has_ups=false + + echo "$sensor_output" | grep -q '"coretemp-isa-\|"k10temp-pci-' && has_cpu=true + echo "$sensor_output" | grep -q '"nvme-pci-' && has_nvme=true + echo "$sensor_output" | grep -q '"drivetemp-scsi-' && has_hdd=true + echo "$sensor_output" | grep -q 'fan[0-9]*_input' && has_fan=true + command -v upsc &> /dev/null && has_ups=true + + echo "" + print_info "Detected hardware sensors:" + [[ "$has_cpu" == "true" ]] && echo -e " ${GREEN}●${NC} CPU temperature (coretemp/k10temp)" + [[ "$has_nvme" == "true" ]] && echo -e " ${GREEN}●${NC} NVMe drive temperature" + [[ "$has_hdd" == "true" ]] && echo -e " ${GREEN}●${NC} HDD drive temperature (drivetemp)" + [[ "$has_fan" == "true" ]] && echo -e " ${GREEN}●${NC} Fan speed" + [[ "$has_ups" == "true" ]] && echo -e " ${GREEN}●${NC} UPS monitoring (NUT)" + + [[ "$has_cpu" == "false" && "$has_nvme" == "false" && "$has_hdd" == "false" && "$has_fan" == "false" ]] && { + print_warning "No supported sensors found in lm-sensors output" + return 1 + } + echo "" + return 0 +} + +# Enumerate individual sensors from sensors -j output for selection +# Populates SENSOR_LIST array with entries like: +# "CPU|coretemp-isa-0000|Package id 0|42.0°C" +# "Fan|it8689-isa-0a40|fan1|850 RPM" +enumerate_sensors() { + SENSOR_LIST=() + local sensor_output + sensor_output=$(sensors -j 2>/dev/null) || true + if [[ -z "$sensor_output" ]]; then + return 1 + fi + + # Parse JSON with awk to extract chip keys, labels, and values + # CPU chips (coretemp, k10temp) + local cpu_chips + cpu_chips=$(echo "$sensor_output" | grep -oP '"(coretemp-isa-[^"]+|k10temp-pci-[^"]+)"' | tr -d '"' | sort -u) + for chip in $cpu_chips; do + # Get package/Tctl temp + local temp + temp=$(echo "$sensor_output" | python3 -c " +import sys,json +try: + d=json.loads(sys.stdin.read()) + chip=d.get('$chip',{}) + for lbl,v in chip.items(): + if lbl=='Adapter': continue + if not isinstance(v,dict): continue + for k,val in v.items(): + if 'input' in k and val is not None: + print(f'{lbl}|{val}') + break +except: pass +" 2>/dev/null) + if [[ -n "$temp" ]]; then + while IFS='|' read -r label val; do + SENSOR_LIST+=("CPU|${chip}|${label}|${val}°C") + done <<< "$temp" + fi + done + + # NVMe drives + local nvme_chips + nvme_chips=$(echo "$sensor_output" | grep -oP '"(nvme-pci-[^"]+)"' | tr -d '"' | sort -u) + for chip in $nvme_chips; do + local temp + temp=$(echo "$sensor_output" | python3 -c " +import sys,json +try: + d=json.loads(sys.stdin.read()) + chip=d.get('$chip',{}) + for lbl,v in chip.items(): + if lbl=='Adapter': continue + if not isinstance(v,dict): continue + for k,val in v.items(): + if 'input' in k and val is not None: + print(f'{lbl}|{val}') + break +except: pass +" 2>/dev/null) + if [[ -n "$temp" ]]; then + while IFS='|' read -r label val; do + SENSOR_LIST+=("NVMe|${chip}|${label}|${val}°C") + done <<< "$temp" + fi + done + + # HDD/SATA drives + local hdd_chips + hdd_chips=$(echo "$sensor_output" | grep -oP '"(drivetemp-scsi-[^"]+)"' | tr -d '"' | sort -u) + for chip in $hdd_chips; do + local temp + temp=$(echo "$sensor_output" | python3 -c " +import sys,json +try: + d=json.loads(sys.stdin.read()) + chip=d.get('$chip',{}) + for lbl,v in chip.items(): + if lbl=='Adapter': continue + if not isinstance(v,dict): continue + for k,val in v.items(): + if 'input' in k and val is not None: + print(f'{lbl}|{val}') + break +except: pass +" 2>/dev/null) + if [[ -n "$temp" ]]; then + while IFS='|' read -r label val; do + SENSOR_LIST+=("HDD|${chip}|${label}|${val}°C") + done <<< "$temp" + fi + done + + # Fan sensors (any chip) + local fan_data + fan_data=$(echo "$sensor_output" | python3 -c " +import sys,json +try: + d=json.loads(sys.stdin.read()) + def find_fans(obj, chip_key, parent=''): + if not isinstance(obj, dict): return + for k,v in obj.items(): + if k == 'Adapter': continue + if isinstance(v, dict): + for fk,fv in v.items(): + if 'fan' in fk and 'input' in fk and fv is not None: + print(f'{chip_key}|{k}|{int(fv)} RPM') + if not any('fan' in fk and 'input' in fk for fk in v): + find_fans(v, chip_key, k) + for chip_key in d: + find_fans(d[chip_key], chip_key) +except: pass +" 2>/dev/null) + if [[ -n "$fan_data" ]]; then + while IFS='|' read -r chip label val; do + SENSOR_LIST+=("Fan|${chip}|${label}|${val}") + done <<< "$fan_data" + fi + + # UPS + if command -v upsc &> /dev/null; then + local ups_list + ups_list=$(upsc -l 2>/dev/null | head -5) + if [[ -n "$ups_list" ]]; then + while read -r ups_name; do + [[ -z "$ups_name" ]] && continue + SENSOR_LIST+=("UPS|ups|${ups_name}|NUT") + done <<< "$ups_list" + fi + fi + + return 0 +} + +# Interactive sensor selection — lets user pick which sensors to display +configure_sensor_filter() { + if ! enumerate_sensors; then + print_warning "Could not enumerate sensors" + return 1 + fi + + if [[ ${#SENSOR_LIST[@]} -eq 0 ]]; then + print_warning "No individual sensors found to configure" + return 1 + fi + + echo "" + echo "=== Sensor Selection ===" + echo "" + print_info "Available sensors:" + echo "" + + local i=1 + for entry in "${SENSOR_LIST[@]}"; do + IFS='|' read -r type chip label value <<< "$entry" + printf " ${CYAN}%2d)${NC} [%-4s] %s: %s (%s)\n" "$i" "$type" "$chip" "$label" "$value" + i=$((i + 1)) + done + + echo "" + echo -e " ${CYAN} a)${NC} All sensors (default)" + echo "" + read -p "Select sensors to display [1-$((i-1)), comma-separated, or 'a' for all]: " selection + + # Handle 'all' or empty + if [[ -z "$selection" || "$selection" == "a" || "$selection" == "all" ]]; then + rm -f "$SENSORS_FILTER" + print_status "All sensors will be displayed" + return 0 + fi + + # Parse comma-separated numbers + local filter_entries=() + IFS=',' read -ra nums <<< "$selection" + for num in "${nums[@]}"; do + num=$(echo "$num" | tr -d ' ') + if [[ "$num" =~ ^[0-9]+$ ]] && [[ "$num" -ge 1 ]] && [[ "$num" -le ${#SENSOR_LIST[@]} ]]; then + local entry="${SENSOR_LIST[$((num - 1))]}" + IFS='|' read -r type chip label value <<< "$entry" + # Store as chip:label for fans/temps, or chip:upsname for UPS + filter_entries+=("${chip}:${label}") + else + print_warning "Ignoring invalid selection: $num" + fi + done + + if [[ ${#filter_entries[@]} -eq 0 ]]; then + print_warning "No valid selections — showing all sensors" + rm -f "$SENSORS_FILTER" + return 0 + fi + + # Write filter file + mkdir -p "$INSTALL_DIR" + printf '%s\n' "${filter_entries[@]}" > "$SENSORS_FILTER" + print_status "Sensor filter saved (${#filter_entries[@]} sensor(s) selected)" + return 0 +} + +# Patch Nodes.pm to expose sensor data via the API +patch_nodes_pm() { + if [[ ! -f "$NODES_PM" ]]; then + print_error "Nodes.pm not found at $NODES_PM" + return 1 + fi + + # Pre-flight: verify Nodes.pm is syntactically valid before we touch it. + # If it is already broken (e.g. from the v2.7.0 APT-hook heredoc bug, #45) + # the post-patch perl -c check would produce a misleading error. + if ! perl -c "$NODES_PM" 2>/dev/null; then + print_error "Nodes.pm already has a syntax error before patching." + print_error "Run 'apt install --reinstall pve-manager' to restore it, then re-run ProxMorph install." + return 1 + fi + + # Refresh legacy sensor patches so old installs get the taint-safe logic. + if grep -q "$SENSORS_PATCH_MARKER" "$NODES_PM" 2>/dev/null; then + if grep -q "local \$ENV{PATH} = '/usr/bin:/bin';" "$NODES_PM" 2>/dev/null && \ + grep -q "safe_ups_name" "$NODES_PM" 2>/dev/null && \ + grep -q "/usr/bin/timeout -k 1 3 /usr/bin/upsc" "$NODES_PM" 2>/dev/null; then + print_info "Nodes.pm already patched for sensors" + return 0 + fi + + print_warning "Legacy sensor patch detected in Nodes.pm, refreshing to current version" + sed -i "/${SENSORS_PATCH_MARKER}/,/${SENSORS_PATCH_MARKER} END/d" "$NODES_PM" + fi + + # Backup Nodes.pm + if [[ ! -f "${BACKUP_DIR}/Nodes.pm.original" ]]; then + mkdir -p "$BACKUP_DIR" + cp "$NODES_PM" "${BACKUP_DIR}/Nodes.pm.original" + print_info "Backed up Nodes.pm" + fi + + # Insert sensor data collection before 'my $dinfo = df('/', 1);' + sed -i "/^\s*my \$dinfo = df/i\\ + ${SENSORS_PATCH_MARKER}\\ + local \$ENV{PATH} = '/usr/bin:/bin';\\ + \$res->{sensorsOutput} = \`sensors -j 2>/dev/null\`;\\ + if (-e '${SENSORS_FILTER}') {\\ + if (open(my \$fh, '<', '${SENSORS_FILTER}')) {\\ + local \$/;\\ + \$res->{sensorsFilter} = <\$fh>;\\ + close(\$fh);\\ + }\\ + }\\ + if (-x '/usr/bin/upsc') {\\ + my \@ups_list = \`if [ -x /usr/bin/timeout ]; then /usr/bin/timeout -k 1 3 /usr/bin/upsc -l; else /usr/bin/upsc -l; fi 2>/dev/null\`;\\ + if (\@ups_list) {\\ + chomp(my \$ups_name = \$ups_list[0]);\\ + if (\$ups_name && \$ups_name =~ /^([A-Za-z0-9_.:-]+)$/) {\\ + my \$safe_ups_name = \$1;\\ + \$res->{upsData} = \`if [ -x /usr/bin/timeout ]; then /usr/bin/timeout -k 1 3 /usr/bin/upsc \$safe_ups_name; else /usr/bin/upsc \$safe_ups_name; fi 2>/dev/null\`;\\ + }\\ + }\\ + }\\ + ${SENSORS_PATCH_MARKER} END" "$NODES_PM" + + if ! perl -c "$NODES_PM" 2>/dev/null; then + print_error "Nodes.pm syntax broken after sensor patch, rolling back" + if [[ -f "${BACKUP_DIR}/Nodes.pm.original" ]]; then + cp "${BACKUP_DIR}/Nodes.pm.original" "$NODES_PM" + print_info "Restored Nodes.pm from backup" + else + sed -i "/${SENSORS_PATCH_MARKER}/,/${SENSORS_PATCH_MARKER} END/d" "$NODES_PM" + fi + return 1 + fi + + print_status "Patched Nodes.pm to expose hardware sensor data" + return 0 +} + +# Remove sensor patches from Nodes.pm +unpatch_nodes_pm() { + if [[ ! -f "$NODES_PM" ]]; then + return 0 + fi + + if ! grep -q "$SENSORS_PATCH_MARKER" "$NODES_PM" 2>/dev/null; then + return 0 + fi + + # Remove lines between our markers (inclusive) + sed -i "/${SENSORS_PATCH_MARKER}/,/${SENSORS_PATCH_MARKER} END/d" "$NODES_PM" + print_status "Removed sensor patches from Nodes.pm" +} + +# Get list of remote cluster node hostnames (excludes local node) +get_remote_nodes() { + if ! command -v pvecm &>/dev/null; then + return 0 + fi + + # pvecm nodes can include a Qdevice status column (e.g. NR, NA,NV,NMW). + # Use the last field as node name, skip local and qdevice rows. + pvecm nodes 2>/dev/null | awk '$1 ~ /^[0-9]+$/ && $3 != "Qdevice" && $NF != "(local)" {print $NF}' +} + +# Deploy sensor API patch to remote cluster nodes via scp +patch_cluster_sensors() { + local remote_nodes + remote_nodes=$(get_remote_nodes) + + if [[ -z "$remote_nodes" ]]; then + return 0 + fi + + # Get local PVE version for comparison + local local_version + local_version=$(dpkg -l pve-manager 2>/dev/null | awk '/^ii/{print $3}') + + echo "" + print_info "Cluster detected. Remote nodes need the API patch for sensors to work." + echo "" + for node in $remote_nodes; do + echo -e " ${CYAN}●${NC} ${node}" + done + echo "" + + read -p "Deploy sensor patch to remote nodes? [Y/n]: " deploy_choice + case "$deploy_choice" in + [Nn]|[Nn][Oo]) + print_info "Skipping remote nodes. Run 'install.sh manage-sensors enable' on each node individually." + return 0 + ;; + esac + + for node in $remote_nodes; do + print_info "Deploying to ${node}..." + + # Verify same PVE version before copying Nodes.pm + local remote_version + remote_version=$(ssh -o ConnectTimeout=5 "root@${node}" "dpkg -l pve-manager 2>/dev/null | awk '/^ii/{print \$3}'" 2>/dev/null) + + if [[ -n "$local_version" && -n "$remote_version" && "$local_version" != "$remote_version" ]]; then + print_warning "Version mismatch on ${node} (local: ${local_version}, remote: ${remote_version}) — skipping" + print_info "Run install.sh on ${node} directly to enable sensors" + continue + fi + + if scp -o ConnectTimeout=5 -q "$NODES_PM" "root@${node}:${NODES_PM}" 2>/dev/null; then + # Sync sensor filter file if it exists + if [[ -f "$SENSORS_FILTER" ]]; then + scp -o ConnectTimeout=5 -q "$SENSORS_FILTER" "root@${node}:${SENSORS_FILTER}" 2>/dev/null || true + fi + if ssh -o ConnectTimeout=5 "root@${node}" "systemctl restart pveproxy" 2>/dev/null; then + print_status "Sensors deployed to ${node}" + else + print_warning "Patched ${node} but failed to restart pveproxy" + fi + else + print_warning "Failed to deploy to ${node} — run install.sh on that node directly" + fi + done +} + +# Remove sensor API patch from remote cluster nodes +unpatch_cluster_sensors() { + local remote_nodes + remote_nodes=$(get_remote_nodes) + + if [[ -z "$remote_nodes" ]]; then + return 0 + fi + + for node in $remote_nodes; do + print_info "Removing sensor patch from ${node}..." + if ssh -o ConnectTimeout=5 "root@${node}" \ + "sed -i '/# ProxMorph Sensors/,/# ProxMorph Sensors END/d' /usr/share/perl5/PVE/API2/Nodes.pm 2>/dev/null && systemctl restart pveproxy" 2>/dev/null; then + print_status "Sensors removed from ${node}" + else + print_warning "Failed to unpatch ${node}" + fi + done +} + +# Install sensor support interactively +install_sensors() { + if [[ "$PRODUCT" != "PVE" ]]; then + return 0 + fi + + if ! detect_sensors; then + return 0 + fi + + read -p "Enable hardware sensor monitoring in the dashboard? [y/N]: " sensor_choice + case "$sensor_choice" in + [Yy]|[Yy][Ee][Ss]) + patch_nodes_pm || return 1 + mkdir -p "$INSTALL_DIR" + echo "enabled" > "$SENSORS_CONFIG" + print_status "Hardware sensor monitoring enabled!" + echo "" + read -p "Would you like to choose which sensors to display? [y/N]: " filter_choice + case "$filter_choice" in + [Yy]|[Yy][Ee][Ss]) + configure_sensor_filter + ;; + *) + print_info "Showing all sensors (can be configured later with: install.sh manage-sensors)" + ;; + esac + patch_cluster_sensors + ;; + *) + print_info "Skipping sensor integration (can be enabled later with: install.sh sensors enable)" + ;; + esac +} + +# Remove sensor support +remove_sensors() { + unpatch_nodes_pm + unpatch_cluster_sensors + if [[ -f "$SENSORS_CONFIG" ]]; then + rm -f "$SENSORS_CONFIG" + print_info "Sensor configuration removed" + fi + if [[ -f "$SENSORS_FILTER" ]]; then + rm -f "$SENSORS_FILTER" + print_info "Sensor filter removed" + fi +} + +# Check if sensors are enabled +check_sensors() { + if [[ -f "$SENSORS_CONFIG" ]] && grep -q "$SENSORS_PATCH_MARKER" "$NODES_PM" 2>/dev/null; then + return 0 + fi + return 1 +} + +# Manage sensors subcommand +manage_sensors() { + local action="${1:-status}" + + case "$action" in + enable) + if [[ "$PRODUCT" != "PVE" ]]; then + print_error "Sensor support is only available for Proxmox VE" + exit 1 + fi + detect_sensors || exit 1 + patch_nodes_pm || exit 1 + mkdir -p "$INSTALL_DIR" + echo "enabled" > "$SENSORS_CONFIG" + print_status "Hardware sensor monitoring enabled!" + print_info "Restarting ${PROXY_SERVICE}..." + nohup systemctl restart "${PROXY_SERVICE}" &>/dev/null & + patch_cluster_sensors + ;; + disable) + remove_sensors + print_status "Hardware sensor monitoring disabled" + print_info "Restarting ${PROXY_SERVICE}..." + nohup systemctl restart "${PROXY_SERVICE}" &>/dev/null & + ;; + detect) + detect_sensors + ;; + configure) + if [[ "$PRODUCT" != "PVE" ]]; then + print_error "Sensor support is only available for Proxmox VE" + exit 1 + fi + if ! check_sensors; then + print_error "Sensors are not enabled. Enable them first with: install.sh manage-sensors enable" + exit 1 + fi + configure_sensor_filter + # Re-patch Nodes.pm so the filter file path is current + unpatch_nodes_pm + patch_nodes_pm + print_info "Restarting ${PROXY_SERVICE}..." + systemctl restart "${PROXY_SERVICE}" + print_status "Sensor filter applied!" + ;; + status|*) + if check_sensors; then + echo -e " Sensors: ${GREEN}Enabled${NC}" + if [[ -f "$SENSORS_FILTER" ]]; then + local count + count=$(wc -l < "$SENSORS_FILTER" 2>/dev/null) + echo -e " Filter: ${CYAN}${count} sensor(s) selected${NC}" + else + echo -e " Filter: ${CYAN}All sensors (no filter)${NC}" + fi + else + echo -e " Sensors: ${YELLOW}Disabled${NC}" + fi + ;; + esac +} + +# Interactive sensors management menu (called from show_menu option 7) +manage_sensors_menu() { + if [[ "$PRODUCT" != "PVE" ]]; then + print_error "Sensor support is only available for Proxmox VE" + return + fi + + echo "" + echo "=== Hardware Sensor Management ===" + echo "" + manage_sensors status + echo "" + echo " 1) Enable sensors" + echo " 2) Disable sensors" + echo " 3) Detect available sensors" + echo " 4) Configure sensor selection" + echo " 0) Back to main menu" + echo "" + read -p "Enter choice [0-4]: " sensor_choice + + case $sensor_choice in + 1) manage_sensors enable ;; + 2) manage_sensors disable ;; + 3) manage_sensors detect ;; + 4) manage_sensors configure ;; + 0) show_menu ;; + *) print_error "Invalid option" ; manage_sensors_menu ;; + esac +} + +# Get themes source directory - prioritizes local script directory, then /opt/proxmorph +# For PDM, looks for themes/pdm/ subdirectory first +get_themes_source() { + # 1. Check local script directory (prioritize local execution/development) + local script_dir="" + if [[ -n "${BASH_SOURCE[0]}" ]]; then + script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd 2>/dev/null)" + fi + + # Handle piped execution where BASH_SOURCE might be /dev/fd/* + if [[ -n "$script_dir" && "$script_dir" != /dev/fd* && "$script_dir" != /proc/* && -d "${script_dir}/themes" ]]; then + # PDM uses a separate theme subdirectory + if [[ "$PRODUCT" == "PDM" && -d "${script_dir}/themes/pdm" ]]; then + echo "${script_dir}/themes/pdm" + return 0 + fi + echo "${script_dir}/themes" + return 0 + fi + + # 2. Check /opt/proxmorph (fallback to installed cache) + if [[ -d "${INSTALL_DIR}/themes" ]]; then + if [[ "$PRODUCT" == "PDM" && -d "${INSTALL_DIR}/themes/pdm" ]]; then + echo "${INSTALL_DIR}/themes/pdm" + return 0 + fi + echo "${INSTALL_DIR}/themes" + return 0 + fi + + return 1 +} + +# Install all themes from themes directory +install_themes() { + print_info "Installing ProxMorph themes..." + + local themes_source=$(get_themes_source) + + if [[ -z "$themes_source" ]]; then + print_info "Local themes not found, attempting to download latest release..." + download_release + themes_source=$(get_themes_source) + + if [[ -z "$themes_source" ]]; then + print_error "Failed to locate themes even after download" + exit 1 + fi + fi + + # Count themes + local theme_count=$(find "$themes_source" -name "theme-*.css" 2>/dev/null | wc -l) + if [[ $theme_count -eq 0 ]]; then + print_error "No theme files found in $themes_source (looking for theme-*.css)" + exit 1 + fi + + print_info "Found $theme_count theme(s)" + + # Backup original files + backup_files + + # PDM uses a completely different installation approach (CSS injection via index.hbs) + if [[ "$PRODUCT" == "PDM" ]]; then + # Sync to local cache + if [[ "$themes_source" != "${INSTALL_DIR}/themes/pdm" ]]; then + mkdir -p "${INSTALL_DIR}/themes/pdm" + cp "$themes_source"/theme-*.css "${INSTALL_DIR}/themes/pdm/" 2>/dev/null || true + fi + + install_pdm_themes "$themes_source" + install_apt_hook + echo "$VERSION" > "${INSTALL_DIR}/.version" + + echo "" + print_status "ProxMorph PDM themes installed successfully!" + echo "" + print_info "To activate a theme:" + print_info " 1. Open browser console (F12) on your PDM web UI" + print_info " 2. Run: localStorage.setItem('proxmorph-theme', 'theme-dracula.css')" + print_info " 3. Reload the page (Ctrl+Shift+R)" + print_info "" + print_info "Available themes:" + for css_file in "$themes_source"/theme-*.css; do + if [[ -f "$css_file" ]]; then + local pname=$(basename "$css_file") + local ptitle=$(get_theme_title "$css_file") + print_theme " ${ptitle}: localStorage.setItem('proxmorph-theme', '${pname}')" + fi + done + print_info "" + print_info "To disable: localStorage.removeItem('proxmorph-theme') + reload" + + # Restart service + print_info "Restarting ${PROXY_SERVICE} service in background..." + nohup systemctl restart "${PROXY_SERVICE}" &>/dev/null & + return 0 + fi + + # PVE/PBS standard installation path + # Create themes directory if not exists + mkdir -p "$THEMES_DIR" + mkdir -p "${INSTALL_DIR}/themes" + + # Process each theme + for css_file in "$themes_source"/theme-*.css; do + if [[ -f "$css_file" ]]; then + theme_key=$(get_theme_key "$css_file") + theme_title=$(get_theme_title "$css_file") + + # Copy CSS file to live Proxmox web directory + cp "$css_file" "${THEMES_DIR}/" + chmod 644 "${THEMES_DIR}/$(basename "$css_file")" + + # Sync to local cache so apt hook uses the newest files on update + if [[ "$themes_source" != "${INSTALL_DIR}/themes" && "$themes_source" != "${INSTALL_DIR}/themes/pdm" ]]; then + if [[ "$PRODUCT" == "PDM" ]]; then + mkdir -p "${INSTALL_DIR}/themes/pdm" + cp "$css_file" "${INSTALL_DIR}/themes/pdm/" + else + cp "$css_file" "${INSTALL_DIR}/themes/" + fi + fi + + # Register in theme_map (PDM may not use proxmoxlib.js theme_map) + if [[ -f "$PROXMOXLIB_JS" ]]; then + patch_theme_map "$theme_key" "$theme_title" + elif [[ "$PRODUCT" == "PDM" ]]; then + print_info "PDM detected — skipping proxmoxlib.js theme_map (not applicable)" + fi + fi + done + + # Sync JavaScript patches to cache if installing locally + if [[ -d "${themes_source}/patches" && "$themes_source" != "${INSTALL_DIR}/themes" ]]; then + mkdir -p "${INSTALL_DIR}/themes/patches" + cp "${themes_source}/patches"/*.js "${INSTALL_DIR}/themes/patches/" 2>/dev/null || true + fi + + # Install apt hook for persistence across updates + install_apt_hook + + # Install JavaScript patches (chart colors, etc.) + install_js_patches + + # Write version file + echo "$VERSION" > "${INSTALL_DIR}/.version" + + # Offer hardware sensor integration (PVE only) + if [[ "$PRODUCT" == "PVE" ]]; then + echo "" + install_sensors + fi + + echo "" + print_status "ProxMorph themes installed successfully!" + echo "" + print_info "To apply a theme:" + print_info " 1. Clear your browser cache (Ctrl+Shift+R)" + print_info " 2. Click your username → Color Theme" + print_info " 3. Select a ProxMorph theme from the dropdown" + + # Restart proxy service in background + print_info "Restarting ${PROXY_SERVICE} service in background..." + nohup systemctl restart "${PROXY_SERVICE}" &>/dev/null & +} + +# Install a specific theme +install_single_theme() { + local theme_file="$1" + + if [[ ! -f "$theme_file" ]]; then + print_error "Theme file not found: $theme_file" + exit 1 + fi + + backup_files + mkdir -p "$THEMES_DIR" + + theme_key=$(get_theme_key "$theme_file") + theme_title=$(get_theme_title "$theme_file") + + cp "$theme_file" "${THEMES_DIR}/" + chmod 644 "${THEMES_DIR}/$(basename "$theme_file")" + patch_theme_map "$theme_key" "$theme_title" + + print_status "Theme '${theme_title}' installed!" + print_info "Restarting ${PROXY_SERVICE} service in background..." + nohup systemctl restart "${PROXY_SERVICE}" &>/dev/null & +} + +# Reinstall themes (after PVE update) +reinstall_themes() { + print_info "Reinstalling ProxMorph themes..." + restore_packages + install_themes +} + +# Uninstall all themes +uninstall_themes() { + print_info "Uninstalling ProxMorph themes..." + + # PDM-specific uninstall + if [[ "$PRODUCT" == "PDM" ]]; then + remove_pdm_themes + remove_apt_hook + if [[ -d "$INSTALL_DIR" ]]; then + rm -rf "$INSTALL_DIR" + print_status "Removed install directory: $INSTALL_DIR" + fi + echo "" + print_status "ProxMorph PDM themes uninstalled!" + print_info "Clear your browser cache and localStorage to see the changes." + print_info "Restarting ${PROXY_SERVICE}..." + nohup systemctl restart "${PROXY_SERVICE}" &>/dev/null & + return 0 + fi + + # PVE/PBS uninstall + # Find themes source + local themes_source=$(get_themes_source) || THEMES_DIR + + # Remove CSS files + for css_file in "$themes_source"/theme-*.css; do + if [[ -f "$css_file" ]]; then + target_file="${THEMES_DIR}/$(basename "$css_file")" + if [[ -f "$target_file" ]]; then + rm "$target_file" + print_status "Removed: $(basename "$css_file")" + fi + fi + done + + # Remove JavaScript patches + remove_js_patches + + # Remove sensor patches + remove_sensors + + # Remove apt hook + remove_apt_hook + + # Restore original proxmoxlib.js + restore_packages + + # Clean up install directory + if [[ -d "$INSTALL_DIR" ]]; then + rm -rf "$INSTALL_DIR" + print_status "Removed install directory: $INSTALL_DIR" + fi + + echo "" + print_status "ProxMorph themes uninstalled!" + print_info "Clear your browser cache to see the changes." +} + +# List available themes +list_themes() { + print_info "Available ProxMorph Themes:" + echo "" + + # Find themes source + local themes_source=$(get_themes_source) + + if [[ -z "$themes_source" ]]; then + print_error "Themes directory not found. Run 'update' first to download themes." + return 1 + fi + + for css_file in "$themes_source"/theme-*.css; do + if [[ -f "$css_file" ]]; then + theme_key=$(get_theme_key "$css_file") + theme_title=$(get_theme_title "$css_file") + + # Check if installed + if [[ -f "${THEMES_DIR}/$(basename "$css_file")" ]]; then + echo -e " ${GREEN}●${NC} ${theme_title} (${theme_key}) - Installed" + else + echo -e " ${YELLOW}○${NC} ${theme_title} (${theme_key})" + fi + fi + done + echo "" +} + +# Show status +show_status() { + print_info "ProxMorph Status:" + echo "" + + # Show installed version + if [[ -f "${INSTALL_DIR}/.version" ]]; then + local current_ver=$(cat "${INSTALL_DIR}/.version") + echo -e " Version: ${GREEN}v${current_ver}${NC}" + else + echo -e " Version: ${YELLOW}Unknown (local install)${NC}" + fi + + # Dynamically check if our themes are registered in proxmoxlib.js + local themes_source=$(get_themes_source) + local is_patched=false + if [[ -n "$themes_source" ]]; then + for css_file in "${themes_source}"/theme-*.css; do + if [[ -f "$css_file" ]]; then + local theme_key=$(get_theme_key "$css_file") + if grep -q "\"${theme_key}\":" "$PROXMOXLIB_JS" 2>/dev/null; then + is_patched=true + break + fi + fi + done + fi + + if [[ "$is_patched" == "true" ]]; then + echo -e " Theme Map: ${GREEN}Patched${NC}" + else + echo -e " Theme Map: ${YELLOW}Not patched${NC}" + fi + + # Count installed themes + local installed=0 + if [[ -n "$themes_source" ]]; then + for css_file in "${themes_source}"/theme-*.css; do + if [[ -f "${THEMES_DIR}/$(basename "$css_file")" ]]; then + installed=$((installed + 1)) + fi + done + fi + echo -e " Installed: ${GREEN}${installed}${NC} theme(s)" + + # Backup status + if [[ -f "${BACKUP_DIR}/proxmoxlib.js.original" ]]; then + echo -e " Backup: ${GREEN}Available${NC}" + else + echo -e " Backup: ${YELLOW}Not created${NC}" + fi + + # Apt hook status (persistence) + if check_apt_hook; then + echo -e " Auto-patch: ${GREEN}Enabled${NC} (persists across ${PRODUCT} updates)" + else + echo -e " Auto-patch: ${YELLOW}Not installed${NC}" + fi + + # Sensor status (PVE only) + if [[ "$PRODUCT" == "PVE" ]]; then + manage_sensors status + fi + + echo "" + list_themes +} + +# Main menu +show_menu() { + echo "" + echo "Select an option:" + echo " 1) Install themes" + echo " 2) Update from GitHub (latest release)" + echo " 3) Reinstall themes (after update)" + echo " 4) Uninstall themes" + echo " 5) List themes" + echo " 6) Show status" + [[ "$PRODUCT" == "PVE" ]] && echo " 7) Manage sensors" + echo " 0) Exit" + echo "" + read -p "Enter choice [0-7]: " choice + + case $choice in + 1) install_themes ;; + 2) download_release && install_themes ;; + 3) reinstall_themes ;; + 4) uninstall_themes ;; + 5) list_themes ;; + 6) show_status ;; + 7) manage_sensors_menu ;; + 0) exit 0 ;; + *) print_error "Invalid option" ; show_menu ;; + esac +} + +# Parse command line arguments +main() { + check_root + check_product + + case "${1:-}" in + install) + install_themes + ;; + update) + download_release "${2:-}" + install_themes + ;; + reinstall) + reinstall_themes + ;; + uninstall) + uninstall_themes + ;; + list) + list_themes + ;; + status) + show_status + ;; + check) + check_updates + ;; + sensors) + manage_sensors "${2:-status}" + ;; + *) + show_menu + ;; + esac +} + +main "$@" diff --git a/patch_theme_map.sh b/patch_theme_map.sh new file mode 100644 index 0000000..78acaa4 --- /dev/null +++ b/patch_theme_map.sh @@ -0,0 +1,20 @@ +#!/bin/bash +# Patch proxmoxlib.js to add UniFi theme +FILE="/usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js" + +# Check if already patched +if grep -q "unifi" "$FILE"; then + echo "Already patched!" +else + # Use awk for multi-line insert + awk '/theme_map: \{/ { print; print " '\''unifi'\'': '\''UniFi'\'',"; next }1' "$FILE" > /tmp/proxmoxlib.js.new + mv /tmp/proxmoxlib.js.new "$FILE" + echo "Patched!" +fi + +# Restart pveproxy +systemctl restart pveproxy +echo "pveproxy restarted" + +echo "Current theme_map:" +grep -A6 "theme_map:" "$FILE" diff --git a/themes/original-proxmox-dark.css b/themes/original-proxmox-dark.css new file mode 100644 index 0000000..4df60d9 --- /dev/null +++ b/themes/original-proxmox-dark.css @@ -0,0 +1 @@ +:root{--pwt-panel-background: #262626;--pwt-text-color: #f2f2f2;--pwt-gauge-default: #0060a4;--pwt-gauge-back: #333;--pwt-gauge-warn: #ffae0b;--pwt-gauge-crit: #ce3c3c;--pwt-chart-primary: #0060a4;--pwt-chart-grid-stroke: #4d4d4d}.x-legend-container{background-color:#333}.x-legend-horizontal .x-legend-item{background-color:#333;color:#f2f2f2;border-top:solid 1px #1a1a1a;border-right:solid 1px #1a1a1a;border-bottom:solid 1px #1a1a1a}.x-legend-horizontal .x-legend-item:first-child{border-left:solid 1px #1a1a1a}.x-tool .x-mask{backdrop-filter:none;background-color:#333;opacity:0.6}.x-grid-icon-custom.running,.x-tree-icon-custom.running,.x-tree-icon-custom,.fa-database::before,.fa-tags::before,.fa-file-o::before,.fa-building::before,.x-action-col-icon::before,.fa-shield::before,.fa-file-text-o::before,.fa-clock-o::before,.x-tab-icon-el-default,.pve-icon-verify-lettering::after,.x-tree-icon-custom.lock-migrate::after,.x-grid-icon-custom.lock-migrate::after,.x-tree-icon-leaf:not(.x-tree-icon-custom)::before,.x-tree-icon-parent:not(.x-tree-icon-custom)::before,.x-tree-icon-parent-expanded:not(.x-tree-icon-custom)::before,.x-grid-filters-filtered-column .x-column-header-text::after{color:#e6e6e6}.x-tree-icon-parent:not(.x-tree-icon-custom)::before,.x-tree-icon-parent-expanded:not(.x-tree-icon-custom)::before{filter:invert(90%)}.fa-ceph::before,.fa-sdn::before,.fa-network-wired::before,.pve-itype-treelist-item-icon-cdrom,.fa-chevron-right::before,.x-grid-row-console,.x-box-scroller-toolbar-default.x-box-scroller,.x-tree-elbow-img,.pve-itype-icon-qemu,.x-tree-node-computer,.x-grid-tree-node-expanded .x-tree-node-computer,.pbs-icon-tape,.pbs-icon-tape-drive,.x-tree-icon-leaf:not(.x-tree-icon-custom),.x-tree-icon-parent:not(.x-tree-icon-custom),.x-tree-icon-parent-expanded:not(.x-tree-icon-custom){filter:invert(90%)}.pve-itype-icon-cpu,.pve-itype-icon-cdrom,.pve-itype-icon-memory,.pve-itype-icon-pci,.pve-itype-icon-serial,.pve-itype-icon-die,.pmx-itype-icon-processor,.pmx-itype-icon-memory,.pve-itype-icon-storage,.x-tree-node-harddisk,.x-grid-tree-node-expanded .x-tree-node-harddisk{filter:invert(90%)}.pve-itype-icon-cpu .x-grid-cell-inner,.pve-itype-icon-cdrom .x-grid-cell-inner,.pve-itype-icon-memory .x-grid-cell-inner,.pve-itype-icon-pci .x-grid-cell-inner,.pve-itype-icon-serial .x-grid-cell-inner,.pve-itype-icon-die .x-grid-cell-inner,.pmx-itype-icon-processor .x-grid-cell-inner,.pmx-itype-icon-memory .x-grid-cell-inner,.pve-itype-icon-storage .x-grid-cell-inner,.x-tree-node-harddisk .x-grid-cell-inner,.x-grid-tree-node-expanded .x-tree-node-harddisk .x-grid-cell-inner{color:black}.x-keyboard-mode .pve-itype-icon-cpu.x-grid-item-focused,.x-keyboard-mode .pve-itype-icon-cdrom.x-grid-item-focused,.x-keyboard-mode .pve-itype-icon-memory.x-grid-item-focused,.x-keyboard-mode .pve-itype-icon-pci.x-grid-item-focused,.x-keyboard-mode .pve-itype-icon-serial.x-grid-item-focused,.x-keyboard-mode .pve-itype-icon-die.x-grid-item-focused,.x-keyboard-mode .pmx-itype-icon-processor.x-grid-item-focused,.x-keyboard-mode .pmx-itype-icon-memory.x-grid-item-focused,.x-keyboard-mode .pve-itype-icon-storage.x-grid-item-focused,.x-keyboard-mode .x-tree-node-harddisk.x-grid-item-focused,.x-keyboard-mode .x-grid-tree-node-expanded .x-tree-node-harddisk.x-grid-item-focused{background-color:#9e9e9e}.x-keyboard-mode .pve-itype-icon-cpu.x-grid-item-focused .x-grid-cell-inner::before,.x-keyboard-mode .pve-itype-icon-cdrom.x-grid-item-focused .x-grid-cell-inner::before,.x-keyboard-mode .pve-itype-icon-memory.x-grid-item-focused .x-grid-cell-inner::before,.x-keyboard-mode .pve-itype-icon-pci.x-grid-item-focused .x-grid-cell-inner::before,.x-keyboard-mode .pve-itype-icon-serial.x-grid-item-focused .x-grid-cell-inner::before,.x-keyboard-mode .pve-itype-icon-die.x-grid-item-focused .x-grid-cell-inner::before,.x-keyboard-mode .pmx-itype-icon-processor.x-grid-item-focused .x-grid-cell-inner::before,.x-keyboard-mode .pmx-itype-icon-memory.x-grid-item-focused .x-grid-cell-inner::before,.x-keyboard-mode .pve-itype-icon-storage.x-grid-item-focused .x-grid-cell-inner::before,.x-keyboard-mode .x-tree-node-harddisk.x-grid-item-focused .x-grid-cell-inner::before,.x-keyboard-mode .x-grid-tree-node-expanded .x-tree-node-harddisk.x-grid-item-focused .x-grid-cell-inner::before{border-color:#e69962}.fa.black,.fa.black::after,.fa.black::before,.x-action-col-icon.fa-chevron-right::before{filter:none}.x-tree-arrows .x-tree-expander{filter:brightness(200%)}.x-tree-arrows .x-tree-expander-over .x-tree-expander{filter:brightness(0)}.x-form-checkbox-default,.x-form-radio-default,.x-column-header-checkbox .x-column-header-checkbox::after,.x-grid-checkcolumn::after,.x-menu-item-checked .x-menu-item-icon-default.x-menu-item-checkbox,.x-menu-item-unchecked .x-menu-item-icon-default.x-menu-item-checkbox{filter:invert(90%) hue-rotate(180deg) brightness(125%)}.x-tree-icon-custom,.x-grid-icon-custom{color:#e6e6e6}.x-tree-icon-custom::after,.x-grid-icon-custom::after{color:#e6e6e6;text-shadow:-1px 0 1px #262626}.x-tree-icon-custom.stopped,.x-tree-icon-custom.offline,.x-tree-icon-custom.unknown::after,.x-grid-icon-custom.stopped,.x-grid-icon-custom.offline,.x-grid-icon-custom.unknown::after{color:#8c8c8c}.x-tree-icon-custom.locked::after,.x-grid-icon-custom.locked::after{color:#e6e6e6}.x-tree-icon-custom.lxc::after,.x-tree-icon-custom.qemu::after,.x-grid-icon-custom.lxc::after,.x-grid-icon-custom.qemu::after{background-color:#262626;color:#e6e6e6}.pmx-tree-icon-custom::after{text-shadow:-1px 0 1px #262626}.pmx-tree-icon-custom.maintenance::before{color:#8c8c8c}.pmx-tree-icon-custom.maintenance::after{color:#e6e6e6}.x-treelist-item-icon.lxc::after,.x-treelist-item-icon.qemu::after{background-color:#262626;color:#e6e6e6}.x-grid-item .x-grid-icon-custom.lxc::after,.x-grid-item .x-grid-icon-custom.qemu::after{background-color:#262626}.x-grid-item-alt .x-grid-icon-custom.lxc::after,.x-grid-item-alt .x-grid-icon-custom.qemu::after{background-color:#1a1a1a}.x-treelist-item-selected .lxc::after,.x-treelist-item-selected .qemu::after{background-color:#0060a4;text-shadow:-1px 0 1px #0060a4}.x-grid-item-over .lxc::after,.x-grid-item-over .qemu::after,.x-treelist-item-over .lxc::after,.x-treelist-item-over .qemu::after,.x-grid-item-selected .lxc::after,.x-grid-item-selected .qemu::after,.x-keyboard-mode .x-grid-item-focused .lxc::after,.x-keyboard-mode .x-grid-item-focused .qemu::after{background-color:#595959 !important;text-shadow:-1px 0 1px #595959}.x-action-col-icon:hover::before,.x-action-col-icon:hover::after{text-shadow:-1px 0 1px #262626}.fa.black{color:#e6e6e6}.usage-wrapper{border:1px solid #e6e6e6}.usage-negative{background-color:transparent}.usage{background-color:#e6e6e6}.x-btn-default-small{background-color:#0060a4;border-color:#0060a4}.x-btn-default-small.x-btn-over,.x-keyboard-mode .x-btn-default-small.x-btn-focus{background-color:#0078cf;border-color:#0078cf}.x-btn-default-small.x-btn.x-btn-disabled{background-color:#0060a4}.x-btn-default-small.x-btn.x-btn-pressed{background-color:#004a80;border-color:#0060a4}.x-btn-default-toolbar-small{background-color:#404040;border-color:#595959}.x-btn-default-toolbar-small .x-btn-inner-default-toolbar-small{color:#f2f2f2}.x-btn-default-toolbar-small .x-btn-icon-el-default-toolbar-small{color:#f2f2f2}.x-btn-default-toolbar-small .x-btn-wrap-default-toolbar-small.x-btn-arrow-right::after,.x-btn-default-toolbar-small .x-btn-wrap-default-toolbar-small.x-btn-split-right::after{filter:brightness(150%)}.x-btn-default-toolbar-small.x-btn-over,.x-keyboard-mode .x-btn-default-toolbar-small.x-btn-focus{background-color:#595959;border-color:#595959}.x-btn-default-toolbar-small.x-btn.x-btn-disabled{background-color:#404040}.x-btn-default-toolbar-small.x-btn.x-btn-menu-active,.x-btn-default-toolbar-small.x-btn.x-btn-pressed{background-color:#004a80;border-color:#0060a4}.x-form-trigger-default{background-color:#333}.x-boundlist{background-color:#333;border-color:#333}.x-boundlist-item{background-color:#333;border-color:#333;color:#f2f2f2}.x-boundlist-selected{background-color:#474747}.x-boundlist-item-over{background-color:#595959}.x-form-display-field-default{color:#f2f2f2}.x-form-text-default{background-color:#333;color:#f2f2f2}.x-form-trigger-wrap-default{border-color:#333}.x-form-trigger-wrap-default.x-form-trigger-wrap-focus{border-color:#005da0}.x-form-item-label-default{color:#f2f2f2}.x-form-spinner-default{background-color:#333}.x-form-cb-label-default{color:#e6e6e6}.x-fieldset-default{border-color:#404040}.x-column-header{border-color:#404040}.x-grid-item,.x-column-header-default,.x-grid-cell-row-numberer{color:#f2f2f2;background-color:#262626}.x-column-header-trigger{border-color:#666}.x-grid-cell-special{border-color:#404040}.x-grid-group-hd{background-color:#262626;border-color:#404040}.x-grid-group-title{color:#f2f2f2}.x-grid-header-ct{border:solid 1px #333;background-color:#333}.x-grid-item-alt{background-color:#1a1a1a}.x-grid-with-row-lines .x-grid-item{border-color:#404040;border-right:0}.x-grid-with-row-lines .x-grid-item:last-child{border-color:#404040}.x-grid-with-row-lines .x-grid-item:first-child{border-color:#404040}.x-grid-with-row-lines .x-grid-item.x-grid-item-over,.x-grid-with-row-lines .x-grid-item.x-grid-item-selected{background-color:#595959;border-color:#404040}.x-grid-with-row-lines .x-grid-item-selected+.x-grid-item,.x-grid-with-row-lines .x-grid-item-over+.x-grid-item{border-color:#404040}.x-grid-item-over,.x-grid-item-selected{background-color:#595959}.x-column-header-over,.x-column-header-open,.x-column-header-last .x-column-header-over .x-column-header-trigger{background-color:#4d4d4d}.x-column-header-sort-ASC,.x-column-header-sort-DESC{background-color:#1b384c}.x-grid-row-summary .x-grid-cell,.x-grid-row-summary .x-grid-rowwrap,.x-grid-row-summary .x-grid-cell-rowbody{background-color:#262626 !important;border-color:#404040}.x-grid-with-col-lines .x-grid-cell,.x-grid-with-col-lines .x-grid-item-over .x-grid-cell,.x-grid-with-col-lines .x-grid-item-selected .x-grid-cell{border-color:#404040}.x-dd-drag-proxy{background-color:#1a1a1a;border-color:#404040;color:#f2f2f2}.x-keyboard-mode .x-grid-item-focused{background-color:#595959;color:#fff}.x-keyboard-mode .x-grid-item-focused .x-grid-cell-inner::before{border-color:#0060a4}.x-keyboard-mode .x-column-header.x-column-header-focus{color:#f2f2f2}.x-keyboard-mode .x-column-header.x-column-header-focus .x-column-header-inner::after{border-color:#0060a4}.x-keyboard-mode .proxmox-invalid-row .x-grid-item-focused{background-color:#521414}.x-grid-empty{background-color:#262626;color:#f2f2f2}.x-menu-default{border-color:#333}.x-menu-body-default{background-color:#333}.x-menu-header{background-color:#0060a4}.x-menu-item-default.x-menu-item-separator{background-color:#333;border-color:#666}.x-menu-item-default.x-menu-item-focus,.x-menu-item-default.x-menu-item-active{background-color:#595959;color:#fff}.x-menu-item-text-default{color:#f2f2f2}.x-menu-item-icon-default{color:#e6e6e6}.x-menu-icon-separator-default{background-color:#333;border-color:#666}.x-panel-header-default{background-color:#333;border:none}.x-panel-header-default .x-tool-tool-el{background-color:transparent}.x-tool-img{filter:brightness(175%)}.x-tool-img.x-tool-expand,.x-tool-img.x-tool-collapse,.x-tool-img.x-tool-refresh{filter:brightness(125%)}.x-tool-img.x-tool-print{filter:invert(100%) hue-rotate(180deg) brightness(125%)}.x-tool-over .x-tool-img{filter:brightness(200%)}.x-tool-over .x-tool-img.x-tool-expand,.x-tool-over .x-tool-img.x-tool-collapse,.x-tool-over .x-tool-img.x-tool-refresh{filter:brightness(150%)}.x-tool-over .x-tool-img.x-tool-print{filter:invert(100%) hue-rotate(180deg) brightness(150%)}.x-panel-header-title-default{color:#4db5ff}.x-panel-body-default{background-color:#262626;border-color:#404040;color:#f2f2f2}div[id^="pveResourceTree-"][id$="-body"]{border-color:#262626}.x-progress-default{background-color:#333}.x-progress-default .x-progress-bar-default{background-color:#0060a4}.x-progress-default .x-progress-text{color:#f2f2f2}.x-progress.warning .x-progress-bar{background-color:var(--pwt-gauge-warn)}.x-progress.critical .x-progress-bar{background-color:var(--pwt-gauge-crit)}.x-splitter{background-color:#1a1a1a}.x-splitter-horizontal{background-color:#0d0d0d}.x-keyboard-mode .x-splitter-focus::after{border-color:#0060a4}.x-layout-split-bottom{opacity:0.7}.x-tab-bar-default{background-color:#262626}.x-tab-default.x-tab-over{background-color:#004a80;border-color:#004a80}.x-tab-default.x-tab.x-tab-active{background-color:#0078cf;border-color:#0078cf}.x-tab-default.x-tab.x-tab-disabled{background-color:#262626;border-color:transparent;color:#f2f2f2}.x-keyboard-mode .x-tab-default.x-tab-focus,.x-keyboard-mode .x-tab-default.x-tab-focus.x-tab-over,.x-keyboard-mode .x-tab-default.x-tab-focus.x-tab-active{background-color:#0060a4;border-color:#0060a4}.x-tab-default-top{background-color:#262626;border-color:#262626}.x-tab-inner-default{color:#f2f2f2}.x-tip-default{background-color:#1a1a1a;border-color:#404040}.x-tip-body-default{color:#f2f2f2}.x-tip-form-invalid{background-color:#333;border-color:#404040}.x-tip-body-form-invalid{color:#f2f2f2}.x-toolbar{background-color:#262626}.x-toolbar-default{background-color:#262626;border-color:#404040}.x-toolbar-default.x-docked-top{border-width:1px;border-color:#404040}.x-toolbar-default .x-toolbar-separator{border-color:#666}.x-toolbar-text-default{color:#f2f2f2}.x-treelist-item{background-color:#262626}.x-treelist-item-text,.x-treelist-item-icon,.x-treelist-row-over .x-treelist-item-icon,.x-treelist-row-over .x-treelist-item-text{color:#f2f2f2}.x-treelist-item-selected>.x-treelist-row{background-color:#0060a4}.x-treelist-row-over{background-color:#595959}.x-treelist-pve-nav{background-color:#262626;border-color:#666}.x-window-default{background-color:#1a1a1a;border-color:transparent}.x-window-header-default{background-color:#262626;border-color:transparent}.x-window-header-default .x-mask{background-color:rgba(38,38,38,0.7)}.x-window-header-title-default{color:#4db5ff}.x-window-body-default{background-color:#262626;border-color:#404040;color:#f2f2f2}.x-window-ghost{background-color:#262626}.x-window-header-default .x-tool-img{background-color:transparent}.x-message-box .x-window-body{background-color:#333}:root{color-scheme:dark}.x-body{color:#f2f2f2;background-color:#1a1a1a}.x-viewport>.x-body{background-color:#1a1a1a}body.x-border-layout-ct,div.x-border-layout-ct{background-color:#1a1a1a}.x-mask{background-color:rgba(38,38,38,0.5)}.x-css-shadow{box-shadow:black 0 -1px 15px 5px !important}img[id^="proxmoxlogo-"][id$="-img"]{filter:invert(1) hue-rotate(180deg)}img[id^="proxmoxLogoSvg-"][id$="-img"]{filter:invert(1) hue-rotate(180deg)}div[id^="versioninfo-"]+div[id^="panel-"]>div[id^="panel-"][id$="-bodyWrap"]>div,div.eol-notice+div[id^="panel-"]>div[id^="panel-"][id$="-bodyWrap"]>div{background-color:transparent;border-color:transparent}.x-fieldset-header-default>.x-fieldset-header-text{color:#f2f2f2}.proxmox-invalid-row{background-color:#521414}.proxmox-warning-row{background-color:#640}.proxmox-disabled-row td{color:#999}.pmx-hint{background-color:#640}.pmx-hint a{color:#99d5ff}.pmx-hint a:active{color:#4db5ff}.pmx-unclickable{pointer-events:none}.proxmox-inline-button{background-color:#a6a6a6;border-color:#bfbfbf;color:#1a1a1a}.proxmox-inline-button.x-btn-over,.proxmox-inline-button.x-btn.x-btn-pressed.x-btn-default-toolbar-small,.x-keyboard-mode .proxmox-inline-button.x-btn-default-toolbar-small.x-btn-focus{background-color:#bfbfbf;border-color:#bfbfbf}.proxmox-inline-button .x-btn-inner,.proxmox-inline-button .x-btn-icon-el{color:#1a1a1a}.x-grid-row-loading,.x-treelist-item-loading .x-treelist-item-icon,.x-treelist-nav .x-treelist-item-loading .x-treelist-item-icon,.x-mask-msg-text,.x-grid-tree-loading .x-tree-icon{filter:invert(90%);color:black}.x-keyboard-mode .x-grid-item-focused.x-grid-row-loading{background-color:#9e9e9e}.x-keyboard-mode .x-grid-item-focused.x-grid-row-loading .x-grid-cell-inner::before{border-color:#e69962 !important}.x-mask-msg{background-color:#333;border:solid 1px #404040}.pmx-md code{background-color:#1a1a1a}.pmx-md pre code{border-color:#404040}.pmx-md tbody tr td{border-color:#666}.pmx-md tbody tr:nth-of-type(2n){background-color:#1a1a1a}.pmx-md tbody tr:hover td{background-color:#4d4d4d}.pmx-md a{color:#4db5ff}.pmx-md a:active{color:#99d5ff}.proxmox-apt-repos .x-grid-group-hd{background-color:#1a1a1a;border-color:#404040}.proxmox-apt-repos .x-grid-group-title{color:#f2f2f2}:root{--pmg-spam-high-neg: #123954;--pmg-spam-high-pos: #4f1717;--pmg-spam-mid-neg: #1b557e;--pmg-spam-mid-pos: #722;--pmg-spam-low-neg: #2471a8;--pmg-spam-low-pos: #9e2e2e}.info-blue{color:#4db5ff !important}.critical{color:#ff4d4d !important}tr.blocked,.x-keyboard-mode tr.blocked .x-grid-item-focused{background-color:#521414}tr.quarantine,.x-keyboard-mode tr.quarantine .x-grid-item-focused{background-color:#5c2c0a}tr.bounced,.x-keyboard-mode tr.bounced .x-grid-item-focused{background-color:#640}.pmg-mail-preview-themed div>iframe{filter:brightness(95%) invert(95%)}table.osds tr{border-color:#666}table.osds td{border-color:#666}.install-mask{background-color:#262626;color:#f2f2f2}.x-window.install-mask{box-shadow:black 0 -1px 5px 1px !important}div.monitor{border-color:#666}.pve-edit-tag.editable span{background-color:#333;color:#f2f2f2;border-color:#666}.proxmox-tags-full .proxmox-tag-light,.proxmox-tags-full .proxmox-tag-dark,.proxmox-tags-circle .proxmox-tag-light,.proxmox-tags-circle .proxmox-tag-dark{outline:1px solid rgba(51,51,51,0.3)}.x-datepicker,.x-datepicker-column-header,.x-monthpicker{background-color:#262626;color:#f2f2f2;border-color:transparent}.x-datepicker-month .x-btn-over.x-btn-default-small{background-color:#595959}.x-monthpicker-months{border-color:#404040}.x-datepicker-header{background-color:#1a1a1a}.x-datepicker-cell,.x-monthpicker-item-inner{border-color:transparent}.x-datepicker-date,.x-monthpicker-item-inner{color:#f2f2f2}.x-datepicker-prevday .x-datepicker-date,.x-datepicker-nextday .x-datepicker-date{color:#999}.x-datepicker-footer,.x-monthpicker-buttons{background-color:#1a1a1a}.x-datepicker-selected div.x-datepicker-date,.x-monthpicker-item a.x-monthpicker-selected,a.x-monthpicker-item-inner:hover,div.x-datepicker-date:hover{background-color:#595959;color:#fff}.x-datepicker-disabled .x-datepicker-date{background-color:#1a1a1a}.x-datepicker-disabled div.x-datepicker-date:hover{background-color:#262626} diff --git a/themes/patches/github-dark-init.js b/themes/patches/github-dark-init.js new file mode 100644 index 0000000..4e42fde --- /dev/null +++ b/themes/patches/github-dark-init.js @@ -0,0 +1,59 @@ +/** + * ProxMorph GitHub Dark — Checkbox/Radio Init Patch + * + * Problem: ExtJS pre-selects checkboxes/radios by setting background-position + * to "0px -15px" (sprite selected state) WITHOUT adding the .x-form-cb-checked + * class to the .x-form-item ancestor. Our CSS relies on that class. + * + * Fix: Scan all .x-form-cb spans, detect the -15px sprite offset, and add + * .x-form-cb-checked to the nearest .x-form-item ancestor so our CSS rules fire. + * + * Runs on load + via MutationObserver whenever new dialogs are added to the DOM. + */ +(function () { + 'use strict'; + + function isGithubDarkActive() { + return !!document.querySelector('link[href*="theme-github-dark.css"]'); + } + + function fixInitialCbState() { + if (!isGithubDarkActive()) return; + + document.querySelectorAll('.x-form-cb').forEach(function (span) { + var bgPos = window.getComputedStyle(span).backgroundPosition; + if (bgPos && bgPos.indexOf('-15px') !== -1) { + var fieldItem = span.closest('.x-form-item'); + if (fieldItem && !fieldItem.classList.contains('x-form-cb-checked')) { + fieldItem.classList.add('x-form-cb-checked'); + } + } + }); + } + + // Run once after the page is fully loaded + if (document.readyState === 'complete') { + setTimeout(fixInitialCbState, 100); + } else { + window.addEventListener('load', function () { + setTimeout(fixInitialCbState, 100); + }); + } + + // Re-run whenever new nodes are added (dialog opens, panel navigation, etc.) + var observer = new MutationObserver(function (mutations) { + var hasNew = false; + for (var i = 0; i < mutations.length; i++) { + if (mutations[i].addedNodes.length) { + hasNew = true; + break; + } + } + if (hasNew) { + setTimeout(fixInitialCbState, 50); + } + }); + + observer.observe(document.body, { childList: true, subtree: true }); + +})(); diff --git a/themes/patches/pdm-theme-selector.js b/themes/patches/pdm-theme-selector.js new file mode 100644 index 0000000..2fa6496 --- /dev/null +++ b/themes/patches/pdm-theme-selector.js @@ -0,0 +1,296 @@ +/* + * ProxMorph PDM Theme Selector Patch + * Version: 1.0.0 + * + * Injects ProxMorph theme options into PDM's native Theme dialog dropdown. + * Uses MutationObserver to detect when the dialog opens and adds custom + * theme entries alongside the built-in Desktop/Crisp options. + * + * Theme guard: only runs if proxmorph-theme CSS links are present. + */ +(function() { + 'use strict'; + + if (!document.querySelector('link.proxmorph-theme')) return; + + var themeLinks = document.querySelectorAll('link.proxmorph-theme'); + var themes = []; + for (var i = 0; i < themeLinks.length; i++) { + var href = themeLinks[i].getAttribute('href'); + var filename = href.split('/').pop(); + var name = filename.replace('theme-', '').replace('.css', '') + .split('-').map(function(w) { return w.charAt(0).toUpperCase() + w.slice(1); }).join(' '); + themes.push({ filename: filename, display: 'PM: ' + name, link: themeLinks[i] }); + } + + function activateTheme(filename) { + for (var i = 0; i < themeLinks.length; i++) { + themeLinks[i].setAttribute('disabled', ''); + } + if (filename) { + localStorage.setItem('proxmorph-theme', filename); + var base = document.querySelector('link.proxmorph-base'); + if (base) base.removeAttribute('disabled'); + for (var j = 0; j < themeLinks.length; j++) { + if (themeLinks[j].href.indexOf(filename) !== -1) { + themeLinks[j].removeAttribute('disabled'); + } + } + } else { + localStorage.removeItem('proxmorph-theme'); + var base = document.querySelector('link.proxmorph-base'); + if (base) base.setAttribute('disabled', ''); + } + } + + function deactivateProxmorph() { + for (var i = 0; i < themeLinks.length; i++) { + themeLinks[i].setAttribute('disabled', ''); + } + var base = document.querySelector('link.proxmorph-base'); + if (base) base.setAttribute('disabled', ''); + localStorage.removeItem('proxmorph-theme'); + } + + var patched = false; + + function setupObserver() { + var observer = new MutationObserver(function() { + if (patched) return; + tryInject(); + }); + observer.observe(document.documentElement, { childList: true, subtree: true }); + } + + if (document.readyState === 'loading') { + document.addEventListener('DOMContentLoaded', setupObserver); + } else { + setupObserver(); + } + + function tryInject() { + var dialog = document.querySelector('dialog'); + if (!dialog) { patched = false; return; } + + var combo = dialog.querySelector('[aria-label="Select Theme"]'); + if (!combo) return; + + /* Early combo fix: override value as soon as dialog appears, before dropdown is expanded */ + var currentThemeEarly = localStorage.getItem('proxmorph-theme'); + if (currentThemeEarly && combo.tagName === 'INPUT' && !combo.__proxmorphPatched) { + for (var ei = 0; ei < themes.length; ei++) { + if (themes[ei].filename === currentThemeEarly) { + var origDesc = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, 'value'); + origDesc.set.call(combo, themes[ei].display); + Object.defineProperty(combo, 'value', { + get: function() { return origDesc.get.call(this); }, + set: function(v) { + var active = localStorage.getItem('proxmorph-theme'); + if (active && (v === 'Desktop' || v === 'Crisp' || v === 'Material')) { + return; + } + origDesc.set.call(this, v); + }, + configurable: true + }); + combo.__proxmorphPatched = true; + break; + } + } + } + + var tables = dialog.querySelectorAll('.pwt-datatable-content'); + var themeTable = null; + + for (var t = 0; t < tables.length; t++) { + var rows = tables[t].querySelectorAll('tr[role="row"]'); + for (var r = 0; r < rows.length; r++) { + var cellText = rows[r].textContent.trim(); + if (cellText === 'Desktop' || cellText === 'Crisp' || cellText === 'Material') { + themeTable = tables[t]; + break; + } + } + if (themeTable) break; + } + + if (!themeTable) return; + if (themeTable.querySelector('[data-proxmorph-theme]')) { patched = true; return; } + + var nativeRows = themeTable.querySelectorAll('tr[role="row"]'); + var existingCount = nativeRows.length; + + var idPrefix = 'ProxMorph'; + if (nativeRows.length > 0 && nativeRows[0].id) { + idPrefix = nativeRows[0].id.split('-item-')[0]; + } + + var sepRow = document.createElement('tr'); + sepRow.setAttribute('role', 'none'); + sepRow.className = 'proxmorph-separator'; + var sepTd = document.createElement('td'); + sepTd.setAttribute('role', 'none'); + sepTd.setAttribute('colspan', '2'); + sepTd.style.cssText = 'padding:4px 0;border-top:1px solid var(--pwt-color-neutral-40,#555);'; + var sepDiv = document.createElement('div'); + sepDiv.style.cssText = 'font-size:11px;color:var(--pwt-color-neutral-60,#999);padding:2px 8px;'; + sepDiv.textContent = 'ProxMorph Themes'; + sepTd.appendChild(sepDiv); + sepRow.appendChild(sepTd); + themeTable.appendChild(sepRow); + + var currentTheme = localStorage.getItem('proxmorph-theme'); + + for (var i = 0; i < themes.length; i++) { + var theme = themes[i]; + var rowIndex = existingCount + i + 1; + var isSelected = currentTheme === theme.filename; + + var row = document.createElement('tr'); + row.setAttribute('role', 'row'); + row.setAttribute('aria-rowindex', String(rowIndex)); + row.setAttribute('aria-selected', isSelected ? 'true' : 'false'); + row.id = idPrefix + '-item-PM-' + theme.filename; + row.className = isSelected ? 'row-cursor selected' : ''; + row.setAttribute('data-proxmorph-theme', theme.filename); + + var td = document.createElement('td'); + td.setAttribute('role', 'gridcell'); + td.setAttribute('data-column-num', '0'); + td.setAttribute('tabindex', '-1'); + td.className = 'pwt-datatable-cell pwt-pointer' + (isSelected ? ' cell-cursor' : ''); + td.style.cssText = 'vertical-align:baseline;text-align:start;'; + + var div = document.createElement('div'); + div.setAttribute('role', 'none'); + div.textContent = theme.display; + td.appendChild(div); + + var td2 = document.createElement('td'); + td2.setAttribute('role', 'none'); + td2.style.cssText = 'vertical-align:top;height:22px;'; + + row.appendChild(td); + row.appendChild(td2); + themeTable.appendChild(row); + + (function(themeObj, rowEl) { + rowEl.addEventListener('click', function(e) { + e.stopPropagation(); + var allRows = themeTable.querySelectorAll('tr[role="row"]'); + for (var k = 0; k < allRows.length; k++) { + allRows[k].className = ''; + allRows[k].setAttribute('aria-selected', 'false'); + var cells = allRows[k].querySelectorAll('.pwt-datatable-cell'); + for (var c = 0; c < cells.length; c++) { + cells[c].classList.remove('cell-cursor'); + } + } + rowEl.className = 'row-cursor selected'; + rowEl.setAttribute('aria-selected', 'true'); + var myCell = rowEl.querySelector('.pwt-datatable-cell'); + if (myCell) myCell.classList.add('cell-cursor'); + + activateTheme(themeObj.filename); + + var combo = dialog.querySelector('[aria-label="Select Theme"]'); + if (combo) { + if (combo.tagName === 'INPUT') { + /* Remove override temporarily to set the new value */ + var origDesc = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, 'value'); + delete combo.value; + origDesc.set.call(combo, themeObj.display); + /* Re-install override to block PWT resets */ + Object.defineProperty(combo, 'value', { + get: function() { return origDesc.get.call(this); }, + set: function(v) { + var active = localStorage.getItem('proxmorph-theme'); + if (active && (v === 'Desktop' || v === 'Crisp' || v === 'Material')) { + return; + } + origDesc.set.call(this, v); + }, + configurable: true + }); + } else { + var valueSpan = combo.querySelector('.pwt-text-truncate') || combo; + if (valueSpan) valueSpan.textContent = themeObj.display; + } + } + }); + })(theme, row); + } + + /* If a ProxMorph theme is active, deselect native rows and update combo */ + if (currentTheme) { + for (var d = 0; d < nativeRows.length; d++) { + nativeRows[d].className = ''; + nativeRows[d].setAttribute('aria-selected', 'false'); + var dCells = nativeRows[d].querySelectorAll('.pwt-datatable-cell'); + for (var dc = 0; dc < dCells.length; dc++) { + dCells[dc].classList.remove('cell-cursor'); + } + } + /* Update combo display text to active PM theme name */ + var activeCombo = dialog.querySelector('[aria-label="Select Theme"]'); + if (activeCombo) { + for (var at = 0; at < themes.length; at++) { + if (themes[at].filename === currentTheme) { + if (activeCombo.tagName === 'INPUT') { + activeCombo.value = themes[at].display; + /* Override value setter to prevent PWT from resetting to native theme name */ + var pmDisplay = themes[at].display; + var origDescriptor = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, 'value'); + Object.defineProperty(activeCombo, 'value', { + get: function() { return origDescriptor.get.call(this); }, + set: function(v) { + var active = localStorage.getItem('proxmorph-theme'); + if (active && (v === 'Desktop' || v === 'Crisp' || v === 'Material')) { + return; + } + origDescriptor.set.call(this, v); + }, + configurable: true + }); + } else { + var valSpan = activeCombo.querySelector('.pwt-text-truncate') || activeCombo; + if (valSpan) valSpan.textContent = themes[at].display; + } + break; + } + } + } + } + + for (var nr = 0; nr < nativeRows.length; nr++) { + (function(nativeRow) { + nativeRow.addEventListener('click', function() { + deactivateProxmorph(); + /* Remove value override so PWT can set native theme name */ + var cmb = dialog.querySelector('[aria-label="Select Theme"]'); + if (cmb && cmb.tagName === 'INPUT') { + delete cmb.value; + } + var pmRows = themeTable.querySelectorAll('[data-proxmorph-theme]'); + for (var p = 0; p < pmRows.length; p++) { + pmRows[p].className = ''; + pmRows[p].setAttribute('aria-selected', 'false'); + var cells = pmRows[p].querySelectorAll('.pwt-datatable-cell'); + for (var c = 0; c < cells.length; c++) { + cells[c].classList.remove('cell-cursor'); + } + } + }); + })(nativeRows[nr]); + } + + patched = true; + + var closeCheck = setInterval(function() { + if (!document.contains(themeTable)) { + patched = false; + clearInterval(closeCheck); + } + }, 500); + } +})(); diff --git a/themes/patches/proxmorph-sensors.js b/themes/patches/proxmorph-sensors.js new file mode 100644 index 0000000..9e58163 --- /dev/null +++ b/themes/patches/proxmorph-sensors.js @@ -0,0 +1,468 @@ +/** + * ProxMorph Hardware Sensors + * Adds hardware sensor monitoring to the Proxmox VE node status panel. + * Displays CPU, NVMe, HDD temperatures, fan speeds, and UPS status + * in a compact single-row layout. + * + * Requires: + * - lm-sensors installed on the Proxmox host + * - Nodes.pm patched to expose sensor data via API + * - Enabled via ProxMorph installer (--sensors flag) + * + * Data flow: + * 1. Nodes.pm runs `sensors -j` and exposes sensorsOutput in API + * 2. PVE.node.StatusView fetches /api2/json/nodes/{node}/status + * 3. Our override injects a single "Sensors" item reading that field + * 4. Combined renderer parses JSON and produces compact themed HTML + * + * Supports: + * - Intel (coretemp-isa-*) and AMD (k10temp-pci-*) CPU temperatures + * - NVMe drive temperatures (nvme-pci-*) + * - HDD/SATA drive temperatures (drivetemp-scsi-*) + * - Fan speeds (recursive detection of fan*_input keys) + * - UPS status via NUT (upsc) — optional, shown inline when present + * + * Version: 1.2.0 + */ +(function () { + 'use strict'; + + // ─── Configuration ───────────────────────────────────────────── + var SENSOR_UNIT = 'C'; // 'C' or 'F' + + // ─── Sensor Filter (populated from API on store load) ────────── + // null = no filter (show all), otherwise object with chip:label keys + var activeSensorFilter = null; + + function isSensorAllowed(chipKey, label) { + if (!activeSensorFilter) return true; + return activeSensorFilter[chipKey + ':' + label] === true; + } + + function parseSensorFilter(raw) { + if (!raw || typeof raw !== 'string' || raw.trim() === '') return null; + var filter = {}; + raw.split('\n').forEach(function (line) { + line = line.trim(); + if (line !== '') filter[line] = true; + }); + return Object.keys(filter).length > 0 ? filter : null; + } + + // ─── CSS Variable Reader ─────────────────────────────────────── + function getThemeColors() { + var cs = getComputedStyle(document.documentElement); + return { + text: cs.getPropertyValue('--pm-text').trim() || '#e5e7eb', + textDim: cs.getPropertyValue('--pm-text-dim').trim() || '#9ca3af', + warning: cs.getPropertyValue('--pm-warning').trim() || '#f5a623', + error: cs.getPropertyValue('--pm-error').trim() || '#f03a3e', + success: cs.getPropertyValue('--pm-success').trim() || '#37be5f', + accent: cs.getPropertyValue('--pm-accent').trim() || '#006eff' + }; + } + + // ─── Temperature Helpers ─────────────────────────────────────── + function formatTemp(celsius) { + if (celsius === null || celsius === undefined || isNaN(celsius)) return '—'; + var val = SENSOR_UNIT === 'F' ? (celsius * 9 / 5) + 32 : celsius; + return Ext.util.Format.number(val, '0.#') + '°' + SENSOR_UNIT; + } + + function tempColor(temp, max, crit, colors) { + if (crit !== null && temp >= crit) return colors.error; + if (max !== null && temp >= max) return colors.warning; + return colors.text; + } + + // ─── JSON Parser ─────────────────────────────────────────────── + function parseSensorsJSON(raw) { + if (!raw || typeof raw !== 'string') return null; + try { + var cleaned = raw + .replace(/,(\s*[}\]])/g, '$1') + .replace(/\bNaN\b/g, 'null') + .replace(/\bERROR\b[^\n]*/g, ''); + return JSON.parse(cleaned); + } catch (e) { + console.warn('[ProxMorph Sensors] JSON parse error:', e.message); + return null; + } + } + + // ─── Inline HTML Helpers ─────────────────────────────────────── + function tag(text, color, bold) { + var s = 'color:' + color + ';'; + if (bold) s += 'font-weight:600;'; + return '' + text + ''; + } + + function sep(colors) { + return '|'; + } + + // ─── Combined Sensors Renderer ───────────────────────────────── + // Produces a compact single-line output: CPU | NVMe | Fan + // Only sections with data are shown — no "No X detected" clutter. + function renderSensors(value, record) { + // Read filter from the StatusView's store (resolves timing issue where + // our store.on('load') fires after ExtJS already called this renderer) + try { + var store = (record && record.store) ? record.store : null; + if (!store) { + var widget = Ext.ComponentQuery.query('#sensors')[0]; + if (widget && widget.ownerCt && widget.ownerCt.getStore) { + store = widget.ownerCt.getStore(); + } + } + if (store) { + var filterRec = store.findRecord('key', 'sensorsFilter'); + activeSensorFilter = filterRec ? parseSensorFilter(filterRec.get('value')) : null; + } + } catch (e) { /* filter stays as-is */ } + + var data = parseSensorsJSON(value); + var colors = getThemeColors(); + if (!data) return tag('N/A', colors.textDim); + + var sections = []; + + // ── CPU Temperature ───────────────────────────────────── + var cpuChips = Object.keys(data).filter(function (k) { + return k.indexOf('coretemp-isa-') === 0 || + k.indexOf('k10temp-pci-') === 0; + }); + + cpuChips.forEach(function (chipKey) { + var chip = data[chipKey]; + var pkgTemp = null, pkgMax = null, pkgCrit = null; + var coreTemps = []; + + Object.keys(chip).forEach(function (label) { + if (label === 'Adapter') return; + if (!isSensorAllowed(chipKey, label)) return; + var sensor = chip[label]; + if (!sensor || typeof sensor !== 'object') return; + + var inputKey = null, maxKey = null, critKey = null; + Object.keys(sensor).forEach(function (k) { + if (/^temp\d+_input$/.test(k)) inputKey = k; + else if (/^temp\d+_max$/.test(k)) maxKey = k; + else if (/^temp\d+_crit$/.test(k)) critKey = k; + }); + if (!inputKey) return; + + var temp = sensor[inputKey]; + if (temp === null || temp === undefined) return; + + if (/Package|Tctl|Tdie/i.test(label)) { + pkgTemp = temp; + pkgMax = maxKey ? sensor[maxKey] : null; + pkgCrit = critKey ? sensor[critKey] : null; + } else { + coreTemps.push({ + label: label, + temp: temp, + max: maxKey ? sensor[maxKey] : null, + crit: critKey ? sensor[critKey] : null + }); + } + }); + + if (pkgTemp !== null) { + var color = tempColor(pkgTemp, pkgMax, pkgCrit, colors); + var txt = 'CPU: ' + formatTemp(pkgTemp); + if (coreTemps.length > 0) txt += ' (' + coreTemps.length + ' cores)'; + sections.push(tag(txt, color)); + } else if (coreTemps.length > 0) { + if (activeSensorFilter) { + // Filter active: show each selected core individually + coreTemps.forEach(function (core) { + var color = tempColor(core.temp, core.max, core.crit, colors); + sections.push(tag(core.label + ': ' + formatTemp(core.temp), color)); + }); + } else { + var maxT = Math.max.apply(null, coreTemps.map(function (c) { return c.temp; })); + var color = tempColor(maxT, 80, 95, colors); + sections.push(tag('CPU: ' + formatTemp(maxT) + ' peak (' + coreTemps.length + ' cores)', color)); + } + } + }); + + // ── NVMe Temperature (composite only) ─────────────────── + var nvmeKeys = Object.keys(data).filter(function (k) { + return k.indexOf('nvme-pci-') === 0; + }); + nvmeKeys.forEach(function (chipKey, idx) { + var chip = data[chipKey]; + var compositeTemp = null, compMax = null, compCrit = null; + + Object.keys(chip).forEach(function (label) { + if (label !== 'Composite') return; + if (!isSensorAllowed(chipKey, label)) return; + var sensor = chip[label]; + if (!sensor || typeof sensor !== 'object') return; + + Object.keys(sensor).forEach(function (k) { + if (/^temp\d+_input$/.test(k) && compositeTemp === null) { + compositeTemp = sensor[k]; + } + if (/^temp\d+_max$/.test(k)) { + var m = sensor[k]; + if (m !== null && m < 200) compMax = m; + } + if (/^temp\d+_crit$/.test(k)) compCrit = sensor[k]; + }); + }); + + if (compositeTemp !== null) { + var color = tempColor(compositeTemp, compMax || 70, compCrit || 80, colors); + var lbl = nvmeKeys.length > 1 ? 'NVMe' + idx : 'NVMe'; + sections.push(tag(lbl + ': ' + formatTemp(compositeTemp), color)); + } + }); + + // ── SATA/HDD Temperature ──────────────────────────────── + var hddKeys = Object.keys(data).filter(function (k) { + return k.indexOf('drivetemp-scsi-') === 0; + }); + hddKeys.forEach(function (chipKey, idx) { + var chip = data[chipKey]; + Object.keys(chip).forEach(function (label) { + if (label === 'Adapter') return; + if (!isSensorAllowed(chipKey, label)) return; + var sensor = chip[label]; + if (!sensor || typeof sensor !== 'object') return; + + var inputKey = null; + Object.keys(sensor).forEach(function (k) { + if (/^temp\d+_input$/.test(k)) inputKey = k; + }); + if (!inputKey) return; + + var temp = sensor[inputKey]; + if (temp !== null && temp !== undefined) { + var color = tempColor(temp, 45, 55, colors); + var lbl = hddKeys.length > 1 ? 'HDD' + idx : 'HDD'; + sections.push(tag(lbl + ': ' + formatTemp(temp), color)); + } + }); + }); + + // ── Fan Speeds ────────────────────────────────────────── + var fans = []; + function findFans(obj, parentLabel, chipKey) { + if (!obj || typeof obj !== 'object') return; + Object.keys(obj).forEach(function (key) { + if (/^fan\d+_input$/.test(key)) { + var label = parentLabel || key.replace('_input', ''); + if (isSensorAllowed(chipKey, label)) { + fans.push({ + label: label, + rpm: obj[key] + }); + } + } else if (typeof obj[key] === 'object' && key !== 'Adapter') { + findFans(obj[key], key, chipKey); + } + }); + } + Object.keys(data).forEach(function (chipKey) { + findFans(data[chipKey], '', chipKey); + }); + + if (fans.length > 0) { + fans.forEach(function (fan) { + var rpm = fan.rpm || 0; + var color = rpm === 0 ? colors.warning : colors.text; + sections.push(tag(fan.label + ': ' + rpm + ' RPM', color)); + }); + } + + // ── Join all sections ─────────────────────────────────── + if (sections.length === 0) return tag('No sensors detected', colors.textDim); + return sections.join(sep(colors)); + } + + // ─── UPS Renderer (compact inline) ───────────────────────────── + function renderUps(value) { + var colors = getThemeColors(); + if (!value || typeof value !== 'string' || value.trim() === '') { + return ''; + } + + var fields = {}; + value.split('\n').forEach(function (line) { + var idx = line.indexOf(':'); + if (idx > 0) { + fields[line.substring(0, idx).trim()] = line.substring(idx + 1).trim(); + } + }); + if (Object.keys(fields).length === 0) return ''; + + var parts = []; + + // Status + var status = fields['ups.status'] || ''; + var sColor = colors.success, sText = 'Online'; + if (status.indexOf('OB') !== -1) { sColor = colors.error; sText = 'On Battery'; } + else if (status.indexOf('LB') !== -1) { sColor = colors.error; sText = 'Low Battery'; } + else if (status.indexOf('CHRG') !== -1) { sColor = colors.warning; sText = 'Charging'; } + else if (status.indexOf('OL') === -1 && status) { sColor = colors.warning; sText = status; } + parts.push(tag(sText, sColor, true)); + + // Battery + var charge = parseFloat(fields['battery.charge']); + if (!isNaN(charge)) { + var cColor = charge < 20 ? colors.error : charge < 50 ? colors.warning : colors.success; + parts.push(tag(charge + '%', cColor)); + } + + // Load + var load = parseFloat(fields['ups.load']); + if (!isNaN(load)) { + var lColor = load > 80 ? colors.error : load > 60 ? colors.warning : colors.text; + parts.push(tag('Load ' + load + '%', lColor)); + } + + // Runtime + var runtime = parseFloat(fields['battery.runtime']); + if (!isNaN(runtime)) { + var mins = Math.floor(runtime / 60); + var secs = Math.floor(runtime % 60); + var rText = mins > 0 ? mins + 'm' : secs + 's'; + parts.push(tag(rText, mins < 5 ? colors.warning : colors.textDim)); + } + + return parts.join(sep(colors)); + } + + // ─── StatusView Override ─────────────────────────────────────── + function applyOverride() { + if (typeof Ext === 'undefined' || !Ext.ClassManager) { + setTimeout(applyOverride, 500); + return; + } + + var cls = Ext.ClassManager.get('PVE.node.StatusView'); + if (!cls) { + setTimeout(applyOverride, 500); + return; + } + + var origInitComponent = cls.prototype.initComponent; + + cls.prototype.initComponent = function () { + // Single compact sensor row — CPU + Storage + Fan inline + var sensorItems = [ + { + itemId: 'sensors', + colspan: 2, + printBar: false, + title: gettext('Sensors'), + textField: 'sensorsOutput', + renderer: renderSensors + } + ]; + + // Inject after 'cpus' + if (Ext.isArray(this.items)) { + var insertIdx = -1; + for (var i = 0; i < this.items.length; i++) { + if (this.items[i].itemId === 'cpus') { + insertIdx = i + 1; + break; + } + } + + if (insertIdx >= 0) { + Ext.Array.insert(this.items, insertIdx, sensorItems); + } else { + this.items = this.items.concat(sensorItems); + } + } + + // Call original initComponent + if (origInitComponent) { + origInitComponent.apply(this, arguments); + } + + // After render: conditionally add UPS row if data exists, + // then trigger layout recalculation so the panel expands. + var me = this; + me.on('afterrender', function () { + var store = me.getStore ? me.getStore() : null; + if (!store) return; + + store.on('load', function (s, records) { + if (!records || !records.length) return; + + // Update sensor filter from API data + var filterRec = s.findRecord('key', 'sensorsFilter'); + activeSensorFilter = filterRec ? parseSensorFilter(filterRec.get('value')) : null; + + // Hide sensor row entirely when API doesn't include sensorsOutput + var sensorWidget = me.down('#sensors'); + if (sensorWidget) { + var sensorsRec = s.findRecord('key', 'sensorsOutput'); + var hasSensorData = sensorsRec !== null; + sensorWidget.setVisible(hasSensorData); + + // Force re-render with filter applied (our handler fires + // after StatusView's internal renderer, need to update) + if (hasSensorData && sensorWidget.setText) { + sensorWidget.setText(renderSensors(sensorsRec.get('value'))); + } + } + + // Check for UPS data in the store + var upsRec = s.findRecord('key', 'upsData'); + var upsData = upsRec ? upsRec.get('value') : null; + + // Only inject UPS item once, and only if there is data + if (upsData && upsData.trim() !== '' && !me.down('#upsStatus')) { + me.add({ + xtype: 'pmxInfoWidget', + itemId: 'upsStatus', + colspan: 2, + printBar: false, + title: gettext('UPS'), + iconCls: 'fa fa-fw fa-battery-half', + textField: 'upsData', + renderer: renderUps + }); + me.updateLayout(); + } + + // Recalculate layout to accommodate sensor row + Ext.defer(function () { + me.updateLayout(); + var parent = me.ownerCt; + if (parent && parent.updateLayout) { + parent.updateLayout(); + } + }, 100); + }); + }); + }; + + console.log('[ProxMorph] Sensor widget initialized (v1.1.0)'); + } + + // ─── Init ────────────────────────────────────────────────────── + function init() { + try { + applyOverride(); + window.ProxMorphSensors = { version: '1.1.0' }; + } catch (e) { + console.error('[ProxMorph Sensors] Init error:', e); + } + } + + if (document.readyState === 'complete' || document.readyState === 'interactive') { + init(); + } else { + window.addEventListener('DOMContentLoaded', init); + } + +})(); diff --git a/themes/patches/unifi-charts.js b/themes/patches/unifi-charts.js new file mode 100644 index 0000000..69c2f12 --- /dev/null +++ b/themes/patches/unifi-charts.js @@ -0,0 +1,139 @@ +/** + * ProxMorph Chart Patcher + * Applies custom colors to Proxmox RRD charts + * + * Features: + * - Custom UniFi color palette for chart lines/areas + * - Special handling for Network Traffic (blue/green layering) + * - Subtle white border on hover dots for visibility + * + * Color Palette: + * Primary: #30AD55 (UniFi green) + * Secondary: #006EFF (UniFi blue) + * Tertiary: #5DC0E0 (Cyan/teal) + * Warning: #D08D1E (Amber/orange) + * Critical: #CC3135 (Red) + */ + +(function () { + 'use strict'; + + const PROXMORPH_CHART_COLORS = [ + '#30AD55', // UniFi green (PRIMARY) + '#006EFF', // UniFi blue (SECONDARY) + '#5DC0E0', // UniFi cyan/teal + '#D08D1E', // UniFi amber/orange + '#CC3135', // UniFi red + '#4797FF', // UniFi light blue + ]; + + /** + * Apply custom colors to a single chart + */ + function patchChart(chart) { + if (!chart || !chart.getSeries) return; + + try { + const series = chart.getSeries(); + if (!series || series.length === 0) return; + + // Special handling for Network Traffic chart to avoid color blending + if (chart.title === 'Network Traffic') { + // Swap colors: Blue (bottom layer), Green (top layer) + chart.setColors(['#006EFF', '#30AD55']); + series.forEach((s, idx) => { + if (idx === 0) { + // Incoming - Blue area (bottom) + s.setStyle({ + fillStyle: 'rgba(0, 110, 255, 0.7)', + strokeStyle: '#006EFF', + lineWidth: 2 + }); + } else if (idx === 1) { + // Outgoing - Green area (top) + s.setStyle({ + fillStyle: 'rgba(48, 173, 85, 0.8)', + strokeStyle: '#30AD55', + lineWidth: 2 + }); + } + // Add subtle white border to hover dots + s.setHighlight({ + opacity: 1, + scaling: 1.5, + strokeStyle: '#FFFFFF', + lineWidth: 1 + }); + }); + } else { + // Standard color application for all other charts + chart.setColors(PROXMORPH_CHART_COLORS); + series.forEach((s, idx) => { + const color = PROXMORPH_CHART_COLORS[idx % PROXMORPH_CHART_COLORS.length]; + s.setStyle({ + fillStyle: color, + strokeStyle: color + }); + // Add subtle white border to hover dots + s.setHighlight({ + opacity: 1, + scaling: 1.5, + strokeStyle: '#FFFFFF', + lineWidth: 1 + }); + }); + } + + chart.redraw(); + } catch (e) { + console.warn('[ProxMorph] Chart patch error:', e); + } + } + + /** + * Check if UniFi theme is active + */ + function isUnifiThemeActive() { + // Check for the presence of the UniFi theme stylesheet + return !!document.querySelector('link[href*="theme-unifi.css"]'); + } + + /** + * Find and patch all RRD charts on the page + */ + function patchAllCharts() { + // Only patch if UniFi theme is active + if (!isUnifiThemeActive()) return; + + if (typeof Ext === 'undefined' || !Ext.ComponentQuery) return; + + const charts = Ext.ComponentQuery.query('proxmoxRRDChart'); + if (charts && charts.length > 0) { + charts.forEach(patchChart); + } + } + + /** + * Initialize the chart patcher with delayed start and periodic refresh + */ + function init() { + // Initial patch after page load + if (document.readyState === 'complete') { + setTimeout(patchAllCharts, 500); + } else { + window.addEventListener('load', function () { + setTimeout(patchAllCharts, 500); + }); + } + + // Periodic re-patch to catch dynamically loaded charts + // Charts can be reloaded when switching views or refreshing data + setInterval(patchAllCharts, 2000); + + console.log('[ProxMorph] Chart patcher initialized'); + } + + // Start initialization + init(); + +})(); diff --git a/themes/patches/unifi-light-charts.js b/themes/patches/unifi-light-charts.js new file mode 100644 index 0000000..045e832 --- /dev/null +++ b/themes/patches/unifi-light-charts.js @@ -0,0 +1,143 @@ +/** + * ProxMorph Chart Patcher (UniFi Light) + * Applies custom colors to Proxmox RRD charts for light theme + * + * Features: + * - Custom UniFi color palette for chart lines/areas + * - Special handling for Network Traffic (blue/green layering) + * - Dark border on hover dots for visibility on light backgrounds + * + * Color Palette (same as dark - UniFi uses identical colors): + * Primary: #3ACC65 (UniFi green) + * Secondary: #006FFF (UniFi blue) + * Tertiary: #5DC0E0 (Cyan/teal) + * Warning: #F6B94F (Amber/orange) + * Critical: #F36165 (Red) + */ + +(function () { + 'use strict'; + + const PROXMORPH_CHART_COLORS = [ + '#3ACC65', // UniFi green (PRIMARY) + '#006FFF', // UniFi blue (SECONDARY) + '#5DC0E0', // UniFi cyan/teal + '#F6B94F', // UniFi amber/orange + '#F36165', // UniFi red + '#4797FF', // UniFi light blue + ]; + + // Hover dot stroke color - dark for visibility on light backgrounds + const HOVER_STROKE_COLOR = '#1A1C21'; + + /** + * Apply custom colors to a single chart + */ + function patchChart(chart) { + if (!chart || !chart.getSeries) return; + + try { + const series = chart.getSeries(); + if (!series || series.length === 0) return; + + // Special handling for Network Traffic chart to avoid color blending + if (chart.title === 'Network Traffic') { + // Swap colors: Blue (bottom layer), Green (top layer) + chart.setColors(['#006FFF', '#3ACC65']); + series.forEach((s, idx) => { + if (idx === 0) { + // Incoming - Blue area (bottom) + // Slightly lower opacity for light backgrounds + s.setStyle({ + fillStyle: 'rgba(0, 111, 255, 0.4)', + strokeStyle: '#006FFF', + lineWidth: 2 + }); + } else if (idx === 1) { + // Outgoing - Green area (top) + s.setStyle({ + fillStyle: 'rgba(58, 204, 101, 0.5)', + strokeStyle: '#3ACC65', + lineWidth: 2 + }); + } + // Add dark border to hover dots for visibility on light background + s.setHighlight({ + opacity: 1, + scaling: 1.5, + strokeStyle: HOVER_STROKE_COLOR, + lineWidth: 1 + }); + }); + } else { + // Standard color application for all other charts + chart.setColors(PROXMORPH_CHART_COLORS); + series.forEach((s, idx) => { + const color = PROXMORPH_CHART_COLORS[idx % PROXMORPH_CHART_COLORS.length]; + s.setStyle({ + fillStyle: color, + strokeStyle: color + }); + // Add dark border to hover dots for visibility on light background + s.setHighlight({ + opacity: 1, + scaling: 1.5, + strokeStyle: HOVER_STROKE_COLOR, + lineWidth: 1 + }); + }); + } + + chart.redraw(); + } catch (e) { + console.warn('[ProxMorph] Chart patch error:', e); + } + } + + /** + * Check if UniFi Light theme is active + */ + function isUnifiLightThemeActive() { + // Check for the presence of the UniFi Light theme stylesheet + return !!document.querySelector('link[href*="theme-unifi-light.css"]'); + } + + /** + * Find and patch all RRD charts on the page + */ + function patchAllCharts() { + // Only patch if UniFi Light theme is active + if (!isUnifiLightThemeActive()) return; + + if (typeof Ext === 'undefined' || !Ext.ComponentQuery) return; + + const charts = Ext.ComponentQuery.query('proxmoxRRDChart'); + if (charts && charts.length > 0) { + charts.forEach(patchChart); + } + } + + /** + * Initialize the chart patcher with delayed start and periodic refresh + */ + function init() { + // Initial patch after page load + if (document.readyState === 'complete') { + setTimeout(patchAllCharts, 500); + } else { + window.addEventListener('load', function () { + setTimeout(patchAllCharts, 500); + }); + } + + // Periodic re-patch to catch dynamically loaded charts + // Charts can be reloaded when switching views or refreshing data + setInterval(patchAllCharts, 2000); + + console.log('[ProxMorph] UniFi Light chart patcher initialized'); + } + + // Start initialization + init(); + +})(); diff --git a/themes/pdm/.gitkeep b/themes/pdm/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/themes/pdm/proxmorph-pdm-base.css b/themes/pdm/proxmorph-pdm-base.css new file mode 100644 index 0000000..7c71d75 --- /dev/null +++ b/themes/pdm/proxmorph-pdm-base.css @@ -0,0 +1,215 @@ +/*!ProxMorph PDM Base*/ +/* + * ProxMorph PDM Base Styles + * Version: 1.0.0 + * + * Shared component-level styling applied whenever ANY ProxMorph PDM theme + * is active. Overrides the default PWt shape/corner/shadow tokens to + * give rounded corners, better elevation shadows, and polished component + * appearance. + * + * This file does NOT set colors — colors come from theme-specific CSS. + */ + +/* ===== Shape & Corner Overrides ===== */ +:root { + /* Global shape tokens — increase roundness */ + --pwt-shape-corner-none: 0px !important; + --pwt-shape-corner-extra-small: 4px !important; + --pwt-shape-corner-small: 8px !important; + --pwt-shape-corner-medium: 12px !important; + --pwt-shape-corner-large: 16px !important; + --pwt-shape-corner-extra-large: 24px !important; + + /* Component-specific corner shapes */ + --pwt-button-corner-shape: 8px !important; + --pwt-card-corner-shape: 12px !important; + --pwt-dialog-corner-shape: 12px !important; + --pwt-input-corner-shape: 8px !important; + --pwt-fab-corner-shape: 16px !important; + --pwt-progress-corner-shape: 8px !important; + --pwt-nav-link-corner-shape: 8px !important; + --pwt-nav-pills-corner-shape: 8px !important; + --pwt-tooltip-corner-shape: 8px !important; +} + +/* ===== Panel Styling ===== */ +.pwt-panel { + border-radius: 12px !important; + overflow: clip !important; /* clip (not hidden) preserves min-width:auto for correct flex wrapping */ +} + +.pwt-panel-header { + border-radius: 12px 12px 0 0 !important; +} + +/* ===== Shadow Enhancements ===== */ +.pwt-shadow2 { + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.25) !important; +} + +/* ===== Dialog Styling ===== */ +dialog, +.pwt-dialog:not(.pwt-dropdown) { + border-radius: 12px !important; + box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4) !important; + overflow: hidden !important; +} + +/* ===== Button Enhancements ===== */ +.pwt-button { + border-radius: 8px !important; + transition: background-color 0.15s ease, box-shadow 0.15s ease !important; +} + +.pwt-button:hover { + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2) !important; +} + +.pwt-button.rounded, +.pwt-button.circle { + border-radius: 10rem !important; +} + +/* Segmented buttons: rounded ends only */ +.pwt-segmented-button { + border-radius: 8px !important; + overflow: hidden !important; +} + +.pwt-segmented-button > .pwt-button { + border-radius: 0px !important; +} + +.pwt-segmented-button > .pwt-button:first-child { + border-radius: 8px 0 0 8px !important; +} + +.pwt-segmented-button > .pwt-button:last-child { + border-radius: 0 8px 8px 0 !important; +} + +/* FAB */ +.pwt-fab { + border-radius: 16px !important; + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3) !important; +} + +/* ===== Input / Form Enhancements ===== */ +.pwt-input { + border-radius: 8px !important; + transition: border-color 0.15s ease, box-shadow 0.15s ease !important; +} + +.pwt-input:focus-within { + box-shadow: 0 0 0 2px rgba(var(--pwt-color-primary-80), 0.3) !important; +} + +.pwt-textarea { + border-radius: 8px !important; +} + +.pwt-input-display { + border-radius: 8px !important; +} + +/* ===== Card Styling ===== */ +.pwt-card { + border-radius: 12px !important; + overflow: hidden !important; +} + +/* ===== Navigation ===== */ +.pwt-nav-link { + border-radius: 8px !important; + transition: background-color 0.15s ease !important; +} + +.pwt-nav-menu { + border-radius: 8px !important; +} + +/* ===== Datatable Enhancements ===== */ +.pwt-datatable { + border-radius: 8px !important; + overflow: hidden !important; +} + +.pwt-datatable-header { + border-radius: 8px 8px 0 0 !important; +} + +/* ===== Menu / Dropdown ===== */ +.pwt-submenu { + border-radius: 8px !important; + box-shadow: 0 4px 16px rgba(0, 0, 0, 0.3) !important; + overflow: hidden !important; +} + +.pwt-dropdown { + border-radius: 8px !important; + box-shadow: 0 4px 16px rgba(0, 0, 0, 0.3) !important; + overflow: hidden !important; +} + +/* ===== List / List Tile ===== */ +.pwt-list { + border-radius: 8px !important; +} + +.pwt-list-tile { + border-radius: 8px !important; +} + +/* ===== Meter / Progress ===== */ +.pwt-meter { + border-radius: 8px !important; +} + +/* ===== Switch ===== */ +.pwt-switch { + border-radius: 14px !important; +} + +/* ===== Tooltips ===== */ +[class*="pwt-tooltip"] { + border-radius: 8px !important; +} + +/* ===== Scrollbar Styling ===== */ +::-webkit-scrollbar { + width: 8px !important; + height: 8px !important; +} + +::-webkit-scrollbar-track { + background: transparent !important; +} + +::-webkit-scrollbar-thumb { + border-radius: 4px !important; + background: rgba(128, 128, 128, 0.4) !important; +} + +::-webkit-scrollbar-thumb:hover { + background: rgba(128, 128, 128, 0.6) !important; +} + +/* ===== Logo tinting (dark themes) ===== */ +.pwt-dark-mode img[src*="proxmox_logo"] { + filter: brightness(0.9) !important; +} + +/* ===== Smooth transitions for theme switching ===== */ +*, +*::before, +*::after { + transition-property: background-color, border-color, color, fill, stroke, box-shadow !important; + transition-duration: 0.15s !important; + transition-timing-function: ease !important; +} + +/* Restore tab indicator slide animation (needs left/width/inset transitions) */ +.pwt-tab-active-indicator { + transition: all 0.2s ease !important; +} diff --git a/themes/pdm/theme-blue-slate.css b/themes/pdm/theme-blue-slate.css new file mode 100644 index 0000000..8a98c93 --- /dev/null +++ b/themes/pdm/theme-blue-slate.css @@ -0,0 +1,180 @@ +/*!Blue Slate*/ +/* + * ProxMorph PDM Theme: Blue Slate + * Overrides the PWT Material Design tonal color system with Blue Slate palette + * Version: 1.0.0 + * + * ─── Blue Slate Palette ──────────────────────────────────────── + * Accent: #5294e2 Text: #d3dae3 + * Base: #2b2e37 Surface: #383c4a + * Elevated: #404552 + */ + +:root { + /* Primary — Blue Slate (#5294e2) tonal scale */ + --pwt-color-primary-100: rgb(255, 255, 255) !important; + --pwt-color-primary-99: rgb(248, 252, 255) !important; + --pwt-color-primary-95: rgb(222, 240, 255) !important; + --pwt-color-primary-90: rgb(195, 225, 252) !important; + --pwt-color-primary-80: rgb(140, 192, 238) !important; + --pwt-color-primary-70: rgb(82, 148, 226) !important; + --pwt-color-primary-60: rgb(60, 125, 205) !important; + --pwt-color-primary-50: rgb(42, 105, 182) !important; + --pwt-color-primary-40: rgb(28, 85, 158) !important; + --pwt-color-primary-30: rgb(16, 68, 132) !important; + --pwt-color-primary-20: rgb(6, 50, 105) !important; + --pwt-color-primary-15: rgb(2, 40, 85) !important; + --pwt-color-primary-10: rgb(0, 28, 65) !important; + --pwt-color-primary-5: rgb(0, 16, 42) !important; + --pwt-color-primary-0: rgb(0, 0, 0) !important; + + /* Secondary — Slate (#7c818c) tonal scale */ + --pwt-color-secondary-100: rgb(255, 255, 255) !important; + --pwt-color-secondary-99: rgb(248, 250, 252) !important; + --pwt-color-secondary-95: rgb(228, 232, 238) !important; + --pwt-color-secondary-90: rgb(211, 218, 227) !important; + --pwt-color-secondary-80: rgb(178, 186, 198) !important; + --pwt-color-secondary-70: rgb(148, 155, 168) !important; + --pwt-color-secondary-60: rgb(124, 129, 140) !important; + --pwt-color-secondary-50: rgb(100, 105, 118) !important; + --pwt-color-secondary-40: rgb(78, 82, 95) !important; + --pwt-color-secondary-30: rgb(56, 60, 74) !important; + --pwt-color-secondary-20: rgb(43, 46, 55) !important; + --pwt-color-secondary-15: rgb(36, 38, 48) !important; + --pwt-color-secondary-10: rgb(28, 30, 38) !important; + --pwt-color-secondary-5: rgb(18, 18, 25) !important; + --pwt-color-secondary-0: rgb(0, 0, 0) !important; + + /* Tertiary — Muted Purple (#8c7ec8) tonal scale */ + --pwt-color-tertiary-100: rgb(255, 255, 255) !important; + --pwt-color-tertiary-99: rgb(252, 250, 255) !important; + --pwt-color-tertiary-95: rgb(235, 228, 255) !important; + --pwt-color-tertiary-90: rgb(218, 208, 248) !important; + --pwt-color-tertiary-80: rgb(178, 165, 228) !important; + --pwt-color-tertiary-70: rgb(140, 126, 200) !important; + --pwt-color-tertiary-60: rgb(115, 102, 178) !important; + --pwt-color-tertiary-50: rgb(92, 80, 155) !important; + --pwt-color-tertiary-40: rgb(72, 60, 132) !important; + --pwt-color-tertiary-30: rgb(52, 42, 108) !important; + --pwt-color-tertiary-20: rgb(36, 28, 85) !important; + --pwt-color-tertiary-15: rgb(28, 20, 70) !important; + --pwt-color-tertiary-10: rgb(20, 12, 55) !important; + --pwt-color-tertiary-5: rgb(12, 5, 35) !important; + --pwt-color-tertiary-0: rgb(0, 0, 0) !important; + + /* Success */ + --pwt-color-success-100: rgb(255, 255, 255) !important; + --pwt-color-success-99: rgb(242, 255, 245) !important; + --pwt-color-success-95: rgb(200, 255, 212) !important; + --pwt-color-success-90: rgb(148, 248, 172) !important; + --pwt-color-success-80: rgb(88, 225, 120) !important; + --pwt-color-success-70: rgb(50, 195, 85) !important; + --pwt-color-success-60: rgb(32, 168, 65) !important; + --pwt-color-success-50: rgb(18, 140, 48) !important; + --pwt-color-success-40: rgb(6, 115, 35) !important; + --pwt-color-success-30: rgb(0, 90, 22) !important; + --pwt-color-success-20: rgb(0, 66, 14) !important; + --pwt-color-success-15: rgb(0, 50, 8) !important; + --pwt-color-success-10: rgb(0, 36, 4) !important; + --pwt-color-success-5: rgb(0, 22, 0) !important; + --pwt-color-success-0: rgb(0, 0, 0) !important; + + /* Error */ + --pwt-color-error-100: rgb(255, 255, 255) !important; + --pwt-color-error-99: rgb(255, 248, 248) !important; + --pwt-color-error-95: rgb(255, 228, 228) !important; + --pwt-color-error-90: rgb(255, 200, 200) !important; + --pwt-color-error-80: rgb(255, 148, 148) !important; + --pwt-color-error-70: rgb(248, 98, 98) !important; + --pwt-color-error-60: rgb(225, 65, 65) !important; + --pwt-color-error-50: rgb(198, 42, 42) !important; + --pwt-color-error-40: rgb(168, 22, 22) !important; + --pwt-color-error-30: rgb(138, 8, 8) !important; + --pwt-color-error-20: rgb(105, 2, 2) !important; + --pwt-color-error-15: rgb(82, 0, 0) !important; + --pwt-color-error-10: rgb(62, 0, 0) !important; + --pwt-color-error-5: rgb(40, 0, 0) !important; + --pwt-color-error-0: rgb(0, 0, 0) !important; + + /* Warning */ + --pwt-color-warning-100: rgb(255, 255, 255) !important; + --pwt-color-warning-99: rgb(255, 252, 245) !important; + --pwt-color-warning-95: rgb(255, 242, 205) !important; + --pwt-color-warning-90: rgb(255, 228, 160) !important; + --pwt-color-warning-80: rgb(248, 205, 100) !important; + --pwt-color-warning-70: rgb(235, 175, 45) !important; + --pwt-color-warning-60: rgb(210, 152, 25) !important; + --pwt-color-warning-50: rgb(182, 128, 10) !important; + --pwt-color-warning-40: rgb(155, 105, 0) !important; + --pwt-color-warning-30: rgb(125, 82, 0) !important; + --pwt-color-warning-20: rgb(95, 60, 0) !important; + --pwt-color-warning-15: rgb(72, 45, 0) !important; + --pwt-color-warning-10: rgb(52, 32, 0) !important; + --pwt-color-warning-5: rgb(32, 18, 0) !important; + --pwt-color-warning-0: rgb(0, 0, 0) !important; + + /* Neutral — Blue Slate scale */ + --pwt-color-neutral-100: rgb(211, 218, 227) !important; + --pwt-color-neutral-99: rgb(205, 212, 222) !important; + --pwt-color-neutral-95: rgb(188, 196, 208) !important; + --pwt-color-neutral-90: rgb(168, 176, 190) !important; + --pwt-color-neutral-80: rgb(145, 152, 168) !important; + --pwt-color-neutral-70: rgb(124, 129, 140) !important; + --pwt-color-neutral-60: rgb(100, 105, 118) !important; + --pwt-color-neutral-50: rgb(78, 82, 95) !important; + --pwt-color-neutral-40: rgb(64, 69, 82) !important; + --pwt-color-neutral-30: rgb(56, 60, 74) !important; + --pwt-color-neutral-20: rgb(43, 46, 55) !important; + --pwt-color-neutral-15: rgb(36, 38, 48) !important; + --pwt-color-neutral-10: rgb(28, 30, 38) !important; + --pwt-color-neutral-5: rgb(18, 18, 25) !important; + --pwt-color-neutral-0: rgb(0, 0, 0) !important; + + /* Neutral Alt */ + --pwt-color-neutral-alt-100: rgb(211, 218, 227) !important; + --pwt-color-neutral-alt-99: rgb(208, 215, 225) !important; + --pwt-color-neutral-alt-95: rgb(192, 200, 212) !important; + --pwt-color-neutral-alt-90: rgb(172, 180, 195) !important; + --pwt-color-neutral-alt-80: rgb(148, 155, 172) !important; + --pwt-color-neutral-alt-70: rgb(126, 132, 148) !important; + --pwt-color-neutral-alt-60: rgb(105, 110, 125) !important; + --pwt-color-neutral-alt-50: rgb(82, 88, 102) !important; + --pwt-color-neutral-alt-40: rgb(65, 70, 85) !important; + --pwt-color-neutral-alt-30: rgb(50, 55, 68) !important; + --pwt-color-neutral-alt-20: rgb(38, 42, 52) !important; + --pwt-color-neutral-alt-15: rgb(30, 34, 44) !important; + --pwt-color-neutral-alt-10: rgb(22, 25, 34) !important; + --pwt-color-neutral-alt-5: rgb(14, 15, 22) !important; + --pwt-color-neutral-alt-0: rgb(0, 0, 0) !important; +} + +/* ===== Semantic Color Remapping (darker surfaces) ===== */ +:root.pwt-dark-mode { + --pwt-color-surface: var(--pwt-color-neutral-10) !important; + --pwt-color-on-surface: var(--pwt-color-neutral-95) !important; + --pwt-color-surface-container: var(--pwt-color-neutral-15) !important; + --pwt-color-on-surface-container: var(--pwt-color-neutral-95) !important; + --pwt-color-neutral: var(--pwt-color-neutral-15) !important; + --pwt-color-on-neutral: var(--pwt-color-neutral-95) !important; + --pwt-color-neutral-container: var(--pwt-color-neutral-10) !important; + --pwt-color-on-neutral-container: var(--pwt-color-neutral-95) !important; + --pwt-color-dark-surface: var(--pwt-color-neutral-10) !important; + --pwt-color-on-dark-surface: var(--pwt-color-neutral-95) !important; + --pwt-color-dark-surface-container: var(--pwt-color-neutral-15) !important; + --pwt-color-on-dark-surface-container: var(--pwt-color-neutral-95) !important; + --pwt-color-neutral-alt: var(--pwt-color-neutral-alt-15) !important; + --pwt-color-on-neutral-alt: var(--pwt-color-neutral-alt-80) !important; + --pwt-color-neutral-alt-container: var(--pwt-color-neutral-alt-10) !important; + --pwt-color-on-neutral-alt-container: var(--pwt-color-neutral-alt-80) !important; + --pwt-color-background: var(--pwt-color-neutral-10) !important; + --pwt-color-inverse-surface: var(--pwt-color-neutral-80) !important; + --pwt-color-on-inverse-surface: var(--pwt-color-neutral-10) !important; + --pwt-color-border: var(--pwt-color-neutral-alt-30) !important; + --pwt-color-shadow: var(--pwt-color-neutral-0) !important; + background: var(--pwt-color-neutral-10) !important; + color: var(--pwt-color-neutral-95) !important; +} + +body { + background-color: var(--pwt-color-neutral-10) !important; +} \ No newline at end of file diff --git a/themes/pdm/theme-catppuccin-frappe.css b/themes/pdm/theme-catppuccin-frappe.css new file mode 100644 index 0000000..3e65e4e --- /dev/null +++ b/themes/pdm/theme-catppuccin-frappe.css @@ -0,0 +1,180 @@ +/*!Catppuccin Frappé*/ +/* + * ProxMorph PDM Theme: Catppuccin Frappé + * Overrides the PWT Material Design tonal color system with Catppuccin Frappé palette + * Version: 1.0.0 + * Author: ProxMorph / Catppuccin Community Palette + * + * ─── Catppuccin Frappé Palette ──────────────────────────────── + * Mauve (accent): #ca9ee6 Blue: #8caaee + * Green: #a6d189 Red: #e78284 + * Yellow: #e5c890 Pink: #f4b8e4 + * Text: #c6d0f5 Base: #303446 + * Surface0: #414559 Mantle: #292c3c + * Crust: #232634 + */ + +/* ===== Tonal Color Overrides ===== */ +:root { + /* Primary — Catppuccin Frappé Mauve (#ca9ee6) tonal scale */ + --pwt-color-primary-100: rgb(255, 255, 255) !important; + --pwt-color-primary-99: rgb(252, 248, 255) !important; + --pwt-color-primary-95: rgb(240, 230, 252) !important; + --pwt-color-primary-90: rgb(228, 210, 248) !important; + --pwt-color-primary-80: rgb(202, 158, 230) !important; + --pwt-color-primary-70: rgb(178, 135, 208) !important; + --pwt-color-primary-60: rgb(152, 112, 185) !important; + --pwt-color-primary-50: rgb(128, 90, 162) !important; + --pwt-color-primary-40: rgb(105, 68, 138) !important; + --pwt-color-primary-30: rgb(82, 48, 115) !important; + --pwt-color-primary-20: rgb(60, 30, 92) !important; + --pwt-color-primary-15: rgb(48, 20, 76) !important; + --pwt-color-primary-10: rgb(36, 12, 60) !important; + --pwt-color-primary-5: rgb(22, 5, 42) !important; + --pwt-color-primary-0: rgb(0, 0, 0) !important; + + /* Secondary — Catppuccin Frappé Blue (#8caaee) tonal scale */ + --pwt-color-secondary-100: rgb(255, 255, 255) !important; + --pwt-color-secondary-99: rgb(248, 250, 255) !important; + --pwt-color-secondary-95: rgb(222, 235, 255) !important; + --pwt-color-secondary-90: rgb(198, 218, 252) !important; + --pwt-color-secondary-80: rgb(155, 188, 240) !important; + --pwt-color-secondary-70: rgb(140, 170, 238) !important; + --pwt-color-secondary-60: rgb(112, 145, 212) !important; + --pwt-color-secondary-50: rgb(88, 120, 188) !important; + --pwt-color-secondary-40: rgb(66, 98, 162) !important; + --pwt-color-secondary-30: rgb(46, 76, 135) !important; + --pwt-color-secondary-20: rgb(28, 55, 108) !important; + --pwt-color-secondary-15: rgb(20, 42, 88) !important; + --pwt-color-secondary-10: rgb(12, 30, 68) !important; + --pwt-color-secondary-5: rgb(5, 16, 45) !important; + --pwt-color-secondary-0: rgb(0, 0, 0) !important; + + /* Tertiary — Catppuccin Frappé Pink (#f4b8e4) tonal scale */ + --pwt-color-tertiary-100: rgb(255, 255, 255) !important; + --pwt-color-tertiary-99: rgb(255, 250, 253) !important; + --pwt-color-tertiary-95: rgb(255, 236, 248) !important; + --pwt-color-tertiary-90: rgb(252, 218, 240) !important; + --pwt-color-tertiary-80: rgb(244, 184, 228) !important; + --pwt-color-tertiary-70: rgb(222, 158, 205) !important; + --pwt-color-tertiary-60: rgb(198, 132, 182) !important; + --pwt-color-tertiary-50: rgb(172, 108, 158) !important; + --pwt-color-tertiary-40: rgb(148, 85, 135) !important; + --pwt-color-tertiary-30: rgb(122, 62, 110) !important; + --pwt-color-tertiary-20: rgb(96, 40, 86) !important; + --pwt-color-tertiary-15: rgb(78, 28, 70) !important; + --pwt-color-tertiary-10: rgb(60, 16, 54) !important; + --pwt-color-tertiary-5: rgb(40, 6, 35) !important; + --pwt-color-tertiary-0: rgb(0, 0, 0) !important; + + /* Success — Catppuccin Frappé Green (#a6d189) tonal scale */ + --pwt-color-success-100: rgb(255, 255, 255) !important; + --pwt-color-success-99: rgb(248, 255, 245) !important; + --pwt-color-success-95: rgb(220, 252, 210) !important; + --pwt-color-success-90: rgb(192, 240, 178) !important; + --pwt-color-success-80: rgb(166, 209, 137) !important; + --pwt-color-success-70: rgb(142, 185, 115) !important; + --pwt-color-success-60: rgb(118, 162, 92) !important; + --pwt-color-success-50: rgb(95, 138, 72) !important; + --pwt-color-success-40: rgb(72, 115, 52) !important; + --pwt-color-success-30: rgb(52, 92, 35) !important; + --pwt-color-success-20: rgb(34, 70, 20) !important; + --pwt-color-success-15: rgb(24, 55, 12) !important; + --pwt-color-success-10: rgb(15, 42, 5) !important; + --pwt-color-success-5: rgb(6, 26, 0) !important; + --pwt-color-success-0: rgb(0, 0, 0) !important; + + /* Error — Catppuccin Frappé Red (#e78284) tonal scale */ + --pwt-color-error-100: rgb(255, 255, 255) !important; + --pwt-color-error-99: rgb(255, 248, 248) !important; + --pwt-color-error-95: rgb(255, 228, 228) !important; + --pwt-color-error-90: rgb(252, 205, 206) !important; + --pwt-color-error-80: rgb(242, 168, 170) !important; + --pwt-color-error-70: rgb(231, 130, 132) !important; + --pwt-color-error-60: rgb(208, 105, 108) !important; + --pwt-color-error-50: rgb(185, 82, 85) !important; + --pwt-color-error-40: rgb(160, 58, 62) !important; + --pwt-color-error-30: rgb(132, 38, 42) !important; + --pwt-color-error-20: rgb(105, 18, 22) !important; + --pwt-color-error-15: rgb(85, 8, 14) !important; + --pwt-color-error-10: rgb(65, 0, 6) !important; + --pwt-color-error-5: rgb(42, 0, 2) !important; + --pwt-color-error-0: rgb(0, 0, 0) !important; + + /* Warning — Catppuccin Frappé Yellow (#e5c890) tonal scale */ + --pwt-color-warning-100: rgb(255, 255, 255) !important; + --pwt-color-warning-99: rgb(255, 252, 246) !important; + --pwt-color-warning-95: rgb(252, 242, 218) !important; + --pwt-color-warning-90: rgb(245, 232, 192) !important; + --pwt-color-warning-80: rgb(229, 200, 144) !important; + --pwt-color-warning-70: rgb(210, 180, 120) !important; + --pwt-color-warning-60: rgb(188, 158, 98) !important; + --pwt-color-warning-50: rgb(165, 135, 76) !important; + --pwt-color-warning-40: rgb(140, 112, 55) !important; + --pwt-color-warning-30: rgb(115, 90, 36) !important; + --pwt-color-warning-20: rgb(88, 68, 18) !important; + --pwt-color-warning-15: rgb(70, 54, 8) !important; + --pwt-color-warning-10: rgb(52, 40, 2) !important; + --pwt-color-warning-5: rgb(32, 24, 0) !important; + --pwt-color-warning-0: rgb(0, 0, 0) !important; + + /* Neutral — Catppuccin Frappé Background scale (base #303446) */ + --pwt-color-neutral-100: rgb(198, 208, 245) !important; + --pwt-color-neutral-99: rgb(192, 202, 238) !important; + --pwt-color-neutral-95: rgb(180, 190, 222) !important; + --pwt-color-neutral-90: rgb(162, 172, 202) !important; + --pwt-color-neutral-80: rgb(140, 148, 178) !important; + --pwt-color-neutral-70: rgb(118, 126, 155) !important; + --pwt-color-neutral-60: rgb(98, 105, 132) !important; + --pwt-color-neutral-50: rgb(80, 86, 110) !important; + --pwt-color-neutral-40: rgb(65, 69, 89) !important; + --pwt-color-neutral-30: rgb(48, 52, 70) !important; + --pwt-color-neutral-20: rgb(35, 38, 52) !important; + --pwt-color-neutral-15: rgb(30, 32, 44) !important; + --pwt-color-neutral-10: rgb(24, 26, 36) !important; + --pwt-color-neutral-5: rgb(16, 17, 25) !important; + --pwt-color-neutral-0: rgb(0, 0, 0) !important; + + /* Neutral Alt — Catppuccin Frappé Overlay tones */ + --pwt-color-neutral-alt-100: rgb(198, 208, 245) !important; + --pwt-color-neutral-alt-99: rgb(192, 202, 240) !important; + --pwt-color-neutral-alt-95: rgb(182, 192, 225) !important; + --pwt-color-neutral-alt-90: rgb(164, 174, 208) !important; + --pwt-color-neutral-alt-80: rgb(142, 150, 182) !important; + --pwt-color-neutral-alt-70: rgb(120, 128, 158) !important; + --pwt-color-neutral-alt-60: rgb(100, 108, 135) !important; + --pwt-color-neutral-alt-50: rgb(82, 88, 112) !important; + --pwt-color-neutral-alt-40: rgb(66, 72, 92) !important; + --pwt-color-neutral-alt-30: rgb(50, 55, 74) !important; + --pwt-color-neutral-alt-20: rgb(36, 40, 55) !important; + --pwt-color-neutral-alt-15: rgb(30, 34, 46) !important; + --pwt-color-neutral-alt-10: rgb(24, 27, 38) !important; + --pwt-color-neutral-alt-5: rgb(16, 18, 26) !important; + --pwt-color-neutral-alt-0: rgb(0, 0, 0) !important; +} + --pwt-color-surface-container: var(--pwt-color-neutral-15) !important; + --pwt-color-on-surface-container: var(--pwt-color-neutral-95) !important; + --pwt-color-neutral: var(--pwt-color-neutral-15) !important; + --pwt-color-on-neutral: var(--pwt-color-neutral-95) !important; + --pwt-color-neutral-container: var(--pwt-color-neutral-10) !important; + --pwt-color-on-neutral-container: var(--pwt-color-neutral-95) !important; + --pwt-color-dark-surface: var(--pwt-color-neutral-10) !important; + --pwt-color-on-dark-surface: var(--pwt-color-neutral-95) !important; + --pwt-color-dark-surface-container: var(--pwt-color-neutral-15) !important; + --pwt-color-on-dark-surface-container: var(--pwt-color-neutral-95) !important; + --pwt-color-neutral-alt: var(--pwt-color-neutral-alt-15) !important; + --pwt-color-on-neutral-alt: var(--pwt-color-neutral-alt-80) !important; + --pwt-color-neutral-alt-container: var(--pwt-color-neutral-alt-10) !important; + --pwt-color-on-neutral-alt-container: var(--pwt-color-neutral-alt-80) !important; + --pwt-color-background: var(--pwt-color-neutral-10) !important; + --pwt-color-inverse-surface: var(--pwt-color-neutral-80) !important; + --pwt-color-on-inverse-surface: var(--pwt-color-neutral-10) !important; + --pwt-color-border: var(--pwt-color-neutral-alt-30) !important; + --pwt-color-shadow: var(--pwt-color-neutral-0) !important; + background: var(--pwt-color-neutral-10) !important; + color: var(--pwt-color-neutral-95) !important; +} + +body { + background-color: var(--pwt-color-neutral-10) !important; +} diff --git a/themes/pdm/theme-catppuccin-latte.css b/themes/pdm/theme-catppuccin-latte.css new file mode 100644 index 0000000..5fbe1a7 --- /dev/null +++ b/themes/pdm/theme-catppuccin-latte.css @@ -0,0 +1,195 @@ +/*!Catppuccin Latte*/ +/* + * ProxMorph PDM Theme: Catppuccin Latte (Light) + * Overrides the PWT Material Design tonal color system with Catppuccin Latte palette + * Version: 1.0.0 + * Author: ProxMorph / Catppuccin Community Palette + * + * ─── Catppuccin Latte Palette (Light) ───────────────────────── + * Mauve (accent): #8839ef Blue: #1e66f5 + * Green: #40a02b Red: #d20f39 + * Yellow: #df8e1d Pink: #ea76cb + * Text: #4c4f69 Base: #eff1f5 + * Surface0: #ccd0da Mantle: #e6e9ef + * Crust: #dce0e8 + */ + +/* ===== Tonal Color Overrides ===== */ +:root { + /* Primary — Catppuccin Latte Mauve (#8839ef) tonal scale */ + --pwt-color-primary-100: rgb(255, 255, 255) !important; + --pwt-color-primary-99: rgb(252, 248, 255) !important; + --pwt-color-primary-95: rgb(240, 228, 255) !important; + --pwt-color-primary-90: rgb(225, 205, 255) !important; + --pwt-color-primary-80: rgb(195, 162, 248) !important; + --pwt-color-primary-70: rgb(165, 120, 240) !important; + --pwt-color-primary-60: rgb(136, 57, 239) !important; + --pwt-color-primary-50: rgb(115, 38, 210) !important; + --pwt-color-primary-40: rgb(95, 25, 185) !important; + --pwt-color-primary-30: rgb(75, 15, 155) !important; + --pwt-color-primary-20: rgb(56, 8, 125) !important; + --pwt-color-primary-15: rgb(44, 4, 102) !important; + --pwt-color-primary-10: rgb(32, 0, 80) !important; + --pwt-color-primary-5: rgb(18, 0, 52) !important; + --pwt-color-primary-0: rgb(0, 0, 0) !important; + + /* Secondary — Catppuccin Latte Blue (#1e66f5) tonal scale */ + --pwt-color-secondary-100: rgb(255, 255, 255) !important; + --pwt-color-secondary-99: rgb(248, 250, 255) !important; + --pwt-color-secondary-95: rgb(218, 232, 255) !important; + --pwt-color-secondary-90: rgb(185, 210, 255) !important; + --pwt-color-secondary-80: rgb(130, 175, 252) !important; + --pwt-color-secondary-70: rgb(75, 138, 248) !important; + --pwt-color-secondary-60: rgb(30, 102, 245) !important; + --pwt-color-secondary-50: rgb(18, 82, 218) !important; + --pwt-color-secondary-40: rgb(10, 64, 188) !important; + --pwt-color-secondary-30: rgb(4, 48, 155) !important; + --pwt-color-secondary-20: rgb(0, 34, 122) !important; + --pwt-color-secondary-15: rgb(0, 26, 100) !important; + --pwt-color-secondary-10: rgb(0, 18, 78) !important; + --pwt-color-secondary-5: rgb(0, 10, 50) !important; + --pwt-color-secondary-0: rgb(0, 0, 0) !important; + + /* Tertiary — Catppuccin Latte Pink (#ea76cb) tonal scale */ + --pwt-color-tertiary-100: rgb(255, 255, 255) !important; + --pwt-color-tertiary-99: rgb(255, 248, 253) !important; + --pwt-color-tertiary-95: rgb(255, 228, 245) !important; + --pwt-color-tertiary-90: rgb(252, 200, 235) !important; + --pwt-color-tertiary-80: rgb(245, 155, 215) !important; + --pwt-color-tertiary-70: rgb(240, 118, 203) !important; + --pwt-color-tertiary-60: rgb(215, 88, 178) !important; + --pwt-color-tertiary-50: rgb(188, 62, 152) !important; + --pwt-color-tertiary-40: rgb(160, 40, 128) !important; + --pwt-color-tertiary-30: rgb(132, 22, 105) !important; + --pwt-color-tertiary-20: rgb(102, 8, 80) !important; + --pwt-color-tertiary-15: rgb(82, 2, 65) !important; + --pwt-color-tertiary-10: rgb(62, 0, 48) !important; + --pwt-color-tertiary-5: rgb(40, 0, 30) !important; + --pwt-color-tertiary-0: rgb(0, 0, 0) !important; + + /* Success — Catppuccin Latte Green (#40a02b) tonal scale */ + --pwt-color-success-100: rgb(255, 255, 255) !important; + --pwt-color-success-99: rgb(248, 255, 246) !important; + --pwt-color-success-95: rgb(218, 252, 208) !important; + --pwt-color-success-90: rgb(180, 242, 168) !important; + --pwt-color-success-80: rgb(120, 215, 105) !important; + --pwt-color-success-70: rgb(80, 185, 65) !important; + --pwt-color-success-60: rgb(64, 160, 43) !important; + --pwt-color-success-50: rgb(48, 138, 28) !important; + --pwt-color-success-40: rgb(35, 115, 16) !important; + --pwt-color-success-30: rgb(24, 92, 8) !important; + --pwt-color-success-20: rgb(14, 70, 2) !important; + --pwt-color-success-15: rgb(8, 55, 0) !important; + --pwt-color-success-10: rgb(4, 40, 0) !important; + --pwt-color-success-5: rgb(0, 25, 0) !important; + --pwt-color-success-0: rgb(0, 0, 0) !important; + + /* Error — Catppuccin Latte Red (#d20f39) tonal scale */ + --pwt-color-error-100: rgb(255, 255, 255) !important; + --pwt-color-error-99: rgb(255, 248, 248) !important; + --pwt-color-error-95: rgb(255, 222, 226) !important; + --pwt-color-error-90: rgb(255, 190, 198) !important; + --pwt-color-error-80: rgb(242, 135, 148) !important; + --pwt-color-error-70: rgb(228, 75, 98) !important; + --pwt-color-error-60: rgb(210, 15, 57) !important; + --pwt-color-error-50: rgb(185, 8, 45) !important; + --pwt-color-error-40: rgb(158, 2, 34) !important; + --pwt-color-error-30: rgb(130, 0, 25) !important; + --pwt-color-error-20: rgb(100, 0, 16) !important; + --pwt-color-error-15: rgb(80, 0, 10) !important; + --pwt-color-error-10: rgb(60, 0, 5) !important; + --pwt-color-error-5: rgb(38, 0, 2) !important; + --pwt-color-error-0: rgb(0, 0, 0) !important; + + /* Warning — Catppuccin Latte Yellow (#df8e1d) tonal scale */ + --pwt-color-warning-100: rgb(255, 255, 255) !important; + --pwt-color-warning-99: rgb(255, 252, 246) !important; + --pwt-color-warning-95: rgb(255, 240, 210) !important; + --pwt-color-warning-90: rgb(252, 225, 170) !important; + --pwt-color-warning-80: rgb(242, 190, 105) !important; + --pwt-color-warning-70: rgb(230, 158, 52) !important; + --pwt-color-warning-60: rgb(223, 142, 29) !important; + --pwt-color-warning-50: rgb(195, 120, 15) !important; + --pwt-color-warning-40: rgb(165, 98, 6) !important; + --pwt-color-warning-30: rgb(135, 78, 0) !important; + --pwt-color-warning-20: rgb(105, 58, 0) !important; + --pwt-color-warning-15: rgb(85, 45, 0) !important; + --pwt-color-warning-10: rgb(62, 32, 0) !important; + --pwt-color-warning-5: rgb(38, 18, 0) !important; + --pwt-color-warning-0: rgb(0, 0, 0) !important; + + /* Neutral — Catppuccin Latte Background scale (base #eff1f5) */ + --pwt-color-neutral-100: rgb(255, 255, 255) !important; + --pwt-color-neutral-99: rgb(250, 251, 254) !important; + --pwt-color-neutral-95: rgb(239, 241, 245) !important; + --pwt-color-neutral-90: rgb(230, 233, 239) !important; + --pwt-color-neutral-80: rgb(220, 224, 232) !important; + --pwt-color-neutral-70: rgb(204, 208, 218) !important; + --pwt-color-neutral-60: rgb(172, 176, 190) !important; + --pwt-color-neutral-50: rgb(140, 143, 161) !important; + --pwt-color-neutral-40: rgb(108, 111, 133) !important; + --pwt-color-neutral-30: rgb(92, 95, 119) !important; + --pwt-color-neutral-20: rgb(76, 79, 105) !important; + --pwt-color-neutral-15: rgb(64, 66, 88) !important; + --pwt-color-neutral-10: rgb(50, 52, 72) !important; + --pwt-color-neutral-5: rgb(35, 36, 52) !important; + --pwt-color-neutral-0: rgb(0, 0, 0) !important; + + /* Neutral Alt — Catppuccin Latte Overlay tones */ + --pwt-color-neutral-alt-100: rgb(255, 255, 255) !important; + --pwt-color-neutral-alt-99: rgb(250, 251, 254) !important; + --pwt-color-neutral-alt-95: rgb(242, 244, 248) !important; + --pwt-color-neutral-alt-90: rgb(232, 235, 242) !important; + --pwt-color-neutral-alt-80: rgb(215, 218, 228) !important; + --pwt-color-neutral-alt-70: rgb(188, 192, 204) !important; + --pwt-color-neutral-alt-60: rgb(156, 160, 176) !important; + --pwt-color-neutral-alt-50: rgb(124, 128, 148) !important; + --pwt-color-neutral-alt-40: rgb(96, 100, 120) !important; + --pwt-color-neutral-alt-30: rgb(76, 80, 100) !important; + --pwt-color-neutral-alt-20: rgb(58, 62, 82) !important; + --pwt-color-neutral-alt-15: rgb(46, 48, 68) !important; + --pwt-color-neutral-alt-10: rgb(34, 36, 54) !important; + --pwt-color-neutral-alt-5: rgb(22, 24, 38) !important; + --pwt-color-neutral-alt-0: rgb(0, 0, 0) !important; +} + +/* ===== Semantic Color Remapping (light surfaces) ===== */ +:root.pwt-dark-mode { + --pwt-color-surface: var(--pwt-color-neutral-95) !important; + --pwt-color-on-surface: var(--pwt-color-neutral-10) !important; + --pwt-color-surface-container: var(--pwt-color-neutral-90) !important; + --pwt-color-on-surface-container: var(--pwt-color-neutral-10) !important; + --pwt-color-neutral: var(--pwt-color-neutral-90) !important; + --pwt-color-on-neutral: var(--pwt-color-neutral-10) !important; + --pwt-color-neutral-container: var(--pwt-color-neutral-95) !important; + --pwt-color-on-neutral-container: var(--pwt-color-neutral-10) !important; + --pwt-color-dark-surface: var(--pwt-color-neutral-95) !important; + --pwt-color-on-dark-surface: var(--pwt-color-neutral-10) !important; + --pwt-color-dark-surface-container: var(--pwt-color-neutral-90) !important; + --pwt-color-on-dark-surface-container: var(--pwt-color-neutral-10) !important; + --pwt-color-neutral-alt: var(--pwt-color-neutral-alt-90) !important; + --pwt-color-on-neutral-alt: var(--pwt-color-neutral-alt-20) !important; + --pwt-color-neutral-alt-container: var(--pwt-color-neutral-alt-95) !important; + --pwt-color-on-neutral-alt-container: var(--pwt-color-neutral-alt-20) !important; + --pwt-color-background: var(--pwt-color-neutral-95) !important; + --pwt-color-inverse-surface: var(--pwt-color-neutral-20) !important; + --pwt-color-on-inverse-surface: var(--pwt-color-neutral-95) !important; + --pwt-color-border: var(--pwt-color-neutral-alt-80) !important; + --pwt-color-shadow: rgba(0, 0, 0, 0.12) !important; + --pwt-color-primary: var(--pwt-color-primary-40) !important; + --pwt-color-on-primary: var(--pwt-color-primary-100) !important; + --pwt-color-primary-container: var(--pwt-color-primary-90) !important; + --pwt-color-on-primary-container: var(--pwt-color-primary-10) !important; + background: var(--pwt-color-neutral-95) !important; + color: var(--pwt-color-neutral-10) !important; + color-scheme: light !important; +} + +body { + background-color: var(--pwt-color-neutral-95) !important; +} + +/* ===== Logo — swap to dark variant for light background ===== */ +img[src*="proxmox_logo_white"] { + content: url("/images/proxmox_logo.svg") !important; +} diff --git a/themes/pdm/theme-catppuccin-macchiato.css b/themes/pdm/theme-catppuccin-macchiato.css new file mode 100644 index 0000000..969ba6c --- /dev/null +++ b/themes/pdm/theme-catppuccin-macchiato.css @@ -0,0 +1,180 @@ +/*!Catppuccin Macchiato*/ +/* + * ProxMorph PDM Theme: Catppuccin Macchiato + * Overrides the PWT Material Design tonal color system with Catppuccin Macchiato palette + * Version: 1.0.0 + * Author: ProxMorph / Catppuccin Community Palette + * + * ─── Catppuccin Macchiato Palette ───────────────────────────── + * Mauve (accent): #c6a0f6 Blue: #8aadf4 + * Green: #a6da95 Red: #ed8796 + * Yellow: #eed49f Pink: #f5bde6 + * Text: #cad3f5 Base: #24273a + * Surface0: #363a4f Mantle: #1e2030 + * Crust: #181926 + */ + +/* ===== Tonal Color Overrides ===== */ +:root { + /* Primary — Catppuccin Macchiato Mauve (#c6a0f6) tonal scale */ + --pwt-color-primary-100: rgb(255, 255, 255) !important; + --pwt-color-primary-99: rgb(252, 248, 255) !important; + --pwt-color-primary-95: rgb(240, 228, 254) !important; + --pwt-color-primary-90: rgb(225, 208, 250) !important; + --pwt-color-primary-80: rgb(198, 160, 246) !important; + --pwt-color-primary-70: rgb(175, 138, 225) !important; + --pwt-color-primary-60: rgb(150, 114, 200) !important; + --pwt-color-primary-50: rgb(126, 92, 178) !important; + --pwt-color-primary-40: rgb(102, 70, 152) !important; + --pwt-color-primary-30: rgb(80, 48, 128) !important; + --pwt-color-primary-20: rgb(58, 30, 102) !important; + --pwt-color-primary-15: rgb(46, 20, 85) !important; + --pwt-color-primary-10: rgb(35, 12, 68) !important; + --pwt-color-primary-5: rgb(22, 5, 46) !important; + --pwt-color-primary-0: rgb(0, 0, 0) !important; + + /* Secondary — Catppuccin Macchiato Blue (#8aadf4) tonal scale */ + --pwt-color-secondary-100: rgb(255, 255, 255) !important; + --pwt-color-secondary-99: rgb(248, 250, 255) !important; + --pwt-color-secondary-95: rgb(222, 236, 255) !important; + --pwt-color-secondary-90: rgb(198, 220, 254) !important; + --pwt-color-secondary-80: rgb(158, 192, 248) !important; + --pwt-color-secondary-70: rgb(138, 173, 244) !important; + --pwt-color-secondary-60: rgb(112, 148, 218) !important; + --pwt-color-secondary-50: rgb(88, 124, 192) !important; + --pwt-color-secondary-40: rgb(66, 100, 166) !important; + --pwt-color-secondary-30: rgb(46, 78, 138) !important; + --pwt-color-secondary-20: rgb(28, 56, 110) !important; + --pwt-color-secondary-15: rgb(20, 44, 90) !important; + --pwt-color-secondary-10: rgb(12, 32, 70) !important; + --pwt-color-secondary-5: rgb(5, 18, 46) !important; + --pwt-color-secondary-0: rgb(0, 0, 0) !important; + + /* Tertiary — Catppuccin Macchiato Pink (#f5bde6) tonal scale */ + --pwt-color-tertiary-100: rgb(255, 255, 255) !important; + --pwt-color-tertiary-99: rgb(255, 250, 253) !important; + --pwt-color-tertiary-95: rgb(255, 236, 248) !important; + --pwt-color-tertiary-90: rgb(252, 215, 242) !important; + --pwt-color-tertiary-80: rgb(245, 189, 230) !important; + --pwt-color-tertiary-70: rgb(225, 162, 208) !important; + --pwt-color-tertiary-60: rgb(200, 136, 184) !important; + --pwt-color-tertiary-50: rgb(175, 112, 160) !important; + --pwt-color-tertiary-40: rgb(150, 88, 136) !important; + --pwt-color-tertiary-30: rgb(124, 64, 112) !important; + --pwt-color-tertiary-20: rgb(98, 42, 88) !important; + --pwt-color-tertiary-15: rgb(80, 30, 72) !important; + --pwt-color-tertiary-10: rgb(62, 18, 56) !important; + --pwt-color-tertiary-5: rgb(42, 6, 36) !important; + --pwt-color-tertiary-0: rgb(0, 0, 0) !important; + + /* Success — Catppuccin Macchiato Green (#a6da95) tonal scale */ + --pwt-color-success-100: rgb(255, 255, 255) !important; + --pwt-color-success-99: rgb(248, 255, 246) !important; + --pwt-color-success-95: rgb(218, 252, 212) !important; + --pwt-color-success-90: rgb(190, 242, 182) !important; + --pwt-color-success-80: rgb(166, 218, 149) !important; + --pwt-color-success-70: rgb(142, 195, 128) !important; + --pwt-color-success-60: rgb(118, 172, 105) !important; + --pwt-color-success-50: rgb(95, 148, 82) !important; + --pwt-color-success-40: rgb(72, 125, 60) !important; + --pwt-color-success-30: rgb(52, 100, 40) !important; + --pwt-color-success-20: rgb(34, 76, 22) !important; + --pwt-color-success-15: rgb(24, 60, 14) !important; + --pwt-color-success-10: rgb(15, 45, 6) !important; + --pwt-color-success-5: rgb(6, 28, 0) !important; + --pwt-color-success-0: rgb(0, 0, 0) !important; + + /* Error — Catppuccin Macchiato Red (#ed8796) tonal scale */ + --pwt-color-error-100: rgb(255, 255, 255) !important; + --pwt-color-error-99: rgb(255, 248, 249) !important; + --pwt-color-error-95: rgb(255, 228, 232) !important; + --pwt-color-error-90: rgb(252, 205, 212) !important; + --pwt-color-error-80: rgb(245, 170, 180) !important; + --pwt-color-error-70: rgb(237, 135, 150) !important; + --pwt-color-error-60: rgb(215, 108, 125) !important; + --pwt-color-error-50: rgb(192, 85, 102) !important; + --pwt-color-error-40: rgb(168, 62, 78) !important; + --pwt-color-error-30: rgb(140, 40, 56) !important; + --pwt-color-error-20: rgb(112, 20, 36) !important; + --pwt-color-error-15: rgb(92, 10, 25) !important; + --pwt-color-error-10: rgb(70, 0, 15) !important; + --pwt-color-error-5: rgb(46, 0, 6) !important; + --pwt-color-error-0: rgb(0, 0, 0) !important; + + /* Warning — Catppuccin Macchiato Yellow (#eed49f) tonal scale */ + --pwt-color-warning-100: rgb(255, 255, 255) !important; + --pwt-color-warning-99: rgb(255, 252, 248) !important; + --pwt-color-warning-95: rgb(252, 244, 222) !important; + --pwt-color-warning-90: rgb(248, 236, 195) !important; + --pwt-color-warning-80: rgb(238, 212, 159) !important; + --pwt-color-warning-70: rgb(218, 192, 132) !important; + --pwt-color-warning-60: rgb(195, 168, 106) !important; + --pwt-color-warning-50: rgb(172, 145, 82) !important; + --pwt-color-warning-40: rgb(148, 122, 60) !important; + --pwt-color-warning-30: rgb(122, 98, 40) !important; + --pwt-color-warning-20: rgb(95, 75, 22) !important; + --pwt-color-warning-15: rgb(76, 58, 12) !important; + --pwt-color-warning-10: rgb(56, 42, 4) !important; + --pwt-color-warning-5: rgb(35, 26, 0) !important; + --pwt-color-warning-0: rgb(0, 0, 0) !important; + + /* Neutral — Catppuccin Macchiato Background scale (base #24273a) */ + --pwt-color-neutral-100: rgb(202, 211, 245) !important; + --pwt-color-neutral-99: rgb(195, 204, 240) !important; + --pwt-color-neutral-95: rgb(182, 192, 225) !important; + --pwt-color-neutral-90: rgb(164, 172, 205) !important; + --pwt-color-neutral-80: rgb(142, 150, 180) !important; + --pwt-color-neutral-70: rgb(120, 128, 158) !important; + --pwt-color-neutral-60: rgb(100, 106, 135) !important; + --pwt-color-neutral-50: rgb(82, 88, 112) !important; + --pwt-color-neutral-40: rgb(54, 58, 79) !important; + --pwt-color-neutral-30: rgb(36, 39, 58) !important; + --pwt-color-neutral-20: rgb(30, 32, 48) !important; + --pwt-color-neutral-15: rgb(24, 26, 38) !important; + --pwt-color-neutral-10: rgb(18, 19, 30) !important; + --pwt-color-neutral-5: rgb(12, 12, 20) !important; + --pwt-color-neutral-0: rgb(0, 0, 0) !important; + + /* Neutral Alt — Catppuccin Macchiato Overlay tones */ + --pwt-color-neutral-alt-100: rgb(202, 211, 245) !important; + --pwt-color-neutral-alt-99: rgb(196, 206, 242) !important; + --pwt-color-neutral-alt-95: rgb(184, 194, 228) !important; + --pwt-color-neutral-alt-90: rgb(166, 174, 208) !important; + --pwt-color-neutral-alt-80: rgb(144, 152, 184) !important; + --pwt-color-neutral-alt-70: rgb(122, 130, 160) !important; + --pwt-color-neutral-alt-60: rgb(102, 108, 138) !important; + --pwt-color-neutral-alt-50: rgb(84, 90, 115) !important; + --pwt-color-neutral-alt-40: rgb(56, 60, 82) !important; + --pwt-color-neutral-alt-30: rgb(38, 42, 62) !important; + --pwt-color-neutral-alt-20: rgb(30, 34, 50) !important; + --pwt-color-neutral-alt-15: rgb(25, 28, 40) !important; + --pwt-color-neutral-alt-10: rgb(19, 20, 32) !important; + --pwt-color-neutral-alt-5: rgb(12, 13, 22) !important; + --pwt-color-neutral-alt-0: rgb(0, 0, 0) !important; +} + --pwt-color-surface-container: var(--pwt-color-neutral-15) !important; + --pwt-color-on-surface-container: var(--pwt-color-neutral-95) !important; + --pwt-color-neutral: var(--pwt-color-neutral-15) !important; + --pwt-color-on-neutral: var(--pwt-color-neutral-95) !important; + --pwt-color-neutral-container: var(--pwt-color-neutral-10) !important; + --pwt-color-on-neutral-container: var(--pwt-color-neutral-95) !important; + --pwt-color-dark-surface: var(--pwt-color-neutral-10) !important; + --pwt-color-on-dark-surface: var(--pwt-color-neutral-95) !important; + --pwt-color-dark-surface-container: var(--pwt-color-neutral-15) !important; + --pwt-color-on-dark-surface-container: var(--pwt-color-neutral-95) !important; + --pwt-color-neutral-alt: var(--pwt-color-neutral-alt-15) !important; + --pwt-color-on-neutral-alt: var(--pwt-color-neutral-alt-80) !important; + --pwt-color-neutral-alt-container: var(--pwt-color-neutral-alt-10) !important; + --pwt-color-on-neutral-alt-container: var(--pwt-color-neutral-alt-80) !important; + --pwt-color-background: var(--pwt-color-neutral-10) !important; + --pwt-color-inverse-surface: var(--pwt-color-neutral-80) !important; + --pwt-color-on-inverse-surface: var(--pwt-color-neutral-10) !important; + --pwt-color-border: var(--pwt-color-neutral-alt-30) !important; + --pwt-color-shadow: var(--pwt-color-neutral-0) !important; + background: var(--pwt-color-neutral-10) !important; + color: var(--pwt-color-neutral-95) !important; +} + +body { + background-color: var(--pwt-color-neutral-10) !important; +} diff --git a/themes/pdm/theme-catppuccin-mocha-teal.css b/themes/pdm/theme-catppuccin-mocha-teal.css new file mode 100644 index 0000000..44f5214 --- /dev/null +++ b/themes/pdm/theme-catppuccin-mocha-teal.css @@ -0,0 +1,185 @@ +/*!Catppuccin Mocha Teal*/ +/* + * ProxMorph PDM Theme: Catppuccin Mocha Teal + * Overrides the PWT Material Design tonal color system with Catppuccin Mocha Teal palette + * Version: 1.0.0 + * Author: ProxMorph / Catppuccin Community Palette + * + * ─── Catppuccin Mocha Teal Palette ──────────────────────────── + * Teal (accent): #94e2d5 Blue: #89b4fa + * Green: #a6e3a1 Red: #f38ba8 + * Yellow: #f9e2af Pink: #f5c2e7 + * Text: #cdd6f4 Base: #1e1e2e + * Surface0: #313244 Mantle: #181825 + * Crust: #11111b + */ + +/* ===== Tonal Color Overrides ===== */ +:root { + /* Primary — Catppuccin Teal (#94e2d5) tonal scale */ + --pwt-color-primary-100: rgb(255, 255, 255) !important; + --pwt-color-primary-99: rgb(245, 254, 252) !important; + --pwt-color-primary-95: rgb(220, 250, 245) !important; + --pwt-color-primary-90: rgb(185, 242, 232) !important; + --pwt-color-primary-80: rgb(148, 226, 213) !important; + --pwt-color-primary-70: rgb(118, 198, 186) !important; + --pwt-color-primary-60: rgb(88, 170, 160) !important; + --pwt-color-primary-50: rgb(62, 145, 135) !important; + --pwt-color-primary-40: rgb(38, 118, 110) !important; + --pwt-color-primary-30: rgb(18, 92, 85) !important; + --pwt-color-primary-20: rgb(4, 68, 62) !important; + --pwt-color-primary-15: rgb(0, 54, 48) !important; + --pwt-color-primary-10: rgb(0, 40, 36) !important; + --pwt-color-primary-5: rgb(0, 25, 22) !important; + --pwt-color-primary-0: rgb(0, 0, 0) !important; + + /* Secondary — Catppuccin Blue (#89b4fa) tonal scale */ + --pwt-color-secondary-100: rgb(255, 255, 255) !important; + --pwt-color-secondary-99: rgb(248, 251, 255) !important; + --pwt-color-secondary-95: rgb(225, 238, 255) !important; + --pwt-color-secondary-90: rgb(200, 222, 255) !important; + --pwt-color-secondary-80: rgb(160, 195, 250) !important; + --pwt-color-secondary-70: rgb(137, 180, 250) !important; + --pwt-color-secondary-60: rgb(110, 155, 220) !important; + --pwt-color-secondary-50: rgb(88, 130, 195) !important; + --pwt-color-secondary-40: rgb(68, 108, 170) !important; + --pwt-color-secondary-30: rgb(48, 85, 142) !important; + --pwt-color-secondary-20: rgb(32, 62, 112) !important; + --pwt-color-secondary-15: rgb(24, 48, 92) !important; + --pwt-color-secondary-10: rgb(16, 35, 72) !important; + --pwt-color-secondary-5: rgb(8, 20, 48) !important; + --pwt-color-secondary-0: rgb(0, 0, 0) !important; + + /* Tertiary — Catppuccin Pink (#f5c2e7) tonal scale */ + --pwt-color-tertiary-100: rgb(255, 255, 255) !important; + --pwt-color-tertiary-99: rgb(255, 250, 254) !important; + --pwt-color-tertiary-95: rgb(255, 238, 248) !important; + --pwt-color-tertiary-90: rgb(255, 220, 240) !important; + --pwt-color-tertiary-80: rgb(245, 194, 231) !important; + --pwt-color-tertiary-70: rgb(225, 168, 210) !important; + --pwt-color-tertiary-60: rgb(200, 140, 185) !important; + --pwt-color-tertiary-50: rgb(175, 115, 162) !important; + --pwt-color-tertiary-40: rgb(150, 90, 138) !important; + --pwt-color-tertiary-30: rgb(125, 65, 112) !important; + --pwt-color-tertiary-20: rgb(98, 42, 88) !important; + --pwt-color-tertiary-15: rgb(80, 30, 72) !important; + --pwt-color-tertiary-10: rgb(62, 18, 55) !important; + --pwt-color-tertiary-5: rgb(42, 8, 38) !important; + --pwt-color-tertiary-0: rgb(0, 0, 0) !important; + + /* Success — Catppuccin Green (#a6e3a1) tonal scale */ + --pwt-color-success-100: rgb(255, 255, 255) !important; + --pwt-color-success-99: rgb(245, 255, 244) !important; + --pwt-color-success-95: rgb(215, 255, 212) !important; + --pwt-color-success-90: rgb(185, 245, 182) !important; + --pwt-color-success-80: rgb(166, 227, 161) !important; + --pwt-color-success-70: rgb(140, 200, 136) !important; + --pwt-color-success-60: rgb(115, 175, 112) !important; + --pwt-color-success-50: rgb(90, 150, 88) !important; + --pwt-color-success-40: rgb(68, 125, 65) !important; + --pwt-color-success-30: rgb(48, 100, 45) !important; + --pwt-color-success-20: rgb(30, 76, 28) !important; + --pwt-color-success-15: rgb(20, 60, 18) !important; + --pwt-color-success-10: rgb(12, 45, 10) !important; + --pwt-color-success-5: rgb(5, 28, 4) !important; + --pwt-color-success-0: rgb(0, 0, 0) !important; + + /* Error — Catppuccin Red (#f38ba8) tonal scale */ + --pwt-color-error-100: rgb(255, 255, 255) !important; + --pwt-color-error-99: rgb(255, 249, 250) !important; + --pwt-color-error-95: rgb(255, 232, 238) !important; + --pwt-color-error-90: rgb(255, 210, 220) !important; + --pwt-color-error-80: rgb(248, 165, 185) !important; + --pwt-color-error-70: rgb(243, 139, 168) !important; + --pwt-color-error-60: rgb(220, 110, 140) !important; + --pwt-color-error-50: rgb(195, 85, 115) !important; + --pwt-color-error-40: rgb(170, 60, 90) !important; + --pwt-color-error-30: rgb(142, 38, 68) !important; + --pwt-color-error-20: rgb(110, 18, 48) !important; + --pwt-color-error-15: rgb(90, 8, 35) !important; + --pwt-color-error-10: rgb(68, 0, 22) !important; + --pwt-color-error-5: rgb(45, 0, 12) !important; + --pwt-color-error-0: rgb(0, 0, 0) !important; + + /* Warning — Catppuccin Yellow (#f9e2af) tonal scale */ + --pwt-color-warning-100: rgb(255, 255, 255) !important; + --pwt-color-warning-99: rgb(255, 253, 248) !important; + --pwt-color-warning-95: rgb(255, 248, 225) !important; + --pwt-color-warning-90: rgb(252, 240, 195) !important; + --pwt-color-warning-80: rgb(249, 226, 175) !important; + --pwt-color-warning-70: rgb(225, 200, 145) !important; + --pwt-color-warning-60: rgb(200, 178, 118) !important; + --pwt-color-warning-50: rgb(175, 155, 92) !important; + --pwt-color-warning-40: rgb(148, 130, 68) !important; + --pwt-color-warning-30: rgb(120, 105, 45) !important; + --pwt-color-warning-20: rgb(92, 80, 25) !important; + --pwt-color-warning-15: rgb(72, 62, 15) !important; + --pwt-color-warning-10: rgb(52, 45, 5) !important; + --pwt-color-warning-5: rgb(32, 28, 0) !important; + --pwt-color-warning-0: rgb(0, 0, 0) !important; + + /* Neutral — Catppuccin Background scale */ + --pwt-color-neutral-100: rgb(205, 214, 244) !important; + --pwt-color-neutral-99: rgb(198, 208, 240) !important; + --pwt-color-neutral-95: rgb(186, 194, 222) !important; + --pwt-color-neutral-90: rgb(166, 173, 200) !important; + --pwt-color-neutral-80: rgb(147, 153, 178) !important; + --pwt-color-neutral-70: rgb(127, 132, 156) !important; + --pwt-color-neutral-60: rgb(108, 112, 134) !important; + --pwt-color-neutral-50: rgb(88, 91, 112) !important; + --pwt-color-neutral-40: rgb(69, 71, 90) !important; + --pwt-color-neutral-30: rgb(49, 50, 68) !important; + --pwt-color-neutral-20: rgb(30, 30, 46) !important; + --pwt-color-neutral-15: rgb(24, 24, 37) !important; + --pwt-color-neutral-10: rgb(17, 17, 27) !important; + --pwt-color-neutral-5: rgb(10, 10, 18) !important; + --pwt-color-neutral-0: rgb(0, 0, 0) !important; + + /* Neutral Alt — Catppuccin Overlay tones */ + --pwt-color-neutral-alt-100: rgb(205, 214, 244) !important; + --pwt-color-neutral-alt-99: rgb(200, 210, 242) !important; + --pwt-color-neutral-alt-95: rgb(186, 194, 222) !important; + --pwt-color-neutral-alt-90: rgb(166, 173, 200) !important; + --pwt-color-neutral-alt-80: rgb(147, 153, 178) !important; + --pwt-color-neutral-alt-70: rgb(127, 132, 156) !important; + --pwt-color-neutral-alt-60: rgb(108, 112, 134) !important; + --pwt-color-neutral-alt-50: rgb(88, 91, 112) !important; + --pwt-color-neutral-alt-40: rgb(69, 71, 90) !important; + --pwt-color-neutral-alt-30: rgb(49, 50, 68) !important; + --pwt-color-neutral-alt-20: rgb(30, 30, 46) !important; + --pwt-color-neutral-alt-15: rgb(24, 24, 37) !important; + --pwt-color-neutral-alt-10: rgb(17, 17, 27) !important; + --pwt-color-neutral-alt-5: rgb(10, 10, 18) !important; + --pwt-color-neutral-alt-0: rgb(0, 0, 0) !important; +} + +/* ===== Semantic Color Remapping (darker surfaces) ===== */ +:root.pwt-dark-mode { + --pwt-color-surface: var(--pwt-color-neutral-10) !important; + --pwt-color-on-surface: var(--pwt-color-neutral-95) !important; + --pwt-color-surface-container: var(--pwt-color-neutral-15) !important; + --pwt-color-on-surface-container: var(--pwt-color-neutral-95) !important; + --pwt-color-neutral: var(--pwt-color-neutral-15) !important; + --pwt-color-on-neutral: var(--pwt-color-neutral-95) !important; + --pwt-color-neutral-container: var(--pwt-color-neutral-10) !important; + --pwt-color-on-neutral-container: var(--pwt-color-neutral-95) !important; + --pwt-color-dark-surface: var(--pwt-color-neutral-10) !important; + --pwt-color-on-dark-surface: var(--pwt-color-neutral-95) !important; + --pwt-color-dark-surface-container: var(--pwt-color-neutral-15) !important; + --pwt-color-on-dark-surface-container: var(--pwt-color-neutral-95) !important; + --pwt-color-neutral-alt: var(--pwt-color-neutral-alt-15) !important; + --pwt-color-on-neutral-alt: var(--pwt-color-neutral-alt-80) !important; + --pwt-color-neutral-alt-container: var(--pwt-color-neutral-alt-10) !important; + --pwt-color-on-neutral-alt-container: var(--pwt-color-neutral-alt-80) !important; + --pwt-color-background: var(--pwt-color-neutral-10) !important; + --pwt-color-inverse-surface: var(--pwt-color-neutral-80) !important; + --pwt-color-on-inverse-surface: var(--pwt-color-neutral-10) !important; + --pwt-color-border: var(--pwt-color-neutral-alt-30) !important; + --pwt-color-shadow: var(--pwt-color-neutral-0) !important; + background: var(--pwt-color-neutral-10) !important; + color: var(--pwt-color-neutral-95) !important; +} + +body { + background-color: var(--pwt-color-neutral-10) !important; +} diff --git a/themes/pdm/theme-catppuccin-mocha.css b/themes/pdm/theme-catppuccin-mocha.css new file mode 100644 index 0000000..dc05703 --- /dev/null +++ b/themes/pdm/theme-catppuccin-mocha.css @@ -0,0 +1,185 @@ +/*!Catppuccin Mocha*/ +/* + * ProxMorph PDM Theme: Catppuccin Mocha + * Overrides the PWT Material Design tonal color system with Catppuccin Mocha palette + * Version: 1.0.0 + * Author: ProxMorph / Catppuccin Community Palette + * + * ─── Catppuccin Mocha Palette ────────────────────────────────── + * Mauve (accent): #cba6f7 Blue: #89b4fa + * Green: #a6e3a1 Red: #f38ba8 + * Yellow: #f9e2af Pink: #f5c2e7 + * Text: #cdd6f4 Base: #1e1e2e + * Surface0: #313244 Mantle: #181825 + * Crust: #11111b + */ + +/* ===== Tonal Color Overrides ===== */ +:root { + /* Primary — Catppuccin Mauve (#cba6f7) tonal scale */ + --pwt-color-primary-100: rgb(255, 255, 255) !important; + --pwt-color-primary-99: rgb(252, 248, 255) !important; + --pwt-color-primary-95: rgb(242, 232, 255) !important; + --pwt-color-primary-90: rgb(230, 215, 255) !important; + --pwt-color-primary-80: rgb(203, 166, 247) !important; + --pwt-color-primary-70: rgb(178, 140, 225) !important; + --pwt-color-primary-60: rgb(152, 115, 200) !important; + --pwt-color-primary-50: rgb(128, 92, 178) !important; + --pwt-color-primary-40: rgb(105, 70, 155) !important; + --pwt-color-primary-30: rgb(82, 50, 130) !important; + --pwt-color-primary-20: rgb(60, 32, 105) !important; + --pwt-color-primary-15: rgb(48, 22, 88) !important; + --pwt-color-primary-10: rgb(38, 14, 72) !important; + --pwt-color-primary-5: rgb(24, 6, 50) !important; + --pwt-color-primary-0: rgb(0, 0, 0) !important; + + /* Secondary — Catppuccin Blue (#89b4fa) tonal scale */ + --pwt-color-secondary-100: rgb(255, 255, 255) !important; + --pwt-color-secondary-99: rgb(248, 251, 255) !important; + --pwt-color-secondary-95: rgb(225, 238, 255) !important; + --pwt-color-secondary-90: rgb(200, 222, 255) !important; + --pwt-color-secondary-80: rgb(160, 195, 250) !important; + --pwt-color-secondary-70: rgb(137, 180, 250) !important; + --pwt-color-secondary-60: rgb(110, 155, 220) !important; + --pwt-color-secondary-50: rgb(88, 130, 195) !important; + --pwt-color-secondary-40: rgb(68, 108, 170) !important; + --pwt-color-secondary-30: rgb(48, 85, 142) !important; + --pwt-color-secondary-20: rgb(32, 62, 112) !important; + --pwt-color-secondary-15: rgb(24, 48, 92) !important; + --pwt-color-secondary-10: rgb(16, 35, 72) !important; + --pwt-color-secondary-5: rgb(8, 20, 48) !important; + --pwt-color-secondary-0: rgb(0, 0, 0) !important; + + /* Tertiary — Catppuccin Pink (#f5c2e7) tonal scale */ + --pwt-color-tertiary-100: rgb(255, 255, 255) !important; + --pwt-color-tertiary-99: rgb(255, 250, 254) !important; + --pwt-color-tertiary-95: rgb(255, 238, 248) !important; + --pwt-color-tertiary-90: rgb(255, 220, 240) !important; + --pwt-color-tertiary-80: rgb(245, 194, 231) !important; + --pwt-color-tertiary-70: rgb(225, 168, 210) !important; + --pwt-color-tertiary-60: rgb(200, 140, 185) !important; + --pwt-color-tertiary-50: rgb(175, 115, 162) !important; + --pwt-color-tertiary-40: rgb(150, 90, 138) !important; + --pwt-color-tertiary-30: rgb(125, 65, 112) !important; + --pwt-color-tertiary-20: rgb(98, 42, 88) !important; + --pwt-color-tertiary-15: rgb(80, 30, 72) !important; + --pwt-color-tertiary-10: rgb(62, 18, 55) !important; + --pwt-color-tertiary-5: rgb(42, 8, 38) !important; + --pwt-color-tertiary-0: rgb(0, 0, 0) !important; + + /* Success — Catppuccin Green (#a6e3a1) tonal scale */ + --pwt-color-success-100: rgb(255, 255, 255) !important; + --pwt-color-success-99: rgb(245, 255, 244) !important; + --pwt-color-success-95: rgb(215, 255, 212) !important; + --pwt-color-success-90: rgb(185, 245, 182) !important; + --pwt-color-success-80: rgb(166, 227, 161) !important; + --pwt-color-success-70: rgb(140, 200, 136) !important; + --pwt-color-success-60: rgb(115, 175, 112) !important; + --pwt-color-success-50: rgb(90, 150, 88) !important; + --pwt-color-success-40: rgb(68, 125, 65) !important; + --pwt-color-success-30: rgb(48, 100, 45) !important; + --pwt-color-success-20: rgb(30, 76, 28) !important; + --pwt-color-success-15: rgb(20, 60, 18) !important; + --pwt-color-success-10: rgb(12, 45, 10) !important; + --pwt-color-success-5: rgb(5, 28, 4) !important; + --pwt-color-success-0: rgb(0, 0, 0) !important; + + /* Error — Catppuccin Red (#f38ba8) tonal scale */ + --pwt-color-error-100: rgb(255, 255, 255) !important; + --pwt-color-error-99: rgb(255, 249, 250) !important; + --pwt-color-error-95: rgb(255, 232, 238) !important; + --pwt-color-error-90: rgb(255, 210, 220) !important; + --pwt-color-error-80: rgb(248, 165, 185) !important; + --pwt-color-error-70: rgb(243, 139, 168) !important; + --pwt-color-error-60: rgb(220, 110, 140) !important; + --pwt-color-error-50: rgb(195, 85, 115) !important; + --pwt-color-error-40: rgb(170, 60, 90) !important; + --pwt-color-error-30: rgb(142, 38, 68) !important; + --pwt-color-error-20: rgb(110, 18, 48) !important; + --pwt-color-error-15: rgb(90, 8, 35) !important; + --pwt-color-error-10: rgb(68, 0, 22) !important; + --pwt-color-error-5: rgb(45, 0, 12) !important; + --pwt-color-error-0: rgb(0, 0, 0) !important; + + /* Warning — Catppuccin Yellow (#f9e2af) tonal scale */ + --pwt-color-warning-100: rgb(255, 255, 255) !important; + --pwt-color-warning-99: rgb(255, 253, 248) !important; + --pwt-color-warning-95: rgb(255, 248, 225) !important; + --pwt-color-warning-90: rgb(252, 240, 195) !important; + --pwt-color-warning-80: rgb(249, 226, 175) !important; + --pwt-color-warning-70: rgb(225, 200, 145) !important; + --pwt-color-warning-60: rgb(200, 178, 118) !important; + --pwt-color-warning-50: rgb(175, 155, 92) !important; + --pwt-color-warning-40: rgb(148, 130, 68) !important; + --pwt-color-warning-30: rgb(120, 105, 45) !important; + --pwt-color-warning-20: rgb(92, 80, 25) !important; + --pwt-color-warning-15: rgb(72, 62, 15) !important; + --pwt-color-warning-10: rgb(52, 45, 5) !important; + --pwt-color-warning-5: rgb(32, 28, 0) !important; + --pwt-color-warning-0: rgb(0, 0, 0) !important; + + /* Neutral — Catppuccin Background scale */ + --pwt-color-neutral-100: rgb(205, 214, 244) !important; + --pwt-color-neutral-99: rgb(198, 208, 240) !important; + --pwt-color-neutral-95: rgb(186, 194, 222) !important; + --pwt-color-neutral-90: rgb(166, 173, 200) !important; + --pwt-color-neutral-80: rgb(147, 153, 178) !important; + --pwt-color-neutral-70: rgb(127, 132, 156) !important; + --pwt-color-neutral-60: rgb(108, 112, 134) !important; + --pwt-color-neutral-50: rgb(88, 91, 112) !important; + --pwt-color-neutral-40: rgb(69, 71, 90) !important; + --pwt-color-neutral-30: rgb(49, 50, 68) !important; + --pwt-color-neutral-20: rgb(30, 30, 46) !important; + --pwt-color-neutral-15: rgb(24, 24, 37) !important; + --pwt-color-neutral-10: rgb(17, 17, 27) !important; + --pwt-color-neutral-5: rgb(10, 10, 18) !important; + --pwt-color-neutral-0: rgb(0, 0, 0) !important; + + /* Neutral Alt — Catppuccin Overlay tones */ + --pwt-color-neutral-alt-100: rgb(205, 214, 244) !important; + --pwt-color-neutral-alt-99: rgb(200, 210, 242) !important; + --pwt-color-neutral-alt-95: rgb(186, 194, 222) !important; + --pwt-color-neutral-alt-90: rgb(166, 173, 200) !important; + --pwt-color-neutral-alt-80: rgb(147, 153, 178) !important; + --pwt-color-neutral-alt-70: rgb(127, 132, 156) !important; + --pwt-color-neutral-alt-60: rgb(108, 112, 134) !important; + --pwt-color-neutral-alt-50: rgb(88, 91, 112) !important; + --pwt-color-neutral-alt-40: rgb(69, 71, 90) !important; + --pwt-color-neutral-alt-30: rgb(49, 50, 68) !important; + --pwt-color-neutral-alt-20: rgb(30, 30, 46) !important; + --pwt-color-neutral-alt-15: rgb(24, 24, 37) !important; + --pwt-color-neutral-alt-10: rgb(17, 17, 27) !important; + --pwt-color-neutral-alt-5: rgb(10, 10, 18) !important; + --pwt-color-neutral-alt-0: rgb(0, 0, 0) !important; +} + +/* ===== Semantic Color Remapping (darker surfaces) ===== */ +:root.pwt-dark-mode { + --pwt-color-surface: var(--pwt-color-neutral-10) !important; + --pwt-color-on-surface: var(--pwt-color-neutral-95) !important; + --pwt-color-surface-container: var(--pwt-color-neutral-15) !important; + --pwt-color-on-surface-container: var(--pwt-color-neutral-95) !important; + --pwt-color-neutral: var(--pwt-color-neutral-15) !important; + --pwt-color-on-neutral: var(--pwt-color-neutral-95) !important; + --pwt-color-neutral-container: var(--pwt-color-neutral-10) !important; + --pwt-color-on-neutral-container: var(--pwt-color-neutral-95) !important; + --pwt-color-dark-surface: var(--pwt-color-neutral-10) !important; + --pwt-color-on-dark-surface: var(--pwt-color-neutral-95) !important; + --pwt-color-dark-surface-container: var(--pwt-color-neutral-15) !important; + --pwt-color-on-dark-surface-container: var(--pwt-color-neutral-95) !important; + --pwt-color-neutral-alt: var(--pwt-color-neutral-alt-15) !important; + --pwt-color-on-neutral-alt: var(--pwt-color-neutral-alt-80) !important; + --pwt-color-neutral-alt-container: var(--pwt-color-neutral-alt-10) !important; + --pwt-color-on-neutral-alt-container: var(--pwt-color-neutral-alt-80) !important; + --pwt-color-background: var(--pwt-color-neutral-10) !important; + --pwt-color-inverse-surface: var(--pwt-color-neutral-80) !important; + --pwt-color-on-inverse-surface: var(--pwt-color-neutral-10) !important; + --pwt-color-border: var(--pwt-color-neutral-alt-30) !important; + --pwt-color-shadow: var(--pwt-color-neutral-0) !important; + background: var(--pwt-color-neutral-10) !important; + color: var(--pwt-color-neutral-95) !important; +} + +body { + background-color: var(--pwt-color-neutral-10) !important; +} \ No newline at end of file diff --git a/themes/pdm/theme-dracula-cyan.css b/themes/pdm/theme-dracula-cyan.css new file mode 100644 index 0000000..729d1ea --- /dev/null +++ b/themes/pdm/theme-dracula-cyan.css @@ -0,0 +1,181 @@ +/*!Dracula Cyan*/ +/* + * ProxMorph PDM Theme: Dracula Cyan + * Overrides the PWT Material Design tonal color system with Dracula Cyan palette + * Version: 1.0.0 + * Author: ProxMorph / Dracula Theme (https://draculatheme.com) + * + * ─── Dracula Cyan Palette ───────────────────────────────────── + * Background: #282a36 Accent: #8be9fd (Cyan) + * Foreground: #f8f8f2 Comment: #6272a4 + */ + +/* ===== Tonal Color Overrides ===== */ +:root { + /* Primary — Dracula Cyan (#8be9fd) tonal scale */ + --pwt-color-primary-100: rgb(255, 255, 255) !important; + --pwt-color-primary-99: rgb(245, 253, 255) !important; + --pwt-color-primary-95: rgb(214, 247, 255) !important; + --pwt-color-primary-90: rgb(175, 240, 254) !important; + --pwt-color-primary-80: rgb(139, 233, 253) !important; + --pwt-color-primary-70: rgb(98, 200, 228) !important; + --pwt-color-primary-60: rgb(60, 168, 205) !important; + --pwt-color-primary-50: rgb(25, 138, 180) !important; + --pwt-color-primary-40: rgb(0, 110, 155) !important; + --pwt-color-primary-30: rgb(0, 82, 125) !important; + --pwt-color-primary-20: rgb(0, 58, 95) !important; + --pwt-color-primary-15: rgb(0, 45, 78) !important; + --pwt-color-primary-10: rgb(0, 32, 60) !important; + --pwt-color-primary-5: rgb(0, 18, 38) !important; + --pwt-color-primary-0: rgb(0, 0, 0) !important; + + /* Secondary — Dracula Comment/Overlay (#6272a4) tonal scale */ + --pwt-color-secondary-100: rgb(255, 255, 255) !important; + --pwt-color-secondary-99: rgb(248, 250, 255) !important; + --pwt-color-secondary-95: rgb(230, 236, 252) !important; + --pwt-color-secondary-90: rgb(210, 220, 245) !important; + --pwt-color-secondary-80: rgb(178, 196, 230) !important; + --pwt-color-secondary-70: rgb(146, 163, 200) !important; + --pwt-color-secondary-60: rgb(118, 137, 180) !important; + --pwt-color-secondary-50: rgb(98, 114, 164) !important; + --pwt-color-secondary-40: rgb(78, 94, 140) !important; + --pwt-color-secondary-30: rgb(58, 72, 115) !important; + --pwt-color-secondary-20: rgb(40, 52, 90) !important; + --pwt-color-secondary-15: rgb(32, 42, 75) !important; + --pwt-color-secondary-10: rgb(24, 32, 60) !important; + --pwt-color-secondary-5: rgb(16, 20, 42) !important; + --pwt-color-secondary-0: rgb(0, 0, 0) !important; + + /* Tertiary — Dracula Pink (#ff79c6) tonal scale */ + --pwt-color-tertiary-100: rgb(255, 255, 255) !important; + --pwt-color-tertiary-99: rgb(255, 248, 252) !important; + --pwt-color-tertiary-95: rgb(255, 234, 244) !important; + --pwt-color-tertiary-90: rgb(255, 210, 232) !important; + --pwt-color-tertiary-80: rgb(255, 165, 210) !important; + --pwt-color-tertiary-70: rgb(255, 121, 198) !important; + --pwt-color-tertiary-60: rgb(230, 95, 175) !important; + --pwt-color-tertiary-50: rgb(200, 70, 150) !important; + --pwt-color-tertiary-40: rgb(170, 48, 125) !important; + --pwt-color-tertiary-30: rgb(140, 28, 100) !important; + --pwt-color-tertiary-20: rgb(108, 12, 78) !important; + --pwt-color-tertiary-15: rgb(88, 4, 62) !important; + --pwt-color-tertiary-10: rgb(68, 0, 48) !important; + --pwt-color-tertiary-5: rgb(45, 0, 30) !important; + --pwt-color-tertiary-0: rgb(0, 0, 0) !important; + + /* Success — Dracula Green (#50fa7b) tonal scale */ + --pwt-color-success-100: rgb(255, 255, 255) !important; + --pwt-color-success-99: rgb(240, 255, 245) !important; + --pwt-color-success-95: rgb(200, 255, 215) !important; + --pwt-color-success-90: rgb(140, 255, 175) !important; + --pwt-color-success-80: rgb(80, 250, 123) !important; + --pwt-color-success-70: rgb(55, 220, 98) !important; + --pwt-color-success-60: rgb(30, 190, 75) !important; + --pwt-color-success-50: rgb(10, 160, 55) !important; + --pwt-color-success-40: rgb(0, 130, 40) !important; + --pwt-color-success-30: rgb(0, 100, 28) !important; + --pwt-color-success-20: rgb(0, 72, 18) !important; + --pwt-color-success-15: rgb(0, 55, 12) !important; + --pwt-color-success-10: rgb(0, 40, 8) !important; + --pwt-color-success-5: rgb(0, 25, 4) !important; + --pwt-color-success-0: rgb(0, 0, 0) !important; + + /* Error — Dracula Red (#ff5555) tonal scale */ + --pwt-color-error-100: rgb(255, 255, 255) !important; + --pwt-color-error-99: rgb(255, 248, 248) !important; + --pwt-color-error-95: rgb(255, 230, 230) !important; + --pwt-color-error-90: rgb(255, 205, 205) !important; + --pwt-color-error-80: rgb(255, 150, 150) !important; + --pwt-color-error-70: rgb(255, 110, 110) !important; + --pwt-color-error-60: rgb(255, 85, 85) !important; + --pwt-color-error-50: rgb(230, 60, 60) !important; + --pwt-color-error-40: rgb(200, 38, 38) !important; + --pwt-color-error-30: rgb(168, 16, 16) !important; + --pwt-color-error-20: rgb(120, 10, 10) !important; + --pwt-color-error-15: rgb(95, 5, 5) !important; + --pwt-color-error-10: rgb(72, 0, 0) !important; + --pwt-color-error-5: rgb(48, 0, 0) !important; + --pwt-color-error-0: rgb(0, 0, 0) !important; + + /* Warning — Dracula Yellow (#f1fa8c) tonal scale */ + --pwt-color-warning-100: rgb(255, 255, 255) !important; + --pwt-color-warning-99: rgb(255, 254, 248) !important; + --pwt-color-warning-95: rgb(252, 255, 210) !important; + --pwt-color-warning-90: rgb(245, 252, 160) !important; + --pwt-color-warning-80: rgb(241, 250, 140) !important; + --pwt-color-warning-70: rgb(218, 228, 100) !important; + --pwt-color-warning-60: rgb(195, 205, 65) !important; + --pwt-color-warning-50: rgb(170, 180, 35) !important; + --pwt-color-warning-40: rgb(140, 150, 15) !important; + --pwt-color-warning-30: rgb(110, 118, 0) !important; + --pwt-color-warning-20: rgb(80, 85, 0) !important; + --pwt-color-warning-15: rgb(60, 65, 0) !important; + --pwt-color-warning-10: rgb(42, 46, 0) !important; + --pwt-color-warning-5: rgb(25, 28, 0) !important; + --pwt-color-warning-0: rgb(0, 0, 0) !important; + + /* Neutral — Dracula Background/Surface scale */ + --pwt-color-neutral-100: rgb(248, 248, 242) !important; + --pwt-color-neutral-99: rgb(240, 240, 236) !important; + --pwt-color-neutral-95: rgb(220, 222, 218) !important; + --pwt-color-neutral-90: rgb(208, 212, 224) !important; + --pwt-color-neutral-80: rgb(176, 181, 200) !important; + --pwt-color-neutral-70: rgb(146, 152, 184) !important; + --pwt-color-neutral-60: rgb(124, 131, 160) !important; + --pwt-color-neutral-50: rgb(98, 114, 164) !important; + --pwt-color-neutral-40: rgb(86, 90, 114) !important; + --pwt-color-neutral-30: rgb(68, 71, 90) !important; + --pwt-color-neutral-20: rgb(40, 42, 54) !important; + --pwt-color-neutral-15: rgb(33, 34, 44) !important; + --pwt-color-neutral-10: rgb(30, 31, 41) !important; + --pwt-color-neutral-5: rgb(22, 23, 30) !important; + --pwt-color-neutral-0: rgb(0, 0, 0) !important; + + /* Neutral Alt — Dracula Comment tones */ + --pwt-color-neutral-alt-100: rgb(248, 248, 242) !important; + --pwt-color-neutral-alt-99: rgb(242, 244, 255) !important; + --pwt-color-neutral-alt-95: rgb(225, 230, 248) !important; + --pwt-color-neutral-alt-90: rgb(210, 216, 238) !important; + --pwt-color-neutral-alt-80: rgb(178, 186, 215) !important; + --pwt-color-neutral-alt-70: rgb(146, 156, 190) !important; + --pwt-color-neutral-alt-60: rgb(118, 128, 165) !important; + --pwt-color-neutral-alt-50: rgb(98, 114, 164) !important; + --pwt-color-neutral-alt-40: rgb(80, 90, 130) !important; + --pwt-color-neutral-alt-30: rgb(60, 68, 105) !important; + --pwt-color-neutral-alt-20: rgb(44, 50, 80) !important; + --pwt-color-neutral-alt-15: rgb(36, 40, 65) !important; + --pwt-color-neutral-alt-10: rgb(28, 32, 52) !important; + --pwt-color-neutral-alt-5: rgb(18, 20, 35) !important; + --pwt-color-neutral-alt-0: rgb(0, 0, 0) !important; +} + +/* ===== Semantic Color Remapping (darker surfaces) ===== */ +:root.pwt-dark-mode { + --pwt-color-surface: var(--pwt-color-neutral-10) !important; + --pwt-color-on-surface: var(--pwt-color-neutral-95) !important; + --pwt-color-surface-container: var(--pwt-color-neutral-15) !important; + --pwt-color-on-surface-container: var(--pwt-color-neutral-95) !important; + --pwt-color-neutral: var(--pwt-color-neutral-15) !important; + --pwt-color-on-neutral: var(--pwt-color-neutral-95) !important; + --pwt-color-neutral-container: var(--pwt-color-neutral-10) !important; + --pwt-color-on-neutral-container: var(--pwt-color-neutral-95) !important; + --pwt-color-dark-surface: var(--pwt-color-neutral-10) !important; + --pwt-color-on-dark-surface: var(--pwt-color-neutral-95) !important; + --pwt-color-dark-surface-container: var(--pwt-color-neutral-15) !important; + --pwt-color-on-dark-surface-container: var(--pwt-color-neutral-95) !important; + --pwt-color-neutral-alt: var(--pwt-color-neutral-alt-15) !important; + --pwt-color-on-neutral-alt: var(--pwt-color-neutral-alt-80) !important; + --pwt-color-neutral-alt-container: var(--pwt-color-neutral-alt-10) !important; + --pwt-color-on-neutral-alt-container: var(--pwt-color-neutral-alt-80) !important; + --pwt-color-background: var(--pwt-color-neutral-10) !important; + --pwt-color-inverse-surface: var(--pwt-color-neutral-80) !important; + --pwt-color-on-inverse-surface: var(--pwt-color-neutral-10) !important; + --pwt-color-border: var(--pwt-color-neutral-alt-30) !important; + --pwt-color-shadow: var(--pwt-color-neutral-0) !important; + background: var(--pwt-color-neutral-10) !important; + color: var(--pwt-color-neutral-95) !important; +} + +body { + background-color: var(--pwt-color-neutral-10) !important; +} diff --git a/themes/pdm/theme-dracula-green.css b/themes/pdm/theme-dracula-green.css new file mode 100644 index 0000000..88a4646 --- /dev/null +++ b/themes/pdm/theme-dracula-green.css @@ -0,0 +1,181 @@ +/*!Dracula Green*/ +/* + * ProxMorph PDM Theme: Dracula Green + * Overrides the PWT Material Design tonal color system with Dracula Green palette + * Version: 1.0.0 + * Author: ProxMorph / Dracula Theme (https://draculatheme.com) + * + * ─── Dracula Green Palette ──────────────────────────────────── + * Background: #1c2820 Accent: #50fa7b (Green) + * Foreground: #f8f8f2 Comment: #6272a4 + */ + +/* ===== Tonal Color Overrides ===== */ +:root { + /* Primary — Dracula Green (#50fa7b) tonal scale */ + --pwt-color-primary-100: rgb(255, 255, 255) !important; + --pwt-color-primary-99: rgb(240, 255, 245) !important; + --pwt-color-primary-95: rgb(200, 255, 215) !important; + --pwt-color-primary-90: rgb(140, 255, 175) !important; + --pwt-color-primary-80: rgb(80, 250, 123) !important; + --pwt-color-primary-70: rgb(55, 220, 98) !important; + --pwt-color-primary-60: rgb(30, 190, 75) !important; + --pwt-color-primary-50: rgb(10, 160, 55) !important; + --pwt-color-primary-40: rgb(0, 130, 40) !important; + --pwt-color-primary-30: rgb(0, 100, 28) !important; + --pwt-color-primary-20: rgb(0, 72, 18) !important; + --pwt-color-primary-15: rgb(0, 55, 12) !important; + --pwt-color-primary-10: rgb(0, 40, 8) !important; + --pwt-color-primary-5: rgb(0, 25, 4) !important; + --pwt-color-primary-0: rgb(0, 0, 0) !important; + + /* Secondary — Dracula Comment/Overlay (#6272a4) tonal scale */ + --pwt-color-secondary-100: rgb(255, 255, 255) !important; + --pwt-color-secondary-99: rgb(248, 250, 255) !important; + --pwt-color-secondary-95: rgb(230, 236, 252) !important; + --pwt-color-secondary-90: rgb(210, 220, 245) !important; + --pwt-color-secondary-80: rgb(178, 196, 230) !important; + --pwt-color-secondary-70: rgb(146, 163, 200) !important; + --pwt-color-secondary-60: rgb(118, 137, 180) !important; + --pwt-color-secondary-50: rgb(98, 114, 164) !important; + --pwt-color-secondary-40: rgb(78, 94, 140) !important; + --pwt-color-secondary-30: rgb(58, 72, 115) !important; + --pwt-color-secondary-20: rgb(40, 52, 90) !important; + --pwt-color-secondary-15: rgb(32, 42, 75) !important; + --pwt-color-secondary-10: rgb(24, 32, 60) !important; + --pwt-color-secondary-5: rgb(16, 20, 42) !important; + --pwt-color-secondary-0: rgb(0, 0, 0) !important; + + /* Tertiary — Dracula Pink (#ff79c6) tonal scale */ + --pwt-color-tertiary-100: rgb(255, 255, 255) !important; + --pwt-color-tertiary-99: rgb(255, 248, 252) !important; + --pwt-color-tertiary-95: rgb(255, 234, 244) !important; + --pwt-color-tertiary-90: rgb(255, 210, 232) !important; + --pwt-color-tertiary-80: rgb(255, 165, 210) !important; + --pwt-color-tertiary-70: rgb(255, 121, 198) !important; + --pwt-color-tertiary-60: rgb(230, 95, 175) !important; + --pwt-color-tertiary-50: rgb(200, 70, 150) !important; + --pwt-color-tertiary-40: rgb(170, 48, 125) !important; + --pwt-color-tertiary-30: rgb(140, 28, 100) !important; + --pwt-color-tertiary-20: rgb(108, 12, 78) !important; + --pwt-color-tertiary-15: rgb(88, 4, 62) !important; + --pwt-color-tertiary-10: rgb(68, 0, 48) !important; + --pwt-color-tertiary-5: rgb(45, 0, 30) !important; + --pwt-color-tertiary-0: rgb(0, 0, 0) !important; + + /* Success — Dracula Green (#50fa7b) tonal scale */ + --pwt-color-success-100: rgb(255, 255, 255) !important; + --pwt-color-success-99: rgb(240, 255, 245) !important; + --pwt-color-success-95: rgb(200, 255, 215) !important; + --pwt-color-success-90: rgb(140, 255, 175) !important; + --pwt-color-success-80: rgb(80, 250, 123) !important; + --pwt-color-success-70: rgb(55, 220, 98) !important; + --pwt-color-success-60: rgb(30, 190, 75) !important; + --pwt-color-success-50: rgb(10, 160, 55) !important; + --pwt-color-success-40: rgb(0, 130, 40) !important; + --pwt-color-success-30: rgb(0, 100, 28) !important; + --pwt-color-success-20: rgb(0, 72, 18) !important; + --pwt-color-success-15: rgb(0, 55, 12) !important; + --pwt-color-success-10: rgb(0, 40, 8) !important; + --pwt-color-success-5: rgb(0, 25, 4) !important; + --pwt-color-success-0: rgb(0, 0, 0) !important; + + /* Error — Dracula Red (#ff5555) tonal scale */ + --pwt-color-error-100: rgb(255, 255, 255) !important; + --pwt-color-error-99: rgb(255, 248, 248) !important; + --pwt-color-error-95: rgb(255, 230, 230) !important; + --pwt-color-error-90: rgb(255, 205, 205) !important; + --pwt-color-error-80: rgb(255, 150, 150) !important; + --pwt-color-error-70: rgb(255, 110, 110) !important; + --pwt-color-error-60: rgb(255, 85, 85) !important; + --pwt-color-error-50: rgb(230, 60, 60) !important; + --pwt-color-error-40: rgb(200, 38, 38) !important; + --pwt-color-error-30: rgb(168, 16, 16) !important; + --pwt-color-error-20: rgb(120, 10, 10) !important; + --pwt-color-error-15: rgb(95, 5, 5) !important; + --pwt-color-error-10: rgb(72, 0, 0) !important; + --pwt-color-error-5: rgb(48, 0, 0) !important; + --pwt-color-error-0: rgb(0, 0, 0) !important; + + /* Warning — Dracula Yellow (#f1fa8c) tonal scale */ + --pwt-color-warning-100: rgb(255, 255, 255) !important; + --pwt-color-warning-99: rgb(255, 254, 248) !important; + --pwt-color-warning-95: rgb(252, 255, 210) !important; + --pwt-color-warning-90: rgb(245, 252, 160) !important; + --pwt-color-warning-80: rgb(241, 250, 140) !important; + --pwt-color-warning-70: rgb(218, 228, 100) !important; + --pwt-color-warning-60: rgb(195, 205, 65) !important; + --pwt-color-warning-50: rgb(170, 180, 35) !important; + --pwt-color-warning-40: rgb(140, 150, 15) !important; + --pwt-color-warning-30: rgb(110, 118, 0) !important; + --pwt-color-warning-20: rgb(80, 85, 0) !important; + --pwt-color-warning-15: rgb(60, 65, 0) !important; + --pwt-color-warning-10: rgb(42, 46, 0) !important; + --pwt-color-warning-5: rgb(25, 28, 0) !important; + --pwt-color-warning-0: rgb(0, 0, 0) !important; + + + /* Neutral — Dracula Green (forest-tinted) Background/Surface scale */ + --pwt-color-neutral-100: rgb(248, 248, 242) !important; + --pwt-color-neutral-99: rgb(238, 242, 240) !important; + --pwt-color-neutral-95: rgb(215, 225, 218) !important; + --pwt-color-neutral-90: rgb(200, 215, 205) !important; + --pwt-color-neutral-80: rgb(165, 185, 175) !important; + --pwt-color-neutral-70: rgb(130, 155, 145) !important; + --pwt-color-neutral-60: rgb(100, 130, 118) !important; + --pwt-color-neutral-50: rgb(75, 105, 92) !important; + --pwt-color-neutral-40: rgb(60, 85, 72) !important; + --pwt-color-neutral-30: rgb(46, 68, 56) !important; + --pwt-color-neutral-20: rgb(28, 40, 32) !important; + --pwt-color-neutral-15: rgb(22, 32, 26) !important; + --pwt-color-neutral-10: rgb(16, 24, 20) !important; + --pwt-color-neutral-5: rgb(10, 15, 12) !important; + --pwt-color-neutral-0: rgb(0, 0, 0) !important; + + /* Neutral Alt — Dracula Green Comment tones */ + --pwt-color-neutral-alt-100: rgb(248, 248, 242) !important; + --pwt-color-neutral-alt-99: rgb(238, 242, 240) !important; + --pwt-color-neutral-alt-95: rgb(218, 228, 222) !important; + --pwt-color-neutral-alt-90: rgb(200, 212, 205) !important; + --pwt-color-neutral-alt-80: rgb(168, 182, 175) !important; + --pwt-color-neutral-alt-70: rgb(135, 152, 145) !important; + --pwt-color-neutral-alt-60: rgb(105, 125, 118) !important; + --pwt-color-neutral-alt-50: rgb(80, 100, 92) !important; + --pwt-color-neutral-alt-40: rgb(62, 82, 72) !important; + --pwt-color-neutral-alt-30: rgb(48, 65, 55) !important; + --pwt-color-neutral-alt-20: rgb(32, 45, 36) !important; + --pwt-color-neutral-alt-15: rgb(25, 36, 28) !important; + --pwt-color-neutral-alt-10: rgb(18, 28, 22) !important; + --pwt-color-neutral-alt-5: rgb(10, 16, 12) !important; + --pwt-color-neutral-alt-0: rgb(0, 0, 0) !important; +} +/* ===== Semantic Color Remapping (darker surfaces) ===== */ +:root.pwt-dark-mode { + --pwt-color-surface: var(--pwt-color-neutral-10) !important; + --pwt-color-on-surface: var(--pwt-color-neutral-95) !important; + --pwt-color-surface-container: var(--pwt-color-neutral-15) !important; + --pwt-color-on-surface-container: var(--pwt-color-neutral-95) !important; + --pwt-color-neutral: var(--pwt-color-neutral-15) !important; + --pwt-color-on-neutral: var(--pwt-color-neutral-95) !important; + --pwt-color-neutral-container: var(--pwt-color-neutral-10) !important; + --pwt-color-on-neutral-container: var(--pwt-color-neutral-95) !important; + --pwt-color-dark-surface: var(--pwt-color-neutral-10) !important; + --pwt-color-on-dark-surface: var(--pwt-color-neutral-95) !important; + --pwt-color-dark-surface-container: var(--pwt-color-neutral-15) !important; + --pwt-color-on-dark-surface-container: var(--pwt-color-neutral-95) !important; + --pwt-color-neutral-alt: var(--pwt-color-neutral-alt-15) !important; + --pwt-color-on-neutral-alt: var(--pwt-color-neutral-alt-80) !important; + --pwt-color-neutral-alt-container: var(--pwt-color-neutral-alt-10) !important; + --pwt-color-on-neutral-alt-container: var(--pwt-color-neutral-alt-80) !important; + --pwt-color-background: var(--pwt-color-neutral-10) !important; + --pwt-color-inverse-surface: var(--pwt-color-neutral-80) !important; + --pwt-color-on-inverse-surface: var(--pwt-color-neutral-10) !important; + --pwt-color-border: var(--pwt-color-neutral-alt-30) !important; + --pwt-color-shadow: var(--pwt-color-neutral-0) !important; + background: var(--pwt-color-neutral-10) !important; + color: var(--pwt-color-neutral-95) !important; +} + +body { + background-color: var(--pwt-color-neutral-10) !important; +} diff --git a/themes/pdm/theme-dracula-midnight.css b/themes/pdm/theme-dracula-midnight.css new file mode 100644 index 0000000..0740050 --- /dev/null +++ b/themes/pdm/theme-dracula-midnight.css @@ -0,0 +1,182 @@ +/*!Dracula Midnight*/ +/* + * ProxMorph PDM Theme: Dracula Midnight + * Overrides the PWT Material Design tonal color system with Dracula Midnight palette + * Version: 1.0.0 + * Author: ProxMorph / Dracula Theme (https://draculatheme.com) + * + * ─── Dracula Midnight Palette ───────────────────────────────── + * Background: #191a21 Accent: #bd93f9 (Purple) + * Foreground: #f8f8f2 Comment: #6272a4 + */ + +/* ===== Tonal Color Overrides ===== */ +:root { + /* Primary — Dracula Purple (#bd93f9) tonal scale */ + --pwt-color-primary-100: rgb(255, 255, 255) !important; + --pwt-color-primary-99: rgb(252, 248, 255) !important; + --pwt-color-primary-95: rgb(240, 230, 255) !important; + --pwt-color-primary-90: rgb(225, 210, 255) !important; + --pwt-color-primary-80: rgb(189, 147, 249) !important; + --pwt-color-primary-70: rgb(163, 120, 230) !important; + --pwt-color-primary-60: rgb(137, 95, 210) !important; + --pwt-color-primary-50: rgb(112, 72, 190) !important; + --pwt-color-primary-40: rgb(88, 52, 168) !important; + --pwt-color-primary-30: rgb(65, 35, 140) !important; + --pwt-color-primary-20: rgb(46, 20, 110) !important; + --pwt-color-primary-15: rgb(36, 12, 90) !important; + --pwt-color-primary-10: rgb(28, 5, 72) !important; + --pwt-color-primary-5: rgb(18, 2, 48) !important; + --pwt-color-primary-0: rgb(0, 0, 0) !important; + + + /* Secondary — Dracula Comment/Overlay (#6272a4) tonal scale */ + --pwt-color-secondary-100: rgb(255, 255, 255) !important; + --pwt-color-secondary-99: rgb(248, 250, 255) !important; + --pwt-color-secondary-95: rgb(230, 236, 252) !important; + --pwt-color-secondary-90: rgb(210, 220, 245) !important; + --pwt-color-secondary-80: rgb(178, 196, 230) !important; + --pwt-color-secondary-70: rgb(146, 163, 200) !important; + --pwt-color-secondary-60: rgb(118, 137, 180) !important; + --pwt-color-secondary-50: rgb(98, 114, 164) !important; + --pwt-color-secondary-40: rgb(78, 94, 140) !important; + --pwt-color-secondary-30: rgb(58, 72, 115) !important; + --pwt-color-secondary-20: rgb(40, 52, 90) !important; + --pwt-color-secondary-15: rgb(32, 42, 75) !important; + --pwt-color-secondary-10: rgb(24, 32, 60) !important; + --pwt-color-secondary-5: rgb(16, 20, 42) !important; + --pwt-color-secondary-0: rgb(0, 0, 0) !important; + + /* Tertiary — Dracula Pink (#ff79c6) tonal scale */ + --pwt-color-tertiary-100: rgb(255, 255, 255) !important; + --pwt-color-tertiary-99: rgb(255, 248, 252) !important; + --pwt-color-tertiary-95: rgb(255, 234, 244) !important; + --pwt-color-tertiary-90: rgb(255, 210, 232) !important; + --pwt-color-tertiary-80: rgb(255, 165, 210) !important; + --pwt-color-tertiary-70: rgb(255, 121, 198) !important; + --pwt-color-tertiary-60: rgb(230, 95, 175) !important; + --pwt-color-tertiary-50: rgb(200, 70, 150) !important; + --pwt-color-tertiary-40: rgb(170, 48, 125) !important; + --pwt-color-tertiary-30: rgb(140, 28, 100) !important; + --pwt-color-tertiary-20: rgb(108, 12, 78) !important; + --pwt-color-tertiary-15: rgb(88, 4, 62) !important; + --pwt-color-tertiary-10: rgb(68, 0, 48) !important; + --pwt-color-tertiary-5: rgb(45, 0, 30) !important; + --pwt-color-tertiary-0: rgb(0, 0, 0) !important; + + /* Success — Dracula Green (#50fa7b) tonal scale */ + --pwt-color-success-100: rgb(255, 255, 255) !important; + --pwt-color-success-99: rgb(240, 255, 245) !important; + --pwt-color-success-95: rgb(200, 255, 215) !important; + --pwt-color-success-90: rgb(140, 255, 175) !important; + --pwt-color-success-80: rgb(80, 250, 123) !important; + --pwt-color-success-70: rgb(55, 220, 98) !important; + --pwt-color-success-60: rgb(30, 190, 75) !important; + --pwt-color-success-50: rgb(10, 160, 55) !important; + --pwt-color-success-40: rgb(0, 130, 40) !important; + --pwt-color-success-30: rgb(0, 100, 28) !important; + --pwt-color-success-20: rgb(0, 72, 18) !important; + --pwt-color-success-15: rgb(0, 55, 12) !important; + --pwt-color-success-10: rgb(0, 40, 8) !important; + --pwt-color-success-5: rgb(0, 25, 4) !important; + --pwt-color-success-0: rgb(0, 0, 0) !important; + + /* Error — Dracula Red (#ff5555) tonal scale */ + --pwt-color-error-100: rgb(255, 255, 255) !important; + --pwt-color-error-99: rgb(255, 248, 248) !important; + --pwt-color-error-95: rgb(255, 230, 230) !important; + --pwt-color-error-90: rgb(255, 205, 205) !important; + --pwt-color-error-80: rgb(255, 150, 150) !important; + --pwt-color-error-70: rgb(255, 110, 110) !important; + --pwt-color-error-60: rgb(255, 85, 85) !important; + --pwt-color-error-50: rgb(230, 60, 60) !important; + --pwt-color-error-40: rgb(200, 38, 38) !important; + --pwt-color-error-30: rgb(168, 16, 16) !important; + --pwt-color-error-20: rgb(120, 10, 10) !important; + --pwt-color-error-15: rgb(95, 5, 5) !important; + --pwt-color-error-10: rgb(72, 0, 0) !important; + --pwt-color-error-5: rgb(48, 0, 0) !important; + --pwt-color-error-0: rgb(0, 0, 0) !important; + + /* Warning — Dracula Yellow (#f1fa8c) tonal scale */ + --pwt-color-warning-100: rgb(255, 255, 255) !important; + --pwt-color-warning-99: rgb(255, 254, 248) !important; + --pwt-color-warning-95: rgb(252, 255, 210) !important; + --pwt-color-warning-90: rgb(245, 252, 160) !important; + --pwt-color-warning-80: rgb(241, 250, 140) !important; + --pwt-color-warning-70: rgb(218, 228, 100) !important; + --pwt-color-warning-60: rgb(195, 205, 65) !important; + --pwt-color-warning-50: rgb(170, 180, 35) !important; + --pwt-color-warning-40: rgb(140, 150, 15) !important; + --pwt-color-warning-30: rgb(110, 118, 0) !important; + --pwt-color-warning-20: rgb(80, 85, 0) !important; + --pwt-color-warning-15: rgb(60, 65, 0) !important; + --pwt-color-warning-10: rgb(42, 46, 0) !important; + --pwt-color-warning-5: rgb(25, 28, 0) !important; + --pwt-color-warning-0: rgb(0, 0, 0) !important; + + + /* Neutral — Dracula Midnight (darker) Background/Surface scale */ + --pwt-color-neutral-100: rgb(248, 248, 242) !important; + --pwt-color-neutral-99: rgb(240, 240, 236) !important; + --pwt-color-neutral-95: rgb(220, 222, 218) !important; + --pwt-color-neutral-90: rgb(208, 212, 224) !important; + --pwt-color-neutral-80: rgb(176, 181, 200) !important; + --pwt-color-neutral-70: rgb(146, 152, 184) !important; + --pwt-color-neutral-60: rgb(124, 131, 160) !important; + --pwt-color-neutral-50: rgb(98, 114, 164) !important; + --pwt-color-neutral-40: rgb(76, 80, 102) !important; + --pwt-color-neutral-30: rgb(55, 58, 76) !important; + --pwt-color-neutral-20: rgb(36, 38, 50) !important; + --pwt-color-neutral-15: rgb(28, 30, 40) !important; + --pwt-color-neutral-10: rgb(22, 23, 32) !important; + --pwt-color-neutral-5: rgb(16, 16, 22) !important; + --pwt-color-neutral-0: rgb(0, 0, 0) !important; + + /* Neutral Alt — Dracula Midnight Comment tones */ + --pwt-color-neutral-alt-100: rgb(248, 248, 242) !important; + --pwt-color-neutral-alt-99: rgb(242, 244, 255) !important; + --pwt-color-neutral-alt-95: rgb(225, 230, 248) !important; + --pwt-color-neutral-alt-90: rgb(210, 216, 238) !important; + --pwt-color-neutral-alt-80: rgb(178, 186, 215) !important; + --pwt-color-neutral-alt-70: rgb(146, 156, 190) !important; + --pwt-color-neutral-alt-60: rgb(118, 128, 165) !important; + --pwt-color-neutral-alt-50: rgb(98, 114, 164) !important; + --pwt-color-neutral-alt-40: rgb(72, 82, 120) !important; + --pwt-color-neutral-alt-30: rgb(52, 60, 95) !important; + --pwt-color-neutral-alt-20: rgb(36, 42, 70) !important; + --pwt-color-neutral-alt-15: rgb(28, 32, 55) !important; + --pwt-color-neutral-alt-10: rgb(22, 25, 42) !important; + --pwt-color-neutral-alt-5: rgb(14, 15, 28) !important; + --pwt-color-neutral-alt-0: rgb(0, 0, 0) !important; +} +/* ===== Semantic Color Remapping (darker surfaces) ===== */ +:root.pwt-dark-mode { + --pwt-color-surface: var(--pwt-color-neutral-10) !important; + --pwt-color-on-surface: var(--pwt-color-neutral-95) !important; + --pwt-color-surface-container: var(--pwt-color-neutral-15) !important; + --pwt-color-on-surface-container: var(--pwt-color-neutral-95) !important; + --pwt-color-neutral: var(--pwt-color-neutral-15) !important; + --pwt-color-on-neutral: var(--pwt-color-neutral-95) !important; + --pwt-color-neutral-container: var(--pwt-color-neutral-10) !important; + --pwt-color-on-neutral-container: var(--pwt-color-neutral-95) !important; + --pwt-color-dark-surface: var(--pwt-color-neutral-10) !important; + --pwt-color-on-dark-surface: var(--pwt-color-neutral-95) !important; + --pwt-color-dark-surface-container: var(--pwt-color-neutral-15) !important; + --pwt-color-on-dark-surface-container: var(--pwt-color-neutral-95) !important; + --pwt-color-neutral-alt: var(--pwt-color-neutral-alt-15) !important; + --pwt-color-on-neutral-alt: var(--pwt-color-neutral-alt-80) !important; + --pwt-color-neutral-alt-container: var(--pwt-color-neutral-alt-10) !important; + --pwt-color-on-neutral-alt-container: var(--pwt-color-neutral-alt-80) !important; + --pwt-color-background: var(--pwt-color-neutral-10) !important; + --pwt-color-inverse-surface: var(--pwt-color-neutral-80) !important; + --pwt-color-on-inverse-surface: var(--pwt-color-neutral-10) !important; + --pwt-color-border: var(--pwt-color-neutral-alt-30) !important; + --pwt-color-shadow: var(--pwt-color-neutral-0) !important; + background: var(--pwt-color-neutral-10) !important; + color: var(--pwt-color-neutral-95) !important; +} + +body { + background-color: var(--pwt-color-neutral-10) !important; +} diff --git a/themes/pdm/theme-dracula-orange.css b/themes/pdm/theme-dracula-orange.css new file mode 100644 index 0000000..e6eb9e3 --- /dev/null +++ b/themes/pdm/theme-dracula-orange.css @@ -0,0 +1,181 @@ +/*!Dracula Orange*/ +/* + * ProxMorph PDM Theme: Dracula Orange + * Overrides the PWT Material Design tonal color system with Dracula Orange palette + * Version: 1.0.0 + * Author: ProxMorph / Dracula Theme (https://draculatheme.com) + * + * ─── Dracula Orange Palette ─────────────────────────────────── + * Background: #26201b Accent: #ffb86c (Orange) + * Foreground: #f8f8f2 Comment: #6272a4 + */ + +/* ===== Tonal Color Overrides ===== */ +:root { + /* Primary — Dracula Orange (#ffb86c) tonal scale */ + --pwt-color-primary-100: rgb(255, 255, 255) !important; + --pwt-color-primary-99: rgb(255, 252, 248) !important; + --pwt-color-primary-95: rgb(255, 240, 222) !important; + --pwt-color-primary-90: rgb(255, 225, 185) !important; + --pwt-color-primary-80: rgb(255, 184, 108) !important; + --pwt-color-primary-70: rgb(230, 158, 82) !important; + --pwt-color-primary-60: rgb(205, 132, 58) !important; + --pwt-color-primary-50: rgb(180, 108, 38) !important; + --pwt-color-primary-40: rgb(152, 86, 22) !important; + --pwt-color-primary-30: rgb(122, 65, 10) !important; + --pwt-color-primary-20: rgb(90, 46, 2) !important; + --pwt-color-primary-15: rgb(72, 36, 0) !important; + --pwt-color-primary-10: rgb(55, 26, 0) !important; + --pwt-color-primary-5: rgb(35, 15, 0) !important; + --pwt-color-primary-0: rgb(0, 0, 0) !important; + + /* Secondary — Dracula Comment/Overlay (#6272a4) tonal scale */ + --pwt-color-secondary-100: rgb(255, 255, 255) !important; + --pwt-color-secondary-99: rgb(248, 250, 255) !important; + --pwt-color-secondary-95: rgb(230, 236, 252) !important; + --pwt-color-secondary-90: rgb(210, 220, 245) !important; + --pwt-color-secondary-80: rgb(178, 196, 230) !important; + --pwt-color-secondary-70: rgb(146, 163, 200) !important; + --pwt-color-secondary-60: rgb(118, 137, 180) !important; + --pwt-color-secondary-50: rgb(98, 114, 164) !important; + --pwt-color-secondary-40: rgb(78, 94, 140) !important; + --pwt-color-secondary-30: rgb(58, 72, 115) !important; + --pwt-color-secondary-20: rgb(40, 52, 90) !important; + --pwt-color-secondary-15: rgb(32, 42, 75) !important; + --pwt-color-secondary-10: rgb(24, 32, 60) !important; + --pwt-color-secondary-5: rgb(16, 20, 42) !important; + --pwt-color-secondary-0: rgb(0, 0, 0) !important; + + /* Tertiary — Dracula Pink (#ff79c6) tonal scale */ + --pwt-color-tertiary-100: rgb(255, 255, 255) !important; + --pwt-color-tertiary-99: rgb(255, 248, 252) !important; + --pwt-color-tertiary-95: rgb(255, 234, 244) !important; + --pwt-color-tertiary-90: rgb(255, 210, 232) !important; + --pwt-color-tertiary-80: rgb(255, 165, 210) !important; + --pwt-color-tertiary-70: rgb(255, 121, 198) !important; + --pwt-color-tertiary-60: rgb(230, 95, 175) !important; + --pwt-color-tertiary-50: rgb(200, 70, 150) !important; + --pwt-color-tertiary-40: rgb(170, 48, 125) !important; + --pwt-color-tertiary-30: rgb(140, 28, 100) !important; + --pwt-color-tertiary-20: rgb(108, 12, 78) !important; + --pwt-color-tertiary-15: rgb(88, 4, 62) !important; + --pwt-color-tertiary-10: rgb(68, 0, 48) !important; + --pwt-color-tertiary-5: rgb(45, 0, 30) !important; + --pwt-color-tertiary-0: rgb(0, 0, 0) !important; + + /* Success — Dracula Green (#50fa7b) tonal scale */ + --pwt-color-success-100: rgb(255, 255, 255) !important; + --pwt-color-success-99: rgb(240, 255, 245) !important; + --pwt-color-success-95: rgb(200, 255, 215) !important; + --pwt-color-success-90: rgb(140, 255, 175) !important; + --pwt-color-success-80: rgb(80, 250, 123) !important; + --pwt-color-success-70: rgb(55, 220, 98) !important; + --pwt-color-success-60: rgb(30, 190, 75) !important; + --pwt-color-success-50: rgb(10, 160, 55) !important; + --pwt-color-success-40: rgb(0, 130, 40) !important; + --pwt-color-success-30: rgb(0, 100, 28) !important; + --pwt-color-success-20: rgb(0, 72, 18) !important; + --pwt-color-success-15: rgb(0, 55, 12) !important; + --pwt-color-success-10: rgb(0, 40, 8) !important; + --pwt-color-success-5: rgb(0, 25, 4) !important; + --pwt-color-success-0: rgb(0, 0, 0) !important; + + /* Error — Dracula Red (#ff5555) tonal scale */ + --pwt-color-error-100: rgb(255, 255, 255) !important; + --pwt-color-error-99: rgb(255, 248, 248) !important; + --pwt-color-error-95: rgb(255, 230, 230) !important; + --pwt-color-error-90: rgb(255, 205, 205) !important; + --pwt-color-error-80: rgb(255, 150, 150) !important; + --pwt-color-error-70: rgb(255, 110, 110) !important; + --pwt-color-error-60: rgb(255, 85, 85) !important; + --pwt-color-error-50: rgb(230, 60, 60) !important; + --pwt-color-error-40: rgb(200, 38, 38) !important; + --pwt-color-error-30: rgb(168, 16, 16) !important; + --pwt-color-error-20: rgb(120, 10, 10) !important; + --pwt-color-error-15: rgb(95, 5, 5) !important; + --pwt-color-error-10: rgb(72, 0, 0) !important; + --pwt-color-error-5: rgb(48, 0, 0) !important; + --pwt-color-error-0: rgb(0, 0, 0) !important; + + /* Warning — Dracula Yellow (#f1fa8c) tonal scale */ + --pwt-color-warning-100: rgb(255, 255, 255) !important; + --pwt-color-warning-99: rgb(255, 254, 248) !important; + --pwt-color-warning-95: rgb(252, 255, 210) !important; + --pwt-color-warning-90: rgb(245, 252, 160) !important; + --pwt-color-warning-80: rgb(241, 250, 140) !important; + --pwt-color-warning-70: rgb(218, 228, 100) !important; + --pwt-color-warning-60: rgb(195, 205, 65) !important; + --pwt-color-warning-50: rgb(170, 180, 35) !important; + --pwt-color-warning-40: rgb(140, 150, 15) !important; + --pwt-color-warning-30: rgb(110, 118, 0) !important; + --pwt-color-warning-20: rgb(80, 85, 0) !important; + --pwt-color-warning-15: rgb(60, 65, 0) !important; + --pwt-color-warning-10: rgb(42, 46, 0) !important; + --pwt-color-warning-5: rgb(25, 28, 0) !important; + --pwt-color-warning-0: rgb(0, 0, 0) !important; + + + /* Neutral — Dracula Orange (warm-tinted) Background/Surface scale */ + --pwt-color-neutral-100: rgb(248, 248, 242) !important; + --pwt-color-neutral-99: rgb(242, 240, 236) !important; + --pwt-color-neutral-95: rgb(228, 222, 215) !important; + --pwt-color-neutral-90: rgb(212, 205, 198) !important; + --pwt-color-neutral-80: rgb(180, 172, 162) !important; + --pwt-color-neutral-70: rgb(148, 140, 130) !important; + --pwt-color-neutral-60: rgb(120, 112, 102) !important; + --pwt-color-neutral-50: rgb(95, 88, 78) !important; + --pwt-color-neutral-40: rgb(75, 68, 58) !important; + --pwt-color-neutral-30: rgb(58, 52, 44) !important; + --pwt-color-neutral-20: rgb(38, 32, 27) !important; + --pwt-color-neutral-15: rgb(30, 26, 22) !important; + --pwt-color-neutral-10: rgb(22, 20, 17) !important; + --pwt-color-neutral-5: rgb(14, 12, 10) !important; + --pwt-color-neutral-0: rgb(0, 0, 0) !important; + + /* Neutral Alt — Dracula Orange Comment tones */ + --pwt-color-neutral-alt-100: rgb(248, 248, 242) !important; + --pwt-color-neutral-alt-99: rgb(242, 240, 236) !important; + --pwt-color-neutral-alt-95: rgb(230, 225, 218) !important; + --pwt-color-neutral-alt-90: rgb(215, 208, 200) !important; + --pwt-color-neutral-alt-80: rgb(182, 175, 166) !important; + --pwt-color-neutral-alt-70: rgb(150, 142, 132) !important; + --pwt-color-neutral-alt-60: rgb(122, 115, 105) !important; + --pwt-color-neutral-alt-50: rgb(98, 90, 80) !important; + --pwt-color-neutral-alt-40: rgb(78, 70, 60) !important; + --pwt-color-neutral-alt-30: rgb(60, 54, 45) !important; + --pwt-color-neutral-alt-20: rgb(42, 36, 30) !important; + --pwt-color-neutral-alt-15: rgb(34, 28, 24) !important; + --pwt-color-neutral-alt-10: rgb(25, 22, 18) !important; + --pwt-color-neutral-alt-5: rgb(16, 14, 11) !important; + --pwt-color-neutral-alt-0: rgb(0, 0, 0) !important; +} +/* ===== Semantic Color Remapping (darker surfaces) ===== */ +:root.pwt-dark-mode { + --pwt-color-surface: var(--pwt-color-neutral-10) !important; + --pwt-color-on-surface: var(--pwt-color-neutral-95) !important; + --pwt-color-surface-container: var(--pwt-color-neutral-15) !important; + --pwt-color-on-surface-container: var(--pwt-color-neutral-95) !important; + --pwt-color-neutral: var(--pwt-color-neutral-15) !important; + --pwt-color-on-neutral: var(--pwt-color-neutral-95) !important; + --pwt-color-neutral-container: var(--pwt-color-neutral-10) !important; + --pwt-color-on-neutral-container: var(--pwt-color-neutral-95) !important; + --pwt-color-dark-surface: var(--pwt-color-neutral-10) !important; + --pwt-color-on-dark-surface: var(--pwt-color-neutral-95) !important; + --pwt-color-dark-surface-container: var(--pwt-color-neutral-15) !important; + --pwt-color-on-dark-surface-container: var(--pwt-color-neutral-95) !important; + --pwt-color-neutral-alt: var(--pwt-color-neutral-alt-15) !important; + --pwt-color-on-neutral-alt: var(--pwt-color-neutral-alt-80) !important; + --pwt-color-neutral-alt-container: var(--pwt-color-neutral-alt-10) !important; + --pwt-color-on-neutral-alt-container: var(--pwt-color-neutral-alt-80) !important; + --pwt-color-background: var(--pwt-color-neutral-10) !important; + --pwt-color-inverse-surface: var(--pwt-color-neutral-80) !important; + --pwt-color-on-inverse-surface: var(--pwt-color-neutral-10) !important; + --pwt-color-border: var(--pwt-color-neutral-alt-30) !important; + --pwt-color-shadow: var(--pwt-color-neutral-0) !important; + background: var(--pwt-color-neutral-10) !important; + color: var(--pwt-color-neutral-95) !important; +} + +body { + background-color: var(--pwt-color-neutral-10) !important; +} diff --git a/themes/pdm/theme-dracula-pink.css b/themes/pdm/theme-dracula-pink.css new file mode 100644 index 0000000..2209157 --- /dev/null +++ b/themes/pdm/theme-dracula-pink.css @@ -0,0 +1,181 @@ +/*!Dracula Pink*/ +/* + * ProxMorph PDM Theme: Dracula Pink + * Overrides the PWT Material Design tonal color system with Dracula Pink palette + * Version: 1.0.0 + * Author: ProxMorph / Dracula Theme (https://draculatheme.com) + * + * ─── Dracula Pink Palette ───────────────────────────────────── + * Background: #282a36 Accent: #ff79c6 (Pink) + * Foreground: #f8f8f2 Comment: #6272a4 + */ + +/* ===== Tonal Color Overrides ===== */ +:root { + /* Primary — Dracula Pink (#ff79c6) tonal scale */ + --pwt-color-primary-100: rgb(255, 255, 255) !important; + --pwt-color-primary-99: rgb(255, 248, 252) !important; + --pwt-color-primary-95: rgb(255, 230, 242) !important; + --pwt-color-primary-90: rgb(255, 195, 225) !important; + --pwt-color-primary-80: rgb(255, 121, 198) !important; + --pwt-color-primary-70: rgb(230, 95, 175) !important; + --pwt-color-primary-60: rgb(200, 70, 150) !important; + --pwt-color-primary-50: rgb(170, 50, 125) !important; + --pwt-color-primary-40: rgb(140, 35, 100) !important; + --pwt-color-primary-30: rgb(110, 20, 78) !important; + --pwt-color-primary-20: rgb(82, 10, 58) !important; + --pwt-color-primary-15: rgb(65, 4, 45) !important; + --pwt-color-primary-10: rgb(50, 0, 35) !important; + --pwt-color-primary-5: rgb(30, 0, 20) !important; + --pwt-color-primary-0: rgb(0, 0, 0) !important; + + /* Secondary — Dracula Comment/Overlay (#6272a4) tonal scale */ + --pwt-color-secondary-100: rgb(255, 255, 255) !important; + --pwt-color-secondary-99: rgb(248, 250, 255) !important; + --pwt-color-secondary-95: rgb(230, 236, 252) !important; + --pwt-color-secondary-90: rgb(210, 220, 245) !important; + --pwt-color-secondary-80: rgb(178, 196, 230) !important; + --pwt-color-secondary-70: rgb(146, 163, 200) !important; + --pwt-color-secondary-60: rgb(118, 137, 180) !important; + --pwt-color-secondary-50: rgb(98, 114, 164) !important; + --pwt-color-secondary-40: rgb(78, 94, 140) !important; + --pwt-color-secondary-30: rgb(58, 72, 115) !important; + --pwt-color-secondary-20: rgb(40, 52, 90) !important; + --pwt-color-secondary-15: rgb(32, 42, 75) !important; + --pwt-color-secondary-10: rgb(24, 32, 60) !important; + --pwt-color-secondary-5: rgb(16, 20, 42) !important; + --pwt-color-secondary-0: rgb(0, 0, 0) !important; + + /* Tertiary — Dracula Pink (#ff79c6) tonal scale */ + --pwt-color-tertiary-100: rgb(255, 255, 255) !important; + --pwt-color-tertiary-99: rgb(255, 248, 252) !important; + --pwt-color-tertiary-95: rgb(255, 234, 244) !important; + --pwt-color-tertiary-90: rgb(255, 210, 232) !important; + --pwt-color-tertiary-80: rgb(255, 165, 210) !important; + --pwt-color-tertiary-70: rgb(255, 121, 198) !important; + --pwt-color-tertiary-60: rgb(230, 95, 175) !important; + --pwt-color-tertiary-50: rgb(200, 70, 150) !important; + --pwt-color-tertiary-40: rgb(170, 48, 125) !important; + --pwt-color-tertiary-30: rgb(140, 28, 100) !important; + --pwt-color-tertiary-20: rgb(108, 12, 78) !important; + --pwt-color-tertiary-15: rgb(88, 4, 62) !important; + --pwt-color-tertiary-10: rgb(68, 0, 48) !important; + --pwt-color-tertiary-5: rgb(45, 0, 30) !important; + --pwt-color-tertiary-0: rgb(0, 0, 0) !important; + + /* Success — Dracula Green (#50fa7b) tonal scale */ + --pwt-color-success-100: rgb(255, 255, 255) !important; + --pwt-color-success-99: rgb(240, 255, 245) !important; + --pwt-color-success-95: rgb(200, 255, 215) !important; + --pwt-color-success-90: rgb(140, 255, 175) !important; + --pwt-color-success-80: rgb(80, 250, 123) !important; + --pwt-color-success-70: rgb(55, 220, 98) !important; + --pwt-color-success-60: rgb(30, 190, 75) !important; + --pwt-color-success-50: rgb(10, 160, 55) !important; + --pwt-color-success-40: rgb(0, 130, 40) !important; + --pwt-color-success-30: rgb(0, 100, 28) !important; + --pwt-color-success-20: rgb(0, 72, 18) !important; + --pwt-color-success-15: rgb(0, 55, 12) !important; + --pwt-color-success-10: rgb(0, 40, 8) !important; + --pwt-color-success-5: rgb(0, 25, 4) !important; + --pwt-color-success-0: rgb(0, 0, 0) !important; + + /* Error — Dracula Red (#ff5555) tonal scale */ + --pwt-color-error-100: rgb(255, 255, 255) !important; + --pwt-color-error-99: rgb(255, 248, 248) !important; + --pwt-color-error-95: rgb(255, 230, 230) !important; + --pwt-color-error-90: rgb(255, 205, 205) !important; + --pwt-color-error-80: rgb(255, 150, 150) !important; + --pwt-color-error-70: rgb(255, 110, 110) !important; + --pwt-color-error-60: rgb(255, 85, 85) !important; + --pwt-color-error-50: rgb(230, 60, 60) !important; + --pwt-color-error-40: rgb(200, 38, 38) !important; + --pwt-color-error-30: rgb(168, 16, 16) !important; + --pwt-color-error-20: rgb(120, 10, 10) !important; + --pwt-color-error-15: rgb(95, 5, 5) !important; + --pwt-color-error-10: rgb(72, 0, 0) !important; + --pwt-color-error-5: rgb(48, 0, 0) !important; + --pwt-color-error-0: rgb(0, 0, 0) !important; + + /* Warning — Dracula Yellow (#f1fa8c) tonal scale */ + --pwt-color-warning-100: rgb(255, 255, 255) !important; + --pwt-color-warning-99: rgb(255, 254, 248) !important; + --pwt-color-warning-95: rgb(252, 255, 210) !important; + --pwt-color-warning-90: rgb(245, 252, 160) !important; + --pwt-color-warning-80: rgb(241, 250, 140) !important; + --pwt-color-warning-70: rgb(218, 228, 100) !important; + --pwt-color-warning-60: rgb(195, 205, 65) !important; + --pwt-color-warning-50: rgb(170, 180, 35) !important; + --pwt-color-warning-40: rgb(140, 150, 15) !important; + --pwt-color-warning-30: rgb(110, 118, 0) !important; + --pwt-color-warning-20: rgb(80, 85, 0) !important; + --pwt-color-warning-15: rgb(60, 65, 0) !important; + --pwt-color-warning-10: rgb(42, 46, 0) !important; + --pwt-color-warning-5: rgb(25, 28, 0) !important; + --pwt-color-warning-0: rgb(0, 0, 0) !important; + + /* Neutral — Dracula Background/Surface scale */ + --pwt-color-neutral-100: rgb(248, 248, 242) !important; + --pwt-color-neutral-99: rgb(240, 240, 236) !important; + --pwt-color-neutral-95: rgb(220, 222, 218) !important; + --pwt-color-neutral-90: rgb(208, 212, 224) !important; + --pwt-color-neutral-80: rgb(176, 181, 200) !important; + --pwt-color-neutral-70: rgb(146, 152, 184) !important; + --pwt-color-neutral-60: rgb(124, 131, 160) !important; + --pwt-color-neutral-50: rgb(98, 114, 164) !important; + --pwt-color-neutral-40: rgb(86, 90, 114) !important; + --pwt-color-neutral-30: rgb(68, 71, 90) !important; + --pwt-color-neutral-20: rgb(40, 42, 54) !important; + --pwt-color-neutral-15: rgb(33, 34, 44) !important; + --pwt-color-neutral-10: rgb(30, 31, 41) !important; + --pwt-color-neutral-5: rgb(22, 23, 30) !important; + --pwt-color-neutral-0: rgb(0, 0, 0) !important; + + /* Neutral Alt — Dracula Comment tones */ + --pwt-color-neutral-alt-100: rgb(248, 248, 242) !important; + --pwt-color-neutral-alt-99: rgb(242, 244, 255) !important; + --pwt-color-neutral-alt-95: rgb(225, 230, 248) !important; + --pwt-color-neutral-alt-90: rgb(210, 216, 238) !important; + --pwt-color-neutral-alt-80: rgb(178, 186, 215) !important; + --pwt-color-neutral-alt-70: rgb(146, 156, 190) !important; + --pwt-color-neutral-alt-60: rgb(118, 128, 165) !important; + --pwt-color-neutral-alt-50: rgb(98, 114, 164) !important; + --pwt-color-neutral-alt-40: rgb(80, 90, 130) !important; + --pwt-color-neutral-alt-30: rgb(60, 68, 105) !important; + --pwt-color-neutral-alt-20: rgb(44, 50, 80) !important; + --pwt-color-neutral-alt-15: rgb(36, 40, 65) !important; + --pwt-color-neutral-alt-10: rgb(28, 32, 52) !important; + --pwt-color-neutral-alt-5: rgb(18, 20, 35) !important; + --pwt-color-neutral-alt-0: rgb(0, 0, 0) !important; +} + +/* ===== Semantic Color Remapping (darker surfaces) ===== */ +:root.pwt-dark-mode { + --pwt-color-surface: var(--pwt-color-neutral-10) !important; + --pwt-color-on-surface: var(--pwt-color-neutral-95) !important; + --pwt-color-surface-container: var(--pwt-color-neutral-15) !important; + --pwt-color-on-surface-container: var(--pwt-color-neutral-95) !important; + --pwt-color-neutral: var(--pwt-color-neutral-15) !important; + --pwt-color-on-neutral: var(--pwt-color-neutral-95) !important; + --pwt-color-neutral-container: var(--pwt-color-neutral-10) !important; + --pwt-color-on-neutral-container: var(--pwt-color-neutral-95) !important; + --pwt-color-dark-surface: var(--pwt-color-neutral-10) !important; + --pwt-color-on-dark-surface: var(--pwt-color-neutral-95) !important; + --pwt-color-dark-surface-container: var(--pwt-color-neutral-15) !important; + --pwt-color-on-dark-surface-container: var(--pwt-color-neutral-95) !important; + --pwt-color-neutral-alt: var(--pwt-color-neutral-alt-15) !important; + --pwt-color-on-neutral-alt: var(--pwt-color-neutral-alt-80) !important; + --pwt-color-neutral-alt-container: var(--pwt-color-neutral-alt-10) !important; + --pwt-color-on-neutral-alt-container: var(--pwt-color-neutral-alt-80) !important; + --pwt-color-background: var(--pwt-color-neutral-10) !important; + --pwt-color-inverse-surface: var(--pwt-color-neutral-80) !important; + --pwt-color-on-inverse-surface: var(--pwt-color-neutral-10) !important; + --pwt-color-border: var(--pwt-color-neutral-alt-30) !important; + --pwt-color-shadow: var(--pwt-color-neutral-0) !important; + background: var(--pwt-color-neutral-10) !important; + color: var(--pwt-color-neutral-95) !important; +} + +body { + background-color: var(--pwt-color-neutral-10) !important; +} diff --git a/themes/pdm/theme-dracula.css b/themes/pdm/theme-dracula.css new file mode 100644 index 0000000..33652a5 --- /dev/null +++ b/themes/pdm/theme-dracula.css @@ -0,0 +1,189 @@ +/*!Dracula*/ +/* + * ProxMorph PDM Theme: Dracula + * Overrides the PWt Material Design tonal color system with Dracula palette + * Version: 1.0.0 + * Author: ProxMorph / Dracula Theme (https://draculatheme.com) + * + * This file is injected into PDM via index.hbs and overrides the + * tonal color values from *-yew-style.css. The WASM dark/light mode + * selectors continue to work because they reference these tonal vars. + * + * ─── Dracula Specification Palette ───────────────────────────── + * Background: #282a36 Current Line: #44475a + * Foreground: #f8f8f2 Comment: #6272a4 + * Purple: #bd93f9 Pink: #ff79c6 + * Cyan: #8be9fd Green: #50fa7b + * Orange: #ffb86c Red: #ff5555 + * Yellow: #f1fa8c + */ + +/* ===== Tonal Color Overrides ===== */ +:root { + /* Primary — Dracula Purple (#bd93f9) tonal scale */ + --pwt-color-primary-100: rgb(255, 255, 255) !important; + --pwt-color-primary-99: rgb(252, 248, 255) !important; + --pwt-color-primary-95: rgb(240, 230, 255) !important; + --pwt-color-primary-90: rgb(225, 210, 255) !important; + --pwt-color-primary-80: rgb(189, 147, 249) !important; + --pwt-color-primary-70: rgb(163, 120, 230) !important; + --pwt-color-primary-60: rgb(137, 95, 210) !important; + --pwt-color-primary-50: rgb(112, 72, 190) !important; + --pwt-color-primary-40: rgb(88, 52, 168) !important; + --pwt-color-primary-30: rgb(65, 35, 140) !important; + --pwt-color-primary-20: rgb(46, 20, 110) !important; + --pwt-color-primary-15: rgb(36, 12, 90) !important; + --pwt-color-primary-10: rgb(28, 5, 72) !important; + --pwt-color-primary-5: rgb(18, 2, 48) !important; + --pwt-color-primary-0: rgb(0, 0, 0) !important; + + /* Secondary — Dracula Comment/Overlay (#6272a4) tonal scale */ + --pwt-color-secondary-100: rgb(255, 255, 255) !important; + --pwt-color-secondary-99: rgb(248, 250, 255) !important; + --pwt-color-secondary-95: rgb(230, 236, 252) !important; + --pwt-color-secondary-90: rgb(210, 220, 245) !important; + --pwt-color-secondary-80: rgb(178, 196, 230) !important; + --pwt-color-secondary-70: rgb(146, 163, 200) !important; + --pwt-color-secondary-60: rgb(118, 137, 180) !important; + --pwt-color-secondary-50: rgb(98, 114, 164) !important; + --pwt-color-secondary-40: rgb(78, 94, 140) !important; + --pwt-color-secondary-30: rgb(58, 72, 115) !important; + --pwt-color-secondary-20: rgb(40, 52, 90) !important; + --pwt-color-secondary-15: rgb(32, 42, 75) !important; + --pwt-color-secondary-10: rgb(24, 32, 60) !important; + --pwt-color-secondary-5: rgb(16, 20, 42) !important; + --pwt-color-secondary-0: rgb(0, 0, 0) !important; + + /* Tertiary — Dracula Pink (#ff79c6) tonal scale */ + --pwt-color-tertiary-100: rgb(255, 255, 255) !important; + --pwt-color-tertiary-99: rgb(255, 248, 252) !important; + --pwt-color-tertiary-95: rgb(255, 234, 244) !important; + --pwt-color-tertiary-90: rgb(255, 210, 232) !important; + --pwt-color-tertiary-80: rgb(255, 165, 210) !important; + --pwt-color-tertiary-70: rgb(255, 121, 198) !important; + --pwt-color-tertiary-60: rgb(230, 95, 175) !important; + --pwt-color-tertiary-50: rgb(200, 70, 150) !important; + --pwt-color-tertiary-40: rgb(170, 48, 125) !important; + --pwt-color-tertiary-30: rgb(140, 28, 100) !important; + --pwt-color-tertiary-20: rgb(108, 12, 78) !important; + --pwt-color-tertiary-15: rgb(88, 4, 62) !important; + --pwt-color-tertiary-10: rgb(68, 0, 48) !important; + --pwt-color-tertiary-5: rgb(45, 0, 30) !important; + --pwt-color-tertiary-0: rgb(0, 0, 0) !important; + + /* Success — Dracula Green (#50fa7b) tonal scale */ + --pwt-color-success-100: rgb(255, 255, 255) !important; + --pwt-color-success-99: rgb(240, 255, 245) !important; + --pwt-color-success-95: rgb(200, 255, 215) !important; + --pwt-color-success-90: rgb(140, 255, 175) !important; + --pwt-color-success-80: rgb(80, 250, 123) !important; + --pwt-color-success-70: rgb(55, 220, 98) !important; + --pwt-color-success-60: rgb(30, 190, 75) !important; + --pwt-color-success-50: rgb(10, 160, 55) !important; + --pwt-color-success-40: rgb(0, 130, 40) !important; + --pwt-color-success-30: rgb(0, 100, 28) !important; + --pwt-color-success-20: rgb(0, 72, 18) !important; + --pwt-color-success-15: rgb(0, 55, 12) !important; + --pwt-color-success-10: rgb(0, 40, 8) !important; + --pwt-color-success-5: rgb(0, 25, 4) !important; + --pwt-color-success-0: rgb(0, 0, 0) !important; + + /* Error — Dracula Red (#ff5555) tonal scale */ + --pwt-color-error-100: rgb(255, 255, 255) !important; + --pwt-color-error-99: rgb(255, 248, 248) !important; + --pwt-color-error-95: rgb(255, 230, 230) !important; + --pwt-color-error-90: rgb(255, 205, 205) !important; + --pwt-color-error-80: rgb(255, 150, 150) !important; + --pwt-color-error-70: rgb(255, 110, 110) !important; + --pwt-color-error-60: rgb(255, 85, 85) !important; + --pwt-color-error-50: rgb(230, 60, 60) !important; + --pwt-color-error-40: rgb(200, 38, 38) !important; + --pwt-color-error-30: rgb(168, 16, 16) !important; + --pwt-color-error-20: rgb(120, 10, 10) !important; + --pwt-color-error-15: rgb(95, 5, 5) !important; + --pwt-color-error-10: rgb(72, 0, 0) !important; + --pwt-color-error-5: rgb(48, 0, 0) !important; + --pwt-color-error-0: rgb(0, 0, 0) !important; + + /* Warning — Dracula Yellow (#f1fa8c) tonal scale */ + --pwt-color-warning-100: rgb(255, 255, 255) !important; + --pwt-color-warning-99: rgb(255, 254, 248) !important; + --pwt-color-warning-95: rgb(252, 255, 210) !important; + --pwt-color-warning-90: rgb(245, 252, 160) !important; + --pwt-color-warning-80: rgb(241, 250, 140) !important; + --pwt-color-warning-70: rgb(218, 228, 100) !important; + --pwt-color-warning-60: rgb(195, 205, 65) !important; + --pwt-color-warning-50: rgb(170, 180, 35) !important; + --pwt-color-warning-40: rgb(140, 150, 15) !important; + --pwt-color-warning-30: rgb(110, 118, 0) !important; + --pwt-color-warning-20: rgb(80, 85, 0) !important; + --pwt-color-warning-15: rgb(60, 65, 0) !important; + --pwt-color-warning-10: rgb(42, 46, 0) !important; + --pwt-color-warning-5: rgb(25, 28, 0) !important; + --pwt-color-warning-0: rgb(0, 0, 0) !important; + + /* Neutral — Dracula Background/Surface scale */ + --pwt-color-neutral-100: rgb(248, 248, 242) !important; + --pwt-color-neutral-99: rgb(240, 240, 236) !important; + --pwt-color-neutral-95: rgb(220, 222, 218) !important; + --pwt-color-neutral-90: rgb(208, 212, 224) !important; + --pwt-color-neutral-80: rgb(176, 181, 200) !important; + --pwt-color-neutral-70: rgb(146, 152, 184) !important; + --pwt-color-neutral-60: rgb(124, 131, 160) !important; + --pwt-color-neutral-50: rgb(98, 114, 164) !important; + --pwt-color-neutral-40: rgb(86, 90, 114) !important; + --pwt-color-neutral-30: rgb(68, 71, 90) !important; + --pwt-color-neutral-20: rgb(40, 42, 54) !important; + --pwt-color-neutral-15: rgb(33, 34, 44) !important; + --pwt-color-neutral-10: rgb(30, 31, 41) !important; + --pwt-color-neutral-5: rgb(22, 23, 30) !important; + --pwt-color-neutral-0: rgb(0, 0, 0) !important; + + /* Neutral Alt — Dracula Comment tones */ + --pwt-color-neutral-alt-100: rgb(248, 248, 242) !important; + --pwt-color-neutral-alt-99: rgb(242, 244, 255) !important; + --pwt-color-neutral-alt-95: rgb(225, 230, 248) !important; + --pwt-color-neutral-alt-90: rgb(210, 216, 238) !important; + --pwt-color-neutral-alt-80: rgb(178, 186, 215) !important; + --pwt-color-neutral-alt-70: rgb(146, 156, 190) !important; + --pwt-color-neutral-alt-60: rgb(118, 128, 165) !important; + --pwt-color-neutral-alt-50: rgb(98, 114, 164) !important; + --pwt-color-neutral-alt-40: rgb(80, 90, 130) !important; + --pwt-color-neutral-alt-30: rgb(60, 68, 105) !important; + --pwt-color-neutral-alt-20: rgb(44, 50, 80) !important; + --pwt-color-neutral-alt-15: rgb(36, 40, 65) !important; + --pwt-color-neutral-alt-10: rgb(28, 32, 52) !important; + --pwt-color-neutral-alt-5: rgb(18, 20, 35) !important; + --pwt-color-neutral-alt-0: rgb(0, 0, 0) !important; +} + +/* ===== Semantic Color Remapping (darker surfaces) ===== */ +:root.pwt-dark-mode { + --pwt-color-surface: var(--pwt-color-neutral-10) !important; + --pwt-color-on-surface: var(--pwt-color-neutral-95) !important; + --pwt-color-surface-container: var(--pwt-color-neutral-15) !important; + --pwt-color-on-surface-container: var(--pwt-color-neutral-95) !important; + --pwt-color-neutral: var(--pwt-color-neutral-15) !important; + --pwt-color-on-neutral: var(--pwt-color-neutral-95) !important; + --pwt-color-neutral-container: var(--pwt-color-neutral-10) !important; + --pwt-color-on-neutral-container: var(--pwt-color-neutral-95) !important; + --pwt-color-dark-surface: var(--pwt-color-neutral-10) !important; + --pwt-color-on-dark-surface: var(--pwt-color-neutral-95) !important; + --pwt-color-dark-surface-container: var(--pwt-color-neutral-15) !important; + --pwt-color-on-dark-surface-container: var(--pwt-color-neutral-95) !important; + --pwt-color-neutral-alt: var(--pwt-color-neutral-alt-15) !important; + --pwt-color-on-neutral-alt: var(--pwt-color-neutral-alt-80) !important; + --pwt-color-neutral-alt-container: var(--pwt-color-neutral-alt-10) !important; + --pwt-color-on-neutral-alt-container: var(--pwt-color-neutral-alt-80) !important; + --pwt-color-background: var(--pwt-color-neutral-10) !important; + --pwt-color-inverse-surface: var(--pwt-color-neutral-80) !important; + --pwt-color-on-inverse-surface: var(--pwt-color-neutral-10) !important; + --pwt-color-border: var(--pwt-color-neutral-alt-30) !important; + --pwt-color-shadow: var(--pwt-color-neutral-0) !important; + background: var(--pwt-color-neutral-10) !important; + color: var(--pwt-color-neutral-95) !important; +} + +body { + background-color: var(--pwt-color-neutral-10) !important; +} \ No newline at end of file diff --git a/themes/pdm/theme-github-dark.css b/themes/pdm/theme-github-dark.css new file mode 100644 index 0000000..bb410f2 --- /dev/null +++ b/themes/pdm/theme-github-dark.css @@ -0,0 +1,183 @@ +/*!GitHub Dark*/ +/* + * ProxMorph PDM Theme: GitHub Dark + * Overrides the PWT Material Design tonal color system with GitHub Primer palette + * Version: 1.0.0 + * Author: ProxMorph / GitHub Primer Design System + * + * ─── GitHub Primer Dark Palette ──────────────────────────────── + * Accent Blue: #4493f8 Emphasis: #1f6feb + * Success: #3fb950 Danger: #f85149 + * Attention: #d29922 Text: #f0f6fc + * Canvas: #0d1117 Subtle: #161b22 + * Border: #3d444d + */ + +:root { + /* Primary — GitHub Accent Blue (#4493f8) tonal scale */ + --pwt-color-primary-100: rgb(255, 255, 255) !important; + --pwt-color-primary-99: rgb(246, 251, 255) !important; + --pwt-color-primary-95: rgb(218, 238, 255) !important; + --pwt-color-primary-90: rgb(188, 222, 255) !important; + --pwt-color-primary-80: rgb(130, 188, 252) !important; + --pwt-color-primary-70: rgb(68, 147, 248) !important; + --pwt-color-primary-60: rgb(31, 111, 235) !important; + --pwt-color-primary-50: rgb(18, 90, 205) !important; + --pwt-color-primary-40: rgb(8, 72, 172) !important; + --pwt-color-primary-30: rgb(2, 55, 140) !important; + --pwt-color-primary-20: rgb(0, 40, 108) !important; + --pwt-color-primary-15: rgb(0, 30, 85) !important; + --pwt-color-primary-10: rgb(0, 22, 65) !important; + --pwt-color-primary-5: rgb(0, 12, 42) !important; + --pwt-color-primary-0: rgb(0, 0, 0) !important; + + /* Secondary — GitHub Muted tonal scale */ + --pwt-color-secondary-100: rgb(255, 255, 255) !important; + --pwt-color-secondary-99: rgb(250, 252, 255) !important; + --pwt-color-secondary-95: rgb(230, 238, 248) !important; + --pwt-color-secondary-90: rgb(210, 220, 235) !important; + --pwt-color-secondary-80: rgb(175, 190, 210) !important; + --pwt-color-secondary-70: rgb(145, 152, 161) !important; + --pwt-color-secondary-60: rgb(110, 118, 129) !important; + --pwt-color-secondary-50: rgb(88, 95, 105) !important; + --pwt-color-secondary-40: rgb(61, 68, 77) !important; + --pwt-color-secondary-30: rgb(48, 54, 62) !important; + --pwt-color-secondary-20: rgb(22, 27, 34) !important; + --pwt-color-secondary-15: rgb(16, 20, 28) !important; + --pwt-color-secondary-10: rgb(13, 17, 23) !important; + --pwt-color-secondary-5: rgb(6, 8, 14) !important; + --pwt-color-secondary-0: rgb(0, 0, 0) !important; + + /* Tertiary — GitHub Purple (#a371f7) tonal scale */ + --pwt-color-tertiary-100: rgb(255, 255, 255) !important; + --pwt-color-tertiary-99: rgb(252, 250, 255) !important; + --pwt-color-tertiary-95: rgb(238, 228, 255) !important; + --pwt-color-tertiary-90: rgb(222, 208, 255) !important; + --pwt-color-tertiary-80: rgb(188, 160, 252) !important; + --pwt-color-tertiary-70: rgb(163, 113, 247) !important; + --pwt-color-tertiary-60: rgb(138, 88, 225) !important; + --pwt-color-tertiary-50: rgb(115, 65, 200) !important; + --pwt-color-tertiary-40: rgb(92, 45, 175) !important; + --pwt-color-tertiary-30: rgb(72, 28, 148) !important; + --pwt-color-tertiary-20: rgb(52, 14, 118) !important; + --pwt-color-tertiary-15: rgb(42, 8, 98) !important; + --pwt-color-tertiary-10: rgb(32, 4, 78) !important; + --pwt-color-tertiary-5: rgb(20, 0, 50) !important; + --pwt-color-tertiary-0: rgb(0, 0, 0) !important; + + /* Success — GitHub Green (#3fb950) */ + --pwt-color-success-100: rgb(255, 255, 255) !important; + --pwt-color-success-99: rgb(242, 255, 245) !important; + --pwt-color-success-95: rgb(205, 255, 215) !important; + --pwt-color-success-90: rgb(165, 248, 180) !important; + --pwt-color-success-80: rgb(105, 225, 125) !important; + --pwt-color-success-70: rgb(63, 185, 80) !important; + --pwt-color-success-60: rgb(46, 160, 67) !important; + --pwt-color-success-50: rgb(35, 134, 54) !important; + --pwt-color-success-40: rgb(22, 110, 40) !important; + --pwt-color-success-30: rgb(12, 88, 28) !important; + --pwt-color-success-20: rgb(4, 66, 18) !important; + --pwt-color-success-15: rgb(0, 52, 12) !important; + --pwt-color-success-10: rgb(0, 38, 6) !important; + --pwt-color-success-5: rgb(0, 24, 2) !important; + --pwt-color-success-0: rgb(0, 0, 0) !important; + + /* Error — GitHub Danger Red (#f85149) */ + --pwt-color-error-100: rgb(255, 255, 255) !important; + --pwt-color-error-99: rgb(255, 248, 248) !important; + --pwt-color-error-95: rgb(255, 228, 226) !important; + --pwt-color-error-90: rgb(255, 200, 198) !important; + --pwt-color-error-80: rgb(255, 148, 144) !important; + --pwt-color-error-70: rgb(248, 81, 73) !important; + --pwt-color-error-60: rgb(218, 54, 51) !important; + --pwt-color-error-50: rgb(190, 36, 34) !important; + --pwt-color-error-40: rgb(162, 20, 18) !important; + --pwt-color-error-30: rgb(132, 8, 6) !important; + --pwt-color-error-20: rgb(100, 2, 0) !important; + --pwt-color-error-15: rgb(80, 0, 0) !important; + --pwt-color-error-10: rgb(60, 0, 0) !important; + --pwt-color-error-5: rgb(38, 0, 0) !important; + --pwt-color-error-0: rgb(0, 0, 0) !important; + + /* Warning — GitHub Attention (#d29922) */ + --pwt-color-warning-100: rgb(255, 255, 255) !important; + --pwt-color-warning-99: rgb(255, 252, 244) !important; + --pwt-color-warning-95: rgb(255, 240, 200) !important; + --pwt-color-warning-90: rgb(248, 225, 155) !important; + --pwt-color-warning-80: rgb(235, 198, 95) !important; + --pwt-color-warning-70: rgb(210, 153, 34) !important; + --pwt-color-warning-60: rgb(185, 130, 15) !important; + --pwt-color-warning-50: rgb(158, 106, 3) !important; + --pwt-color-warning-40: rgb(132, 88, 0) !important; + --pwt-color-warning-30: rgb(105, 68, 0) !important; + --pwt-color-warning-20: rgb(78, 50, 0) !important; + --pwt-color-warning-15: rgb(60, 38, 0) !important; + --pwt-color-warning-10: rgb(44, 28, 0) !important; + --pwt-color-warning-5: rgb(28, 16, 0) !important; + --pwt-color-warning-0: rgb(0, 0, 0) !important; + + /* Neutral — GitHub Canvas scale */ + --pwt-color-neutral-100: rgb(240, 246, 252) !important; + --pwt-color-neutral-99: rgb(232, 238, 245) !important; + --pwt-color-neutral-95: rgb(210, 218, 228) !important; + --pwt-color-neutral-90: rgb(185, 195, 208) !important; + --pwt-color-neutral-80: rgb(155, 165, 178) !important; + --pwt-color-neutral-70: rgb(125, 135, 148) !important; + --pwt-color-neutral-60: rgb(110, 118, 129) !important; + --pwt-color-neutral-50: rgb(88, 95, 108) !important; + --pwt-color-neutral-40: rgb(61, 68, 77) !important; + --pwt-color-neutral-30: rgb(33, 38, 45) !important; + --pwt-color-neutral-20: rgb(22, 27, 34) !important; + --pwt-color-neutral-15: rgb(13, 17, 23) !important; + --pwt-color-neutral-10: rgb(1, 4, 9) !important; + --pwt-color-neutral-5: rgb(0, 2, 6) !important; + --pwt-color-neutral-0: rgb(0, 0, 0) !important; + + /* Neutral Alt */ + --pwt-color-neutral-alt-100: rgb(240, 246, 252) !important; + --pwt-color-neutral-alt-99: rgb(235, 241, 248) !important; + --pwt-color-neutral-alt-95: rgb(215, 222, 232) !important; + --pwt-color-neutral-alt-90: rgb(192, 200, 212) !important; + --pwt-color-neutral-alt-80: rgb(160, 170, 185) !important; + --pwt-color-neutral-alt-70: rgb(130, 140, 155) !important; + --pwt-color-neutral-alt-60: rgb(102, 112, 128) !important; + --pwt-color-neutral-alt-50: rgb(80, 90, 105) !important; + --pwt-color-neutral-alt-40: rgb(58, 65, 78) !important; + --pwt-color-neutral-alt-30: rgb(38, 44, 55) !important; + --pwt-color-neutral-alt-20: rgb(24, 30, 38) !important; + --pwt-color-neutral-alt-15: rgb(15, 20, 28) !important; + --pwt-color-neutral-alt-10: rgb(8, 12, 18) !important; + --pwt-color-neutral-alt-5: rgb(2, 4, 10) !important; + --pwt-color-neutral-alt-0: rgb(0, 0, 0) !important; +} + +/* ===== Semantic Color Remapping (darker surfaces) ===== */ +:root.pwt-dark-mode { + --pwt-color-surface: var(--pwt-color-neutral-10) !important; + --pwt-color-on-surface: var(--pwt-color-neutral-95) !important; + --pwt-color-surface-container: var(--pwt-color-neutral-15) !important; + --pwt-color-on-surface-container: var(--pwt-color-neutral-95) !important; + --pwt-color-neutral: var(--pwt-color-neutral-15) !important; + --pwt-color-on-neutral: var(--pwt-color-neutral-95) !important; + --pwt-color-neutral-container: var(--pwt-color-neutral-10) !important; + --pwt-color-on-neutral-container: var(--pwt-color-neutral-95) !important; + --pwt-color-dark-surface: var(--pwt-color-neutral-10) !important; + --pwt-color-on-dark-surface: var(--pwt-color-neutral-95) !important; + --pwt-color-dark-surface-container: var(--pwt-color-neutral-15) !important; + --pwt-color-on-dark-surface-container: var(--pwt-color-neutral-95) !important; + --pwt-color-neutral-alt: var(--pwt-color-neutral-alt-15) !important; + --pwt-color-on-neutral-alt: var(--pwt-color-neutral-alt-80) !important; + --pwt-color-neutral-alt-container: var(--pwt-color-neutral-alt-10) !important; + --pwt-color-on-neutral-alt-container: var(--pwt-color-neutral-alt-80) !important; + --pwt-color-background: var(--pwt-color-neutral-10) !important; + --pwt-color-inverse-surface: var(--pwt-color-neutral-80) !important; + --pwt-color-on-inverse-surface: var(--pwt-color-neutral-10) !important; + --pwt-color-border: var(--pwt-color-neutral-alt-30) !important; + --pwt-color-shadow: var(--pwt-color-neutral-0) !important; + background: var(--pwt-color-neutral-10) !important; + color: var(--pwt-color-neutral-95) !important; +} + +body { + background-color: var(--pwt-color-neutral-10) !important; +} \ No newline at end of file diff --git a/themes/pdm/theme-gruvbox-dark.css b/themes/pdm/theme-gruvbox-dark.css new file mode 100644 index 0000000..7436583 --- /dev/null +++ b/themes/pdm/theme-gruvbox-dark.css @@ -0,0 +1,181 @@ +/*!Gruvbox Dark*/ +/* + * ProxMorph PDM Theme: Gruvbox Dark + * Overrides the PWT Material Design tonal color system with Gruvbox palette + * Version: 1.0.0 + * + * ─── Gruvbox Dark Palette ────────────────────────────────────── + * Accent Yellow: #fabd2f Orange: #fe8019 + * Green: #b8bb26 Red: #fb4934 + * Aqua: #8ec07c Blue: #83a598 + * Text: #ebdbb2 Base: #282828 + */ + +:root { + /* Primary — Gruvbox Yellow (#fabd2f) tonal scale */ + --pwt-color-primary-100: rgb(255, 255, 255) !important; + --pwt-color-primary-99: rgb(255, 253, 245) !important; + --pwt-color-primary-95: rgb(255, 245, 210) !important; + --pwt-color-primary-90: rgb(255, 235, 175) !important; + --pwt-color-primary-80: rgb(250, 210, 110) !important; + --pwt-color-primary-70: rgb(250, 189, 47) !important; + --pwt-color-primary-60: rgb(225, 168, 30) !important; + --pwt-color-primary-50: rgb(198, 145, 18) !important; + --pwt-color-primary-40: rgb(168, 120, 8) !important; + --pwt-color-primary-30: rgb(138, 98, 0) !important; + --pwt-color-primary-20: rgb(108, 75, 0) !important; + --pwt-color-primary-15: rgb(85, 58, 0) !important; + --pwt-color-primary-10: rgb(65, 44, 0) !important; + --pwt-color-primary-5: rgb(40, 28, 0) !important; + --pwt-color-primary-0: rgb(0, 0, 0) !important; + + /* Secondary — Gruvbox Blue (#83a598) tonal scale */ + --pwt-color-secondary-100: rgb(255, 255, 255) !important; + --pwt-color-secondary-99: rgb(248, 254, 252) !important; + --pwt-color-secondary-95: rgb(222, 242, 238) !important; + --pwt-color-secondary-90: rgb(195, 228, 222) !important; + --pwt-color-secondary-80: rgb(158, 200, 192) !important; + --pwt-color-secondary-70: rgb(131, 165, 152) !important; + --pwt-color-secondary-60: rgb(108, 142, 130) !important; + --pwt-color-secondary-50: rgb(85, 118, 108) !important; + --pwt-color-secondary-40: rgb(65, 96, 86) !important; + --pwt-color-secondary-30: rgb(46, 75, 66) !important; + --pwt-color-secondary-20: rgb(30, 55, 48) !important; + --pwt-color-secondary-15: rgb(22, 44, 38) !important; + --pwt-color-secondary-10: rgb(14, 34, 28) !important; + --pwt-color-secondary-5: rgb(6, 20, 16) !important; + --pwt-color-secondary-0: rgb(0, 0, 0) !important; + + /* Tertiary — Gruvbox Aqua (#8ec07c) tonal scale */ + --pwt-color-tertiary-100: rgb(255, 255, 255) !important; + --pwt-color-tertiary-99: rgb(248, 255, 246) !important; + --pwt-color-tertiary-95: rgb(225, 248, 218) !important; + --pwt-color-tertiary-90: rgb(200, 238, 192) !important; + --pwt-color-tertiary-80: rgb(165, 215, 155) !important; + --pwt-color-tertiary-70: rgb(142, 192, 124) !important; + --pwt-color-tertiary-60: rgb(118, 168, 102) !important; + --pwt-color-tertiary-50: rgb(95, 142, 80) !important; + --pwt-color-tertiary-40: rgb(75, 118, 62) !important; + --pwt-color-tertiary-30: rgb(55, 95, 42) !important; + --pwt-color-tertiary-20: rgb(38, 72, 28) !important; + --pwt-color-tertiary-15: rgb(28, 58, 18) !important; + --pwt-color-tertiary-10: rgb(20, 44, 12) !important; + --pwt-color-tertiary-5: rgb(10, 28, 5) !important; + --pwt-color-tertiary-0: rgb(0, 0, 0) !important; + + /* Success — Gruvbox Green (#b8bb26) */ + --pwt-color-success-100: rgb(255, 255, 255) !important; + --pwt-color-success-99: rgb(252, 255, 242) !important; + --pwt-color-success-95: rgb(238, 248, 195) !important; + --pwt-color-success-90: rgb(218, 235, 130) !important; + --pwt-color-success-80: rgb(200, 215, 68) !important; + --pwt-color-success-70: rgb(184, 187, 38) !important; + --pwt-color-success-60: rgb(160, 165, 25) !important; + --pwt-color-success-50: rgb(135, 140, 12) !important; + --pwt-color-success-40: rgb(110, 115, 2) !important; + --pwt-color-success-30: rgb(88, 92, 0) !important; + --pwt-color-success-20: rgb(65, 68, 0) !important; + --pwt-color-success-15: rgb(50, 52, 0) !important; + --pwt-color-success-10: rgb(38, 40, 0) !important; + --pwt-color-success-5: rgb(22, 24, 0) !important; + --pwt-color-success-0: rgb(0, 0, 0) !important; + + /* Error — Gruvbox Red (#fb4934) */ + --pwt-color-error-100: rgb(255, 255, 255) !important; + --pwt-color-error-99: rgb(255, 248, 246) !important; + --pwt-color-error-95: rgb(255, 228, 222) !important; + --pwt-color-error-90: rgb(255, 200, 192) !important; + --pwt-color-error-80: rgb(255, 148, 135) !important; + --pwt-color-error-70: rgb(251, 105, 82) !important; + --pwt-color-error-60: rgb(251, 73, 52) !important; + --pwt-color-error-50: rgb(225, 50, 35) !important; + --pwt-color-error-40: rgb(195, 32, 18) !important; + --pwt-color-error-30: rgb(165, 14, 4) !important; + --pwt-color-error-20: rgb(120, 8, 0) !important; + --pwt-color-error-15: rgb(95, 4, 0) !important; + --pwt-color-error-10: rgb(72, 0, 0) !important; + --pwt-color-error-5: rgb(45, 0, 0) !important; + --pwt-color-error-0: rgb(0, 0, 0) !important; + + /* Warning — Gruvbox Orange (#fe8019) */ + --pwt-color-warning-100: rgb(255, 255, 255) !important; + --pwt-color-warning-99: rgb(255, 251, 246) !important; + --pwt-color-warning-95: rgb(255, 238, 215) !important; + --pwt-color-warning-90: rgb(255, 220, 175) !important; + --pwt-color-warning-80: rgb(255, 185, 110) !important; + --pwt-color-warning-70: rgb(254, 128, 25) !important; + --pwt-color-warning-60: rgb(228, 108, 12) !important; + --pwt-color-warning-50: rgb(200, 90, 4) !important; + --pwt-color-warning-40: rgb(170, 72, 0) !important; + --pwt-color-warning-30: rgb(138, 55, 0) !important; + --pwt-color-warning-20: rgb(105, 40, 0) !important; + --pwt-color-warning-15: rgb(82, 30, 0) !important; + --pwt-color-warning-10: rgb(60, 22, 0) !important; + --pwt-color-warning-5: rgb(38, 12, 0) !important; + --pwt-color-warning-0: rgb(0, 0, 0) !important; + + /* Neutral — Gruvbox Background scale */ + --pwt-color-neutral-100: rgb(235, 219, 178) !important; + --pwt-color-neutral-99: rgb(228, 212, 172) !important; + --pwt-color-neutral-95: rgb(213, 196, 161) !important; + --pwt-color-neutral-90: rgb(189, 174, 147) !important; + --pwt-color-neutral-80: rgb(168, 153, 132) !important; + --pwt-color-neutral-70: rgb(146, 131, 116) !important; + --pwt-color-neutral-60: rgb(124, 111, 100) !important; + --pwt-color-neutral-50: rgb(102, 92, 84) !important; + --pwt-color-neutral-40: rgb(80, 73, 69) !important; + --pwt-color-neutral-30: rgb(60, 56, 54) !important; + --pwt-color-neutral-20: rgb(40, 40, 40) !important; + --pwt-color-neutral-15: rgb(29, 32, 33) !important; + --pwt-color-neutral-10: rgb(24, 26, 28) !important; + --pwt-color-neutral-5: rgb(16, 16, 18) !important; + --pwt-color-neutral-0: rgb(0, 0, 0) !important; + + /* Neutral Alt */ + --pwt-color-neutral-alt-100: rgb(235, 219, 178) !important; + --pwt-color-neutral-alt-99: rgb(230, 215, 175) !important; + --pwt-color-neutral-alt-95: rgb(215, 200, 165) !important; + --pwt-color-neutral-alt-90: rgb(195, 180, 148) !important; + --pwt-color-neutral-alt-80: rgb(170, 158, 135) !important; + --pwt-color-neutral-alt-70: rgb(148, 135, 118) !important; + --pwt-color-neutral-alt-60: rgb(126, 115, 102) !important; + --pwt-color-neutral-alt-50: rgb(105, 95, 85) !important; + --pwt-color-neutral-alt-40: rgb(83, 76, 70) !important; + --pwt-color-neutral-alt-30: rgb(62, 58, 55) !important; + --pwt-color-neutral-alt-20: rgb(42, 42, 42) !important; + --pwt-color-neutral-alt-15: rgb(32, 34, 35) !important; + --pwt-color-neutral-alt-10: rgb(25, 27, 28) !important; + --pwt-color-neutral-alt-5: rgb(16, 17, 18) !important; + --pwt-color-neutral-alt-0: rgb(0, 0, 0) !important; +} + +/* ===== Semantic Color Remapping (darker surfaces) ===== */ +:root.pwt-dark-mode { + --pwt-color-surface: var(--pwt-color-neutral-10) !important; + --pwt-color-on-surface: var(--pwt-color-neutral-95) !important; + --pwt-color-surface-container: var(--pwt-color-neutral-15) !important; + --pwt-color-on-surface-container: var(--pwt-color-neutral-95) !important; + --pwt-color-neutral: var(--pwt-color-neutral-15) !important; + --pwt-color-on-neutral: var(--pwt-color-neutral-95) !important; + --pwt-color-neutral-container: var(--pwt-color-neutral-10) !important; + --pwt-color-on-neutral-container: var(--pwt-color-neutral-95) !important; + --pwt-color-dark-surface: var(--pwt-color-neutral-10) !important; + --pwt-color-on-dark-surface: var(--pwt-color-neutral-95) !important; + --pwt-color-dark-surface-container: var(--pwt-color-neutral-15) !important; + --pwt-color-on-dark-surface-container: var(--pwt-color-neutral-95) !important; + --pwt-color-neutral-alt: var(--pwt-color-neutral-alt-15) !important; + --pwt-color-on-neutral-alt: var(--pwt-color-neutral-alt-80) !important; + --pwt-color-neutral-alt-container: var(--pwt-color-neutral-alt-10) !important; + --pwt-color-on-neutral-alt-container: var(--pwt-color-neutral-alt-80) !important; + --pwt-color-background: var(--pwt-color-neutral-10) !important; + --pwt-color-inverse-surface: var(--pwt-color-neutral-80) !important; + --pwt-color-on-inverse-surface: var(--pwt-color-neutral-10) !important; + --pwt-color-border: var(--pwt-color-neutral-alt-30) !important; + --pwt-color-shadow: var(--pwt-color-neutral-0) !important; + background: var(--pwt-color-neutral-10) !important; + color: var(--pwt-color-neutral-95) !important; +} + +body { + background-color: var(--pwt-color-neutral-10) !important; +} \ No newline at end of file diff --git a/themes/pdm/theme-gruvbox-light.css b/themes/pdm/theme-gruvbox-light.css new file mode 100644 index 0000000..4cfb634 --- /dev/null +++ b/themes/pdm/theme-gruvbox-light.css @@ -0,0 +1,194 @@ +/*!Gruvbox Light*/ +/* + * ProxMorph PDM Theme: Gruvbox Light + * Overrides the PWT Material Design tonal color system with Gruvbox Light palette + * Version: 1.0.0 + * Author: ProxMorph / Gruvbox (https://github.com/morhetz/gruvbox) + * + * ─── Gruvbox Light Palette ──────────────────────────────────── + * Yellow (accent): #d79921 Aqua: #427b58 + * Green: #98971a Red: #cc241d + * Orange: #d65d0e Purple: #8f3f71 + * Text (dark): #282828 Background:#fbf1c7 + * bg1: #ebdbb2 bg2: #d5c4a1 + */ + +/* ===== Tonal Color Overrides ===== */ +:root { + /* Primary — Gruvbox Yellow (#d79921) tonal scale */ + --pwt-color-primary-100: rgb(255, 255, 255) !important; + --pwt-color-primary-99: rgb(255, 252, 245) !important; + --pwt-color-primary-95: rgb(255, 242, 208) !important; + --pwt-color-primary-90: rgb(252, 230, 168) !important; + --pwt-color-primary-80: rgb(240, 200, 100) !important; + --pwt-color-primary-70: rgb(228, 172, 52) !important; + --pwt-color-primary-60: rgb(215, 153, 33) !important; + --pwt-color-primary-50: rgb(188, 130, 20) !important; + --pwt-color-primary-40: rgb(160, 108, 10) !important; + --pwt-color-primary-30: rgb(130, 86, 2) !important; + --pwt-color-primary-20: rgb(100, 65, 0) !important; + --pwt-color-primary-15: rgb(80, 50, 0) !important; + --pwt-color-primary-10: rgb(60, 36, 0) !important; + --pwt-color-primary-5: rgb(38, 22, 0) !important; + --pwt-color-primary-0: rgb(0, 0, 0) !important; + + /* Secondary — Gruvbox Aqua (#427b58) tonal scale */ + --pwt-color-secondary-100: rgb(255, 255, 255) !important; + --pwt-color-secondary-99: rgb(245, 254, 250) !important; + --pwt-color-secondary-95: rgb(210, 245, 228) !important; + --pwt-color-secondary-90: rgb(170, 232, 202) !important; + --pwt-color-secondary-80: rgb(105, 198, 155) !important; + --pwt-color-secondary-70: rgb(72, 165, 118) !important; + --pwt-color-secondary-60: rgb(66, 123, 88) !important; + --pwt-color-secondary-50: rgb(52, 105, 72) !important; + --pwt-color-secondary-40: rgb(38, 85, 56) !important; + --pwt-color-secondary-30: rgb(26, 68, 42) !important; + --pwt-color-secondary-20: rgb(16, 52, 30) !important; + --pwt-color-secondary-15: rgb(10, 42, 22) !important; + --pwt-color-secondary-10: rgb(5, 32, 15) !important; + --pwt-color-secondary-5: rgb(0, 20, 8) !important; + --pwt-color-secondary-0: rgb(0, 0, 0) !important; + + /* Tertiary — Gruvbox Purple (#8f3f71) tonal scale */ + --pwt-color-tertiary-100: rgb(255, 255, 255) !important; + --pwt-color-tertiary-99: rgb(255, 248, 252) !important; + --pwt-color-tertiary-95: rgb(248, 225, 240) !important; + --pwt-color-tertiary-90: rgb(238, 198, 225) !important; + --pwt-color-tertiary-80: rgb(215, 148, 195) !important; + --pwt-color-tertiary-70: rgb(185, 105, 162) !important; + --pwt-color-tertiary-60: rgb(143, 63, 113) !important; + --pwt-color-tertiary-50: rgb(122, 48, 95) !important; + --pwt-color-tertiary-40: rgb(100, 35, 78) !important; + --pwt-color-tertiary-30: rgb(80, 22, 62) !important; + --pwt-color-tertiary-20: rgb(60, 12, 46) !important; + --pwt-color-tertiary-15: rgb(48, 6, 36) !important; + --pwt-color-tertiary-10: rgb(36, 2, 26) !important; + --pwt-color-tertiary-5: rgb(22, 0, 14) !important; + --pwt-color-tertiary-0: rgb(0, 0, 0) !important; + + /* Success — Gruvbox Green (#98971a) tonal scale */ + --pwt-color-success-100: rgb(255, 255, 255) !important; + --pwt-color-success-99: rgb(252, 255, 238) !important; + --pwt-color-success-95: rgb(235, 248, 185) !important; + --pwt-color-success-90: rgb(215, 238, 135) !important; + --pwt-color-success-80: rgb(180, 210, 68) !important; + --pwt-color-success-70: rgb(160, 185, 38) !important; + --pwt-color-success-60: rgb(152, 151, 26) !important; + --pwt-color-success-50: rgb(130, 128, 15) !important; + --pwt-color-success-40: rgb(108, 106, 6) !important; + --pwt-color-success-30: rgb(86, 84, 0) !important; + --pwt-color-success-20: rgb(65, 64, 0) !important; + --pwt-color-success-15: rgb(52, 50, 0) !important; + --pwt-color-success-10: rgb(38, 36, 0) !important; + --pwt-color-success-5: rgb(22, 20, 0) !important; + --pwt-color-success-0: rgb(0, 0, 0) !important; + + /* Error — Gruvbox Red (#cc241d) tonal scale */ + --pwt-color-error-100: rgb(255, 255, 255) !important; + --pwt-color-error-99: rgb(255, 248, 246) !important; + --pwt-color-error-95: rgb(255, 220, 216) !important; + --pwt-color-error-90: rgb(255, 188, 182) !important; + --pwt-color-error-80: rgb(240, 128, 118) !important; + --pwt-color-error-70: rgb(225, 72, 62) !important; + --pwt-color-error-60: rgb(204, 36, 29) !important; + --pwt-color-error-50: rgb(178, 22, 16) !important; + --pwt-color-error-40: rgb(150, 12, 8) !important; + --pwt-color-error-30: rgb(122, 4, 2) !important; + --pwt-color-error-20: rgb(94, 0, 0) !important; + --pwt-color-error-15: rgb(75, 0, 0) !important; + --pwt-color-error-10: rgb(56, 0, 0) !important; + --pwt-color-error-5: rgb(35, 0, 0) !important; + --pwt-color-error-0: rgb(0, 0, 0) !important; + + /* Warning — Gruvbox Orange (#d65d0e) tonal scale */ + --pwt-color-warning-100: rgb(255, 255, 255) !important; + --pwt-color-warning-99: rgb(255, 250, 245) !important; + --pwt-color-warning-95: rgb(255, 230, 205) !important; + --pwt-color-warning-90: rgb(252, 205, 160) !important; + --pwt-color-warning-80: rgb(240, 155, 80) !important; + --pwt-color-warning-70: rgb(228, 118, 32) !important; + --pwt-color-warning-60: rgb(214, 93, 14) !important; + --pwt-color-warning-50: rgb(188, 76, 5) !important; + --pwt-color-warning-40: rgb(160, 60, 0) !important; + --pwt-color-warning-30: rgb(130, 46, 0) !important; + --pwt-color-warning-20: rgb(100, 32, 0) !important; + --pwt-color-warning-15: rgb(80, 24, 0) !important; + --pwt-color-warning-10: rgb(58, 16, 0) !important; + --pwt-color-warning-5: rgb(36, 8, 0) !important; + --pwt-color-warning-0: rgb(0, 0, 0) !important; + + /* Neutral — Gruvbox Light Background scale (#fbf1c7 base) */ + --pwt-color-neutral-100: rgb(255, 255, 255) !important; + --pwt-color-neutral-99: rgb(253, 249, 238) !important; + --pwt-color-neutral-95: rgb(251, 241, 199) !important; + --pwt-color-neutral-90: rgb(235, 219, 178) !important; + --pwt-color-neutral-80: rgb(213, 196, 161) !important; + --pwt-color-neutral-70: rgb(189, 174, 147) !important; + --pwt-color-neutral-60: rgb(168, 153, 132) !important; + --pwt-color-neutral-50: rgb(146, 131, 116) !important; + --pwt-color-neutral-40: rgb(124, 111, 100) !important; + --pwt-color-neutral-30: rgb(102, 92, 84) !important; + --pwt-color-neutral-20: rgb(80, 73, 69) !important; + --pwt-color-neutral-15: rgb(60, 56, 54) !important; + --pwt-color-neutral-10: rgb(40, 40, 40) !important; + --pwt-color-neutral-5: rgb(24, 24, 24) !important; + --pwt-color-neutral-0: rgb(0, 0, 0) !important; + + /* Neutral Alt — Gruvbox Light fg tones */ + --pwt-color-neutral-alt-100: rgb(255, 255, 255) !important; + --pwt-color-neutral-alt-99: rgb(252, 248, 235) !important; + --pwt-color-neutral-alt-95: rgb(248, 240, 202) !important; + --pwt-color-neutral-alt-90: rgb(238, 225, 182) !important; + --pwt-color-neutral-alt-80: rgb(218, 202, 165) !important; + --pwt-color-neutral-alt-70: rgb(195, 180, 148) !important; + --pwt-color-neutral-alt-60: rgb(172, 158, 132) !important; + --pwt-color-neutral-alt-50: rgb(150, 136, 118) !important; + --pwt-color-neutral-alt-40: rgb(128, 115, 102) !important; + --pwt-color-neutral-alt-30: rgb(106, 95, 85) !important; + --pwt-color-neutral-alt-20: rgb(84, 76, 70) !important; + --pwt-color-neutral-alt-15: rgb(64, 58, 55) !important; + --pwt-color-neutral-alt-10: rgb(45, 42, 40) !important; + --pwt-color-neutral-alt-5: rgb(28, 26, 25) !important; + --pwt-color-neutral-alt-0: rgb(0, 0, 0) !important; +} + +/* ===== Semantic Color Remapping (light surfaces) ===== */ +:root.pwt-dark-mode { + --pwt-color-surface: var(--pwt-color-neutral-95) !important; + --pwt-color-on-surface: var(--pwt-color-neutral-10) !important; + --pwt-color-surface-container: var(--pwt-color-neutral-90) !important; + --pwt-color-on-surface-container: var(--pwt-color-neutral-10) !important; + --pwt-color-neutral: var(--pwt-color-neutral-90) !important; + --pwt-color-on-neutral: var(--pwt-color-neutral-10) !important; + --pwt-color-neutral-container: var(--pwt-color-neutral-95) !important; + --pwt-color-on-neutral-container: var(--pwt-color-neutral-10) !important; + --pwt-color-dark-surface: var(--pwt-color-neutral-95) !important; + --pwt-color-on-dark-surface: var(--pwt-color-neutral-10) !important; + --pwt-color-dark-surface-container: var(--pwt-color-neutral-90) !important; + --pwt-color-on-dark-surface-container: var(--pwt-color-neutral-10) !important; + --pwt-color-neutral-alt: var(--pwt-color-neutral-alt-90) !important; + --pwt-color-on-neutral-alt: var(--pwt-color-neutral-alt-20) !important; + --pwt-color-neutral-alt-container: var(--pwt-color-neutral-alt-95) !important; + --pwt-color-on-neutral-alt-container: var(--pwt-color-neutral-alt-20) !important; + --pwt-color-background: var(--pwt-color-neutral-95) !important; + --pwt-color-inverse-surface: var(--pwt-color-neutral-20) !important; + --pwt-color-on-inverse-surface: var(--pwt-color-neutral-95) !important; + --pwt-color-border: var(--pwt-color-neutral-alt-80) !important; + --pwt-color-shadow: rgba(0, 0, 0, 0.12) !important; + --pwt-color-primary: var(--pwt-color-primary-40) !important; + --pwt-color-on-primary: var(--pwt-color-primary-100) !important; + --pwt-color-primary-container: var(--pwt-color-primary-90) !important; + --pwt-color-on-primary-container: var(--pwt-color-primary-10) !important; + background: var(--pwt-color-neutral-95) !important; + color: var(--pwt-color-neutral-10) !important; + color-scheme: light !important; +} + +body { + background-color: var(--pwt-color-neutral-95) !important; +} + +/* ===== Logo — swap to dark variant for light background ===== */ +img[src*="proxmox_logo_white"] { + content: url("/images/proxmox_logo.svg") !important; +} diff --git a/themes/pdm/theme-nord-dark.css b/themes/pdm/theme-nord-dark.css new file mode 100644 index 0000000..bbf1bba --- /dev/null +++ b/themes/pdm/theme-nord-dark.css @@ -0,0 +1,181 @@ +/*!Nord Dark*/ +/* + * ProxMorph PDM Theme: Nord Dark + * Overrides the PWT Material Design tonal color system with Nord palette + * Version: 1.0.0 + * + * ─── Nord Palette ────────────────────────────────────────────── + * Frost 1 (accent): #88c0d0 Frost 2: #81a1c1 + * Aurora Green: #a3be8c Aurora Yellow: #ebcb8b + * Aurora Red: #bf616a Aurora Orange: #d08770 + * Snow Storm: #e5e9f0 Polar Night: #2e3440 + */ + +:root { + /* Primary — Nord Frost (#88c0d0) tonal scale */ + --pwt-color-primary-100: rgb(255, 255, 255) !important; + --pwt-color-primary-99: rgb(248, 254, 255) !important; + --pwt-color-primary-95: rgb(225, 245, 252) !important; + --pwt-color-primary-90: rgb(200, 232, 242) !important; + --pwt-color-primary-80: rgb(160, 210, 225) !important; + --pwt-color-primary-70: rgb(136, 192, 208) !important; + --pwt-color-primary-60: rgb(110, 168, 185) !important; + --pwt-color-primary-50: rgb(88, 142, 160) !important; + --pwt-color-primary-40: rgb(65, 118, 135) !important; + --pwt-color-primary-30: rgb(45, 95, 112) !important; + --pwt-color-primary-20: rgb(28, 72, 88) !important; + --pwt-color-primary-15: rgb(18, 58, 72) !important; + --pwt-color-primary-10: rgb(10, 44, 56) !important; + --pwt-color-primary-5: rgb(4, 28, 38) !important; + --pwt-color-primary-0: rgb(0, 0, 0) !important; + + /* Secondary — Nord Frost 2 (#81a1c1) tonal scale */ + --pwt-color-secondary-100: rgb(255, 255, 255) !important; + --pwt-color-secondary-99: rgb(248, 252, 255) !important; + --pwt-color-secondary-95: rgb(225, 238, 252) !important; + --pwt-color-secondary-90: rgb(200, 222, 240) !important; + --pwt-color-secondary-80: rgb(160, 192, 215) !important; + --pwt-color-secondary-70: rgb(129, 161, 193) !important; + --pwt-color-secondary-60: rgb(105, 138, 170) !important; + --pwt-color-secondary-50: rgb(82, 115, 148) !important; + --pwt-color-secondary-40: rgb(62, 95, 125) !important; + --pwt-color-secondary-30: rgb(44, 75, 102) !important; + --pwt-color-secondary-20: rgb(28, 56, 78) !important; + --pwt-color-secondary-15: rgb(20, 45, 65) !important; + --pwt-color-secondary-10: rgb(12, 35, 52) !important; + --pwt-color-secondary-5: rgb(5, 22, 35) !important; + --pwt-color-secondary-0: rgb(0, 0, 0) !important; + + /* Tertiary — Nord Aurora Purple (#b48ead) tonal scale */ + --pwt-color-tertiary-100: rgb(255, 255, 255) !important; + --pwt-color-tertiary-99: rgb(255, 250, 254) !important; + --pwt-color-tertiary-95: rgb(245, 232, 242) !important; + --pwt-color-tertiary-90: rgb(232, 212, 228) !important; + --pwt-color-tertiary-80: rgb(205, 175, 200) !important; + --pwt-color-tertiary-70: rgb(180, 142, 173) !important; + --pwt-color-tertiary-60: rgb(155, 118, 148) !important; + --pwt-color-tertiary-50: rgb(130, 95, 125) !important; + --pwt-color-tertiary-40: rgb(108, 72, 102) !important; + --pwt-color-tertiary-30: rgb(85, 52, 80) !important; + --pwt-color-tertiary-20: rgb(62, 34, 58) !important; + --pwt-color-tertiary-15: rgb(50, 24, 48) !important; + --pwt-color-tertiary-10: rgb(38, 16, 36) !important; + --pwt-color-tertiary-5: rgb(25, 8, 24) !important; + --pwt-color-tertiary-0: rgb(0, 0, 0) !important; + + /* Success — Nord Aurora Green (#a3be8c) */ + --pwt-color-success-100: rgb(255, 255, 255) !important; + --pwt-color-success-99: rgb(248, 255, 245) !important; + --pwt-color-success-95: rgb(225, 245, 215) !important; + --pwt-color-success-90: rgb(200, 232, 190) !important; + --pwt-color-success-80: rgb(175, 210, 160) !important; + --pwt-color-success-70: rgb(163, 190, 140) !important; + --pwt-color-success-60: rgb(138, 165, 118) !important; + --pwt-color-success-50: rgb(115, 140, 95) !important; + --pwt-color-success-40: rgb(92, 118, 75) !important; + --pwt-color-success-30: rgb(70, 95, 55) !important; + --pwt-color-success-20: rgb(50, 72, 38) !important; + --pwt-color-success-15: rgb(38, 58, 28) !important; + --pwt-color-success-10: rgb(28, 44, 18) !important; + --pwt-color-success-5: rgb(16, 28, 10) !important; + --pwt-color-success-0: rgb(0, 0, 0) !important; + + /* Error — Nord Aurora Red (#bf616a) */ + --pwt-color-error-100: rgb(255, 255, 255) !important; + --pwt-color-error-99: rgb(255, 249, 249) !important; + --pwt-color-error-95: rgb(255, 228, 230) !important; + --pwt-color-error-90: rgb(248, 202, 206) !important; + --pwt-color-error-80: rgb(225, 150, 158) !important; + --pwt-color-error-70: rgb(205, 115, 125) !important; + --pwt-color-error-60: rgb(191, 97, 106) !important; + --pwt-color-error-50: rgb(168, 72, 82) !important; + --pwt-color-error-40: rgb(142, 50, 60) !important; + --pwt-color-error-30: rgb(118, 30, 40) !important; + --pwt-color-error-20: rgb(90, 16, 24) !important; + --pwt-color-error-15: rgb(72, 8, 16) !important; + --pwt-color-error-10: rgb(55, 2, 8) !important; + --pwt-color-error-5: rgb(35, 0, 4) !important; + --pwt-color-error-0: rgb(0, 0, 0) !important; + + /* Warning — Nord Aurora Yellow (#ebcb8b) */ + --pwt-color-warning-100: rgb(255, 255, 255) !important; + --pwt-color-warning-99: rgb(255, 253, 248) !important; + --pwt-color-warning-95: rgb(252, 245, 222) !important; + --pwt-color-warning-90: rgb(248, 235, 195) !important; + --pwt-color-warning-80: rgb(240, 218, 160) !important; + --pwt-color-warning-70: rgb(235, 203, 139) !important; + --pwt-color-warning-60: rgb(210, 178, 112) !important; + --pwt-color-warning-50: rgb(185, 155, 88) !important; + --pwt-color-warning-40: rgb(158, 130, 65) !important; + --pwt-color-warning-30: rgb(130, 105, 42) !important; + --pwt-color-warning-20: rgb(100, 80, 22) !important; + --pwt-color-warning-15: rgb(78, 62, 12) !important; + --pwt-color-warning-10: rgb(58, 45, 4) !important; + --pwt-color-warning-5: rgb(35, 28, 0) !important; + --pwt-color-warning-0: rgb(0, 0, 0) !important; + + /* Neutral — Nord Polar Night scale */ + --pwt-color-neutral-100: rgb(236, 239, 244) !important; + --pwt-color-neutral-99: rgb(229, 233, 240) !important; + --pwt-color-neutral-95: rgb(216, 222, 233) !important; + --pwt-color-neutral-90: rgb(195, 202, 218) !important; + --pwt-color-neutral-80: rgb(168, 178, 198) !important; + --pwt-color-neutral-70: rgb(140, 152, 175) !important; + --pwt-color-neutral-60: rgb(115, 128, 152) !important; + --pwt-color-neutral-50: rgb(92, 105, 130) !important; + --pwt-color-neutral-40: rgb(76, 86, 106) !important; + --pwt-color-neutral-30: rgb(67, 76, 94) !important; + --pwt-color-neutral-20: rgb(59, 66, 82) !important; + --pwt-color-neutral-15: rgb(52, 58, 72) !important; + --pwt-color-neutral-10: rgb(46, 52, 64) !important; + --pwt-color-neutral-5: rgb(36, 40, 52) !important; + --pwt-color-neutral-0: rgb(0, 0, 0) !important; + + /* Neutral Alt */ + --pwt-color-neutral-alt-100: rgb(236, 239, 244) !important; + --pwt-color-neutral-alt-99: rgb(232, 236, 242) !important; + --pwt-color-neutral-alt-95: rgb(218, 225, 238) !important; + --pwt-color-neutral-alt-90: rgb(200, 208, 225) !important; + --pwt-color-neutral-alt-80: rgb(170, 182, 202) !important; + --pwt-color-neutral-alt-70: rgb(142, 155, 180) !important; + --pwt-color-neutral-alt-60: rgb(118, 130, 158) !important; + --pwt-color-neutral-alt-50: rgb(95, 108, 135) !important; + --pwt-color-neutral-alt-40: rgb(76, 88, 112) !important; + --pwt-color-neutral-alt-30: rgb(60, 70, 92) !important; + --pwt-color-neutral-alt-20: rgb(48, 56, 74) !important; + --pwt-color-neutral-alt-15: rgb(40, 46, 62) !important; + --pwt-color-neutral-alt-10: rgb(32, 38, 50) !important; + --pwt-color-neutral-alt-5: rgb(22, 26, 38) !important; + --pwt-color-neutral-alt-0: rgb(0, 0, 0) !important; +} + +/* ===== Semantic Color Remapping (darker surfaces) ===== */ +:root.pwt-dark-mode { + --pwt-color-surface: var(--pwt-color-neutral-10) !important; + --pwt-color-on-surface: var(--pwt-color-neutral-95) !important; + --pwt-color-surface-container: var(--pwt-color-neutral-15) !important; + --pwt-color-on-surface-container: var(--pwt-color-neutral-95) !important; + --pwt-color-neutral: var(--pwt-color-neutral-15) !important; + --pwt-color-on-neutral: var(--pwt-color-neutral-95) !important; + --pwt-color-neutral-container: var(--pwt-color-neutral-10) !important; + --pwt-color-on-neutral-container: var(--pwt-color-neutral-95) !important; + --pwt-color-dark-surface: var(--pwt-color-neutral-10) !important; + --pwt-color-on-dark-surface: var(--pwt-color-neutral-95) !important; + --pwt-color-dark-surface-container: var(--pwt-color-neutral-15) !important; + --pwt-color-on-dark-surface-container: var(--pwt-color-neutral-95) !important; + --pwt-color-neutral-alt: var(--pwt-color-neutral-alt-15) !important; + --pwt-color-on-neutral-alt: var(--pwt-color-neutral-alt-80) !important; + --pwt-color-neutral-alt-container: var(--pwt-color-neutral-alt-10) !important; + --pwt-color-on-neutral-alt-container: var(--pwt-color-neutral-alt-80) !important; + --pwt-color-background: var(--pwt-color-neutral-10) !important; + --pwt-color-inverse-surface: var(--pwt-color-neutral-80) !important; + --pwt-color-on-inverse-surface: var(--pwt-color-neutral-10) !important; + --pwt-color-border: var(--pwt-color-neutral-alt-30) !important; + --pwt-color-shadow: var(--pwt-color-neutral-0) !important; + background: var(--pwt-color-neutral-10) !important; + color: var(--pwt-color-neutral-95) !important; +} + +body { + background-color: var(--pwt-color-neutral-10) !important; +} \ No newline at end of file diff --git a/themes/pdm/theme-nord-light.css b/themes/pdm/theme-nord-light.css new file mode 100644 index 0000000..d927691 --- /dev/null +++ b/themes/pdm/theme-nord-light.css @@ -0,0 +1,194 @@ +/*!Nord Light*/ +/* + * ProxMorph PDM Theme: Nord Light + * Overrides the PWT Material Design tonal color system with Nord Light palette + * Version: 1.0.0 + * Author: ProxMorph / Nord (https://www.nordtheme.com) + * + * ─── Nord Light Palette ─────────────────────────────────────── + * Frost Blue (accent): #5e81ac Frost Cyan: #88c0d0 + * Aurora Green: #a3be8c Aurora Red: #bf616a + * Aurora Yellow:#ebcb8b Aurora Purple:#b48ead + * Text: #2e3440 Background: #eceff4 + * Snow: #d8dee9 Night: #3b4252 + */ + +/* ===== Tonal Color Overrides ===== */ +:root { + /* Primary — Nord Frost Blue (#5e81ac) tonal scale */ + --pwt-color-primary-100: rgb(255, 255, 255) !important; + --pwt-color-primary-99: rgb(248, 251, 255) !important; + --pwt-color-primary-95: rgb(220, 235, 252) !important; + --pwt-color-primary-90: rgb(188, 215, 245) !important; + --pwt-color-primary-80: rgb(138, 180, 225) !important; + --pwt-color-primary-70: rgb(110, 155, 200) !important; + --pwt-color-primary-60: rgb(94, 129, 172) !important; + --pwt-color-primary-50: rgb(76, 108, 148) !important; + --pwt-color-primary-40: rgb(60, 88, 125) !important; + --pwt-color-primary-30: rgb(45, 68, 100) !important; + --pwt-color-primary-20: rgb(32, 50, 78) !important; + --pwt-color-primary-15: rgb(24, 38, 62) !important; + --pwt-color-primary-10: rgb(16, 28, 48) !important; + --pwt-color-primary-5: rgb(8, 15, 30) !important; + --pwt-color-primary-0: rgb(0, 0, 0) !important; + + /* Secondary — Nord Frost Cyan (#88c0d0) tonal scale */ + --pwt-color-secondary-100: rgb(255, 255, 255) !important; + --pwt-color-secondary-99: rgb(248, 254, 255) !important; + --pwt-color-secondary-95: rgb(218, 245, 250) !important; + --pwt-color-secondary-90: rgb(188, 235, 242) !important; + --pwt-color-secondary-80: rgb(150, 210, 225) !important; + --pwt-color-secondary-70: rgb(136, 192, 208) !important; + --pwt-color-secondary-60: rgb(108, 165, 182) !important; + --pwt-color-secondary-50: rgb(85, 140, 158) !important; + --pwt-color-secondary-40: rgb(64, 115, 132) !important; + --pwt-color-secondary-30: rgb(45, 92, 108) !important; + --pwt-color-secondary-20: rgb(28, 68, 82) !important; + --pwt-color-secondary-15: rgb(20, 54, 66) !important; + --pwt-color-secondary-10: rgb(12, 40, 50) !important; + --pwt-color-secondary-5: rgb(5, 24, 32) !important; + --pwt-color-secondary-0: rgb(0, 0, 0) !important; + + /* Tertiary — Nord Aurora Purple (#b48ead) tonal scale */ + --pwt-color-tertiary-100: rgb(255, 255, 255) !important; + --pwt-color-tertiary-99: rgb(255, 250, 254) !important; + --pwt-color-tertiary-95: rgb(245, 232, 242) !important; + --pwt-color-tertiary-90: rgb(235, 210, 230) !important; + --pwt-color-tertiary-80: rgb(210, 172, 202) !important; + --pwt-color-tertiary-70: rgb(180, 142, 173) !important; + --pwt-color-tertiary-60: rgb(155, 115, 148) !important; + --pwt-color-tertiary-50: rgb(132, 92, 125) !important; + --pwt-color-tertiary-40: rgb(108, 70, 102) !important; + --pwt-color-tertiary-30: rgb(86, 50, 80) !important; + --pwt-color-tertiary-20: rgb(64, 32, 58) !important; + --pwt-color-tertiary-15: rgb(50, 22, 46) !important; + --pwt-color-tertiary-10: rgb(38, 14, 34) !important; + --pwt-color-tertiary-5: rgb(22, 5, 20) !important; + --pwt-color-tertiary-0: rgb(0, 0, 0) !important; + + /* Success — Nord Aurora Green (#a3be8c) tonal scale */ + --pwt-color-success-100: rgb(255, 255, 255) !important; + --pwt-color-success-99: rgb(250, 255, 248) !important; + --pwt-color-success-95: rgb(228, 248, 218) !important; + --pwt-color-success-90: rgb(200, 235, 185) !important; + --pwt-color-success-80: rgb(172, 210, 152) !important; + --pwt-color-success-70: rgb(163, 190, 140) !important; + --pwt-color-success-60: rgb(138, 165, 116) !important; + --pwt-color-success-50: rgb(115, 142, 95) !important; + --pwt-color-success-40: rgb(92, 118, 74) !important; + --pwt-color-success-30: rgb(72, 96, 55) !important; + --pwt-color-success-20: rgb(52, 74, 38) !important; + --pwt-color-success-15: rgb(40, 58, 28) !important; + --pwt-color-success-10: rgb(28, 44, 18) !important; + --pwt-color-success-5: rgb(16, 28, 8) !important; + --pwt-color-success-0: rgb(0, 0, 0) !important; + + /* Error — Nord Aurora Red (#bf616a) tonal scale */ + --pwt-color-error-100: rgb(255, 255, 255) !important; + --pwt-color-error-99: rgb(255, 248, 249) !important; + --pwt-color-error-95: rgb(255, 225, 228) !important; + --pwt-color-error-90: rgb(248, 195, 200) !important; + --pwt-color-error-80: rgb(225, 148, 155) !important; + --pwt-color-error-70: rgb(191, 97, 106) !important; + --pwt-color-error-60: rgb(168, 72, 82) !important; + --pwt-color-error-50: rgb(145, 52, 62) !important; + --pwt-color-error-40: rgb(120, 35, 44) !important; + --pwt-color-error-30: rgb(98, 20, 28) !important; + --pwt-color-error-20: rgb(75, 8, 15) !important; + --pwt-color-error-15: rgb(60, 2, 8) !important; + --pwt-color-error-10: rgb(45, 0, 4) !important; + --pwt-color-error-5: rgb(28, 0, 0) !important; + --pwt-color-error-0: rgb(0, 0, 0) !important; + + /* Warning — Nord Aurora Yellow (#ebcb8b) tonal scale */ + --pwt-color-warning-100: rgb(255, 255, 255) !important; + --pwt-color-warning-99: rgb(255, 252, 248) !important; + --pwt-color-warning-95: rgb(252, 242, 218) !important; + --pwt-color-warning-90: rgb(248, 230, 185) !important; + --pwt-color-warning-80: rgb(238, 212, 148) !important; + --pwt-color-warning-70: rgb(235, 203, 139) !important; + --pwt-color-warning-60: rgb(212, 178, 110) !important; + --pwt-color-warning-50: rgb(188, 155, 85) !important; + --pwt-color-warning-40: rgb(162, 130, 62) !important; + --pwt-color-warning-30: rgb(135, 105, 40) !important; + --pwt-color-warning-20: rgb(108, 82, 22) !important; + --pwt-color-warning-15: rgb(86, 64, 12) !important; + --pwt-color-warning-10: rgb(65, 46, 4) !important; + --pwt-color-warning-5: rgb(42, 28, 0) !important; + --pwt-color-warning-0: rgb(0, 0, 0) !important; + + /* Neutral — Nord Snow Storm (polar) scale (#eceff4 base) */ + --pwt-color-neutral-100: rgb(255, 255, 255) !important; + --pwt-color-neutral-99: rgb(246, 248, 252) !important; + --pwt-color-neutral-95: rgb(236, 239, 244) !important; + --pwt-color-neutral-90: rgb(229, 233, 240) !important; + --pwt-color-neutral-80: rgb(216, 222, 233) !important; + --pwt-color-neutral-70: rgb(190, 198, 214) !important; + --pwt-color-neutral-60: rgb(165, 174, 195) !important; + --pwt-color-neutral-50: rgb(136, 146, 170) !important; + --pwt-color-neutral-40: rgb(76, 86, 106) !important; + --pwt-color-neutral-30: rgb(67, 76, 94) !important; + --pwt-color-neutral-20: rgb(59, 66, 82) !important; + --pwt-color-neutral-15: rgb(52, 58, 72) !important; + --pwt-color-neutral-10: rgb(46, 52, 64) !important; + --pwt-color-neutral-5: rgb(36, 40, 52) !important; + --pwt-color-neutral-0: rgb(0, 0, 0) !important; + + /* Neutral Alt — Nord Frost/Snow tones */ + --pwt-color-neutral-alt-100: rgb(255, 255, 255) !important; + --pwt-color-neutral-alt-99: rgb(248, 250, 254) !important; + --pwt-color-neutral-alt-95: rgb(238, 242, 248) !important; + --pwt-color-neutral-alt-90: rgb(230, 235, 242) !important; + --pwt-color-neutral-alt-80: rgb(218, 224, 235) !important; + --pwt-color-neutral-alt-70: rgb(195, 202, 218) !important; + --pwt-color-neutral-alt-60: rgb(170, 178, 198) !important; + --pwt-color-neutral-alt-50: rgb(142, 152, 175) !important; + --pwt-color-neutral-alt-40: rgb(80, 90, 112) !important; + --pwt-color-neutral-alt-30: rgb(70, 78, 98) !important; + --pwt-color-neutral-alt-20: rgb(60, 68, 85) !important; + --pwt-color-neutral-alt-15: rgb(54, 60, 75) !important; + --pwt-color-neutral-alt-10: rgb(48, 54, 68) !important; + --pwt-color-neutral-alt-5: rgb(38, 42, 55) !important; + --pwt-color-neutral-alt-0: rgb(0, 0, 0) !important; +} + +/* ===== Semantic Color Remapping (light surfaces) ===== */ +:root.pwt-dark-mode { + --pwt-color-surface: var(--pwt-color-neutral-95) !important; + --pwt-color-on-surface: var(--pwt-color-neutral-10) !important; + --pwt-color-surface-container: var(--pwt-color-neutral-90) !important; + --pwt-color-on-surface-container: var(--pwt-color-neutral-10) !important; + --pwt-color-neutral: var(--pwt-color-neutral-90) !important; + --pwt-color-on-neutral: var(--pwt-color-neutral-10) !important; + --pwt-color-neutral-container: var(--pwt-color-neutral-95) !important; + --pwt-color-on-neutral-container: var(--pwt-color-neutral-10) !important; + --pwt-color-dark-surface: var(--pwt-color-neutral-95) !important; + --pwt-color-on-dark-surface: var(--pwt-color-neutral-10) !important; + --pwt-color-dark-surface-container: var(--pwt-color-neutral-90) !important; + --pwt-color-on-dark-surface-container: var(--pwt-color-neutral-10) !important; + --pwt-color-neutral-alt: var(--pwt-color-neutral-alt-90) !important; + --pwt-color-on-neutral-alt: var(--pwt-color-neutral-alt-20) !important; + --pwt-color-neutral-alt-container: var(--pwt-color-neutral-alt-95) !important; + --pwt-color-on-neutral-alt-container: var(--pwt-color-neutral-alt-20) !important; + --pwt-color-background: var(--pwt-color-neutral-95) !important; + --pwt-color-inverse-surface: var(--pwt-color-neutral-20) !important; + --pwt-color-on-inverse-surface: var(--pwt-color-neutral-95) !important; + --pwt-color-border: var(--pwt-color-neutral-alt-80) !important; + --pwt-color-shadow: rgba(0, 0, 0, 0.12) !important; + --pwt-color-primary: var(--pwt-color-primary-40) !important; + --pwt-color-on-primary: var(--pwt-color-primary-100) !important; + --pwt-color-primary-container: var(--pwt-color-primary-90) !important; + --pwt-color-on-primary-container: var(--pwt-color-primary-10) !important; + background: var(--pwt-color-neutral-95) !important; + color: var(--pwt-color-neutral-10) !important; + color-scheme: light !important; +} + +body { + background-color: var(--pwt-color-neutral-95) !important; +} + +/* ===== Logo — swap to dark variant for light background ===== */ +img[src*="proxmox_logo_white"] { + content: url("/images/proxmox_logo.svg") !important; +} diff --git a/themes/pdm/theme-solarized-dark.css b/themes/pdm/theme-solarized-dark.css new file mode 100644 index 0000000..6a32244 --- /dev/null +++ b/themes/pdm/theme-solarized-dark.css @@ -0,0 +1,184 @@ +/*!Solarized Dark*/ +/* + * ProxMorph PDM Theme: Solarized Dark + * Overrides the PWT Material Design tonal color system with Solarized palette + * Version: 1.0.0 + * Author: ProxMorph / Ethan Schoonover (Solarized) + * + * ─── Solarized Palette ───────────────────────────────────────── + * Blue: #268bd2 Cyan: #2aa198 + * Green: #859900 Yellow: #b58900 + * Red: #dc322f Orange: #cb4b16 + * Base03: #002b36 Base02: #073642 + * Base01: #586e75 Base0: #839496 + * Base1: #93a1a1 + */ + +:root { + /* Primary — Solarized Blue (#268bd2) tonal scale */ + --pwt-color-primary-100: rgb(255, 255, 255) !important; + --pwt-color-primary-99: rgb(246, 252, 255) !important; + --pwt-color-primary-95: rgb(218, 240, 255) !important; + --pwt-color-primary-90: rgb(188, 225, 248) !important; + --pwt-color-primary-80: rgb(130, 195, 235) !important; + --pwt-color-primary-70: rgb(75, 165, 222) !important; + --pwt-color-primary-60: rgb(38, 139, 210) !important; + --pwt-color-primary-50: rgb(25, 115, 185) !important; + --pwt-color-primary-40: rgb(12, 95, 160) !important; + --pwt-color-primary-30: rgb(4, 75, 132) !important; + --pwt-color-primary-20: rgb(0, 55, 105) !important; + --pwt-color-primary-15: rgb(0, 44, 85) !important; + --pwt-color-primary-10: rgb(0, 32, 65) !important; + --pwt-color-primary-5: rgb(0, 18, 42) !important; + --pwt-color-primary-0: rgb(0, 0, 0) !important; + + /* Secondary — Solarized Cyan (#2aa198) tonal scale */ + --pwt-color-secondary-100: rgb(255, 255, 255) !important; + --pwt-color-secondary-99: rgb(245, 255, 254) !important; + --pwt-color-secondary-95: rgb(215, 248, 245) !important; + --pwt-color-secondary-90: rgb(180, 238, 232) !important; + --pwt-color-secondary-80: rgb(115, 210, 202) !important; + --pwt-color-secondary-70: rgb(65, 185, 175) !important; + --pwt-color-secondary-60: rgb(42, 161, 152) !important; + --pwt-color-secondary-50: rgb(28, 135, 128) !important; + --pwt-color-secondary-40: rgb(15, 110, 105) !important; + --pwt-color-secondary-30: rgb(4, 88, 82) !important; + --pwt-color-secondary-20: rgb(0, 65, 60) !important; + --pwt-color-secondary-15: rgb(0, 52, 48) !important; + --pwt-color-secondary-10: rgb(0, 38, 35) !important; + --pwt-color-secondary-5: rgb(0, 22, 20) !important; + --pwt-color-secondary-0: rgb(0, 0, 0) !important; + + /* Tertiary — Solarized Violet (#6c71c4) tonal scale */ + --pwt-color-tertiary-100: rgb(255, 255, 255) !important; + --pwt-color-tertiary-99: rgb(250, 250, 255) !important; + --pwt-color-tertiary-95: rgb(232, 232, 252) !important; + --pwt-color-tertiary-90: rgb(210, 212, 242) !important; + --pwt-color-tertiary-80: rgb(168, 172, 228) !important; + --pwt-color-tertiary-70: rgb(130, 135, 210) !important; + --pwt-color-tertiary-60: rgb(108, 113, 196) !important; + --pwt-color-tertiary-50: rgb(85, 90, 172) !important; + --pwt-color-tertiary-40: rgb(65, 70, 148) !important; + --pwt-color-tertiary-30: rgb(46, 50, 122) !important; + --pwt-color-tertiary-20: rgb(30, 34, 98) !important; + --pwt-color-tertiary-15: rgb(22, 25, 80) !important; + --pwt-color-tertiary-10: rgb(14, 16, 62) !important; + --pwt-color-tertiary-5: rgb(6, 8, 40) !important; + --pwt-color-tertiary-0: rgb(0, 0, 0) !important; + + /* Success — Solarized Green (#859900) */ + --pwt-color-success-100: rgb(255, 255, 255) !important; + --pwt-color-success-99: rgb(250, 255, 242) !important; + --pwt-color-success-95: rgb(228, 248, 195) !important; + --pwt-color-success-90: rgb(205, 238, 130) !important; + --pwt-color-success-80: rgb(175, 215, 55) !important; + --pwt-color-success-70: rgb(155, 190, 15) !important; + --pwt-color-success-60: rgb(133, 153, 0) !important; + --pwt-color-success-50: rgb(112, 130, 0) !important; + --pwt-color-success-40: rgb(90, 108, 0) !important; + --pwt-color-success-30: rgb(70, 85, 0) !important; + --pwt-color-success-20: rgb(50, 62, 0) !important; + --pwt-color-success-15: rgb(38, 48, 0) !important; + --pwt-color-success-10: rgb(28, 35, 0) !important; + --pwt-color-success-5: rgb(16, 20, 0) !important; + --pwt-color-success-0: rgb(0, 0, 0) !important; + + /* Error — Solarized Red (#dc322f) */ + --pwt-color-error-100: rgb(255, 255, 255) !important; + --pwt-color-error-99: rgb(255, 248, 248) !important; + --pwt-color-error-95: rgb(255, 225, 224) !important; + --pwt-color-error-90: rgb(255, 198, 197) !important; + --pwt-color-error-80: rgb(248, 140, 138) !important; + --pwt-color-error-70: rgb(238, 90, 88) !important; + --pwt-color-error-60: rgb(220, 50, 47) !important; + --pwt-color-error-50: rgb(192, 35, 32) !important; + --pwt-color-error-40: rgb(165, 20, 18) !important; + --pwt-color-error-30: rgb(135, 8, 6) !important; + --pwt-color-error-20: rgb(102, 2, 0) !important; + --pwt-color-error-15: rgb(82, 0, 0) !important; + --pwt-color-error-10: rgb(62, 0, 0) !important; + --pwt-color-error-5: rgb(40, 0, 0) !important; + --pwt-color-error-0: rgb(0, 0, 0) !important; + + /* Warning — Solarized Yellow (#b58900) */ + --pwt-color-warning-100: rgb(255, 255, 255) !important; + --pwt-color-warning-99: rgb(255, 252, 242) !important; + --pwt-color-warning-95: rgb(255, 242, 195) !important; + --pwt-color-warning-90: rgb(248, 225, 135) !important; + --pwt-color-warning-80: rgb(225, 195, 60) !important; + --pwt-color-warning-70: rgb(200, 168, 15) !important; + --pwt-color-warning-60: rgb(181, 137, 0) !important; + --pwt-color-warning-50: rgb(155, 118, 0) !important; + --pwt-color-warning-40: rgb(130, 98, 0) !important; + --pwt-color-warning-30: rgb(105, 78, 0) !important; + --pwt-color-warning-20: rgb(78, 58, 0) !important; + --pwt-color-warning-15: rgb(60, 44, 0) !important; + --pwt-color-warning-10: rgb(44, 32, 0) !important; + --pwt-color-warning-5: rgb(28, 18, 0) !important; + --pwt-color-warning-0: rgb(0, 0, 0) !important; + + /* Neutral — Solarized Base scale */ + --pwt-color-neutral-100: rgb(253, 246, 227) !important; + --pwt-color-neutral-99: rgb(238, 232, 213) !important; + --pwt-color-neutral-95: rgb(198, 200, 198) !important; + --pwt-color-neutral-90: rgb(147, 161, 161) !important; + --pwt-color-neutral-80: rgb(131, 148, 150) !important; + --pwt-color-neutral-70: rgb(110, 128, 132) !important; + --pwt-color-neutral-60: rgb(88, 110, 117) !important; + --pwt-color-neutral-50: rgb(70, 92, 100) !important; + --pwt-color-neutral-40: rgb(55, 75, 82) !important; + --pwt-color-neutral-30: rgb(42, 60, 68) !important; + --pwt-color-neutral-20: rgb(7, 54, 66) !important; + --pwt-color-neutral-15: rgb(0, 43, 54) !important; + --pwt-color-neutral-10: rgb(0, 34, 44) !important; + --pwt-color-neutral-5: rgb(0, 22, 30) !important; + --pwt-color-neutral-0: rgb(0, 0, 0) !important; + + /* Neutral Alt */ + --pwt-color-neutral-alt-100: rgb(253, 246, 227) !important; + --pwt-color-neutral-alt-99: rgb(240, 235, 218) !important; + --pwt-color-neutral-alt-95: rgb(202, 205, 202) !important; + --pwt-color-neutral-alt-90: rgb(152, 166, 166) !important; + --pwt-color-neutral-alt-80: rgb(135, 152, 155) !important; + --pwt-color-neutral-alt-70: rgb(115, 132, 138) !important; + --pwt-color-neutral-alt-60: rgb(92, 115, 122) !important; + --pwt-color-neutral-alt-50: rgb(74, 95, 104) !important; + --pwt-color-neutral-alt-40: rgb(58, 78, 86) !important; + --pwt-color-neutral-alt-30: rgb(44, 62, 70) !important; + --pwt-color-neutral-alt-20: rgb(12, 50, 60) !important; + --pwt-color-neutral-alt-15: rgb(4, 40, 50) !important; + --pwt-color-neutral-alt-10: rgb(0, 30, 40) !important; + --pwt-color-neutral-alt-5: rgb(0, 18, 26) !important; + --pwt-color-neutral-alt-0: rgb(0, 0, 0) !important; +} + +/* ===== Semantic Color Remapping (darker surfaces) ===== */ +:root.pwt-dark-mode { + --pwt-color-surface: var(--pwt-color-neutral-10) !important; + --pwt-color-on-surface: var(--pwt-color-neutral-95) !important; + --pwt-color-surface-container: var(--pwt-color-neutral-15) !important; + --pwt-color-on-surface-container: var(--pwt-color-neutral-95) !important; + --pwt-color-neutral: var(--pwt-color-neutral-15) !important; + --pwt-color-on-neutral: var(--pwt-color-neutral-95) !important; + --pwt-color-neutral-container: var(--pwt-color-neutral-10) !important; + --pwt-color-on-neutral-container: var(--pwt-color-neutral-95) !important; + --pwt-color-dark-surface: var(--pwt-color-neutral-10) !important; + --pwt-color-on-dark-surface: var(--pwt-color-neutral-95) !important; + --pwt-color-dark-surface-container: var(--pwt-color-neutral-15) !important; + --pwt-color-on-dark-surface-container: var(--pwt-color-neutral-95) !important; + --pwt-color-neutral-alt: var(--pwt-color-neutral-alt-15) !important; + --pwt-color-on-neutral-alt: var(--pwt-color-neutral-alt-80) !important; + --pwt-color-neutral-alt-container: var(--pwt-color-neutral-alt-10) !important; + --pwt-color-on-neutral-alt-container: var(--pwt-color-neutral-alt-80) !important; + --pwt-color-background: var(--pwt-color-neutral-10) !important; + --pwt-color-inverse-surface: var(--pwt-color-neutral-80) !important; + --pwt-color-on-inverse-surface: var(--pwt-color-neutral-10) !important; + --pwt-color-border: var(--pwt-color-neutral-alt-30) !important; + --pwt-color-shadow: var(--pwt-color-neutral-0) !important; + background: var(--pwt-color-neutral-10) !important; + color: var(--pwt-color-neutral-95) !important; +} + +body { + background-color: var(--pwt-color-neutral-10) !important; +} \ No newline at end of file diff --git a/themes/pdm/theme-solarized-light.css b/themes/pdm/theme-solarized-light.css new file mode 100644 index 0000000..42bb9f2 --- /dev/null +++ b/themes/pdm/theme-solarized-light.css @@ -0,0 +1,194 @@ +/*!Solarized Light*/ +/* + * ProxMorph PDM Theme: Solarized Light + * Overrides the PWT Material Design tonal color system with Solarized Light palette + * Version: 1.0.0 + * Author: ProxMorph / Ethan Schoonover (https://ethanschoonover.com/solarized) + * + * ─── Solarized Light Palette ────────────────────────────────── + * Blue (accent): #268bd2 Cyan: #2aa198 + * Green: #859900 Red: #dc322f + * Yellow: #b58900 Magenta: #d33682 + * Text: #657b83 (base00) Background: #fdf6e3 (base3) + * base1: #93a1a1 base2: #eee8d5 + */ + +/* ===== Tonal Color Overrides ===== */ +:root { + /* Primary — Solarized Blue (#268bd2) tonal scale */ + --pwt-color-primary-100: rgb(255, 255, 255) !important; + --pwt-color-primary-99: rgb(248, 252, 255) !important; + --pwt-color-primary-95: rgb(215, 238, 255) !important; + --pwt-color-primary-90: rgb(178, 222, 252) !important; + --pwt-color-primary-80: rgb(115, 188, 238) !important; + --pwt-color-primary-70: rgb(62, 158, 222) !important; + --pwt-color-primary-60: rgb(38, 139, 210) !important; + --pwt-color-primary-50: rgb(25, 118, 185) !important; + --pwt-color-primary-40: rgb(15, 98, 158) !important; + --pwt-color-primary-30: rgb(6, 78, 130) !important; + --pwt-color-primary-20: rgb(0, 58, 102) !important; + --pwt-color-primary-15: rgb(0, 46, 82) !important; + --pwt-color-primary-10: rgb(0, 34, 62) !important; + --pwt-color-primary-5: rgb(0, 20, 38) !important; + --pwt-color-primary-0: rgb(0, 0, 0) !important; + + /* Secondary — Solarized Cyan (#2aa198) tonal scale */ + --pwt-color-secondary-100: rgb(255, 255, 255) !important; + --pwt-color-secondary-99: rgb(245, 255, 254) !important; + --pwt-color-secondary-95: rgb(208, 248, 244) !important; + --pwt-color-secondary-90: rgb(168, 238, 232) !important; + --pwt-color-secondary-80: rgb(100, 210, 200) !important; + --pwt-color-secondary-70: rgb(55, 180, 172) !important; + --pwt-color-secondary-60: rgb(42, 161, 152) !important; + --pwt-color-secondary-50: rgb(28, 138, 130) !important; + --pwt-color-secondary-40: rgb(16, 115, 108) !important; + --pwt-color-secondary-30: rgb(6, 92, 86) !important; + --pwt-color-secondary-20: rgb(0, 70, 65) !important; + --pwt-color-secondary-15: rgb(0, 55, 52) !important; + --pwt-color-secondary-10: rgb(0, 42, 38) !important; + --pwt-color-secondary-5: rgb(0, 25, 22) !important; + --pwt-color-secondary-0: rgb(0, 0, 0) !important; + + /* Tertiary — Solarized Magenta (#d33682) tonal scale */ + --pwt-color-tertiary-100: rgb(255, 255, 255) !important; + --pwt-color-tertiary-99: rgb(255, 248, 252) !important; + --pwt-color-tertiary-95: rgb(255, 225, 240) !important; + --pwt-color-tertiary-90: rgb(252, 198, 222) !important; + --pwt-color-tertiary-80: rgb(238, 140, 185) !important; + --pwt-color-tertiary-70: rgb(225, 85, 152) !important; + --pwt-color-tertiary-60: rgb(211, 54, 130) !important; + --pwt-color-tertiary-50: rgb(185, 38, 110) !important; + --pwt-color-tertiary-40: rgb(158, 24, 92) !important; + --pwt-color-tertiary-30: rgb(128, 12, 72) !important; + --pwt-color-tertiary-20: rgb(98, 2, 54) !important; + --pwt-color-tertiary-15: rgb(78, 0, 42) !important; + --pwt-color-tertiary-10: rgb(58, 0, 30) !important; + --pwt-color-tertiary-5: rgb(36, 0, 16) !important; + --pwt-color-tertiary-0: rgb(0, 0, 0) !important; + + /* Success — Solarized Green (#859900) tonal scale */ + --pwt-color-success-100: rgb(255, 255, 255) !important; + --pwt-color-success-99: rgb(252, 255, 240) !important; + --pwt-color-success-95: rgb(232, 250, 182) !important; + --pwt-color-success-90: rgb(210, 240, 125) !important; + --pwt-color-success-80: rgb(170, 210, 40) !important; + --pwt-color-success-70: rgb(148, 178, 10) !important; + --pwt-color-success-60: rgb(133, 153, 0) !important; + --pwt-color-success-50: rgb(112, 130, 0) !important; + --pwt-color-success-40: rgb(92, 108, 0) !important; + --pwt-color-success-30: rgb(72, 86, 0) !important; + --pwt-color-success-20: rgb(54, 66, 0) !important; + --pwt-color-success-15: rgb(42, 52, 0) !important; + --pwt-color-success-10: rgb(30, 38, 0) !important; + --pwt-color-success-5: rgb(18, 22, 0) !important; + --pwt-color-success-0: rgb(0, 0, 0) !important; + + /* Error — Solarized Red (#dc322f) tonal scale */ + --pwt-color-error-100: rgb(255, 255, 255) !important; + --pwt-color-error-99: rgb(255, 248, 248) !important; + --pwt-color-error-95: rgb(255, 218, 218) !important; + --pwt-color-error-90: rgb(255, 185, 184) !important; + --pwt-color-error-80: rgb(245, 120, 118) !important; + --pwt-color-error-70: rgb(235, 72, 70) !important; + --pwt-color-error-60: rgb(220, 50, 47) !important; + --pwt-color-error-50: rgb(192, 35, 32) !important; + --pwt-color-error-40: rgb(162, 22, 20) !important; + --pwt-color-error-30: rgb(132, 10, 10) !important; + --pwt-color-error-20: rgb(102, 2, 2) !important; + --pwt-color-error-15: rgb(82, 0, 0) !important; + --pwt-color-error-10: rgb(60, 0, 0) !important; + --pwt-color-error-5: rgb(38, 0, 0) !important; + --pwt-color-error-0: rgb(0, 0, 0) !important; + + /* Warning — Solarized Yellow (#b58900) tonal scale */ + --pwt-color-warning-100: rgb(255, 255, 255) !important; + --pwt-color-warning-99: rgb(255, 252, 242) !important; + --pwt-color-warning-95: rgb(255, 240, 195) !important; + --pwt-color-warning-90: rgb(248, 225, 148) !important; + --pwt-color-warning-80: rgb(232, 195, 62) !important; + --pwt-color-warning-70: rgb(202, 162, 10) !important; + --pwt-color-warning-60: rgb(181, 137, 0) !important; + --pwt-color-warning-50: rgb(155, 115, 0) !important; + --pwt-color-warning-40: rgb(130, 95, 0) !important; + --pwt-color-warning-30: rgb(105, 75, 0) !important; + --pwt-color-warning-20: rgb(80, 56, 0) !important; + --pwt-color-warning-15: rgb(64, 44, 0) !important; + --pwt-color-warning-10: rgb(48, 32, 0) !important; + --pwt-color-warning-5: rgb(28, 18, 0) !important; + --pwt-color-warning-0: rgb(0, 0, 0) !important; + + /* Neutral — Solarized Light Background scale (#fdf6e3 base3) */ + --pwt-color-neutral-100: rgb(255, 255, 255) !important; + --pwt-color-neutral-99: rgb(254, 250, 240) !important; + --pwt-color-neutral-95: rgb(253, 246, 227) !important; + --pwt-color-neutral-90: rgb(238, 232, 213) !important; + --pwt-color-neutral-80: rgb(220, 215, 200) !important; + --pwt-color-neutral-70: rgb(195, 192, 180) !important; + --pwt-color-neutral-60: rgb(147, 161, 161) !important; + --pwt-color-neutral-50: rgb(131, 148, 150) !important; + --pwt-color-neutral-40: rgb(101, 123, 131) !important; + --pwt-color-neutral-30: rgb(88, 110, 117) !important; + --pwt-color-neutral-20: rgb(73, 95, 102) !important; + --pwt-color-neutral-15: rgb(56, 76, 82) !important; + --pwt-color-neutral-10: rgb(42, 60, 65) !important; + --pwt-color-neutral-5: rgb(28, 42, 46) !important; + --pwt-color-neutral-0: rgb(0, 0, 0) !important; + + /* Neutral Alt — Solarized Light content tones */ + --pwt-color-neutral-alt-100: rgb(255, 255, 255) !important; + --pwt-color-neutral-alt-99: rgb(254, 250, 242) !important; + --pwt-color-neutral-alt-95: rgb(252, 248, 232) !important; + --pwt-color-neutral-alt-90: rgb(242, 236, 218) !important; + --pwt-color-neutral-alt-80: rgb(225, 220, 205) !important; + --pwt-color-neutral-alt-70: rgb(200, 196, 185) !important; + --pwt-color-neutral-alt-60: rgb(150, 162, 164) !important; + --pwt-color-neutral-alt-50: rgb(134, 150, 152) !important; + --pwt-color-neutral-alt-40: rgb(105, 126, 134) !important; + --pwt-color-neutral-alt-30: rgb(90, 112, 120) !important; + --pwt-color-neutral-alt-20: rgb(76, 98, 105) !important; + --pwt-color-neutral-alt-15: rgb(60, 80, 86) !important; + --pwt-color-neutral-alt-10: rgb(46, 64, 70) !important; + --pwt-color-neutral-alt-5: rgb(30, 45, 50) !important; + --pwt-color-neutral-alt-0: rgb(0, 0, 0) !important; +} + +/* ===== Semantic Color Remapping (light surfaces) ===== */ +:root.pwt-dark-mode { + --pwt-color-surface: var(--pwt-color-neutral-95) !important; + --pwt-color-on-surface: var(--pwt-color-neutral-10) !important; + --pwt-color-surface-container: var(--pwt-color-neutral-90) !important; + --pwt-color-on-surface-container: var(--pwt-color-neutral-10) !important; + --pwt-color-neutral: var(--pwt-color-neutral-90) !important; + --pwt-color-on-neutral: var(--pwt-color-neutral-10) !important; + --pwt-color-neutral-container: var(--pwt-color-neutral-95) !important; + --pwt-color-on-neutral-container: var(--pwt-color-neutral-10) !important; + --pwt-color-dark-surface: var(--pwt-color-neutral-95) !important; + --pwt-color-on-dark-surface: var(--pwt-color-neutral-10) !important; + --pwt-color-dark-surface-container: var(--pwt-color-neutral-90) !important; + --pwt-color-on-dark-surface-container: var(--pwt-color-neutral-10) !important; + --pwt-color-neutral-alt: var(--pwt-color-neutral-alt-90) !important; + --pwt-color-on-neutral-alt: var(--pwt-color-neutral-alt-20) !important; + --pwt-color-neutral-alt-container: var(--pwt-color-neutral-alt-95) !important; + --pwt-color-on-neutral-alt-container: var(--pwt-color-neutral-alt-20) !important; + --pwt-color-background: var(--pwt-color-neutral-95) !important; + --pwt-color-inverse-surface: var(--pwt-color-neutral-20) !important; + --pwt-color-on-inverse-surface: var(--pwt-color-neutral-95) !important; + --pwt-color-border: var(--pwt-color-neutral-alt-80) !important; + --pwt-color-shadow: rgba(0, 0, 0, 0.12) !important; + --pwt-color-primary: var(--pwt-color-primary-40) !important; + --pwt-color-on-primary: var(--pwt-color-primary-100) !important; + --pwt-color-primary-container: var(--pwt-color-primary-90) !important; + --pwt-color-on-primary-container: var(--pwt-color-primary-10) !important; + background: var(--pwt-color-neutral-95) !important; + color: var(--pwt-color-neutral-10) !important; + color-scheme: light !important; +} + +body { + background-color: var(--pwt-color-neutral-95) !important; +} + +/* ===== Logo — swap to dark variant for light background ===== */ +img[src*="proxmox_logo_white"] { + content: url("/images/proxmox_logo.svg") !important; +} diff --git a/themes/pdm/theme-theraiwy-dark.css b/themes/pdm/theme-theraiwy-dark.css new file mode 100644 index 0000000..0e873a0 --- /dev/null +++ b/themes/pdm/theme-theraiwy-dark.css @@ -0,0 +1,182 @@ +/*!TheRaiwy Dark*/ +/* + * ProxMorph PDM Theme: TheRaiwy Dark + * Overrides the PWT Material Design tonal color system with TheRaiwy cyber palette + * Version: 1.0.0 + * + * ─── TheRaiwy Cyber Dark Palette ──────────────────────────────── + * Accent Red: #dc2626 Emphasis: #c62222 + * Success: #22c55e Danger: #dc2626 + * Attention: #cc9903 Text: #f0ede8 + * Canvas: #080808 Surface: #0d0d0d + * Border: #2e2e31 + */ + +:root { + /* Primary — TheRaiwy Accent Red (#dc2626) tonal scale */ + --pwt-color-primary-100: rgb(255, 255, 255) !important; + --pwt-color-primary-99: rgb(255, 247, 247) !important; + --pwt-color-primary-95: rgb(255, 226, 226) !important; + --pwt-color-primary-90: rgb(255, 202, 202) !important; + --pwt-color-primary-80: rgb(255, 148, 148) !important; + --pwt-color-primary-70: rgb(240, 90, 90) !important; + --pwt-color-primary-60: rgb(220, 38, 38) !important; + --pwt-color-primary-50: rgb(198, 30, 30) !important; + --pwt-color-primary-40: rgb(163, 24, 24) !important; + --pwt-color-primary-30: rgb(128, 18, 18) !important; + --pwt-color-primary-20: rgb(92, 12, 12) !important; + --pwt-color-primary-15: rgb(66, 8, 8) !important; + --pwt-color-primary-10: rgb(42, 5, 5) !important; + --pwt-color-primary-5: rgb(20, 2, 2) !important; + --pwt-color-primary-0: rgb(0, 0, 0) !important; + + /* Secondary — TheRaiwy Muted (#6b6966) tonal scale */ + --pwt-color-secondary-100: rgb(255, 255, 255) !important; + --pwt-color-secondary-99: rgb(247, 246, 245) !important; + --pwt-color-secondary-95: rgb(230, 228, 226) !important; + --pwt-color-secondary-90: rgb(212, 210, 207) !important; + --pwt-color-secondary-80: rgb(176, 174, 170) !important; + --pwt-color-secondary-70: rgb(148, 145, 141) !important; + --pwt-color-secondary-60: rgb(120, 118, 114) !important; + --pwt-color-secondary-50: rgb(107, 105, 102) !important; + --pwt-color-secondary-40: rgb(90, 88, 84) !important; + --pwt-color-secondary-30: rgb(72, 70, 67) !important; + --pwt-color-secondary-20: rgb(54, 53, 50) !important; + --pwt-color-secondary-15: rgb(38, 37, 35) !important; + --pwt-color-secondary-10: rgb(22, 21, 20) !important; + --pwt-color-secondary-5: rgb(12, 11, 10) !important; + --pwt-color-secondary-0: rgb(0, 0, 0) !important; + + /* Tertiary — TheRaiwy Warm Copper (#c08465) tonal scale */ + --pwt-color-tertiary-100: rgb(255, 255, 255) !important; + --pwt-color-tertiary-99: rgb(255, 248, 244) !important; + --pwt-color-tertiary-95: rgb(250, 234, 224) !important; + --pwt-color-tertiary-90: rgb(240, 218, 204) !important; + --pwt-color-tertiary-80: rgb(220, 186, 166) !important; + --pwt-color-tertiary-70: rgb(200, 156, 130) !important; + --pwt-color-tertiary-60: rgb(182, 128, 96) !important; + --pwt-color-tertiary-50: rgb(162, 106, 74) !important; + --pwt-color-tertiary-40: rgb(140, 86, 56) !important; + --pwt-color-tertiary-30: rgb(116, 66, 40) !important; + --pwt-color-tertiary-20: rgb(92, 48, 26) !important; + --pwt-color-tertiary-15: rgb(74, 36, 18) !important; + --pwt-color-tertiary-10: rgb(56, 24, 10) !important; + --pwt-color-tertiary-5: rgb(34, 12, 4) !important; + --pwt-color-tertiary-0: rgb(0, 0, 0) !important; + + /* Success — TheRaiwy Green (#22c55e) */ + --pwt-color-success-100: rgb(255, 255, 255) !important; + --pwt-color-success-99: rgb(242, 255, 246) !important; + --pwt-color-success-95: rgb(210, 250, 222) !important; + --pwt-color-success-90: rgb(172, 242, 196) !important; + --pwt-color-success-80: rgb(114, 225, 150) !important; + --pwt-color-success-70: rgb(60, 200, 110) !important; + --pwt-color-success-60: rgb(34, 197, 94) !important; + --pwt-color-success-50: rgb(22, 163, 74) !important; + --pwt-color-success-40: rgb(16, 138, 60) !important; + --pwt-color-success-30: rgb(10, 112, 46) !important; + --pwt-color-success-20: rgb(6, 86, 34) !important; + --pwt-color-success-15: rgb(2, 68, 24) !important; + --pwt-color-success-10: rgb(0, 50, 16) !important; + --pwt-color-success-5: rgb(0, 30, 8) !important; + --pwt-color-success-0: rgb(0, 0, 0) !important; + + /* Error — TheRaiwy Red (#dc2626) */ + --pwt-color-error-100: rgb(255, 255, 255) !important; + --pwt-color-error-99: rgb(255, 247, 247) !important; + --pwt-color-error-95: rgb(255, 226, 226) !important; + --pwt-color-error-90: rgb(255, 202, 202) !important; + --pwt-color-error-80: rgb(255, 148, 148) !important; + --pwt-color-error-70: rgb(240, 90, 90) !important; + --pwt-color-error-60: rgb(220, 38, 38) !important; + --pwt-color-error-50: rgb(185, 28, 28) !important; + --pwt-color-error-40: rgb(153, 20, 20) !important; + --pwt-color-error-30: rgb(120, 12, 12) !important; + --pwt-color-error-20: rgb(88, 6, 6) !important; + --pwt-color-error-15: rgb(64, 2, 2) !important; + --pwt-color-error-10: rgb(44, 0, 0) !important; + --pwt-color-error-5: rgb(22, 0, 0) !important; + --pwt-color-error-0: rgb(0, 0, 0) !important; + + /* Warning — TheRaiwy Amber (#cc9903) */ + --pwt-color-warning-100: rgb(255, 255, 255) !important; + --pwt-color-warning-99: rgb(255, 252, 242) !important; + --pwt-color-warning-95: rgb(255, 244, 206) !important; + --pwt-color-warning-90: rgb(252, 232, 166) !important; + --pwt-color-warning-80: rgb(240, 210, 106) !important; + --pwt-color-warning-70: rgb(220, 180, 50) !important; + --pwt-color-warning-60: rgb(204, 153, 3) !important; + --pwt-color-warning-50: rgb(176, 130, 2) !important; + --pwt-color-warning-40: rgb(148, 108, 0) !important; + --pwt-color-warning-30: rgb(118, 84, 0) !important; + --pwt-color-warning-20: rgb(90, 62, 0) !important; + --pwt-color-warning-15: rgb(68, 46, 0) !important; + --pwt-color-warning-10: rgb(48, 32, 0) !important; + --pwt-color-warning-5: rgb(26, 16, 0) !important; + --pwt-color-warning-0: rgb(0, 0, 0) !important; + + /* Neutral — TheRaiwy Dark surface scale */ + --pwt-color-neutral-100: rgb(240, 237, 232) !important; + --pwt-color-neutral-99: rgb(224, 222, 218) !important; + --pwt-color-neutral-95: rgb(198, 196, 192) !important; + --pwt-color-neutral-90: rgb(170, 168, 165) !important; + --pwt-color-neutral-80: rgb(136, 134, 131) !important; + --pwt-color-neutral-70: rgb(108, 106, 104) !important; + --pwt-color-neutral-60: rgb(90, 88, 86) !important; + --pwt-color-neutral-50: rgb(72, 70, 68) !important; + --pwt-color-neutral-40: rgb(54, 53, 50) !important; + --pwt-color-neutral-30: rgb(46, 46, 49) !important; + --pwt-color-neutral-20: rgb(22, 22, 24) !important; + --pwt-color-neutral-15: rgb(13, 13, 13) !important; + --pwt-color-neutral-10: rgb(8, 8, 8) !important; + --pwt-color-neutral-5: rgb(4, 4, 4) !important; + --pwt-color-neutral-0: rgb(0, 0, 0) !important; + + /* Neutral Alt — TheRaiwy subtle variant */ + --pwt-color-neutral-alt-100: rgb(240, 237, 232) !important; + --pwt-color-neutral-alt-99: rgb(226, 224, 220) !important; + --pwt-color-neutral-alt-95: rgb(202, 200, 196) !important; + --pwt-color-neutral-alt-90: rgb(176, 174, 170) !important; + --pwt-color-neutral-alt-80: rgb(142, 140, 136) !important; + --pwt-color-neutral-alt-70: rgb(114, 112, 108) !important; + --pwt-color-neutral-alt-60: rgb(96, 94, 90) !important; + --pwt-color-neutral-alt-50: rgb(78, 76, 72) !important; + --pwt-color-neutral-alt-40: rgb(60, 58, 56) !important; + --pwt-color-neutral-alt-30: rgb(50, 48, 46) !important; + --pwt-color-neutral-alt-20: rgb(30, 28, 26) !important; + --pwt-color-neutral-alt-15: rgb(18, 17, 16) !important; + --pwt-color-neutral-alt-10: rgb(12, 11, 10) !important; + --pwt-color-neutral-alt-5: rgb(6, 6, 6) !important; + --pwt-color-neutral-alt-0: rgb(0, 0, 0) !important; +} + +/* ===== Semantic Color Remapping (darker surfaces) ===== */ +:root.pwt-dark-mode { + --pwt-color-surface: var(--pwt-color-neutral-10) !important; + --pwt-color-on-surface: var(--pwt-color-neutral-100) !important; + --pwt-color-surface-container: var(--pwt-color-neutral-15) !important; + --pwt-color-on-surface-container: var(--pwt-color-neutral-100) !important; + --pwt-color-neutral: var(--pwt-color-neutral-15) !important; + --pwt-color-on-neutral: var(--pwt-color-neutral-100) !important; + --pwt-color-neutral-container: var(--pwt-color-neutral-10) !important; + --pwt-color-on-neutral-container: var(--pwt-color-neutral-100) !important; + --pwt-color-dark-surface: var(--pwt-color-neutral-10) !important; + --pwt-color-on-dark-surface: var(--pwt-color-neutral-100) !important; + --pwt-color-dark-surface-container: var(--pwt-color-neutral-15) !important; + --pwt-color-on-dark-surface-container: var(--pwt-color-neutral-100) !important; + --pwt-color-neutral-alt: var(--pwt-color-neutral-alt-15) !important; + --pwt-color-on-neutral-alt: var(--pwt-color-neutral-alt-100) !important; + --pwt-color-neutral-alt-container: var(--pwt-color-neutral-alt-10) !important; + --pwt-color-on-neutral-alt-container: var(--pwt-color-neutral-alt-100) !important; + --pwt-color-background: var(--pwt-color-neutral-10) !important; + --pwt-color-inverse-surface: var(--pwt-color-neutral-100) !important; + --pwt-color-on-inverse-surface: var(--pwt-color-neutral-10) !important; + --pwt-color-border: var(--pwt-color-neutral-30) !important; + --pwt-color-shadow: var(--pwt-color-neutral-0) !important; + background: var(--pwt-color-neutral-10) !important; + color: var(--pwt-color-neutral-100) !important; +} + +body { + background-color: var(--pwt-color-neutral-10) !important; +} diff --git a/themes/pdm/theme-tokyo-night.css b/themes/pdm/theme-tokyo-night.css new file mode 100644 index 0000000..51ec9ae --- /dev/null +++ b/themes/pdm/theme-tokyo-night.css @@ -0,0 +1,181 @@ +/*!Tokyo Night*/ +/* + * ProxMorph PDM Theme: Tokyo Night + * Overrides the PWT Material Design tonal color system with Tokyo Night palette + * Version: 1.0.0 + * + * ─── Tokyo Night Palette ─────────────────────────────────────── + * Accent Blue: #7aa2f7 Purple: #9d7cd8 + * Green: #9ece6a Yellow: #e0af68 + * Red: #f7768e Cyan: #7dcfff + * Text: #c0caf5 Base: #1a1b26 + */ + +:root { + /* Primary — Tokyo Night Blue (#7aa2f7) tonal scale */ + --pwt-color-primary-100: rgb(255, 255, 255) !important; + --pwt-color-primary-99: rgb(248, 252, 255) !important; + --pwt-color-primary-95: rgb(225, 238, 255) !important; + --pwt-color-primary-90: rgb(200, 222, 255) !important; + --pwt-color-primary-80: rgb(155, 192, 252) !important; + --pwt-color-primary-70: rgb(122, 162, 247) !important; + --pwt-color-primary-60: rgb(98, 140, 225) !important; + --pwt-color-primary-50: rgb(78, 118, 200) !important; + --pwt-color-primary-40: rgb(58, 96, 175) !important; + --pwt-color-primary-30: rgb(40, 75, 148) !important; + --pwt-color-primary-20: rgb(25, 55, 118) !important; + --pwt-color-primary-15: rgb(18, 44, 98) !important; + --pwt-color-primary-10: rgb(10, 32, 78) !important; + --pwt-color-primary-5: rgb(4, 18, 50) !important; + --pwt-color-primary-0: rgb(0, 0, 0) !important; + + /* Secondary — Tokyo Night Purple (#9d7cd8) tonal scale */ + --pwt-color-secondary-100: rgb(255, 255, 255) !important; + --pwt-color-secondary-99: rgb(252, 250, 255) !important; + --pwt-color-secondary-95: rgb(238, 228, 255) !important; + --pwt-color-secondary-90: rgb(222, 210, 250) !important; + --pwt-color-secondary-80: rgb(188, 168, 235) !important; + --pwt-color-secondary-70: rgb(157, 124, 216) !important; + --pwt-color-secondary-60: rgb(132, 102, 192) !important; + --pwt-color-secondary-50: rgb(108, 80, 168) !important; + --pwt-color-secondary-40: rgb(85, 60, 145) !important; + --pwt-color-secondary-30: rgb(65, 42, 120) !important; + --pwt-color-secondary-20: rgb(46, 26, 95) !important; + --pwt-color-secondary-15: rgb(36, 18, 78) !important; + --pwt-color-secondary-10: rgb(28, 12, 62) !important; + --pwt-color-secondary-5: rgb(16, 5, 40) !important; + --pwt-color-secondary-0: rgb(0, 0, 0) !important; + + /* Tertiary — Tokyo Night Cyan (#7dcfff) tonal scale */ + --pwt-color-tertiary-100: rgb(255, 255, 255) !important; + --pwt-color-tertiary-99: rgb(248, 254, 255) !important; + --pwt-color-tertiary-95: rgb(222, 248, 255) !important; + --pwt-color-tertiary-90: rgb(195, 238, 255) !important; + --pwt-color-tertiary-80: rgb(150, 218, 255) !important; + --pwt-color-tertiary-70: rgb(125, 207, 255) !important; + --pwt-color-tertiary-60: rgb(98, 182, 230) !important; + --pwt-color-tertiary-50: rgb(75, 155, 205) !important; + --pwt-color-tertiary-40: rgb(55, 130, 178) !important; + --pwt-color-tertiary-30: rgb(38, 105, 150) !important; + --pwt-color-tertiary-20: rgb(22, 80, 120) !important; + --pwt-color-tertiary-15: rgb(14, 65, 100) !important; + --pwt-color-tertiary-10: rgb(8, 48, 78) !important; + --pwt-color-tertiary-5: rgb(2, 30, 50) !important; + --pwt-color-tertiary-0: rgb(0, 0, 0) !important; + + /* Success — Tokyo Night Green (#9ece6a) */ + --pwt-color-success-100: rgb(255, 255, 255) !important; + --pwt-color-success-99: rgb(248, 255, 242) !important; + --pwt-color-success-95: rgb(225, 248, 200) !important; + --pwt-color-success-90: rgb(200, 238, 165) !important; + --pwt-color-success-80: rgb(175, 220, 130) !important; + --pwt-color-success-70: rgb(158, 206, 106) !important; + --pwt-color-success-60: rgb(132, 180, 82) !important; + --pwt-color-success-50: rgb(108, 155, 60) !important; + --pwt-color-success-40: rgb(86, 130, 42) !important; + --pwt-color-success-30: rgb(66, 105, 25) !important; + --pwt-color-success-20: rgb(48, 80, 12) !important; + --pwt-color-success-15: rgb(36, 62, 5) !important; + --pwt-color-success-10: rgb(26, 46, 0) !important; + --pwt-color-success-5: rgb(14, 28, 0) !important; + --pwt-color-success-0: rgb(0, 0, 0) !important; + + /* Error — Tokyo Night Red (#f7768e) */ + --pwt-color-error-100: rgb(255, 255, 255) !important; + --pwt-color-error-99: rgb(255, 249, 250) !important; + --pwt-color-error-95: rgb(255, 232, 236) !important; + --pwt-color-error-90: rgb(255, 210, 218) !important; + --pwt-color-error-80: rgb(252, 165, 180) !important; + --pwt-color-error-70: rgb(247, 118, 142) !important; + --pwt-color-error-60: rgb(225, 92, 118) !important; + --pwt-color-error-50: rgb(200, 68, 95) !important; + --pwt-color-error-40: rgb(172, 46, 72) !important; + --pwt-color-error-30: rgb(145, 26, 52) !important; + --pwt-color-error-20: rgb(112, 10, 35) !important; + --pwt-color-error-15: rgb(90, 4, 24) !important; + --pwt-color-error-10: rgb(68, 0, 14) !important; + --pwt-color-error-5: rgb(45, 0, 6) !important; + --pwt-color-error-0: rgb(0, 0, 0) !important; + + /* Warning — Tokyo Night Yellow (#e0af68) */ + --pwt-color-warning-100: rgb(255, 255, 255) !important; + --pwt-color-warning-99: rgb(255, 252, 246) !important; + --pwt-color-warning-95: rgb(255, 242, 215) !important; + --pwt-color-warning-90: rgb(248, 228, 180) !important; + --pwt-color-warning-80: rgb(238, 200, 138) !important; + --pwt-color-warning-70: rgb(224, 175, 104) !important; + --pwt-color-warning-60: rgb(200, 152, 80) !important; + --pwt-color-warning-50: rgb(175, 130, 58) !important; + --pwt-color-warning-40: rgb(150, 108, 38) !important; + --pwt-color-warning-30: rgb(122, 85, 20) !important; + --pwt-color-warning-20: rgb(95, 65, 8) !important; + --pwt-color-warning-15: rgb(75, 50, 2) !important; + --pwt-color-warning-10: rgb(55, 36, 0) !important; + --pwt-color-warning-5: rgb(35, 22, 0) !important; + --pwt-color-warning-0: rgb(0, 0, 0) !important; + + /* Neutral — Tokyo Night Background scale */ + --pwt-color-neutral-100: rgb(192, 202, 245) !important; + --pwt-color-neutral-99: rgb(185, 196, 240) !important; + --pwt-color-neutral-95: rgb(169, 177, 214) !important; + --pwt-color-neutral-90: rgb(148, 160, 198) !important; + --pwt-color-neutral-80: rgb(125, 138, 178) !important; + --pwt-color-neutral-70: rgb(105, 118, 158) !important; + --pwt-color-neutral-60: rgb(86, 98, 138) !important; + --pwt-color-neutral-50: rgb(68, 80, 118) !important; + --pwt-color-neutral-40: rgb(52, 62, 98) !important; + --pwt-color-neutral-30: rgb(36, 40, 59) !important; + --pwt-color-neutral-20: rgb(31, 35, 53) !important; + --pwt-color-neutral-15: rgb(26, 27, 38) !important; + --pwt-color-neutral-10: rgb(22, 22, 30) !important; + --pwt-color-neutral-5: rgb(14, 14, 20) !important; + --pwt-color-neutral-0: rgb(0, 0, 0) !important; + + /* Neutral Alt */ + --pwt-color-neutral-alt-100: rgb(192, 202, 245) !important; + --pwt-color-neutral-alt-99: rgb(188, 198, 242) !important; + --pwt-color-neutral-alt-95: rgb(172, 182, 225) !important; + --pwt-color-neutral-alt-90: rgb(152, 162, 205) !important; + --pwt-color-neutral-alt-80: rgb(128, 140, 182) !important; + --pwt-color-neutral-alt-70: rgb(108, 120, 162) !important; + --pwt-color-neutral-alt-60: rgb(88, 100, 142) !important; + --pwt-color-neutral-alt-50: rgb(70, 82, 122) !important; + --pwt-color-neutral-alt-40: rgb(54, 65, 102) !important; + --pwt-color-neutral-alt-30: rgb(38, 48, 78) !important; + --pwt-color-neutral-alt-20: rgb(28, 34, 56) !important; + --pwt-color-neutral-alt-15: rgb(22, 26, 42) !important; + --pwt-color-neutral-alt-10: rgb(18, 20, 32) !important; + --pwt-color-neutral-alt-5: rgb(12, 12, 22) !important; + --pwt-color-neutral-alt-0: rgb(0, 0, 0) !important; +} + +/* ===== Semantic Color Remapping (darker surfaces) ===== */ +:root.pwt-dark-mode { + --pwt-color-surface: var(--pwt-color-neutral-10) !important; + --pwt-color-on-surface: var(--pwt-color-neutral-95) !important; + --pwt-color-surface-container: var(--pwt-color-neutral-15) !important; + --pwt-color-on-surface-container: var(--pwt-color-neutral-95) !important; + --pwt-color-neutral: var(--pwt-color-neutral-15) !important; + --pwt-color-on-neutral: var(--pwt-color-neutral-95) !important; + --pwt-color-neutral-container: var(--pwt-color-neutral-10) !important; + --pwt-color-on-neutral-container: var(--pwt-color-neutral-95) !important; + --pwt-color-dark-surface: var(--pwt-color-neutral-10) !important; + --pwt-color-on-dark-surface: var(--pwt-color-neutral-95) !important; + --pwt-color-dark-surface-container: var(--pwt-color-neutral-15) !important; + --pwt-color-on-dark-surface-container: var(--pwt-color-neutral-95) !important; + --pwt-color-neutral-alt: var(--pwt-color-neutral-alt-15) !important; + --pwt-color-on-neutral-alt: var(--pwt-color-neutral-alt-80) !important; + --pwt-color-neutral-alt-container: var(--pwt-color-neutral-alt-10) !important; + --pwt-color-on-neutral-alt-container: var(--pwt-color-neutral-alt-80) !important; + --pwt-color-background: var(--pwt-color-neutral-10) !important; + --pwt-color-inverse-surface: var(--pwt-color-neutral-80) !important; + --pwt-color-on-inverse-surface: var(--pwt-color-neutral-10) !important; + --pwt-color-border: var(--pwt-color-neutral-alt-30) !important; + --pwt-color-shadow: var(--pwt-color-neutral-0) !important; + background: var(--pwt-color-neutral-10) !important; + color: var(--pwt-color-neutral-95) !important; +} + +body { + background-color: var(--pwt-color-neutral-10) !important; +} \ No newline at end of file diff --git a/themes/pdm/theme-unifi-light.css b/themes/pdm/theme-unifi-light.css new file mode 100644 index 0000000..b6eb3ba --- /dev/null +++ b/themes/pdm/theme-unifi-light.css @@ -0,0 +1,194 @@ +/*!UniFi Light*/ +/* + * ProxMorph PDM Theme: UniFi Light + * Overrides the PWT Material Design tonal color system with UniFi Light palette + * Version: 1.0.0 + * Author: ProxMorph / Ubiquiti Design System + * + * ─── UniFi Light Palette ────────────────────────────────────── + * Blue (accent): #006FFF Secondary: #00A4E4 + * Green: #00C853 Red: #F44336 + * Yellow: #FFB300 Purple: #7B1FA2 + * Text (dark): #1A1A1A Background:#F5F6FA + * Surface: #FFFFFF Border: #E0E0E0 + */ + +/* ===== Tonal Color Overrides ===== */ +:root { + /* Primary — UniFi Blue (#006FFF) tonal scale */ + --pwt-color-primary-100: rgb(255, 255, 255) !important; + --pwt-color-primary-99: rgb(248, 251, 255) !important; + --pwt-color-primary-95: rgb(215, 232, 255) !important; + --pwt-color-primary-90: rgb(178, 212, 255) !important; + --pwt-color-primary-80: rgb(105, 170, 255) !important; + --pwt-color-primary-70: rgb(50, 135, 255) !important; + --pwt-color-primary-60: rgb(0, 111, 255) !important; + --pwt-color-primary-50: rgb(0, 92, 218) !important; + --pwt-color-primary-40: rgb(0, 74, 182) !important; + --pwt-color-primary-30: rgb(0, 56, 145) !important; + --pwt-color-primary-20: rgb(0, 40, 110) !important; + --pwt-color-primary-15: rgb(0, 30, 88) !important; + --pwt-color-primary-10: rgb(0, 22, 68) !important; + --pwt-color-primary-5: rgb(0, 12, 42) !important; + --pwt-color-primary-0: rgb(0, 0, 0) !important; + + /* Secondary — UniFi Teal (#00A4E4) tonal scale */ + --pwt-color-secondary-100: rgb(255, 255, 255) !important; + --pwt-color-secondary-99: rgb(245, 253, 255) !important; + --pwt-color-secondary-95: rgb(210, 245, 255) !important; + --pwt-color-secondary-90: rgb(170, 232, 252) !important; + --pwt-color-secondary-80: rgb(100, 202, 238) !important; + --pwt-color-secondary-70: rgb(40, 178, 232) !important; + --pwt-color-secondary-60: rgb(0, 164, 228) !important; + --pwt-color-secondary-50: rgb(0, 138, 198) !important; + --pwt-color-secondary-40: rgb(0, 112, 165) !important; + --pwt-color-secondary-30: rgb(0, 88, 132) !important; + --pwt-color-secondary-20: rgb(0, 65, 100) !important; + --pwt-color-secondary-15: rgb(0, 50, 80) !important; + --pwt-color-secondary-10: rgb(0, 38, 60) !important; + --pwt-color-secondary-5: rgb(0, 22, 38) !important; + --pwt-color-secondary-0: rgb(0, 0, 0) !important; + + /* Tertiary — UniFi Purple (#7B1FA2) tonal scale */ + --pwt-color-tertiary-100: rgb(255, 255, 255) !important; + --pwt-color-tertiary-99: rgb(255, 248, 255) !important; + --pwt-color-tertiary-95: rgb(248, 225, 255) !important; + --pwt-color-tertiary-90: rgb(235, 198, 255) !important; + --pwt-color-tertiary-80: rgb(208, 148, 242) !important; + --pwt-color-tertiary-70: rgb(175, 95, 215) !important; + --pwt-color-tertiary-60: rgb(123, 31, 162) !important; + --pwt-color-tertiary-50: rgb(105, 20, 140) !important; + --pwt-color-tertiary-40: rgb(85, 12, 118) !important; + --pwt-color-tertiary-30: rgb(68, 5, 95) !important; + --pwt-color-tertiary-20: rgb(50, 0, 72) !important; + --pwt-color-tertiary-15: rgb(40, 0, 58) !important; + --pwt-color-tertiary-10: rgb(28, 0, 42) !important; + --pwt-color-tertiary-5: rgb(16, 0, 25) !important; + --pwt-color-tertiary-0: rgb(0, 0, 0) !important; + + /* Success — UniFi Green (#00C853) tonal scale */ + --pwt-color-success-100: rgb(255, 255, 255) !important; + --pwt-color-success-99: rgb(245, 255, 248) !important; + --pwt-color-success-95: rgb(200, 255, 218) !important; + --pwt-color-success-90: rgb(150, 248, 185) !important; + --pwt-color-success-80: rgb(80, 228, 138) !important; + --pwt-color-success-70: rgb(20, 210, 100) !important; + --pwt-color-success-60: rgb(0, 200, 83) !important; + --pwt-color-success-50: rgb(0, 172, 68) !important; + --pwt-color-success-40: rgb(0, 142, 52) !important; + --pwt-color-success-30: rgb(0, 115, 38) !important; + --pwt-color-success-20: rgb(0, 88, 26) !important; + --pwt-color-success-15: rgb(0, 70, 18) !important; + --pwt-color-success-10: rgb(0, 52, 12) !important; + --pwt-color-success-5: rgb(0, 32, 5) !important; + --pwt-color-success-0: rgb(0, 0, 0) !important; + + /* Error — UniFi Red (#F44336) tonal scale */ + --pwt-color-error-100: rgb(255, 255, 255) !important; + --pwt-color-error-99: rgb(255, 248, 248) !important; + --pwt-color-error-95: rgb(255, 218, 215) !important; + --pwt-color-error-90: rgb(255, 185, 180) !important; + --pwt-color-error-80: rgb(252, 128, 118) !important; + --pwt-color-error-70: rgb(248, 88, 75) !important; + --pwt-color-error-60: rgb(244, 67, 54) !important; + --pwt-color-error-50: rgb(215, 48, 38) !important; + --pwt-color-error-40: rgb(182, 32, 24) !important; + --pwt-color-error-30: rgb(148, 18, 12) !important; + --pwt-color-error-20: rgb(115, 6, 2) !important; + --pwt-color-error-15: rgb(92, 0, 0) !important; + --pwt-color-error-10: rgb(68, 0, 0) !important; + --pwt-color-error-5: rgb(42, 0, 0) !important; + --pwt-color-error-0: rgb(0, 0, 0) !important; + + /* Warning — UniFi Amber (#FFB300) tonal scale */ + --pwt-color-warning-100: rgb(255, 255, 255) !important; + --pwt-color-warning-99: rgb(255, 252, 242) !important; + --pwt-color-warning-95: rgb(255, 240, 195) !important; + --pwt-color-warning-90: rgb(255, 225, 145) !important; + --pwt-color-warning-80: rgb(255, 200, 60) !important; + --pwt-color-warning-70: rgb(255, 185, 15) !important; + --pwt-color-warning-60: rgb(255, 179, 0) !important; + --pwt-color-warning-50: rgb(222, 152, 0) !important; + --pwt-color-warning-40: rgb(188, 126, 0) !important; + --pwt-color-warning-30: rgb(155, 100, 0) !important; + --pwt-color-warning-20: rgb(120, 76, 0) !important; + --pwt-color-warning-15: rgb(96, 58, 0) !important; + --pwt-color-warning-10: rgb(72, 42, 0) !important; + --pwt-color-warning-5: rgb(44, 24, 0) !important; + --pwt-color-warning-0: rgb(0, 0, 0) !important; + + /* Neutral — UniFi Light Background scale (#F5F6FA base) */ + --pwt-color-neutral-100: rgb(255, 255, 255) !important; + --pwt-color-neutral-99: rgb(250, 250, 252) !important; + --pwt-color-neutral-95: rgb(245, 246, 250) !important; + --pwt-color-neutral-90: rgb(235, 236, 242) !important; + --pwt-color-neutral-80: rgb(224, 224, 230) !important; + --pwt-color-neutral-70: rgb(200, 200, 210) !important; + --pwt-color-neutral-60: rgb(170, 172, 185) !important; + --pwt-color-neutral-50: rgb(140, 142, 158) !important; + --pwt-color-neutral-40: rgb(108, 110, 128) !important; + --pwt-color-neutral-30: rgb(82, 84, 100) !important; + --pwt-color-neutral-20: rgb(58, 60, 75) !important; + --pwt-color-neutral-15: rgb(42, 44, 58) !important; + --pwt-color-neutral-10: rgb(26, 26, 38) !important; + --pwt-color-neutral-5: rgb(16, 16, 24) !important; + --pwt-color-neutral-0: rgb(0, 0, 0) !important; + + /* Neutral Alt — UniFi Light border/surface tones */ + --pwt-color-neutral-alt-100: rgb(255, 255, 255) !important; + --pwt-color-neutral-alt-99: rgb(250, 251, 254) !important; + --pwt-color-neutral-alt-95: rgb(242, 244, 248) !important; + --pwt-color-neutral-alt-90: rgb(232, 234, 240) !important; + --pwt-color-neutral-alt-80: rgb(218, 220, 228) !important; + --pwt-color-neutral-alt-70: rgb(196, 198, 208) !important; + --pwt-color-neutral-alt-60: rgb(168, 170, 182) !important; + --pwt-color-neutral-alt-50: rgb(138, 140, 155) !important; + --pwt-color-neutral-alt-40: rgb(106, 108, 126) !important; + --pwt-color-neutral-alt-30: rgb(80, 82, 98) !important; + --pwt-color-neutral-alt-20: rgb(56, 58, 72) !important; + --pwt-color-neutral-alt-15: rgb(42, 44, 56) !important; + --pwt-color-neutral-alt-10: rgb(28, 28, 40) !important; + --pwt-color-neutral-alt-5: rgb(16, 16, 26) !important; + --pwt-color-neutral-alt-0: rgb(0, 0, 0) !important; +} + +/* ===== Semantic Color Remapping (light surfaces) ===== */ +:root.pwt-dark-mode { + --pwt-color-surface: var(--pwt-color-neutral-95) !important; + --pwt-color-on-surface: var(--pwt-color-neutral-10) !important; + --pwt-color-surface-container: var(--pwt-color-neutral-90) !important; + --pwt-color-on-surface-container: var(--pwt-color-neutral-10) !important; + --pwt-color-neutral: var(--pwt-color-neutral-90) !important; + --pwt-color-on-neutral: var(--pwt-color-neutral-10) !important; + --pwt-color-neutral-container: var(--pwt-color-neutral-95) !important; + --pwt-color-on-neutral-container: var(--pwt-color-neutral-10) !important; + --pwt-color-dark-surface: var(--pwt-color-neutral-95) !important; + --pwt-color-on-dark-surface: var(--pwt-color-neutral-10) !important; + --pwt-color-dark-surface-container: var(--pwt-color-neutral-90) !important; + --pwt-color-on-dark-surface-container: var(--pwt-color-neutral-10) !important; + --pwt-color-neutral-alt: var(--pwt-color-neutral-alt-90) !important; + --pwt-color-on-neutral-alt: var(--pwt-color-neutral-alt-20) !important; + --pwt-color-neutral-alt-container: var(--pwt-color-neutral-alt-95) !important; + --pwt-color-on-neutral-alt-container: var(--pwt-color-neutral-alt-20) !important; + --pwt-color-background: var(--pwt-color-neutral-95) !important; + --pwt-color-inverse-surface: var(--pwt-color-neutral-20) !important; + --pwt-color-on-inverse-surface: var(--pwt-color-neutral-95) !important; + --pwt-color-border: var(--pwt-color-neutral-alt-80) !important; + --pwt-color-shadow: rgba(0, 0, 0, 0.12) !important; + --pwt-color-primary: var(--pwt-color-primary-40) !important; + --pwt-color-on-primary: var(--pwt-color-primary-100) !important; + --pwt-color-primary-container: var(--pwt-color-primary-90) !important; + --pwt-color-on-primary-container: var(--pwt-color-primary-10) !important; + background: var(--pwt-color-neutral-95) !important; + color: var(--pwt-color-neutral-10) !important; + color-scheme: light !important; +} + +body { + background-color: var(--pwt-color-neutral-95) !important; +} + +/* ===== Logo — swap to dark variant for light background ===== */ +img[src*="proxmox_logo_white"] { + content: url("/images/proxmox_logo.svg") !important; +} diff --git a/themes/pdm/theme-unifi.css b/themes/pdm/theme-unifi.css new file mode 100644 index 0000000..ba83948 --- /dev/null +++ b/themes/pdm/theme-unifi.css @@ -0,0 +1,192 @@ +/*!UniFi*/ +/* + * ProxMorph PDM Theme: UniFi + * Overrides the PWT Material Design tonal color system with UniFi palette + * Version: 1.0.0 + * Author: ProxMorph / Ubiquiti Design System + * + * ─── UniFi Palette ───────────────────────────────────────────── + * Accent Blue: #006EFF Blue Hover: #4797FF + * Success: #37BE5F Warning: #f5a623 + * Danger: #f03a3e Text: #DEE0E3 + * Base: #131416 Surface: #282B2F + * Elevated: #34383D + */ + +/* ===== Tonal Color Overrides ===== */ +:root { + /* Primary — UniFi Blue (#006EFF) tonal scale */ + --pwt-color-primary-100: rgb(255, 255, 255) !important; + --pwt-color-primary-99: rgb(245, 250, 255) !important; + --pwt-color-primary-95: rgb(220, 238, 255) !important; + --pwt-color-primary-90: rgb(190, 222, 255) !important; + --pwt-color-primary-80: rgb(130, 190, 255) !important; + --pwt-color-primary-70: rgb(71, 151, 255) !important; + --pwt-color-primary-60: rgb(0, 110, 255) !important; + --pwt-color-primary-50: rgb(0, 90, 210) !important; + --pwt-color-primary-40: rgb(0, 72, 170) !important; + --pwt-color-primary-30: rgb(0, 55, 135) !important; + --pwt-color-primary-20: rgb(0, 40, 100) !important; + --pwt-color-primary-15: rgb(0, 30, 80) !important; + --pwt-color-primary-10: rgb(0, 22, 62) !important; + --pwt-color-primary-5: rgb(0, 12, 40) !important; + --pwt-color-primary-0: rgb(0, 0, 0) !important; + + /* Secondary — UniFi Dim Blue tonal scale */ + --pwt-color-secondary-100: rgb(255, 255, 255) !important; + --pwt-color-secondary-99: rgb(248, 250, 255) !important; + --pwt-color-secondary-95: rgb(228, 235, 248) !important; + --pwt-color-secondary-90: rgb(208, 218, 238) !important; + --pwt-color-secondary-80: rgb(175, 190, 215) !important; + --pwt-color-secondary-70: rgb(145, 162, 192) !important; + --pwt-color-secondary-60: rgb(115, 124, 135) !important; + --pwt-color-secondary-50: rgb(95, 105, 118) !important; + --pwt-color-secondary-40: rgb(75, 85, 98) !important; + --pwt-color-secondary-30: rgb(52, 56, 61) !important; + --pwt-color-secondary-20: rgb(40, 43, 47) !important; + --pwt-color-secondary-15: rgb(32, 35, 38) !important; + --pwt-color-secondary-10: rgb(24, 26, 30) !important; + --pwt-color-secondary-5: rgb(16, 17, 20) !important; + --pwt-color-secondary-0: rgb(0, 0, 0) !important; + + /* Tertiary — UniFi Cyan/Teal tonal scale */ + --pwt-color-tertiary-100: rgb(255, 255, 255) !important; + --pwt-color-tertiary-99: rgb(248, 254, 255) !important; + --pwt-color-tertiary-95: rgb(225, 248, 255) !important; + --pwt-color-tertiary-90: rgb(195, 238, 252) !important; + --pwt-color-tertiary-80: rgb(140, 215, 240) !important; + --pwt-color-tertiary-70: rgb(90, 192, 225) !important; + --pwt-color-tertiary-60: rgb(50, 168, 200) !important; + --pwt-color-tertiary-50: rgb(20, 142, 175) !important; + --pwt-color-tertiary-40: rgb(0, 118, 150) !important; + --pwt-color-tertiary-30: rgb(0, 92, 120) !important; + --pwt-color-tertiary-20: rgb(0, 68, 92) !important; + --pwt-color-tertiary-15: rgb(0, 52, 72) !important; + --pwt-color-tertiary-10: rgb(0, 38, 55) !important; + --pwt-color-tertiary-5: rgb(0, 22, 35) !important; + --pwt-color-tertiary-0: rgb(0, 0, 0) !important; + + /* Success — UniFi Green (#37BE5F) tonal scale */ + --pwt-color-success-100: rgb(255, 255, 255) !important; + --pwt-color-success-99: rgb(242, 255, 246) !important; + --pwt-color-success-95: rgb(205, 255, 220) !important; + --pwt-color-success-90: rgb(160, 248, 185) !important; + --pwt-color-success-80: rgb(100, 220, 135) !important; + --pwt-color-success-70: rgb(55, 190, 95) !important; + --pwt-color-success-60: rgb(40, 165, 78) !important; + --pwt-color-success-50: rgb(25, 140, 60) !important; + --pwt-color-success-40: rgb(12, 115, 45) !important; + --pwt-color-success-30: rgb(0, 90, 32) !important; + --pwt-color-success-20: rgb(0, 66, 20) !important; + --pwt-color-success-15: rgb(0, 50, 14) !important; + --pwt-color-success-10: rgb(0, 36, 8) !important; + --pwt-color-success-5: rgb(0, 22, 4) !important; + --pwt-color-success-0: rgb(0, 0, 0) !important; + + /* Error — UniFi Danger (#f03a3e) tonal scale */ + --pwt-color-error-100: rgb(255, 255, 255) !important; + --pwt-color-error-99: rgb(255, 248, 248) !important; + --pwt-color-error-95: rgb(255, 228, 228) !important; + --pwt-color-error-90: rgb(255, 200, 202) !important; + --pwt-color-error-80: rgb(255, 145, 148) !important; + --pwt-color-error-70: rgb(248, 95, 98) !important; + --pwt-color-error-60: rgb(240, 58, 62) !important; + --pwt-color-error-50: rgb(210, 40, 44) !important; + --pwt-color-error-40: rgb(180, 24, 28) !important; + --pwt-color-error-30: rgb(148, 10, 14) !important; + --pwt-color-error-20: rgb(110, 4, 8) !important; + --pwt-color-error-15: rgb(88, 0, 2) !important; + --pwt-color-error-10: rgb(65, 0, 0) !important; + --pwt-color-error-5: rgb(42, 0, 0) !important; + --pwt-color-error-0: rgb(0, 0, 0) !important; + + /* Warning — UniFi Warning (#f5a623) tonal scale */ + --pwt-color-warning-100: rgb(255, 255, 255) !important; + --pwt-color-warning-99: rgb(255, 252, 245) !important; + --pwt-color-warning-95: rgb(255, 242, 210) !important; + --pwt-color-warning-90: rgb(255, 228, 168) !important; + --pwt-color-warning-80: rgb(252, 205, 105) !important; + --pwt-color-warning-70: rgb(245, 166, 35) !important; + --pwt-color-warning-60: rgb(218, 145, 20) !important; + --pwt-color-warning-50: rgb(190, 122, 8) !important; + --pwt-color-warning-40: rgb(158, 100, 0) !important; + --pwt-color-warning-30: rgb(125, 78, 0) !important; + --pwt-color-warning-20: rgb(92, 56, 0) !important; + --pwt-color-warning-15: rgb(72, 42, 0) !important; + --pwt-color-warning-10: rgb(52, 30, 0) !important; + --pwt-color-warning-5: rgb(32, 18, 0) !important; + --pwt-color-warning-0: rgb(0, 0, 0) !important; + + /* Neutral — UniFi Dark Background scale */ + --pwt-color-neutral-100: rgb(249, 250, 250) !important; + --pwt-color-neutral-99: rgb(240, 242, 244) !important; + --pwt-color-neutral-95: rgb(222, 224, 227) !important; + --pwt-color-neutral-90: rgb(200, 205, 210) !important; + --pwt-color-neutral-80: rgb(183, 188, 194) !important; + --pwt-color-neutral-70: rgb(155, 162, 172) !important; + --pwt-color-neutral-60: rgb(115, 124, 135) !important; + --pwt-color-neutral-50: rgb(90, 98, 108) !important; + --pwt-color-neutral-40: rgb(68, 72, 78) !important; + --pwt-color-neutral-30: rgb(52, 56, 61) !important; + --pwt-color-neutral-20: rgb(40, 43, 47) !important; + --pwt-color-neutral-15: rgb(28, 30, 34) !important; + --pwt-color-neutral-10: rgb(19, 20, 22) !important; + --pwt-color-neutral-5: rgb(12, 12, 14) !important; + --pwt-color-neutral-0: rgb(0, 0, 0) !important; + + /* Neutral Alt — UniFi Alt tones */ + --pwt-color-neutral-alt-100: rgb(249, 250, 250) !important; + --pwt-color-neutral-alt-99: rgb(242, 245, 248) !important; + --pwt-color-neutral-alt-95: rgb(225, 230, 238) !important; + --pwt-color-neutral-alt-90: rgb(208, 215, 225) !important; + --pwt-color-neutral-alt-80: rgb(178, 188, 200) !important; + --pwt-color-neutral-alt-70: rgb(148, 158, 172) !important; + --pwt-color-neutral-alt-60: rgb(118, 128, 142) !important; + --pwt-color-neutral-alt-50: rgb(92, 102, 115) !important; + --pwt-color-neutral-alt-40: rgb(68, 76, 88) !important; + --pwt-color-neutral-alt-30: rgb(48, 54, 64) !important; + --pwt-color-neutral-alt-20: rgb(35, 40, 48) !important; + --pwt-color-neutral-alt-15: rgb(26, 30, 36) !important; + --pwt-color-neutral-alt-10: rgb(18, 20, 26) !important; + --pwt-color-neutral-alt-5: rgb(10, 12, 16) !important; + --pwt-color-neutral-alt-0: rgb(0, 0, 0) !important; +} + +/* ===== Semantic Color Remapping (darker surfaces to match PVE) ===== */ +:root.pwt-dark-mode { + /* Flat surfaces — panels slightly elevated above background */ + --pwt-color-surface: var(--pwt-color-neutral-10) !important; + --pwt-color-on-surface: var(--pwt-color-neutral-95) !important; + --pwt-color-surface-container: var(--pwt-color-neutral-15) !important; + --pwt-color-on-surface-container: var(--pwt-color-neutral-95) !important; + --pwt-color-neutral: var(--pwt-color-neutral-15) !important; + --pwt-color-on-neutral: var(--pwt-color-neutral-95) !important; + --pwt-color-neutral-container: var(--pwt-color-neutral-10) !important; + --pwt-color-on-neutral-container: var(--pwt-color-neutral-95) !important; + --pwt-color-dark-surface: var(--pwt-color-neutral-10) !important; + --pwt-color-on-dark-surface: var(--pwt-color-neutral-95) !important; + --pwt-color-dark-surface-container: var(--pwt-color-neutral-15) !important; + --pwt-color-on-dark-surface-container: var(--pwt-color-neutral-95) !important; + --pwt-color-neutral-alt: var(--pwt-color-neutral-alt-15) !important; + --pwt-color-on-neutral-alt: var(--pwt-color-neutral-alt-80) !important; + --pwt-color-neutral-alt-container: var(--pwt-color-neutral-alt-10) !important; + --pwt-color-on-neutral-alt-container: var(--pwt-color-neutral-alt-80) !important; + --pwt-color-background: var(--pwt-color-neutral-10) !important; + --pwt-color-inverse-surface: var(--pwt-color-neutral-80) !important; + --pwt-color-on-inverse-surface: var(--pwt-color-neutral-10) !important; + --pwt-color-border: var(--pwt-color-neutral-alt-30) !important; + --pwt-color-shadow: var(--pwt-color-neutral-0) !important; + + /* Vivid primary — match PVE's #006EFF accent */ + --pwt-color-primary: var(--pwt-color-primary-60) !important; + --pwt-color-on-primary: var(--pwt-color-primary-100) !important; + --pwt-color-primary-container: var(--pwt-color-primary-30) !important; + --pwt-color-on-primary-container: var(--pwt-color-primary-90) !important; + + background: var(--pwt-color-neutral-10) !important; + color: var(--pwt-color-neutral-95) !important; +} + +body { + background-color: rgb(19, 20, 22) !important; +} diff --git a/themes/theme-blue-slate.css b/themes/theme-blue-slate.css new file mode 100644 index 0000000..396951d --- /dev/null +++ b/themes/theme-blue-slate.css @@ -0,0 +1,1965 @@ +/*!Blue Slate*/ +/* + * ProxMorph Theme: Blue Slate + * A clean, minimal dark theme with blue accent - Tailwind Slate palette + * Version: 2.0.0 + * + * v2.0.0: Complete overhaul - ported all Tier 2 fixes from Dracula reference + * - Global border-radius architecture (reset/re-apply) + * - FontAwesome tool icons, button 28px height, icon alignment + * - Custom checkboxes/radios, menu flex layout, dropdown fixes + * - Console, charts, tags, APT repos, markdown, date picker + * - Hardware icon invert(100%) with double-cancellation + * - Transitions, keyboard focus removal, cursor:pointer + * + * --- Blue Slate Palette (Tailwind Slate) --- + * Accent: #3b82f6 Accent Light: #60a5fa Accent Dark: #2563eb + * Success: #10b981 Warning: #f59e0b Error: #ef4444 + * Info: #06b6d4 + * BG Base: #0f172a BG Surface: #1e293b BG Elevated: #334155 + * Text: #f1f5f9 Text Dim: #cbd5e1 Text Muted: #94a3b8 + * Border: #475569 Border Sub: #334155 + */ + +/* ===== CSS VARIABLES ===== */ +:root { + --pm-accent: #3b82f6; + --pm-accent-light: #60a5fa; + --pm-accent-dark: #2563eb; + --pm-success: #10b981; + --pm-warning: #f59e0b; + --pm-error: #ef4444; + --pm-info: #06b6d4; + --pm-bg-base: #0f172a; + --pm-bg-surface: #1e293b; + --pm-bg-elevated: #334155; + --pm-text: #f1f5f9; + --pm-text-dim: #cbd5e1; + --pm-text-muted: #94a3b8; + --pm-border: #475569; + --pm-border-subtle: #334155; + --pm-radius-sm: 4px; + --pm-radius-md: 6px; + --pm-radius-lg: 8px; + + --pwt-panel-background: var(--pm-bg-base); + --pwt-text-color: var(--pm-text-dim); + --pwt-gauge-default: var(--pm-accent); + --pwt-gauge-back: var(--pm-bg-elevated); + --pwt-gauge-warn: var(--pm-warning); + --pwt-gauge-crit: var(--pm-error); + --pwt-chart-primary: var(--pm-success); + --pwt-chart-grid-stroke: var(--pm-border); + + --pm-on-accent: #0f172a; + --pm-hover-overlay: rgba(71, 85, 105, 0.15); + --pm-select-overlay: rgba(59, 130, 246, 0.25); + --pm-accent-muted: rgba(59, 130, 246, 0.4); + --pm-accent-subtle: rgba(59, 130, 246, 0.15); + + color-scheme: dark; +} + +/* ===== GLOBAL BORDER-RADIUS ARCHITECTURE ===== */ +.x-border-box, +.x-border-box * { + border-radius: var(--pm-radius-lg); +} + +.x-grid, .x-grid *, .x-grid-header-ct, .x-grid-header-ct *, +.x-grid-view, .x-grid-view *, .x-column-header, .x-column-header *, +.x-grid-item, .x-grid-cell, .x-grid-cell-inner, .x-grid-row, +table, table *, tr, td, th, +.x-legend, .x-legend *, .x-legend-container, .x-legend-container *, +.x-legend-item, .x-legend-horizontal .x-legend-item, .x-legend-vertical .x-legend-item, +.x-legend-horizontal .x-legend-item:first-child, .x-legend-horizontal .x-legend-item:last-child, +.x-legend-vertical .x-legend-item:first-child, .x-legend-vertical .x-legend-item:last-child, +.x-tool, .x-tool-tool-el, .x-tool-default, .x-tool-img { + border-radius: 0 !important; +} + +.x-form-item, .x-form-item-default, .x-form-item-body, .x-form-item-body-default, +.x-form-text-field-body, .x-form-text-field-body-default, +.x-form-fieldcontainer, .x-field, .x-field-default, .x-form-type-text { + border-radius: 0 !important; +} + +.x-box-layout-ct, .x-panel-bodyWrap, .x-panel-bodyWrap-default, +.x-autocontainer-innerCt, .x-autocontainer-outerCt, +.x-panel.x-tabpanel-child, .x-panel.x-box-item, +.x-box-inner, .x-box-target, .x-container, .x-container-default, +.x-window .x-panel-body, .x-window .x-window-body, .x-window .x-window-bodyWrap { + border-radius: 0 !important; +} + +.x-window *, .x-window .x-autocontainer-innerCt, .x-window .x-autocontainer-outerCt, +.x-window .x-form-layout-wrap, .x-window .x-form-layout-auto-label, +.x-window .x-form-layout-colgroup, .x-window .x-form-layout-column, +.x-window .x-field, .x-window .x-form-item, .x-window .x-form-item-body { + border-radius: 0 !important; +} + +.x-chart-grid, .x-chart-axis, canvas.x-surface, .x-chart canvas, +canvas.x-surface-canvas, .x-surface-canvas, .x-draw-component canvas, +.proxmox-rrd-chart canvas, svg.x-surface, .x-draw-container, .x-surface { + border-radius: 0 !important; +} + +.x-legend-item-marker { + border-radius: 50% !important; +} + +/* ===== RE-APPLY BORDER RADII ===== */ +.x-window, .x-window-default { + border-radius: var(--pm-radius-lg) !important; +} + +.x-window-header, .x-window-header-default { + border-radius: var(--pm-radius-lg) var(--pm-radius-lg) 0 0 !important; +} + +.x-window .x-window-body, .x-window-body-default { + border-radius: 0 !important; +} + +.x-window .x-btn { + border-radius: var(--pm-radius-md) !important; +} + +.x-window .x-form-checkbox { + border-radius: 3px !important; +} + +.x-window .x-form-trigger-wrap, .x-window .x-form-trigger-wrap-default { + border-radius: var(--pm-radius-sm) !important; +} + +.x-window .x-form-text-wrap, .x-window .x-form-text { + border-radius: var(--pm-radius-sm) 0 0 var(--pm-radius-sm) !important; +} + +.x-window .x-form-arrow-trigger { + border-radius: 0 var(--pm-radius-sm) var(--pm-radius-sm) 0 !important; +} + +.x-form-trigger-wrap, .x-form-trigger-wrap *, .x-form-text-wrap, .x-form-text-wrap *, +.x-form-text, .x-form-trigger { + border-radius: 0 !important; +} + +.x-form-trigger-wrap, .x-form-trigger-wrap-default { + border-radius: var(--pm-radius-sm) !important; + overflow: hidden !important; +} + +.x-form-text-wrap, .x-form-text-wrap-default { + border-radius: var(--pm-radius-sm) 0 0 var(--pm-radius-sm) !important; +} + +.x-form-text, .x-form-text-default { + border-radius: var(--pm-radius-sm) 0 0 var(--pm-radius-sm) !important; +} + +.x-form-trigger, .x-form-trigger-default, .x-form-arrow-trigger, .x-form-arrow-trigger-default { + border-radius: 0 var(--pm-radius-sm) var(--pm-radius-sm) 0 !important; +} + +.x-window .x-tabpanel-child .x-autocontainer-innerCt { + padding: 12px 0 !important; +} + +.x-window .x-panel-body:not(.x-scroller) { + overflow: visible !important; +} + +.x-window .x-panel.x-box-item .x-panel-body { + padding: 0 4px !important; +} + +.x-window .x-autocontainer-outerCt { + max-width: 100% !important; +} + +.x-window > .x-window-header, .x-window > .x-window-body, +.x-window > .x-window-bodyWrap, .x-window-bodyWrap > .x-window-body { + width: 100% !important; +} + +.x-window-header > .x-box-inner, .x-window-header > .x-box-inner > .x-box-target { + width: 100% !important; +} + +.x-window-header-title { + width: auto !important; + flex: 1 !important; + max-width: calc(100% - 30px) !important; +} + +.x-boundlist { + border-radius: var(--pm-radius-md) !important; + overflow: hidden !important; +} + +/* ===== BASE / BODY ===== */ +.x-body, .x-viewport > .x-body, body.x-border-layout-ct, div.x-border-layout-ct { + background-color: var(--pm-bg-base) !important; + color: var(--pm-text) !important; +} + +/* ===== MASKS & OVERLAYS ===== */ +.x-mask { + background-color: rgba(15, 23, 42, 0.6) !important; + backdrop-filter: blur(4px); +} + +.x-mask-msg { + background-color: var(--pm-bg-surface) !important; + border: 1px solid var(--pm-border) !important; + border-radius: var(--pm-radius-lg) !important; +} + +.x-mask-msg-text { + color: var(--pm-text-muted) !important; + filter: none !important; +} + +.x-css-shadow { + box-shadow: 0 8px 24px rgba(15, 23, 42, 0.6) !important; +} + +.x-grid-row-loading, +.x-treelist-item-loading .x-treelist-item-icon, +.x-grid-tree-loading .x-tree-icon { + filter: invert(90%); +} + +/* ===== ICONS ===== */ +.x-tree-icon-custom, .x-grid-icon-custom, +.fa-tags::before, .fa-file-o::before, .fa-building::before, +.x-action-col-icon::before, .fa-shield::before, +.fa-file-text-o::before, .fa-clock-o::before, +.x-tab-icon-el-default, +.pve-icon-verify-lettering::after, +.x-tree-icon-leaf:not(.x-tree-icon-custom)::before, +.x-tree-icon-parent:not(.x-tree-icon-custom)::before, +.x-tree-icon-parent-expanded:not(.x-tree-icon-custom)::before, +.x-grid-filters-filtered-column .x-column-header-text::after { + color: var(--pm-text-dim) !important; +} + +.x-tree-icon-parent:not(.x-tree-icon-custom)::before, +.x-tree-icon-parent-expanded:not(.x-tree-icon-custom)::before { + filter: invert(90%); +} + +.fa-ceph::before, .fa-sdn::before, .fa-network-wired::before, +.pve-itype-treelist-item-icon-cdrom, +.fa-chevron-right::before, +.x-grid-row-console, +.x-box-scroller-toolbar-default.x-box-scroller, +.x-tree-elbow-img, +.pve-itype-icon-qemu, +.x-tree-node-computer, .x-grid-tree-node-expanded .x-tree-node-computer, +.pbs-icon-tape, .pbs-icon-tape-drive, +.x-tree-icon-leaf:not(.x-tree-icon-custom), +.x-tree-icon-parent:not(.x-tree-icon-custom), +.x-tree-icon-parent-expanded:not(.x-tree-icon-custom) { + filter: invert(90%); +} + +/* Hardware icons - invert(100%) for crisp rendering */ +.pve-itype-icon-cpu, .pve-itype-icon-cdrom, .pve-itype-icon-memory, +.pve-itype-icon-pci, .pve-itype-icon-serial, .pve-itype-icon-die, +.pmx-itype-icon-processor, .pmx-itype-icon-memory, +.pve-itype-icon-storage, .x-tree-node-harddisk, +.x-grid-tree-node-expanded .x-tree-node-harddisk { + filter: invert(100%); +} + +/* Hardware icons — counter-invert for non-SVG icon cells */ +td.pve-itype-icon-storage .x-grid-cell-inner, +td.x-tree-node-harddisk .x-grid-cell-inner { + filter: invert(100%) !important; +} + +/* Hardware icons — hide inverted borders for non-SVG icon cells */ +td.pve-itype-icon-storage, +td.x-tree-node-harddisk { + border-color: transparent !important; +} + +/* Hardware grid icons — mask-image renders SVG icons in theme text color + Replaces filter:invert approach for pve-itype-icon-* and pmx-itype-icon-* grid cells */ +td.pve-itype-icon-cpu, +td.pve-itype-icon-cdrom, +td.pve-itype-icon-memory, +td.pve-itype-icon-pci, +td.pve-itype-icon-serial, +td.pve-itype-icon-die, +td.pmx-itype-icon-processor, +td.pmx-itype-icon-memory { + filter: none !important; + background-image: none !important; + padding-left: 0 !important; + border-color: transparent !important; +} + +td.pve-itype-icon-cpu .x-grid-cell-inner, +td.pve-itype-icon-cdrom .x-grid-cell-inner, +td.pve-itype-icon-memory .x-grid-cell-inner, +td.pve-itype-icon-pci .x-grid-cell-inner, +td.pve-itype-icon-serial .x-grid-cell-inner, +td.pve-itype-icon-die .x-grid-cell-inner, +td.pmx-itype-icon-processor .x-grid-cell-inner, +td.pmx-itype-icon-memory .x-grid-cell-inner { + padding-left: 3px !important; +} + +td.pve-itype-icon-cpu .x-grid-cell-inner::before, +td.pve-itype-icon-cdrom .x-grid-cell-inner::before, +td.pve-itype-icon-memory .x-grid-cell-inner::before, +td.pve-itype-icon-pci .x-grid-cell-inner::before, +td.pve-itype-icon-serial .x-grid-cell-inner::before, +td.pve-itype-icon-die .x-grid-cell-inner::before, +td.pmx-itype-icon-processor .x-grid-cell-inner::before, +td.pmx-itype-icon-memory .x-grid-cell-inner::before { + content: '' !important; + display: inline-block !important; + width: 18px !important; + height: 14px !important; + vertical-align: middle !important; + margin-right: 10px !important; + background-color: currentColor !important; + -webkit-mask-size: contain !important; + mask-size: contain !important; + -webkit-mask-repeat: no-repeat !important; + mask-repeat: no-repeat !important; + -webkit-mask-position: center !important; + mask-position: center !important; +} + +td.pve-itype-icon-cpu .x-grid-cell-inner::before { + -webkit-mask-image: url('/pve2/images/icon-cpu.svg') !important; + mask-image: url('/pve2/images/icon-cpu.svg') !important; +} + +td.pve-itype-icon-memory .x-grid-cell-inner::before { + -webkit-mask-image: url('/pve2/images/icon-memory.svg') !important; + mask-image: url('/pve2/images/icon-memory.svg') !important; +} + +td.pve-itype-icon-cdrom .x-grid-cell-inner::before { + -webkit-mask-image: url('/pve2/images/icon-cd-drive.svg') !important; + mask-image: url('/pve2/images/icon-cd-drive.svg') !important; +} + +td.pve-itype-icon-pci .x-grid-cell-inner::before { + -webkit-mask-image: url('/pve2/images/icon-pci.svg') !important; + mask-image: url('/pve2/images/icon-pci.svg') !important; +} + +td.pve-itype-icon-serial .x-grid-cell-inner::before { + -webkit-mask-image: url('/pve2/images/icon-serial.svg') !important; + mask-image: url('/pve2/images/icon-serial.svg') !important; +} + +td.pve-itype-icon-die .x-grid-cell-inner::before { + -webkit-mask-image: url('/pve2/images/icon-die.svg') !important; + mask-image: url('/pve2/images/icon-die.svg') !important; +} + +td.pmx-itype-icon-processor .x-grid-cell-inner::before { + -webkit-mask-image: url('../images/icon-cpu.svg') !important; + mask-image: url('../images/icon-cpu.svg') !important; +} + +td.pmx-itype-icon-memory .x-grid-cell-inner::before { + -webkit-mask-image: url('../images/icon-ram.svg') !important; + mask-image: url('../images/icon-ram.svg') !important; +} + + +.x-tree-icon-custom::after, .x-grid-icon-custom::after { + color: var(--pm-text-dim) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* RUNNING - Green */ +.x-tree-icon-custom.running::after, .x-grid-icon-custom.running::after, +.x-treelist-item-icon.running::after { + color: var(--pm-success) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +.x-tree-icon-custom.online::after, .x-grid-icon-custom.online::after { + color: var(--pm-success) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +.x-tree-icon-custom.stopped, .x-tree-icon-custom.offline, +.x-grid-icon-custom.stopped, .x-grid-icon-custom.offline { + color: var(--pm-text-muted) !important; +} + +.x-tree-icon-custom.unknown::after, .x-grid-icon-custom.unknown::after { + color: var(--pm-text-muted) !important; +} + +/* ERROR - Red */ +.x-tree-icon-custom.error::after, .x-tree-icon-custom.offline::after, +.x-tree-icon-custom.ha-error::after, +.x-grid-icon-custom.error::after, .x-grid-icon-custom.offline::after, +.x-grid-icon-custom.ha-error::after { + color: var(--pm-error) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* PAUSED/SUSPENDED - Warning */ +.x-tree-icon-custom.paused::after, .x-tree-icon-custom.suspended::after, +.x-tree-icon-custom.lock-suspending::after, +.x-grid-icon-custom.paused::after, .x-grid-icon-custom.suspended::after, +.x-grid-icon-custom.lock-suspending::after { + color: var(--pm-warning) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* PENDING/WARNING */ +.x-tree-icon-custom.pending::after, .x-tree-icon-custom.io-error::after, +.x-tree-icon-custom.internal-error::after, .x-tree-icon-custom.guest-panicked::after, +.x-grid-icon-custom.pending::after, .x-grid-icon-custom.io-error::after, +.x-grid-icon-custom.internal-error::after, .x-grid-icon-custom.guest-panicked::after { + color: var(--pm-warning) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* HA MAINTENANCE - Info/Cyan */ +.x-tree-icon-custom.ha-maintenance::after, .x-grid-icon-custom.ha-maintenance::after { + color: var(--pm-info) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* Locked icons */ +.x-tree-icon-custom.locked::after, .x-tree-icon-custom.lock-backup::after, +.x-tree-icon-custom.lock-migrate::after, .x-tree-icon-custom.lock-suspended::after, +.x-grid-icon-custom.locked::after, .x-grid-icon-custom.lock-backup::after, +.x-grid-icon-custom.lock-migrate::after, .x-grid-icon-custom.lock-suspended::after { + color: var(--pm-text-muted) !important; +} + +.x-tree-icon-custom.lxc::after, .x-tree-icon-custom.qemu::after, +.x-grid-icon-custom.lxc::after, .x-grid-icon-custom.qemu::after { + background-color: transparent; + color: var(--pm-text-muted) !important; +} + +.x-treelist-item-icon.lxc::after, .x-treelist-item-icon.qemu::after { + background-color: transparent; + color: var(--pm-text-muted) !important; +} + +.x-tree-arrows .x-tree-expander { + filter: brightness(200%); +} + +.x-form-checkbox-default, .x-form-radio-default, +.x-column-header-checkbox .x-column-header-checkbox::after, +.x-grid-checkcolumn::after, +.x-menu-item-checked .x-menu-item-icon-default.x-menu-item-checkbox, +.x-menu-item-unchecked .x-menu-item-icon-default.x-menu-item-checkbox { + filter: none !important; +} + +/* ===== PANELS & HEADERS ===== */ +.x-panel, .x-panel-default { + border-radius: var(--pm-radius-lg) !important; + padding: 0 !important; +} + +/* Column panels (Issue #23 fix) */ +.x-panel.x-column { + padding: 5px !important; + margin: 0 !important; + max-width: none !important; + box-sizing: border-box !important; +} + +.x-panel.x-panel-default.x-column { + border: 1px solid var(--pm-border-subtle) !important; + border-radius: var(--pm-radius-lg) !important; + overflow: hidden !important; +} + +[id^="pveGuestStatusView-"].x-panel, [id^="pveLxcStatusView-"].x-panel, +[id^="pveQemuStatusView-"].x-panel, [id^="pmxNotesView-"].x-panel { + border: 1px solid var(--pm-border-subtle) !important; + border-radius: var(--pm-radius-lg) !important; +} + +.x-panel-body, .x-panel-body-default { + background-color: var(--pm-bg-base) !important; + color: var(--pm-text) !important; + border: none !important; +} + +.x-panel-header, .x-panel-header-default { + background-color: var(--pm-bg-surface) !important; + border: none !important; + border-bottom: 1px solid var(--pm-border-subtle) !important; + border-radius: var(--pm-radius-lg) var(--pm-radius-lg) 0 0 !important; + margin: 0 !important; + padding: 8px 12px !important; + width: 100% !important; + box-sizing: border-box !important; + overflow: visible !important; +} + +.x-title-text, .x-title-text-default { + overflow: visible !important; +} + +.x-panel-bodyWrap, .x-panel-bodyWrap-default { + margin: 0 !important; + padding: 0 !important; + overflow: visible !important; +} + +.x-panel-body > .x-box-layout-ct, .x-panel-body > .x-container, +.x-panel-body > .x-box-inner, [id*="pmxGauge"] { + border: none !important; +} + +.x-panel-header-title-default, .x-window-header-title-default { + color: var(--pm-text) !important; +} + +/* Tool backgrounds - transparent (fix white X background) */ +.x-panel-header-default .x-tool-tool-el { + background-color: transparent; +} + +.x-tool-img { + filter: brightness(175%); +} + +.x-tool-over .x-tool-img { + filter: brightness(200%); +} + +div[id^="pveResourceTree-"][id$="-body"] { + border-color: var(--pm-bg-base) !important; +} + +[id^="pveResourceTree-"].x-tree-panel td.x-grid-cell, +[id^="pveResourceTree-"].x-tree-panel .x-grid-td, +[id^="pveResourceTree-"].x-tree-panel .x-grid-cell { + border-bottom: none !important; +} + +div[id^="pveResourceTree"] .x-grid-cell { + padding-top: 3px !important; + padding-bottom: 3px !important; +} + +.pveStatusPanel, .x-panel-default-framed, .x-panel-body-default-framed { + border-radius: 12px !important; +} + +.x-panel-header-default-framed { + border-radius: 12px 12px 0 0 !important; +} + +.x-panel.x-column > .x-panel-bodyWrap > .x-panel-body.x-panel-body-default { + border-radius: var(--pm-radius-lg) !important; +} + +/* ===== SPLITTERS / SEPARATORS ===== */ +.x-splitter-vertical { + background-color: transparent !important; + border-left: 1px solid var(--pm-border-subtle) !important; + border-right: none !important; + width: 1px !important; +} + +.x-splitter-horizontal { + background-color: var(--pm-bg-base) !important; + border-top: 1px solid var(--pm-border-subtle) !important; +} + +.x-splitter { + background-color: var(--pm-bg-base) !important; +} + +.x-keyboard-mode .x-splitter-focus::after { + border-color: var(--pm-accent) !important; +} + +.x-layout-split-bottom { + opacity: 0.7; +} + +.pve-toolbar-bg { + border-right: 1px solid var(--pm-border-subtle) !important; + z-index: 3 !important; +} + +.x-treelist.x-treelist-pve-nav { + border-right: none !important; +} + +/* ===== TOOLBARS ===== */ +.x-toolbar, .x-toolbar-default { + background-color: var(--pm-bg-base) !important; + border-color: var(--pm-border-subtle) !important; +} + +.x-toolbar-default.x-docked-top { + border: none !important; + border-bottom: 1px solid var(--pm-border-subtle) !important; +} + +.x-toolbar-default .x-toolbar-separator { + border-color: var(--pm-border-subtle); +} + +.x-toolbar-text-default { + color: var(--pm-text-muted); +} + +/* ===== PRIMARY BUTTONS ===== */ +.x-btn-default-small { + background-color: var(--pm-accent) !important; + border: 1px solid var(--pm-accent-muted) !important; + border-radius: var(--pm-radius-md) !important; + transition: background-color 0.15s ease, box-shadow 0.15s ease !important; +} + +.x-btn-default-small .x-btn-inner { + color: #fff !important; + font-weight: 600 !important; +} + +.x-btn-default-small .x-btn-icon-el { + color: #fff !important; +} + +.x-btn-default-small.x-btn-over, +.x-keyboard-mode .x-btn-default-small.x-btn-focus { + background-color: var(--pm-accent-light) !important; + box-shadow: 0 0 0 3px var(--pm-accent-subtle) !important; +} + +.x-btn-default-small.x-btn.x-btn-disabled { + background-color: var(--pm-accent) !important; + opacity: 0.4; +} + +.x-btn-default-small.x-btn.x-btn-pressed { + background-color: var(--pm-accent-dark) !important; +} + +/* Button height consistency - 28px */ +.x-btn.x-btn-default-small:not(.x-btn-default-toolbar-small):not([style*="display: none"]):not([style*="display:none"]):not(:has(.fa-check)) { + height: 28px !important; + min-height: 28px !important; + display: flex !important; + align-items: center !important; + padding: 3px 8px !important; +} + +.x-btn.x-btn-default-small:not(.x-btn-default-toolbar-small):not([style*="display: none"]):not([style*="display:none"]):not(:has(.fa-check)) .x-btn-wrap { + display: flex !important; + align-items: center !important; +} + +.x-btn.x-btn-default-small:not(.x-btn-default-toolbar-small):not([style*="display: none"]):not([style*="display:none"]):not(:has(.fa-check)) .x-btn-inner { + display: flex !important; + align-items: center !important; +} + +.x-btn-wrap.x-btn-arrow-right::after, .x-btn-wrap.x-btn-split-right::after { + height: 16px !important; + min-height: 16px !important; + width: 20px !important; + display: flex !important; + align-items: center !important; +} + +.x-btn-no-text .x-btn-inner, +.x-btn-button.x-btn-no-text .x-btn-inner, +.x-btn-button-default-toolbar-small.x-btn-no-text .x-btn-inner-default-toolbar-small, +.x-btn-button-default-small.x-btn-no-text .x-btn-inner-default-small, +.x-btn-button-default-small.x-btn-no-text > .x-btn-inner-default-small { + display: none !important; +} + +.x-btn-icon-el.fa-desktop { + transform: translateY(1.1px) !important; +} + +/* ===== SECONDARY / TOOLBAR BUTTONS ===== */ +.x-btn-default-toolbar-small { + background-color: var(--pm-bg-surface) !important; + border: 1px solid var(--pm-border-subtle) !important; + border-radius: var(--pm-radius-md) !important; + transition: background-color 0.15s ease, border-color 0.15s ease !important; +} + +.x-btn-default-toolbar-small .x-btn-inner-default-toolbar-small, +.x-btn-default-toolbar-small .x-btn-icon-el-default-toolbar-small { + color: var(--pm-text) !important; +} + +.x-btn-default-toolbar-small .x-btn-wrap-default-toolbar-small.x-btn-arrow-right::after, +.x-btn-default-toolbar-small .x-btn-wrap-default-toolbar-small.x-btn-split-right::after { + filter: brightness(150%); +} + +.x-btn-default-toolbar-small.x-btn-over, +.x-keyboard-mode .x-btn-default-toolbar-small.x-btn-focus { + background-color: var(--pm-bg-elevated) !important; + border-color: var(--pm-border) !important; +} + +.x-btn-default-toolbar-small.x-btn.x-btn-disabled { + background-color: var(--pm-bg-surface) !important; + opacity: 0.4; +} + +.x-btn-default-toolbar-small.x-btn.x-btn-menu-active, +.x-btn-default-toolbar-small.x-btn.x-btn-pressed { + background-color: var(--pm-accent) !important; + border-color: var(--pm-accent) !important; + padding: 4px 8px !important; /* Fix #30: prevent width change on dropdown */ +} + +.x-btn-default-toolbar-small.x-btn.x-btn-pressed .x-btn-inner-default-toolbar-small, +.x-btn-default-toolbar-small.x-btn.x-btn-pressed .x-btn-icon-el-default-toolbar-small, +.x-btn-default-toolbar-small.x-btn.x-btn-pressed .x-btn-inner-default-small, +.x-btn-default-toolbar-small.x-btn.x-btn-pressed .x-btn-icon-el-default-small { + color: #fff !important; +} + +/* Segmented buttons */ +.x-segmented-button { + border-radius: var(--pm-radius-md) !important; +} + +.x-segmented-button .x-btn, .x-segmented-button .x-btn-default-small, +.x-segmented-button .x-btn-inner, .x-segmented-button .x-btn-wrap { + border-radius: var(--pm-radius-md) !important; +} + +/* Inline buttons */ +.proxmox-inline-button { + height: 28px !important; + min-height: 28px !important; + display: flex !important; + align-items: center !important; + padding: 3px 8px !important; + background-color: var(--pm-bg-surface) !important; + border: 1px solid var(--pm-border-subtle) !important; + border-radius: var(--pm-radius-md) !important; + color: var(--pm-text) !important; + transition: background-color 0.15s ease !important; +} + +.proxmox-inline-button:hover, .proxmox-inline-button.x-btn-over { + background-color: var(--pm-bg-elevated) !important; + border-color: var(--pm-border) !important; +} + +.proxmox-inline-button:active, .proxmox-inline-button.x-btn-pressed { + background-color: var(--pm-bg-elevated) !important; +} + +.proxmox-inline-button .x-btn-inner, .proxmox-inline-button .x-btn-icon-el { + color: var(--pm-text) !important; +} + +.proxmox-inline-button.x-btn-pressed .x-btn-inner, +.proxmox-inline-button.x-btn-pressed .x-btn-icon-el, +.proxmox-inline-button.x-btn-menu-active .x-btn-inner, +.proxmox-inline-button.x-btn-menu-active .x-btn-icon-el { + color: #fff !important; +} + +/* ===== FORM ELEMENTS ===== */ +.x-form-trigger-default { + background-color: var(--pm-bg-surface) !important; +} + +.x-form-text-default { + background-color: var(--pm-bg-surface) !important; + color: var(--pm-text) !important; + border-radius: var(--pm-radius-sm) !important; +} + +.x-form-trigger-wrap, .x-form-trigger-wrap-default { + border-color: var(--pm-border-subtle) !important; + background-color: var(--pm-bg-surface) !important; + border-radius: var(--pm-radius-sm) !important; + transition: border-color 0.15s ease !important; +} + +.x-form-trigger-wrap-default.x-form-trigger-wrap-focus { + border-color: var(--pm-accent) !important; + box-shadow: 0 0 0 3px var(--pm-accent-subtle) !important; +} + +.x-form-item-label-default, .x-form-cb-label-default { + color: var(--pm-text) !important; +} + +.x-form-display-field-default { + color: var(--pm-text-muted) !important; + border-radius: var(--pm-radius-md) !important; +} + +.x-form-spinner-default { + background-color: var(--pm-bg-surface) !important; +} + +.x-fieldset, .x-fieldset-default { + border-color: var(--pm-border-subtle) !important; + border-radius: var(--pm-radius-lg) !important; +} + +.x-fieldset-header-default > .x-fieldset-header-text { + color: var(--pm-text) !important; +} + +/* ===== CHECKBOXES & RADIOS ===== */ +.x-form-checkbox, .x-form-checkbox-default, +.x-form-radio, .x-form-radio-default { + background-image: none !important; + background-color: var(--pm-bg-surface) !important; + border: 1.5px solid var(--pm-text-muted) !important; + width: 16px !important; + height: 16px !important; + display: inline-block !important; + box-sizing: border-box !important; + cursor: pointer !important; + transition: border-color 0.12s ease, background-color 0.12s ease !important; +} + +.x-form-checkbox, .x-form-checkbox-default { + border-radius: 3px !important; +} + +.x-form-radio, .x-form-radio-default { + border-radius: 50% !important; + position: relative !important; + transform: translateZ(0) !important; + box-shadow: inset 0 0 0 0 transparent !important; +} + +.x-form-radio::after { + content: '' !important; + position: absolute !important; + top: 50% !important; + left: 50% !important; + width: 7px !important; + height: 7px !important; + border-radius: 50% !important; + background: transparent !important; + transform: translate(-50%, -50%) scale(0) !important; + transition: transform 0.15s ease, background 0.15s ease !important; + pointer-events: none !important; +} + +.x-form-checkbox:hover, .x-form-checkbox-default:hover, +.x-form-cb-wrap:hover .x-form-checkbox, +.x-form-radio:hover, .x-form-radio-default:hover, +.x-form-cb-wrap:hover .x-form-radio { + border-color: var(--pm-accent) !important; +} + +.x-form-cb-checked .x-form-checkbox, .x-form-cb-checked .x-form-checkbox-default { + background-color: var(--pm-accent) !important; + border-color: var(--pm-accent) !important; + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 8'%3E%3Cpath d='M1 4l3 3 5-6' fill='none' stroke='%230f172a' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") !important; + background-repeat: no-repeat !important; + background-position: center !important; + background-size: 9px 7px !important; +} + +.x-form-cb-checked .x-form-radio, .x-form-cb-checked .x-form-radio-default { + border-color: var(--pm-accent) !important; + background-color: var(--pm-bg-base) !important; +} + +.x-form-cb-checked .x-form-radio::after { + background: var(--pm-accent) !important; + transform: translate(-50%, -50%) scale(1) !important; +} + +/* ===== BOUNDLIST / DROPDOWNS ===== */ +.x-boundlist { + background-color: var(--pm-bg-surface) !important; + border: 1px solid var(--pm-border) !important; + border-radius: var(--pm-radius-md) !important; + box-shadow: 0 8px 24px rgba(15, 23, 42, 0.7) !important; + padding: 2px !important; + overflow: hidden !important; +} + +.x-boundlist-item { + background-color: transparent !important; + color: var(--pm-text) !important; + border-radius: var(--pm-radius-sm) !important; + padding: 4px 8px !important; + line-height: normal !important; + border: none !important; + cursor: pointer !important; + outline: none !important; + box-shadow: none !important; +} + +.x-boundlist-selected { + background-color: var(--pm-select-overlay) !important; + color: var(--pm-text) !important; +} + +.x-boundlist-item-over { + background-color: var(--pm-hover-overlay) !important; +} + +/* ===== GRIDS / TABLES ===== */ +.x-grid, .x-grid-view { + border-radius: 0 !important; +} + +.x-column-header { + border-color: var(--pm-border-subtle) !important; + background-color: transparent !important; +} + +.x-column-header-inner, .x-column-header-text { + color: var(--pm-text) !important; + font-weight: 600 !important; +} + +.x-column-header-trigger { + border-color: var(--pm-border-subtle) !important; +} + +.x-grid-item, .x-column-header-default, .x-grid-cell-row-numberer { + color: var(--pm-text) !important; + background-color: var(--pm-bg-base) !important; +} + +.x-grid-cell-special { + border-color: var(--pm-border-subtle) !important; +} + +.x-grid-group-hd { + background-color: var(--pm-bg-base) !important; + border-color: var(--pm-border-subtle) !important; +} + +.x-grid-group-title { + color: var(--pm-text) !important; +} + +.x-grid-header-ct { + background-color: var(--pm-bg-surface) !important; + border: 1px solid var(--pm-border-subtle) !important; + border-radius: var(--pm-radius-lg) var(--pm-radius-lg) 0 0 !important; +} + +.x-grid-item-alt { + background-color: rgba(15, 23, 42, 0.5) !important; +} + +.x-grid-with-row-lines .x-grid-item { + border-color: var(--pm-border-subtle) !important; +} + +.x-grid-cell { + border-bottom: 1px solid rgba(48, 54, 61, 0.4) !important; +} + +.x-grid-item-over, .x-grid-with-row-lines .x-grid-item.x-grid-item-over { + background-color: var(--pm-hover-overlay) !important; +} + +.x-grid-item-selected, .x-grid-with-row-lines .x-grid-item.x-grid-item-selected { + background-color: var(--pm-select-overlay) !important; +} + +.x-column-header-over, .x-column-header-open { + background-color: var(--pm-hover-overlay) !important; +} + +.x-column-header-sort-ASC, .x-column-header-sort-DESC { + background-color: var(--pm-hover-overlay) !important; +} + +.x-grid-row-summary .x-grid-cell, .x-grid-row-summary .x-grid-rowwrap, +.x-grid-row-summary .x-grid-cell-rowbody { + background-color: var(--pm-bg-base) !important; + border-color: var(--pm-border-subtle); +} + +.x-grid-with-col-lines .x-grid-cell, +.x-grid-with-col-lines .x-grid-item-over .x-grid-cell, +.x-grid-with-col-lines .x-grid-item-selected .x-grid-cell { + border-color: var(--pm-border-subtle) !important; +} + +.x-dd-drag-proxy { + background-color: var(--pm-bg-surface); + border-color: var(--pm-border-subtle); + color: var(--pm-text); +} + +.x-keyboard-mode .x-grid-item-focused { + background-color: var(--pm-hover-overlay) !important; + color: var(--pm-text) !important; +} + +/* Remove focus outlines */ +.x-keyboard-mode .x-grid-item-focused .x-grid-cell-inner::before, +.x-keyboard-mode .x-grid-item-selected .x-grid-cell-inner::before, +.x-grid-item-selected .x-grid-cell-inner::before, +.x-grid-item-focused .x-grid-cell-inner::before, +[id^="pveResourceTree"] .x-grid-item-selected .x-grid-cell-inner::before, +[id^="pveResourceTree"] .x-grid-item-focused .x-grid-cell-inner::before { + content: none !important; + display: none !important; + border: none !important; +} + +.x-grid-empty { + background-color: var(--pm-bg-base) !important; + color: var(--pm-text-muted) !important; +} + +.pve-info-grid { + border-radius: 12px !important; +} + +.pve-rrdview, .rrdview { + border-radius: 12px !important; +} + +.pve-summary-status, .x-container .pve-status { + border-radius: var(--pm-radius-lg) !important; +} + +[id^="pveGuestStatusView-"][id$="-body"], [id^="pmxNotesView-"] .x-panel-body { + border-radius: var(--pm-radius-lg) !important; +} + +.x-panel-default[id*="notes"], .pve-notes-view { + border-radius: var(--pm-radius-lg) !important; +} + +/* Floating grid pickers */ +.x-layer.x-grid .x-grid-view, .x-panel.x-layer.x-grid .x-grid-view, +.x-panel.x-layer.x-grid, .x-layer.x-panel.x-grid { + border-radius: var(--pm-radius-sm) !important; +} + +.x-layer.x-grid .x-grid-item-over, .x-layer.x-grid .x-grid-item-selected, +.x-panel.x-layer.x-grid .x-grid-item-over, .x-panel.x-layer.x-grid .x-grid-item-selected { + border-radius: var(--pm-radius-sm) !important; + outline: none !important; + box-shadow: none !important; +} + +.x-layer.x-grid .x-grid-item-over td, .x-layer.x-grid .x-grid-item-selected td, +.x-layer.x-grid .x-grid-item-over .x-grid-cell, .x-layer.x-grid .x-grid-item-selected .x-grid-cell, +.x-panel.x-layer.x-grid .x-grid-item-over td, .x-panel.x-layer.x-grid .x-grid-item-selected td, +.x-panel.x-layer.x-grid .x-grid-item-over .x-grid-cell, .x-panel.x-layer.x-grid .x-grid-item-selected .x-grid-cell { + border-radius: 0 !important; +} + +.x-layer.x-grid .x-grid-item-over td:first-child, .x-layer.x-grid .x-grid-item-selected td:first-child, +.x-panel.x-layer.x-grid .x-grid-item-over td:first-child, .x-panel.x-layer.x-grid .x-grid-item-selected td:first-child { + border-radius: var(--pm-radius-sm) 0 0 var(--pm-radius-sm) !important; +} + +.x-layer.x-grid .x-grid-item-over td:last-child, .x-layer.x-grid .x-grid-item-selected td:last-child, +.x-panel.x-layer.x-grid .x-grid-item-over td:last-child, .x-panel.x-layer.x-grid .x-grid-item-selected td:last-child { + border-radius: 0 var(--pm-radius-sm) var(--pm-radius-sm) 0 !important; +} + +/* ===== MENUS ===== */ +.x-menu, .x-menu-default { + background-color: var(--pm-bg-surface) !important; + border: 1px solid var(--pm-border) !important; + border-radius: var(--pm-radius-lg) !important; + box-shadow: 0 8px 24px rgba(15, 23, 42, 0.8) !important; + padding: 2px !important; + overflow: hidden !important; +} + +.x-menu-body-default { + background-color: transparent !important; + padding: 4px !important; +} + +.x-menu-header { + background-color: transparent !important; + color: var(--pm-text) !important; +} + +.x-menu-icon-separator-default { + display: none !important; +} + +/* Menu item layout (Issue #24 fix) */ +.x-menu-item-default > .x-menu-item-link { + display: flex !important; + align-items: center !important; + flex-direction: row !important; + gap: 4px !important; + justify-content: flex-start !important; + flex-wrap: nowrap !important; + border-radius: var(--pm-radius-md) !important; + padding: 4px 8px !important; + line-height: 20px !important; + cursor: pointer !important; + outline: none !important; + box-shadow: none !important; + white-space: nowrap !important; + text-decoration: none !important; +} + +.x-menu-item-text-default { + color: var(--pm-text) !important; + font-size: 13px !important; + order: 1 !important; + margin-left: 0 !important; + text-align: left !important; + line-height: 20px !important; + display: inline-flex !important; + align-items: center !important; + flex: 1 1 auto !important; + width: auto !important; + white-space: nowrap !important; +} + +.x-menu-item-icon-default { + color: var(--pm-text-muted) !important; + order: -1 !important; + position: relative !important; + float: none !important; + margin-right: 8px !important; + margin-left: 0 !important; + left: auto !important; + top: auto !important; + width: 16px !important; + text-align: center !important; + display: inline-flex !important; + align-items: center !important; + justify-content: center !important; + height: 20px !important; + line-height: 20px !important; + vertical-align: middle !important; + flex: 0 0 16px !important; + align-self: center !important; +} + +.x-menu-item-arrow, .x-menu-item-arrow-default { + order: 2 !important; + margin-left: auto !important; +} + +.x-menu-item-default.x-menu-item-separator { + background-color: var(--pm-border-subtle) !important; + border: none !important; + height: 1px !important; + margin: 6px 4px !important; +} + +.x-menu-item-default.x-menu-item-focus, +.x-menu-item-default.x-menu-item-active, .x-menu-item:hover { + background-color: var(--pm-bg-elevated) !important; + color: var(--pm-text) !important; + border-radius: var(--pm-radius-md) !important; +} + +.x-menu-item-active .x-menu-item-text-default, +.x-menu-item-focus .x-menu-item-text-default { + color: var(--pm-text) !important; +} + +.x-menu-item-active .x-menu-item-icon-default, +.x-menu-item-focus .x-menu-item-icon-default { + color: var(--pm-info) !important; +} + +/* ===== PROGRESS BARS ===== */ +.x-container[id^="pmxInfoWidget"], .x-container.x-box-layout-ct { + overflow: visible !important; +} + +.x-progress, .x-progress-default { + background-color: var(--pm-bg-surface) !important; + border-radius: 5px !important; +} + +.x-progress-default .x-progress-bar-default { + background-color: var(--pm-accent) !important; + border-radius: 5px !important; + transition: width 0.4s ease !important; +} + +.x-progress-default .x-progress-text { + color: var(--pm-text) !important; +} + +.x-progress-bar .x-progress-text { + color: #fff !important; +} + +.x-progress.warning .x-progress-bar { + background-color: var(--pm-warning) !important; +} + +.x-progress.critical .x-progress-bar { + background-color: var(--pm-error) !important; +} + +/* ===== TABS ===== */ +.x-tab-bar, .x-tab-bar-default { + background-color: var(--pm-bg-base) !important; + border-radius: 0 !important; + border-bottom: 1px solid var(--pm-border-subtle) !important; + padding-bottom: 0 !important; +} + +.x-tab-bar .x-box-inner, .x-tab-bar .x-box-target, +.x-tab-bar-body, .x-tab-bar-body-default { + overflow: visible !important; +} + +.x-tab, .x-tab-default, .x-tab-default-top { + background-color: transparent !important; + border: none !important; + border-radius: var(--pm-radius-md) var(--pm-radius-md) 0 0 !important; + padding: 8px 16px 8px !important; + overflow: visible !important; + margin-bottom: 0 !important; + transition: color 0.15s ease !important; + outline: none !important; + box-shadow: none !important; +} + +.x-tab::after { + display: none !important; +} + +.x-tab-inner-default { + color: var(--pm-text-muted) !important; + font-size: 13px !important; +} + +.x-tab-default.x-tab-over { + background-color: transparent !important; +} + +.x-tab-default.x-tab-over .x-tab-inner-default { + color: var(--pm-text) !important; +} + +.x-tab-default.x-tab.x-tab-active { + background-color: transparent !important; + border: none !important; + overflow: visible !important; + margin-bottom: 0 !important; + outline: none !important; + box-shadow: none !important; +} + +/* Blue underline indicator */ +.x-tab-default.x-tab.x-tab-active::after { + content: '' !important; + display: block !important; + position: absolute !important; + bottom: 0 !important; + left: 0 !important; + right: 0 !important; + height: 2px !important; + background: var(--pm-accent) !important; + z-index: 10 !important; + border-radius: 2px 2px 0 0 !important; + pointer-events: none !important; +} + +.x-tab-active .x-tab-inner-default { + color: var(--pm-text) !important; + font-weight: 600 !important; +} + +.x-tab-default.x-tab.x-tab-disabled { + background-color: transparent !important; + border: none !important; + color: var(--pm-text-muted) !important; + margin-bottom: 0 !important; +} + +.x-keyboard-mode .x-tab-default.x-tab-focus, +.x-keyboard-mode .x-tab-default.x-tab-focus.x-tab-active { + background-color: transparent !important; + border: none !important; + outline: none !important; + box-shadow: none !important; + margin-bottom: 0 !important; +} + +.x-keyboard-mode .x-tab-default.x-tab-focus.x-tab-active::after { + content: '' !important; + display: block !important; + position: absolute !important; + bottom: 0 !important; + left: 0 !important; + right: 0 !important; + height: 2px !important; + background: var(--pm-accent) !important; + z-index: 10 !important; + pointer-events: none !important; +} + +.x-tab:focus, .x-tab *:focus, .x-tab-focus, +.x-tab-active.x-tab-focus, .x-tab-inner-focus, .x-tab-button-focus, +.x-tab-pressed, .x-tab-active.x-tab-pressed, +.x-tab-over, .x-tab:active, .x-tab *:active { + outline: none !important; + box-shadow: none !important; +} + +.x-tabpanel-child { + border-radius: 0 0 var(--pm-radius-lg) var(--pm-radius-lg) !important; +} + +.x-tab-default.x-tab-over, .x-tab-default.x-tab.x-tab-active { + border-radius: var(--pm-radius-md) var(--pm-radius-md) 0 0 !important; +} + +/* ===== TOOLTIPS ===== */ +.x-tip, .x-tip-default { + background-color: var(--pm-bg-elevated) !important; + border: 1px solid var(--pm-border) !important; + border-radius: var(--pm-radius-md) !important; + box-shadow: 0 4px 12px rgba(15, 23, 42, 0.5); +} + +.x-tip-body-default { + color: var(--pm-text) !important; +} + +.x-tip-form-invalid { + background-color: var(--pm-bg-elevated) !important; + border-color: var(--pm-error) !important; +} + +.x-tip-body-form-invalid { + color: var(--pm-error) !important; +} + +/* ===== TREE NAVIGATION (Sidebar) ===== */ +.x-treelist-item { + background-color: var(--pm-bg-base) !important; + border-radius: var(--pm-radius-md) !important; +} + +.x-treelist-row { + border-radius: var(--pm-radius-md) !important; + background-color: transparent !important; + position: relative !important; + z-index: 0 !important; +} + +.x-treelist-row::before { + content: ""; + position: absolute; + top: 1px; + bottom: 1px; + left: 0; + right: 4px; + border-radius: var(--pm-radius-md); + background-color: transparent; + z-index: -1; + pointer-events: none; + transition: background-color 0.15s ease; +} + +.x-treelist-item-text { + margin-left: 28px !important; +} + +.x-treelist-item-text, .x-treelist-item-icon, +.x-treelist.x-treelist-pve-nav .x-treelist-item-text, +.x-treelist.x-treelist-pve-nav .x-treelist-item-icon { + color: var(--pm-text-dim) !important; +} + +.x-treelist-row-over { + background-color: transparent !important; +} + +.x-treelist-row-over::before { + background-color: var(--pm-hover-overlay) !important; +} + +.x-treelist-row-over .x-treelist-item-icon, +.x-treelist-row-over .x-treelist-item-text { + background-color: transparent !important; + color: var(--pm-text) !important; +} + +.x-treelist-item-selected > .x-treelist-row { + background-color: transparent !important; +} + +.x-treelist-item-selected > .x-treelist-row::before, +.x-treelist-item-selected > .x-treelist-row:hover::before { + background-color: var(--pm-accent) !important; +} + +.x-treelist-item-selected .x-treelist-item-text, +.x-treelist-item-selected .x-treelist-item-icon, +.x-treelist.x-treelist-pve-nav .x-treelist-item-selected .x-treelist-item-text, +.x-treelist.x-treelist-pve-nav .x-treelist-item-selected .x-treelist-item-icon { + color: #fff !important; +} + +.x-treelist-pve-nav { + background-color: var(--pm-bg-base) !important; + border-color: var(--pm-border-subtle) !important; +} + +.x-treelist-item, .x-treelist-item-tool { + border-radius: var(--pm-radius-sm) !important; +} + +.x-treelist-row, .x-treelist-row:hover, .x-treelist-row-over, +.x-treelist-item-selected > .x-treelist-row, +.x-treelist-item-selected > .x-treelist-row:hover, +.x-treelist-item-expanded > .x-treelist-row, +.x-treelist-item-expanded > .x-treelist-row-over, +.x-treelist-item-expandable > .x-treelist-row, +.x-treelist-item-expandable > .x-treelist-row-over { + border-radius: var(--pm-radius-sm) !important; +} + +.x-treelist-row::before { + border-radius: var(--pm-radius-sm) !important; +} + +.x-treelist-item-wrap, .x-treelist-item-text, .x-treelist-row, +.x-treelist-container, .x-treelist-root-container, +.x-treelist, .x-treelist-pve-nav { + border-radius: var(--pm-radius-sm) !important; +} + +.x-grid-cell, .x-grid-cell-inner, .x-tree-elbow-img, .x-tree-icon, +.x-treelist-item, .x-treelist-row, .x-treelist-item-wrap, +.x-treelist-item-text, .x-treelist-item-icon { + cursor: pointer !important; +} + +/* ===== TREE EXPANDER ARROWS ===== */ +.x-tree-expander { + background-image: none !important; + position: relative !important; + width: 18px !important; + height: 18px !important; + margin-right: 4px !important; + vertical-align: middle !important; +} + +.x-tree-expander::before { + content: "\f054" !important; + font-family: "FontAwesome" !important; + font-size: 11px !important; + color: var(--pm-text-muted) !important; + position: absolute !important; + top: -2px !important; + left: 3px !important; + transition: transform 0.2s ease, color 0.15s ease !important; +} + +.x-grid-tree-node-expanded .x-tree-expander::before { + transform: rotate(90deg) !important; + color: var(--pm-text-dim) !important; +} + +tr:not(.x-grid-tree-node-expanded) .x-tree-expander::before { + transform: rotate(0deg) !important; +} + +.x-tree-expander:hover::before { + color: var(--pm-accent) !important; +} + +/* ===== WINDOWS / MODALS ===== */ +.x-window, .x-window-default { + background-color: var(--pm-bg-base) !important; + border: 1px solid var(--pm-border-subtle) !important; + border-radius: var(--pm-radius-lg) !important; + box-shadow: 0 8px 24px rgba(15, 23, 42, 0.6) !important; + overflow: hidden !important; +} + +.x-window .x-window-header, .x-window-header-default { + background-color: var(--pm-bg-surface) !important; + border-color: transparent !important; + border-radius: var(--pm-radius-lg) var(--pm-radius-lg) 0 0 !important; +} + +.x-window-header-default .x-mask { + background-color: rgba(15, 23, 42, 0.7); +} + +.x-window .x-window-body, .x-window-body-default { + background-color: var(--pm-bg-base) !important; + border-color: var(--pm-border-subtle) !important; + color: var(--pm-text) !important; + border-radius: 0 0 var(--pm-radius-lg) var(--pm-radius-lg) !important; +} + +.x-window-ghost { + background-color: var(--pm-bg-base) !important; +} + +.x-window-header-default .x-tool-img { + background-color: transparent; +} + +.x-message-box .x-window-body { + background-color: var(--pm-bg-surface) !important; +} + +/* Respect display:none on hidden buttons */ +.x-message-box .x-btn.x-btn-default-small[style*="display: none"], +.x-message-box .x-btn.x-btn-default-small[style*="display:none"], +.x-window .x-toolbar-footer .x-btn[style*="display: none"], +.x-window .x-toolbar-footer .x-btn[style*="display:none"] { + display: none !important; +} + +/* Login dialog */ +.x-window:has(#pveloginrealm) .x-panel-body { + border: none !important; + background: transparent !important; + width: auto !important; +} + +/* ===== CONSOLE / TERMINAL ===== */ +div.monitor { + border-color: var(--pm-border-subtle); +} + +.install-mask { + background-color: var(--pm-bg-base); + color: var(--pm-text-muted); +} + +.x-window.install-mask { + box-shadow: rgba(15, 23, 42, 0.5) 0 4px 20px !important; +} + +/* ===== LEGEND / CHARTS ===== */ +.x-legend-container { + background-color: var(--pm-bg-base) !important; +} + +.x-legend-horizontal .x-legend-item { + background-color: var(--pm-bg-surface) !important; + color: var(--pm-text) !important; + border: 1px solid var(--pm-border-subtle) !important; +} + +div[id*="rrdchart"], .pve-rrddatastore, .pmx-panel-rrd { + background-color: var(--pm-bg-base) !important; +} + +.proxmox-rrd-panel canvas, .proxmox-widget-toolkit canvas, +canvas.x-surface, .x-surface canvas { + background-color: transparent !important; + opacity: 1 !important; +} + +.proxmox-rrd-panel, .proxmox-rrd-chart { + background-color: var(--pm-bg-base) !important; +} + +.x-surface text, svg text { + fill: var(--pm-text) !important; +} + +/* ===== PROXMOX-SPECIFIC OVERRIDES ===== */ +img[id^="proxmoxlogo-"][id$="-img"], +img[id^="proxmoxLogoSvg-"][id$="-img"] { + filter: invert(1) hue-rotate(180deg); +} + +.proxmox-invalid-row { + background-color: rgba(239, 68, 68, 0.15) !important; +} + +.proxmox-warning-row { + background-color: rgba(245, 158, 11, 0.15) !important; +} + +.proxmox-disabled-row td { + color: var(--pm-text-muted) !important; +} + +.pmx-hint { + background-color: rgba(245, 158, 11, 0.15) !important; + white-space: nowrap !important; +} + +.pmx-hint a { + color: var(--pm-info) !important; +} + +.info-blue { + color: var(--pm-info) !important; +} + +.critical { + color: var(--pm-error) !important; +} + +a { + color: var(--pm-info) !important; +} + +/* Markdown content */ +.pmx-md code { + background-color: var(--pm-bg-surface) !important; + color: var(--pm-accent-light) !important; + border-radius: var(--pm-radius-sm) !important; +} + +.pmx-md pre code { + border-color: var(--pm-border-subtle) !important; + background-color: var(--pm-bg-base) !important; +} + +.pmx-md a { + color: var(--pm-info) !important; +} + +.pmx-md table { + border-color: var(--pm-border-subtle) !important; +} + +.pmx-md th { + background-color: var(--pm-bg-surface) !important; + border-color: var(--pm-border-subtle) !important; +} + +.pmx-md td { + border-color: var(--pm-border-subtle) !important; +} + +/* APT repos */ +.proxmox-apt-repos .x-grid-group-hd { + background-color: var(--pm-bg-base) !important; + border: none !important; +} + +.proxmox-apt-repos .x-grid-group-title { + color: var(--pm-text) !important; +} + +/* Tags */ +.pve-edit-tag { + border-radius: var(--pm-radius-md) !important; +} + +.pve-edit-tag.editable span { + background-color: var(--pm-bg-surface) !important; + color: var(--pm-text) !important; + border-color: var(--pm-border-subtle) !important; +} + +.x-tree-node-text .proxmox-tag-dark, .x-tree-node-text .proxmox-tag-light, +.x-grid-cell-inner .proxmox-tag-dark, .x-grid-cell-inner .proxmox-tag-light, +span.proxmox-tag-dark, span.proxmox-tag-light { + border-radius: var(--pm-radius-md) !important; +} + +/* Checkmark button in tag edit */ +.x-btn.x-btn-default-small:has(.fa-check) { + min-height: 24px !important; + height: 24px !important; + padding: 3px 8px !important; + border-radius: var(--pm-radius-sm) !important; + background-color: var(--pm-accent) !important; + border: none !important; +} + +.x-btn.x-btn-default-small:has(.fa-check).x-btn-disabled { + background-color: transparent !important; + border: 1px solid var(--pm-border-subtle) !important; + opacity: 0.5 !important; +} + +.x-btn.x-btn-default-small:has(.fa-check) .fa-check { + color: #fff !important; +} + +.x-btn.x-btn-default-small:has(.fa-check).x-btn-disabled .fa-check { + color: var(--pm-text-muted) !important; +} + +.x-btn.x-btn-default-small:has(.fa-check):not(.x-btn-disabled):hover { + background-color: var(--pm-accent-light) !important; +} + +.x-btn.x-btn-default-small:has(.fa-check) .x-btn-inner { + display: none !important; +} + +/* Date picker */ +.x-datepicker, .x-datepicker-column-header, .x-monthpicker { + background-color: var(--pm-bg-base) !important; + color: var(--pm-text) !important; + border-color: transparent !important; +} + +.x-datepicker-header, .x-datepicker-footer, .x-monthpicker-buttons { + background-color: var(--pm-bg-surface) !important; +} + +.x-datepicker-date, .x-monthpicker-item-inner { + color: var(--pm-text) !important; +} + +.x-datepicker-selected div.x-datepicker-date, +.x-monthpicker-item a.x-monthpicker-selected, +a.x-monthpicker-item-inner:hover, div.x-datepicker-date:hover { + background-color: var(--pm-hover-overlay) !important; + color: var(--pm-text) !important; +} + +.x-datepicker-today .x-datepicker-date { + border-color: var(--pm-accent) !important; +} + +.x-datepicker-disabled .x-datepicker-date { + color: var(--pm-text-muted) !important; +} + +.x-datepicker-prev-day .x-datepicker-date, +.x-datepicker-next-day .x-datepicker-date { + color: var(--pm-text-muted) !important; +} + +/* Usage bars */ +.usage-wrapper, .usage { + border-radius: 2px !important; +} + +.usage { + background-color: var(--pm-text-muted) !important; +} + +/* ===== TOOL ICONS - FontAwesome Replacements ===== */ +.x-tool-tool-el.x-tool-minus, .x-tool-img.x-tool-minus, +.x-tool-tool-el.x-tool-collapse-right, .x-tool-img.x-tool-collapse-right, +.x-tool-tool-el.x-tool-collapse-left, .x-tool-img.x-tool-collapse-left, +.x-tool-tool-el.x-tool-expand-right, .x-tool-img.x-tool-expand-right, +.x-tool-tool-el.x-tool-expand-left, .x-tool-img.x-tool-expand-left, +.x-tool-tool-el.x-tool-maximize, .x-tool-img.x-tool-maximize, +.x-tool-tool-el.x-tool-restore, .x-tool-img.x-tool-restore, +.x-tool-tool-el.x-tool-gear, .x-tool-img.x-tool-gear, +.x-tool-tool-el.x-tool-refresh, .x-tool-img.x-tool-refresh, +.x-tool-tool-el.x-tool-close, .x-tool-img.x-tool-close { + background-image: none !important; + font-family: "FontAwesome" !important; + font-size: 14px !important; + line-height: 16px !important; + text-align: center !important; + color: var(--pm-text-dim) !important; + transition: color 0.15s ease !important; + filter: none !important; + width: 16px !important; + height: 16px !important; + display: flex !important; + align-items: center !important; + justify-content: center !important; +} + +.x-tool-tool-el.x-tool-close, .x-tool-img.x-tool-close { + font-size: 20px !important; +} + +.x-tool-tool-el.x-tool-minus::before, .x-tool-img.x-tool-minus::before { + content: "\f010" !important; +} + +.x-tool-tool-el.x-tool-collapse-right::before, .x-tool-img.x-tool-collapse-right::before { + content: "\f054" !important; +} + +.x-tool-tool-el.x-tool-expand-left::before, .x-tool-img.x-tool-expand-left::before { + content: "\f053" !important; +} + +.x-tool-tool-el.x-tool-collapse-left::before, .x-tool-img.x-tool-collapse-left::before { + content: "\f053" !important; +} + +.x-tool-tool-el.x-tool-expand-right::before, .x-tool-img.x-tool-expand-right::before { + content: "\f054" !important; +} + +.x-tool-tool-el.x-tool-maximize::before, .x-tool-img.x-tool-maximize::before { + content: "\f065" !important; +} + +.x-tool-tool-el.x-tool-restore::before, .x-tool-img.x-tool-restore::before { + content: "\f066" !important; +} + +.x-tool-tool-el.x-tool-gear::before, .x-tool-img.x-tool-gear::before { + content: "\f013" !important; +} + +.x-tool-tool-el.x-tool-refresh::before, .x-tool-img.x-tool-refresh::before { + content: "\f021" !important; +} + +.x-tool-tool-el.x-tool-close::before, .x-tool-img.x-tool-close::before { + content: "\f00d" !important; +} + +/* Hover state */ +.x-tool:hover .x-tool-tool-el.x-tool-minus, .x-tool:hover .x-tool-img.x-tool-minus, +.x-tool:hover .x-tool-tool-el.x-tool-collapse-right, .x-tool:hover .x-tool-img.x-tool-collapse-right, +.x-tool:hover .x-tool-tool-el.x-tool-collapse-left, .x-tool:hover .x-tool-img.x-tool-collapse-left, +.x-tool:hover .x-tool-tool-el.x-tool-expand-right, .x-tool:hover .x-tool-img.x-tool-expand-right, +.x-tool:hover .x-tool-tool-el.x-tool-expand-left, .x-tool:hover .x-tool-img.x-tool-expand-left, +.x-tool:hover .x-tool-tool-el.x-tool-maximize, .x-tool:hover .x-tool-img.x-tool-maximize, +.x-tool:hover .x-tool-tool-el.x-tool-restore, .x-tool:hover .x-tool-img.x-tool-restore, +.x-tool:hover .x-tool-tool-el.x-tool-gear, .x-tool:hover .x-tool-img.x-tool-gear, +.x-tool:hover .x-tool-tool-el.x-tool-refresh, .x-tool:hover .x-tool-img.x-tool-refresh, +.x-tool:hover .x-tool-tool-el.x-tool-close, .x-tool:hover .x-tool-img.x-tool-close { + color: var(--pm-text) !important; +} + +.x-tool-disabled .x-tool-tool-el, .x-tool-disabled .x-tool-img { + opacity: 0.4 !important; + cursor: default !important; +} + +/* Inline FA tools */ +.x-tool-tool-el[style*="font-family:FontAwesome"], +.x-tool-tool-el[style*="font-family: FontAwesome"] { + color: var(--pm-text-dim) !important; + font-size: 14px !important; + line-height: 16px !important; + display: flex !important; + align-items: center !important; + justify-content: center !important; + width: 16px !important; + height: 16px !important; + transition: color 0.15s ease !important; + background-image: none !important; + background-color: transparent !important; +} + +.x-tool:not(.x-tool-disabled) .x-tool-tool-el[style*="font-family:FontAwesome"], +.x-tool:not(.x-tool-disabled) .x-tool-tool-el[style*="font-family: FontAwesome"] { + cursor: pointer !important; +} + +.x-tool.x-tool-disabled .x-tool-tool-el[style*="font-family:FontAwesome"], +.x-tool.x-tool-disabled .x-tool-tool-el[style*="font-family: FontAwesome"] { + cursor: default !important; + opacity: 0.4 !important; +} + +.x-tool .x-mask { + background-color: transparent !important; + backdrop-filter: none !important; + pointer-events: none !important; +} + +.x-tool:not(.x-tool-disabled):hover .x-tool-tool-el[style*="font-family:FontAwesome"], +.x-tool:not(.x-tool-disabled):hover .x-tool-tool-el[style*="font-family: FontAwesome"] { + color: var(--pm-text) !important; +} + +/* ===== SCROLLBARS ===== */ +::-webkit-scrollbar { + width: 8px; + height: 8px; +} + +::-webkit-scrollbar-track { + background: var(--pm-bg-base); + border-radius: var(--pm-radius-sm); +} + +::-webkit-scrollbar-thumb { + background: var(--pm-border); + border-radius: var(--pm-radius-sm); + border: 1px solid transparent; + background-clip: padding-box; +} + +::-webkit-scrollbar-thumb:hover { + background: var(--pm-text-muted); +} + +::-webkit-scrollbar-corner { + background: var(--pm-bg-base); +} + +* { + scrollbar-width: thin; + scrollbar-color: var(--pm-border) var(--pm-bg-base); +} + +/* ===== SELECTION HIGHLIGHT ===== */ +::selection { + background-color: rgba(59, 130, 246, 0.3); + color: var(--pm-text); +} + +/* ===== TRANSITIONS ===== */ +.x-grid-item { + transition: background-color 0.15s ease !important; +} + +.x-treelist-row::before { + transition: background-color 0.15s ease !important; +} + +.x-menu-item-default > .x-menu-item-link { + transition: background-color 0.12s ease !important; +} + +.x-boundlist-item { + transition: background-color 0.12s ease !important; +} + +.x-tab { + transition: color 0.15s ease !important; +} + +.x-splitter { + transition: background-color 0.15s ease !important; +} + +.x-tip { + transition: opacity 0.15s ease !important; +} + +.x-progress-bar { + transition: width 0.4s ease !important; +} + +.x-tool-img { + transition: filter 0.15s ease !important; +} \ No newline at end of file diff --git a/themes/theme-catppuccin-frappe.css b/themes/theme-catppuccin-frappe.css new file mode 100644 index 0000000..c7d5ea5 --- /dev/null +++ b/themes/theme-catppuccin-frappe.css @@ -0,0 +1,2382 @@ +/*!Catppuccin Frappe*/ +/* + * ProxMorph Theme: Catppuccin Frappe + * Soothing pastel theme for Proxmox VE — the muted dark flavor of Catppuccin + * Version: 1.0.0 + * Author: ProxMorph / Catppuccin Community Palette + * + * v1.0.0: Initial release - Tier 2 production (generated from Mocha v1.3.0) + * Catppuccin Mocha palette, border-radius architecture (ported from UniFi), + * custom checkboxes/radios, full grid styling, progress bar states, + * tags, markdown, date picker, usage bars, Firefox scrollbar. + * + * Catppuccin Frappe Color Palette: + * + * ACCENT COLORS: + * - Rosewater: #f2d5cf - Flamingo: #eebebe + * - Pink: #f4b8e4 - Mauve: #ca9ee6 (Primary Accent) + * - Red: #e78284 - Maroon: #ea999c + * - Peach: #ef9f76 - Yellow: #e5c890 + * - Green: #a6d189 - Teal: #81c8be + * - Sky: #99d1db - Sapphire: #85c1dc + * - Blue: #8caaee - Lavender: #babbf1 + * + * NEUTRALS: + * - Text: #c6d0f5 - Subtext 1: #b5bfe2 + * - Subtext 0: #a5adce - Overlay 2: #949cbb + * - Overlay 1: #838ba7 - Overlay 0: #737994 + * - Surface 2: #626880 - Surface 1: #51576d + * - Surface 0: #414559 - Base: #303446 + * - Mantle: #292c3c - Crust: #232634 + */ + +/* ===================================================== + CSS VARIABLES + ===================================================== */ +:root { + /* Catppuccin Mocha Tokens */ + --ctp-rosewater: #f2d5cf; + --ctp-flamingo: #eebebe; + --ctp-pink: #f4b8e4; + --ctp-mauve: #ca9ee6; + --ctp-red: #e78284; + --ctp-maroon: #ea999c; + --ctp-peach: #ef9f76; + --ctp-yellow: #e5c890; + --ctp-green: #a6d189; + --ctp-teal: #81c8be; + --ctp-sky: #99d1db; + --ctp-sapphire: #85c1dc; + --ctp-blue: #8caaee; + --ctp-lavender: #babbf1; + + --ctp-text: #c6d0f5; + --ctp-subtext1: #b5bfe2; + --ctp-subtext0: #a5adce; + --ctp-overlay2: #949cbb; + --ctp-overlay1: #838ba7; + --ctp-overlay0: #737994; + --ctp-surface2: #626880; + --ctp-surface1: #51576d; + --ctp-surface0: #414559; + --ctp-base: #303446; + --ctp-mantle: #292c3c; + --ctp-crust: #232634; + + /* ProxMorph Semantic Variables */ + --pm-accent: var(--ctp-mauve); + --pm-bg-base: var(--ctp-base); + --pm-bg-surface: var(--ctp-surface0); + --pm-bg-elevated: var(--ctp-surface1); + --pm-text: var(--ctp-text); + --pm-text-dim: var(--ctp-subtext1); + --pm-success: var(--ctp-green); + --pm-warning: var(--ctp-yellow); + --pm-error: var(--ctp-red); + --pm-border: var(--ctp-surface1); + --pm-radius-sm: 4px; + --pm-radius-md: 6px; + --pm-radius-lg: 8px; + + /* Proxmox Widget Toolkit Mappings (REQUIRED) */ + --pwt-panel-background: var(--ctp-base); + --pwt-text-color: var(--ctp-text); + --pwt-gauge-default: var(--ctp-mauve); + --pwt-gauge-back: var(--ctp-surface1); + --pwt-gauge-warn: var(--ctp-yellow); + --pwt-gauge-crit: var(--ctp-red); + --pwt-chart-primary: var(--ctp-mauve); + --pwt-chart-grid-stroke: var(--ctp-surface1); + + /* On Accent text — style guide mandates Base for text on colored backgrounds */ + --ctp-on-accent: var(--ctp-base); + + /* Hover overlay — Overlay2@12% (neutral, per Catppuccin port conventions) */ + --ctp-hover-overlay: rgba(148, 156, 187, 0.12); + /* Selection overlay — Overlay2@25% (style guide: Selection Background → Overlay2 20-30%) */ + --ctp-select-overlay: rgba(148, 156, 187, 0.25); + /* Accent muted (for focus rings) */ + --ctp-accent-muted: rgba(202, 158, 230, 0.4); + --ctp-accent-subtle: rgba(202, 158, 230, 0.15); + + color-scheme: dark; +} + +/* ===================================================== + GLOBAL BORDER-RADIUS ARCHITECTURE + (Ported from UniFi theme — reset everything, selectively re-apply) + ===================================================== */ +.x-border-box, +.x-border-box * { + border-radius: var(--pm-radius-lg); +} + +/* Remove rounded corners from grids/tables/lists */ +.x-grid, +.x-grid *, +.x-grid-header-ct, +.x-grid-header-ct *, +.x-grid-view, +.x-grid-view *, +.x-column-header, +.x-column-header *, +.x-grid-item, +.x-grid-cell, +.x-grid-cell-inner, +.x-grid-row, +table, +table *, +tr, +td, +th, +.x-legend, +.x-legend *, +.x-legend-container, +.x-legend-container *, +.x-legend-item, +.x-legend-horizontal .x-legend-item, +.x-legend-vertical .x-legend-item, +.x-legend-horizontal .x-legend-item:first-child, +.x-legend-horizontal .x-legend-item:last-child, +.x-legend-vertical .x-legend-item:first-child, +.x-legend-vertical .x-legend-item:last-child, +.x-tool, +.x-tool-tool-el, +.x-tool-default, +.x-tool-img { + border-radius: 0 !important; +} + +/* Form elements - exclude from global radius */ +.x-form-item, +.x-form-item-default, +.x-form-item-body, +.x-form-item-body-default, +.x-form-text-field-body, +.x-form-text-field-body-default, +.x-form-fieldcontainer, +.x-field, +.x-field-default, +.x-form-type-text { + border-radius: 0 !important; +} + +/* Reset layout containers that clip elements with overflow:hidden + radius */ +.x-box-layout-ct, +.x-panel-bodyWrap, +.x-panel-bodyWrap-default, +.x-autocontainer-innerCt, +.x-autocontainer-outerCt, +.x-panel.x-tabpanel-child, +.x-panel.x-box-item, +.x-box-inner, +.x-box-target, +.x-container, +.x-container-default, +.x-window .x-panel-body, +.x-window .x-window-body, +.x-window .x-window-bodyWrap { + border-radius: 0 !important; +} + +/* Reset everything inside windows to 0 — then re-apply specific radii */ +.x-window *, +.x-window .x-autocontainer-innerCt, +.x-window .x-autocontainer-outerCt, +.x-window .x-form-layout-wrap, +.x-window .x-form-layout-auto-label, +.x-window .x-form-layout-colgroup, +.x-window .x-form-layout-column, +.x-window .x-field, +.x-window .x-form-item, +.x-window .x-form-item-body { + border-radius: 0 !important; +} + +/* Chart canvas — no radius on data area */ +.x-chart-grid, +.x-chart-axis, +canvas.x-surface, +.x-chart canvas, +canvas.x-surface-canvas, +.x-surface-canvas, +.x-draw-component canvas, +.proxmox-rrd-chart canvas, +svg.x-surface, +.x-draw-container, +.x-surface { + border-radius: 0 !important; +} + +/* Legend color marker (dot) — keep circular */ +.x-legend-item-marker { + border-radius: 50% !important; +} + +/* ===================================================== + RE-APPLY BORDER RADII (selective) + ===================================================== */ + +/* Windows */ +.x-window, +.x-window-default { + border-radius: var(--pm-radius-lg) !important; +} + +.x-window-header, +.x-window-header-default { + border-radius: var(--pm-radius-lg) var(--pm-radius-lg) 0 0 !important; +} + +.x-window .x-window-body, +.x-window-body-default { + border-radius: 0 !important; +} + +/* Buttons inside windows */ +.x-window .x-btn { + border-radius: var(--pm-radius-md) !important; +} + +/* Checkboxes inside windows */ +.x-window .x-form-checkbox { + border-radius: 3px !important; +} + +/* Form inputs inside windows */ +.x-window .x-form-trigger-wrap, +.x-window .x-form-trigger-wrap-default { + border-radius: var(--pm-radius-sm) !important; +} + +.x-window .x-form-text-wrap, +.x-window .x-form-text { + border-radius: var(--pm-radius-sm) 0 0 var(--pm-radius-sm) !important; +} + +.x-window .x-form-arrow-trigger { + border-radius: 0 var(--pm-radius-sm) var(--pm-radius-sm) 0 !important; +} + +/* Form trigger/text wrap — reset and re-apply */ +.x-form-trigger-wrap, +.x-form-trigger-wrap *, +.x-form-text-wrap, +.x-form-text-wrap *, +.x-form-text, +.x-form-trigger { + border-radius: 0 !important; +} + +.x-form-trigger-wrap, +.x-form-trigger-wrap-default { + border-radius: var(--pm-radius-sm) !important; + overflow: hidden !important; +} + +.x-form-text-wrap, +.x-form-text-wrap-default { + border-radius: var(--pm-radius-sm) 0 0 var(--pm-radius-sm) !important; +} + +.x-form-text, +.x-form-text-default { + border-radius: var(--pm-radius-sm) 0 0 var(--pm-radius-sm) !important; +} + +.x-form-trigger, +.x-form-trigger-default, +.x-form-arrow-trigger, +.x-form-arrow-trigger-default { + border-radius: 0 var(--pm-radius-sm) var(--pm-radius-sm) 0 !important; +} + +/* Dialog form content padding — vertical only (horizontal causes ExtJS overflow) */ +.x-window .x-tabpanel-child .x-autocontainer-innerCt { + padding: 12px 0 !important; +} + +/* Allow column panel bodies to show overflowed form content */ +.x-window .x-panel-body:not(.x-scroller) { + overflow: visible !important; +} + +/* Side padding on column panel bodies inside windows */ +.x-window .x-panel.x-box-item .x-panel-body { + padding: 0 4px !important; +} + +/* Constrain autocontainer width inside windows */ +.x-window .x-autocontainer-outerCt { + max-width: 100% !important; +} + +/* Fix window header/body width consistency */ +.x-window > .x-window-header, +.x-window > .x-window-body, +.x-window > .x-window-bodyWrap, +.x-window-bodyWrap > .x-window-body { + width: 100% !important; +} + +.x-window-header > .x-box-inner, +.x-window-header > .x-box-inner > .x-box-target { + width: 100% !important; +} + +.x-window-header-title { + width: auto !important; + flex: 1 !important; + max-width: calc(100% - 30px) !important; +} + +/* Boundlists */ +.x-boundlist { + border-radius: var(--pm-radius-md) !important; + overflow: hidden !important; +} + +/* ===================================================== + BASE / BODY + ===================================================== */ +.x-body, +.x-viewport > .x-body, +body.x-border-layout-ct, +div.x-border-layout-ct { + background-color: var(--ctp-base) !important; + color: var(--ctp-text) !important; +} + +/* ===================================================== + MASKS & OVERLAYS + ===================================================== */ +.x-mask { + background-color: rgba(35, 38, 52, 0.6) !important; + backdrop-filter: blur(4px); +} + +.x-mask-msg { + background-color: var(--ctp-mantle) !important; + border: 1px solid var(--ctp-surface1) !important; + border-radius: var(--pm-radius-lg) !important; +} + +.x-mask-msg-text { + color: var(--ctp-subtext0) !important; + filter: none !important; +} + +.x-css-shadow { + box-shadow: 0 8px 24px rgba(35, 38, 52, 0.6) !important; +} + +/* Loading indicators */ +.x-grid-row-loading, +.x-treelist-item-loading .x-treelist-item-icon, +.x-grid-tree-loading .x-tree-icon { + filter: invert(90%); +} + +/* ===================================================== + ICONS — Proxmox default colors for dark mode + ===================================================== */ + +/* General icon colors — neutral gray for dark backgrounds */ +.x-tree-icon-custom, +.x-grid-icon-custom, +.fa-tags::before, +.fa-file-o::before, +.fa-building::before, +.x-action-col-icon::before, +.fa-shield::before, +.fa-file-text-o::before, +.fa-clock-o::before, +.x-tab-icon-el-default, +.pve-icon-verify-lettering::after, +.x-tree-icon-leaf:not(.x-tree-icon-custom)::before, +.x-tree-icon-parent:not(.x-tree-icon-custom)::before, +.x-tree-icon-parent-expanded:not(.x-tree-icon-custom)::before, +.x-grid-filters-filtered-column .x-column-header-text::after { + color: var(--ctp-overlay2) !important; +} + +/* Folder icons — invert for dark mode */ +.x-tree-icon-parent:not(.x-tree-icon-custom)::before, +.x-tree-icon-parent-expanded:not(.x-tree-icon-custom)::before { + filter: invert(90%); +} + +/* Various image-based icons — invert for visibility */ +.fa-ceph::before, +.fa-sdn::before, +.fa-network-wired::before, +.pve-itype-treelist-item-icon-cdrom, +.fa-chevron-right::before, +.x-grid-row-console, +.x-box-scroller-toolbar-default.x-box-scroller, +.x-tree-elbow-img, +.pve-itype-icon-qemu, +.x-tree-node-computer, +.x-grid-tree-node-expanded .x-tree-node-computer, +.pbs-icon-tape, +.pbs-icon-tape-drive, +.x-tree-icon-leaf:not(.x-tree-icon-custom), +.x-tree-icon-parent:not(.x-tree-icon-custom), +.x-tree-icon-parent-expanded:not(.x-tree-icon-custom) { + filter: invert(90%); +} + +/* Hardware icons */ +.pve-itype-icon-cpu, +.pve-itype-icon-cdrom, +.pve-itype-icon-memory, +.pve-itype-icon-pci, +.pve-itype-icon-serial, +.pve-itype-icon-die, +.pmx-itype-icon-processor, +.pmx-itype-icon-memory, +.pve-itype-icon-storage, +.x-tree-node-harddisk, +.x-grid-tree-node-expanded .x-tree-node-harddisk { + filter: invert(100%); +} + +/* Hardware icons — counter-invert for non-SVG icon cells */ +td.pve-itype-icon-storage .x-grid-cell-inner, +td.x-tree-node-harddisk .x-grid-cell-inner { + filter: invert(100%) !important; +} + +/* Hardware icons — hide inverted borders for non-SVG icon cells */ +td.pve-itype-icon-storage, +td.x-tree-node-harddisk { + border-color: transparent !important; +} + +/* Hardware grid icons — mask-image renders SVG icons in theme text color + Replaces filter:invert approach for pve-itype-icon-* and pmx-itype-icon-* grid cells */ +td.pve-itype-icon-cpu, +td.pve-itype-icon-cdrom, +td.pve-itype-icon-memory, +td.pve-itype-icon-pci, +td.pve-itype-icon-serial, +td.pve-itype-icon-die, +td.pmx-itype-icon-processor, +td.pmx-itype-icon-memory { + filter: none !important; + background-image: none !important; + padding-left: 0 !important; + border-color: transparent !important; +} + +td.pve-itype-icon-cpu .x-grid-cell-inner, +td.pve-itype-icon-cdrom .x-grid-cell-inner, +td.pve-itype-icon-memory .x-grid-cell-inner, +td.pve-itype-icon-pci .x-grid-cell-inner, +td.pve-itype-icon-serial .x-grid-cell-inner, +td.pve-itype-icon-die .x-grid-cell-inner, +td.pmx-itype-icon-processor .x-grid-cell-inner, +td.pmx-itype-icon-memory .x-grid-cell-inner { + padding-left: 3px !important; +} + +td.pve-itype-icon-cpu .x-grid-cell-inner::before, +td.pve-itype-icon-cdrom .x-grid-cell-inner::before, +td.pve-itype-icon-memory .x-grid-cell-inner::before, +td.pve-itype-icon-pci .x-grid-cell-inner::before, +td.pve-itype-icon-serial .x-grid-cell-inner::before, +td.pve-itype-icon-die .x-grid-cell-inner::before, +td.pmx-itype-icon-processor .x-grid-cell-inner::before, +td.pmx-itype-icon-memory .x-grid-cell-inner::before { + content: '' !important; + display: inline-block !important; + width: 18px !important; + height: 14px !important; + vertical-align: middle !important; + margin-right: 10px !important; + background-color: currentColor !important; + -webkit-mask-size: contain !important; + mask-size: contain !important; + -webkit-mask-repeat: no-repeat !important; + mask-repeat: no-repeat !important; + -webkit-mask-position: center !important; + mask-position: center !important; +} + +td.pve-itype-icon-cpu .x-grid-cell-inner::before { + -webkit-mask-image: url('/pve2/images/icon-cpu.svg') !important; + mask-image: url('/pve2/images/icon-cpu.svg') !important; +} + +td.pve-itype-icon-memory .x-grid-cell-inner::before { + -webkit-mask-image: url('/pve2/images/icon-memory.svg') !important; + mask-image: url('/pve2/images/icon-memory.svg') !important; +} + +td.pve-itype-icon-cdrom .x-grid-cell-inner::before { + -webkit-mask-image: url('/pve2/images/icon-cd-drive.svg') !important; + mask-image: url('/pve2/images/icon-cd-drive.svg') !important; +} + +td.pve-itype-icon-pci .x-grid-cell-inner::before { + -webkit-mask-image: url('/pve2/images/icon-pci.svg') !important; + mask-image: url('/pve2/images/icon-pci.svg') !important; +} + +td.pve-itype-icon-serial .x-grid-cell-inner::before { + -webkit-mask-image: url('/pve2/images/icon-serial.svg') !important; + mask-image: url('/pve2/images/icon-serial.svg') !important; +} + +td.pve-itype-icon-die .x-grid-cell-inner::before { + -webkit-mask-image: url('/pve2/images/icon-die.svg') !important; + mask-image: url('/pve2/images/icon-die.svg') !important; +} + +td.pmx-itype-icon-processor .x-grid-cell-inner::before { + -webkit-mask-image: url('../images/icon-cpu.svg') !important; + mask-image: url('../images/icon-cpu.svg') !important; +} + +td.pmx-itype-icon-memory .x-grid-cell-inner::before { + -webkit-mask-image: url('../images/icon-ram.svg') !important; + mask-image: url('../images/icon-ram.svg') !important; +} + + +/* Icon overlays — default */ +.x-tree-icon-custom::after, +.x-grid-icon-custom::after { + color: var(--ctp-overlay2) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* RUNNING VMs/CTs — Catppuccin Green */ +.x-tree-icon-custom.running::after, +.x-grid-icon-custom.running::after, +.x-treelist-item-icon.running::after { + color: var(--ctp-green) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* ONLINE state — Green */ +.x-tree-icon-custom.online::after, +.x-grid-icon-custom.online::after { + color: var(--ctp-green) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* Stopped/offline — Overlay1 (muted gray) */ +.x-tree-icon-custom.stopped, +.x-tree-icon-custom.offline, +.x-grid-icon-custom.stopped, +.x-grid-icon-custom.offline { + color: var(--ctp-overlay1) !important; +} + +/* Unknown state — Overlay1 */ +.x-tree-icon-custom.unknown::after, +.x-grid-icon-custom.unknown::after { + color: var(--ctp-overlay1) !important; +} + +/* ERROR states — Catppuccin Red */ +.x-tree-icon-custom.error::after, +.x-tree-icon-custom.offline::after, +.x-tree-icon-custom.ha-error::after, +.x-grid-icon-custom.error::after, +.x-grid-icon-custom.offline::after, +.x-grid-icon-custom.ha-error::after { + color: var(--ctp-red) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* PAUSED/SUSPENDED — Catppuccin Peach */ +.x-tree-icon-custom.paused::after, +.x-tree-icon-custom.suspended::after, +.x-tree-icon-custom.lock-suspending::after, +.x-grid-icon-custom.paused::after, +.x-grid-icon-custom.suspended::after, +.x-grid-icon-custom.lock-suspending::after { + color: var(--ctp-peach) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* PENDING/WARNING states — Catppuccin Yellow */ +.x-tree-icon-custom.pending::after, +.x-tree-icon-custom.io-error::after, +.x-tree-icon-custom.internal-error::after, +.x-tree-icon-custom.guest-panicked::after, +.x-grid-icon-custom.pending::after, +.x-grid-icon-custom.io-error::after, +.x-grid-icon-custom.internal-error::after, +.x-grid-icon-custom.guest-panicked::after { + color: var(--ctp-yellow) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* HA MAINTENANCE — Catppuccin Sky */ +.x-tree-icon-custom.ha-maintenance::after, +.x-grid-icon-custom.ha-maintenance::after { + color: var(--ctp-sky) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* Locked icons */ +.x-tree-icon-custom.locked::after, +.x-tree-icon-custom.lock-backup::after, +.x-tree-icon-custom.lock-migrate::after, +.x-tree-icon-custom.lock-suspended::after, +.x-grid-icon-custom.locked::after, +.x-grid-icon-custom.lock-backup::after, +.x-grid-icon-custom.lock-migrate::after, +.x-grid-icon-custom.lock-suspended::after { + color: var(--ctp-overlay2) !important; +} + +/* LXC/QEMU type indicators */ +.x-tree-icon-custom.lxc::after, +.x-tree-icon-custom.qemu::after, +.x-grid-icon-custom.lxc::after, +.x-grid-icon-custom.qemu::after { + background-color: transparent; + color: var(--ctp-overlay1) !important; +} + +.x-treelist-item-icon.lxc::after, +.x-treelist-item-icon.qemu::after { + background-color: transparent; + color: var(--ctp-overlay1) !important; +} + +/* Tree expander arrows */ +.x-tree-arrows .x-tree-expander { + filter: brightness(200%); +} + +/* Cancel sprite-inversion on custom controls (checkboxes/radios handled via CSS) */ +.x-form-checkbox-default, +.x-form-radio-default, +.x-column-header-checkbox .x-column-header-checkbox::after, +.x-grid-checkcolumn::after, +.x-menu-item-checked .x-menu-item-icon-default.x-menu-item-checkbox, +.x-menu-item-unchecked .x-menu-item-icon-default.x-menu-item-checkbox { + filter: none !important; +} + +/* ===================================================== + PANELS & HEADERS + ===================================================== */ +.x-panel, +.x-panel-default { + border-radius: var(--pm-radius-lg) !important; + padding: 0 !important; +} + +/* Column panels — native stacked layout (Issue #23 fix) */ +.x-panel.x-column { + padding: 5px !important; + margin: 0 !important; + max-width: none !important; + box-sizing: border-box !important; +} + +/* Column panel card styling — borders for summary + chart panels */ +.x-panel.x-panel-default.x-column { + border: 1px solid var(--ctp-surface1) !important; + border-radius: var(--pm-radius-lg) !important; + overflow: hidden !important; +} + +/* Guest status + Notes panel borders */ +[id^="pveGuestStatusView-"].x-panel, +[id^="pveLxcStatusView-"].x-panel, +[id^="pveQemuStatusView-"].x-panel, +[id^="pmxNotesView-"].x-panel { + border: 1px solid var(--ctp-surface1) !important; + border-radius: var(--pm-radius-lg) !important; +} + +.x-panel-body, +.x-panel-body-default { + background-color: var(--ctp-base) !important; + color: var(--ctp-text) !important; + border: none !important; +} + +/* Panel headers — bottom border only */ +.x-panel-header, +.x-panel-header-default { + background-color: var(--ctp-mantle) !important; + border: none !important; + border-bottom: 1px solid var(--ctp-surface1) !important; + border-radius: var(--pm-radius-lg) var(--pm-radius-lg) 0 0 !important; + margin: 0 !important; + padding: 8px 12px !important; + width: 100% !important; + box-sizing: border-box !important; + overflow: visible !important; +} + +/* Title text — prevent border-radius clipping */ +.x-title-text, +.x-title-text-default { + overflow: visible !important; +} + +.x-panel-bodyWrap, +.x-panel-bodyWrap-default { + margin: 0 !important; + padding: 0 !important; + overflow: visible !important; +} + +/* Remove borders from nested panels */ +.x-panel-body > .x-box-layout-ct, +.x-panel-body > .x-container, +.x-panel-body > .x-box-inner, +[id*="pmxGauge"] { + border: none !important; +} + +.x-panel-header-title-default, +.x-window-header-title-default { + color: var(--ctp-text) !important; +} + +.x-panel-header-default .x-tool-tool-el { + background-color: transparent; +} + +.x-tool-img { + filter: brightness(175%); +} + +.x-tool-over .x-tool-img { + filter: brightness(200%); +} + +/* Resource tree — panel body border */ +div[id^="pveResourceTree-"][id$="-body"] { + border-color: var(--ctp-base) !important; +} + +/* Resource tree — remove row separators */ +[id^="pveResourceTree-"].x-tree-panel td.x-grid-cell, +[id^="pveResourceTree-"].x-tree-panel .x-grid-td, +[id^="pveResourceTree-"].x-tree-panel .x-grid-cell { + border-bottom: none !important; +} + +/* Resource tree — row spacing */ +div[id^="pveResourceTree"] .x-grid-cell { + padding-top: 3px !important; + padding-bottom: 3px !important; +} + +/* Summary/stats panel radius overrides */ +.pveStatusPanel, +.x-panel-default-framed, +.x-panel-body-default-framed { + border-radius: 12px !important; +} + +.x-panel-header-default-framed { + border-radius: 12px 12px 0 0 !important; +} + +/* Column widget panel radius */ +.x-panel.x-column > .x-panel-bodyWrap > .x-panel-body.x-panel-body-default { + border-radius: var(--pm-radius-lg) !important; +} + +/* ===================================================== + SPLITTERS / SEPARATORS + ===================================================== */ +.x-splitter-vertical { + background-color: transparent !important; + border-left: 1px solid var(--ctp-surface1) !important; + border-right: none !important; + width: 1px !important; +} + +.x-splitter-horizontal { + background-color: var(--ctp-crust) !important; + border-top: 1px solid var(--ctp-surface1) !important; +} + +.x-splitter { + background-color: var(--ctp-crust) !important; +} + +.x-keyboard-mode .x-splitter-focus::after { + border-color: var(--ctp-mauve) !important; +} + +.x-layout-split-bottom { + opacity: 0.7; +} + +/* Toolbox tree (pve-nav) right border — full height */ +.pve-toolbar-bg { + border-right: 1px solid var(--ctp-surface1) !important; + z-index: 3 !important; +} + +.x-treelist.x-treelist-pve-nav { + border-right: none !important; +} + +/* ===================================================== + TOOLBARS + ===================================================== */ +.x-toolbar, +.x-toolbar-default { + background-color: var(--ctp-base) !important; + border-color: var(--ctp-surface1) !important; +} + +.x-toolbar-default.x-docked-top { + border: none !important; + border-bottom: 1px solid var(--ctp-surface1) !important; +} + +.x-toolbar-default .x-toolbar-separator { + border-color: var(--ctp-surface1); +} + +.x-toolbar-text-default { + color: var(--ctp-subtext0); +} + +/* ===================================================== + PRIMARY BUTTONS — Catppuccin Mauve + ===================================================== */ +.x-btn-default-small { + background-color: var(--ctp-mauve) !important; + border: 1px solid rgba(202, 158, 230, 0.4) !important; + border-radius: var(--pm-radius-md) !important; + transition: background-color 0.15s ease, box-shadow 0.15s ease !important; +} + +.x-btn-default-small .x-btn-inner { + color: var(--ctp-on-accent) !important; + font-weight: 600 !important; +} + +.x-btn-default-small .x-btn-icon-el { + color: var(--ctp-on-accent) !important; +} + +.x-btn-default-small.x-btn-over, +.x-keyboard-mode .x-btn-default-small.x-btn-focus { + background-color: #d5aee9 !important; + box-shadow: 0 0 0 3px var(--ctp-accent-subtle) !important; +} + +.x-btn-default-small.x-btn.x-btn-disabled { + background-color: var(--ctp-mauve) !important; + opacity: 0.4; +} + +.x-btn-default-small.x-btn.x-btn-pressed { + background-color: #b88cd6 !important; +} + +/* Button height consistency — 28px with vertical centering */ +/* Exclude tag edit buttons (display:none when hidden, :has(.fa-check) for checkmark) */ +.x-btn.x-btn-default-small:not(.x-btn-default-toolbar-small):not([style*="display: none"]):not([style*="display:none"]):not(:has(.fa-check)) { + height: 28px !important; + min-height: 28px !important; + display: flex !important; + align-items: center !important; + padding: 3px 8px !important; +} + +/* Fix button inner element centering for proper icon alignment (issue #17) */ +.x-btn.x-btn-default-small:not(.x-btn-default-toolbar-small):not([style*="display: none"]):not([style*="display:none"]):not(:has(.fa-check)) .x-btn-wrap { + display: flex !important; + align-items: center !important; +} + +.x-btn.x-btn-default-small:not(.x-btn-default-toolbar-small):not([style*="display: none"]):not([style*="display:none"]):not(:has(.fa-check)) .x-btn-inner { + display: flex !important; + align-items: center !important; +} + +/* Fix dropdown arrows on split/arrow buttons */ +.x-btn-wrap.x-btn-arrow-right::after, +.x-btn-wrap.x-btn-split-right::after { + height: 16px !important; + min-height: 16px !important; + width: 20px !important; + display: flex !important; + align-items: center !important; +} + +/* Fix icon-only buttons — hide   inner element when button has no text */ +.x-btn-no-text .x-btn-inner, +.x-btn-button.x-btn-no-text .x-btn-inner, +.x-btn-button-default-toolbar-small.x-btn-no-text .x-btn-inner-default-toolbar-small, +.x-btn-button-default-small.x-btn-no-text .x-btn-inner-default-small, +.x-btn-button-default-small.x-btn-no-text > .x-btn-inner-default-small { + display: none !important; +} + +/* Specific fix for fa-desktop icon (Create VM) — visually bottom-heavy */ +.x-btn-icon-el.fa-desktop { + transform: translateY(1.1px) !important; +} + +/* ===================================================== + SECONDARY / TOOLBAR BUTTONS + ===================================================== */ +.x-btn-default-toolbar-small { + background-color: var(--ctp-surface0) !important; + border: 1px solid var(--ctp-surface1) !important; + border-radius: var(--pm-radius-md) !important; + transition: background-color 0.15s ease, border-color 0.15s ease !important; +} + +.x-btn-default-toolbar-small .x-btn-inner-default-toolbar-small, +.x-btn-default-toolbar-small .x-btn-icon-el-default-toolbar-small { + color: var(--ctp-text) !important; +} + +.x-btn-default-toolbar-small .x-btn-wrap-default-toolbar-small.x-btn-arrow-right::after, +.x-btn-default-toolbar-small .x-btn-wrap-default-toolbar-small.x-btn-split-right::after { + filter: brightness(150%); +} + +.x-btn-default-toolbar-small.x-btn-over, +.x-keyboard-mode .x-btn-default-toolbar-small.x-btn-focus { + background-color: var(--ctp-surface1) !important; + border-color: var(--ctp-surface2) !important; +} + +.x-btn-default-toolbar-small.x-btn.x-btn-disabled { + background-color: var(--ctp-surface0) !important; + opacity: 0.4; +} + +.x-btn-default-toolbar-small.x-btn.x-btn-menu-active, +.x-btn-default-toolbar-small.x-btn.x-btn-pressed { + background-color: var(--ctp-mauve) !important; + border-color: var(--ctp-mauve) !important; + padding: 4px 8px !important; /* Fix #30: prevent width change on dropdown */ +} + +.x-btn-default-toolbar-small.x-btn.x-btn-pressed .x-btn-inner-default-toolbar-small, +.x-btn-default-toolbar-small.x-btn.x-btn-pressed .x-btn-icon-el-default-toolbar-small, +.x-btn-default-toolbar-small.x-btn.x-btn-pressed .x-btn-inner-default-small, +.x-btn-default-toolbar-small.x-btn.x-btn-pressed .x-btn-icon-el-default-small { + color: var(--ctp-on-accent) !important; +} + +/* Segmented buttons */ +.x-segmented-button { + border-radius: var(--pm-radius-md) !important; +} + +.x-segmented-button .x-btn, +.x-segmented-button .x-btn-default-small, +.x-segmented-button .x-btn-inner, +.x-segmented-button .x-btn-wrap { + border-radius: var(--pm-radius-md) !important; +} + +/* Inline buttons (Documentation, Help) */ +.proxmox-inline-button { + height: 28px !important; + min-height: 28px !important; + display: flex !important; + align-items: center !important; + padding: 3px 8px !important; + background-color: var(--ctp-surface0) !important; + border: 1px solid var(--ctp-surface1) !important; + border-radius: var(--pm-radius-md) !important; + color: var(--ctp-text) !important; + transition: background-color 0.15s ease !important; +} + +.proxmox-inline-button:hover, +.proxmox-inline-button.x-btn-over { + background-color: var(--ctp-surface1) !important; + border-color: var(--ctp-overlay0) !important; +} + +.proxmox-inline-button:active, +.proxmox-inline-button.x-btn-pressed { + background-color: var(--ctp-surface2) !important; +} + +.proxmox-inline-button .x-btn-inner, +.proxmox-inline-button .x-btn-icon-el { + color: var(--ctp-text) !important; +} + +/* Pressed/active inline buttons get accent bg from toolbar rules — use on-accent text */ +.proxmox-inline-button.x-btn-pressed .x-btn-inner, +.proxmox-inline-button.x-btn-pressed .x-btn-icon-el, +.proxmox-inline-button.x-btn-menu-active .x-btn-inner, +.proxmox-inline-button.x-btn-menu-active .x-btn-icon-el { + color: var(--ctp-on-accent) !important; +} + +/* ===================================================== + FORM ELEMENTS + ===================================================== */ +.x-form-trigger-default { + background-color: var(--ctp-surface0) !important; +} + +.x-form-text-default { + background-color: var(--ctp-surface0) !important; + color: var(--ctp-text) !important; + border-radius: var(--pm-radius-sm) !important; +} + +.x-form-trigger-wrap, +.x-form-trigger-wrap-default { + border-color: var(--ctp-surface1) !important; + background-color: var(--ctp-surface0) !important; + border-radius: var(--pm-radius-sm) !important; + transition: border-color 0.15s ease !important; +} + +.x-form-trigger-wrap-default.x-form-trigger-wrap-focus { + border-color: var(--ctp-mauve) !important; + box-shadow: 0 0 0 3px var(--ctp-accent-subtle) !important; +} + +.x-form-item-label-default, +.x-form-cb-label-default { + color: var(--ctp-text) !important; +} + +.x-form-display-field-default { + color: var(--ctp-subtext0) !important; + border-radius: var(--pm-radius-md) !important; +} + +.x-form-spinner-default { + background-color: var(--ctp-surface0) !important; +} + +.x-fieldset, +.x-fieldset-default { + border-color: var(--ctp-surface1) !important; + border-radius: var(--pm-radius-lg) !important; +} + +.x-fieldset-header-default > .x-fieldset-header-text { + color: var(--ctp-text) !important; +} + +/* ===================================================== + CHECKBOXES & RADIOS — Catppuccin styled + ===================================================== */ + +/* Base: remove sprite, styled as custom control */ +.x-form-checkbox, .x-form-checkbox-default, +.x-form-radio, .x-form-radio-default { + background-image: none !important; + background-color: var(--ctp-surface0) !important; + border: 1.5px solid var(--ctp-overlay0) !important; + width: 16px !important; + height: 16px !important; + display: inline-block !important; + box-sizing: border-box !important; + cursor: pointer !important; + transition: border-color 0.12s ease, background-color 0.12s ease !important; +} + +/* Checkbox: rounded square */ +.x-form-checkbox, .x-form-checkbox-default { + border-radius: 3px !important; +} + +/* Radio: circle + ::after inner dot */ +.x-form-radio, .x-form-radio-default { + border-radius: 50% !important; + position: relative !important; + transform: translateZ(0) !important; + box-shadow: inset 0 0 0 0 transparent !important; +} + +.x-form-radio::after { + content: '' !important; + position: absolute !important; + top: 50% !important; + left: 50% !important; + width: 7px !important; + height: 7px !important; + border-radius: 50% !important; + background: transparent !important; + transform: translate(-50%, -50%) scale(0) !important; + transition: transform 0.15s ease, background 0.15s ease !important; + pointer-events: none !important; +} + +/* Hover */ +.x-form-checkbox:hover, .x-form-checkbox-default:hover, +.x-form-cb-wrap:hover .x-form-checkbox { + border-color: var(--ctp-mauve) !important; +} + +.x-form-radio:hover, .x-form-radio-default:hover, +.x-form-cb-wrap:hover .x-form-radio { + border-color: var(--ctp-mauve) !important; +} + +/* CHECKED checkbox — Mauve fill + white SVG checkmark */ +.x-form-cb-checked .x-form-checkbox, +.x-form-cb-checked .x-form-checkbox-default { + background-color: var(--ctp-mauve) !important; + border-color: var(--ctp-mauve) !important; + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 8'%3E%3Cpath d='M1 4l3 3 5-6' fill='none' stroke='%23303446' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") !important; + background-repeat: no-repeat !important; + background-position: center !important; + background-size: 9px 7px !important; +} + +/* SELECTED radio — Mauve dot */ +.x-form-cb-checked .x-form-radio, +.x-form-cb-checked .x-form-radio-default { + border-color: var(--ctp-mauve) !important; + background-color: var(--ctp-base) !important; +} + +.x-form-cb-checked .x-form-radio::after { + background: var(--ctp-mauve) !important; + transform: translate(-50%, -50%) scale(1) !important; +} + +/* ===================================================== + BOUNDLIST / DROPDOWNS + ===================================================== */ +.x-boundlist { + background-color: var(--ctp-mantle) !important; + border: 1px solid var(--ctp-surface1) !important; + border-radius: var(--pm-radius-md) !important; + box-shadow: 0 8px 24px rgba(35, 38, 52, 0.7) !important; + padding: 2px !important; + overflow: hidden !important; +} + +.x-boundlist-item { + background-color: transparent !important; + color: var(--ctp-text) !important; + border-radius: var(--pm-radius-sm) !important; + padding: 2px 6px !important; + line-height: normal !important; + border: none !important; + cursor: pointer !important; + outline: none !important; + box-shadow: none !important; +} + +.x-boundlist-selected { + background-color: var(--ctp-select-overlay) !important; + color: var(--ctp-text) !important; +} + +.x-boundlist-item-over { + background-color: var(--ctp-hover-overlay) !important; +} + +/* ===================================================== + GRIDS / TABLES + ===================================================== */ +.x-grid, +.x-grid-view { + border-radius: 0 !important; +} + +.x-column-header { + border-color: var(--ctp-surface1) !important; + background-color: transparent !important; +} + +.x-column-header-inner, +.x-column-header-text { + color: var(--ctp-text) !important; + font-weight: 600 !important; +} + +.x-column-header-trigger { + border-color: var(--ctp-surface1) !important; +} + +.x-grid-item, +.x-column-header-default, +.x-grid-cell-row-numberer { + color: var(--ctp-text) !important; + background-color: var(--ctp-base) !important; +} + +.x-grid-cell-special { + border-color: var(--ctp-surface1) !important; +} + +.x-grid-group-hd { + background-color: var(--ctp-base) !important; + border-color: var(--ctp-surface1) !important; +} + +.x-grid-group-title { + color: var(--ctp-text) !important; +} + +.x-grid-header-ct { + background-color: var(--ctp-mantle) !important; + border: 1px solid var(--ctp-surface0) !important; + border-radius: var(--pm-radius-lg) var(--pm-radius-lg) 0 0 !important; +} + +.x-grid-item-alt { + background-color: var(--ctp-crust) !important; +} + +.x-grid-with-row-lines .x-grid-item { + border-color: var(--ctp-surface0) !important; +} + +.x-grid-cell { + border-bottom: 1px solid rgba(69, 71, 90, 0.4) !important; +} + +.x-grid-item-over, +.x-grid-with-row-lines .x-grid-item.x-grid-item-over { + background-color: var(--ctp-hover-overlay) !important; +} + +.x-grid-item-selected, +.x-grid-with-row-lines .x-grid-item.x-grid-item-selected { + background-color: var(--ctp-select-overlay) !important; +} + +.x-column-header-over, +.x-column-header-open { + background-color: var(--ctp-hover-overlay) !important; +} + +.x-column-header-sort-ASC, +.x-column-header-sort-DESC { + background-color: var(--ctp-hover-overlay) !important; +} + +.x-grid-row-summary .x-grid-cell, +.x-grid-row-summary .x-grid-rowwrap, +.x-grid-row-summary .x-grid-cell-rowbody { + background-color: var(--ctp-base) !important; + border-color: var(--ctp-surface1); +} + +.x-grid-with-col-lines .x-grid-cell, +.x-grid-with-col-lines .x-grid-item-over .x-grid-cell, +.x-grid-with-col-lines .x-grid-item-selected .x-grid-cell { + border-color: var(--ctp-surface1) !important; +} + +.x-dd-drag-proxy { + background-color: var(--ctp-mantle); + border-color: var(--ctp-surface1); + color: var(--ctp-text); +} + +.x-keyboard-mode .x-grid-item-focused { + background-color: var(--ctp-hover-overlay) !important; + color: var(--ctp-text) !important; +} + +/* Remove blue outline from focused/selected items in resource tree */ +.x-keyboard-mode .x-grid-item-focused .x-grid-cell-inner::before, +.x-keyboard-mode .x-grid-item-selected .x-grid-cell-inner::before, +.x-grid-item-selected .x-grid-cell-inner::before, +.x-grid-item-focused .x-grid-cell-inner::before, +[id^="pveResourceTree"] .x-grid-item-selected .x-grid-cell-inner::before, +[id^="pveResourceTree"] .x-grid-item-focused .x-grid-cell-inner::before { + content: none !important; + display: none !important; + border: none !important; +} + +.x-grid-empty { + background-color: var(--ctp-base) !important; + color: var(--ctp-subtext0) !important; +} + +/* Grid info (pve-info-grid) and RRD view */ +.pve-info-grid { + border-radius: 12px !important; +} + +.pve-rrdview, +.rrdview { + border-radius: 12px !important; +} + +.pve-summary-status, +.x-container .pve-status { + border-radius: var(--pm-radius-lg) !important; +} + +[id^="pveGuestStatusView-"][id$="-body"], +[id^="pmxNotesView-"] .x-panel-body { + border-radius: var(--pm-radius-lg) !important; +} + +.x-panel-default[id*="notes"], +.pve-notes-view { + border-radius: var(--pm-radius-lg) !important; +} + +/* Floating grid pickers (storage/ISO selectors) */ +.x-layer.x-grid .x-grid-view, +.x-panel.x-layer.x-grid .x-grid-view, +.x-panel.x-layer.x-grid, +.x-layer.x-panel.x-grid { + border-radius: var(--pm-radius-sm) !important; +} + +.x-layer.x-grid .x-grid-item-over, +.x-layer.x-grid .x-grid-item-selected, +.x-panel.x-layer.x-grid .x-grid-item-over, +.x-panel.x-layer.x-grid .x-grid-item-selected { + border-radius: var(--pm-radius-sm) !important; + outline: none !important; + box-shadow: none !important; +} + +.x-layer.x-grid .x-grid-item-over td, +.x-layer.x-grid .x-grid-item-selected td, +.x-layer.x-grid .x-grid-item-over .x-grid-cell, +.x-layer.x-grid .x-grid-item-selected .x-grid-cell, +.x-panel.x-layer.x-grid .x-grid-item-over td, +.x-panel.x-layer.x-grid .x-grid-item-selected td, +.x-panel.x-layer.x-grid .x-grid-item-over .x-grid-cell, +.x-panel.x-layer.x-grid .x-grid-item-selected .x-grid-cell { + border-radius: 0 !important; +} + +.x-layer.x-grid .x-grid-item-over td:first-child, +.x-layer.x-grid .x-grid-item-selected td:first-child, +.x-panel.x-layer.x-grid .x-grid-item-over td:first-child, +.x-panel.x-layer.x-grid .x-grid-item-selected td:first-child { + border-radius: var(--pm-radius-sm) 0 0 var(--pm-radius-sm) !important; +} + +.x-layer.x-grid .x-grid-item-over td:last-child, +.x-layer.x-grid .x-grid-item-selected td:last-child, +.x-panel.x-layer.x-grid .x-grid-item-over td:last-child, +.x-panel.x-layer.x-grid .x-grid-item-selected td:last-child { + border-radius: 0 var(--pm-radius-sm) var(--pm-radius-sm) 0 !important; +} + +/* ===================================================== + MENUS + ===================================================== */ +.x-menu, +.x-menu-default { + background-color: var(--ctp-crust) !important; + border: 1px solid var(--ctp-surface0) !important; + border-radius: var(--pm-radius-lg) !important; + box-shadow: 0 8px 24px rgba(35, 38, 52, 0.8) !important; + padding: 2px !important; + overflow: hidden !important; +} + +.x-menu-body-default { + background-color: transparent !important; + padding: 4px !important; +} + +.x-menu-header { + background-color: transparent !important; + color: var(--ctp-text) !important; +} + +/* Menu icon separator — hide */ +.x-menu-icon-separator-default { + display: none !important; +} + +/* Menu item layout (flexbox reordering) */ +.x-menu-item-default > .x-menu-item-link { + display: flex !important; + align-items: center !important; + flex-direction: row !important; + gap: 4px !important; + justify-content: flex-start !important; + flex-wrap: nowrap !important; + border-radius: var(--pm-radius-md) !important; + padding: 4px 8px !important; + line-height: 20px !important; + cursor: pointer !important; + outline: none !important; + box-shadow: none !important; + white-space: nowrap !important; + text-decoration: none !important; +} + +.x-menu-item-text-default { + color: var(--ctp-text) !important; + font-size: 13px !important; + order: 1 !important; + margin-left: 0 !important; + text-align: left !important; + line-height: 20px !important; + display: inline-flex !important; + align-items: center !important; + flex: 1 1 auto !important; + width: auto !important; + white-space: nowrap !important; +} + +.x-menu-item-icon-default { + color: var(--ctp-subtext0) !important; + order: -1 !important; + position: relative !important; + float: none !important; + margin-right: 8px !important; + margin-left: 0 !important; + left: auto !important; + top: auto !important; + width: 16px !important; + text-align: center !important; + display: inline-flex !important; + align-items: center !important; + justify-content: center !important; + height: 20px !important; + line-height: 20px !important; + vertical-align: middle !important; + flex: 0 0 16px !important; + align-self: center !important; +} + +.x-menu-item-arrow, +.x-menu-item-arrow-default { + order: 2 !important; + margin-left: auto !important; +} + +.x-menu-item-default.x-menu-item-separator { + background-color: var(--ctp-surface0) !important; + border: none !important; + height: 1px !important; + margin: 6px 4px !important; +} + +.x-menu-item-default.x-menu-item-focus, +.x-menu-item-default.x-menu-item-active, +.x-menu-item:hover { + background-color: var(--ctp-surface0) !important; + color: var(--ctp-text) !important; + border-radius: var(--pm-radius-md) !important; +} + +.x-menu-item-active .x-menu-item-text-default, +.x-menu-item-focus .x-menu-item-text-default { + color: var(--ctp-text) !important; +} + +.x-menu-item-active .x-menu-item-icon-default, +.x-menu-item-focus .x-menu-item-icon-default { + color: var(--ctp-lavender) !important; +} + +/* ===================================================== + PROGRESS BARS + ===================================================== */ + +/* Fix: Widget containers need overflow visible to not clip progress bars */ +.x-container[id^="pmxInfoWidget"], +.x-container.x-box-layout-ct { + overflow: visible !important; +} + +.x-progress, +.x-progress-default { + background-color: var(--ctp-surface0) !important; + border-radius: 5px !important; +} + +.x-progress-default .x-progress-bar-default { + background-color: var(--ctp-mauve) !important; + border-radius: 5px !important; + transition: width 0.4s ease !important; +} + +.x-progress-default .x-progress-text { + color: var(--ctp-text) !important; +} + +/* Text overlaid on the progress bar fill — use on-accent for contrast against Mauve/Yellow/Red fills */ +.x-progress-bar .x-progress-text { + color: var(--ctp-on-accent) !important; +} + +.x-progress.warning .x-progress-bar { + background-color: var(--ctp-yellow) !important; +} + +.x-progress.critical .x-progress-bar { + background-color: var(--ctp-red) !important; +} + +/* ===================================================== + TABS — Catppuccin underline style + Flat tabs with Mauve underline on active tab + ===================================================== */ +.x-tab-bar, +.x-tab-bar-default { + background-color: var(--ctp-base) !important; + border-radius: 0 !important; + border-bottom: 1px solid var(--ctp-surface1) !important; + padding-bottom: 0 !important; +} + +/* Overflow visible for the underline indicator */ +.x-tab-bar .x-box-inner, +.x-tab-bar .x-box-target, +.x-tab-bar-body, +.x-tab-bar-body-default { + overflow: visible !important; +} + +/* Base tab */ +.x-tab, +.x-tab-default, +.x-tab-default-top { + background-color: transparent !important; + border: none !important; + border-radius: var(--pm-radius-md) var(--pm-radius-md) 0 0 !important; + padding: 8px 16px 8px !important; + overflow: visible !important; + margin-bottom: 0 !important; + transition: color 0.15s ease !important; + outline: none !important; + box-shadow: none !important; +} + +/* Remove ::after from inactive tabs */ +.x-tab::after { + display: none !important; +} + +.x-tab-inner-default { + color: var(--ctp-subtext0) !important; + font-size: 13px !important; +} + +.x-tab-default.x-tab-over { + background-color: transparent !important; +} + +.x-tab-default.x-tab-over .x-tab-inner-default { + color: var(--ctp-text) !important; +} + +/* Active tab */ +.x-tab-default.x-tab.x-tab-active { + background-color: transparent !important; + border: none !important; + overflow: visible !important; + margin-bottom: 0 !important; + outline: none !important; + box-shadow: none !important; +} + +/* Mauve underline indicator on active tab */ +.x-tab-default.x-tab.x-tab-active::after { + content: '' !important; + display: block !important; + position: absolute !important; + bottom: 0 !important; + left: 0 !important; + right: 0 !important; + height: 2px !important; + background: var(--ctp-mauve) !important; + z-index: 10 !important; + border-radius: 2px 2px 0 0 !important; + pointer-events: none !important; +} + +.x-tab-active .x-tab-inner-default { + color: var(--ctp-text) !important; + font-weight: 600 !important; +} + +.x-tab-default.x-tab.x-tab-disabled { + background-color: transparent !important; + border: none !important; + color: var(--ctp-overlay0) !important; + margin-bottom: 0 !important; +} + +/* Focus states — no outline */ +.x-keyboard-mode .x-tab-default.x-tab-focus, +.x-keyboard-mode .x-tab-default.x-tab-focus.x-tab-active { + background-color: transparent !important; + border: none !important; + outline: none !important; + box-shadow: none !important; + margin-bottom: 0 !important; +} + +.x-keyboard-mode .x-tab-default.x-tab-focus.x-tab-active::after { + content: '' !important; + display: block !important; + position: absolute !important; + bottom: 0 !important; + left: 0 !important; + right: 0 !important; + height: 2px !important; + background: var(--ctp-mauve) !important; + z-index: 10 !important; + pointer-events: none !important; +} + +/* Kill ALL tab interaction outlines/shadows */ +.x-tab:focus, +.x-tab *:focus, +.x-tab-focus, +.x-tab-active.x-tab-focus, +.x-tab-inner-focus, +.x-tab-button-focus, +.x-tab-pressed, +.x-tab-active.x-tab-pressed, +.x-tab-over, +.x-tab:active, +.x-tab *:active { + outline: none !important; + box-shadow: none !important; +} + +.x-tabpanel-child { + border-radius: 0 0 var(--pm-radius-lg) var(--pm-radius-lg) !important; +} + +/* Tab hover/active corners */ +.x-tab-default.x-tab-over, +.x-tab-default.x-tab.x-tab-active { + border-radius: var(--pm-radius-md) var(--pm-radius-md) 0 0 !important; +} + +/* ===================================================== + TOOLTIPS + ===================================================== */ +.x-tip, +.x-tip-default { + background-color: var(--ctp-mantle) !important; + border: 1px solid var(--ctp-surface1) !important; + border-radius: var(--pm-radius-md) !important; + box-shadow: 0 4px 12px rgba(35, 38, 52, 0.5); +} + +.x-tip-body-default { + color: var(--ctp-text) !important; +} + +.x-tip-form-invalid { + background-color: var(--ctp-mantle) !important; + border-color: var(--ctp-red) !important; +} + +.x-tip-body-form-invalid { + color: var(--ctp-red) !important; +} + +/* ===================================================== + TREE NAVIGATION (Sidebar) + ===================================================== */ +.x-treelist-item { + background-color: var(--ctp-base) !important; + border-radius: var(--pm-radius-md) !important; +} + +/* Pseudo-element approach for hover/selected highlighting */ +.x-treelist-row { + border-radius: var(--pm-radius-md) !important; + background-color: transparent !important; + position: relative !important; + z-index: 0 !important; +} + +.x-treelist-row::before { + content: ""; + position: absolute; + top: 1px; + bottom: 1px; + left: 0; + right: 4px; + border-radius: var(--pm-radius-md); + background-color: transparent; + z-index: -1; + pointer-events: none; + transition: background-color 0.15s ease; +} + +/* Fix toolbox tree item text overlapping icons */ +.x-treelist-item-text { + margin-left: 28px !important; +} + +/* Toolbox tree items — bright text */ +.x-treelist-item-text, +.x-treelist-item-icon, +.x-treelist.x-treelist-pve-nav .x-treelist-item-text, +.x-treelist.x-treelist-pve-nav .x-treelist-item-icon { + color: var(--ctp-subtext1) !important; +} + +/* Hover state — apply to pseudo-element */ +.x-treelist-row-over { + background-color: transparent !important; +} + +.x-treelist-row-over::before { + background-color: var(--ctp-hover-overlay) !important; +} + +.x-treelist-row-over .x-treelist-item-icon, +.x-treelist-row-over .x-treelist-item-text { + background-color: transparent !important; + color: var(--ctp-text) !important; +} + +/* Selected/active item — Mauve highlight */ +.x-treelist-item-selected > .x-treelist-row { + background-color: transparent !important; +} + +.x-treelist-item-selected > .x-treelist-row::before, +.x-treelist-item-selected > .x-treelist-row:hover::before { + background-color: var(--ctp-mauve) !important; +} + +.x-treelist-item-selected .x-treelist-item-text, +.x-treelist-item-selected .x-treelist-item-icon, +.x-treelist.x-treelist-pve-nav .x-treelist-item-selected .x-treelist-item-text, +.x-treelist.x-treelist-pve-nav .x-treelist-item-selected .x-treelist-item-icon { + color: var(--ctp-on-accent) !important; +} + +.x-treelist-pve-nav { + background-color: var(--ctp-base) !important; + border-color: var(--ctp-surface1) !important; +} + +/* Tree navigation radius overrides */ +.x-treelist-item, +.x-treelist-item-tool { + border-radius: var(--pm-radius-sm) !important; +} + +.x-treelist-row, +.x-treelist-row:hover, +.x-treelist-row-over, +.x-treelist-item-selected > .x-treelist-row, +.x-treelist-item-selected > .x-treelist-row:hover, +.x-treelist-item-expanded > .x-treelist-row, +.x-treelist-item-expanded > .x-treelist-row-over, +.x-treelist-item-expandable > .x-treelist-row, +.x-treelist-item-expandable > .x-treelist-row-over { + border-radius: var(--pm-radius-sm) !important; +} + +.x-treelist-row::before { + border-radius: var(--pm-radius-sm) !important; +} + +.x-treelist-item-wrap, +.x-treelist-item-text, +.x-treelist-row, +.x-treelist-container, +.x-treelist-root-container, +.x-treelist, +.x-treelist-pve-nav { + border-radius: var(--pm-radius-sm) !important; +} + +/* Cursor pointer for interactive tree/grid items */ +.x-grid-cell, +.x-grid-cell-inner, +.x-tree-elbow-img, +.x-tree-icon, +.x-treelist-item, +.x-treelist-row, +.x-treelist-item-wrap, +.x-treelist-item-text, +.x-treelist-item-icon { + cursor: pointer !important; +} + +/* ===================================================== + WINDOWS / MODALS + ===================================================== */ +.x-window, +.x-window-default { + background-color: var(--ctp-crust) !important; + border: 1px solid var(--ctp-surface1) !important; + border-radius: var(--pm-radius-lg) !important; + box-shadow: 0 8px 24px rgba(35, 38, 52, 0.6) !important; + overflow: hidden !important; +} + +.x-window .x-window-header, +.x-window-header-default { + background-color: var(--ctp-mantle) !important; + border-color: transparent !important; + border-radius: var(--pm-radius-lg) var(--pm-radius-lg) 0 0 !important; +} + +.x-window-header-default .x-mask { + background-color: rgba(35, 38, 52, 0.7); +} + +.x-window .x-window-body, +.x-window-body-default { + background-color: var(--ctp-base) !important; + border-color: var(--ctp-surface1) !important; + color: var(--ctp-text) !important; + border-radius: 0 0 var(--pm-radius-lg) var(--pm-radius-lg) !important; +} + +.x-window-ghost { + background-color: var(--ctp-base) !important; +} + +.x-window-header-default .x-tool-img { + background-color: transparent; +} + +.x-message-box .x-window-body { + background-color: var(--ctp-mantle) !important; +} + +/* Respect ExtJS inline display:none on hidden dialog buttons */ +.x-message-box .x-btn.x-btn-default-small[style*="display: none"], +.x-message-box .x-btn.x-btn-default-small[style*="display:none"], +.x-window .x-toolbar-footer .x-btn[style*="display: none"], +.x-window .x-toolbar-footer .x-btn[style*="display:none"] { + display: none !important; +} + +/* Login dialog — clean inner panel borders */ +.x-window:has(#pveloginrealm) .x-panel-body { + border: none !important; + background: transparent !important; + width: auto !important; +} + +/* ===================================================== + CONSOLE / TERMINAL + ===================================================== */ +div.monitor { + border-color: var(--ctp-surface1); +} + +.install-mask { + background-color: var(--ctp-crust); + color: var(--ctp-subtext0); +} + +.x-window.install-mask { + box-shadow: rgba(35, 38, 52, 0.5) 0 4px 20px !important; +} + +/* ===================================================== + LEGEND / CHARTS + ===================================================== */ +.x-legend-container { + background-color: var(--ctp-base) !important; +} + +.x-legend-horizontal .x-legend-item { + background-color: var(--ctp-mantle) !important; + color: var(--ctp-text) !important; + border: 1px solid var(--ctp-surface0) !important; +} + +/* Chart/RRD panel backgrounds */ +div[id*="rrdchart"], +.pve-rrddatastore, +.pmx-panel-rrd { + background-color: var(--ctp-base) !important; +} + +.proxmox-rrd-panel canvas, +.proxmox-widget-toolkit canvas, +canvas.x-surface, +.x-surface canvas { + background-color: transparent !important; + opacity: 1 !important; +} + +.proxmox-rrd-panel, +.proxmox-rrd-chart { + background-color: var(--ctp-base) !important; +} + +/* Chart text/labels */ +.x-surface text, +svg text { + fill: var(--ctp-text) !important; +} + +/* ===================================================== + PROXMOX-SPECIFIC OVERRIDES + ===================================================== */ + +/* Logo inversion */ +img[id^="proxmoxlogo-"][id$="-img"], +img[id^="proxmoxLogoSvg-"][id$="-img"] { + filter: invert(1) hue-rotate(180deg); +} + +/* Invalid/warning/disabled rows */ +.proxmox-invalid-row { + background-color: rgba(243, 139, 168, 0.15) !important; +} + +.proxmox-warning-row { + background-color: rgba(250, 179, 135, 0.15) !important; +} + +.proxmox-disabled-row td { + color: var(--ctp-overlay0) !important; +} + +/* Hints */ +.pmx-hint { + background-color: rgba(250, 179, 135, 0.15) !important; + white-space: nowrap !important; +} + +.pmx-hint a { + color: var(--ctp-blue) !important; +} + +/* Status text colors — style guide: Information → Teal */ +.info-blue { + color: var(--ctp-teal) !important; +} + +.critical { + color: var(--ctp-red) !important; +} + +/* Links */ +a { + color: var(--ctp-blue) !important; +} + +/* Markdown content */ +.pmx-md code { + background-color: var(--ctp-mantle) !important; + color: var(--ctp-rosewater) !important; + border-radius: var(--pm-radius-sm) !important; +} + +.pmx-md pre code { + border-color: var(--ctp-surface1) !important; + background-color: var(--ctp-crust) !important; +} + +.pmx-md a { + color: var(--ctp-blue) !important; +} + +.pmx-md table { + border-color: var(--ctp-surface1) !important; +} + +.pmx-md th { + background-color: var(--ctp-mantle) !important; + border-color: var(--ctp-surface1) !important; +} + +.pmx-md td { + border-color: var(--ctp-surface1) !important; +} + +/* APT repos */ +.proxmox-apt-repos .x-grid-group-hd { + background-color: var(--ctp-base) !important; + border: none !important; +} + +.proxmox-apt-repos .x-grid-group-title { + color: var(--ctp-text) !important; +} + +/* Tags */ +.pve-edit-tag { + border-radius: var(--pm-radius-md) !important; +} + +.pve-edit-tag.editable span { + background-color: var(--ctp-mantle) !important; + color: var(--ctp-text) !important; + border-color: var(--ctp-surface1) !important; +} + +.x-tree-node-text .proxmox-tag-dark, +.x-tree-node-text .proxmox-tag-light, +.x-grid-cell-inner .proxmox-tag-dark, +.x-grid-cell-inner .proxmox-tag-light, +span.proxmox-tag-dark, +span.proxmox-tag-light { + border-radius: var(--pm-radius-md) !important; +} + +/* Checkmark button in tag edit — match toolbar button size */ +.x-btn.x-btn-default-small:has(.fa-check) { + min-height: 24px !important; + height: 24px !important; + padding: 3px 8px !important; + border-radius: var(--pm-radius-sm) !important; + background-color: var(--ctp-mauve) !important; + border: none !important; +} + +.x-btn.x-btn-default-small:has(.fa-check).x-btn-disabled { + background-color: transparent !important; + border: 1px solid var(--ctp-surface1) !important; + opacity: 0.5 !important; +} + +.x-btn.x-btn-default-small:has(.fa-check) .fa-check { + color: var(--ctp-on-accent) !important; +} + +.x-btn.x-btn-default-small:has(.fa-check).x-btn-disabled .fa-check { + color: var(--ctp-overlay1) !important; +} + +.x-btn.x-btn-default-small:has(.fa-check):not(.x-btn-disabled):hover { + background-color: #d5aee9 !important; +} + +.x-btn.x-btn-default-small:has(.fa-check) .x-btn-inner { + display: none !important; +} + +/* Date picker */ +.x-datepicker, +.x-datepicker-column-header, +.x-monthpicker { + background-color: var(--ctp-base) !important; + color: var(--ctp-text) !important; + border-color: transparent !important; +} + +.x-datepicker-header, +.x-datepicker-footer, +.x-monthpicker-buttons { + background-color: var(--ctp-mantle) !important; +} + +.x-datepicker-date, +.x-monthpicker-item-inner { + color: var(--ctp-text) !important; +} + +.x-datepicker-selected div.x-datepicker-date, +.x-monthpicker-item a.x-monthpicker-selected, +a.x-monthpicker-item-inner:hover, +div.x-datepicker-date:hover { + background-color: var(--ctp-hover-overlay) !important; + color: var(--ctp-text) !important; +} + +.x-datepicker-today .x-datepicker-date { + border-color: var(--ctp-mauve) !important; +} + +.x-datepicker-disabled .x-datepicker-date { + color: var(--ctp-overlay0) !important; +} + +.x-datepicker-prev-day .x-datepicker-date, +.x-datepicker-next-day .x-datepicker-date { + color: var(--ctp-overlay0) !important; +} + +/* Usage bars */ +.usage-wrapper, +.usage { + border-radius: 2px !important; +} + +.usage { + background-color: var(--ctp-overlay2) !important; +} + +/* ===================================================== + SCROLLBARS + ===================================================== */ +::-webkit-scrollbar { + width: 8px; + height: 8px; +} + +::-webkit-scrollbar-track { + background: var(--ctp-base); + border-radius: var(--pm-radius-sm); +} + +::-webkit-scrollbar-thumb { + background: var(--ctp-surface2); + border-radius: var(--pm-radius-sm); + border: 1px solid transparent; + background-clip: padding-box; + transition: background 0.15s ease; +} + +::-webkit-scrollbar-thumb:hover { + background: var(--ctp-overlay0); +} + +::-webkit-scrollbar-corner { + background: var(--ctp-base); +} + +/* Firefox scrollbar */ +* { + scrollbar-width: thin; + scrollbar-color: var(--ctp-surface2) var(--ctp-base); +} + +/* ===================================================== + SELECTION HIGHLIGHT + ===================================================== */ +::selection { + background-color: rgba(148, 156, 187, 0.3); + color: var(--ctp-text); +} + +/* ===================================================== + TRANSITIONS (smooth interactions) + ===================================================== */ + +/* Grid row transitions */ +.x-grid-item { + transition: background-color 0.15s ease !important; +} + +/* Tree pseudo-element transitions */ +.x-treelist-row::before { + transition: background-color 0.15s ease !important; +} + +/* Menu item transitions */ +.x-menu-item-default > .x-menu-item-link { + transition: background-color 0.12s ease !important; +} + +/* Boundlist item transitions */ +.x-boundlist-item { + transition: background-color 0.12s ease !important; +} + +/* Tab transitions */ +.x-tab { + transition: color 0.15s ease !important; +} + +/* Splitter transition */ +.x-splitter { + transition: background-color 0.15s ease !important; +} + +/* Tooltip transition */ +.x-tip { + transition: opacity 0.15s ease !important; +} + +/* Progress bar width transition */ +.x-progress-bar { + transition: width 0.4s ease !important; +} + +/* Scrollbar thumb transition */ +::-webkit-scrollbar-thumb { + transition: background 0.15s ease !important; +} + +/* Window close tool transition */ +.x-tool-img { + transition: filter 0.15s ease !important; +} + +/* ===================================================== + TOOL ICONS - FontAwesome Replacements + (Ported from UniFi v5.86) + Replace sprite-based ExtJS tool icons with crisp + FontAwesome icons for better consistency and clarity + ===================================================== */ + +/* Base styling for all tool icons - remove sprite backgrounds */ +.x-tool-tool-el.x-tool-minus, +.x-tool-img.x-tool-minus, +.x-tool-tool-el.x-tool-collapse-right, +.x-tool-img.x-tool-collapse-right, +.x-tool-tool-el.x-tool-collapse-left, +.x-tool-img.x-tool-collapse-left, +.x-tool-tool-el.x-tool-expand-right, +.x-tool-img.x-tool-expand-right, +.x-tool-tool-el.x-tool-expand-left, +.x-tool-img.x-tool-expand-left, +.x-tool-tool-el.x-tool-maximize, +.x-tool-img.x-tool-maximize, +.x-tool-tool-el.x-tool-restore, +.x-tool-img.x-tool-restore, +.x-tool-tool-el.x-tool-gear, +.x-tool-img.x-tool-gear, +.x-tool-tool-el.x-tool-refresh, +.x-tool-img.x-tool-refresh, +.x-tool-tool-el.x-tool-close, +.x-tool-img.x-tool-close { + background-image: none !important; + font-family: "FontAwesome" !important; + font-size: 14px !important; + line-height: 16px !important; + text-align: center !important; + color: var(--pm-text-dim) !important; + transition: color 0.15s ease !important; + filter: none !important; + width: 16px !important; + height: 16px !important; + display: flex !important; + align-items: center !important; + justify-content: center !important; +} + +/* Close button - slightly larger */ +.x-tool-tool-el.x-tool-close, +.x-tool-img.x-tool-close { + font-size: 20px !important; +} + +/* Individual glyph assignments */ +.x-tool-tool-el.x-tool-minus::before, +.x-tool-img.x-tool-minus::before { + content: "\f010" !important; /* fa-search-minus (zoom out) */ +} + +.x-tool-tool-el.x-tool-collapse-right::before, +.x-tool-img.x-tool-collapse-right::before { + content: "\f054" !important; /* fa-chevron-right */ +} + +.x-tool-tool-el.x-tool-expand-left::before, +.x-tool-img.x-tool-expand-left::before { + content: "\f053" !important; /* fa-chevron-left */ +} + +.x-tool-tool-el.x-tool-collapse-left::before, +.x-tool-img.x-tool-collapse-left::before { + content: "\f053" !important; /* fa-chevron-left */ +} + +.x-tool-tool-el.x-tool-expand-right::before, +.x-tool-img.x-tool-expand-right::before { + content: "\f054" !important; /* fa-chevron-right */ +} + +.x-tool-tool-el.x-tool-maximize::before, +.x-tool-img.x-tool-maximize::before { + content: "\f065" !important; /* fa-expand */ +} + +.x-tool-tool-el.x-tool-restore::before, +.x-tool-img.x-tool-restore::before { + content: "\f066" !important; /* fa-compress */ +} + +.x-tool-tool-el.x-tool-gear::before, +.x-tool-img.x-tool-gear::before { + content: "\f013" !important; /* fa-cog */ +} + +.x-tool-tool-el.x-tool-refresh::before, +.x-tool-img.x-tool-refresh::before { + content: "\f021" !important; /* fa-refresh */ +} + +.x-tool-tool-el.x-tool-close::before, +.x-tool-img.x-tool-close::before { + content: "\f00d" !important; /* fa-times */ +} + +/* Hover state - all tool icons */ +.x-tool:hover .x-tool-tool-el.x-tool-minus, +.x-tool:hover .x-tool-img.x-tool-minus, +.x-tool:hover .x-tool-tool-el.x-tool-collapse-right, +.x-tool:hover .x-tool-img.x-tool-collapse-right, +.x-tool:hover .x-tool-tool-el.x-tool-collapse-left, +.x-tool:hover .x-tool-img.x-tool-collapse-left, +.x-tool:hover .x-tool-tool-el.x-tool-expand-right, +.x-tool:hover .x-tool-img.x-tool-expand-right, +.x-tool:hover .x-tool-tool-el.x-tool-expand-left, +.x-tool:hover .x-tool-img.x-tool-expand-left, +.x-tool:hover .x-tool-tool-el.x-tool-maximize, +.x-tool:hover .x-tool-img.x-tool-maximize, +.x-tool:hover .x-tool-tool-el.x-tool-restore, +.x-tool:hover .x-tool-img.x-tool-restore, +.x-tool:hover .x-tool-tool-el.x-tool-gear, +.x-tool:hover .x-tool-img.x-tool-gear, +.x-tool:hover .x-tool-tool-el.x-tool-refresh, +.x-tool:hover .x-tool-img.x-tool-refresh, +.x-tool:hover .x-tool-tool-el.x-tool-close, +.x-tool:hover .x-tool-img.x-tool-close { + color: var(--pm-text) !important; +} + +/* Disabled state */ +.x-tool-disabled .x-tool-tool-el, +.x-tool-disabled .x-tool-img { + opacity: 0.4 !important; + cursor: default !important; +} + +/* Inline FontAwesome tools (PVE-injected) */ +.x-tool-tool-el[style*="font-family:FontAwesome"], +.x-tool-tool-el[style*="font-family: FontAwesome"] { + color: var(--pm-text-dim) !important; + font-size: 14px !important; + line-height: 16px !important; + display: flex !important; + align-items: center !important; + justify-content: center !important; + width: 16px !important; + height: 16px !important; + transition: color 0.15s ease !important; + background-image: none !important; + background-color: transparent !important; +} + +.x-tool:not(.x-tool-disabled) .x-tool-tool-el[style*="font-family:FontAwesome"], +.x-tool:not(.x-tool-disabled) .x-tool-tool-el[style*="font-family: FontAwesome"] { + cursor: pointer !important; +} + +.x-tool.x-tool-disabled .x-tool-tool-el[style*="font-family:FontAwesome"], +.x-tool.x-tool-disabled .x-tool-tool-el[style*="font-family: FontAwesome"] { + cursor: default !important; + opacity: 0.4 !important; +} + +.x-tool .x-mask { + background-color: transparent !important; + backdrop-filter: none !important; + pointer-events: none !important; +} + +.x-tool:not(.x-tool-disabled):hover .x-tool-tool-el[style*="font-family:FontAwesome"], +.x-tool:not(.x-tool-disabled):hover .x-tool-tool-el[style*="font-family: FontAwesome"] { + color: var(--pm-text) !important; +} diff --git a/themes/theme-catppuccin-latte.css b/themes/theme-catppuccin-latte.css new file mode 100644 index 0000000..7d102b9 --- /dev/null +++ b/themes/theme-catppuccin-latte.css @@ -0,0 +1,2386 @@ +/*!Catppuccin Latte*/ +/* + * ProxMorph Theme: Catppuccin Latte + * Soothing pastel theme for Proxmox VE — the official light flavor of Catppuccin + * Version: 1.0.1 + * Author: ProxMorph / Catppuccin Community Palette + * + * v1.0.1: Fixed dark-mode filter inversions carried over from Mocha generation: + * Removed filter:invert from loading indicators, folder icons, + * image-based icons, hardware icons, counter-invert cells, and + * Proxmox logo. All now use filter:none for light background. + * v1.0.0: Initial release - Tier 2 production (generated from Mocha v1.3.0) + * Catppuccin Mocha palette, border-radius architecture (ported from UniFi), + * custom checkboxes/radios, full grid styling, progress bar states, + * tags, markdown, date picker, usage bars, Firefox scrollbar. + * + * Catppuccin Latte Color Palette: + * + * ACCENT COLORS: + * - Rosewater: #dc8a78 - Flamingo: #dd7878 + * - Pink: #ea76cb - Mauve: #8839ef (Primary Accent) + * - Red: #d20f39 - Maroon: #e64553 + * - Peach: #fe640b - Yellow: #df8e1d + * - Green: #40a02b - Teal: #179299 + * - Sky: #04a5e5 - Sapphire: #209fb5 + * - Blue: #1e66f5 - Lavender: #7287fd + * + * NEUTRALS: + * - Text: #4c4f69 - Subtext 1: #5c5f77 + * - Subtext 0: #6c6f85 - Overlay 2: #7c7f93 + * - Overlay 1: #8c8fa1 - Overlay 0: #9ca0b0 + * - Surface 2: #acb0be - Surface 1: #bcc0cc + * - Surface 0: #ccd0da - Base: #eff1f5 + * - Mantle: #e6e9ef - Crust: #dce0e8 + */ + +/* ===================================================== + CSS VARIABLES + ===================================================== */ +:root { + /* Catppuccin Mocha Tokens */ + --ctp-rosewater: #dc8a78; + --ctp-flamingo: #dd7878; + --ctp-pink: #ea76cb; + --ctp-mauve: #8839ef; + --ctp-red: #d20f39; + --ctp-maroon: #e64553; + --ctp-peach: #fe640b; + --ctp-yellow: #df8e1d; + --ctp-green: #40a02b; + --ctp-teal: #179299; + --ctp-sky: #04a5e5; + --ctp-sapphire: #209fb5; + --ctp-blue: #1e66f5; + --ctp-lavender: #7287fd; + + --ctp-text: #4c4f69; + --ctp-subtext1: #5c5f77; + --ctp-subtext0: #6c6f85; + --ctp-overlay2: #7c7f93; + --ctp-overlay1: #8c8fa1; + --ctp-overlay0: #9ca0b0; + --ctp-surface2: #acb0be; + --ctp-surface1: #bcc0cc; + --ctp-surface0: #ccd0da; + --ctp-base: #eff1f5; + --ctp-mantle: #e6e9ef; + --ctp-crust: #dce0e8; + + /* ProxMorph Semantic Variables */ + --pm-accent: var(--ctp-mauve); + --pm-bg-base: var(--ctp-base); + --pm-bg-surface: var(--ctp-surface0); + --pm-bg-elevated: var(--ctp-surface1); + --pm-text: var(--ctp-text); + --pm-text-dim: var(--ctp-subtext1); + --pm-success: var(--ctp-green); + --pm-warning: var(--ctp-yellow); + --pm-error: var(--ctp-red); + --pm-border: var(--ctp-surface1); + --pm-radius-sm: 4px; + --pm-radius-md: 6px; + --pm-radius-lg: 8px; + + /* Proxmox Widget Toolkit Mappings (REQUIRED) */ + --pwt-panel-background: var(--ctp-base); + --pwt-text-color: var(--ctp-text); + --pwt-gauge-default: var(--ctp-mauve); + --pwt-gauge-back: var(--ctp-surface1); + --pwt-gauge-warn: var(--ctp-yellow); + --pwt-gauge-crit: var(--ctp-red); + --pwt-chart-primary: var(--ctp-mauve); + --pwt-chart-grid-stroke: var(--ctp-surface1); + + /* On Accent text — white for Latte vivid accents (mauve/red contrast); Base is near-white, invisible on light bg */ + --ctp-on-accent: #ffffff; + + /* Hover overlay — Overlay2@12% (neutral, per Catppuccin port conventions) */ + --ctp-hover-overlay: rgba(124, 127, 147, 0.12); + /* Selection overlay — Overlay2@25% (style guide: Selection Background → Overlay2 20-30%) */ + --ctp-select-overlay: rgba(124, 127, 147, 0.25); + /* Accent muted (for focus rings) */ + --ctp-accent-muted: rgba(136, 57, 239, 0.4); + --ctp-accent-subtle: rgba(136, 57, 239, 0.15); + + color-scheme: light; +} + +/* ===================================================== + GLOBAL BORDER-RADIUS ARCHITECTURE + (Ported from UniFi theme — reset everything, selectively re-apply) + ===================================================== */ +.x-border-box, +.x-border-box * { + border-radius: var(--pm-radius-lg); +} + +/* Remove rounded corners from grids/tables/lists */ +.x-grid, +.x-grid *, +.x-grid-header-ct, +.x-grid-header-ct *, +.x-grid-view, +.x-grid-view *, +.x-column-header, +.x-column-header *, +.x-grid-item, +.x-grid-cell, +.x-grid-cell-inner, +.x-grid-row, +table, +table *, +tr, +td, +th, +.x-legend, +.x-legend *, +.x-legend-container, +.x-legend-container *, +.x-legend-item, +.x-legend-horizontal .x-legend-item, +.x-legend-vertical .x-legend-item, +.x-legend-horizontal .x-legend-item:first-child, +.x-legend-horizontal .x-legend-item:last-child, +.x-legend-vertical .x-legend-item:first-child, +.x-legend-vertical .x-legend-item:last-child, +.x-tool, +.x-tool-tool-el, +.x-tool-default, +.x-tool-img { + border-radius: 0 !important; +} + +/* Form elements - exclude from global radius */ +.x-form-item, +.x-form-item-default, +.x-form-item-body, +.x-form-item-body-default, +.x-form-text-field-body, +.x-form-text-field-body-default, +.x-form-fieldcontainer, +.x-field, +.x-field-default, +.x-form-type-text { + border-radius: 0 !important; +} + +/* Reset layout containers that clip elements with overflow:hidden + radius */ +.x-box-layout-ct, +.x-panel-bodyWrap, +.x-panel-bodyWrap-default, +.x-autocontainer-innerCt, +.x-autocontainer-outerCt, +.x-panel.x-tabpanel-child, +.x-panel.x-box-item, +.x-box-inner, +.x-box-target, +.x-container, +.x-container-default, +.x-window .x-panel-body, +.x-window .x-window-body, +.x-window .x-window-bodyWrap { + border-radius: 0 !important; +} + +/* Reset everything inside windows to 0 — then re-apply specific radii */ +.x-window *, +.x-window .x-autocontainer-innerCt, +.x-window .x-autocontainer-outerCt, +.x-window .x-form-layout-wrap, +.x-window .x-form-layout-auto-label, +.x-window .x-form-layout-colgroup, +.x-window .x-form-layout-column, +.x-window .x-field, +.x-window .x-form-item, +.x-window .x-form-item-body { + border-radius: 0 !important; +} + +/* Chart canvas — no radius on data area */ +.x-chart-grid, +.x-chart-axis, +canvas.x-surface, +.x-chart canvas, +canvas.x-surface-canvas, +.x-surface-canvas, +.x-draw-component canvas, +.proxmox-rrd-chart canvas, +svg.x-surface, +.x-draw-container, +.x-surface { + border-radius: 0 !important; +} + +/* Legend color marker (dot) — keep circular */ +.x-legend-item-marker { + border-radius: 50% !important; +} + +/* ===================================================== + RE-APPLY BORDER RADII (selective) + ===================================================== */ + +/* Windows */ +.x-window, +.x-window-default { + border-radius: var(--pm-radius-lg) !important; +} + +.x-window-header, +.x-window-header-default { + border-radius: var(--pm-radius-lg) var(--pm-radius-lg) 0 0 !important; +} + +.x-window .x-window-body, +.x-window-body-default { + border-radius: 0 !important; +} + +/* Buttons inside windows */ +.x-window .x-btn { + border-radius: var(--pm-radius-md) !important; +} + +/* Checkboxes inside windows */ +.x-window .x-form-checkbox { + border-radius: 3px !important; +} + +/* Form inputs inside windows */ +.x-window .x-form-trigger-wrap, +.x-window .x-form-trigger-wrap-default { + border-radius: var(--pm-radius-sm) !important; +} + +.x-window .x-form-text-wrap, +.x-window .x-form-text { + border-radius: var(--pm-radius-sm) 0 0 var(--pm-radius-sm) !important; +} + +.x-window .x-form-arrow-trigger { + border-radius: 0 var(--pm-radius-sm) var(--pm-radius-sm) 0 !important; +} + +/* Form trigger/text wrap — reset and re-apply */ +.x-form-trigger-wrap, +.x-form-trigger-wrap *, +.x-form-text-wrap, +.x-form-text-wrap *, +.x-form-text, +.x-form-trigger { + border-radius: 0 !important; +} + +.x-form-trigger-wrap, +.x-form-trigger-wrap-default { + border-radius: var(--pm-radius-sm) !important; + overflow: hidden !important; +} + +.x-form-text-wrap, +.x-form-text-wrap-default { + border-radius: var(--pm-radius-sm) 0 0 var(--pm-radius-sm) !important; +} + +.x-form-text, +.x-form-text-default { + border-radius: var(--pm-radius-sm) 0 0 var(--pm-radius-sm) !important; +} + +.x-form-trigger, +.x-form-trigger-default, +.x-form-arrow-trigger, +.x-form-arrow-trigger-default { + border-radius: 0 var(--pm-radius-sm) var(--pm-radius-sm) 0 !important; +} + +/* Dialog form content padding — vertical only (horizontal causes ExtJS overflow) */ +.x-window .x-tabpanel-child .x-autocontainer-innerCt { + padding: 12px 0 !important; +} + +/* Allow column panel bodies to show overflowed form content */ +.x-window .x-panel-body:not(.x-scroller) { + overflow: visible !important; +} + +/* Side padding on column panel bodies inside windows */ +.x-window .x-panel.x-box-item .x-panel-body { + padding: 0 4px !important; +} + +/* Constrain autocontainer width inside windows */ +.x-window .x-autocontainer-outerCt { + max-width: 100% !important; +} + +/* Fix window header/body width consistency */ +.x-window > .x-window-header, +.x-window > .x-window-body, +.x-window > .x-window-bodyWrap, +.x-window-bodyWrap > .x-window-body { + width: 100% !important; +} + +.x-window-header > .x-box-inner, +.x-window-header > .x-box-inner > .x-box-target { + width: 100% !important; +} + +.x-window-header-title { + width: auto !important; + flex: 1 !important; + max-width: calc(100% - 30px) !important; +} + +/* Boundlists */ +.x-boundlist { + border-radius: var(--pm-radius-md) !important; + overflow: hidden !important; +} + +/* ===================================================== + BASE / BODY + ===================================================== */ +.x-body, +.x-viewport > .x-body, +body.x-border-layout-ct, +div.x-border-layout-ct { + background-color: var(--ctp-base) !important; + color: var(--ctp-text) !important; +} + +/* ===================================================== + MASKS & OVERLAYS + ===================================================== */ +.x-mask { + background-color: rgba(76, 79, 105, 0.6) !important; + backdrop-filter: blur(4px); +} + +.x-mask-msg { + background-color: var(--ctp-mantle) !important; + border: 1px solid var(--ctp-surface1) !important; + border-radius: var(--pm-radius-lg) !important; +} + +.x-mask-msg-text { + color: var(--ctp-subtext0) !important; + filter: none !important; +} + +.x-css-shadow { + box-shadow: 0 8px 24px rgba(76, 79, 105, 0.6) !important; +} + +/* Loading indicators */ +.x-grid-row-loading, +.x-treelist-item-loading .x-treelist-item-icon, +.x-grid-tree-loading .x-tree-icon { + filter: none; +} + +/* ===================================================== + ICONS — Proxmox default colors for dark mode + ===================================================== */ + +/* General icon colors — neutral gray for dark backgrounds */ +.x-tree-icon-custom, +.x-grid-icon-custom, +.fa-tags::before, +.fa-file-o::before, +.fa-building::before, +.x-action-col-icon::before, +.fa-shield::before, +.fa-file-text-o::before, +.fa-clock-o::before, +.x-tab-icon-el-default, +.pve-icon-verify-lettering::after, +.x-tree-icon-leaf:not(.x-tree-icon-custom)::before, +.x-tree-icon-parent:not(.x-tree-icon-custom)::before, +.x-tree-icon-parent-expanded:not(.x-tree-icon-custom)::before, +.x-grid-filters-filtered-column .x-column-header-text::after { + color: var(--ctp-overlay2) !important; +} + +/* Folder icons — no invert needed for light theme */ +.x-tree-icon-parent:not(.x-tree-icon-custom)::before, +.x-tree-icon-parent-expanded:not(.x-tree-icon-custom)::before { + filter: none; +} + +/* Various image-based icons — no invert needed for light theme */ +.fa-ceph::before, +.fa-sdn::before, +.fa-network-wired::before, +.pve-itype-treelist-item-icon-cdrom, +.fa-chevron-right::before, +.x-grid-row-console, +.x-box-scroller-toolbar-default.x-box-scroller, +.x-tree-elbow-img, +.pve-itype-icon-qemu, +.x-tree-node-computer, +.x-grid-tree-node-expanded .x-tree-node-computer, +.pbs-icon-tape, +.pbs-icon-tape-drive, +.x-tree-icon-leaf:not(.x-tree-icon-custom), +.x-tree-icon-parent:not(.x-tree-icon-custom), +.x-tree-icon-parent-expanded:not(.x-tree-icon-custom) { + filter: none; +} + +/* Hardware icons */ +.pve-itype-icon-cpu, +.pve-itype-icon-cdrom, +.pve-itype-icon-memory, +.pve-itype-icon-pci, +.pve-itype-icon-serial, +.pve-itype-icon-die, +.pmx-itype-icon-processor, +.pmx-itype-icon-memory, +.pve-itype-icon-storage, +.x-tree-node-harddisk, +.x-grid-tree-node-expanded .x-tree-node-harddisk { + filter: none; +} + +/* Hardware icons — counter-invert for non-SVG icon cells */ +td.pve-itype-icon-storage .x-grid-cell-inner, +td.x-tree-node-harddisk .x-grid-cell-inner { + filter: none !important; +} + +/* Hardware icons — hide inverted borders for non-SVG icon cells */ +td.pve-itype-icon-storage, +td.x-tree-node-harddisk { + border-color: transparent !important; +} + +/* Hardware grid icons — mask-image renders SVG icons in theme text color + Replaces filter:invert approach for pve-itype-icon-* and pmx-itype-icon-* grid cells */ +td.pve-itype-icon-cpu, +td.pve-itype-icon-cdrom, +td.pve-itype-icon-memory, +td.pve-itype-icon-pci, +td.pve-itype-icon-serial, +td.pve-itype-icon-die, +td.pmx-itype-icon-processor, +td.pmx-itype-icon-memory { + filter: none !important; + background-image: none !important; + padding-left: 0 !important; + border-color: transparent !important; +} + +td.pve-itype-icon-cpu .x-grid-cell-inner, +td.pve-itype-icon-cdrom .x-grid-cell-inner, +td.pve-itype-icon-memory .x-grid-cell-inner, +td.pve-itype-icon-pci .x-grid-cell-inner, +td.pve-itype-icon-serial .x-grid-cell-inner, +td.pve-itype-icon-die .x-grid-cell-inner, +td.pmx-itype-icon-processor .x-grid-cell-inner, +td.pmx-itype-icon-memory .x-grid-cell-inner { + padding-left: 3px !important; +} + +td.pve-itype-icon-cpu .x-grid-cell-inner::before, +td.pve-itype-icon-cdrom .x-grid-cell-inner::before, +td.pve-itype-icon-memory .x-grid-cell-inner::before, +td.pve-itype-icon-pci .x-grid-cell-inner::before, +td.pve-itype-icon-serial .x-grid-cell-inner::before, +td.pve-itype-icon-die .x-grid-cell-inner::before, +td.pmx-itype-icon-processor .x-grid-cell-inner::before, +td.pmx-itype-icon-memory .x-grid-cell-inner::before { + content: '' !important; + display: inline-block !important; + width: 18px !important; + height: 14px !important; + vertical-align: middle !important; + margin-right: 10px !important; + background-color: currentColor !important; + -webkit-mask-size: contain !important; + mask-size: contain !important; + -webkit-mask-repeat: no-repeat !important; + mask-repeat: no-repeat !important; + -webkit-mask-position: center !important; + mask-position: center !important; +} + +td.pve-itype-icon-cpu .x-grid-cell-inner::before { + -webkit-mask-image: url('/pve2/images/icon-cpu.svg') !important; + mask-image: url('/pve2/images/icon-cpu.svg') !important; +} + +td.pve-itype-icon-memory .x-grid-cell-inner::before { + -webkit-mask-image: url('/pve2/images/icon-memory.svg') !important; + mask-image: url('/pve2/images/icon-memory.svg') !important; +} + +td.pve-itype-icon-cdrom .x-grid-cell-inner::before { + -webkit-mask-image: url('/pve2/images/icon-cd-drive.svg') !important; + mask-image: url('/pve2/images/icon-cd-drive.svg') !important; +} + +td.pve-itype-icon-pci .x-grid-cell-inner::before { + -webkit-mask-image: url('/pve2/images/icon-pci.svg') !important; + mask-image: url('/pve2/images/icon-pci.svg') !important; +} + +td.pve-itype-icon-serial .x-grid-cell-inner::before { + -webkit-mask-image: url('/pve2/images/icon-serial.svg') !important; + mask-image: url('/pve2/images/icon-serial.svg') !important; +} + +td.pve-itype-icon-die .x-grid-cell-inner::before { + -webkit-mask-image: url('/pve2/images/icon-die.svg') !important; + mask-image: url('/pve2/images/icon-die.svg') !important; +} + +td.pmx-itype-icon-processor .x-grid-cell-inner::before { + -webkit-mask-image: url('../images/icon-cpu.svg') !important; + mask-image: url('../images/icon-cpu.svg') !important; +} + +td.pmx-itype-icon-memory .x-grid-cell-inner::before { + -webkit-mask-image: url('../images/icon-ram.svg') !important; + mask-image: url('../images/icon-ram.svg') !important; +} + + +/* Icon overlays — default */ +.x-tree-icon-custom::after, +.x-grid-icon-custom::after { + color: var(--ctp-overlay2) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* RUNNING VMs/CTs — Catppuccin Green */ +.x-tree-icon-custom.running::after, +.x-grid-icon-custom.running::after, +.x-treelist-item-icon.running::after { + color: var(--ctp-green) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* ONLINE state — Green */ +.x-tree-icon-custom.online::after, +.x-grid-icon-custom.online::after { + color: var(--ctp-green) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* Stopped/offline — Overlay1 (muted gray) */ +.x-tree-icon-custom.stopped, +.x-tree-icon-custom.offline, +.x-grid-icon-custom.stopped, +.x-grid-icon-custom.offline { + color: var(--ctp-overlay1) !important; +} + +/* Unknown state — Overlay1 */ +.x-tree-icon-custom.unknown::after, +.x-grid-icon-custom.unknown::after { + color: var(--ctp-overlay1) !important; +} + +/* ERROR states — Catppuccin Red */ +.x-tree-icon-custom.error::after, +.x-tree-icon-custom.offline::after, +.x-tree-icon-custom.ha-error::after, +.x-grid-icon-custom.error::after, +.x-grid-icon-custom.offline::after, +.x-grid-icon-custom.ha-error::after { + color: var(--ctp-red) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* PAUSED/SUSPENDED — Catppuccin Peach */ +.x-tree-icon-custom.paused::after, +.x-tree-icon-custom.suspended::after, +.x-tree-icon-custom.lock-suspending::after, +.x-grid-icon-custom.paused::after, +.x-grid-icon-custom.suspended::after, +.x-grid-icon-custom.lock-suspending::after { + color: var(--ctp-peach) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* PENDING/WARNING states — Catppuccin Yellow */ +.x-tree-icon-custom.pending::after, +.x-tree-icon-custom.io-error::after, +.x-tree-icon-custom.internal-error::after, +.x-tree-icon-custom.guest-panicked::after, +.x-grid-icon-custom.pending::after, +.x-grid-icon-custom.io-error::after, +.x-grid-icon-custom.internal-error::after, +.x-grid-icon-custom.guest-panicked::after { + color: var(--ctp-yellow) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* HA MAINTENANCE — Catppuccin Sky */ +.x-tree-icon-custom.ha-maintenance::after, +.x-grid-icon-custom.ha-maintenance::after { + color: var(--ctp-sky) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* Locked icons */ +.x-tree-icon-custom.locked::after, +.x-tree-icon-custom.lock-backup::after, +.x-tree-icon-custom.lock-migrate::after, +.x-tree-icon-custom.lock-suspended::after, +.x-grid-icon-custom.locked::after, +.x-grid-icon-custom.lock-backup::after, +.x-grid-icon-custom.lock-migrate::after, +.x-grid-icon-custom.lock-suspended::after { + color: var(--ctp-overlay2) !important; +} + +/* LXC/QEMU type indicators */ +.x-tree-icon-custom.lxc::after, +.x-tree-icon-custom.qemu::after, +.x-grid-icon-custom.lxc::after, +.x-grid-icon-custom.qemu::after { + background-color: transparent; + color: var(--ctp-overlay1) !important; +} + +.x-treelist-item-icon.lxc::after, +.x-treelist-item-icon.qemu::after { + background-color: transparent; + color: var(--ctp-overlay1) !important; +} + +/* Tree expander arrows */ +.x-tree-arrows .x-tree-expander { + filter: brightness(200%); +} + +/* Cancel sprite-inversion on custom controls (checkboxes/radios handled via CSS) */ +.x-form-checkbox-default, +.x-form-radio-default, +.x-column-header-checkbox .x-column-header-checkbox::after, +.x-grid-checkcolumn::after, +.x-menu-item-checked .x-menu-item-icon-default.x-menu-item-checkbox, +.x-menu-item-unchecked .x-menu-item-icon-default.x-menu-item-checkbox { + filter: none !important; +} + +/* ===================================================== + PANELS & HEADERS + ===================================================== */ +.x-panel, +.x-panel-default { + border-radius: var(--pm-radius-lg) !important; + padding: 0 !important; +} + +/* Column panels — native stacked layout (Issue #23 fix) */ +.x-panel.x-column { + padding: 5px !important; + margin: 0 !important; + max-width: none !important; + box-sizing: border-box !important; +} + +/* Column panel card styling — borders for summary + chart panels */ +.x-panel.x-panel-default.x-column { + border: 1px solid var(--ctp-surface1) !important; + border-radius: var(--pm-radius-lg) !important; + overflow: hidden !important; +} + +/* Guest status + Notes panel borders */ +[id^="pveGuestStatusView-"].x-panel, +[id^="pveLxcStatusView-"].x-panel, +[id^="pveQemuStatusView-"].x-panel, +[id^="pmxNotesView-"].x-panel { + border: 1px solid var(--ctp-surface1) !important; + border-radius: var(--pm-radius-lg) !important; +} + +.x-panel-body, +.x-panel-body-default { + background-color: var(--ctp-base) !important; + color: var(--ctp-text) !important; + border: none !important; +} + +/* Panel headers — bottom border only */ +.x-panel-header, +.x-panel-header-default { + background-color: var(--ctp-mantle) !important; + border: none !important; + border-bottom: 1px solid var(--ctp-surface1) !important; + border-radius: var(--pm-radius-lg) var(--pm-radius-lg) 0 0 !important; + margin: 0 !important; + padding: 8px 12px !important; + width: 100% !important; + box-sizing: border-box !important; + overflow: visible !important; +} + +/* Title text — prevent border-radius clipping */ +.x-title-text, +.x-title-text-default { + overflow: visible !important; +} + +.x-panel-bodyWrap, +.x-panel-bodyWrap-default { + margin: 0 !important; + padding: 0 !important; + overflow: visible !important; +} + +/* Remove borders from nested panels */ +.x-panel-body > .x-box-layout-ct, +.x-panel-body > .x-container, +.x-panel-body > .x-box-inner, +[id*="pmxGauge"] { + border: none !important; +} + +.x-panel-header-title-default, +.x-window-header-title-default { + color: var(--ctp-text) !important; +} + +.x-panel-header-default .x-tool-tool-el { + background-color: transparent; +} + +.x-tool-img { + filter: brightness(175%); +} + +.x-tool-over .x-tool-img { + filter: brightness(200%); +} + +/* Resource tree — panel body border */ +div[id^="pveResourceTree-"][id$="-body"] { + border-color: var(--ctp-base) !important; +} + +/* Resource tree — remove row separators */ +[id^="pveResourceTree-"].x-tree-panel td.x-grid-cell, +[id^="pveResourceTree-"].x-tree-panel .x-grid-td, +[id^="pveResourceTree-"].x-tree-panel .x-grid-cell { + border-bottom: none !important; +} + +/* Resource tree — row spacing */ +div[id^="pveResourceTree"] .x-grid-cell { + padding-top: 3px !important; + padding-bottom: 3px !important; +} + +/* Summary/stats panel radius overrides */ +.pveStatusPanel, +.x-panel-default-framed, +.x-panel-body-default-framed { + border-radius: 12px !important; +} + +.x-panel-header-default-framed { + border-radius: 12px 12px 0 0 !important; +} + +/* Column widget panel radius */ +.x-panel.x-column > .x-panel-bodyWrap > .x-panel-body.x-panel-body-default { + border-radius: var(--pm-radius-lg) !important; +} + +/* ===================================================== + SPLITTERS / SEPARATORS + ===================================================== */ +.x-splitter-vertical { + background-color: transparent !important; + border-left: 1px solid var(--ctp-surface1) !important; + border-right: none !important; + width: 1px !important; +} + +.x-splitter-horizontal { + background-color: var(--ctp-crust) !important; + border-top: 1px solid var(--ctp-surface1) !important; +} + +.x-splitter { + background-color: var(--ctp-crust) !important; +} + +.x-keyboard-mode .x-splitter-focus::after { + border-color: var(--ctp-mauve) !important; +} + +.x-layout-split-bottom { + opacity: 0.7; +} + +/* Toolbox tree (pve-nav) right border — full height */ +.pve-toolbar-bg { + border-right: 1px solid var(--ctp-surface1) !important; + z-index: 3 !important; +} + +.x-treelist.x-treelist-pve-nav { + border-right: none !important; +} + +/* ===================================================== + TOOLBARS + ===================================================== */ +.x-toolbar, +.x-toolbar-default { + background-color: var(--ctp-base) !important; + border-color: var(--ctp-surface1) !important; +} + +.x-toolbar-default.x-docked-top { + border: none !important; + border-bottom: 1px solid var(--ctp-surface1) !important; +} + +.x-toolbar-default .x-toolbar-separator { + border-color: var(--ctp-surface1); +} + +.x-toolbar-text-default { + color: var(--ctp-subtext0); +} + +/* ===================================================== + PRIMARY BUTTONS — Catppuccin Mauve + ===================================================== */ +.x-btn-default-small { + background-color: var(--ctp-mauve) !important; + border: 1px solid rgba(136, 57, 239, 0.4) !important; + border-radius: var(--pm-radius-md) !important; + transition: background-color 0.15s ease, box-shadow 0.15s ease !important; +} + +.x-btn-default-small .x-btn-inner { + color: var(--ctp-on-accent) !important; + font-weight: 600 !important; +} + +.x-btn-default-small .x-btn-icon-el { + color: var(--ctp-on-accent) !important; +} + +.x-btn-default-small.x-btn-over, +.x-keyboard-mode .x-btn-default-small.x-btn-focus { + background-color: #9f5ff5 !important; + box-shadow: 0 0 0 3px var(--ctp-accent-subtle) !important; +} + +.x-btn-default-small.x-btn.x-btn-disabled { + background-color: var(--ctp-mauve) !important; + opacity: 0.4; +} + +.x-btn-default-small.x-btn.x-btn-pressed { + background-color: #7730d4 !important; +} + +/* Button height consistency — 28px with vertical centering */ +/* Exclude tag edit buttons (display:none when hidden, :has(.fa-check) for checkmark) */ +.x-btn.x-btn-default-small:not(.x-btn-default-toolbar-small):not([style*="display: none"]):not([style*="display:none"]):not(:has(.fa-check)) { + height: 28px !important; + min-height: 28px !important; + display: flex !important; + align-items: center !important; + padding: 3px 8px !important; +} + +/* Fix button inner element centering for proper icon alignment (issue #17) */ +.x-btn.x-btn-default-small:not(.x-btn-default-toolbar-small):not([style*="display: none"]):not([style*="display:none"]):not(:has(.fa-check)) .x-btn-wrap { + display: flex !important; + align-items: center !important; +} + +.x-btn.x-btn-default-small:not(.x-btn-default-toolbar-small):not([style*="display: none"]):not([style*="display:none"]):not(:has(.fa-check)) .x-btn-inner { + display: flex !important; + align-items: center !important; +} + +/* Fix dropdown arrows on split/arrow buttons */ +.x-btn-wrap.x-btn-arrow-right::after, +.x-btn-wrap.x-btn-split-right::after { + height: 16px !important; + min-height: 16px !important; + width: 20px !important; + display: flex !important; + align-items: center !important; +} + +/* Fix icon-only buttons — hide   inner element when button has no text */ +.x-btn-no-text .x-btn-inner, +.x-btn-button.x-btn-no-text .x-btn-inner, +.x-btn-button-default-toolbar-small.x-btn-no-text .x-btn-inner-default-toolbar-small, +.x-btn-button-default-small.x-btn-no-text .x-btn-inner-default-small, +.x-btn-button-default-small.x-btn-no-text > .x-btn-inner-default-small { + display: none !important; +} + +/* Specific fix for fa-desktop icon (Create VM) — visually bottom-heavy */ +.x-btn-icon-el.fa-desktop { + transform: translateY(1.1px) !important; +} + +/* ===================================================== + SECONDARY / TOOLBAR BUTTONS + ===================================================== */ +.x-btn-default-toolbar-small { + background-color: var(--ctp-surface0) !important; + border: 1px solid var(--ctp-surface1) !important; + border-radius: var(--pm-radius-md) !important; + transition: background-color 0.15s ease, border-color 0.15s ease !important; +} + +.x-btn-default-toolbar-small .x-btn-inner-default-toolbar-small, +.x-btn-default-toolbar-small .x-btn-icon-el-default-toolbar-small { + color: var(--ctp-text) !important; +} + +.x-btn-default-toolbar-small .x-btn-wrap-default-toolbar-small.x-btn-arrow-right::after, +.x-btn-default-toolbar-small .x-btn-wrap-default-toolbar-small.x-btn-split-right::after { + filter: brightness(150%); +} + +.x-btn-default-toolbar-small.x-btn-over, +.x-keyboard-mode .x-btn-default-toolbar-small.x-btn-focus { + background-color: var(--ctp-surface1) !important; + border-color: var(--ctp-surface2) !important; +} + +.x-btn-default-toolbar-small.x-btn.x-btn-disabled { + background-color: var(--ctp-surface0) !important; + opacity: 0.4; +} + +.x-btn-default-toolbar-small.x-btn.x-btn-menu-active, +.x-btn-default-toolbar-small.x-btn.x-btn-pressed { + background-color: var(--ctp-mauve) !important; + border-color: var(--ctp-mauve) !important; + padding: 4px 8px !important; /* Fix #30: prevent width change on dropdown */ +} + +.x-btn-default-toolbar-small.x-btn.x-btn-pressed .x-btn-inner-default-toolbar-small, +.x-btn-default-toolbar-small.x-btn.x-btn-pressed .x-btn-icon-el-default-toolbar-small, +.x-btn-default-toolbar-small.x-btn.x-btn-pressed .x-btn-inner-default-small, +.x-btn-default-toolbar-small.x-btn.x-btn-pressed .x-btn-icon-el-default-small { + color: var(--ctp-on-accent) !important; +} + +/* Segmented buttons */ +.x-segmented-button { + border-radius: var(--pm-radius-md) !important; +} + +.x-segmented-button .x-btn, +.x-segmented-button .x-btn-default-small, +.x-segmented-button .x-btn-inner, +.x-segmented-button .x-btn-wrap { + border-radius: var(--pm-radius-md) !important; +} + +/* Inline buttons (Documentation, Help) */ +.proxmox-inline-button { + height: 28px !important; + min-height: 28px !important; + display: flex !important; + align-items: center !important; + padding: 3px 8px !important; + background-color: var(--ctp-surface0) !important; + border: 1px solid var(--ctp-surface1) !important; + border-radius: var(--pm-radius-md) !important; + color: var(--ctp-text) !important; + transition: background-color 0.15s ease !important; +} + +.proxmox-inline-button:hover, +.proxmox-inline-button.x-btn-over { + background-color: var(--ctp-surface1) !important; + border-color: var(--ctp-overlay0) !important; +} + +.proxmox-inline-button:active, +.proxmox-inline-button.x-btn-pressed { + background-color: var(--ctp-surface2) !important; +} + +.proxmox-inline-button .x-btn-inner, +.proxmox-inline-button .x-btn-icon-el { + color: var(--ctp-text) !important; +} + +/* Pressed/active inline buttons get accent bg from toolbar rules — use on-accent text */ +.proxmox-inline-button.x-btn-pressed .x-btn-inner, +.proxmox-inline-button.x-btn-pressed .x-btn-icon-el, +.proxmox-inline-button.x-btn-menu-active .x-btn-inner, +.proxmox-inline-button.x-btn-menu-active .x-btn-icon-el { + color: var(--ctp-on-accent) !important; +} + +/* ===================================================== + FORM ELEMENTS + ===================================================== */ +.x-form-trigger-default { + background-color: var(--ctp-surface0) !important; +} + +.x-form-text-default { + background-color: var(--ctp-surface0) !important; + color: var(--ctp-text) !important; + border-radius: var(--pm-radius-sm) !important; +} + +.x-form-trigger-wrap, +.x-form-trigger-wrap-default { + border-color: var(--ctp-surface1) !important; + background-color: var(--ctp-surface0) !important; + border-radius: var(--pm-radius-sm) !important; + transition: border-color 0.15s ease !important; +} + +.x-form-trigger-wrap-default.x-form-trigger-wrap-focus { + border-color: var(--ctp-mauve) !important; + box-shadow: 0 0 0 3px var(--ctp-accent-subtle) !important; +} + +.x-form-item-label-default, +.x-form-cb-label-default { + color: var(--ctp-text) !important; +} + +.x-form-display-field-default { + color: var(--ctp-subtext0) !important; + border-radius: var(--pm-radius-md) !important; +} + +.x-form-spinner-default { + background-color: var(--ctp-surface0) !important; +} + +.x-fieldset, +.x-fieldset-default { + border-color: var(--ctp-surface1) !important; + border-radius: var(--pm-radius-lg) !important; +} + +.x-fieldset-header-default > .x-fieldset-header-text { + color: var(--ctp-text) !important; +} + +/* ===================================================== + CHECKBOXES & RADIOS — Catppuccin styled + ===================================================== */ + +/* Base: remove sprite, styled as custom control */ +.x-form-checkbox, .x-form-checkbox-default, +.x-form-radio, .x-form-radio-default { + background-image: none !important; + background-color: var(--ctp-surface0) !important; + border: 1.5px solid var(--ctp-overlay0) !important; + width: 16px !important; + height: 16px !important; + display: inline-block !important; + box-sizing: border-box !important; + cursor: pointer !important; + transition: border-color 0.12s ease, background-color 0.12s ease !important; +} + +/* Checkbox: rounded square */ +.x-form-checkbox, .x-form-checkbox-default { + border-radius: 3px !important; +} + +/* Radio: circle + ::after inner dot */ +.x-form-radio, .x-form-radio-default { + border-radius: 50% !important; + position: relative !important; + transform: translateZ(0) !important; + box-shadow: inset 0 0 0 0 transparent !important; +} + +.x-form-radio::after { + content: '' !important; + position: absolute !important; + top: 50% !important; + left: 50% !important; + width: 7px !important; + height: 7px !important; + border-radius: 50% !important; + background: transparent !important; + transform: translate(-50%, -50%) scale(0) !important; + transition: transform 0.15s ease, background 0.15s ease !important; + pointer-events: none !important; +} + +/* Hover */ +.x-form-checkbox:hover, .x-form-checkbox-default:hover, +.x-form-cb-wrap:hover .x-form-checkbox { + border-color: var(--ctp-mauve) !important; +} + +.x-form-radio:hover, .x-form-radio-default:hover, +.x-form-cb-wrap:hover .x-form-radio { + border-color: var(--ctp-mauve) !important; +} + +/* CHECKED checkbox — Mauve fill + white SVG checkmark */ +.x-form-cb-checked .x-form-checkbox, +.x-form-cb-checked .x-form-checkbox-default { + background-color: var(--ctp-mauve) !important; + border-color: var(--ctp-mauve) !important; + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 8'%3E%3Cpath d='M1 4l3 3 5-6' fill='none' stroke='%23eff1f5' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") !important; + background-repeat: no-repeat !important; + background-position: center !important; + background-size: 9px 7px !important; +} + +/* SELECTED radio — Mauve dot */ +.x-form-cb-checked .x-form-radio, +.x-form-cb-checked .x-form-radio-default { + border-color: var(--ctp-mauve) !important; + background-color: var(--ctp-base) !important; +} + +.x-form-cb-checked .x-form-radio::after { + background: var(--ctp-mauve) !important; + transform: translate(-50%, -50%) scale(1) !important; +} + +/* ===================================================== + BOUNDLIST / DROPDOWNS + ===================================================== */ +.x-boundlist { + background-color: var(--ctp-mantle) !important; + border: 1px solid var(--ctp-surface1) !important; + border-radius: var(--pm-radius-md) !important; + box-shadow: 0 8px 24px rgba(76, 79, 105, 0.7) !important; + padding: 2px !important; + overflow: hidden !important; +} + +.x-boundlist-item { + background-color: transparent !important; + color: var(--ctp-text) !important; + border-radius: var(--pm-radius-sm) !important; + padding: 2px 6px !important; + line-height: normal !important; + border: none !important; + cursor: pointer !important; + outline: none !important; + box-shadow: none !important; +} + +.x-boundlist-selected { + background-color: var(--ctp-select-overlay) !important; + color: var(--ctp-text) !important; +} + +.x-boundlist-item-over { + background-color: var(--ctp-hover-overlay) !important; +} + +/* ===================================================== + GRIDS / TABLES + ===================================================== */ +.x-grid, +.x-grid-view { + border-radius: 0 !important; +} + +.x-column-header { + border-color: var(--ctp-surface1) !important; + background-color: transparent !important; +} + +.x-column-header-inner, +.x-column-header-text { + color: var(--ctp-text) !important; + font-weight: 600 !important; +} + +.x-column-header-trigger { + border-color: var(--ctp-surface1) !important; +} + +.x-grid-item, +.x-column-header-default, +.x-grid-cell-row-numberer { + color: var(--ctp-text) !important; + background-color: var(--ctp-base) !important; +} + +.x-grid-cell-special { + border-color: var(--ctp-surface1) !important; +} + +.x-grid-group-hd { + background-color: var(--ctp-base) !important; + border-color: var(--ctp-surface1) !important; +} + +.x-grid-group-title { + color: var(--ctp-text) !important; +} + +.x-grid-header-ct { + background-color: var(--ctp-mantle) !important; + border: 1px solid var(--ctp-surface0) !important; + border-radius: var(--pm-radius-lg) var(--pm-radius-lg) 0 0 !important; +} + +.x-grid-item-alt { + background-color: var(--ctp-crust) !important; +} + +.x-grid-with-row-lines .x-grid-item { + border-color: var(--ctp-surface0) !important; +} + +.x-grid-cell { + border-bottom: 1px solid rgba(69, 71, 90, 0.4) !important; +} + +.x-grid-item-over, +.x-grid-with-row-lines .x-grid-item.x-grid-item-over { + background-color: var(--ctp-hover-overlay) !important; +} + +.x-grid-item-selected, +.x-grid-with-row-lines .x-grid-item.x-grid-item-selected { + background-color: var(--ctp-select-overlay) !important; +} + +.x-column-header-over, +.x-column-header-open { + background-color: var(--ctp-hover-overlay) !important; +} + +.x-column-header-sort-ASC, +.x-column-header-sort-DESC { + background-color: var(--ctp-hover-overlay) !important; +} + +.x-grid-row-summary .x-grid-cell, +.x-grid-row-summary .x-grid-rowwrap, +.x-grid-row-summary .x-grid-cell-rowbody { + background-color: var(--ctp-base) !important; + border-color: var(--ctp-surface1); +} + +.x-grid-with-col-lines .x-grid-cell, +.x-grid-with-col-lines .x-grid-item-over .x-grid-cell, +.x-grid-with-col-lines .x-grid-item-selected .x-grid-cell { + border-color: var(--ctp-surface1) !important; +} + +.x-dd-drag-proxy { + background-color: var(--ctp-mantle); + border-color: var(--ctp-surface1); + color: var(--ctp-text); +} + +.x-keyboard-mode .x-grid-item-focused { + background-color: var(--ctp-hover-overlay) !important; + color: var(--ctp-text) !important; +} + +/* Remove blue outline from focused/selected items in resource tree */ +.x-keyboard-mode .x-grid-item-focused .x-grid-cell-inner::before, +.x-keyboard-mode .x-grid-item-selected .x-grid-cell-inner::before, +.x-grid-item-selected .x-grid-cell-inner::before, +.x-grid-item-focused .x-grid-cell-inner::before, +[id^="pveResourceTree"] .x-grid-item-selected .x-grid-cell-inner::before, +[id^="pveResourceTree"] .x-grid-item-focused .x-grid-cell-inner::before { + content: none !important; + display: none !important; + border: none !important; +} + +.x-grid-empty { + background-color: var(--ctp-base) !important; + color: var(--ctp-subtext0) !important; +} + +/* Grid info (pve-info-grid) and RRD view */ +.pve-info-grid { + border-radius: 12px !important; +} + +.pve-rrdview, +.rrdview { + border-radius: 12px !important; +} + +.pve-summary-status, +.x-container .pve-status { + border-radius: var(--pm-radius-lg) !important; +} + +[id^="pveGuestStatusView-"][id$="-body"], +[id^="pmxNotesView-"] .x-panel-body { + border-radius: var(--pm-radius-lg) !important; +} + +.x-panel-default[id*="notes"], +.pve-notes-view { + border-radius: var(--pm-radius-lg) !important; +} + +/* Floating grid pickers (storage/ISO selectors) */ +.x-layer.x-grid .x-grid-view, +.x-panel.x-layer.x-grid .x-grid-view, +.x-panel.x-layer.x-grid, +.x-layer.x-panel.x-grid { + border-radius: var(--pm-radius-sm) !important; +} + +.x-layer.x-grid .x-grid-item-over, +.x-layer.x-grid .x-grid-item-selected, +.x-panel.x-layer.x-grid .x-grid-item-over, +.x-panel.x-layer.x-grid .x-grid-item-selected { + border-radius: var(--pm-radius-sm) !important; + outline: none !important; + box-shadow: none !important; +} + +.x-layer.x-grid .x-grid-item-over td, +.x-layer.x-grid .x-grid-item-selected td, +.x-layer.x-grid .x-grid-item-over .x-grid-cell, +.x-layer.x-grid .x-grid-item-selected .x-grid-cell, +.x-panel.x-layer.x-grid .x-grid-item-over td, +.x-panel.x-layer.x-grid .x-grid-item-selected td, +.x-panel.x-layer.x-grid .x-grid-item-over .x-grid-cell, +.x-panel.x-layer.x-grid .x-grid-item-selected .x-grid-cell { + border-radius: 0 !important; +} + +.x-layer.x-grid .x-grid-item-over td:first-child, +.x-layer.x-grid .x-grid-item-selected td:first-child, +.x-panel.x-layer.x-grid .x-grid-item-over td:first-child, +.x-panel.x-layer.x-grid .x-grid-item-selected td:first-child { + border-radius: var(--pm-radius-sm) 0 0 var(--pm-radius-sm) !important; +} + +.x-layer.x-grid .x-grid-item-over td:last-child, +.x-layer.x-grid .x-grid-item-selected td:last-child, +.x-panel.x-layer.x-grid .x-grid-item-over td:last-child, +.x-panel.x-layer.x-grid .x-grid-item-selected td:last-child { + border-radius: 0 var(--pm-radius-sm) var(--pm-radius-sm) 0 !important; +} + +/* ===================================================== + MENUS + ===================================================== */ +.x-menu, +.x-menu-default { + background-color: var(--ctp-crust) !important; + border: 1px solid var(--ctp-surface0) !important; + border-radius: var(--pm-radius-lg) !important; + box-shadow: 0 8px 24px rgba(76, 79, 105, 0.8) !important; + padding: 2px !important; + overflow: hidden !important; +} + +.x-menu-body-default { + background-color: transparent !important; + padding: 4px !important; +} + +.x-menu-header { + background-color: transparent !important; + color: var(--ctp-text) !important; +} + +/* Menu icon separator — hide */ +.x-menu-icon-separator-default { + display: none !important; +} + +/* Menu item layout (flexbox reordering) */ +.x-menu-item-default > .x-menu-item-link { + display: flex !important; + align-items: center !important; + flex-direction: row !important; + gap: 4px !important; + justify-content: flex-start !important; + flex-wrap: nowrap !important; + border-radius: var(--pm-radius-md) !important; + padding: 4px 8px !important; + line-height: 20px !important; + cursor: pointer !important; + outline: none !important; + box-shadow: none !important; + white-space: nowrap !important; + text-decoration: none !important; +} + +.x-menu-item-text-default { + color: var(--ctp-text) !important; + font-size: 13px !important; + order: 1 !important; + margin-left: 0 !important; + text-align: left !important; + line-height: 20px !important; + display: inline-flex !important; + align-items: center !important; + flex: 1 1 auto !important; + width: auto !important; + white-space: nowrap !important; +} + +.x-menu-item-icon-default { + color: var(--ctp-subtext0) !important; + order: -1 !important; + position: relative !important; + float: none !important; + margin-right: 8px !important; + margin-left: 0 !important; + left: auto !important; + top: auto !important; + width: 16px !important; + text-align: center !important; + display: inline-flex !important; + align-items: center !important; + justify-content: center !important; + height: 20px !important; + line-height: 20px !important; + vertical-align: middle !important; + flex: 0 0 16px !important; + align-self: center !important; +} + +.x-menu-item-arrow, +.x-menu-item-arrow-default { + order: 2 !important; + margin-left: auto !important; +} + +.x-menu-item-default.x-menu-item-separator { + background-color: var(--ctp-surface0) !important; + border: none !important; + height: 1px !important; + margin: 6px 4px !important; +} + +.x-menu-item-default.x-menu-item-focus, +.x-menu-item-default.x-menu-item-active, +.x-menu-item:hover { + background-color: var(--ctp-surface0) !important; + color: var(--ctp-text) !important; + border-radius: var(--pm-radius-md) !important; +} + +.x-menu-item-active .x-menu-item-text-default, +.x-menu-item-focus .x-menu-item-text-default { + color: var(--ctp-text) !important; +} + +.x-menu-item-active .x-menu-item-icon-default, +.x-menu-item-focus .x-menu-item-icon-default { + color: var(--ctp-lavender) !important; +} + +/* ===================================================== + PROGRESS BARS + ===================================================== */ + +/* Fix: Widget containers need overflow visible to not clip progress bars */ +.x-container[id^="pmxInfoWidget"], +.x-container.x-box-layout-ct { + overflow: visible !important; +} + +.x-progress, +.x-progress-default { + background-color: var(--ctp-surface0) !important; + border-radius: 5px !important; +} + +.x-progress-default .x-progress-bar-default { + background-color: var(--ctp-mauve) !important; + border-radius: 5px !important; + transition: width 0.4s ease !important; +} + +.x-progress-default .x-progress-text { + color: var(--ctp-text) !important; +} + +/* Text overlaid on the progress bar fill — use on-accent for contrast against Mauve/Yellow/Red fills */ +.x-progress-bar .x-progress-text { + color: var(--ctp-on-accent) !important; +} + +.x-progress.warning .x-progress-bar { + background-color: var(--ctp-yellow) !important; +} + +.x-progress.critical .x-progress-bar { + background-color: var(--ctp-red) !important; +} + +/* ===================================================== + TABS — Catppuccin underline style + Flat tabs with Mauve underline on active tab + ===================================================== */ +.x-tab-bar, +.x-tab-bar-default { + background-color: var(--ctp-base) !important; + border-radius: 0 !important; + border-bottom: 1px solid var(--ctp-surface1) !important; + padding-bottom: 0 !important; +} + +/* Overflow visible for the underline indicator */ +.x-tab-bar .x-box-inner, +.x-tab-bar .x-box-target, +.x-tab-bar-body, +.x-tab-bar-body-default { + overflow: visible !important; +} + +/* Base tab */ +.x-tab, +.x-tab-default, +.x-tab-default-top { + background-color: transparent !important; + border: none !important; + border-radius: var(--pm-radius-md) var(--pm-radius-md) 0 0 !important; + padding: 8px 16px 8px !important; + overflow: visible !important; + margin-bottom: 0 !important; + transition: color 0.15s ease !important; + outline: none !important; + box-shadow: none !important; +} + +/* Remove ::after from inactive tabs */ +.x-tab::after { + display: none !important; +} + +.x-tab-inner-default { + color: var(--ctp-subtext0) !important; + font-size: 13px !important; +} + +.x-tab-default.x-tab-over { + background-color: transparent !important; +} + +.x-tab-default.x-tab-over .x-tab-inner-default { + color: var(--ctp-text) !important; +} + +/* Active tab */ +.x-tab-default.x-tab.x-tab-active { + background-color: transparent !important; + border: none !important; + overflow: visible !important; + margin-bottom: 0 !important; + outline: none !important; + box-shadow: none !important; +} + +/* Mauve underline indicator on active tab */ +.x-tab-default.x-tab.x-tab-active::after { + content: '' !important; + display: block !important; + position: absolute !important; + bottom: 0 !important; + left: 0 !important; + right: 0 !important; + height: 2px !important; + background: var(--ctp-mauve) !important; + z-index: 10 !important; + border-radius: 2px 2px 0 0 !important; + pointer-events: none !important; +} + +.x-tab-active .x-tab-inner-default { + color: var(--ctp-text) !important; + font-weight: 600 !important; +} + +.x-tab-default.x-tab.x-tab-disabled { + background-color: transparent !important; + border: none !important; + color: var(--ctp-overlay0) !important; + margin-bottom: 0 !important; +} + +/* Focus states — no outline */ +.x-keyboard-mode .x-tab-default.x-tab-focus, +.x-keyboard-mode .x-tab-default.x-tab-focus.x-tab-active { + background-color: transparent !important; + border: none !important; + outline: none !important; + box-shadow: none !important; + margin-bottom: 0 !important; +} + +.x-keyboard-mode .x-tab-default.x-tab-focus.x-tab-active::after { + content: '' !important; + display: block !important; + position: absolute !important; + bottom: 0 !important; + left: 0 !important; + right: 0 !important; + height: 2px !important; + background: var(--ctp-mauve) !important; + z-index: 10 !important; + pointer-events: none !important; +} + +/* Kill ALL tab interaction outlines/shadows */ +.x-tab:focus, +.x-tab *:focus, +.x-tab-focus, +.x-tab-active.x-tab-focus, +.x-tab-inner-focus, +.x-tab-button-focus, +.x-tab-pressed, +.x-tab-active.x-tab-pressed, +.x-tab-over, +.x-tab:active, +.x-tab *:active { + outline: none !important; + box-shadow: none !important; +} + +.x-tabpanel-child { + border-radius: 0 0 var(--pm-radius-lg) var(--pm-radius-lg) !important; +} + +/* Tab hover/active corners */ +.x-tab-default.x-tab-over, +.x-tab-default.x-tab.x-tab-active { + border-radius: var(--pm-radius-md) var(--pm-radius-md) 0 0 !important; +} + +/* ===================================================== + TOOLTIPS + ===================================================== */ +.x-tip, +.x-tip-default { + background-color: var(--ctp-mantle) !important; + border: 1px solid var(--ctp-surface1) !important; + border-radius: var(--pm-radius-md) !important; + box-shadow: 0 4px 12px rgba(76, 79, 105, 0.5); +} + +.x-tip-body-default { + color: var(--ctp-text) !important; +} + +.x-tip-form-invalid { + background-color: var(--ctp-mantle) !important; + border-color: var(--ctp-red) !important; +} + +.x-tip-body-form-invalid { + color: var(--ctp-red) !important; +} + +/* ===================================================== + TREE NAVIGATION (Sidebar) + ===================================================== */ +.x-treelist-item { + background-color: var(--ctp-base) !important; + border-radius: var(--pm-radius-md) !important; +} + +/* Pseudo-element approach for hover/selected highlighting */ +.x-treelist-row { + border-radius: var(--pm-radius-md) !important; + background-color: transparent !important; + position: relative !important; + z-index: 0 !important; +} + +.x-treelist-row::before { + content: ""; + position: absolute; + top: 1px; + bottom: 1px; + left: 0; + right: 4px; + border-radius: var(--pm-radius-md); + background-color: transparent; + z-index: -1; + pointer-events: none; + transition: background-color 0.15s ease; +} + +/* Fix toolbox tree item text overlapping icons */ +.x-treelist-item-text { + margin-left: 28px !important; +} + +/* Toolbox tree items — bright text */ +.x-treelist-item-text, +.x-treelist-item-icon, +.x-treelist.x-treelist-pve-nav .x-treelist-item-text, +.x-treelist.x-treelist-pve-nav .x-treelist-item-icon { + color: var(--ctp-subtext1) !important; +} + +/* Hover state — apply to pseudo-element */ +.x-treelist-row-over { + background-color: transparent !important; +} + +.x-treelist-row-over::before { + background-color: var(--ctp-hover-overlay) !important; +} + +.x-treelist-row-over .x-treelist-item-icon, +.x-treelist-row-over .x-treelist-item-text { + background-color: transparent !important; + color: var(--ctp-text) !important; +} + +/* Selected/active item — Mauve highlight */ +.x-treelist-item-selected > .x-treelist-row { + background-color: transparent !important; +} + +.x-treelist-item-selected > .x-treelist-row::before, +.x-treelist-item-selected > .x-treelist-row:hover::before { + background-color: var(--ctp-mauve) !important; +} + +.x-treelist-item-selected .x-treelist-item-text, +.x-treelist-item-selected .x-treelist-item-icon, +.x-treelist.x-treelist-pve-nav .x-treelist-item-selected .x-treelist-item-text, +.x-treelist.x-treelist-pve-nav .x-treelist-item-selected .x-treelist-item-icon { + color: var(--ctp-on-accent) !important; +} + +.x-treelist-pve-nav { + background-color: var(--ctp-base) !important; + border-color: var(--ctp-surface1) !important; +} + +/* Tree navigation radius overrides */ +.x-treelist-item, +.x-treelist-item-tool { + border-radius: var(--pm-radius-sm) !important; +} + +.x-treelist-row, +.x-treelist-row:hover, +.x-treelist-row-over, +.x-treelist-item-selected > .x-treelist-row, +.x-treelist-item-selected > .x-treelist-row:hover, +.x-treelist-item-expanded > .x-treelist-row, +.x-treelist-item-expanded > .x-treelist-row-over, +.x-treelist-item-expandable > .x-treelist-row, +.x-treelist-item-expandable > .x-treelist-row-over { + border-radius: var(--pm-radius-sm) !important; +} + +.x-treelist-row::before { + border-radius: var(--pm-radius-sm) !important; +} + +.x-treelist-item-wrap, +.x-treelist-item-text, +.x-treelist-row, +.x-treelist-container, +.x-treelist-root-container, +.x-treelist, +.x-treelist-pve-nav { + border-radius: var(--pm-radius-sm) !important; +} + +/* Cursor pointer for interactive tree/grid items */ +.x-grid-cell, +.x-grid-cell-inner, +.x-tree-elbow-img, +.x-tree-icon, +.x-treelist-item, +.x-treelist-row, +.x-treelist-item-wrap, +.x-treelist-item-text, +.x-treelist-item-icon { + cursor: pointer !important; +} + +/* ===================================================== + WINDOWS / MODALS + ===================================================== */ +.x-window, +.x-window-default { + background-color: var(--ctp-crust) !important; + border: 1px solid var(--ctp-surface1) !important; + border-radius: var(--pm-radius-lg) !important; + box-shadow: 0 8px 24px rgba(76, 79, 105, 0.6) !important; + overflow: hidden !important; +} + +.x-window .x-window-header, +.x-window-header-default { + background-color: var(--ctp-mantle) !important; + border-color: transparent !important; + border-radius: var(--pm-radius-lg) var(--pm-radius-lg) 0 0 !important; +} + +.x-window-header-default .x-mask { + background-color: rgba(76, 79, 105, 0.7); +} + +.x-window .x-window-body, +.x-window-body-default { + background-color: var(--ctp-base) !important; + border-color: var(--ctp-surface1) !important; + color: var(--ctp-text) !important; + border-radius: 0 0 var(--pm-radius-lg) var(--pm-radius-lg) !important; +} + +.x-window-ghost { + background-color: var(--ctp-base) !important; +} + +.x-window-header-default .x-tool-img { + background-color: transparent; +} + +.x-message-box .x-window-body { + background-color: var(--ctp-mantle) !important; +} + +/* Respect ExtJS inline display:none on hidden dialog buttons */ +.x-message-box .x-btn.x-btn-default-small[style*="display: none"], +.x-message-box .x-btn.x-btn-default-small[style*="display:none"], +.x-window .x-toolbar-footer .x-btn[style*="display: none"], +.x-window .x-toolbar-footer .x-btn[style*="display:none"] { + display: none !important; +} + +/* Login dialog — clean inner panel borders */ +.x-window:has(#pveloginrealm) .x-panel-body { + border: none !important; + background: transparent !important; + width: auto !important; +} + +/* ===================================================== + CONSOLE / TERMINAL + ===================================================== */ +div.monitor { + border-color: var(--ctp-surface1); +} + +.install-mask { + background-color: var(--ctp-crust); + color: var(--ctp-subtext0); +} + +.x-window.install-mask { + box-shadow: rgba(76, 79, 105, 0.5) 0 4px 20px !important; +} + +/* ===================================================== + LEGEND / CHARTS + ===================================================== */ +.x-legend-container { + background-color: var(--ctp-base) !important; +} + +.x-legend-horizontal .x-legend-item { + background-color: var(--ctp-mantle) !important; + color: var(--ctp-text) !important; + border: 1px solid var(--ctp-surface0) !important; +} + +/* Chart/RRD panel backgrounds */ +div[id*="rrdchart"], +.pve-rrddatastore, +.pmx-panel-rrd { + background-color: var(--ctp-base) !important; +} + +.proxmox-rrd-panel canvas, +.proxmox-widget-toolkit canvas, +canvas.x-surface, +.x-surface canvas { + background-color: transparent !important; + opacity: 1 !important; +} + +.proxmox-rrd-panel, +.proxmox-rrd-chart { + background-color: var(--ctp-base) !important; +} + +/* Chart text/labels */ +.x-surface text, +svg text { + fill: var(--ctp-text) !important; +} + +/* ===================================================== + PROXMOX-SPECIFIC OVERRIDES + ===================================================== */ + +/* Logo — no inversion for light theme */ +img[id^="proxmoxlogo-"][id$="-img"], +img[id^="proxmoxLogoSvg-"][id$="-img"] { + filter: none; +} + +/* Invalid/warning/disabled rows */ +.proxmox-invalid-row { + background-color: rgba(243, 139, 168, 0.15) !important; +} + +.proxmox-warning-row { + background-color: rgba(250, 179, 135, 0.15) !important; +} + +.proxmox-disabled-row td { + color: var(--ctp-overlay0) !important; +} + +/* Hints */ +.pmx-hint { + background-color: rgba(250, 179, 135, 0.15) !important; + white-space: nowrap !important; +} + +.pmx-hint a { + color: var(--ctp-blue) !important; +} + +/* Status text colors — style guide: Information → Teal */ +.info-blue { + color: var(--ctp-teal) !important; +} + +.critical { + color: var(--ctp-red) !important; +} + +/* Links */ +a { + color: var(--ctp-blue) !important; +} + +/* Markdown content */ +.pmx-md code { + background-color: var(--ctp-mantle) !important; + color: var(--ctp-rosewater) !important; + border-radius: var(--pm-radius-sm) !important; +} + +.pmx-md pre code { + border-color: var(--ctp-surface1) !important; + background-color: var(--ctp-crust) !important; +} + +.pmx-md a { + color: var(--ctp-blue) !important; +} + +.pmx-md table { + border-color: var(--ctp-surface1) !important; +} + +.pmx-md th { + background-color: var(--ctp-mantle) !important; + border-color: var(--ctp-surface1) !important; +} + +.pmx-md td { + border-color: var(--ctp-surface1) !important; +} + +/* APT repos */ +.proxmox-apt-repos .x-grid-group-hd { + background-color: var(--ctp-base) !important; + border: none !important; +} + +.proxmox-apt-repos .x-grid-group-title { + color: var(--ctp-text) !important; +} + +/* Tags */ +.pve-edit-tag { + border-radius: var(--pm-radius-md) !important; +} + +.pve-edit-tag.editable span { + background-color: var(--ctp-mantle) !important; + color: var(--ctp-text) !important; + border-color: var(--ctp-surface1) !important; +} + +.x-tree-node-text .proxmox-tag-dark, +.x-tree-node-text .proxmox-tag-light, +.x-grid-cell-inner .proxmox-tag-dark, +.x-grid-cell-inner .proxmox-tag-light, +span.proxmox-tag-dark, +span.proxmox-tag-light { + border-radius: var(--pm-radius-md) !important; +} + +/* Checkmark button in tag edit — match toolbar button size */ +.x-btn.x-btn-default-small:has(.fa-check) { + min-height: 24px !important; + height: 24px !important; + padding: 3px 8px !important; + border-radius: var(--pm-radius-sm) !important; + background-color: var(--ctp-mauve) !important; + border: none !important; +} + +.x-btn.x-btn-default-small:has(.fa-check).x-btn-disabled { + background-color: transparent !important; + border: 1px solid var(--ctp-surface1) !important; + opacity: 0.5 !important; +} + +.x-btn.x-btn-default-small:has(.fa-check) .fa-check { + color: var(--ctp-on-accent) !important; +} + +.x-btn.x-btn-default-small:has(.fa-check).x-btn-disabled .fa-check { + color: var(--ctp-overlay1) !important; +} + +.x-btn.x-btn-default-small:has(.fa-check):not(.x-btn-disabled):hover { + background-color: #9f5ff5 !important; +} + +.x-btn.x-btn-default-small:has(.fa-check) .x-btn-inner { + display: none !important; +} + +/* Date picker */ +.x-datepicker, +.x-datepicker-column-header, +.x-monthpicker { + background-color: var(--ctp-base) !important; + color: var(--ctp-text) !important; + border-color: transparent !important; +} + +.x-datepicker-header, +.x-datepicker-footer, +.x-monthpicker-buttons { + background-color: var(--ctp-mantle) !important; +} + +.x-datepicker-date, +.x-monthpicker-item-inner { + color: var(--ctp-text) !important; +} + +.x-datepicker-selected div.x-datepicker-date, +.x-monthpicker-item a.x-monthpicker-selected, +a.x-monthpicker-item-inner:hover, +div.x-datepicker-date:hover { + background-color: var(--ctp-hover-overlay) !important; + color: var(--ctp-text) !important; +} + +.x-datepicker-today .x-datepicker-date { + border-color: var(--ctp-mauve) !important; +} + +.x-datepicker-disabled .x-datepicker-date { + color: var(--ctp-overlay0) !important; +} + +.x-datepicker-prev-day .x-datepicker-date, +.x-datepicker-next-day .x-datepicker-date { + color: var(--ctp-overlay0) !important; +} + +/* Usage bars */ +.usage-wrapper, +.usage { + border-radius: 2px !important; +} + +.usage { + background-color: var(--ctp-overlay2) !important; +} + +/* ===================================================== + SCROLLBARS + ===================================================== */ +::-webkit-scrollbar { + width: 8px; + height: 8px; +} + +::-webkit-scrollbar-track { + background: var(--ctp-base); + border-radius: var(--pm-radius-sm); +} + +::-webkit-scrollbar-thumb { + background: var(--ctp-surface2); + border-radius: var(--pm-radius-sm); + border: 1px solid transparent; + background-clip: padding-box; + transition: background 0.15s ease; +} + +::-webkit-scrollbar-thumb:hover { + background: var(--ctp-overlay0); +} + +::-webkit-scrollbar-corner { + background: var(--ctp-base); +} + +/* Firefox scrollbar */ +* { + scrollbar-width: thin; + scrollbar-color: var(--ctp-surface2) var(--ctp-base); +} + +/* ===================================================== + SELECTION HIGHLIGHT + ===================================================== */ +::selection { + background-color: rgba(124, 127, 147, 0.3); + color: var(--ctp-text); +} + +/* ===================================================== + TRANSITIONS (smooth interactions) + ===================================================== */ + +/* Grid row transitions */ +.x-grid-item { + transition: background-color 0.15s ease !important; +} + +/* Tree pseudo-element transitions */ +.x-treelist-row::before { + transition: background-color 0.15s ease !important; +} + +/* Menu item transitions */ +.x-menu-item-default > .x-menu-item-link { + transition: background-color 0.12s ease !important; +} + +/* Boundlist item transitions */ +.x-boundlist-item { + transition: background-color 0.12s ease !important; +} + +/* Tab transitions */ +.x-tab { + transition: color 0.15s ease !important; +} + +/* Splitter transition */ +.x-splitter { + transition: background-color 0.15s ease !important; +} + +/* Tooltip transition */ +.x-tip { + transition: opacity 0.15s ease !important; +} + +/* Progress bar width transition */ +.x-progress-bar { + transition: width 0.4s ease !important; +} + +/* Scrollbar thumb transition */ +::-webkit-scrollbar-thumb { + transition: background 0.15s ease !important; +} + +/* Window close tool transition */ +.x-tool-img { + transition: filter 0.15s ease !important; +} + +/* ===================================================== + TOOL ICONS - FontAwesome Replacements + (Ported from UniFi v5.86) + Replace sprite-based ExtJS tool icons with crisp + FontAwesome icons for better consistency and clarity + ===================================================== */ + +/* Base styling for all tool icons - remove sprite backgrounds */ +.x-tool-tool-el.x-tool-minus, +.x-tool-img.x-tool-minus, +.x-tool-tool-el.x-tool-collapse-right, +.x-tool-img.x-tool-collapse-right, +.x-tool-tool-el.x-tool-collapse-left, +.x-tool-img.x-tool-collapse-left, +.x-tool-tool-el.x-tool-expand-right, +.x-tool-img.x-tool-expand-right, +.x-tool-tool-el.x-tool-expand-left, +.x-tool-img.x-tool-expand-left, +.x-tool-tool-el.x-tool-maximize, +.x-tool-img.x-tool-maximize, +.x-tool-tool-el.x-tool-restore, +.x-tool-img.x-tool-restore, +.x-tool-tool-el.x-tool-gear, +.x-tool-img.x-tool-gear, +.x-tool-tool-el.x-tool-refresh, +.x-tool-img.x-tool-refresh, +.x-tool-tool-el.x-tool-close, +.x-tool-img.x-tool-close { + background-image: none !important; + font-family: "FontAwesome" !important; + font-size: 14px !important; + line-height: 16px !important; + text-align: center !important; + color: var(--pm-text-dim) !important; + transition: color 0.15s ease !important; + filter: none !important; + width: 16px !important; + height: 16px !important; + display: flex !important; + align-items: center !important; + justify-content: center !important; +} + +/* Close button - slightly larger */ +.x-tool-tool-el.x-tool-close, +.x-tool-img.x-tool-close { + font-size: 20px !important; +} + +/* Individual glyph assignments */ +.x-tool-tool-el.x-tool-minus::before, +.x-tool-img.x-tool-minus::before { + content: "\f010" !important; /* fa-search-minus (zoom out) */ +} + +.x-tool-tool-el.x-tool-collapse-right::before, +.x-tool-img.x-tool-collapse-right::before { + content: "\f054" !important; /* fa-chevron-right */ +} + +.x-tool-tool-el.x-tool-expand-left::before, +.x-tool-img.x-tool-expand-left::before { + content: "\f053" !important; /* fa-chevron-left */ +} + +.x-tool-tool-el.x-tool-collapse-left::before, +.x-tool-img.x-tool-collapse-left::before { + content: "\f053" !important; /* fa-chevron-left */ +} + +.x-tool-tool-el.x-tool-expand-right::before, +.x-tool-img.x-tool-expand-right::before { + content: "\f054" !important; /* fa-chevron-right */ +} + +.x-tool-tool-el.x-tool-maximize::before, +.x-tool-img.x-tool-maximize::before { + content: "\f065" !important; /* fa-expand */ +} + +.x-tool-tool-el.x-tool-restore::before, +.x-tool-img.x-tool-restore::before { + content: "\f066" !important; /* fa-compress */ +} + +.x-tool-tool-el.x-tool-gear::before, +.x-tool-img.x-tool-gear::before { + content: "\f013" !important; /* fa-cog */ +} + +.x-tool-tool-el.x-tool-refresh::before, +.x-tool-img.x-tool-refresh::before { + content: "\f021" !important; /* fa-refresh */ +} + +.x-tool-tool-el.x-tool-close::before, +.x-tool-img.x-tool-close::before { + content: "\f00d" !important; /* fa-times */ +} + +/* Hover state - all tool icons */ +.x-tool:hover .x-tool-tool-el.x-tool-minus, +.x-tool:hover .x-tool-img.x-tool-minus, +.x-tool:hover .x-tool-tool-el.x-tool-collapse-right, +.x-tool:hover .x-tool-img.x-tool-collapse-right, +.x-tool:hover .x-tool-tool-el.x-tool-collapse-left, +.x-tool:hover .x-tool-img.x-tool-collapse-left, +.x-tool:hover .x-tool-tool-el.x-tool-expand-right, +.x-tool:hover .x-tool-img.x-tool-expand-right, +.x-tool:hover .x-tool-tool-el.x-tool-expand-left, +.x-tool:hover .x-tool-img.x-tool-expand-left, +.x-tool:hover .x-tool-tool-el.x-tool-maximize, +.x-tool:hover .x-tool-img.x-tool-maximize, +.x-tool:hover .x-tool-tool-el.x-tool-restore, +.x-tool:hover .x-tool-img.x-tool-restore, +.x-tool:hover .x-tool-tool-el.x-tool-gear, +.x-tool:hover .x-tool-img.x-tool-gear, +.x-tool:hover .x-tool-tool-el.x-tool-refresh, +.x-tool:hover .x-tool-img.x-tool-refresh, +.x-tool:hover .x-tool-tool-el.x-tool-close, +.x-tool:hover .x-tool-img.x-tool-close { + color: var(--pm-text) !important; +} + +/* Disabled state */ +.x-tool-disabled .x-tool-tool-el, +.x-tool-disabled .x-tool-img { + opacity: 0.4 !important; + cursor: default !important; +} + +/* Inline FontAwesome tools (PVE-injected) */ +.x-tool-tool-el[style*="font-family:FontAwesome"], +.x-tool-tool-el[style*="font-family: FontAwesome"] { + color: var(--pm-text-dim) !important; + font-size: 14px !important; + line-height: 16px !important; + display: flex !important; + align-items: center !important; + justify-content: center !important; + width: 16px !important; + height: 16px !important; + transition: color 0.15s ease !important; + background-image: none !important; + background-color: transparent !important; +} + +.x-tool:not(.x-tool-disabled) .x-tool-tool-el[style*="font-family:FontAwesome"], +.x-tool:not(.x-tool-disabled) .x-tool-tool-el[style*="font-family: FontAwesome"] { + cursor: pointer !important; +} + +.x-tool.x-tool-disabled .x-tool-tool-el[style*="font-family:FontAwesome"], +.x-tool.x-tool-disabled .x-tool-tool-el[style*="font-family: FontAwesome"] { + cursor: default !important; + opacity: 0.4 !important; +} + +.x-tool .x-mask { + background-color: transparent !important; + backdrop-filter: none !important; + pointer-events: none !important; +} + +.x-tool:not(.x-tool-disabled):hover .x-tool-tool-el[style*="font-family:FontAwesome"], +.x-tool:not(.x-tool-disabled):hover .x-tool-tool-el[style*="font-family: FontAwesome"] { + color: var(--pm-text) !important; +} diff --git a/themes/theme-catppuccin-macchiato.css b/themes/theme-catppuccin-macchiato.css new file mode 100644 index 0000000..11223b9 --- /dev/null +++ b/themes/theme-catppuccin-macchiato.css @@ -0,0 +1,2382 @@ +/*!Catppuccin Macchiato*/ +/* + * ProxMorph Theme: Catppuccin Macchiato + * Soothing pastel theme for Proxmox VE — the medium-contrast dark flavor of Catppuccin + * Version: 1.0.0 + * Author: ProxMorph / Catppuccin Community Palette + * + * v1.0.0: Initial release - Tier 2 production (generated from Mocha v1.3.0) + * Catppuccin Mocha palette, border-radius architecture (ported from UniFi), + * custom checkboxes/radios, full grid styling, progress bar states, + * tags, markdown, date picker, usage bars, Firefox scrollbar. + * + * Catppuccin Macchiato Color Palette: + * + * ACCENT COLORS: + * - Rosewater: #f4dbd6 - Flamingo: #f0c6c6 + * - Pink: #f5bde6 - Mauve: #c6a0f6 (Primary Accent) + * - Red: #ed8796 - Maroon: #ee99a0 + * - Peach: #f5a97f - Yellow: #eed49f + * - Green: #a6da95 - Teal: #8bd5ca + * - Sky: #91d7e3 - Sapphire: #7dc4e4 + * - Blue: #8aadf4 - Lavender: #b7bdf8 + * + * NEUTRALS: + * - Text: #cad3f5 - Subtext 1: #b8c0e0 + * - Subtext 0: #a5adcb - Overlay 2: #939ab7 + * - Overlay 1: #8087a2 - Overlay 0: #6e738d + * - Surface 2: #5b6078 - Surface 1: #494d64 + * - Surface 0: #363a4f - Base: #24273a + * - Mantle: #1e2030 - Crust: #181926 + */ + +/* ===================================================== + CSS VARIABLES + ===================================================== */ +:root { + /* Catppuccin Mocha Tokens */ + --ctp-rosewater: #f4dbd6; + --ctp-flamingo: #f0c6c6; + --ctp-pink: #f5bde6; + --ctp-mauve: #c6a0f6; + --ctp-red: #ed8796; + --ctp-maroon: #ee99a0; + --ctp-peach: #f5a97f; + --ctp-yellow: #eed49f; + --ctp-green: #a6da95; + --ctp-teal: #8bd5ca; + --ctp-sky: #91d7e3; + --ctp-sapphire: #7dc4e4; + --ctp-blue: #8aadf4; + --ctp-lavender: #b7bdf8; + + --ctp-text: #cad3f5; + --ctp-subtext1: #b8c0e0; + --ctp-subtext0: #a5adcb; + --ctp-overlay2: #939ab7; + --ctp-overlay1: #8087a2; + --ctp-overlay0: #6e738d; + --ctp-surface2: #5b6078; + --ctp-surface1: #494d64; + --ctp-surface0: #363a4f; + --ctp-base: #24273a; + --ctp-mantle: #1e2030; + --ctp-crust: #181926; + + /* ProxMorph Semantic Variables */ + --pm-accent: var(--ctp-mauve); + --pm-bg-base: var(--ctp-base); + --pm-bg-surface: var(--ctp-surface0); + --pm-bg-elevated: var(--ctp-surface1); + --pm-text: var(--ctp-text); + --pm-text-dim: var(--ctp-subtext1); + --pm-success: var(--ctp-green); + --pm-warning: var(--ctp-yellow); + --pm-error: var(--ctp-red); + --pm-border: var(--ctp-surface1); + --pm-radius-sm: 4px; + --pm-radius-md: 6px; + --pm-radius-lg: 8px; + + /* Proxmox Widget Toolkit Mappings (REQUIRED) */ + --pwt-panel-background: var(--ctp-base); + --pwt-text-color: var(--ctp-text); + --pwt-gauge-default: var(--ctp-mauve); + --pwt-gauge-back: var(--ctp-surface1); + --pwt-gauge-warn: var(--ctp-yellow); + --pwt-gauge-crit: var(--ctp-red); + --pwt-chart-primary: var(--ctp-mauve); + --pwt-chart-grid-stroke: var(--ctp-surface1); + + /* On Accent text — style guide mandates Base for text on colored backgrounds */ + --ctp-on-accent: var(--ctp-base); + + /* Hover overlay — Overlay2@12% (neutral, per Catppuccin port conventions) */ + --ctp-hover-overlay: rgba(147, 154, 183, 0.12); + /* Selection overlay — Overlay2@25% (style guide: Selection Background → Overlay2 20-30%) */ + --ctp-select-overlay: rgba(147, 154, 183, 0.25); + /* Accent muted (for focus rings) */ + --ctp-accent-muted: rgba(198, 160, 246, 0.4); + --ctp-accent-subtle: rgba(198, 160, 246, 0.15); + + color-scheme: dark; +} + +/* ===================================================== + GLOBAL BORDER-RADIUS ARCHITECTURE + (Ported from UniFi theme — reset everything, selectively re-apply) + ===================================================== */ +.x-border-box, +.x-border-box * { + border-radius: var(--pm-radius-lg); +} + +/* Remove rounded corners from grids/tables/lists */ +.x-grid, +.x-grid *, +.x-grid-header-ct, +.x-grid-header-ct *, +.x-grid-view, +.x-grid-view *, +.x-column-header, +.x-column-header *, +.x-grid-item, +.x-grid-cell, +.x-grid-cell-inner, +.x-grid-row, +table, +table *, +tr, +td, +th, +.x-legend, +.x-legend *, +.x-legend-container, +.x-legend-container *, +.x-legend-item, +.x-legend-horizontal .x-legend-item, +.x-legend-vertical .x-legend-item, +.x-legend-horizontal .x-legend-item:first-child, +.x-legend-horizontal .x-legend-item:last-child, +.x-legend-vertical .x-legend-item:first-child, +.x-legend-vertical .x-legend-item:last-child, +.x-tool, +.x-tool-tool-el, +.x-tool-default, +.x-tool-img { + border-radius: 0 !important; +} + +/* Form elements - exclude from global radius */ +.x-form-item, +.x-form-item-default, +.x-form-item-body, +.x-form-item-body-default, +.x-form-text-field-body, +.x-form-text-field-body-default, +.x-form-fieldcontainer, +.x-field, +.x-field-default, +.x-form-type-text { + border-radius: 0 !important; +} + +/* Reset layout containers that clip elements with overflow:hidden + radius */ +.x-box-layout-ct, +.x-panel-bodyWrap, +.x-panel-bodyWrap-default, +.x-autocontainer-innerCt, +.x-autocontainer-outerCt, +.x-panel.x-tabpanel-child, +.x-panel.x-box-item, +.x-box-inner, +.x-box-target, +.x-container, +.x-container-default, +.x-window .x-panel-body, +.x-window .x-window-body, +.x-window .x-window-bodyWrap { + border-radius: 0 !important; +} + +/* Reset everything inside windows to 0 — then re-apply specific radii */ +.x-window *, +.x-window .x-autocontainer-innerCt, +.x-window .x-autocontainer-outerCt, +.x-window .x-form-layout-wrap, +.x-window .x-form-layout-auto-label, +.x-window .x-form-layout-colgroup, +.x-window .x-form-layout-column, +.x-window .x-field, +.x-window .x-form-item, +.x-window .x-form-item-body { + border-radius: 0 !important; +} + +/* Chart canvas — no radius on data area */ +.x-chart-grid, +.x-chart-axis, +canvas.x-surface, +.x-chart canvas, +canvas.x-surface-canvas, +.x-surface-canvas, +.x-draw-component canvas, +.proxmox-rrd-chart canvas, +svg.x-surface, +.x-draw-container, +.x-surface { + border-radius: 0 !important; +} + +/* Legend color marker (dot) — keep circular */ +.x-legend-item-marker { + border-radius: 50% !important; +} + +/* ===================================================== + RE-APPLY BORDER RADII (selective) + ===================================================== */ + +/* Windows */ +.x-window, +.x-window-default { + border-radius: var(--pm-radius-lg) !important; +} + +.x-window-header, +.x-window-header-default { + border-radius: var(--pm-radius-lg) var(--pm-radius-lg) 0 0 !important; +} + +.x-window .x-window-body, +.x-window-body-default { + border-radius: 0 !important; +} + +/* Buttons inside windows */ +.x-window .x-btn { + border-radius: var(--pm-radius-md) !important; +} + +/* Checkboxes inside windows */ +.x-window .x-form-checkbox { + border-radius: 3px !important; +} + +/* Form inputs inside windows */ +.x-window .x-form-trigger-wrap, +.x-window .x-form-trigger-wrap-default { + border-radius: var(--pm-radius-sm) !important; +} + +.x-window .x-form-text-wrap, +.x-window .x-form-text { + border-radius: var(--pm-radius-sm) 0 0 var(--pm-radius-sm) !important; +} + +.x-window .x-form-arrow-trigger { + border-radius: 0 var(--pm-radius-sm) var(--pm-radius-sm) 0 !important; +} + +/* Form trigger/text wrap — reset and re-apply */ +.x-form-trigger-wrap, +.x-form-trigger-wrap *, +.x-form-text-wrap, +.x-form-text-wrap *, +.x-form-text, +.x-form-trigger { + border-radius: 0 !important; +} + +.x-form-trigger-wrap, +.x-form-trigger-wrap-default { + border-radius: var(--pm-radius-sm) !important; + overflow: hidden !important; +} + +.x-form-text-wrap, +.x-form-text-wrap-default { + border-radius: var(--pm-radius-sm) 0 0 var(--pm-radius-sm) !important; +} + +.x-form-text, +.x-form-text-default { + border-radius: var(--pm-radius-sm) 0 0 var(--pm-radius-sm) !important; +} + +.x-form-trigger, +.x-form-trigger-default, +.x-form-arrow-trigger, +.x-form-arrow-trigger-default { + border-radius: 0 var(--pm-radius-sm) var(--pm-radius-sm) 0 !important; +} + +/* Dialog form content padding — vertical only (horizontal causes ExtJS overflow) */ +.x-window .x-tabpanel-child .x-autocontainer-innerCt { + padding: 12px 0 !important; +} + +/* Allow column panel bodies to show overflowed form content */ +.x-window .x-panel-body:not(.x-scroller) { + overflow: visible !important; +} + +/* Side padding on column panel bodies inside windows */ +.x-window .x-panel.x-box-item .x-panel-body { + padding: 0 4px !important; +} + +/* Constrain autocontainer width inside windows */ +.x-window .x-autocontainer-outerCt { + max-width: 100% !important; +} + +/* Fix window header/body width consistency */ +.x-window > .x-window-header, +.x-window > .x-window-body, +.x-window > .x-window-bodyWrap, +.x-window-bodyWrap > .x-window-body { + width: 100% !important; +} + +.x-window-header > .x-box-inner, +.x-window-header > .x-box-inner > .x-box-target { + width: 100% !important; +} + +.x-window-header-title { + width: auto !important; + flex: 1 !important; + max-width: calc(100% - 30px) !important; +} + +/* Boundlists */ +.x-boundlist { + border-radius: var(--pm-radius-md) !important; + overflow: hidden !important; +} + +/* ===================================================== + BASE / BODY + ===================================================== */ +.x-body, +.x-viewport > .x-body, +body.x-border-layout-ct, +div.x-border-layout-ct { + background-color: var(--ctp-base) !important; + color: var(--ctp-text) !important; +} + +/* ===================================================== + MASKS & OVERLAYS + ===================================================== */ +.x-mask { + background-color: rgba(24, 25, 38, 0.6) !important; + backdrop-filter: blur(4px); +} + +.x-mask-msg { + background-color: var(--ctp-mantle) !important; + border: 1px solid var(--ctp-surface1) !important; + border-radius: var(--pm-radius-lg) !important; +} + +.x-mask-msg-text { + color: var(--ctp-subtext0) !important; + filter: none !important; +} + +.x-css-shadow { + box-shadow: 0 8px 24px rgba(24, 25, 38, 0.6) !important; +} + +/* Loading indicators */ +.x-grid-row-loading, +.x-treelist-item-loading .x-treelist-item-icon, +.x-grid-tree-loading .x-tree-icon { + filter: invert(90%); +} + +/* ===================================================== + ICONS — Proxmox default colors for dark mode + ===================================================== */ + +/* General icon colors — neutral gray for dark backgrounds */ +.x-tree-icon-custom, +.x-grid-icon-custom, +.fa-tags::before, +.fa-file-o::before, +.fa-building::before, +.x-action-col-icon::before, +.fa-shield::before, +.fa-file-text-o::before, +.fa-clock-o::before, +.x-tab-icon-el-default, +.pve-icon-verify-lettering::after, +.x-tree-icon-leaf:not(.x-tree-icon-custom)::before, +.x-tree-icon-parent:not(.x-tree-icon-custom)::before, +.x-tree-icon-parent-expanded:not(.x-tree-icon-custom)::before, +.x-grid-filters-filtered-column .x-column-header-text::after { + color: var(--ctp-overlay2) !important; +} + +/* Folder icons — invert for dark mode */ +.x-tree-icon-parent:not(.x-tree-icon-custom)::before, +.x-tree-icon-parent-expanded:not(.x-tree-icon-custom)::before { + filter: invert(90%); +} + +/* Various image-based icons — invert for visibility */ +.fa-ceph::before, +.fa-sdn::before, +.fa-network-wired::before, +.pve-itype-treelist-item-icon-cdrom, +.fa-chevron-right::before, +.x-grid-row-console, +.x-box-scroller-toolbar-default.x-box-scroller, +.x-tree-elbow-img, +.pve-itype-icon-qemu, +.x-tree-node-computer, +.x-grid-tree-node-expanded .x-tree-node-computer, +.pbs-icon-tape, +.pbs-icon-tape-drive, +.x-tree-icon-leaf:not(.x-tree-icon-custom), +.x-tree-icon-parent:not(.x-tree-icon-custom), +.x-tree-icon-parent-expanded:not(.x-tree-icon-custom) { + filter: invert(90%); +} + +/* Hardware icons */ +.pve-itype-icon-cpu, +.pve-itype-icon-cdrom, +.pve-itype-icon-memory, +.pve-itype-icon-pci, +.pve-itype-icon-serial, +.pve-itype-icon-die, +.pmx-itype-icon-processor, +.pmx-itype-icon-memory, +.pve-itype-icon-storage, +.x-tree-node-harddisk, +.x-grid-tree-node-expanded .x-tree-node-harddisk { + filter: invert(100%); +} + +/* Hardware icons — counter-invert for non-SVG icon cells */ +td.pve-itype-icon-storage .x-grid-cell-inner, +td.x-tree-node-harddisk .x-grid-cell-inner { + filter: invert(100%) !important; +} + +/* Hardware icons — hide inverted borders for non-SVG icon cells */ +td.pve-itype-icon-storage, +td.x-tree-node-harddisk { + border-color: transparent !important; +} + +/* Hardware grid icons — mask-image renders SVG icons in theme text color + Replaces filter:invert approach for pve-itype-icon-* and pmx-itype-icon-* grid cells */ +td.pve-itype-icon-cpu, +td.pve-itype-icon-cdrom, +td.pve-itype-icon-memory, +td.pve-itype-icon-pci, +td.pve-itype-icon-serial, +td.pve-itype-icon-die, +td.pmx-itype-icon-processor, +td.pmx-itype-icon-memory { + filter: none !important; + background-image: none !important; + padding-left: 0 !important; + border-color: transparent !important; +} + +td.pve-itype-icon-cpu .x-grid-cell-inner, +td.pve-itype-icon-cdrom .x-grid-cell-inner, +td.pve-itype-icon-memory .x-grid-cell-inner, +td.pve-itype-icon-pci .x-grid-cell-inner, +td.pve-itype-icon-serial .x-grid-cell-inner, +td.pve-itype-icon-die .x-grid-cell-inner, +td.pmx-itype-icon-processor .x-grid-cell-inner, +td.pmx-itype-icon-memory .x-grid-cell-inner { + padding-left: 3px !important; +} + +td.pve-itype-icon-cpu .x-grid-cell-inner::before, +td.pve-itype-icon-cdrom .x-grid-cell-inner::before, +td.pve-itype-icon-memory .x-grid-cell-inner::before, +td.pve-itype-icon-pci .x-grid-cell-inner::before, +td.pve-itype-icon-serial .x-grid-cell-inner::before, +td.pve-itype-icon-die .x-grid-cell-inner::before, +td.pmx-itype-icon-processor .x-grid-cell-inner::before, +td.pmx-itype-icon-memory .x-grid-cell-inner::before { + content: '' !important; + display: inline-block !important; + width: 18px !important; + height: 14px !important; + vertical-align: middle !important; + margin-right: 10px !important; + background-color: currentColor !important; + -webkit-mask-size: contain !important; + mask-size: contain !important; + -webkit-mask-repeat: no-repeat !important; + mask-repeat: no-repeat !important; + -webkit-mask-position: center !important; + mask-position: center !important; +} + +td.pve-itype-icon-cpu .x-grid-cell-inner::before { + -webkit-mask-image: url('/pve2/images/icon-cpu.svg') !important; + mask-image: url('/pve2/images/icon-cpu.svg') !important; +} + +td.pve-itype-icon-memory .x-grid-cell-inner::before { + -webkit-mask-image: url('/pve2/images/icon-memory.svg') !important; + mask-image: url('/pve2/images/icon-memory.svg') !important; +} + +td.pve-itype-icon-cdrom .x-grid-cell-inner::before { + -webkit-mask-image: url('/pve2/images/icon-cd-drive.svg') !important; + mask-image: url('/pve2/images/icon-cd-drive.svg') !important; +} + +td.pve-itype-icon-pci .x-grid-cell-inner::before { + -webkit-mask-image: url('/pve2/images/icon-pci.svg') !important; + mask-image: url('/pve2/images/icon-pci.svg') !important; +} + +td.pve-itype-icon-serial .x-grid-cell-inner::before { + -webkit-mask-image: url('/pve2/images/icon-serial.svg') !important; + mask-image: url('/pve2/images/icon-serial.svg') !important; +} + +td.pve-itype-icon-die .x-grid-cell-inner::before { + -webkit-mask-image: url('/pve2/images/icon-die.svg') !important; + mask-image: url('/pve2/images/icon-die.svg') !important; +} + +td.pmx-itype-icon-processor .x-grid-cell-inner::before { + -webkit-mask-image: url('../images/icon-cpu.svg') !important; + mask-image: url('../images/icon-cpu.svg') !important; +} + +td.pmx-itype-icon-memory .x-grid-cell-inner::before { + -webkit-mask-image: url('../images/icon-ram.svg') !important; + mask-image: url('../images/icon-ram.svg') !important; +} + + +/* Icon overlays — default */ +.x-tree-icon-custom::after, +.x-grid-icon-custom::after { + color: var(--ctp-overlay2) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* RUNNING VMs/CTs — Catppuccin Green */ +.x-tree-icon-custom.running::after, +.x-grid-icon-custom.running::after, +.x-treelist-item-icon.running::after { + color: var(--ctp-green) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* ONLINE state — Green */ +.x-tree-icon-custom.online::after, +.x-grid-icon-custom.online::after { + color: var(--ctp-green) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* Stopped/offline — Overlay1 (muted gray) */ +.x-tree-icon-custom.stopped, +.x-tree-icon-custom.offline, +.x-grid-icon-custom.stopped, +.x-grid-icon-custom.offline { + color: var(--ctp-overlay1) !important; +} + +/* Unknown state — Overlay1 */ +.x-tree-icon-custom.unknown::after, +.x-grid-icon-custom.unknown::after { + color: var(--ctp-overlay1) !important; +} + +/* ERROR states — Catppuccin Red */ +.x-tree-icon-custom.error::after, +.x-tree-icon-custom.offline::after, +.x-tree-icon-custom.ha-error::after, +.x-grid-icon-custom.error::after, +.x-grid-icon-custom.offline::after, +.x-grid-icon-custom.ha-error::after { + color: var(--ctp-red) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* PAUSED/SUSPENDED — Catppuccin Peach */ +.x-tree-icon-custom.paused::after, +.x-tree-icon-custom.suspended::after, +.x-tree-icon-custom.lock-suspending::after, +.x-grid-icon-custom.paused::after, +.x-grid-icon-custom.suspended::after, +.x-grid-icon-custom.lock-suspending::after { + color: var(--ctp-peach) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* PENDING/WARNING states — Catppuccin Yellow */ +.x-tree-icon-custom.pending::after, +.x-tree-icon-custom.io-error::after, +.x-tree-icon-custom.internal-error::after, +.x-tree-icon-custom.guest-panicked::after, +.x-grid-icon-custom.pending::after, +.x-grid-icon-custom.io-error::after, +.x-grid-icon-custom.internal-error::after, +.x-grid-icon-custom.guest-panicked::after { + color: var(--ctp-yellow) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* HA MAINTENANCE — Catppuccin Sky */ +.x-tree-icon-custom.ha-maintenance::after, +.x-grid-icon-custom.ha-maintenance::after { + color: var(--ctp-sky) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* Locked icons */ +.x-tree-icon-custom.locked::after, +.x-tree-icon-custom.lock-backup::after, +.x-tree-icon-custom.lock-migrate::after, +.x-tree-icon-custom.lock-suspended::after, +.x-grid-icon-custom.locked::after, +.x-grid-icon-custom.lock-backup::after, +.x-grid-icon-custom.lock-migrate::after, +.x-grid-icon-custom.lock-suspended::after { + color: var(--ctp-overlay2) !important; +} + +/* LXC/QEMU type indicators */ +.x-tree-icon-custom.lxc::after, +.x-tree-icon-custom.qemu::after, +.x-grid-icon-custom.lxc::after, +.x-grid-icon-custom.qemu::after { + background-color: transparent; + color: var(--ctp-overlay1) !important; +} + +.x-treelist-item-icon.lxc::after, +.x-treelist-item-icon.qemu::after { + background-color: transparent; + color: var(--ctp-overlay1) !important; +} + +/* Tree expander arrows */ +.x-tree-arrows .x-tree-expander { + filter: brightness(200%); +} + +/* Cancel sprite-inversion on custom controls (checkboxes/radios handled via CSS) */ +.x-form-checkbox-default, +.x-form-radio-default, +.x-column-header-checkbox .x-column-header-checkbox::after, +.x-grid-checkcolumn::after, +.x-menu-item-checked .x-menu-item-icon-default.x-menu-item-checkbox, +.x-menu-item-unchecked .x-menu-item-icon-default.x-menu-item-checkbox { + filter: none !important; +} + +/* ===================================================== + PANELS & HEADERS + ===================================================== */ +.x-panel, +.x-panel-default { + border-radius: var(--pm-radius-lg) !important; + padding: 0 !important; +} + +/* Column panels — native stacked layout (Issue #23 fix) */ +.x-panel.x-column { + padding: 5px !important; + margin: 0 !important; + max-width: none !important; + box-sizing: border-box !important; +} + +/* Column panel card styling — borders for summary + chart panels */ +.x-panel.x-panel-default.x-column { + border: 1px solid var(--ctp-surface1) !important; + border-radius: var(--pm-radius-lg) !important; + overflow: hidden !important; +} + +/* Guest status + Notes panel borders */ +[id^="pveGuestStatusView-"].x-panel, +[id^="pveLxcStatusView-"].x-panel, +[id^="pveQemuStatusView-"].x-panel, +[id^="pmxNotesView-"].x-panel { + border: 1px solid var(--ctp-surface1) !important; + border-radius: var(--pm-radius-lg) !important; +} + +.x-panel-body, +.x-panel-body-default { + background-color: var(--ctp-base) !important; + color: var(--ctp-text) !important; + border: none !important; +} + +/* Panel headers — bottom border only */ +.x-panel-header, +.x-panel-header-default { + background-color: var(--ctp-mantle) !important; + border: none !important; + border-bottom: 1px solid var(--ctp-surface1) !important; + border-radius: var(--pm-radius-lg) var(--pm-radius-lg) 0 0 !important; + margin: 0 !important; + padding: 8px 12px !important; + width: 100% !important; + box-sizing: border-box !important; + overflow: visible !important; +} + +/* Title text — prevent border-radius clipping */ +.x-title-text, +.x-title-text-default { + overflow: visible !important; +} + +.x-panel-bodyWrap, +.x-panel-bodyWrap-default { + margin: 0 !important; + padding: 0 !important; + overflow: visible !important; +} + +/* Remove borders from nested panels */ +.x-panel-body > .x-box-layout-ct, +.x-panel-body > .x-container, +.x-panel-body > .x-box-inner, +[id*="pmxGauge"] { + border: none !important; +} + +.x-panel-header-title-default, +.x-window-header-title-default { + color: var(--ctp-text) !important; +} + +.x-panel-header-default .x-tool-tool-el { + background-color: transparent; +} + +.x-tool-img { + filter: brightness(175%); +} + +.x-tool-over .x-tool-img { + filter: brightness(200%); +} + +/* Resource tree — panel body border */ +div[id^="pveResourceTree-"][id$="-body"] { + border-color: var(--ctp-base) !important; +} + +/* Resource tree — remove row separators */ +[id^="pveResourceTree-"].x-tree-panel td.x-grid-cell, +[id^="pveResourceTree-"].x-tree-panel .x-grid-td, +[id^="pveResourceTree-"].x-tree-panel .x-grid-cell { + border-bottom: none !important; +} + +/* Resource tree — row spacing */ +div[id^="pveResourceTree"] .x-grid-cell { + padding-top: 3px !important; + padding-bottom: 3px !important; +} + +/* Summary/stats panel radius overrides */ +.pveStatusPanel, +.x-panel-default-framed, +.x-panel-body-default-framed { + border-radius: 12px !important; +} + +.x-panel-header-default-framed { + border-radius: 12px 12px 0 0 !important; +} + +/* Column widget panel radius */ +.x-panel.x-column > .x-panel-bodyWrap > .x-panel-body.x-panel-body-default { + border-radius: var(--pm-radius-lg) !important; +} + +/* ===================================================== + SPLITTERS / SEPARATORS + ===================================================== */ +.x-splitter-vertical { + background-color: transparent !important; + border-left: 1px solid var(--ctp-surface1) !important; + border-right: none !important; + width: 1px !important; +} + +.x-splitter-horizontal { + background-color: var(--ctp-crust) !important; + border-top: 1px solid var(--ctp-surface1) !important; +} + +.x-splitter { + background-color: var(--ctp-crust) !important; +} + +.x-keyboard-mode .x-splitter-focus::after { + border-color: var(--ctp-mauve) !important; +} + +.x-layout-split-bottom { + opacity: 0.7; +} + +/* Toolbox tree (pve-nav) right border — full height */ +.pve-toolbar-bg { + border-right: 1px solid var(--ctp-surface1) !important; + z-index: 3 !important; +} + +.x-treelist.x-treelist-pve-nav { + border-right: none !important; +} + +/* ===================================================== + TOOLBARS + ===================================================== */ +.x-toolbar, +.x-toolbar-default { + background-color: var(--ctp-base) !important; + border-color: var(--ctp-surface1) !important; +} + +.x-toolbar-default.x-docked-top { + border: none !important; + border-bottom: 1px solid var(--ctp-surface1) !important; +} + +.x-toolbar-default .x-toolbar-separator { + border-color: var(--ctp-surface1); +} + +.x-toolbar-text-default { + color: var(--ctp-subtext0); +} + +/* ===================================================== + PRIMARY BUTTONS — Catppuccin Mauve + ===================================================== */ +.x-btn-default-small { + background-color: var(--ctp-mauve) !important; + border: 1px solid rgba(198, 160, 246, 0.4) !important; + border-radius: var(--pm-radius-md) !important; + transition: background-color 0.15s ease, box-shadow 0.15s ease !important; +} + +.x-btn-default-small .x-btn-inner { + color: var(--ctp-on-accent) !important; + font-weight: 600 !important; +} + +.x-btn-default-small .x-btn-icon-el { + color: var(--ctp-on-accent) !important; +} + +.x-btn-default-small.x-btn-over, +.x-keyboard-mode .x-btn-default-small.x-btn-focus { + background-color: #d0b0f8 !important; + box-shadow: 0 0 0 3px var(--ctp-accent-subtle) !important; +} + +.x-btn-default-small.x-btn.x-btn-disabled { + background-color: var(--ctp-mauve) !important; + opacity: 0.4; +} + +.x-btn-default-small.x-btn.x-btn-pressed { + background-color: #b48cf4 !important; +} + +/* Button height consistency — 28px with vertical centering */ +/* Exclude tag edit buttons (display:none when hidden, :has(.fa-check) for checkmark) */ +.x-btn.x-btn-default-small:not(.x-btn-default-toolbar-small):not([style*="display: none"]):not([style*="display:none"]):not(:has(.fa-check)) { + height: 28px !important; + min-height: 28px !important; + display: flex !important; + align-items: center !important; + padding: 3px 8px !important; +} + +/* Fix button inner element centering for proper icon alignment (issue #17) */ +.x-btn.x-btn-default-small:not(.x-btn-default-toolbar-small):not([style*="display: none"]):not([style*="display:none"]):not(:has(.fa-check)) .x-btn-wrap { + display: flex !important; + align-items: center !important; +} + +.x-btn.x-btn-default-small:not(.x-btn-default-toolbar-small):not([style*="display: none"]):not([style*="display:none"]):not(:has(.fa-check)) .x-btn-inner { + display: flex !important; + align-items: center !important; +} + +/* Fix dropdown arrows on split/arrow buttons */ +.x-btn-wrap.x-btn-arrow-right::after, +.x-btn-wrap.x-btn-split-right::after { + height: 16px !important; + min-height: 16px !important; + width: 20px !important; + display: flex !important; + align-items: center !important; +} + +/* Fix icon-only buttons — hide   inner element when button has no text */ +.x-btn-no-text .x-btn-inner, +.x-btn-button.x-btn-no-text .x-btn-inner, +.x-btn-button-default-toolbar-small.x-btn-no-text .x-btn-inner-default-toolbar-small, +.x-btn-button-default-small.x-btn-no-text .x-btn-inner-default-small, +.x-btn-button-default-small.x-btn-no-text > .x-btn-inner-default-small { + display: none !important; +} + +/* Specific fix for fa-desktop icon (Create VM) — visually bottom-heavy */ +.x-btn-icon-el.fa-desktop { + transform: translateY(1.1px) !important; +} + +/* ===================================================== + SECONDARY / TOOLBAR BUTTONS + ===================================================== */ +.x-btn-default-toolbar-small { + background-color: var(--ctp-surface0) !important; + border: 1px solid var(--ctp-surface1) !important; + border-radius: var(--pm-radius-md) !important; + transition: background-color 0.15s ease, border-color 0.15s ease !important; +} + +.x-btn-default-toolbar-small .x-btn-inner-default-toolbar-small, +.x-btn-default-toolbar-small .x-btn-icon-el-default-toolbar-small { + color: var(--ctp-text) !important; +} + +.x-btn-default-toolbar-small .x-btn-wrap-default-toolbar-small.x-btn-arrow-right::after, +.x-btn-default-toolbar-small .x-btn-wrap-default-toolbar-small.x-btn-split-right::after { + filter: brightness(150%); +} + +.x-btn-default-toolbar-small.x-btn-over, +.x-keyboard-mode .x-btn-default-toolbar-small.x-btn-focus { + background-color: var(--ctp-surface1) !important; + border-color: var(--ctp-surface2) !important; +} + +.x-btn-default-toolbar-small.x-btn.x-btn-disabled { + background-color: var(--ctp-surface0) !important; + opacity: 0.4; +} + +.x-btn-default-toolbar-small.x-btn.x-btn-menu-active, +.x-btn-default-toolbar-small.x-btn.x-btn-pressed { + background-color: var(--ctp-mauve) !important; + border-color: var(--ctp-mauve) !important; + padding: 4px 8px !important; /* Fix #30: prevent width change on dropdown */ +} + +.x-btn-default-toolbar-small.x-btn.x-btn-pressed .x-btn-inner-default-toolbar-small, +.x-btn-default-toolbar-small.x-btn.x-btn-pressed .x-btn-icon-el-default-toolbar-small, +.x-btn-default-toolbar-small.x-btn.x-btn-pressed .x-btn-inner-default-small, +.x-btn-default-toolbar-small.x-btn.x-btn-pressed .x-btn-icon-el-default-small { + color: var(--ctp-on-accent) !important; +} + +/* Segmented buttons */ +.x-segmented-button { + border-radius: var(--pm-radius-md) !important; +} + +.x-segmented-button .x-btn, +.x-segmented-button .x-btn-default-small, +.x-segmented-button .x-btn-inner, +.x-segmented-button .x-btn-wrap { + border-radius: var(--pm-radius-md) !important; +} + +/* Inline buttons (Documentation, Help) */ +.proxmox-inline-button { + height: 28px !important; + min-height: 28px !important; + display: flex !important; + align-items: center !important; + padding: 3px 8px !important; + background-color: var(--ctp-surface0) !important; + border: 1px solid var(--ctp-surface1) !important; + border-radius: var(--pm-radius-md) !important; + color: var(--ctp-text) !important; + transition: background-color 0.15s ease !important; +} + +.proxmox-inline-button:hover, +.proxmox-inline-button.x-btn-over { + background-color: var(--ctp-surface1) !important; + border-color: var(--ctp-overlay0) !important; +} + +.proxmox-inline-button:active, +.proxmox-inline-button.x-btn-pressed { + background-color: var(--ctp-surface2) !important; +} + +.proxmox-inline-button .x-btn-inner, +.proxmox-inline-button .x-btn-icon-el { + color: var(--ctp-text) !important; +} + +/* Pressed/active inline buttons get accent bg from toolbar rules — use on-accent text */ +.proxmox-inline-button.x-btn-pressed .x-btn-inner, +.proxmox-inline-button.x-btn-pressed .x-btn-icon-el, +.proxmox-inline-button.x-btn-menu-active .x-btn-inner, +.proxmox-inline-button.x-btn-menu-active .x-btn-icon-el { + color: var(--ctp-on-accent) !important; +} + +/* ===================================================== + FORM ELEMENTS + ===================================================== */ +.x-form-trigger-default { + background-color: var(--ctp-surface0) !important; +} + +.x-form-text-default { + background-color: var(--ctp-surface0) !important; + color: var(--ctp-text) !important; + border-radius: var(--pm-radius-sm) !important; +} + +.x-form-trigger-wrap, +.x-form-trigger-wrap-default { + border-color: var(--ctp-surface1) !important; + background-color: var(--ctp-surface0) !important; + border-radius: var(--pm-radius-sm) !important; + transition: border-color 0.15s ease !important; +} + +.x-form-trigger-wrap-default.x-form-trigger-wrap-focus { + border-color: var(--ctp-mauve) !important; + box-shadow: 0 0 0 3px var(--ctp-accent-subtle) !important; +} + +.x-form-item-label-default, +.x-form-cb-label-default { + color: var(--ctp-text) !important; +} + +.x-form-display-field-default { + color: var(--ctp-subtext0) !important; + border-radius: var(--pm-radius-md) !important; +} + +.x-form-spinner-default { + background-color: var(--ctp-surface0) !important; +} + +.x-fieldset, +.x-fieldset-default { + border-color: var(--ctp-surface1) !important; + border-radius: var(--pm-radius-lg) !important; +} + +.x-fieldset-header-default > .x-fieldset-header-text { + color: var(--ctp-text) !important; +} + +/* ===================================================== + CHECKBOXES & RADIOS — Catppuccin styled + ===================================================== */ + +/* Base: remove sprite, styled as custom control */ +.x-form-checkbox, .x-form-checkbox-default, +.x-form-radio, .x-form-radio-default { + background-image: none !important; + background-color: var(--ctp-surface0) !important; + border: 1.5px solid var(--ctp-overlay0) !important; + width: 16px !important; + height: 16px !important; + display: inline-block !important; + box-sizing: border-box !important; + cursor: pointer !important; + transition: border-color 0.12s ease, background-color 0.12s ease !important; +} + +/* Checkbox: rounded square */ +.x-form-checkbox, .x-form-checkbox-default { + border-radius: 3px !important; +} + +/* Radio: circle + ::after inner dot */ +.x-form-radio, .x-form-radio-default { + border-radius: 50% !important; + position: relative !important; + transform: translateZ(0) !important; + box-shadow: inset 0 0 0 0 transparent !important; +} + +.x-form-radio::after { + content: '' !important; + position: absolute !important; + top: 50% !important; + left: 50% !important; + width: 7px !important; + height: 7px !important; + border-radius: 50% !important; + background: transparent !important; + transform: translate(-50%, -50%) scale(0) !important; + transition: transform 0.15s ease, background 0.15s ease !important; + pointer-events: none !important; +} + +/* Hover */ +.x-form-checkbox:hover, .x-form-checkbox-default:hover, +.x-form-cb-wrap:hover .x-form-checkbox { + border-color: var(--ctp-mauve) !important; +} + +.x-form-radio:hover, .x-form-radio-default:hover, +.x-form-cb-wrap:hover .x-form-radio { + border-color: var(--ctp-mauve) !important; +} + +/* CHECKED checkbox — Mauve fill + white SVG checkmark */ +.x-form-cb-checked .x-form-checkbox, +.x-form-cb-checked .x-form-checkbox-default { + background-color: var(--ctp-mauve) !important; + border-color: var(--ctp-mauve) !important; + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 8'%3E%3Cpath d='M1 4l3 3 5-6' fill='none' stroke='%2324273a' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") !important; + background-repeat: no-repeat !important; + background-position: center !important; + background-size: 9px 7px !important; +} + +/* SELECTED radio — Mauve dot */ +.x-form-cb-checked .x-form-radio, +.x-form-cb-checked .x-form-radio-default { + border-color: var(--ctp-mauve) !important; + background-color: var(--ctp-base) !important; +} + +.x-form-cb-checked .x-form-radio::after { + background: var(--ctp-mauve) !important; + transform: translate(-50%, -50%) scale(1) !important; +} + +/* ===================================================== + BOUNDLIST / DROPDOWNS + ===================================================== */ +.x-boundlist { + background-color: var(--ctp-mantle) !important; + border: 1px solid var(--ctp-surface1) !important; + border-radius: var(--pm-radius-md) !important; + box-shadow: 0 8px 24px rgba(24, 25, 38, 0.7) !important; + padding: 2px !important; + overflow: hidden !important; +} + +.x-boundlist-item { + background-color: transparent !important; + color: var(--ctp-text) !important; + border-radius: var(--pm-radius-sm) !important; + padding: 2px 6px !important; + line-height: normal !important; + border: none !important; + cursor: pointer !important; + outline: none !important; + box-shadow: none !important; +} + +.x-boundlist-selected { + background-color: var(--ctp-select-overlay) !important; + color: var(--ctp-text) !important; +} + +.x-boundlist-item-over { + background-color: var(--ctp-hover-overlay) !important; +} + +/* ===================================================== + GRIDS / TABLES + ===================================================== */ +.x-grid, +.x-grid-view { + border-radius: 0 !important; +} + +.x-column-header { + border-color: var(--ctp-surface1) !important; + background-color: transparent !important; +} + +.x-column-header-inner, +.x-column-header-text { + color: var(--ctp-text) !important; + font-weight: 600 !important; +} + +.x-column-header-trigger { + border-color: var(--ctp-surface1) !important; +} + +.x-grid-item, +.x-column-header-default, +.x-grid-cell-row-numberer { + color: var(--ctp-text) !important; + background-color: var(--ctp-base) !important; +} + +.x-grid-cell-special { + border-color: var(--ctp-surface1) !important; +} + +.x-grid-group-hd { + background-color: var(--ctp-base) !important; + border-color: var(--ctp-surface1) !important; +} + +.x-grid-group-title { + color: var(--ctp-text) !important; +} + +.x-grid-header-ct { + background-color: var(--ctp-mantle) !important; + border: 1px solid var(--ctp-surface0) !important; + border-radius: var(--pm-radius-lg) var(--pm-radius-lg) 0 0 !important; +} + +.x-grid-item-alt { + background-color: var(--ctp-crust) !important; +} + +.x-grid-with-row-lines .x-grid-item { + border-color: var(--ctp-surface0) !important; +} + +.x-grid-cell { + border-bottom: 1px solid rgba(69, 71, 90, 0.4) !important; +} + +.x-grid-item-over, +.x-grid-with-row-lines .x-grid-item.x-grid-item-over { + background-color: var(--ctp-hover-overlay) !important; +} + +.x-grid-item-selected, +.x-grid-with-row-lines .x-grid-item.x-grid-item-selected { + background-color: var(--ctp-select-overlay) !important; +} + +.x-column-header-over, +.x-column-header-open { + background-color: var(--ctp-hover-overlay) !important; +} + +.x-column-header-sort-ASC, +.x-column-header-sort-DESC { + background-color: var(--ctp-hover-overlay) !important; +} + +.x-grid-row-summary .x-grid-cell, +.x-grid-row-summary .x-grid-rowwrap, +.x-grid-row-summary .x-grid-cell-rowbody { + background-color: var(--ctp-base) !important; + border-color: var(--ctp-surface1); +} + +.x-grid-with-col-lines .x-grid-cell, +.x-grid-with-col-lines .x-grid-item-over .x-grid-cell, +.x-grid-with-col-lines .x-grid-item-selected .x-grid-cell { + border-color: var(--ctp-surface1) !important; +} + +.x-dd-drag-proxy { + background-color: var(--ctp-mantle); + border-color: var(--ctp-surface1); + color: var(--ctp-text); +} + +.x-keyboard-mode .x-grid-item-focused { + background-color: var(--ctp-hover-overlay) !important; + color: var(--ctp-text) !important; +} + +/* Remove blue outline from focused/selected items in resource tree */ +.x-keyboard-mode .x-grid-item-focused .x-grid-cell-inner::before, +.x-keyboard-mode .x-grid-item-selected .x-grid-cell-inner::before, +.x-grid-item-selected .x-grid-cell-inner::before, +.x-grid-item-focused .x-grid-cell-inner::before, +[id^="pveResourceTree"] .x-grid-item-selected .x-grid-cell-inner::before, +[id^="pveResourceTree"] .x-grid-item-focused .x-grid-cell-inner::before { + content: none !important; + display: none !important; + border: none !important; +} + +.x-grid-empty { + background-color: var(--ctp-base) !important; + color: var(--ctp-subtext0) !important; +} + +/* Grid info (pve-info-grid) and RRD view */ +.pve-info-grid { + border-radius: 12px !important; +} + +.pve-rrdview, +.rrdview { + border-radius: 12px !important; +} + +.pve-summary-status, +.x-container .pve-status { + border-radius: var(--pm-radius-lg) !important; +} + +[id^="pveGuestStatusView-"][id$="-body"], +[id^="pmxNotesView-"] .x-panel-body { + border-radius: var(--pm-radius-lg) !important; +} + +.x-panel-default[id*="notes"], +.pve-notes-view { + border-radius: var(--pm-radius-lg) !important; +} + +/* Floating grid pickers (storage/ISO selectors) */ +.x-layer.x-grid .x-grid-view, +.x-panel.x-layer.x-grid .x-grid-view, +.x-panel.x-layer.x-grid, +.x-layer.x-panel.x-grid { + border-radius: var(--pm-radius-sm) !important; +} + +.x-layer.x-grid .x-grid-item-over, +.x-layer.x-grid .x-grid-item-selected, +.x-panel.x-layer.x-grid .x-grid-item-over, +.x-panel.x-layer.x-grid .x-grid-item-selected { + border-radius: var(--pm-radius-sm) !important; + outline: none !important; + box-shadow: none !important; +} + +.x-layer.x-grid .x-grid-item-over td, +.x-layer.x-grid .x-grid-item-selected td, +.x-layer.x-grid .x-grid-item-over .x-grid-cell, +.x-layer.x-grid .x-grid-item-selected .x-grid-cell, +.x-panel.x-layer.x-grid .x-grid-item-over td, +.x-panel.x-layer.x-grid .x-grid-item-selected td, +.x-panel.x-layer.x-grid .x-grid-item-over .x-grid-cell, +.x-panel.x-layer.x-grid .x-grid-item-selected .x-grid-cell { + border-radius: 0 !important; +} + +.x-layer.x-grid .x-grid-item-over td:first-child, +.x-layer.x-grid .x-grid-item-selected td:first-child, +.x-panel.x-layer.x-grid .x-grid-item-over td:first-child, +.x-panel.x-layer.x-grid .x-grid-item-selected td:first-child { + border-radius: var(--pm-radius-sm) 0 0 var(--pm-radius-sm) !important; +} + +.x-layer.x-grid .x-grid-item-over td:last-child, +.x-layer.x-grid .x-grid-item-selected td:last-child, +.x-panel.x-layer.x-grid .x-grid-item-over td:last-child, +.x-panel.x-layer.x-grid .x-grid-item-selected td:last-child { + border-radius: 0 var(--pm-radius-sm) var(--pm-radius-sm) 0 !important; +} + +/* ===================================================== + MENUS + ===================================================== */ +.x-menu, +.x-menu-default { + background-color: var(--ctp-crust) !important; + border: 1px solid var(--ctp-surface0) !important; + border-radius: var(--pm-radius-lg) !important; + box-shadow: 0 8px 24px rgba(24, 25, 38, 0.8) !important; + padding: 2px !important; + overflow: hidden !important; +} + +.x-menu-body-default { + background-color: transparent !important; + padding: 4px !important; +} + +.x-menu-header { + background-color: transparent !important; + color: var(--ctp-text) !important; +} + +/* Menu icon separator — hide */ +.x-menu-icon-separator-default { + display: none !important; +} + +/* Menu item layout (flexbox reordering) */ +.x-menu-item-default > .x-menu-item-link { + display: flex !important; + align-items: center !important; + flex-direction: row !important; + gap: 4px !important; + justify-content: flex-start !important; + flex-wrap: nowrap !important; + border-radius: var(--pm-radius-md) !important; + padding: 4px 8px !important; + line-height: 20px !important; + cursor: pointer !important; + outline: none !important; + box-shadow: none !important; + white-space: nowrap !important; + text-decoration: none !important; +} + +.x-menu-item-text-default { + color: var(--ctp-text) !important; + font-size: 13px !important; + order: 1 !important; + margin-left: 0 !important; + text-align: left !important; + line-height: 20px !important; + display: inline-flex !important; + align-items: center !important; + flex: 1 1 auto !important; + width: auto !important; + white-space: nowrap !important; +} + +.x-menu-item-icon-default { + color: var(--ctp-subtext0) !important; + order: -1 !important; + position: relative !important; + float: none !important; + margin-right: 8px !important; + margin-left: 0 !important; + left: auto !important; + top: auto !important; + width: 16px !important; + text-align: center !important; + display: inline-flex !important; + align-items: center !important; + justify-content: center !important; + height: 20px !important; + line-height: 20px !important; + vertical-align: middle !important; + flex: 0 0 16px !important; + align-self: center !important; +} + +.x-menu-item-arrow, +.x-menu-item-arrow-default { + order: 2 !important; + margin-left: auto !important; +} + +.x-menu-item-default.x-menu-item-separator { + background-color: var(--ctp-surface0) !important; + border: none !important; + height: 1px !important; + margin: 6px 4px !important; +} + +.x-menu-item-default.x-menu-item-focus, +.x-menu-item-default.x-menu-item-active, +.x-menu-item:hover { + background-color: var(--ctp-surface0) !important; + color: var(--ctp-text) !important; + border-radius: var(--pm-radius-md) !important; +} + +.x-menu-item-active .x-menu-item-text-default, +.x-menu-item-focus .x-menu-item-text-default { + color: var(--ctp-text) !important; +} + +.x-menu-item-active .x-menu-item-icon-default, +.x-menu-item-focus .x-menu-item-icon-default { + color: var(--ctp-lavender) !important; +} + +/* ===================================================== + PROGRESS BARS + ===================================================== */ + +/* Fix: Widget containers need overflow visible to not clip progress bars */ +.x-container[id^="pmxInfoWidget"], +.x-container.x-box-layout-ct { + overflow: visible !important; +} + +.x-progress, +.x-progress-default { + background-color: var(--ctp-surface0) !important; + border-radius: 5px !important; +} + +.x-progress-default .x-progress-bar-default { + background-color: var(--ctp-mauve) !important; + border-radius: 5px !important; + transition: width 0.4s ease !important; +} + +.x-progress-default .x-progress-text { + color: var(--ctp-text) !important; +} + +/* Text overlaid on the progress bar fill — use on-accent for contrast against Mauve/Yellow/Red fills */ +.x-progress-bar .x-progress-text { + color: var(--ctp-on-accent) !important; +} + +.x-progress.warning .x-progress-bar { + background-color: var(--ctp-yellow) !important; +} + +.x-progress.critical .x-progress-bar { + background-color: var(--ctp-red) !important; +} + +/* ===================================================== + TABS — Catppuccin underline style + Flat tabs with Mauve underline on active tab + ===================================================== */ +.x-tab-bar, +.x-tab-bar-default { + background-color: var(--ctp-base) !important; + border-radius: 0 !important; + border-bottom: 1px solid var(--ctp-surface1) !important; + padding-bottom: 0 !important; +} + +/* Overflow visible for the underline indicator */ +.x-tab-bar .x-box-inner, +.x-tab-bar .x-box-target, +.x-tab-bar-body, +.x-tab-bar-body-default { + overflow: visible !important; +} + +/* Base tab */ +.x-tab, +.x-tab-default, +.x-tab-default-top { + background-color: transparent !important; + border: none !important; + border-radius: var(--pm-radius-md) var(--pm-radius-md) 0 0 !important; + padding: 8px 16px 8px !important; + overflow: visible !important; + margin-bottom: 0 !important; + transition: color 0.15s ease !important; + outline: none !important; + box-shadow: none !important; +} + +/* Remove ::after from inactive tabs */ +.x-tab::after { + display: none !important; +} + +.x-tab-inner-default { + color: var(--ctp-subtext0) !important; + font-size: 13px !important; +} + +.x-tab-default.x-tab-over { + background-color: transparent !important; +} + +.x-tab-default.x-tab-over .x-tab-inner-default { + color: var(--ctp-text) !important; +} + +/* Active tab */ +.x-tab-default.x-tab.x-tab-active { + background-color: transparent !important; + border: none !important; + overflow: visible !important; + margin-bottom: 0 !important; + outline: none !important; + box-shadow: none !important; +} + +/* Mauve underline indicator on active tab */ +.x-tab-default.x-tab.x-tab-active::after { + content: '' !important; + display: block !important; + position: absolute !important; + bottom: 0 !important; + left: 0 !important; + right: 0 !important; + height: 2px !important; + background: var(--ctp-mauve) !important; + z-index: 10 !important; + border-radius: 2px 2px 0 0 !important; + pointer-events: none !important; +} + +.x-tab-active .x-tab-inner-default { + color: var(--ctp-text) !important; + font-weight: 600 !important; +} + +.x-tab-default.x-tab.x-tab-disabled { + background-color: transparent !important; + border: none !important; + color: var(--ctp-overlay0) !important; + margin-bottom: 0 !important; +} + +/* Focus states — no outline */ +.x-keyboard-mode .x-tab-default.x-tab-focus, +.x-keyboard-mode .x-tab-default.x-tab-focus.x-tab-active { + background-color: transparent !important; + border: none !important; + outline: none !important; + box-shadow: none !important; + margin-bottom: 0 !important; +} + +.x-keyboard-mode .x-tab-default.x-tab-focus.x-tab-active::after { + content: '' !important; + display: block !important; + position: absolute !important; + bottom: 0 !important; + left: 0 !important; + right: 0 !important; + height: 2px !important; + background: var(--ctp-mauve) !important; + z-index: 10 !important; + pointer-events: none !important; +} + +/* Kill ALL tab interaction outlines/shadows */ +.x-tab:focus, +.x-tab *:focus, +.x-tab-focus, +.x-tab-active.x-tab-focus, +.x-tab-inner-focus, +.x-tab-button-focus, +.x-tab-pressed, +.x-tab-active.x-tab-pressed, +.x-tab-over, +.x-tab:active, +.x-tab *:active { + outline: none !important; + box-shadow: none !important; +} + +.x-tabpanel-child { + border-radius: 0 0 var(--pm-radius-lg) var(--pm-radius-lg) !important; +} + +/* Tab hover/active corners */ +.x-tab-default.x-tab-over, +.x-tab-default.x-tab.x-tab-active { + border-radius: var(--pm-radius-md) var(--pm-radius-md) 0 0 !important; +} + +/* ===================================================== + TOOLTIPS + ===================================================== */ +.x-tip, +.x-tip-default { + background-color: var(--ctp-mantle) !important; + border: 1px solid var(--ctp-surface1) !important; + border-radius: var(--pm-radius-md) !important; + box-shadow: 0 4px 12px rgba(24, 25, 38, 0.5); +} + +.x-tip-body-default { + color: var(--ctp-text) !important; +} + +.x-tip-form-invalid { + background-color: var(--ctp-mantle) !important; + border-color: var(--ctp-red) !important; +} + +.x-tip-body-form-invalid { + color: var(--ctp-red) !important; +} + +/* ===================================================== + TREE NAVIGATION (Sidebar) + ===================================================== */ +.x-treelist-item { + background-color: var(--ctp-base) !important; + border-radius: var(--pm-radius-md) !important; +} + +/* Pseudo-element approach for hover/selected highlighting */ +.x-treelist-row { + border-radius: var(--pm-radius-md) !important; + background-color: transparent !important; + position: relative !important; + z-index: 0 !important; +} + +.x-treelist-row::before { + content: ""; + position: absolute; + top: 1px; + bottom: 1px; + left: 0; + right: 4px; + border-radius: var(--pm-radius-md); + background-color: transparent; + z-index: -1; + pointer-events: none; + transition: background-color 0.15s ease; +} + +/* Fix toolbox tree item text overlapping icons */ +.x-treelist-item-text { + margin-left: 28px !important; +} + +/* Toolbox tree items — bright text */ +.x-treelist-item-text, +.x-treelist-item-icon, +.x-treelist.x-treelist-pve-nav .x-treelist-item-text, +.x-treelist.x-treelist-pve-nav .x-treelist-item-icon { + color: var(--ctp-subtext1) !important; +} + +/* Hover state — apply to pseudo-element */ +.x-treelist-row-over { + background-color: transparent !important; +} + +.x-treelist-row-over::before { + background-color: var(--ctp-hover-overlay) !important; +} + +.x-treelist-row-over .x-treelist-item-icon, +.x-treelist-row-over .x-treelist-item-text { + background-color: transparent !important; + color: var(--ctp-text) !important; +} + +/* Selected/active item — Mauve highlight */ +.x-treelist-item-selected > .x-treelist-row { + background-color: transparent !important; +} + +.x-treelist-item-selected > .x-treelist-row::before, +.x-treelist-item-selected > .x-treelist-row:hover::before { + background-color: var(--ctp-mauve) !important; +} + +.x-treelist-item-selected .x-treelist-item-text, +.x-treelist-item-selected .x-treelist-item-icon, +.x-treelist.x-treelist-pve-nav .x-treelist-item-selected .x-treelist-item-text, +.x-treelist.x-treelist-pve-nav .x-treelist-item-selected .x-treelist-item-icon { + color: var(--ctp-on-accent) !important; +} + +.x-treelist-pve-nav { + background-color: var(--ctp-base) !important; + border-color: var(--ctp-surface1) !important; +} + +/* Tree navigation radius overrides */ +.x-treelist-item, +.x-treelist-item-tool { + border-radius: var(--pm-radius-sm) !important; +} + +.x-treelist-row, +.x-treelist-row:hover, +.x-treelist-row-over, +.x-treelist-item-selected > .x-treelist-row, +.x-treelist-item-selected > .x-treelist-row:hover, +.x-treelist-item-expanded > .x-treelist-row, +.x-treelist-item-expanded > .x-treelist-row-over, +.x-treelist-item-expandable > .x-treelist-row, +.x-treelist-item-expandable > .x-treelist-row-over { + border-radius: var(--pm-radius-sm) !important; +} + +.x-treelist-row::before { + border-radius: var(--pm-radius-sm) !important; +} + +.x-treelist-item-wrap, +.x-treelist-item-text, +.x-treelist-row, +.x-treelist-container, +.x-treelist-root-container, +.x-treelist, +.x-treelist-pve-nav { + border-radius: var(--pm-radius-sm) !important; +} + +/* Cursor pointer for interactive tree/grid items */ +.x-grid-cell, +.x-grid-cell-inner, +.x-tree-elbow-img, +.x-tree-icon, +.x-treelist-item, +.x-treelist-row, +.x-treelist-item-wrap, +.x-treelist-item-text, +.x-treelist-item-icon { + cursor: pointer !important; +} + +/* ===================================================== + WINDOWS / MODALS + ===================================================== */ +.x-window, +.x-window-default { + background-color: var(--ctp-crust) !important; + border: 1px solid var(--ctp-surface1) !important; + border-radius: var(--pm-radius-lg) !important; + box-shadow: 0 8px 24px rgba(24, 25, 38, 0.6) !important; + overflow: hidden !important; +} + +.x-window .x-window-header, +.x-window-header-default { + background-color: var(--ctp-mantle) !important; + border-color: transparent !important; + border-radius: var(--pm-radius-lg) var(--pm-radius-lg) 0 0 !important; +} + +.x-window-header-default .x-mask { + background-color: rgba(24, 25, 38, 0.7); +} + +.x-window .x-window-body, +.x-window-body-default { + background-color: var(--ctp-base) !important; + border-color: var(--ctp-surface1) !important; + color: var(--ctp-text) !important; + border-radius: 0 0 var(--pm-radius-lg) var(--pm-radius-lg) !important; +} + +.x-window-ghost { + background-color: var(--ctp-base) !important; +} + +.x-window-header-default .x-tool-img { + background-color: transparent; +} + +.x-message-box .x-window-body { + background-color: var(--ctp-mantle) !important; +} + +/* Respect ExtJS inline display:none on hidden dialog buttons */ +.x-message-box .x-btn.x-btn-default-small[style*="display: none"], +.x-message-box .x-btn.x-btn-default-small[style*="display:none"], +.x-window .x-toolbar-footer .x-btn[style*="display: none"], +.x-window .x-toolbar-footer .x-btn[style*="display:none"] { + display: none !important; +} + +/* Login dialog — clean inner panel borders */ +.x-window:has(#pveloginrealm) .x-panel-body { + border: none !important; + background: transparent !important; + width: auto !important; +} + +/* ===================================================== + CONSOLE / TERMINAL + ===================================================== */ +div.monitor { + border-color: var(--ctp-surface1); +} + +.install-mask { + background-color: var(--ctp-crust); + color: var(--ctp-subtext0); +} + +.x-window.install-mask { + box-shadow: rgba(24, 25, 38, 0.5) 0 4px 20px !important; +} + +/* ===================================================== + LEGEND / CHARTS + ===================================================== */ +.x-legend-container { + background-color: var(--ctp-base) !important; +} + +.x-legend-horizontal .x-legend-item { + background-color: var(--ctp-mantle) !important; + color: var(--ctp-text) !important; + border: 1px solid var(--ctp-surface0) !important; +} + +/* Chart/RRD panel backgrounds */ +div[id*="rrdchart"], +.pve-rrddatastore, +.pmx-panel-rrd { + background-color: var(--ctp-base) !important; +} + +.proxmox-rrd-panel canvas, +.proxmox-widget-toolkit canvas, +canvas.x-surface, +.x-surface canvas { + background-color: transparent !important; + opacity: 1 !important; +} + +.proxmox-rrd-panel, +.proxmox-rrd-chart { + background-color: var(--ctp-base) !important; +} + +/* Chart text/labels */ +.x-surface text, +svg text { + fill: var(--ctp-text) !important; +} + +/* ===================================================== + PROXMOX-SPECIFIC OVERRIDES + ===================================================== */ + +/* Logo inversion */ +img[id^="proxmoxlogo-"][id$="-img"], +img[id^="proxmoxLogoSvg-"][id$="-img"] { + filter: invert(1) hue-rotate(180deg); +} + +/* Invalid/warning/disabled rows */ +.proxmox-invalid-row { + background-color: rgba(243, 139, 168, 0.15) !important; +} + +.proxmox-warning-row { + background-color: rgba(250, 179, 135, 0.15) !important; +} + +.proxmox-disabled-row td { + color: var(--ctp-overlay0) !important; +} + +/* Hints */ +.pmx-hint { + background-color: rgba(250, 179, 135, 0.15) !important; + white-space: nowrap !important; +} + +.pmx-hint a { + color: var(--ctp-blue) !important; +} + +/* Status text colors — style guide: Information → Teal */ +.info-blue { + color: var(--ctp-teal) !important; +} + +.critical { + color: var(--ctp-red) !important; +} + +/* Links */ +a { + color: var(--ctp-blue) !important; +} + +/* Markdown content */ +.pmx-md code { + background-color: var(--ctp-mantle) !important; + color: var(--ctp-rosewater) !important; + border-radius: var(--pm-radius-sm) !important; +} + +.pmx-md pre code { + border-color: var(--ctp-surface1) !important; + background-color: var(--ctp-crust) !important; +} + +.pmx-md a { + color: var(--ctp-blue) !important; +} + +.pmx-md table { + border-color: var(--ctp-surface1) !important; +} + +.pmx-md th { + background-color: var(--ctp-mantle) !important; + border-color: var(--ctp-surface1) !important; +} + +.pmx-md td { + border-color: var(--ctp-surface1) !important; +} + +/* APT repos */ +.proxmox-apt-repos .x-grid-group-hd { + background-color: var(--ctp-base) !important; + border: none !important; +} + +.proxmox-apt-repos .x-grid-group-title { + color: var(--ctp-text) !important; +} + +/* Tags */ +.pve-edit-tag { + border-radius: var(--pm-radius-md) !important; +} + +.pve-edit-tag.editable span { + background-color: var(--ctp-mantle) !important; + color: var(--ctp-text) !important; + border-color: var(--ctp-surface1) !important; +} + +.x-tree-node-text .proxmox-tag-dark, +.x-tree-node-text .proxmox-tag-light, +.x-grid-cell-inner .proxmox-tag-dark, +.x-grid-cell-inner .proxmox-tag-light, +span.proxmox-tag-dark, +span.proxmox-tag-light { + border-radius: var(--pm-radius-md) !important; +} + +/* Checkmark button in tag edit — match toolbar button size */ +.x-btn.x-btn-default-small:has(.fa-check) { + min-height: 24px !important; + height: 24px !important; + padding: 3px 8px !important; + border-radius: var(--pm-radius-sm) !important; + background-color: var(--ctp-mauve) !important; + border: none !important; +} + +.x-btn.x-btn-default-small:has(.fa-check).x-btn-disabled { + background-color: transparent !important; + border: 1px solid var(--ctp-surface1) !important; + opacity: 0.5 !important; +} + +.x-btn.x-btn-default-small:has(.fa-check) .fa-check { + color: var(--ctp-on-accent) !important; +} + +.x-btn.x-btn-default-small:has(.fa-check).x-btn-disabled .fa-check { + color: var(--ctp-overlay1) !important; +} + +.x-btn.x-btn-default-small:has(.fa-check):not(.x-btn-disabled):hover { + background-color: #d0b0f8 !important; +} + +.x-btn.x-btn-default-small:has(.fa-check) .x-btn-inner { + display: none !important; +} + +/* Date picker */ +.x-datepicker, +.x-datepicker-column-header, +.x-monthpicker { + background-color: var(--ctp-base) !important; + color: var(--ctp-text) !important; + border-color: transparent !important; +} + +.x-datepicker-header, +.x-datepicker-footer, +.x-monthpicker-buttons { + background-color: var(--ctp-mantle) !important; +} + +.x-datepicker-date, +.x-monthpicker-item-inner { + color: var(--ctp-text) !important; +} + +.x-datepicker-selected div.x-datepicker-date, +.x-monthpicker-item a.x-monthpicker-selected, +a.x-monthpicker-item-inner:hover, +div.x-datepicker-date:hover { + background-color: var(--ctp-hover-overlay) !important; + color: var(--ctp-text) !important; +} + +.x-datepicker-today .x-datepicker-date { + border-color: var(--ctp-mauve) !important; +} + +.x-datepicker-disabled .x-datepicker-date { + color: var(--ctp-overlay0) !important; +} + +.x-datepicker-prev-day .x-datepicker-date, +.x-datepicker-next-day .x-datepicker-date { + color: var(--ctp-overlay0) !important; +} + +/* Usage bars */ +.usage-wrapper, +.usage { + border-radius: 2px !important; +} + +.usage { + background-color: var(--ctp-overlay2) !important; +} + +/* ===================================================== + SCROLLBARS + ===================================================== */ +::-webkit-scrollbar { + width: 8px; + height: 8px; +} + +::-webkit-scrollbar-track { + background: var(--ctp-base); + border-radius: var(--pm-radius-sm); +} + +::-webkit-scrollbar-thumb { + background: var(--ctp-surface2); + border-radius: var(--pm-radius-sm); + border: 1px solid transparent; + background-clip: padding-box; + transition: background 0.15s ease; +} + +::-webkit-scrollbar-thumb:hover { + background: var(--ctp-overlay0); +} + +::-webkit-scrollbar-corner { + background: var(--ctp-base); +} + +/* Firefox scrollbar */ +* { + scrollbar-width: thin; + scrollbar-color: var(--ctp-surface2) var(--ctp-base); +} + +/* ===================================================== + SELECTION HIGHLIGHT + ===================================================== */ +::selection { + background-color: rgba(147, 154, 183, 0.3); + color: var(--ctp-text); +} + +/* ===================================================== + TRANSITIONS (smooth interactions) + ===================================================== */ + +/* Grid row transitions */ +.x-grid-item { + transition: background-color 0.15s ease !important; +} + +/* Tree pseudo-element transitions */ +.x-treelist-row::before { + transition: background-color 0.15s ease !important; +} + +/* Menu item transitions */ +.x-menu-item-default > .x-menu-item-link { + transition: background-color 0.12s ease !important; +} + +/* Boundlist item transitions */ +.x-boundlist-item { + transition: background-color 0.12s ease !important; +} + +/* Tab transitions */ +.x-tab { + transition: color 0.15s ease !important; +} + +/* Splitter transition */ +.x-splitter { + transition: background-color 0.15s ease !important; +} + +/* Tooltip transition */ +.x-tip { + transition: opacity 0.15s ease !important; +} + +/* Progress bar width transition */ +.x-progress-bar { + transition: width 0.4s ease !important; +} + +/* Scrollbar thumb transition */ +::-webkit-scrollbar-thumb { + transition: background 0.15s ease !important; +} + +/* Window close tool transition */ +.x-tool-img { + transition: filter 0.15s ease !important; +} + +/* ===================================================== + TOOL ICONS - FontAwesome Replacements + (Ported from UniFi v5.86) + Replace sprite-based ExtJS tool icons with crisp + FontAwesome icons for better consistency and clarity + ===================================================== */ + +/* Base styling for all tool icons - remove sprite backgrounds */ +.x-tool-tool-el.x-tool-minus, +.x-tool-img.x-tool-minus, +.x-tool-tool-el.x-tool-collapse-right, +.x-tool-img.x-tool-collapse-right, +.x-tool-tool-el.x-tool-collapse-left, +.x-tool-img.x-tool-collapse-left, +.x-tool-tool-el.x-tool-expand-right, +.x-tool-img.x-tool-expand-right, +.x-tool-tool-el.x-tool-expand-left, +.x-tool-img.x-tool-expand-left, +.x-tool-tool-el.x-tool-maximize, +.x-tool-img.x-tool-maximize, +.x-tool-tool-el.x-tool-restore, +.x-tool-img.x-tool-restore, +.x-tool-tool-el.x-tool-gear, +.x-tool-img.x-tool-gear, +.x-tool-tool-el.x-tool-refresh, +.x-tool-img.x-tool-refresh, +.x-tool-tool-el.x-tool-close, +.x-tool-img.x-tool-close { + background-image: none !important; + font-family: "FontAwesome" !important; + font-size: 14px !important; + line-height: 16px !important; + text-align: center !important; + color: var(--pm-text-dim) !important; + transition: color 0.15s ease !important; + filter: none !important; + width: 16px !important; + height: 16px !important; + display: flex !important; + align-items: center !important; + justify-content: center !important; +} + +/* Close button - slightly larger */ +.x-tool-tool-el.x-tool-close, +.x-tool-img.x-tool-close { + font-size: 20px !important; +} + +/* Individual glyph assignments */ +.x-tool-tool-el.x-tool-minus::before, +.x-tool-img.x-tool-minus::before { + content: "\f010" !important; /* fa-search-minus (zoom out) */ +} + +.x-tool-tool-el.x-tool-collapse-right::before, +.x-tool-img.x-tool-collapse-right::before { + content: "\f054" !important; /* fa-chevron-right */ +} + +.x-tool-tool-el.x-tool-expand-left::before, +.x-tool-img.x-tool-expand-left::before { + content: "\f053" !important; /* fa-chevron-left */ +} + +.x-tool-tool-el.x-tool-collapse-left::before, +.x-tool-img.x-tool-collapse-left::before { + content: "\f053" !important; /* fa-chevron-left */ +} + +.x-tool-tool-el.x-tool-expand-right::before, +.x-tool-img.x-tool-expand-right::before { + content: "\f054" !important; /* fa-chevron-right */ +} + +.x-tool-tool-el.x-tool-maximize::before, +.x-tool-img.x-tool-maximize::before { + content: "\f065" !important; /* fa-expand */ +} + +.x-tool-tool-el.x-tool-restore::before, +.x-tool-img.x-tool-restore::before { + content: "\f066" !important; /* fa-compress */ +} + +.x-tool-tool-el.x-tool-gear::before, +.x-tool-img.x-tool-gear::before { + content: "\f013" !important; /* fa-cog */ +} + +.x-tool-tool-el.x-tool-refresh::before, +.x-tool-img.x-tool-refresh::before { + content: "\f021" !important; /* fa-refresh */ +} + +.x-tool-tool-el.x-tool-close::before, +.x-tool-img.x-tool-close::before { + content: "\f00d" !important; /* fa-times */ +} + +/* Hover state - all tool icons */ +.x-tool:hover .x-tool-tool-el.x-tool-minus, +.x-tool:hover .x-tool-img.x-tool-minus, +.x-tool:hover .x-tool-tool-el.x-tool-collapse-right, +.x-tool:hover .x-tool-img.x-tool-collapse-right, +.x-tool:hover .x-tool-tool-el.x-tool-collapse-left, +.x-tool:hover .x-tool-img.x-tool-collapse-left, +.x-tool:hover .x-tool-tool-el.x-tool-expand-right, +.x-tool:hover .x-tool-img.x-tool-expand-right, +.x-tool:hover .x-tool-tool-el.x-tool-expand-left, +.x-tool:hover .x-tool-img.x-tool-expand-left, +.x-tool:hover .x-tool-tool-el.x-tool-maximize, +.x-tool:hover .x-tool-img.x-tool-maximize, +.x-tool:hover .x-tool-tool-el.x-tool-restore, +.x-tool:hover .x-tool-img.x-tool-restore, +.x-tool:hover .x-tool-tool-el.x-tool-gear, +.x-tool:hover .x-tool-img.x-tool-gear, +.x-tool:hover .x-tool-tool-el.x-tool-refresh, +.x-tool:hover .x-tool-img.x-tool-refresh, +.x-tool:hover .x-tool-tool-el.x-tool-close, +.x-tool:hover .x-tool-img.x-tool-close { + color: var(--pm-text) !important; +} + +/* Disabled state */ +.x-tool-disabled .x-tool-tool-el, +.x-tool-disabled .x-tool-img { + opacity: 0.4 !important; + cursor: default !important; +} + +/* Inline FontAwesome tools (PVE-injected) */ +.x-tool-tool-el[style*="font-family:FontAwesome"], +.x-tool-tool-el[style*="font-family: FontAwesome"] { + color: var(--pm-text-dim) !important; + font-size: 14px !important; + line-height: 16px !important; + display: flex !important; + align-items: center !important; + justify-content: center !important; + width: 16px !important; + height: 16px !important; + transition: color 0.15s ease !important; + background-image: none !important; + background-color: transparent !important; +} + +.x-tool:not(.x-tool-disabled) .x-tool-tool-el[style*="font-family:FontAwesome"], +.x-tool:not(.x-tool-disabled) .x-tool-tool-el[style*="font-family: FontAwesome"] { + cursor: pointer !important; +} + +.x-tool.x-tool-disabled .x-tool-tool-el[style*="font-family:FontAwesome"], +.x-tool.x-tool-disabled .x-tool-tool-el[style*="font-family: FontAwesome"] { + cursor: default !important; + opacity: 0.4 !important; +} + +.x-tool .x-mask { + background-color: transparent !important; + backdrop-filter: none !important; + pointer-events: none !important; +} + +.x-tool:not(.x-tool-disabled):hover .x-tool-tool-el[style*="font-family:FontAwesome"], +.x-tool:not(.x-tool-disabled):hover .x-tool-tool-el[style*="font-family: FontAwesome"] { + color: var(--pm-text) !important; +} diff --git a/themes/theme-catppuccin-mocha-teal.css b/themes/theme-catppuccin-mocha-teal.css new file mode 100644 index 0000000..4431dfe --- /dev/null +++ b/themes/theme-catppuccin-mocha-teal.css @@ -0,0 +1,2382 @@ +/*!Catppuccin Mocha Teal*/ +/* + * ProxMorph Theme: Catppuccin Mocha Teal + * Soothing pastel theme for Proxmox VE — the dark flavor with Teal accent of Catppuccin + * Version: 1.0.0 + * Author: ProxMorph / Catppuccin Community Palette + * + * v1.0.0: Initial release - accent variant (generated from Mocha v1.3.0) + * Catppuccin Mocha palette, border-radius architecture (ported from UniFi), + * custom checkboxes/radios, full grid styling, progress bar states, + * tags, markdown, date picker, usage bars, Firefox scrollbar. + * + * Catppuccin Mocha Teal Color Palette: + * + * ACCENT COLORS: + * - Rosewater: #f5e0dc - Flamingo: #f2cdcd + * - Pink: #f5c2e7 - Mauve: #cba6f7 (Primary Accent) + * - Red: #f38ba8 - Maroon: #eba0ac + * - Peach: #fab387 - Yellow: #f9e2af + * - Green: #a6e3a1 - Teal: #94e2d5 + * - Sky: #89dceb - Sapphire: #74c7ec + * - Blue: #89b4fa - Lavender: #b4befe + * + * NEUTRALS: + * - Text: #cdd6f4 - Subtext 1: #bac2de + * - Subtext 0: #a6adc8 - Overlay 2: #9399b2 + * - Overlay 1: #7f849c - Overlay 0: #6c7086 + * - Surface 2: #585b70 - Surface 1: #45475a + * - Surface 0: #313244 - Base: #1e1e2e + * - Mantle: #181825 - Crust: #11111b + */ + +/* ===================================================== + CSS VARIABLES + ===================================================== */ +:root { + /* Catppuccin Mocha Tokens */ + --ctp-rosewater: #f5e0dc; + --ctp-flamingo: #f2cdcd; + --ctp-pink: #f5c2e7; + --ctp-mauve: #cba6f7; + --ctp-red: #f38ba8; + --ctp-maroon: #eba0ac; + --ctp-peach: #fab387; + --ctp-yellow: #f9e2af; + --ctp-green: #a6e3a1; + --ctp-teal: #94e2d5; + --ctp-sky: #89dceb; + --ctp-sapphire: #74c7ec; + --ctp-blue: #89b4fa; + --ctp-lavender: #b4befe; + + --ctp-text: #cdd6f4; + --ctp-subtext1: #bac2de; + --ctp-subtext0: #a6adc8; + --ctp-overlay2: #9399b2; + --ctp-overlay1: #7f849c; + --ctp-overlay0: #6c7086; + --ctp-surface2: #585b70; + --ctp-surface1: #45475a; + --ctp-surface0: #313244; + --ctp-base: #1e1e2e; + --ctp-mantle: #181825; + --ctp-crust: #11111b; + + /* ProxMorph Semantic Variables */ + --pm-accent: var(--ctp-teal); + --pm-bg-base: var(--ctp-base); + --pm-bg-surface: var(--ctp-surface0); + --pm-bg-elevated: var(--ctp-surface1); + --pm-text: var(--ctp-text); + --pm-text-dim: var(--ctp-subtext1); + --pm-success: var(--ctp-green); + --pm-warning: var(--ctp-yellow); + --pm-error: var(--ctp-red); + --pm-border: var(--ctp-surface1); + --pm-radius-sm: 4px; + --pm-radius-md: 6px; + --pm-radius-lg: 8px; + + /* Proxmox Widget Toolkit Mappings (REQUIRED) */ + --pwt-panel-background: var(--ctp-base); + --pwt-text-color: var(--ctp-text); + --pwt-gauge-default: var(--ctp-teal); + --pwt-gauge-back: var(--ctp-surface1); + --pwt-gauge-warn: var(--ctp-yellow); + --pwt-gauge-crit: var(--ctp-red); + --pwt-chart-primary: var(--ctp-teal); + --pwt-chart-grid-stroke: var(--ctp-surface1); + + /* On Accent text — style guide mandates Base for text on colored backgrounds */ + --ctp-on-accent: var(--ctp-base); + + /* Hover overlay — Overlay2@12% (neutral, per Catppuccin port conventions) */ + --ctp-hover-overlay: rgba(147, 153, 178, 0.12); + /* Selection overlay — Overlay2@25% (style guide: Selection Background → Overlay2 20-30%) */ + --ctp-select-overlay: rgba(147, 153, 178, 0.25); + /* Accent muted (for focus rings) */ + --ctp-accent-muted: rgba(148, 226, 213, 0.4); + --ctp-accent-subtle: rgba(148, 226, 213, 0.15); + + color-scheme: dark; +} + +/* ===================================================== + GLOBAL BORDER-RADIUS ARCHITECTURE + (Ported from UniFi theme — reset everything, selectively re-apply) + ===================================================== */ +.x-border-box, +.x-border-box * { + border-radius: var(--pm-radius-lg); +} + +/* Remove rounded corners from grids/tables/lists */ +.x-grid, +.x-grid *, +.x-grid-header-ct, +.x-grid-header-ct *, +.x-grid-view, +.x-grid-view *, +.x-column-header, +.x-column-header *, +.x-grid-item, +.x-grid-cell, +.x-grid-cell-inner, +.x-grid-row, +table, +table *, +tr, +td, +th, +.x-legend, +.x-legend *, +.x-legend-container, +.x-legend-container *, +.x-legend-item, +.x-legend-horizontal .x-legend-item, +.x-legend-vertical .x-legend-item, +.x-legend-horizontal .x-legend-item:first-child, +.x-legend-horizontal .x-legend-item:last-child, +.x-legend-vertical .x-legend-item:first-child, +.x-legend-vertical .x-legend-item:last-child, +.x-tool, +.x-tool-tool-el, +.x-tool-default, +.x-tool-img { + border-radius: 0 !important; +} + +/* Form elements - exclude from global radius */ +.x-form-item, +.x-form-item-default, +.x-form-item-body, +.x-form-item-body-default, +.x-form-text-field-body, +.x-form-text-field-body-default, +.x-form-fieldcontainer, +.x-field, +.x-field-default, +.x-form-type-text { + border-radius: 0 !important; +} + +/* Reset layout containers that clip elements with overflow:hidden + radius */ +.x-box-layout-ct, +.x-panel-bodyWrap, +.x-panel-bodyWrap-default, +.x-autocontainer-innerCt, +.x-autocontainer-outerCt, +.x-panel.x-tabpanel-child, +.x-panel.x-box-item, +.x-box-inner, +.x-box-target, +.x-container, +.x-container-default, +.x-window .x-panel-body, +.x-window .x-window-body, +.x-window .x-window-bodyWrap { + border-radius: 0 !important; +} + +/* Reset everything inside windows to 0 — then re-apply specific radii */ +.x-window *, +.x-window .x-autocontainer-innerCt, +.x-window .x-autocontainer-outerCt, +.x-window .x-form-layout-wrap, +.x-window .x-form-layout-auto-label, +.x-window .x-form-layout-colgroup, +.x-window .x-form-layout-column, +.x-window .x-field, +.x-window .x-form-item, +.x-window .x-form-item-body { + border-radius: 0 !important; +} + +/* Chart canvas — no radius on data area */ +.x-chart-grid, +.x-chart-axis, +canvas.x-surface, +.x-chart canvas, +canvas.x-surface-canvas, +.x-surface-canvas, +.x-draw-component canvas, +.proxmox-rrd-chart canvas, +svg.x-surface, +.x-draw-container, +.x-surface { + border-radius: 0 !important; +} + +/* Legend color marker (dot) — keep circular */ +.x-legend-item-marker { + border-radius: 50% !important; +} + +/* ===================================================== + RE-APPLY BORDER RADII (selective) + ===================================================== */ + +/* Windows */ +.x-window, +.x-window-default { + border-radius: var(--pm-radius-lg) !important; +} + +.x-window-header, +.x-window-header-default { + border-radius: var(--pm-radius-lg) var(--pm-radius-lg) 0 0 !important; +} + +.x-window .x-window-body, +.x-window-body-default { + border-radius: 0 !important; +} + +/* Buttons inside windows */ +.x-window .x-btn { + border-radius: var(--pm-radius-md) !important; +} + +/* Checkboxes inside windows */ +.x-window .x-form-checkbox { + border-radius: 3px !important; +} + +/* Form inputs inside windows */ +.x-window .x-form-trigger-wrap, +.x-window .x-form-trigger-wrap-default { + border-radius: var(--pm-radius-sm) !important; +} + +.x-window .x-form-text-wrap, +.x-window .x-form-text { + border-radius: var(--pm-radius-sm) 0 0 var(--pm-radius-sm) !important; +} + +.x-window .x-form-arrow-trigger { + border-radius: 0 var(--pm-radius-sm) var(--pm-radius-sm) 0 !important; +} + +/* Form trigger/text wrap — reset and re-apply */ +.x-form-trigger-wrap, +.x-form-trigger-wrap *, +.x-form-text-wrap, +.x-form-text-wrap *, +.x-form-text, +.x-form-trigger { + border-radius: 0 !important; +} + +.x-form-trigger-wrap, +.x-form-trigger-wrap-default { + border-radius: var(--pm-radius-sm) !important; + overflow: hidden !important; +} + +.x-form-text-wrap, +.x-form-text-wrap-default { + border-radius: var(--pm-radius-sm) 0 0 var(--pm-radius-sm) !important; +} + +.x-form-text, +.x-form-text-default { + border-radius: var(--pm-radius-sm) 0 0 var(--pm-radius-sm) !important; +} + +.x-form-trigger, +.x-form-trigger-default, +.x-form-arrow-trigger, +.x-form-arrow-trigger-default { + border-radius: 0 var(--pm-radius-sm) var(--pm-radius-sm) 0 !important; +} + +/* Dialog form content padding — vertical only (horizontal causes ExtJS overflow) */ +.x-window .x-tabpanel-child .x-autocontainer-innerCt { + padding: 12px 0 !important; +} + +/* Allow column panel bodies to show overflowed form content */ +.x-window .x-panel-body:not(.x-scroller) { + overflow: visible !important; +} + +/* Side padding on column panel bodies inside windows */ +.x-window .x-panel.x-box-item .x-panel-body { + padding: 0 4px !important; +} + +/* Constrain autocontainer width inside windows */ +.x-window .x-autocontainer-outerCt { + max-width: 100% !important; +} + +/* Fix window header/body width consistency */ +.x-window > .x-window-header, +.x-window > .x-window-body, +.x-window > .x-window-bodyWrap, +.x-window-bodyWrap > .x-window-body { + width: 100% !important; +} + +.x-window-header > .x-box-inner, +.x-window-header > .x-box-inner > .x-box-target { + width: 100% !important; +} + +.x-window-header-title { + width: auto !important; + flex: 1 !important; + max-width: calc(100% - 30px) !important; +} + +/* Boundlists */ +.x-boundlist { + border-radius: var(--pm-radius-md) !important; + overflow: hidden !important; +} + +/* ===================================================== + BASE / BODY + ===================================================== */ +.x-body, +.x-viewport > .x-body, +body.x-border-layout-ct, +div.x-border-layout-ct { + background-color: var(--ctp-base) !important; + color: var(--ctp-text) !important; +} + +/* ===================================================== + MASKS & OVERLAYS + ===================================================== */ +.x-mask { + background-color: rgba(17, 17, 27, 0.6) !important; + backdrop-filter: blur(4px); +} + +.x-mask-msg { + background-color: var(--ctp-mantle) !important; + border: 1px solid var(--ctp-surface1) !important; + border-radius: var(--pm-radius-lg) !important; +} + +.x-mask-msg-text { + color: var(--ctp-subtext0) !important; + filter: none !important; +} + +.x-css-shadow { + box-shadow: 0 8px 24px rgba(17, 17, 27, 0.6) !important; +} + +/* Loading indicators */ +.x-grid-row-loading, +.x-treelist-item-loading .x-treelist-item-icon, +.x-grid-tree-loading .x-tree-icon { + filter: invert(90%); +} + +/* ===================================================== + ICONS — Proxmox default colors for dark mode + ===================================================== */ + +/* General icon colors — neutral gray for dark backgrounds */ +.x-tree-icon-custom, +.x-grid-icon-custom, +.fa-tags::before, +.fa-file-o::before, +.fa-building::before, +.x-action-col-icon::before, +.fa-shield::before, +.fa-file-text-o::before, +.fa-clock-o::before, +.x-tab-icon-el-default, +.pve-icon-verify-lettering::after, +.x-tree-icon-leaf:not(.x-tree-icon-custom)::before, +.x-tree-icon-parent:not(.x-tree-icon-custom)::before, +.x-tree-icon-parent-expanded:not(.x-tree-icon-custom)::before, +.x-grid-filters-filtered-column .x-column-header-text::after { + color: var(--ctp-overlay2) !important; +} + +/* Folder icons — invert for dark mode */ +.x-tree-icon-parent:not(.x-tree-icon-custom)::before, +.x-tree-icon-parent-expanded:not(.x-tree-icon-custom)::before { + filter: invert(90%); +} + +/* Various image-based icons — invert for visibility */ +.fa-ceph::before, +.fa-sdn::before, +.fa-network-wired::before, +.pve-itype-treelist-item-icon-cdrom, +.fa-chevron-right::before, +.x-grid-row-console, +.x-box-scroller-toolbar-default.x-box-scroller, +.x-tree-elbow-img, +.pve-itype-icon-qemu, +.x-tree-node-computer, +.x-grid-tree-node-expanded .x-tree-node-computer, +.pbs-icon-tape, +.pbs-icon-tape-drive, +.x-tree-icon-leaf:not(.x-tree-icon-custom), +.x-tree-icon-parent:not(.x-tree-icon-custom), +.x-tree-icon-parent-expanded:not(.x-tree-icon-custom) { + filter: invert(90%); +} + +/* Hardware icons */ +.pve-itype-icon-cpu, +.pve-itype-icon-cdrom, +.pve-itype-icon-memory, +.pve-itype-icon-pci, +.pve-itype-icon-serial, +.pve-itype-icon-die, +.pmx-itype-icon-processor, +.pmx-itype-icon-memory, +.pve-itype-icon-storage, +.x-tree-node-harddisk, +.x-grid-tree-node-expanded .x-tree-node-harddisk { + filter: invert(100%); +} + +/* Hardware icons — counter-invert for non-SVG icon cells */ +td.pve-itype-icon-storage .x-grid-cell-inner, +td.x-tree-node-harddisk .x-grid-cell-inner { + filter: invert(100%) !important; +} + +/* Hardware icons — hide inverted borders for non-SVG icon cells */ +td.pve-itype-icon-storage, +td.x-tree-node-harddisk { + border-color: transparent !important; +} + +/* Hardware grid icons — mask-image renders SVG icons in theme text color + Replaces filter:invert approach for pve-itype-icon-* and pmx-itype-icon-* grid cells */ +td.pve-itype-icon-cpu, +td.pve-itype-icon-cdrom, +td.pve-itype-icon-memory, +td.pve-itype-icon-pci, +td.pve-itype-icon-serial, +td.pve-itype-icon-die, +td.pmx-itype-icon-processor, +td.pmx-itype-icon-memory { + filter: none !important; + background-image: none !important; + padding-left: 0 !important; + border-color: transparent !important; +} + +td.pve-itype-icon-cpu .x-grid-cell-inner, +td.pve-itype-icon-cdrom .x-grid-cell-inner, +td.pve-itype-icon-memory .x-grid-cell-inner, +td.pve-itype-icon-pci .x-grid-cell-inner, +td.pve-itype-icon-serial .x-grid-cell-inner, +td.pve-itype-icon-die .x-grid-cell-inner, +td.pmx-itype-icon-processor .x-grid-cell-inner, +td.pmx-itype-icon-memory .x-grid-cell-inner { + padding-left: 3px !important; +} + +td.pve-itype-icon-cpu .x-grid-cell-inner::before, +td.pve-itype-icon-cdrom .x-grid-cell-inner::before, +td.pve-itype-icon-memory .x-grid-cell-inner::before, +td.pve-itype-icon-pci .x-grid-cell-inner::before, +td.pve-itype-icon-serial .x-grid-cell-inner::before, +td.pve-itype-icon-die .x-grid-cell-inner::before, +td.pmx-itype-icon-processor .x-grid-cell-inner::before, +td.pmx-itype-icon-memory .x-grid-cell-inner::before { + content: '' !important; + display: inline-block !important; + width: 18px !important; + height: 14px !important; + vertical-align: middle !important; + margin-right: 10px !important; + background-color: currentColor !important; + -webkit-mask-size: contain !important; + mask-size: contain !important; + -webkit-mask-repeat: no-repeat !important; + mask-repeat: no-repeat !important; + -webkit-mask-position: center !important; + mask-position: center !important; +} + +td.pve-itype-icon-cpu .x-grid-cell-inner::before { + -webkit-mask-image: url('/pve2/images/icon-cpu.svg') !important; + mask-image: url('/pve2/images/icon-cpu.svg') !important; +} + +td.pve-itype-icon-memory .x-grid-cell-inner::before { + -webkit-mask-image: url('/pve2/images/icon-memory.svg') !important; + mask-image: url('/pve2/images/icon-memory.svg') !important; +} + +td.pve-itype-icon-cdrom .x-grid-cell-inner::before { + -webkit-mask-image: url('/pve2/images/icon-cd-drive.svg') !important; + mask-image: url('/pve2/images/icon-cd-drive.svg') !important; +} + +td.pve-itype-icon-pci .x-grid-cell-inner::before { + -webkit-mask-image: url('/pve2/images/icon-pci.svg') !important; + mask-image: url('/pve2/images/icon-pci.svg') !important; +} + +td.pve-itype-icon-serial .x-grid-cell-inner::before { + -webkit-mask-image: url('/pve2/images/icon-serial.svg') !important; + mask-image: url('/pve2/images/icon-serial.svg') !important; +} + +td.pve-itype-icon-die .x-grid-cell-inner::before { + -webkit-mask-image: url('/pve2/images/icon-die.svg') !important; + mask-image: url('/pve2/images/icon-die.svg') !important; +} + +td.pmx-itype-icon-processor .x-grid-cell-inner::before { + -webkit-mask-image: url('../images/icon-cpu.svg') !important; + mask-image: url('../images/icon-cpu.svg') !important; +} + +td.pmx-itype-icon-memory .x-grid-cell-inner::before { + -webkit-mask-image: url('../images/icon-ram.svg') !important; + mask-image: url('../images/icon-ram.svg') !important; +} + + +/* Icon overlays — default */ +.x-tree-icon-custom::after, +.x-grid-icon-custom::after { + color: var(--ctp-overlay2) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* RUNNING VMs/CTs — Catppuccin Green */ +.x-tree-icon-custom.running::after, +.x-grid-icon-custom.running::after, +.x-treelist-item-icon.running::after { + color: var(--ctp-green) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* ONLINE state — Green */ +.x-tree-icon-custom.online::after, +.x-grid-icon-custom.online::after { + color: var(--ctp-green) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* Stopped/offline — Overlay1 (muted gray) */ +.x-tree-icon-custom.stopped, +.x-tree-icon-custom.offline, +.x-grid-icon-custom.stopped, +.x-grid-icon-custom.offline { + color: var(--ctp-overlay1) !important; +} + +/* Unknown state — Overlay1 */ +.x-tree-icon-custom.unknown::after, +.x-grid-icon-custom.unknown::after { + color: var(--ctp-overlay1) !important; +} + +/* ERROR states — Catppuccin Red */ +.x-tree-icon-custom.error::after, +.x-tree-icon-custom.offline::after, +.x-tree-icon-custom.ha-error::after, +.x-grid-icon-custom.error::after, +.x-grid-icon-custom.offline::after, +.x-grid-icon-custom.ha-error::after { + color: var(--ctp-red) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* PAUSED/SUSPENDED — Catppuccin Peach */ +.x-tree-icon-custom.paused::after, +.x-tree-icon-custom.suspended::after, +.x-tree-icon-custom.lock-suspending::after, +.x-grid-icon-custom.paused::after, +.x-grid-icon-custom.suspended::after, +.x-grid-icon-custom.lock-suspending::after { + color: var(--ctp-peach) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* PENDING/WARNING states — Catppuccin Yellow */ +.x-tree-icon-custom.pending::after, +.x-tree-icon-custom.io-error::after, +.x-tree-icon-custom.internal-error::after, +.x-tree-icon-custom.guest-panicked::after, +.x-grid-icon-custom.pending::after, +.x-grid-icon-custom.io-error::after, +.x-grid-icon-custom.internal-error::after, +.x-grid-icon-custom.guest-panicked::after { + color: var(--ctp-yellow) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* HA MAINTENANCE — Catppuccin Sky */ +.x-tree-icon-custom.ha-maintenance::after, +.x-grid-icon-custom.ha-maintenance::after { + color: var(--ctp-sky) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* Locked icons */ +.x-tree-icon-custom.locked::after, +.x-tree-icon-custom.lock-backup::after, +.x-tree-icon-custom.lock-migrate::after, +.x-tree-icon-custom.lock-suspended::after, +.x-grid-icon-custom.locked::after, +.x-grid-icon-custom.lock-backup::after, +.x-grid-icon-custom.lock-migrate::after, +.x-grid-icon-custom.lock-suspended::after { + color: var(--ctp-overlay2) !important; +} + +/* LXC/QEMU type indicators */ +.x-tree-icon-custom.lxc::after, +.x-tree-icon-custom.qemu::after, +.x-grid-icon-custom.lxc::after, +.x-grid-icon-custom.qemu::after { + background-color: transparent; + color: var(--ctp-overlay1) !important; +} + +.x-treelist-item-icon.lxc::after, +.x-treelist-item-icon.qemu::after { + background-color: transparent; + color: var(--ctp-overlay1) !important; +} + +/* Tree expander arrows */ +.x-tree-arrows .x-tree-expander { + filter: brightness(200%); +} + +/* Cancel sprite-inversion on custom controls (checkboxes/radios handled via CSS) */ +.x-form-checkbox-default, +.x-form-radio-default, +.x-column-header-checkbox .x-column-header-checkbox::after, +.x-grid-checkcolumn::after, +.x-menu-item-checked .x-menu-item-icon-default.x-menu-item-checkbox, +.x-menu-item-unchecked .x-menu-item-icon-default.x-menu-item-checkbox { + filter: none !important; +} + +/* ===================================================== + PANELS & HEADERS + ===================================================== */ +.x-panel, +.x-panel-default { + border-radius: var(--pm-radius-lg) !important; + padding: 0 !important; +} + +/* Column panels — native stacked layout (Issue #23 fix) */ +.x-panel.x-column { + padding: 5px !important; + margin: 0 !important; + max-width: none !important; + box-sizing: border-box !important; +} + +/* Column panel card styling — borders for summary + chart panels */ +.x-panel.x-panel-default.x-column { + border: 1px solid var(--ctp-surface1) !important; + border-radius: var(--pm-radius-lg) !important; + overflow: hidden !important; +} + +/* Guest status + Notes panel borders */ +[id^="pveGuestStatusView-"].x-panel, +[id^="pveLxcStatusView-"].x-panel, +[id^="pveQemuStatusView-"].x-panel, +[id^="pmxNotesView-"].x-panel { + border: 1px solid var(--ctp-surface1) !important; + border-radius: var(--pm-radius-lg) !important; +} + +.x-panel-body, +.x-panel-body-default { + background-color: var(--ctp-base) !important; + color: var(--ctp-text) !important; + border: none !important; +} + +/* Panel headers — bottom border only */ +.x-panel-header, +.x-panel-header-default { + background-color: var(--ctp-mantle) !important; + border: none !important; + border-bottom: 1px solid var(--ctp-surface1) !important; + border-radius: var(--pm-radius-lg) var(--pm-radius-lg) 0 0 !important; + margin: 0 !important; + padding: 8px 12px !important; + width: 100% !important; + box-sizing: border-box !important; + overflow: visible !important; +} + +/* Title text — prevent border-radius clipping */ +.x-title-text, +.x-title-text-default { + overflow: visible !important; +} + +.x-panel-bodyWrap, +.x-panel-bodyWrap-default { + margin: 0 !important; + padding: 0 !important; + overflow: visible !important; +} + +/* Remove borders from nested panels */ +.x-panel-body > .x-box-layout-ct, +.x-panel-body > .x-container, +.x-panel-body > .x-box-inner, +[id*="pmxGauge"] { + border: none !important; +} + +.x-panel-header-title-default, +.x-window-header-title-default { + color: var(--ctp-text) !important; +} + +.x-panel-header-default .x-tool-tool-el { + background-color: transparent; +} + +.x-tool-img { + filter: brightness(175%); +} + +.x-tool-over .x-tool-img { + filter: brightness(200%); +} + +/* Resource tree — panel body border */ +div[id^="pveResourceTree-"][id$="-body"] { + border-color: var(--ctp-base) !important; +} + +/* Resource tree — remove row separators */ +[id^="pveResourceTree-"].x-tree-panel td.x-grid-cell, +[id^="pveResourceTree-"].x-tree-panel .x-grid-td, +[id^="pveResourceTree-"].x-tree-panel .x-grid-cell { + border-bottom: none !important; +} + +/* Resource tree — row spacing */ +div[id^="pveResourceTree"] .x-grid-cell { + padding-top: 3px !important; + padding-bottom: 3px !important; +} + +/* Summary/stats panel radius overrides */ +.pveStatusPanel, +.x-panel-default-framed, +.x-panel-body-default-framed { + border-radius: 12px !important; +} + +.x-panel-header-default-framed { + border-radius: 12px 12px 0 0 !important; +} + +/* Column widget panel radius */ +.x-panel.x-column > .x-panel-bodyWrap > .x-panel-body.x-panel-body-default { + border-radius: var(--pm-radius-lg) !important; +} + +/* ===================================================== + SPLITTERS / SEPARATORS + ===================================================== */ +.x-splitter-vertical { + background-color: transparent !important; + border-left: 1px solid var(--ctp-surface1) !important; + border-right: none !important; + width: 1px !important; +} + +.x-splitter-horizontal { + background-color: var(--ctp-crust) !important; + border-top: 1px solid var(--ctp-surface1) !important; +} + +.x-splitter { + background-color: var(--ctp-crust) !important; +} + +.x-keyboard-mode .x-splitter-focus::after { + border-color: var(--ctp-teal) !important; +} + +.x-layout-split-bottom { + opacity: 0.7; +} + +/* Toolbox tree (pve-nav) right border — full height */ +.pve-toolbar-bg { + border-right: 1px solid var(--ctp-surface1) !important; + z-index: 3 !important; +} + +.x-treelist.x-treelist-pve-nav { + border-right: none !important; +} + +/* ===================================================== + TOOLBARS + ===================================================== */ +.x-toolbar, +.x-toolbar-default { + background-color: var(--ctp-base) !important; + border-color: var(--ctp-surface1) !important; +} + +.x-toolbar-default.x-docked-top { + border: none !important; + border-bottom: 1px solid var(--ctp-surface1) !important; +} + +.x-toolbar-default .x-toolbar-separator { + border-color: var(--ctp-surface1); +} + +.x-toolbar-text-default { + color: var(--ctp-subtext0); +} + +/* ===================================================== + PRIMARY BUTTONS — Catppuccin Mauve + ===================================================== */ +.x-btn-default-small { + background-color: var(--ctp-teal) !important; + border: 1px solid rgba(148, 226, 213, 0.4) !important; + border-radius: var(--pm-radius-md) !important; + transition: background-color 0.15s ease, box-shadow 0.15s ease !important; +} + +.x-btn-default-small .x-btn-inner { + color: var(--ctp-on-accent) !important; + font-weight: 600 !important; +} + +.x-btn-default-small .x-btn-icon-el { + color: var(--ctp-on-accent) !important; +} + +.x-btn-default-small.x-btn-over, +.x-keyboard-mode .x-btn-default-small.x-btn-focus { + background-color: #a7e9de !important; + box-shadow: 0 0 0 3px var(--ctp-accent-subtle) !important; +} + +.x-btn-default-small.x-btn.x-btn-disabled { + background-color: var(--ctp-teal) !important; + opacity: 0.4; +} + +.x-btn-default-small.x-btn.x-btn-pressed { + background-color: #81d3c6 !important; +} + +/* Button height consistency — 28px with vertical centering */ +/* Exclude tag edit buttons (display:none when hidden, :has(.fa-check) for checkmark) */ +.x-btn.x-btn-default-small:not(.x-btn-default-toolbar-small):not([style*="display: none"]):not([style*="display:none"]):not(:has(.fa-check)) { + height: 28px !important; + min-height: 28px !important; + display: flex !important; + align-items: center !important; + padding: 3px 8px !important; +} + +/* Fix button inner element centering for proper icon alignment (issue #17) */ +.x-btn.x-btn-default-small:not(.x-btn-default-toolbar-small):not([style*="display: none"]):not([style*="display:none"]):not(:has(.fa-check)) .x-btn-wrap { + display: flex !important; + align-items: center !important; +} + +.x-btn.x-btn-default-small:not(.x-btn-default-toolbar-small):not([style*="display: none"]):not([style*="display:none"]):not(:has(.fa-check)) .x-btn-inner { + display: flex !important; + align-items: center !important; +} + +/* Fix dropdown arrows on split/arrow buttons */ +.x-btn-wrap.x-btn-arrow-right::after, +.x-btn-wrap.x-btn-split-right::after { + height: 16px !important; + min-height: 16px !important; + width: 20px !important; + display: flex !important; + align-items: center !important; +} + +/* Fix icon-only buttons — hide   inner element when button has no text */ +.x-btn-no-text .x-btn-inner, +.x-btn-button.x-btn-no-text .x-btn-inner, +.x-btn-button-default-toolbar-small.x-btn-no-text .x-btn-inner-default-toolbar-small, +.x-btn-button-default-small.x-btn-no-text .x-btn-inner-default-small, +.x-btn-button-default-small.x-btn-no-text > .x-btn-inner-default-small { + display: none !important; +} + +/* Specific fix for fa-desktop icon (Create VM) — visually bottom-heavy */ +.x-btn-icon-el.fa-desktop { + transform: translateY(1.1px) !important; +} + +/* ===================================================== + SECONDARY / TOOLBAR BUTTONS + ===================================================== */ +.x-btn-default-toolbar-small { + background-color: var(--ctp-surface0) !important; + border: 1px solid var(--ctp-surface1) !important; + border-radius: var(--pm-radius-md) !important; + transition: background-color 0.15s ease, border-color 0.15s ease !important; +} + +.x-btn-default-toolbar-small .x-btn-inner-default-toolbar-small, +.x-btn-default-toolbar-small .x-btn-icon-el-default-toolbar-small { + color: var(--ctp-text) !important; +} + +.x-btn-default-toolbar-small .x-btn-wrap-default-toolbar-small.x-btn-arrow-right::after, +.x-btn-default-toolbar-small .x-btn-wrap-default-toolbar-small.x-btn-split-right::after { + filter: brightness(150%); +} + +.x-btn-default-toolbar-small.x-btn-over, +.x-keyboard-mode .x-btn-default-toolbar-small.x-btn-focus { + background-color: var(--ctp-surface1) !important; + border-color: var(--ctp-surface2) !important; +} + +.x-btn-default-toolbar-small.x-btn.x-btn-disabled { + background-color: var(--ctp-surface0) !important; + opacity: 0.4; +} + +.x-btn-default-toolbar-small.x-btn.x-btn-menu-active, +.x-btn-default-toolbar-small.x-btn.x-btn-pressed { + background-color: var(--ctp-teal) !important; + border-color: var(--ctp-teal) !important; + padding: 4px 8px !important; /* Fix #30: prevent width change on dropdown */ +} + +.x-btn-default-toolbar-small.x-btn.x-btn-pressed .x-btn-inner-default-toolbar-small, +.x-btn-default-toolbar-small.x-btn.x-btn-pressed .x-btn-icon-el-default-toolbar-small, +.x-btn-default-toolbar-small.x-btn.x-btn-pressed .x-btn-inner-default-small, +.x-btn-default-toolbar-small.x-btn.x-btn-pressed .x-btn-icon-el-default-small { + color: var(--ctp-on-accent) !important; +} + +/* Segmented buttons */ +.x-segmented-button { + border-radius: var(--pm-radius-md) !important; +} + +.x-segmented-button .x-btn, +.x-segmented-button .x-btn-default-small, +.x-segmented-button .x-btn-inner, +.x-segmented-button .x-btn-wrap { + border-radius: var(--pm-radius-md) !important; +} + +/* Inline buttons (Documentation, Help) */ +.proxmox-inline-button { + height: 28px !important; + min-height: 28px !important; + display: flex !important; + align-items: center !important; + padding: 3px 8px !important; + background-color: var(--ctp-surface0) !important; + border: 1px solid var(--ctp-surface1) !important; + border-radius: var(--pm-radius-md) !important; + color: var(--ctp-text) !important; + transition: background-color 0.15s ease !important; +} + +.proxmox-inline-button:hover, +.proxmox-inline-button.x-btn-over { + background-color: var(--ctp-surface1) !important; + border-color: var(--ctp-overlay0) !important; +} + +.proxmox-inline-button:active, +.proxmox-inline-button.x-btn-pressed { + background-color: var(--ctp-surface2) !important; +} + +.proxmox-inline-button .x-btn-inner, +.proxmox-inline-button .x-btn-icon-el { + color: var(--ctp-text) !important; +} + +/* Pressed/active inline buttons get accent bg from toolbar rules — use on-accent text */ +.proxmox-inline-button.x-btn-pressed .x-btn-inner, +.proxmox-inline-button.x-btn-pressed .x-btn-icon-el, +.proxmox-inline-button.x-btn-menu-active .x-btn-inner, +.proxmox-inline-button.x-btn-menu-active .x-btn-icon-el { + color: var(--ctp-on-accent) !important; +} + +/* ===================================================== + FORM ELEMENTS + ===================================================== */ +.x-form-trigger-default { + background-color: var(--ctp-surface0) !important; +} + +.x-form-text-default { + background-color: var(--ctp-surface0) !important; + color: var(--ctp-text) !important; + border-radius: var(--pm-radius-sm) !important; +} + +.x-form-trigger-wrap, +.x-form-trigger-wrap-default { + border-color: var(--ctp-surface1) !important; + background-color: var(--ctp-surface0) !important; + border-radius: var(--pm-radius-sm) !important; + transition: border-color 0.15s ease !important; +} + +.x-form-trigger-wrap-default.x-form-trigger-wrap-focus { + border-color: var(--ctp-teal) !important; + box-shadow: 0 0 0 3px var(--ctp-accent-subtle) !important; +} + +.x-form-item-label-default, +.x-form-cb-label-default { + color: var(--ctp-text) !important; +} + +.x-form-display-field-default { + color: var(--ctp-subtext0) !important; + border-radius: var(--pm-radius-md) !important; +} + +.x-form-spinner-default { + background-color: var(--ctp-surface0) !important; +} + +.x-fieldset, +.x-fieldset-default { + border-color: var(--ctp-surface1) !important; + border-radius: var(--pm-radius-lg) !important; +} + +.x-fieldset-header-default > .x-fieldset-header-text { + color: var(--ctp-text) !important; +} + +/* ===================================================== + CHECKBOXES & RADIOS — Catppuccin styled + ===================================================== */ + +/* Base: remove sprite, styled as custom control */ +.x-form-checkbox, .x-form-checkbox-default, +.x-form-radio, .x-form-radio-default { + background-image: none !important; + background-color: var(--ctp-surface0) !important; + border: 1.5px solid var(--ctp-overlay0) !important; + width: 16px !important; + height: 16px !important; + display: inline-block !important; + box-sizing: border-box !important; + cursor: pointer !important; + transition: border-color 0.12s ease, background-color 0.12s ease !important; +} + +/* Checkbox: rounded square */ +.x-form-checkbox, .x-form-checkbox-default { + border-radius: 3px !important; +} + +/* Radio: circle + ::after inner dot */ +.x-form-radio, .x-form-radio-default { + border-radius: 50% !important; + position: relative !important; + transform: translateZ(0) !important; + box-shadow: inset 0 0 0 0 transparent !important; +} + +.x-form-radio::after { + content: '' !important; + position: absolute !important; + top: 50% !important; + left: 50% !important; + width: 7px !important; + height: 7px !important; + border-radius: 50% !important; + background: transparent !important; + transform: translate(-50%, -50%) scale(0) !important; + transition: transform 0.15s ease, background 0.15s ease !important; + pointer-events: none !important; +} + +/* Hover */ +.x-form-checkbox:hover, .x-form-checkbox-default:hover, +.x-form-cb-wrap:hover .x-form-checkbox { + border-color: var(--ctp-teal) !important; +} + +.x-form-radio:hover, .x-form-radio-default:hover, +.x-form-cb-wrap:hover .x-form-radio { + border-color: var(--ctp-teal) !important; +} + +/* CHECKED checkbox — Mauve fill + white SVG checkmark */ +.x-form-cb-checked .x-form-checkbox, +.x-form-cb-checked .x-form-checkbox-default { + background-color: var(--ctp-teal) !important; + border-color: var(--ctp-teal) !important; + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 8'%3E%3Cpath d='M1 4l3 3 5-6' fill='none' stroke='%231e1e2e' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") !important; + background-repeat: no-repeat !important; + background-position: center !important; + background-size: 9px 7px !important; +} + +/* SELECTED radio — Mauve dot */ +.x-form-cb-checked .x-form-radio, +.x-form-cb-checked .x-form-radio-default { + border-color: var(--ctp-teal) !important; + background-color: var(--ctp-base) !important; +} + +.x-form-cb-checked .x-form-radio::after { + background: var(--ctp-teal) !important; + transform: translate(-50%, -50%) scale(1) !important; +} + +/* ===================================================== + BOUNDLIST / DROPDOWNS + ===================================================== */ +.x-boundlist { + background-color: var(--ctp-mantle) !important; + border: 1px solid var(--ctp-surface1) !important; + border-radius: var(--pm-radius-md) !important; + box-shadow: 0 8px 24px rgba(17, 17, 27, 0.7) !important; + padding: 2px !important; + overflow: hidden !important; +} + +.x-boundlist-item { + background-color: transparent !important; + color: var(--ctp-text) !important; + border-radius: var(--pm-radius-sm) !important; + padding: 2px 6px !important; + line-height: normal !important; + border: none !important; + cursor: pointer !important; + outline: none !important; + box-shadow: none !important; +} + +.x-boundlist-selected { + background-color: var(--ctp-select-overlay) !important; + color: var(--ctp-text) !important; +} + +.x-boundlist-item-over { + background-color: var(--ctp-hover-overlay) !important; +} + +/* ===================================================== + GRIDS / TABLES + ===================================================== */ +.x-grid, +.x-grid-view { + border-radius: 0 !important; +} + +.x-column-header { + border-color: var(--ctp-surface1) !important; + background-color: transparent !important; +} + +.x-column-header-inner, +.x-column-header-text { + color: var(--ctp-text) !important; + font-weight: 600 !important; +} + +.x-column-header-trigger { + border-color: var(--ctp-surface1) !important; +} + +.x-grid-item, +.x-column-header-default, +.x-grid-cell-row-numberer { + color: var(--ctp-text) !important; + background-color: var(--ctp-base) !important; +} + +.x-grid-cell-special { + border-color: var(--ctp-surface1) !important; +} + +.x-grid-group-hd { + background-color: var(--ctp-base) !important; + border-color: var(--ctp-surface1) !important; +} + +.x-grid-group-title { + color: var(--ctp-text) !important; +} + +.x-grid-header-ct { + background-color: var(--ctp-mantle) !important; + border: 1px solid var(--ctp-surface0) !important; + border-radius: var(--pm-radius-lg) var(--pm-radius-lg) 0 0 !important; +} + +.x-grid-item-alt { + background-color: var(--ctp-crust) !important; +} + +.x-grid-with-row-lines .x-grid-item { + border-color: var(--ctp-surface0) !important; +} + +.x-grid-cell { + border-bottom: 1px solid rgba(69, 71, 90, 0.4) !important; +} + +.x-grid-item-over, +.x-grid-with-row-lines .x-grid-item.x-grid-item-over { + background-color: var(--ctp-hover-overlay) !important; +} + +.x-grid-item-selected, +.x-grid-with-row-lines .x-grid-item.x-grid-item-selected { + background-color: var(--ctp-select-overlay) !important; +} + +.x-column-header-over, +.x-column-header-open { + background-color: var(--ctp-hover-overlay) !important; +} + +.x-column-header-sort-ASC, +.x-column-header-sort-DESC { + background-color: var(--ctp-hover-overlay) !important; +} + +.x-grid-row-summary .x-grid-cell, +.x-grid-row-summary .x-grid-rowwrap, +.x-grid-row-summary .x-grid-cell-rowbody { + background-color: var(--ctp-base) !important; + border-color: var(--ctp-surface1); +} + +.x-grid-with-col-lines .x-grid-cell, +.x-grid-with-col-lines .x-grid-item-over .x-grid-cell, +.x-grid-with-col-lines .x-grid-item-selected .x-grid-cell { + border-color: var(--ctp-surface1) !important; +} + +.x-dd-drag-proxy { + background-color: var(--ctp-mantle); + border-color: var(--ctp-surface1); + color: var(--ctp-text); +} + +.x-keyboard-mode .x-grid-item-focused { + background-color: var(--ctp-hover-overlay) !important; + color: var(--ctp-text) !important; +} + +/* Remove blue outline from focused/selected items in resource tree */ +.x-keyboard-mode .x-grid-item-focused .x-grid-cell-inner::before, +.x-keyboard-mode .x-grid-item-selected .x-grid-cell-inner::before, +.x-grid-item-selected .x-grid-cell-inner::before, +.x-grid-item-focused .x-grid-cell-inner::before, +[id^="pveResourceTree"] .x-grid-item-selected .x-grid-cell-inner::before, +[id^="pveResourceTree"] .x-grid-item-focused .x-grid-cell-inner::before { + content: none !important; + display: none !important; + border: none !important; +} + +.x-grid-empty { + background-color: var(--ctp-base) !important; + color: var(--ctp-subtext0) !important; +} + +/* Grid info (pve-info-grid) and RRD view */ +.pve-info-grid { + border-radius: 12px !important; +} + +.pve-rrdview, +.rrdview { + border-radius: 12px !important; +} + +.pve-summary-status, +.x-container .pve-status { + border-radius: var(--pm-radius-lg) !important; +} + +[id^="pveGuestStatusView-"][id$="-body"], +[id^="pmxNotesView-"] .x-panel-body { + border-radius: var(--pm-radius-lg) !important; +} + +.x-panel-default[id*="notes"], +.pve-notes-view { + border-radius: var(--pm-radius-lg) !important; +} + +/* Floating grid pickers (storage/ISO selectors) */ +.x-layer.x-grid .x-grid-view, +.x-panel.x-layer.x-grid .x-grid-view, +.x-panel.x-layer.x-grid, +.x-layer.x-panel.x-grid { + border-radius: var(--pm-radius-sm) !important; +} + +.x-layer.x-grid .x-grid-item-over, +.x-layer.x-grid .x-grid-item-selected, +.x-panel.x-layer.x-grid .x-grid-item-over, +.x-panel.x-layer.x-grid .x-grid-item-selected { + border-radius: var(--pm-radius-sm) !important; + outline: none !important; + box-shadow: none !important; +} + +.x-layer.x-grid .x-grid-item-over td, +.x-layer.x-grid .x-grid-item-selected td, +.x-layer.x-grid .x-grid-item-over .x-grid-cell, +.x-layer.x-grid .x-grid-item-selected .x-grid-cell, +.x-panel.x-layer.x-grid .x-grid-item-over td, +.x-panel.x-layer.x-grid .x-grid-item-selected td, +.x-panel.x-layer.x-grid .x-grid-item-over .x-grid-cell, +.x-panel.x-layer.x-grid .x-grid-item-selected .x-grid-cell { + border-radius: 0 !important; +} + +.x-layer.x-grid .x-grid-item-over td:first-child, +.x-layer.x-grid .x-grid-item-selected td:first-child, +.x-panel.x-layer.x-grid .x-grid-item-over td:first-child, +.x-panel.x-layer.x-grid .x-grid-item-selected td:first-child { + border-radius: var(--pm-radius-sm) 0 0 var(--pm-radius-sm) !important; +} + +.x-layer.x-grid .x-grid-item-over td:last-child, +.x-layer.x-grid .x-grid-item-selected td:last-child, +.x-panel.x-layer.x-grid .x-grid-item-over td:last-child, +.x-panel.x-layer.x-grid .x-grid-item-selected td:last-child { + border-radius: 0 var(--pm-radius-sm) var(--pm-radius-sm) 0 !important; +} + +/* ===================================================== + MENUS + ===================================================== */ +.x-menu, +.x-menu-default { + background-color: var(--ctp-crust) !important; + border: 1px solid var(--ctp-surface0) !important; + border-radius: var(--pm-radius-lg) !important; + box-shadow: 0 8px 24px rgba(17, 17, 27, 0.8) !important; + padding: 2px !important; + overflow: hidden !important; +} + +.x-menu-body-default { + background-color: transparent !important; + padding: 4px !important; +} + +.x-menu-header { + background-color: transparent !important; + color: var(--ctp-text) !important; +} + +/* Menu icon separator — hide */ +.x-menu-icon-separator-default { + display: none !important; +} + +/* Menu item layout (flexbox reordering) */ +.x-menu-item-default > .x-menu-item-link { + display: flex !important; + align-items: center !important; + flex-direction: row !important; + gap: 4px !important; + justify-content: flex-start !important; + flex-wrap: nowrap !important; + border-radius: var(--pm-radius-md) !important; + padding: 4px 8px !important; + line-height: 20px !important; + cursor: pointer !important; + outline: none !important; + box-shadow: none !important; + white-space: nowrap !important; + text-decoration: none !important; +} + +.x-menu-item-text-default { + color: var(--ctp-text) !important; + font-size: 13px !important; + order: 1 !important; + margin-left: 0 !important; + text-align: left !important; + line-height: 20px !important; + display: inline-flex !important; + align-items: center !important; + flex: 1 1 auto !important; + width: auto !important; + white-space: nowrap !important; +} + +.x-menu-item-icon-default { + color: var(--ctp-subtext0) !important; + order: -1 !important; + position: relative !important; + float: none !important; + margin-right: 8px !important; + margin-left: 0 !important; + left: auto !important; + top: auto !important; + width: 16px !important; + text-align: center !important; + display: inline-flex !important; + align-items: center !important; + justify-content: center !important; + height: 20px !important; + line-height: 20px !important; + vertical-align: middle !important; + flex: 0 0 16px !important; + align-self: center !important; +} + +.x-menu-item-arrow, +.x-menu-item-arrow-default { + order: 2 !important; + margin-left: auto !important; +} + +.x-menu-item-default.x-menu-item-separator { + background-color: var(--ctp-surface0) !important; + border: none !important; + height: 1px !important; + margin: 6px 4px !important; +} + +.x-menu-item-default.x-menu-item-focus, +.x-menu-item-default.x-menu-item-active, +.x-menu-item:hover { + background-color: var(--ctp-surface0) !important; + color: var(--ctp-text) !important; + border-radius: var(--pm-radius-md) !important; +} + +.x-menu-item-active .x-menu-item-text-default, +.x-menu-item-focus .x-menu-item-text-default { + color: var(--ctp-text) !important; +} + +.x-menu-item-active .x-menu-item-icon-default, +.x-menu-item-focus .x-menu-item-icon-default { + color: var(--ctp-lavender) !important; +} + +/* ===================================================== + PROGRESS BARS + ===================================================== */ + +/* Fix: Widget containers need overflow visible to not clip progress bars */ +.x-container[id^="pmxInfoWidget"], +.x-container.x-box-layout-ct { + overflow: visible !important; +} + +.x-progress, +.x-progress-default { + background-color: var(--ctp-surface0) !important; + border-radius: 5px !important; +} + +.x-progress-default .x-progress-bar-default { + background-color: var(--ctp-teal) !important; + border-radius: 5px !important; + transition: width 0.4s ease !important; +} + +.x-progress-default .x-progress-text { + color: var(--ctp-text) !important; +} + +/* Text overlaid on the progress bar fill — use on-accent for contrast against Mauve/Yellow/Red fills */ +.x-progress-bar .x-progress-text { + color: var(--ctp-on-accent) !important; +} + +.x-progress.warning .x-progress-bar { + background-color: var(--ctp-yellow) !important; +} + +.x-progress.critical .x-progress-bar { + background-color: var(--ctp-red) !important; +} + +/* ===================================================== + TABS — Catppuccin underline style + Flat tabs with Mauve underline on active tab + ===================================================== */ +.x-tab-bar, +.x-tab-bar-default { + background-color: var(--ctp-base) !important; + border-radius: 0 !important; + border-bottom: 1px solid var(--ctp-surface1) !important; + padding-bottom: 0 !important; +} + +/* Overflow visible for the underline indicator */ +.x-tab-bar .x-box-inner, +.x-tab-bar .x-box-target, +.x-tab-bar-body, +.x-tab-bar-body-default { + overflow: visible !important; +} + +/* Base tab */ +.x-tab, +.x-tab-default, +.x-tab-default-top { + background-color: transparent !important; + border: none !important; + border-radius: var(--pm-radius-md) var(--pm-radius-md) 0 0 !important; + padding: 8px 16px 8px !important; + overflow: visible !important; + margin-bottom: 0 !important; + transition: color 0.15s ease !important; + outline: none !important; + box-shadow: none !important; +} + +/* Remove ::after from inactive tabs */ +.x-tab::after { + display: none !important; +} + +.x-tab-inner-default { + color: var(--ctp-subtext0) !important; + font-size: 13px !important; +} + +.x-tab-default.x-tab-over { + background-color: transparent !important; +} + +.x-tab-default.x-tab-over .x-tab-inner-default { + color: var(--ctp-text) !important; +} + +/* Active tab */ +.x-tab-default.x-tab.x-tab-active { + background-color: transparent !important; + border: none !important; + overflow: visible !important; + margin-bottom: 0 !important; + outline: none !important; + box-shadow: none !important; +} + +/* Mauve underline indicator on active tab */ +.x-tab-default.x-tab.x-tab-active::after { + content: '' !important; + display: block !important; + position: absolute !important; + bottom: 0 !important; + left: 0 !important; + right: 0 !important; + height: 2px !important; + background: var(--ctp-teal) !important; + z-index: 10 !important; + border-radius: 2px 2px 0 0 !important; + pointer-events: none !important; +} + +.x-tab-active .x-tab-inner-default { + color: var(--ctp-text) !important; + font-weight: 600 !important; +} + +.x-tab-default.x-tab.x-tab-disabled { + background-color: transparent !important; + border: none !important; + color: var(--ctp-overlay0) !important; + margin-bottom: 0 !important; +} + +/* Focus states — no outline */ +.x-keyboard-mode .x-tab-default.x-tab-focus, +.x-keyboard-mode .x-tab-default.x-tab-focus.x-tab-active { + background-color: transparent !important; + border: none !important; + outline: none !important; + box-shadow: none !important; + margin-bottom: 0 !important; +} + +.x-keyboard-mode .x-tab-default.x-tab-focus.x-tab-active::after { + content: '' !important; + display: block !important; + position: absolute !important; + bottom: 0 !important; + left: 0 !important; + right: 0 !important; + height: 2px !important; + background: var(--ctp-teal) !important; + z-index: 10 !important; + pointer-events: none !important; +} + +/* Kill ALL tab interaction outlines/shadows */ +.x-tab:focus, +.x-tab *:focus, +.x-tab-focus, +.x-tab-active.x-tab-focus, +.x-tab-inner-focus, +.x-tab-button-focus, +.x-tab-pressed, +.x-tab-active.x-tab-pressed, +.x-tab-over, +.x-tab:active, +.x-tab *:active { + outline: none !important; + box-shadow: none !important; +} + +.x-tabpanel-child { + border-radius: 0 0 var(--pm-radius-lg) var(--pm-radius-lg) !important; +} + +/* Tab hover/active corners */ +.x-tab-default.x-tab-over, +.x-tab-default.x-tab.x-tab-active { + border-radius: var(--pm-radius-md) var(--pm-radius-md) 0 0 !important; +} + +/* ===================================================== + TOOLTIPS + ===================================================== */ +.x-tip, +.x-tip-default { + background-color: var(--ctp-mantle) !important; + border: 1px solid var(--ctp-surface1) !important; + border-radius: var(--pm-radius-md) !important; + box-shadow: 0 4px 12px rgba(17, 17, 27, 0.5); +} + +.x-tip-body-default { + color: var(--ctp-text) !important; +} + +.x-tip-form-invalid { + background-color: var(--ctp-mantle) !important; + border-color: var(--ctp-red) !important; +} + +.x-tip-body-form-invalid { + color: var(--ctp-red) !important; +} + +/* ===================================================== + TREE NAVIGATION (Sidebar) + ===================================================== */ +.x-treelist-item { + background-color: var(--ctp-base) !important; + border-radius: var(--pm-radius-md) !important; +} + +/* Pseudo-element approach for hover/selected highlighting */ +.x-treelist-row { + border-radius: var(--pm-radius-md) !important; + background-color: transparent !important; + position: relative !important; + z-index: 0 !important; +} + +.x-treelist-row::before { + content: ""; + position: absolute; + top: 1px; + bottom: 1px; + left: 0; + right: 4px; + border-radius: var(--pm-radius-md); + background-color: transparent; + z-index: -1; + pointer-events: none; + transition: background-color 0.15s ease; +} + +/* Fix toolbox tree item text overlapping icons */ +.x-treelist-item-text { + margin-left: 28px !important; +} + +/* Toolbox tree items — bright text */ +.x-treelist-item-text, +.x-treelist-item-icon, +.x-treelist.x-treelist-pve-nav .x-treelist-item-text, +.x-treelist.x-treelist-pve-nav .x-treelist-item-icon { + color: var(--ctp-subtext1) !important; +} + +/* Hover state — apply to pseudo-element */ +.x-treelist-row-over { + background-color: transparent !important; +} + +.x-treelist-row-over::before { + background-color: var(--ctp-hover-overlay) !important; +} + +.x-treelist-row-over .x-treelist-item-icon, +.x-treelist-row-over .x-treelist-item-text { + background-color: transparent !important; + color: var(--ctp-text) !important; +} + +/* Selected/active item — Mauve highlight */ +.x-treelist-item-selected > .x-treelist-row { + background-color: transparent !important; +} + +.x-treelist-item-selected > .x-treelist-row::before, +.x-treelist-item-selected > .x-treelist-row:hover::before { + background-color: var(--ctp-teal) !important; +} + +.x-treelist-item-selected .x-treelist-item-text, +.x-treelist-item-selected .x-treelist-item-icon, +.x-treelist.x-treelist-pve-nav .x-treelist-item-selected .x-treelist-item-text, +.x-treelist.x-treelist-pve-nav .x-treelist-item-selected .x-treelist-item-icon { + color: var(--ctp-on-accent) !important; +} + +.x-treelist-pve-nav { + background-color: var(--ctp-base) !important; + border-color: var(--ctp-surface1) !important; +} + +/* Tree navigation radius overrides */ +.x-treelist-item, +.x-treelist-item-tool { + border-radius: var(--pm-radius-sm) !important; +} + +.x-treelist-row, +.x-treelist-row:hover, +.x-treelist-row-over, +.x-treelist-item-selected > .x-treelist-row, +.x-treelist-item-selected > .x-treelist-row:hover, +.x-treelist-item-expanded > .x-treelist-row, +.x-treelist-item-expanded > .x-treelist-row-over, +.x-treelist-item-expandable > .x-treelist-row, +.x-treelist-item-expandable > .x-treelist-row-over { + border-radius: var(--pm-radius-sm) !important; +} + +.x-treelist-row::before { + border-radius: var(--pm-radius-sm) !important; +} + +.x-treelist-item-wrap, +.x-treelist-item-text, +.x-treelist-row, +.x-treelist-container, +.x-treelist-root-container, +.x-treelist, +.x-treelist-pve-nav { + border-radius: var(--pm-radius-sm) !important; +} + +/* Cursor pointer for interactive tree/grid items */ +.x-grid-cell, +.x-grid-cell-inner, +.x-tree-elbow-img, +.x-tree-icon, +.x-treelist-item, +.x-treelist-row, +.x-treelist-item-wrap, +.x-treelist-item-text, +.x-treelist-item-icon { + cursor: pointer !important; +} + +/* ===================================================== + WINDOWS / MODALS + ===================================================== */ +.x-window, +.x-window-default { + background-color: var(--ctp-crust) !important; + border: 1px solid var(--ctp-surface1) !important; + border-radius: var(--pm-radius-lg) !important; + box-shadow: 0 8px 24px rgba(17, 17, 27, 0.6) !important; + overflow: hidden !important; +} + +.x-window .x-window-header, +.x-window-header-default { + background-color: var(--ctp-mantle) !important; + border-color: transparent !important; + border-radius: var(--pm-radius-lg) var(--pm-radius-lg) 0 0 !important; +} + +.x-window-header-default .x-mask { + background-color: rgba(17, 17, 27, 0.7); +} + +.x-window .x-window-body, +.x-window-body-default { + background-color: var(--ctp-base) !important; + border-color: var(--ctp-surface1) !important; + color: var(--ctp-text) !important; + border-radius: 0 0 var(--pm-radius-lg) var(--pm-radius-lg) !important; +} + +.x-window-ghost { + background-color: var(--ctp-base) !important; +} + +.x-window-header-default .x-tool-img { + background-color: transparent; +} + +.x-message-box .x-window-body { + background-color: var(--ctp-mantle) !important; +} + +/* Respect ExtJS inline display:none on hidden dialog buttons */ +.x-message-box .x-btn.x-btn-default-small[style*="display: none"], +.x-message-box .x-btn.x-btn-default-small[style*="display:none"], +.x-window .x-toolbar-footer .x-btn[style*="display: none"], +.x-window .x-toolbar-footer .x-btn[style*="display:none"] { + display: none !important; +} + +/* Login dialog — clean inner panel borders */ +.x-window:has(#pveloginrealm) .x-panel-body { + border: none !important; + background: transparent !important; + width: auto !important; +} + +/* ===================================================== + CONSOLE / TERMINAL + ===================================================== */ +div.monitor { + border-color: var(--ctp-surface1); +} + +.install-mask { + background-color: var(--ctp-crust); + color: var(--ctp-subtext0); +} + +.x-window.install-mask { + box-shadow: rgba(17, 17, 27, 0.5) 0 4px 20px !important; +} + +/* ===================================================== + LEGEND / CHARTS + ===================================================== */ +.x-legend-container { + background-color: var(--ctp-base) !important; +} + +.x-legend-horizontal .x-legend-item { + background-color: var(--ctp-mantle) !important; + color: var(--ctp-text) !important; + border: 1px solid var(--ctp-surface0) !important; +} + +/* Chart/RRD panel backgrounds */ +div[id*="rrdchart"], +.pve-rrddatastore, +.pmx-panel-rrd { + background-color: var(--ctp-base) !important; +} + +.proxmox-rrd-panel canvas, +.proxmox-widget-toolkit canvas, +canvas.x-surface, +.x-surface canvas { + background-color: transparent !important; + opacity: 1 !important; +} + +.proxmox-rrd-panel, +.proxmox-rrd-chart { + background-color: var(--ctp-base) !important; +} + +/* Chart text/labels */ +.x-surface text, +svg text { + fill: var(--ctp-text) !important; +} + +/* ===================================================== + PROXMOX-SPECIFIC OVERRIDES + ===================================================== */ + +/* Logo inversion */ +img[id^="proxmoxlogo-"][id$="-img"], +img[id^="proxmoxLogoSvg-"][id$="-img"] { + filter: invert(1) hue-rotate(180deg); +} + +/* Invalid/warning/disabled rows */ +.proxmox-invalid-row { + background-color: rgba(243, 139, 168, 0.15) !important; +} + +.proxmox-warning-row { + background-color: rgba(250, 179, 135, 0.15) !important; +} + +.proxmox-disabled-row td { + color: var(--ctp-overlay0) !important; +} + +/* Hints */ +.pmx-hint { + background-color: rgba(250, 179, 135, 0.15) !important; + white-space: nowrap !important; +} + +.pmx-hint a { + color: var(--ctp-blue) !important; +} + +/* Status text colors — style guide: Information → Teal */ +.info-blue { + color: var(--ctp-teal) !important; +} + +.critical { + color: var(--ctp-red) !important; +} + +/* Links */ +a { + color: var(--ctp-blue) !important; +} + +/* Markdown content */ +.pmx-md code { + background-color: var(--ctp-mantle) !important; + color: var(--ctp-rosewater) !important; + border-radius: var(--pm-radius-sm) !important; +} + +.pmx-md pre code { + border-color: var(--ctp-surface1) !important; + background-color: var(--ctp-crust) !important; +} + +.pmx-md a { + color: var(--ctp-blue) !important; +} + +.pmx-md table { + border-color: var(--ctp-surface1) !important; +} + +.pmx-md th { + background-color: var(--ctp-mantle) !important; + border-color: var(--ctp-surface1) !important; +} + +.pmx-md td { + border-color: var(--ctp-surface1) !important; +} + +/* APT repos */ +.proxmox-apt-repos .x-grid-group-hd { + background-color: var(--ctp-base) !important; + border: none !important; +} + +.proxmox-apt-repos .x-grid-group-title { + color: var(--ctp-text) !important; +} + +/* Tags */ +.pve-edit-tag { + border-radius: var(--pm-radius-md) !important; +} + +.pve-edit-tag.editable span { + background-color: var(--ctp-mantle) !important; + color: var(--ctp-text) !important; + border-color: var(--ctp-surface1) !important; +} + +.x-tree-node-text .proxmox-tag-dark, +.x-tree-node-text .proxmox-tag-light, +.x-grid-cell-inner .proxmox-tag-dark, +.x-grid-cell-inner .proxmox-tag-light, +span.proxmox-tag-dark, +span.proxmox-tag-light { + border-radius: var(--pm-radius-md) !important; +} + +/* Checkmark button in tag edit — match toolbar button size */ +.x-btn.x-btn-default-small:has(.fa-check) { + min-height: 24px !important; + height: 24px !important; + padding: 3px 8px !important; + border-radius: var(--pm-radius-sm) !important; + background-color: var(--ctp-teal) !important; + border: none !important; +} + +.x-btn.x-btn-default-small:has(.fa-check).x-btn-disabled { + background-color: transparent !important; + border: 1px solid var(--ctp-surface1) !important; + opacity: 0.5 !important; +} + +.x-btn.x-btn-default-small:has(.fa-check) .fa-check { + color: var(--ctp-on-accent) !important; +} + +.x-btn.x-btn-default-small:has(.fa-check).x-btn-disabled .fa-check { + color: var(--ctp-overlay1) !important; +} + +.x-btn.x-btn-default-small:has(.fa-check):not(.x-btn-disabled):hover { + background-color: #a7e9de !important; +} + +.x-btn.x-btn-default-small:has(.fa-check) .x-btn-inner { + display: none !important; +} + +/* Date picker */ +.x-datepicker, +.x-datepicker-column-header, +.x-monthpicker { + background-color: var(--ctp-base) !important; + color: var(--ctp-text) !important; + border-color: transparent !important; +} + +.x-datepicker-header, +.x-datepicker-footer, +.x-monthpicker-buttons { + background-color: var(--ctp-mantle) !important; +} + +.x-datepicker-date, +.x-monthpicker-item-inner { + color: var(--ctp-text) !important; +} + +.x-datepicker-selected div.x-datepicker-date, +.x-monthpicker-item a.x-monthpicker-selected, +a.x-monthpicker-item-inner:hover, +div.x-datepicker-date:hover { + background-color: var(--ctp-hover-overlay) !important; + color: var(--ctp-text) !important; +} + +.x-datepicker-today .x-datepicker-date { + border-color: var(--ctp-teal) !important; +} + +.x-datepicker-disabled .x-datepicker-date { + color: var(--ctp-overlay0) !important; +} + +.x-datepicker-prev-day .x-datepicker-date, +.x-datepicker-next-day .x-datepicker-date { + color: var(--ctp-overlay0) !important; +} + +/* Usage bars */ +.usage-wrapper, +.usage { + border-radius: 2px !important; +} + +.usage { + background-color: var(--ctp-overlay2) !important; +} + +/* ===================================================== + SCROLLBARS + ===================================================== */ +::-webkit-scrollbar { + width: 8px; + height: 8px; +} + +::-webkit-scrollbar-track { + background: var(--ctp-base); + border-radius: var(--pm-radius-sm); +} + +::-webkit-scrollbar-thumb { + background: var(--ctp-surface2); + border-radius: var(--pm-radius-sm); + border: 1px solid transparent; + background-clip: padding-box; + transition: background 0.15s ease; +} + +::-webkit-scrollbar-thumb:hover { + background: var(--ctp-overlay0); +} + +::-webkit-scrollbar-corner { + background: var(--ctp-base); +} + +/* Firefox scrollbar */ +* { + scrollbar-width: thin; + scrollbar-color: var(--ctp-surface2) var(--ctp-base); +} + +/* ===================================================== + SELECTION HIGHLIGHT + ===================================================== */ +::selection { + background-color: rgba(147, 153, 178, 0.3); + color: var(--ctp-text); +} + +/* ===================================================== + TRANSITIONS (smooth interactions) + ===================================================== */ + +/* Grid row transitions */ +.x-grid-item { + transition: background-color 0.15s ease !important; +} + +/* Tree pseudo-element transitions */ +.x-treelist-row::before { + transition: background-color 0.15s ease !important; +} + +/* Menu item transitions */ +.x-menu-item-default > .x-menu-item-link { + transition: background-color 0.12s ease !important; +} + +/* Boundlist item transitions */ +.x-boundlist-item { + transition: background-color 0.12s ease !important; +} + +/* Tab transitions */ +.x-tab { + transition: color 0.15s ease !important; +} + +/* Splitter transition */ +.x-splitter { + transition: background-color 0.15s ease !important; +} + +/* Tooltip transition */ +.x-tip { + transition: opacity 0.15s ease !important; +} + +/* Progress bar width transition */ +.x-progress-bar { + transition: width 0.4s ease !important; +} + +/* Scrollbar thumb transition */ +::-webkit-scrollbar-thumb { + transition: background 0.15s ease !important; +} + +/* Window close tool transition */ +.x-tool-img { + transition: filter 0.15s ease !important; +} + +/* ===================================================== + TOOL ICONS - FontAwesome Replacements + (Ported from UniFi v5.86) + Replace sprite-based ExtJS tool icons with crisp + FontAwesome icons for better consistency and clarity + ===================================================== */ + +/* Base styling for all tool icons - remove sprite backgrounds */ +.x-tool-tool-el.x-tool-minus, +.x-tool-img.x-tool-minus, +.x-tool-tool-el.x-tool-collapse-right, +.x-tool-img.x-tool-collapse-right, +.x-tool-tool-el.x-tool-collapse-left, +.x-tool-img.x-tool-collapse-left, +.x-tool-tool-el.x-tool-expand-right, +.x-tool-img.x-tool-expand-right, +.x-tool-tool-el.x-tool-expand-left, +.x-tool-img.x-tool-expand-left, +.x-tool-tool-el.x-tool-maximize, +.x-tool-img.x-tool-maximize, +.x-tool-tool-el.x-tool-restore, +.x-tool-img.x-tool-restore, +.x-tool-tool-el.x-tool-gear, +.x-tool-img.x-tool-gear, +.x-tool-tool-el.x-tool-refresh, +.x-tool-img.x-tool-refresh, +.x-tool-tool-el.x-tool-close, +.x-tool-img.x-tool-close { + background-image: none !important; + font-family: "FontAwesome" !important; + font-size: 14px !important; + line-height: 16px !important; + text-align: center !important; + color: var(--pm-text-dim) !important; + transition: color 0.15s ease !important; + filter: none !important; + width: 16px !important; + height: 16px !important; + display: flex !important; + align-items: center !important; + justify-content: center !important; +} + +/* Close button - slightly larger */ +.x-tool-tool-el.x-tool-close, +.x-tool-img.x-tool-close { + font-size: 20px !important; +} + +/* Individual glyph assignments */ +.x-tool-tool-el.x-tool-minus::before, +.x-tool-img.x-tool-minus::before { + content: "\f010" !important; /* fa-search-minus (zoom out) */ +} + +.x-tool-tool-el.x-tool-collapse-right::before, +.x-tool-img.x-tool-collapse-right::before { + content: "\f054" !important; /* fa-chevron-right */ +} + +.x-tool-tool-el.x-tool-expand-left::before, +.x-tool-img.x-tool-expand-left::before { + content: "\f053" !important; /* fa-chevron-left */ +} + +.x-tool-tool-el.x-tool-collapse-left::before, +.x-tool-img.x-tool-collapse-left::before { + content: "\f053" !important; /* fa-chevron-left */ +} + +.x-tool-tool-el.x-tool-expand-right::before, +.x-tool-img.x-tool-expand-right::before { + content: "\f054" !important; /* fa-chevron-right */ +} + +.x-tool-tool-el.x-tool-maximize::before, +.x-tool-img.x-tool-maximize::before { + content: "\f065" !important; /* fa-expand */ +} + +.x-tool-tool-el.x-tool-restore::before, +.x-tool-img.x-tool-restore::before { + content: "\f066" !important; /* fa-compress */ +} + +.x-tool-tool-el.x-tool-gear::before, +.x-tool-img.x-tool-gear::before { + content: "\f013" !important; /* fa-cog */ +} + +.x-tool-tool-el.x-tool-refresh::before, +.x-tool-img.x-tool-refresh::before { + content: "\f021" !important; /* fa-refresh */ +} + +.x-tool-tool-el.x-tool-close::before, +.x-tool-img.x-tool-close::before { + content: "\f00d" !important; /* fa-times */ +} + +/* Hover state - all tool icons */ +.x-tool:hover .x-tool-tool-el.x-tool-minus, +.x-tool:hover .x-tool-img.x-tool-minus, +.x-tool:hover .x-tool-tool-el.x-tool-collapse-right, +.x-tool:hover .x-tool-img.x-tool-collapse-right, +.x-tool:hover .x-tool-tool-el.x-tool-collapse-left, +.x-tool:hover .x-tool-img.x-tool-collapse-left, +.x-tool:hover .x-tool-tool-el.x-tool-expand-right, +.x-tool:hover .x-tool-img.x-tool-expand-right, +.x-tool:hover .x-tool-tool-el.x-tool-expand-left, +.x-tool:hover .x-tool-img.x-tool-expand-left, +.x-tool:hover .x-tool-tool-el.x-tool-maximize, +.x-tool:hover .x-tool-img.x-tool-maximize, +.x-tool:hover .x-tool-tool-el.x-tool-restore, +.x-tool:hover .x-tool-img.x-tool-restore, +.x-tool:hover .x-tool-tool-el.x-tool-gear, +.x-tool:hover .x-tool-img.x-tool-gear, +.x-tool:hover .x-tool-tool-el.x-tool-refresh, +.x-tool:hover .x-tool-img.x-tool-refresh, +.x-tool:hover .x-tool-tool-el.x-tool-close, +.x-tool:hover .x-tool-img.x-tool-close { + color: var(--pm-text) !important; +} + +/* Disabled state */ +.x-tool-disabled .x-tool-tool-el, +.x-tool-disabled .x-tool-img { + opacity: 0.4 !important; + cursor: default !important; +} + +/* Inline FontAwesome tools (PVE-injected) */ +.x-tool-tool-el[style*="font-family:FontAwesome"], +.x-tool-tool-el[style*="font-family: FontAwesome"] { + color: var(--pm-text-dim) !important; + font-size: 14px !important; + line-height: 16px !important; + display: flex !important; + align-items: center !important; + justify-content: center !important; + width: 16px !important; + height: 16px !important; + transition: color 0.15s ease !important; + background-image: none !important; + background-color: transparent !important; +} + +.x-tool:not(.x-tool-disabled) .x-tool-tool-el[style*="font-family:FontAwesome"], +.x-tool:not(.x-tool-disabled) .x-tool-tool-el[style*="font-family: FontAwesome"] { + cursor: pointer !important; +} + +.x-tool.x-tool-disabled .x-tool-tool-el[style*="font-family:FontAwesome"], +.x-tool.x-tool-disabled .x-tool-tool-el[style*="font-family: FontAwesome"] { + cursor: default !important; + opacity: 0.4 !important; +} + +.x-tool .x-mask { + background-color: transparent !important; + backdrop-filter: none !important; + pointer-events: none !important; +} + +.x-tool:not(.x-tool-disabled):hover .x-tool-tool-el[style*="font-family:FontAwesome"], +.x-tool:not(.x-tool-disabled):hover .x-tool-tool-el[style*="font-family: FontAwesome"] { + color: var(--pm-text) !important; +} diff --git a/themes/theme-catppuccin-mocha.css b/themes/theme-catppuccin-mocha.css new file mode 100644 index 0000000..2fb3a82 --- /dev/null +++ b/themes/theme-catppuccin-mocha.css @@ -0,0 +1,2410 @@ +/*!Catppuccin Mocha*/ +/* + * ProxMorph Theme: Catppuccin Mocha + * Soothing pastel theme for Proxmox VE — the original dark flavor of Catppuccin + * Version: 1.3.0 + * Author: ProxMorph / Catppuccin Community Palette + * + * v1.3.0: Tier 2 baseline fixes — ported from UniFi reference + * - Console/Terminal: monitor border, install mask styling + * - Charts: RRD panel backgrounds, canvas transparency, chart text fills + * - Progress bars: Widget container overflow:visible fix + * - Buttons: 28px height consistency, tag checkmark button styling + * - Windows: Dialog button overlap fix, login dialog clean borders + * - Navigation: cursor:pointer on tree/grid interactive items + * - Proxmox: APT repository grid styling + * + * v1.2.1: Fix selected treelist item text contrast + * - Bumped specificity on selected treelist text/icon rules to beat + * .x-treelist.x-treelist-pve-nav default (0-3-0 → 0-4-0) + * - Text now correctly shows On-Accent (Base) on Mauve highlight + * + * v1.2.0: Contrast & readability fixes + * - Pressed segmented/inline button text: Text → On-Accent on Mauve bg + * - Progress bar fill text: Text → On-Accent on colored fills + * - Loading mask text: filter:invert(90%) → explicit Subtext0 color + * - Added toolbar-pressed rule for x-btn-inner-default-small variant + * + * v1.1.0: Style guide compliance pass (catppuccin/docs/style-guide.md) + * - On Accent text: Crust → Base per style guide + * - Selection overlay: Mauve-tinted → Overlay2@25% per style guide + * - Hover overlay: Lavender-tinted → Overlay2@12% for consistency + * - ::selection: Mauve → Overlay2 per style guide + * - Information color: Blue → Teal per style guide + * - Added --ctp-on-accent semantic variable + * + * v1.0.0: Initial release — Tier 2 production theme + * Catppuccin Mocha palette, border-radius architecture (ported from UniFi), + * custom checkboxes/radios, full grid styling, progress bar states, + * tags, markdown, date picker, usage bars, Firefox scrollbar. + * + * Catppuccin Mocha Color Palette: + * + * ACCENT COLORS: + * - Rosewater: #f5e0dc - Flamingo: #f2cdcd + * - Pink: #f5c2e7 - Mauve: #cba6f7 (Primary Accent) + * - Red: #f38ba8 - Maroon: #eba0ac + * - Peach: #fab387 - Yellow: #f9e2af + * - Green: #a6e3a1 - Teal: #94e2d5 + * - Sky: #89dceb - Sapphire: #74c7ec + * - Blue: #89b4fa - Lavender: #b4befe + * + * NEUTRALS: + * - Text: #cdd6f4 - Subtext 1: #bac2de + * - Subtext 0: #a6adc8 - Overlay 2: #9399b2 + * - Overlay 1: #7f849c - Overlay 0: #6c7086 + * - Surface 2: #585b70 - Surface 1: #45475a + * - Surface 0: #313244 - Base: #1e1e2e + * - Mantle: #181825 - Crust: #11111b + */ + +/* ===================================================== + CSS VARIABLES + ===================================================== */ +:root { + /* Catppuccin Mocha Tokens */ + --ctp-rosewater: #f5e0dc; + --ctp-flamingo: #f2cdcd; + --ctp-pink: #f5c2e7; + --ctp-mauve: #cba6f7; + --ctp-red: #f38ba8; + --ctp-maroon: #eba0ac; + --ctp-peach: #fab387; + --ctp-yellow: #f9e2af; + --ctp-green: #a6e3a1; + --ctp-teal: #94e2d5; + --ctp-sky: #89dceb; + --ctp-sapphire: #74c7ec; + --ctp-blue: #89b4fa; + --ctp-lavender: #b4befe; + + --ctp-text: #cdd6f4; + --ctp-subtext1: #bac2de; + --ctp-subtext0: #a6adc8; + --ctp-overlay2: #9399b2; + --ctp-overlay1: #7f849c; + --ctp-overlay0: #6c7086; + --ctp-surface2: #585b70; + --ctp-surface1: #45475a; + --ctp-surface0: #313244; + --ctp-base: #1e1e2e; + --ctp-mantle: #181825; + --ctp-crust: #11111b; + + /* ProxMorph Semantic Variables */ + --pm-accent: var(--ctp-mauve); + --pm-bg-base: var(--ctp-base); + --pm-bg-surface: var(--ctp-surface0); + --pm-bg-elevated: var(--ctp-surface1); + --pm-text: var(--ctp-text); + --pm-text-dim: var(--ctp-subtext1); + --pm-success: var(--ctp-green); + --pm-warning: var(--ctp-yellow); + --pm-error: var(--ctp-red); + --pm-border: var(--ctp-surface1); + --pm-radius-sm: 4px; + --pm-radius-md: 6px; + --pm-radius-lg: 8px; + + /* Proxmox Widget Toolkit Mappings (REQUIRED) */ + --pwt-panel-background: var(--ctp-base); + --pwt-text-color: var(--ctp-text); + --pwt-gauge-default: var(--ctp-mauve); + --pwt-gauge-back: var(--ctp-surface1); + --pwt-gauge-warn: var(--ctp-yellow); + --pwt-gauge-crit: var(--ctp-red); + --pwt-chart-primary: var(--ctp-mauve); + --pwt-chart-grid-stroke: var(--ctp-surface1); + + /* On Accent text — style guide mandates Base for text on colored backgrounds */ + --ctp-on-accent: var(--ctp-base); + + /* Hover overlay — Overlay2@12% (neutral, per Catppuccin port conventions) */ + --ctp-hover-overlay: rgba(147, 153, 178, 0.12); + /* Selection overlay — Overlay2@25% (style guide: Selection Background → Overlay2 20-30%) */ + --ctp-select-overlay: rgba(147, 153, 178, 0.25); + /* Accent muted (for focus rings) */ + --ctp-accent-muted: rgba(203, 166, 247, 0.4); + --ctp-accent-subtle: rgba(203, 166, 247, 0.15); + + color-scheme: dark; +} + +/* ===================================================== + GLOBAL BORDER-RADIUS ARCHITECTURE + (Ported from UniFi theme — reset everything, selectively re-apply) + ===================================================== */ +.x-border-box, +.x-border-box * { + border-radius: var(--pm-radius-lg); +} + +/* Remove rounded corners from grids/tables/lists */ +.x-grid, +.x-grid *, +.x-grid-header-ct, +.x-grid-header-ct *, +.x-grid-view, +.x-grid-view *, +.x-column-header, +.x-column-header *, +.x-grid-item, +.x-grid-cell, +.x-grid-cell-inner, +.x-grid-row, +table, +table *, +tr, +td, +th, +.x-legend, +.x-legend *, +.x-legend-container, +.x-legend-container *, +.x-legend-item, +.x-legend-horizontal .x-legend-item, +.x-legend-vertical .x-legend-item, +.x-legend-horizontal .x-legend-item:first-child, +.x-legend-horizontal .x-legend-item:last-child, +.x-legend-vertical .x-legend-item:first-child, +.x-legend-vertical .x-legend-item:last-child, +.x-tool, +.x-tool-tool-el, +.x-tool-default, +.x-tool-img { + border-radius: 0 !important; +} + +/* Form elements - exclude from global radius */ +.x-form-item, +.x-form-item-default, +.x-form-item-body, +.x-form-item-body-default, +.x-form-text-field-body, +.x-form-text-field-body-default, +.x-form-fieldcontainer, +.x-field, +.x-field-default, +.x-form-type-text { + border-radius: 0 !important; +} + +/* Reset layout containers that clip elements with overflow:hidden + radius */ +.x-box-layout-ct, +.x-panel-bodyWrap, +.x-panel-bodyWrap-default, +.x-autocontainer-innerCt, +.x-autocontainer-outerCt, +.x-panel.x-tabpanel-child, +.x-panel.x-box-item, +.x-box-inner, +.x-box-target, +.x-container, +.x-container-default, +.x-window .x-panel-body, +.x-window .x-window-body, +.x-window .x-window-bodyWrap { + border-radius: 0 !important; +} + +/* Reset everything inside windows to 0 — then re-apply specific radii */ +.x-window *, +.x-window .x-autocontainer-innerCt, +.x-window .x-autocontainer-outerCt, +.x-window .x-form-layout-wrap, +.x-window .x-form-layout-auto-label, +.x-window .x-form-layout-colgroup, +.x-window .x-form-layout-column, +.x-window .x-field, +.x-window .x-form-item, +.x-window .x-form-item-body { + border-radius: 0 !important; +} + +/* Chart canvas — no radius on data area */ +.x-chart-grid, +.x-chart-axis, +canvas.x-surface, +.x-chart canvas, +canvas.x-surface-canvas, +.x-surface-canvas, +.x-draw-component canvas, +.proxmox-rrd-chart canvas, +svg.x-surface, +.x-draw-container, +.x-surface { + border-radius: 0 !important; +} + +/* Legend color marker (dot) — keep circular */ +.x-legend-item-marker { + border-radius: 50% !important; +} + +/* ===================================================== + RE-APPLY BORDER RADII (selective) + ===================================================== */ + +/* Windows */ +.x-window, +.x-window-default { + border-radius: var(--pm-radius-lg) !important; +} + +.x-window-header, +.x-window-header-default { + border-radius: var(--pm-radius-lg) var(--pm-radius-lg) 0 0 !important; +} + +.x-window .x-window-body, +.x-window-body-default { + border-radius: 0 !important; +} + +/* Buttons inside windows */ +.x-window .x-btn { + border-radius: var(--pm-radius-md) !important; +} + +/* Checkboxes inside windows */ +.x-window .x-form-checkbox { + border-radius: 3px !important; +} + +/* Form inputs inside windows */ +.x-window .x-form-trigger-wrap, +.x-window .x-form-trigger-wrap-default { + border-radius: var(--pm-radius-sm) !important; +} + +.x-window .x-form-text-wrap, +.x-window .x-form-text { + border-radius: var(--pm-radius-sm) 0 0 var(--pm-radius-sm) !important; +} + +.x-window .x-form-arrow-trigger { + border-radius: 0 var(--pm-radius-sm) var(--pm-radius-sm) 0 !important; +} + +/* Form trigger/text wrap — reset and re-apply */ +.x-form-trigger-wrap, +.x-form-trigger-wrap *, +.x-form-text-wrap, +.x-form-text-wrap *, +.x-form-text, +.x-form-trigger { + border-radius: 0 !important; +} + +.x-form-trigger-wrap, +.x-form-trigger-wrap-default { + border-radius: var(--pm-radius-sm) !important; + overflow: hidden !important; +} + +.x-form-text-wrap, +.x-form-text-wrap-default { + border-radius: var(--pm-radius-sm) 0 0 var(--pm-radius-sm) !important; +} + +.x-form-text, +.x-form-text-default { + border-radius: var(--pm-radius-sm) 0 0 var(--pm-radius-sm) !important; +} + +.x-form-trigger, +.x-form-trigger-default, +.x-form-arrow-trigger, +.x-form-arrow-trigger-default { + border-radius: 0 var(--pm-radius-sm) var(--pm-radius-sm) 0 !important; +} + +/* Dialog form content padding — vertical only (horizontal causes ExtJS overflow) */ +.x-window .x-tabpanel-child .x-autocontainer-innerCt { + padding: 12px 0 !important; +} + +/* Allow column panel bodies to show overflowed form content */ +.x-window .x-panel-body:not(.x-scroller) { + overflow: visible !important; +} + +/* Side padding on column panel bodies inside windows */ +.x-window .x-panel.x-box-item .x-panel-body { + padding: 0 4px !important; +} + +/* Constrain autocontainer width inside windows */ +.x-window .x-autocontainer-outerCt { + max-width: 100% !important; +} + +/* Fix window header/body width consistency */ +.x-window > .x-window-header, +.x-window > .x-window-body, +.x-window > .x-window-bodyWrap, +.x-window-bodyWrap > .x-window-body { + width: 100% !important; +} + +.x-window-header > .x-box-inner, +.x-window-header > .x-box-inner > .x-box-target { + width: 100% !important; +} + +.x-window-header-title { + width: auto !important; + flex: 1 !important; + max-width: calc(100% - 30px) !important; +} + +/* Boundlists */ +.x-boundlist { + border-radius: var(--pm-radius-md) !important; + overflow: hidden !important; +} + +/* ===================================================== + BASE / BODY + ===================================================== */ +.x-body, +.x-viewport > .x-body, +body.x-border-layout-ct, +div.x-border-layout-ct { + background-color: var(--ctp-base) !important; + color: var(--ctp-text) !important; +} + +/* ===================================================== + MASKS & OVERLAYS + ===================================================== */ +.x-mask { + background-color: rgba(17, 17, 27, 0.6) !important; + backdrop-filter: blur(4px); +} + +.x-mask-msg { + background-color: var(--ctp-mantle) !important; + border: 1px solid var(--ctp-surface1) !important; + border-radius: var(--pm-radius-lg) !important; +} + +.x-mask-msg-text { + color: var(--ctp-subtext0) !important; + filter: none !important; +} + +.x-css-shadow { + box-shadow: 0 8px 24px rgba(17, 17, 27, 0.6) !important; +} + +/* Loading indicators */ +.x-grid-row-loading, +.x-treelist-item-loading .x-treelist-item-icon, +.x-grid-tree-loading .x-tree-icon { + filter: invert(90%); +} + +/* ===================================================== + ICONS — Proxmox default colors for dark mode + ===================================================== */ + +/* General icon colors — neutral gray for dark backgrounds */ +.x-tree-icon-custom, +.x-grid-icon-custom, +.fa-tags::before, +.fa-file-o::before, +.fa-building::before, +.x-action-col-icon::before, +.fa-shield::before, +.fa-file-text-o::before, +.fa-clock-o::before, +.x-tab-icon-el-default, +.pve-icon-verify-lettering::after, +.x-tree-icon-leaf:not(.x-tree-icon-custom)::before, +.x-tree-icon-parent:not(.x-tree-icon-custom)::before, +.x-tree-icon-parent-expanded:not(.x-tree-icon-custom)::before, +.x-grid-filters-filtered-column .x-column-header-text::after { + color: var(--ctp-overlay2) !important; +} + +/* Folder icons — invert for dark mode */ +.x-tree-icon-parent:not(.x-tree-icon-custom)::before, +.x-tree-icon-parent-expanded:not(.x-tree-icon-custom)::before { + filter: invert(90%); +} + +/* Various image-based icons — invert for visibility */ +.fa-ceph::before, +.fa-sdn::before, +.fa-network-wired::before, +.pve-itype-treelist-item-icon-cdrom, +.fa-chevron-right::before, +.x-grid-row-console, +.x-box-scroller-toolbar-default.x-box-scroller, +.x-tree-elbow-img, +.pve-itype-icon-qemu, +.x-tree-node-computer, +.x-grid-tree-node-expanded .x-tree-node-computer, +.pbs-icon-tape, +.pbs-icon-tape-drive, +.x-tree-icon-leaf:not(.x-tree-icon-custom), +.x-tree-icon-parent:not(.x-tree-icon-custom), +.x-tree-icon-parent-expanded:not(.x-tree-icon-custom) { + filter: invert(90%); +} + +/* Hardware icons */ +.pve-itype-icon-cpu, +.pve-itype-icon-cdrom, +.pve-itype-icon-memory, +.pve-itype-icon-pci, +.pve-itype-icon-serial, +.pve-itype-icon-die, +.pmx-itype-icon-processor, +.pmx-itype-icon-memory, +.pve-itype-icon-storage, +.x-tree-node-harddisk, +.x-grid-tree-node-expanded .x-tree-node-harddisk { + filter: invert(100%); +} + +/* Hardware icons — counter-invert for non-SVG icon cells */ +td.pve-itype-icon-storage .x-grid-cell-inner, +td.x-tree-node-harddisk .x-grid-cell-inner { + filter: invert(100%) !important; +} + +/* Hardware icons — hide inverted borders for non-SVG icon cells */ +td.pve-itype-icon-storage, +td.x-tree-node-harddisk { + border-color: transparent !important; +} + +/* Hardware grid icons — mask-image renders SVG icons in theme text color + Replaces filter:invert approach for pve-itype-icon-* and pmx-itype-icon-* grid cells */ +td.pve-itype-icon-cpu, +td.pve-itype-icon-cdrom, +td.pve-itype-icon-memory, +td.pve-itype-icon-pci, +td.pve-itype-icon-serial, +td.pve-itype-icon-die, +td.pmx-itype-icon-processor, +td.pmx-itype-icon-memory { + filter: none !important; + background-image: none !important; + padding-left: 0 !important; + border-color: transparent !important; +} + +td.pve-itype-icon-cpu .x-grid-cell-inner, +td.pve-itype-icon-cdrom .x-grid-cell-inner, +td.pve-itype-icon-memory .x-grid-cell-inner, +td.pve-itype-icon-pci .x-grid-cell-inner, +td.pve-itype-icon-serial .x-grid-cell-inner, +td.pve-itype-icon-die .x-grid-cell-inner, +td.pmx-itype-icon-processor .x-grid-cell-inner, +td.pmx-itype-icon-memory .x-grid-cell-inner { + padding-left: 3px !important; +} + +td.pve-itype-icon-cpu .x-grid-cell-inner::before, +td.pve-itype-icon-cdrom .x-grid-cell-inner::before, +td.pve-itype-icon-memory .x-grid-cell-inner::before, +td.pve-itype-icon-pci .x-grid-cell-inner::before, +td.pve-itype-icon-serial .x-grid-cell-inner::before, +td.pve-itype-icon-die .x-grid-cell-inner::before, +td.pmx-itype-icon-processor .x-grid-cell-inner::before, +td.pmx-itype-icon-memory .x-grid-cell-inner::before { + content: '' !important; + display: inline-block !important; + width: 18px !important; + height: 14px !important; + vertical-align: middle !important; + margin-right: 10px !important; + background-color: currentColor !important; + -webkit-mask-size: contain !important; + mask-size: contain !important; + -webkit-mask-repeat: no-repeat !important; + mask-repeat: no-repeat !important; + -webkit-mask-position: center !important; + mask-position: center !important; +} + +td.pve-itype-icon-cpu .x-grid-cell-inner::before { + -webkit-mask-image: url('/pve2/images/icon-cpu.svg') !important; + mask-image: url('/pve2/images/icon-cpu.svg') !important; +} + +td.pve-itype-icon-memory .x-grid-cell-inner::before { + -webkit-mask-image: url('/pve2/images/icon-memory.svg') !important; + mask-image: url('/pve2/images/icon-memory.svg') !important; +} + +td.pve-itype-icon-cdrom .x-grid-cell-inner::before { + -webkit-mask-image: url('/pve2/images/icon-cd-drive.svg') !important; + mask-image: url('/pve2/images/icon-cd-drive.svg') !important; +} + +td.pve-itype-icon-pci .x-grid-cell-inner::before { + -webkit-mask-image: url('/pve2/images/icon-pci.svg') !important; + mask-image: url('/pve2/images/icon-pci.svg') !important; +} + +td.pve-itype-icon-serial .x-grid-cell-inner::before { + -webkit-mask-image: url('/pve2/images/icon-serial.svg') !important; + mask-image: url('/pve2/images/icon-serial.svg') !important; +} + +td.pve-itype-icon-die .x-grid-cell-inner::before { + -webkit-mask-image: url('/pve2/images/icon-die.svg') !important; + mask-image: url('/pve2/images/icon-die.svg') !important; +} + +td.pmx-itype-icon-processor .x-grid-cell-inner::before { + -webkit-mask-image: url('../images/icon-cpu.svg') !important; + mask-image: url('../images/icon-cpu.svg') !important; +} + +td.pmx-itype-icon-memory .x-grid-cell-inner::before { + -webkit-mask-image: url('../images/icon-ram.svg') !important; + mask-image: url('../images/icon-ram.svg') !important; +} + + +/* Icon overlays — default */ +.x-tree-icon-custom::after, +.x-grid-icon-custom::after { + color: var(--ctp-overlay2) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* RUNNING VMs/CTs — Catppuccin Green */ +.x-tree-icon-custom.running::after, +.x-grid-icon-custom.running::after, +.x-treelist-item-icon.running::after { + color: var(--ctp-green) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* ONLINE state — Green */ +.x-tree-icon-custom.online::after, +.x-grid-icon-custom.online::after { + color: var(--ctp-green) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* Stopped/offline — Overlay1 (muted gray) */ +.x-tree-icon-custom.stopped, +.x-tree-icon-custom.offline, +.x-grid-icon-custom.stopped, +.x-grid-icon-custom.offline { + color: var(--ctp-overlay1) !important; +} + +/* Unknown state — Overlay1 */ +.x-tree-icon-custom.unknown::after, +.x-grid-icon-custom.unknown::after { + color: var(--ctp-overlay1) !important; +} + +/* ERROR states — Catppuccin Red */ +.x-tree-icon-custom.error::after, +.x-tree-icon-custom.offline::after, +.x-tree-icon-custom.ha-error::after, +.x-grid-icon-custom.error::after, +.x-grid-icon-custom.offline::after, +.x-grid-icon-custom.ha-error::after { + color: var(--ctp-red) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* PAUSED/SUSPENDED — Catppuccin Peach */ +.x-tree-icon-custom.paused::after, +.x-tree-icon-custom.suspended::after, +.x-tree-icon-custom.lock-suspending::after, +.x-grid-icon-custom.paused::after, +.x-grid-icon-custom.suspended::after, +.x-grid-icon-custom.lock-suspending::after { + color: var(--ctp-peach) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* PENDING/WARNING states — Catppuccin Yellow */ +.x-tree-icon-custom.pending::after, +.x-tree-icon-custom.io-error::after, +.x-tree-icon-custom.internal-error::after, +.x-tree-icon-custom.guest-panicked::after, +.x-grid-icon-custom.pending::after, +.x-grid-icon-custom.io-error::after, +.x-grid-icon-custom.internal-error::after, +.x-grid-icon-custom.guest-panicked::after { + color: var(--ctp-yellow) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* HA MAINTENANCE — Catppuccin Sky */ +.x-tree-icon-custom.ha-maintenance::after, +.x-grid-icon-custom.ha-maintenance::after { + color: var(--ctp-sky) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* Locked icons */ +.x-tree-icon-custom.locked::after, +.x-tree-icon-custom.lock-backup::after, +.x-tree-icon-custom.lock-migrate::after, +.x-tree-icon-custom.lock-suspended::after, +.x-grid-icon-custom.locked::after, +.x-grid-icon-custom.lock-backup::after, +.x-grid-icon-custom.lock-migrate::after, +.x-grid-icon-custom.lock-suspended::after { + color: var(--ctp-overlay2) !important; +} + +/* LXC/QEMU type indicators */ +.x-tree-icon-custom.lxc::after, +.x-tree-icon-custom.qemu::after, +.x-grid-icon-custom.lxc::after, +.x-grid-icon-custom.qemu::after { + background-color: transparent; + color: var(--ctp-overlay1) !important; +} + +.x-treelist-item-icon.lxc::after, +.x-treelist-item-icon.qemu::after { + background-color: transparent; + color: var(--ctp-overlay1) !important; +} + +/* Tree expander arrows */ +.x-tree-arrows .x-tree-expander { + filter: brightness(200%); +} + +/* Cancel sprite-inversion on custom controls (checkboxes/radios handled via CSS) */ +.x-form-checkbox-default, +.x-form-radio-default, +.x-column-header-checkbox .x-column-header-checkbox::after, +.x-grid-checkcolumn::after, +.x-menu-item-checked .x-menu-item-icon-default.x-menu-item-checkbox, +.x-menu-item-unchecked .x-menu-item-icon-default.x-menu-item-checkbox { + filter: none !important; +} + +/* ===================================================== + PANELS & HEADERS + ===================================================== */ +.x-panel, +.x-panel-default { + border-radius: var(--pm-radius-lg) !important; + padding: 0 !important; +} + +/* Column panels — native stacked layout (Issue #23 fix) */ +.x-panel.x-column { + padding: 5px !important; + margin: 0 !important; + max-width: none !important; + box-sizing: border-box !important; +} + +/* Column panel card styling — borders for summary + chart panels */ +.x-panel.x-panel-default.x-column { + border: 1px solid var(--ctp-surface1) !important; + border-radius: var(--pm-radius-lg) !important; + overflow: hidden !important; +} + +/* Guest status + Notes panel borders */ +[id^="pveGuestStatusView-"].x-panel, +[id^="pveLxcStatusView-"].x-panel, +[id^="pveQemuStatusView-"].x-panel, +[id^="pmxNotesView-"].x-panel { + border: 1px solid var(--ctp-surface1) !important; + border-radius: var(--pm-radius-lg) !important; +} + +.x-panel-body, +.x-panel-body-default { + background-color: var(--ctp-base) !important; + color: var(--ctp-text) !important; + border: none !important; +} + +/* Panel headers — bottom border only */ +.x-panel-header, +.x-panel-header-default { + background-color: var(--ctp-mantle) !important; + border: none !important; + border-bottom: 1px solid var(--ctp-surface1) !important; + border-radius: var(--pm-radius-lg) var(--pm-radius-lg) 0 0 !important; + margin: 0 !important; + padding: 8px 12px !important; + width: 100% !important; + box-sizing: border-box !important; + overflow: visible !important; +} + +/* Title text — prevent border-radius clipping */ +.x-title-text, +.x-title-text-default { + overflow: visible !important; +} + +.x-panel-bodyWrap, +.x-panel-bodyWrap-default { + margin: 0 !important; + padding: 0 !important; + overflow: visible !important; +} + +/* Remove borders from nested panels */ +.x-panel-body > .x-box-layout-ct, +.x-panel-body > .x-container, +.x-panel-body > .x-box-inner, +[id*="pmxGauge"] { + border: none !important; +} + +.x-panel-header-title-default, +.x-window-header-title-default { + color: var(--ctp-text) !important; +} + +.x-panel-header-default .x-tool-tool-el { + background-color: transparent; +} + +.x-tool-img { + filter: brightness(175%); +} + +.x-tool-over .x-tool-img { + filter: brightness(200%); +} + +/* Resource tree — panel body border */ +div[id^="pveResourceTree-"][id$="-body"] { + border-color: var(--ctp-base) !important; +} + +/* Resource tree — remove row separators */ +[id^="pveResourceTree-"].x-tree-panel td.x-grid-cell, +[id^="pveResourceTree-"].x-tree-panel .x-grid-td, +[id^="pveResourceTree-"].x-tree-panel .x-grid-cell { + border-bottom: none !important; +} + +/* Resource tree — row spacing */ +div[id^="pveResourceTree"] .x-grid-cell { + padding-top: 3px !important; + padding-bottom: 3px !important; +} + +/* Summary/stats panel radius overrides */ +.pveStatusPanel, +.x-panel-default-framed, +.x-panel-body-default-framed { + border-radius: 12px !important; +} + +.x-panel-header-default-framed { + border-radius: 12px 12px 0 0 !important; +} + +/* Column widget panel radius */ +.x-panel.x-column > .x-panel-bodyWrap > .x-panel-body.x-panel-body-default { + border-radius: var(--pm-radius-lg) !important; +} + +/* ===================================================== + SPLITTERS / SEPARATORS + ===================================================== */ +.x-splitter-vertical { + background-color: transparent !important; + border-left: 1px solid var(--ctp-surface1) !important; + border-right: none !important; + width: 1px !important; +} + +.x-splitter-horizontal { + background-color: var(--ctp-crust) !important; + border-top: 1px solid var(--ctp-surface1) !important; +} + +.x-splitter { + background-color: var(--ctp-crust) !important; +} + +.x-keyboard-mode .x-splitter-focus::after { + border-color: var(--ctp-mauve) !important; +} + +.x-layout-split-bottom { + opacity: 0.7; +} + +/* Toolbox tree (pve-nav) right border — full height */ +.pve-toolbar-bg { + border-right: 1px solid var(--ctp-surface1) !important; + z-index: 3 !important; +} + +.x-treelist.x-treelist-pve-nav { + border-right: none !important; +} + +/* ===================================================== + TOOLBARS + ===================================================== */ +.x-toolbar, +.x-toolbar-default { + background-color: var(--ctp-base) !important; + border-color: var(--ctp-surface1) !important; +} + +.x-toolbar-default.x-docked-top { + border: none !important; + border-bottom: 1px solid var(--ctp-surface1) !important; +} + +.x-toolbar-default .x-toolbar-separator { + border-color: var(--ctp-surface1); +} + +.x-toolbar-text-default { + color: var(--ctp-subtext0); +} + +/* ===================================================== + PRIMARY BUTTONS — Catppuccin Mauve + ===================================================== */ +.x-btn-default-small { + background-color: var(--ctp-mauve) !important; + border: 1px solid rgba(203, 166, 247, 0.4) !important; + border-radius: var(--pm-radius-md) !important; + transition: background-color 0.15s ease, box-shadow 0.15s ease !important; +} + +.x-btn-default-small .x-btn-inner { + color: var(--ctp-on-accent) !important; + font-weight: 600 !important; +} + +.x-btn-default-small .x-btn-icon-el { + color: var(--ctp-on-accent) !important; +} + +.x-btn-default-small.x-btn-over, +.x-keyboard-mode .x-btn-default-small.x-btn-focus { + background-color: #d4b4fa !important; + box-shadow: 0 0 0 3px var(--ctp-accent-subtle) !important; +} + +.x-btn-default-small.x-btn.x-btn-disabled { + background-color: var(--ctp-mauve) !important; + opacity: 0.4; +} + +.x-btn-default-small.x-btn.x-btn-pressed { + background-color: #b98cf5 !important; +} + +/* Button height consistency — 28px with vertical centering */ +/* Exclude tag edit buttons (display:none when hidden, :has(.fa-check) for checkmark) */ +.x-btn.x-btn-default-small:not(.x-btn-default-toolbar-small):not([style*="display: none"]):not([style*="display:none"]):not(:has(.fa-check)) { + height: 28px !important; + min-height: 28px !important; + display: flex !important; + align-items: center !important; + padding: 3px 8px !important; +} + +/* Fix button inner element centering for proper icon alignment (issue #17) */ +.x-btn.x-btn-default-small:not(.x-btn-default-toolbar-small):not([style*="display: none"]):not([style*="display:none"]):not(:has(.fa-check)) .x-btn-wrap { + display: flex !important; + align-items: center !important; +} + +.x-btn.x-btn-default-small:not(.x-btn-default-toolbar-small):not([style*="display: none"]):not([style*="display:none"]):not(:has(.fa-check)) .x-btn-inner { + display: flex !important; + align-items: center !important; +} + +/* Fix dropdown arrows on split/arrow buttons */ +.x-btn-wrap.x-btn-arrow-right::after, +.x-btn-wrap.x-btn-split-right::after { + height: 16px !important; + min-height: 16px !important; + width: 20px !important; + display: flex !important; + align-items: center !important; +} + +/* Fix icon-only buttons — hide   inner element when button has no text */ +.x-btn-no-text .x-btn-inner, +.x-btn-button.x-btn-no-text .x-btn-inner, +.x-btn-button-default-toolbar-small.x-btn-no-text .x-btn-inner-default-toolbar-small, +.x-btn-button-default-small.x-btn-no-text .x-btn-inner-default-small, +.x-btn-button-default-small.x-btn-no-text > .x-btn-inner-default-small { + display: none !important; +} + +/* Specific fix for fa-desktop icon (Create VM) — visually bottom-heavy */ +.x-btn-icon-el.fa-desktop { + transform: translateY(1.1px) !important; +} + +/* ===================================================== + SECONDARY / TOOLBAR BUTTONS + ===================================================== */ +.x-btn-default-toolbar-small { + background-color: var(--ctp-surface0) !important; + border: 1px solid var(--ctp-surface1) !important; + border-radius: var(--pm-radius-md) !important; + transition: background-color 0.15s ease, border-color 0.15s ease !important; +} + +.x-btn-default-toolbar-small .x-btn-inner-default-toolbar-small, +.x-btn-default-toolbar-small .x-btn-icon-el-default-toolbar-small { + color: var(--ctp-text) !important; +} + +.x-btn-default-toolbar-small .x-btn-wrap-default-toolbar-small.x-btn-arrow-right::after, +.x-btn-default-toolbar-small .x-btn-wrap-default-toolbar-small.x-btn-split-right::after { + filter: brightness(150%); +} + +.x-btn-default-toolbar-small.x-btn-over, +.x-keyboard-mode .x-btn-default-toolbar-small.x-btn-focus { + background-color: var(--ctp-surface1) !important; + border-color: var(--ctp-surface2) !important; +} + +.x-btn-default-toolbar-small.x-btn.x-btn-disabled { + background-color: var(--ctp-surface0) !important; + opacity: 0.4; +} + +.x-btn-default-toolbar-small.x-btn.x-btn-menu-active, +.x-btn-default-toolbar-small.x-btn.x-btn-pressed { + background-color: var(--ctp-mauve) !important; + border-color: var(--ctp-mauve) !important; + padding: 4px 8px !important; /* Fix #30: prevent width change on dropdown */ +} + +.x-btn-default-toolbar-small.x-btn.x-btn-pressed .x-btn-inner-default-toolbar-small, +.x-btn-default-toolbar-small.x-btn.x-btn-pressed .x-btn-icon-el-default-toolbar-small, +.x-btn-default-toolbar-small.x-btn.x-btn-pressed .x-btn-inner-default-small, +.x-btn-default-toolbar-small.x-btn.x-btn-pressed .x-btn-icon-el-default-small { + color: var(--ctp-on-accent) !important; +} + +/* Segmented buttons */ +.x-segmented-button { + border-radius: var(--pm-radius-md) !important; +} + +.x-segmented-button .x-btn, +.x-segmented-button .x-btn-default-small, +.x-segmented-button .x-btn-inner, +.x-segmented-button .x-btn-wrap { + border-radius: var(--pm-radius-md) !important; +} + +/* Inline buttons (Documentation, Help) */ +.proxmox-inline-button { + height: 28px !important; + min-height: 28px !important; + display: flex !important; + align-items: center !important; + padding: 3px 8px !important; + background-color: var(--ctp-surface0) !important; + border: 1px solid var(--ctp-surface1) !important; + border-radius: var(--pm-radius-md) !important; + color: var(--ctp-text) !important; + transition: background-color 0.15s ease !important; +} + +.proxmox-inline-button:hover, +.proxmox-inline-button.x-btn-over { + background-color: var(--ctp-surface1) !important; + border-color: var(--ctp-overlay0) !important; +} + +.proxmox-inline-button:active, +.proxmox-inline-button.x-btn-pressed { + background-color: var(--ctp-surface2) !important; +} + +.proxmox-inline-button .x-btn-inner, +.proxmox-inline-button .x-btn-icon-el { + color: var(--ctp-text) !important; +} + +/* Pressed/active inline buttons get accent bg from toolbar rules — use on-accent text */ +.proxmox-inline-button.x-btn-pressed .x-btn-inner, +.proxmox-inline-button.x-btn-pressed .x-btn-icon-el, +.proxmox-inline-button.x-btn-menu-active .x-btn-inner, +.proxmox-inline-button.x-btn-menu-active .x-btn-icon-el { + color: var(--ctp-on-accent) !important; +} + +/* ===================================================== + FORM ELEMENTS + ===================================================== */ +.x-form-trigger-default { + background-color: var(--ctp-surface0) !important; +} + +.x-form-text-default { + background-color: var(--ctp-surface0) !important; + color: var(--ctp-text) !important; + border-radius: var(--pm-radius-sm) !important; +} + +.x-form-trigger-wrap, +.x-form-trigger-wrap-default { + border-color: var(--ctp-surface1) !important; + background-color: var(--ctp-surface0) !important; + border-radius: var(--pm-radius-sm) !important; + transition: border-color 0.15s ease !important; +} + +.x-form-trigger-wrap-default.x-form-trigger-wrap-focus { + border-color: var(--ctp-mauve) !important; + box-shadow: 0 0 0 3px var(--ctp-accent-subtle) !important; +} + +.x-form-item-label-default, +.x-form-cb-label-default { + color: var(--ctp-text) !important; +} + +.x-form-display-field-default { + color: var(--ctp-subtext0) !important; + border-radius: var(--pm-radius-md) !important; +} + +.x-form-spinner-default { + background-color: var(--ctp-surface0) !important; +} + +.x-fieldset, +.x-fieldset-default { + border-color: var(--ctp-surface1) !important; + border-radius: var(--pm-radius-lg) !important; +} + +.x-fieldset-header-default > .x-fieldset-header-text { + color: var(--ctp-text) !important; +} + +/* ===================================================== + CHECKBOXES & RADIOS — Catppuccin styled + ===================================================== */ + +/* Base: remove sprite, styled as custom control */ +.x-form-checkbox, .x-form-checkbox-default, +.x-form-radio, .x-form-radio-default { + background-image: none !important; + background-color: var(--ctp-surface0) !important; + border: 1.5px solid var(--ctp-overlay0) !important; + width: 16px !important; + height: 16px !important; + display: inline-block !important; + box-sizing: border-box !important; + cursor: pointer !important; + transition: border-color 0.12s ease, background-color 0.12s ease !important; +} + +/* Checkbox: rounded square */ +.x-form-checkbox, .x-form-checkbox-default { + border-radius: 3px !important; +} + +/* Radio: circle + ::after inner dot */ +.x-form-radio, .x-form-radio-default { + border-radius: 50% !important; + position: relative !important; + transform: translateZ(0) !important; + box-shadow: inset 0 0 0 0 transparent !important; +} + +.x-form-radio::after { + content: '' !important; + position: absolute !important; + top: 50% !important; + left: 50% !important; + width: 7px !important; + height: 7px !important; + border-radius: 50% !important; + background: transparent !important; + transform: translate(-50%, -50%) scale(0) !important; + transition: transform 0.15s ease, background 0.15s ease !important; + pointer-events: none !important; +} + +/* Hover */ +.x-form-checkbox:hover, .x-form-checkbox-default:hover, +.x-form-cb-wrap:hover .x-form-checkbox { + border-color: var(--ctp-mauve) !important; +} + +.x-form-radio:hover, .x-form-radio-default:hover, +.x-form-cb-wrap:hover .x-form-radio { + border-color: var(--ctp-mauve) !important; +} + +/* CHECKED checkbox — Mauve fill + white SVG checkmark */ +.x-form-cb-checked .x-form-checkbox, +.x-form-cb-checked .x-form-checkbox-default { + background-color: var(--ctp-mauve) !important; + border-color: var(--ctp-mauve) !important; + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 8'%3E%3Cpath d='M1 4l3 3 5-6' fill='none' stroke='%231e1e2e' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") !important; + background-repeat: no-repeat !important; + background-position: center !important; + background-size: 9px 7px !important; +} + +/* SELECTED radio — Mauve dot */ +.x-form-cb-checked .x-form-radio, +.x-form-cb-checked .x-form-radio-default { + border-color: var(--ctp-mauve) !important; + background-color: var(--ctp-base) !important; +} + +.x-form-cb-checked .x-form-radio::after { + background: var(--ctp-mauve) !important; + transform: translate(-50%, -50%) scale(1) !important; +} + +/* ===================================================== + BOUNDLIST / DROPDOWNS + ===================================================== */ +.x-boundlist { + background-color: var(--ctp-mantle) !important; + border: 1px solid var(--ctp-surface1) !important; + border-radius: var(--pm-radius-md) !important; + box-shadow: 0 8px 24px rgba(17, 17, 27, 0.7) !important; + padding: 2px !important; + overflow: hidden !important; +} + +.x-boundlist-item { + background-color: transparent !important; + color: var(--ctp-text) !important; + border-radius: var(--pm-radius-sm) !important; + padding: 2px 6px !important; + line-height: normal !important; + border: none !important; + cursor: pointer !important; + outline: none !important; + box-shadow: none !important; +} + +.x-boundlist-selected { + background-color: var(--ctp-select-overlay) !important; + color: var(--ctp-text) !important; +} + +.x-boundlist-item-over { + background-color: var(--ctp-hover-overlay) !important; +} + +/* ===================================================== + GRIDS / TABLES + ===================================================== */ +.x-grid, +.x-grid-view { + border-radius: 0 !important; +} + +.x-column-header { + border-color: var(--ctp-surface1) !important; + background-color: transparent !important; +} + +.x-column-header-inner, +.x-column-header-text { + color: var(--ctp-text) !important; + font-weight: 600 !important; +} + +.x-column-header-trigger { + border-color: var(--ctp-surface1) !important; +} + +.x-grid-item, +.x-column-header-default, +.x-grid-cell-row-numberer { + color: var(--ctp-text) !important; + background-color: var(--ctp-base) !important; +} + +.x-grid-cell-special { + border-color: var(--ctp-surface1) !important; +} + +.x-grid-group-hd { + background-color: var(--ctp-base) !important; + border-color: var(--ctp-surface1) !important; +} + +.x-grid-group-title { + color: var(--ctp-text) !important; +} + +.x-grid-header-ct { + background-color: var(--ctp-mantle) !important; + border: 1px solid var(--ctp-surface0) !important; + border-radius: var(--pm-radius-lg) var(--pm-radius-lg) 0 0 !important; +} + +.x-grid-item-alt { + background-color: var(--ctp-crust) !important; +} + +.x-grid-with-row-lines .x-grid-item { + border-color: var(--ctp-surface0) !important; +} + +.x-grid-cell { + border-bottom: 1px solid rgba(69, 71, 90, 0.4) !important; +} + +.x-grid-item-over, +.x-grid-with-row-lines .x-grid-item.x-grid-item-over { + background-color: var(--ctp-hover-overlay) !important; +} + +.x-grid-item-selected, +.x-grid-with-row-lines .x-grid-item.x-grid-item-selected { + background-color: var(--ctp-select-overlay) !important; +} + +.x-column-header-over, +.x-column-header-open { + background-color: var(--ctp-hover-overlay) !important; +} + +.x-column-header-sort-ASC, +.x-column-header-sort-DESC { + background-color: var(--ctp-hover-overlay) !important; +} + +.x-grid-row-summary .x-grid-cell, +.x-grid-row-summary .x-grid-rowwrap, +.x-grid-row-summary .x-grid-cell-rowbody { + background-color: var(--ctp-base) !important; + border-color: var(--ctp-surface1); +} + +.x-grid-with-col-lines .x-grid-cell, +.x-grid-with-col-lines .x-grid-item-over .x-grid-cell, +.x-grid-with-col-lines .x-grid-item-selected .x-grid-cell { + border-color: var(--ctp-surface1) !important; +} + +.x-dd-drag-proxy { + background-color: var(--ctp-mantle); + border-color: var(--ctp-surface1); + color: var(--ctp-text); +} + +.x-keyboard-mode .x-grid-item-focused { + background-color: var(--ctp-hover-overlay) !important; + color: var(--ctp-text) !important; +} + +/* Remove blue outline from focused/selected items in resource tree */ +.x-keyboard-mode .x-grid-item-focused .x-grid-cell-inner::before, +.x-keyboard-mode .x-grid-item-selected .x-grid-cell-inner::before, +.x-grid-item-selected .x-grid-cell-inner::before, +.x-grid-item-focused .x-grid-cell-inner::before, +[id^="pveResourceTree"] .x-grid-item-selected .x-grid-cell-inner::before, +[id^="pveResourceTree"] .x-grid-item-focused .x-grid-cell-inner::before { + content: none !important; + display: none !important; + border: none !important; +} + +.x-grid-empty { + background-color: var(--ctp-base) !important; + color: var(--ctp-subtext0) !important; +} + +/* Grid info (pve-info-grid) and RRD view */ +.pve-info-grid { + border-radius: 12px !important; +} + +.pve-rrdview, +.rrdview { + border-radius: 12px !important; +} + +.pve-summary-status, +.x-container .pve-status { + border-radius: var(--pm-radius-lg) !important; +} + +[id^="pveGuestStatusView-"][id$="-body"], +[id^="pmxNotesView-"] .x-panel-body { + border-radius: var(--pm-radius-lg) !important; +} + +.x-panel-default[id*="notes"], +.pve-notes-view { + border-radius: var(--pm-radius-lg) !important; +} + +/* Floating grid pickers (storage/ISO selectors) */ +.x-layer.x-grid .x-grid-view, +.x-panel.x-layer.x-grid .x-grid-view, +.x-panel.x-layer.x-grid, +.x-layer.x-panel.x-grid { + border-radius: var(--pm-radius-sm) !important; +} + +.x-layer.x-grid .x-grid-item-over, +.x-layer.x-grid .x-grid-item-selected, +.x-panel.x-layer.x-grid .x-grid-item-over, +.x-panel.x-layer.x-grid .x-grid-item-selected { + border-radius: var(--pm-radius-sm) !important; + outline: none !important; + box-shadow: none !important; +} + +.x-layer.x-grid .x-grid-item-over td, +.x-layer.x-grid .x-grid-item-selected td, +.x-layer.x-grid .x-grid-item-over .x-grid-cell, +.x-layer.x-grid .x-grid-item-selected .x-grid-cell, +.x-panel.x-layer.x-grid .x-grid-item-over td, +.x-panel.x-layer.x-grid .x-grid-item-selected td, +.x-panel.x-layer.x-grid .x-grid-item-over .x-grid-cell, +.x-panel.x-layer.x-grid .x-grid-item-selected .x-grid-cell { + border-radius: 0 !important; +} + +.x-layer.x-grid .x-grid-item-over td:first-child, +.x-layer.x-grid .x-grid-item-selected td:first-child, +.x-panel.x-layer.x-grid .x-grid-item-over td:first-child, +.x-panel.x-layer.x-grid .x-grid-item-selected td:first-child { + border-radius: var(--pm-radius-sm) 0 0 var(--pm-radius-sm) !important; +} + +.x-layer.x-grid .x-grid-item-over td:last-child, +.x-layer.x-grid .x-grid-item-selected td:last-child, +.x-panel.x-layer.x-grid .x-grid-item-over td:last-child, +.x-panel.x-layer.x-grid .x-grid-item-selected td:last-child { + border-radius: 0 var(--pm-radius-sm) var(--pm-radius-sm) 0 !important; +} + +/* ===================================================== + MENUS + ===================================================== */ +.x-menu, +.x-menu-default { + background-color: var(--ctp-crust) !important; + border: 1px solid var(--ctp-surface0) !important; + border-radius: var(--pm-radius-lg) !important; + box-shadow: 0 8px 24px rgba(17, 17, 27, 0.8) !important; + padding: 2px !important; + overflow: hidden !important; +} + +.x-menu-body-default { + background-color: transparent !important; + padding: 4px !important; +} + +.x-menu-header { + background-color: transparent !important; + color: var(--ctp-text) !important; +} + +/* Menu icon separator — hide */ +.x-menu-icon-separator-default { + display: none !important; +} + +/* Menu item layout (flexbox reordering) */ +.x-menu-item-default > .x-menu-item-link { + display: flex !important; + align-items: center !important; + flex-direction: row !important; + gap: 4px !important; + justify-content: flex-start !important; + flex-wrap: nowrap !important; + border-radius: var(--pm-radius-md) !important; + padding: 4px 8px !important; + line-height: 20px !important; + cursor: pointer !important; + outline: none !important; + box-shadow: none !important; + white-space: nowrap !important; + text-decoration: none !important; +} + +.x-menu-item-text-default { + color: var(--ctp-text) !important; + font-size: 13px !important; + order: 1 !important; + margin-left: 0 !important; + text-align: left !important; + line-height: 20px !important; + display: inline-flex !important; + align-items: center !important; + flex: 1 1 auto !important; + width: auto !important; + white-space: nowrap !important; +} + +.x-menu-item-icon-default { + color: var(--ctp-subtext0) !important; + order: -1 !important; + position: relative !important; + float: none !important; + margin-right: 8px !important; + margin-left: 0 !important; + left: auto !important; + top: auto !important; + width: 16px !important; + text-align: center !important; + display: inline-flex !important; + align-items: center !important; + justify-content: center !important; + height: 20px !important; + line-height: 20px !important; + vertical-align: middle !important; + flex: 0 0 16px !important; + align-self: center !important; +} + +.x-menu-item-arrow, +.x-menu-item-arrow-default { + order: 2 !important; + margin-left: auto !important; +} + +.x-menu-item-default.x-menu-item-separator { + background-color: var(--ctp-surface0) !important; + border: none !important; + height: 1px !important; + margin: 6px 4px !important; +} + +.x-menu-item-default.x-menu-item-focus, +.x-menu-item-default.x-menu-item-active, +.x-menu-item:hover { + background-color: var(--ctp-surface0) !important; + color: var(--ctp-text) !important; + border-radius: var(--pm-radius-md) !important; +} + +.x-menu-item-active .x-menu-item-text-default, +.x-menu-item-focus .x-menu-item-text-default { + color: var(--ctp-text) !important; +} + +.x-menu-item-active .x-menu-item-icon-default, +.x-menu-item-focus .x-menu-item-icon-default { + color: var(--ctp-lavender) !important; +} + +/* ===================================================== + PROGRESS BARS + ===================================================== */ + +/* Fix: Widget containers need overflow visible to not clip progress bars */ +.x-container[id^="pmxInfoWidget"], +.x-container.x-box-layout-ct { + overflow: visible !important; +} + +.x-progress, +.x-progress-default { + background-color: var(--ctp-surface0) !important; + border-radius: 5px !important; +} + +.x-progress-default .x-progress-bar-default { + background-color: var(--ctp-mauve) !important; + border-radius: 5px !important; + transition: width 0.4s ease !important; +} + +.x-progress-default .x-progress-text { + color: var(--ctp-text) !important; +} + +/* Text overlaid on the progress bar fill — use on-accent for contrast against Mauve/Yellow/Red fills */ +.x-progress-bar .x-progress-text { + color: var(--ctp-on-accent) !important; +} + +.x-progress.warning .x-progress-bar { + background-color: var(--ctp-yellow) !important; +} + +.x-progress.critical .x-progress-bar { + background-color: var(--ctp-red) !important; +} + +/* ===================================================== + TABS — Catppuccin underline style + Flat tabs with Mauve underline on active tab + ===================================================== */ +.x-tab-bar, +.x-tab-bar-default { + background-color: var(--ctp-base) !important; + border-radius: 0 !important; + border-bottom: 1px solid var(--ctp-surface1) !important; + padding-bottom: 0 !important; +} + +/* Overflow visible for the underline indicator */ +.x-tab-bar .x-box-inner, +.x-tab-bar .x-box-target, +.x-tab-bar-body, +.x-tab-bar-body-default { + overflow: visible !important; +} + +/* Base tab */ +.x-tab, +.x-tab-default, +.x-tab-default-top { + background-color: transparent !important; + border: none !important; + border-radius: var(--pm-radius-md) var(--pm-radius-md) 0 0 !important; + padding: 8px 16px 8px !important; + overflow: visible !important; + margin-bottom: 0 !important; + transition: color 0.15s ease !important; + outline: none !important; + box-shadow: none !important; +} + +/* Remove ::after from inactive tabs */ +.x-tab::after { + display: none !important; +} + +.x-tab-inner-default { + color: var(--ctp-subtext0) !important; + font-size: 13px !important; +} + +.x-tab-default.x-tab-over { + background-color: transparent !important; +} + +.x-tab-default.x-tab-over .x-tab-inner-default { + color: var(--ctp-text) !important; +} + +/* Active tab */ +.x-tab-default.x-tab.x-tab-active { + background-color: transparent !important; + border: none !important; + overflow: visible !important; + margin-bottom: 0 !important; + outline: none !important; + box-shadow: none !important; +} + +/* Mauve underline indicator on active tab */ +.x-tab-default.x-tab.x-tab-active::after { + content: '' !important; + display: block !important; + position: absolute !important; + bottom: 0 !important; + left: 0 !important; + right: 0 !important; + height: 2px !important; + background: var(--ctp-mauve) !important; + z-index: 10 !important; + border-radius: 2px 2px 0 0 !important; + pointer-events: none !important; +} + +.x-tab-active .x-tab-inner-default { + color: var(--ctp-text) !important; + font-weight: 600 !important; +} + +.x-tab-default.x-tab.x-tab-disabled { + background-color: transparent !important; + border: none !important; + color: var(--ctp-overlay0) !important; + margin-bottom: 0 !important; +} + +/* Focus states — no outline */ +.x-keyboard-mode .x-tab-default.x-tab-focus, +.x-keyboard-mode .x-tab-default.x-tab-focus.x-tab-active { + background-color: transparent !important; + border: none !important; + outline: none !important; + box-shadow: none !important; + margin-bottom: 0 !important; +} + +.x-keyboard-mode .x-tab-default.x-tab-focus.x-tab-active::after { + content: '' !important; + display: block !important; + position: absolute !important; + bottom: 0 !important; + left: 0 !important; + right: 0 !important; + height: 2px !important; + background: var(--ctp-mauve) !important; + z-index: 10 !important; + pointer-events: none !important; +} + +/* Kill ALL tab interaction outlines/shadows */ +.x-tab:focus, +.x-tab *:focus, +.x-tab-focus, +.x-tab-active.x-tab-focus, +.x-tab-inner-focus, +.x-tab-button-focus, +.x-tab-pressed, +.x-tab-active.x-tab-pressed, +.x-tab-over, +.x-tab:active, +.x-tab *:active { + outline: none !important; + box-shadow: none !important; +} + +.x-tabpanel-child { + border-radius: 0 0 var(--pm-radius-lg) var(--pm-radius-lg) !important; +} + +/* Tab hover/active corners */ +.x-tab-default.x-tab-over, +.x-tab-default.x-tab.x-tab-active { + border-radius: var(--pm-radius-md) var(--pm-radius-md) 0 0 !important; +} + +/* ===================================================== + TOOLTIPS + ===================================================== */ +.x-tip, +.x-tip-default { + background-color: var(--ctp-mantle) !important; + border: 1px solid var(--ctp-surface1) !important; + border-radius: var(--pm-radius-md) !important; + box-shadow: 0 4px 12px rgba(17, 17, 27, 0.5); +} + +.x-tip-body-default { + color: var(--ctp-text) !important; +} + +.x-tip-form-invalid { + background-color: var(--ctp-mantle) !important; + border-color: var(--ctp-red) !important; +} + +.x-tip-body-form-invalid { + color: var(--ctp-red) !important; +} + +/* ===================================================== + TREE NAVIGATION (Sidebar) + ===================================================== */ +.x-treelist-item { + background-color: var(--ctp-base) !important; + border-radius: var(--pm-radius-md) !important; +} + +/* Pseudo-element approach for hover/selected highlighting */ +.x-treelist-row { + border-radius: var(--pm-radius-md) !important; + background-color: transparent !important; + position: relative !important; + z-index: 0 !important; +} + +.x-treelist-row::before { + content: ""; + position: absolute; + top: 1px; + bottom: 1px; + left: 0; + right: 4px; + border-radius: var(--pm-radius-md); + background-color: transparent; + z-index: -1; + pointer-events: none; + transition: background-color 0.15s ease; +} + +/* Fix toolbox tree item text overlapping icons */ +.x-treelist-item-text { + margin-left: 28px !important; +} + +/* Toolbox tree items — bright text */ +.x-treelist-item-text, +.x-treelist-item-icon, +.x-treelist.x-treelist-pve-nav .x-treelist-item-text, +.x-treelist.x-treelist-pve-nav .x-treelist-item-icon { + color: var(--ctp-subtext1) !important; +} + +/* Hover state — apply to pseudo-element */ +.x-treelist-row-over { + background-color: transparent !important; +} + +.x-treelist-row-over::before { + background-color: var(--ctp-hover-overlay) !important; +} + +.x-treelist-row-over .x-treelist-item-icon, +.x-treelist-row-over .x-treelist-item-text { + background-color: transparent !important; + color: var(--ctp-text) !important; +} + +/* Selected/active item — Mauve highlight */ +.x-treelist-item-selected > .x-treelist-row { + background-color: transparent !important; +} + +.x-treelist-item-selected > .x-treelist-row::before, +.x-treelist-item-selected > .x-treelist-row:hover::before { + background-color: var(--ctp-mauve) !important; +} + +.x-treelist-item-selected .x-treelist-item-text, +.x-treelist-item-selected .x-treelist-item-icon, +.x-treelist.x-treelist-pve-nav .x-treelist-item-selected .x-treelist-item-text, +.x-treelist.x-treelist-pve-nav .x-treelist-item-selected .x-treelist-item-icon { + color: var(--ctp-on-accent) !important; +} + +.x-treelist-pve-nav { + background-color: var(--ctp-base) !important; + border-color: var(--ctp-surface1) !important; +} + +/* Tree navigation radius overrides */ +.x-treelist-item, +.x-treelist-item-tool { + border-radius: var(--pm-radius-sm) !important; +} + +.x-treelist-row, +.x-treelist-row:hover, +.x-treelist-row-over, +.x-treelist-item-selected > .x-treelist-row, +.x-treelist-item-selected > .x-treelist-row:hover, +.x-treelist-item-expanded > .x-treelist-row, +.x-treelist-item-expanded > .x-treelist-row-over, +.x-treelist-item-expandable > .x-treelist-row, +.x-treelist-item-expandable > .x-treelist-row-over { + border-radius: var(--pm-radius-sm) !important; +} + +.x-treelist-row::before { + border-radius: var(--pm-radius-sm) !important; +} + +.x-treelist-item-wrap, +.x-treelist-item-text, +.x-treelist-row, +.x-treelist-container, +.x-treelist-root-container, +.x-treelist, +.x-treelist-pve-nav { + border-radius: var(--pm-radius-sm) !important; +} + +/* Cursor pointer for interactive tree/grid items */ +.x-grid-cell, +.x-grid-cell-inner, +.x-tree-elbow-img, +.x-tree-icon, +.x-treelist-item, +.x-treelist-row, +.x-treelist-item-wrap, +.x-treelist-item-text, +.x-treelist-item-icon { + cursor: pointer !important; +} + +/* ===================================================== + WINDOWS / MODALS + ===================================================== */ +.x-window, +.x-window-default { + background-color: var(--ctp-crust) !important; + border: 1px solid var(--ctp-surface1) !important; + border-radius: var(--pm-radius-lg) !important; + box-shadow: 0 8px 24px rgba(17, 17, 27, 0.6) !important; + overflow: hidden !important; +} + +.x-window .x-window-header, +.x-window-header-default { + background-color: var(--ctp-mantle) !important; + border-color: transparent !important; + border-radius: var(--pm-radius-lg) var(--pm-radius-lg) 0 0 !important; +} + +.x-window-header-default .x-mask { + background-color: rgba(17, 17, 27, 0.7); +} + +.x-window .x-window-body, +.x-window-body-default { + background-color: var(--ctp-base) !important; + border-color: var(--ctp-surface1) !important; + color: var(--ctp-text) !important; + border-radius: 0 0 var(--pm-radius-lg) var(--pm-radius-lg) !important; +} + +.x-window-ghost { + background-color: var(--ctp-base) !important; +} + +.x-window-header-default .x-tool-img { + background-color: transparent; +} + +.x-message-box .x-window-body { + background-color: var(--ctp-mantle) !important; +} + +/* Respect ExtJS inline display:none on hidden dialog buttons */ +.x-message-box .x-btn.x-btn-default-small[style*="display: none"], +.x-message-box .x-btn.x-btn-default-small[style*="display:none"], +.x-window .x-toolbar-footer .x-btn[style*="display: none"], +.x-window .x-toolbar-footer .x-btn[style*="display:none"] { + display: none !important; +} + +/* Login dialog — clean inner panel borders */ +.x-window:has(#pveloginrealm) .x-panel-body { + border: none !important; + background: transparent !important; + width: auto !important; +} + +/* ===================================================== + CONSOLE / TERMINAL + ===================================================== */ +div.monitor { + border-color: var(--ctp-surface1); +} + +.install-mask { + background-color: var(--ctp-crust); + color: var(--ctp-subtext0); +} + +.x-window.install-mask { + box-shadow: rgba(17, 17, 27, 0.5) 0 4px 20px !important; +} + +/* ===================================================== + LEGEND / CHARTS + ===================================================== */ +.x-legend-container { + background-color: var(--ctp-base) !important; +} + +.x-legend-horizontal .x-legend-item { + background-color: var(--ctp-mantle) !important; + color: var(--ctp-text) !important; + border: 1px solid var(--ctp-surface0) !important; +} + +/* Chart/RRD panel backgrounds */ +div[id*="rrdchart"], +.pve-rrddatastore, +.pmx-panel-rrd { + background-color: var(--ctp-base) !important; +} + +.proxmox-rrd-panel canvas, +.proxmox-widget-toolkit canvas, +canvas.x-surface, +.x-surface canvas { + background-color: transparent !important; + opacity: 1 !important; +} + +.proxmox-rrd-panel, +.proxmox-rrd-chart { + background-color: var(--ctp-base) !important; +} + +/* Chart text/labels */ +.x-surface text, +svg text { + fill: var(--ctp-text) !important; +} + +/* ===================================================== + PROXMOX-SPECIFIC OVERRIDES + ===================================================== */ + +/* Logo inversion */ +img[id^="proxmoxlogo-"][id$="-img"], +img[id^="proxmoxLogoSvg-"][id$="-img"] { + filter: invert(1) hue-rotate(180deg); +} + +/* Invalid/warning/disabled rows */ +.proxmox-invalid-row { + background-color: rgba(243, 139, 168, 0.15) !important; +} + +.proxmox-warning-row { + background-color: rgba(250, 179, 135, 0.15) !important; +} + +.proxmox-disabled-row td { + color: var(--ctp-overlay0) !important; +} + +/* Hints */ +.pmx-hint { + background-color: rgba(250, 179, 135, 0.15) !important; + white-space: nowrap !important; +} + +.pmx-hint a { + color: var(--ctp-blue) !important; +} + +/* Status text colors — style guide: Information → Teal */ +.info-blue { + color: var(--ctp-teal) !important; +} + +.critical { + color: var(--ctp-red) !important; +} + +/* Links */ +a { + color: var(--ctp-blue) !important; +} + +/* Markdown content */ +.pmx-md code { + background-color: var(--ctp-mantle) !important; + color: var(--ctp-rosewater) !important; + border-radius: var(--pm-radius-sm) !important; +} + +.pmx-md pre code { + border-color: var(--ctp-surface1) !important; + background-color: var(--ctp-crust) !important; +} + +.pmx-md a { + color: var(--ctp-blue) !important; +} + +.pmx-md table { + border-color: var(--ctp-surface1) !important; +} + +.pmx-md th { + background-color: var(--ctp-mantle) !important; + border-color: var(--ctp-surface1) !important; +} + +.pmx-md td { + border-color: var(--ctp-surface1) !important; +} + +/* APT repos */ +.proxmox-apt-repos .x-grid-group-hd { + background-color: var(--ctp-base) !important; + border: none !important; +} + +.proxmox-apt-repos .x-grid-group-title { + color: var(--ctp-text) !important; +} + +/* Tags */ +.pve-edit-tag { + border-radius: var(--pm-radius-md) !important; +} + +.pve-edit-tag.editable span { + background-color: var(--ctp-mantle) !important; + color: var(--ctp-text) !important; + border-color: var(--ctp-surface1) !important; +} + +.x-tree-node-text .proxmox-tag-dark, +.x-tree-node-text .proxmox-tag-light, +.x-grid-cell-inner .proxmox-tag-dark, +.x-grid-cell-inner .proxmox-tag-light, +span.proxmox-tag-dark, +span.proxmox-tag-light { + border-radius: var(--pm-radius-md) !important; +} + +/* Checkmark button in tag edit — match toolbar button size */ +.x-btn.x-btn-default-small:has(.fa-check) { + min-height: 24px !important; + height: 24px !important; + padding: 3px 8px !important; + border-radius: var(--pm-radius-sm) !important; + background-color: var(--ctp-mauve) !important; + border: none !important; +} + +.x-btn.x-btn-default-small:has(.fa-check).x-btn-disabled { + background-color: transparent !important; + border: 1px solid var(--ctp-surface1) !important; + opacity: 0.5 !important; +} + +.x-btn.x-btn-default-small:has(.fa-check) .fa-check { + color: var(--ctp-on-accent) !important; +} + +.x-btn.x-btn-default-small:has(.fa-check).x-btn-disabled .fa-check { + color: var(--ctp-overlay1) !important; +} + +.x-btn.x-btn-default-small:has(.fa-check):not(.x-btn-disabled):hover { + background-color: #d4b4fa !important; +} + +.x-btn.x-btn-default-small:has(.fa-check) .x-btn-inner { + display: none !important; +} + +/* Date picker */ +.x-datepicker, +.x-datepicker-column-header, +.x-monthpicker { + background-color: var(--ctp-base) !important; + color: var(--ctp-text) !important; + border-color: transparent !important; +} + +.x-datepicker-header, +.x-datepicker-footer, +.x-monthpicker-buttons { + background-color: var(--ctp-mantle) !important; +} + +.x-datepicker-date, +.x-monthpicker-item-inner { + color: var(--ctp-text) !important; +} + +.x-datepicker-selected div.x-datepicker-date, +.x-monthpicker-item a.x-monthpicker-selected, +a.x-monthpicker-item-inner:hover, +div.x-datepicker-date:hover { + background-color: var(--ctp-hover-overlay) !important; + color: var(--ctp-text) !important; +} + +.x-datepicker-today .x-datepicker-date { + border-color: var(--ctp-mauve) !important; +} + +.x-datepicker-disabled .x-datepicker-date { + color: var(--ctp-overlay0) !important; +} + +.x-datepicker-prev-day .x-datepicker-date, +.x-datepicker-next-day .x-datepicker-date { + color: var(--ctp-overlay0) !important; +} + +/* Usage bars */ +.usage-wrapper, +.usage { + border-radius: 2px !important; +} + +.usage { + background-color: var(--ctp-overlay2) !important; +} + +/* ===================================================== + SCROLLBARS + ===================================================== */ +::-webkit-scrollbar { + width: 8px; + height: 8px; +} + +::-webkit-scrollbar-track { + background: var(--ctp-base); + border-radius: var(--pm-radius-sm); +} + +::-webkit-scrollbar-thumb { + background: var(--ctp-surface2); + border-radius: var(--pm-radius-sm); + border: 1px solid transparent; + background-clip: padding-box; + transition: background 0.15s ease; +} + +::-webkit-scrollbar-thumb:hover { + background: var(--ctp-overlay0); +} + +::-webkit-scrollbar-corner { + background: var(--ctp-base); +} + +/* Firefox scrollbar */ +* { + scrollbar-width: thin; + scrollbar-color: var(--ctp-surface2) var(--ctp-base); +} + +/* ===================================================== + SELECTION HIGHLIGHT + ===================================================== */ +::selection { + background-color: rgba(147, 153, 178, 0.3); + color: var(--ctp-text); +} + +/* ===================================================== + TRANSITIONS (smooth interactions) + ===================================================== */ + +/* Grid row transitions */ +.x-grid-item { + transition: background-color 0.15s ease !important; +} + +/* Tree pseudo-element transitions */ +.x-treelist-row::before { + transition: background-color 0.15s ease !important; +} + +/* Menu item transitions */ +.x-menu-item-default > .x-menu-item-link { + transition: background-color 0.12s ease !important; +} + +/* Boundlist item transitions */ +.x-boundlist-item { + transition: background-color 0.12s ease !important; +} + +/* Tab transitions */ +.x-tab { + transition: color 0.15s ease !important; +} + +/* Splitter transition */ +.x-splitter { + transition: background-color 0.15s ease !important; +} + +/* Tooltip transition */ +.x-tip { + transition: opacity 0.15s ease !important; +} + +/* Progress bar width transition */ +.x-progress-bar { + transition: width 0.4s ease !important; +} + +/* Scrollbar thumb transition */ +::-webkit-scrollbar-thumb { + transition: background 0.15s ease !important; +} + +/* Window close tool transition */ +.x-tool-img { + transition: filter 0.15s ease !important; +} + +/* ===================================================== + TOOL ICONS - FontAwesome Replacements + (Ported from UniFi v5.86) + Replace sprite-based ExtJS tool icons with crisp + FontAwesome icons for better consistency and clarity + ===================================================== */ + +/* Base styling for all tool icons - remove sprite backgrounds */ +.x-tool-tool-el.x-tool-minus, +.x-tool-img.x-tool-minus, +.x-tool-tool-el.x-tool-collapse-right, +.x-tool-img.x-tool-collapse-right, +.x-tool-tool-el.x-tool-collapse-left, +.x-tool-img.x-tool-collapse-left, +.x-tool-tool-el.x-tool-expand-right, +.x-tool-img.x-tool-expand-right, +.x-tool-tool-el.x-tool-expand-left, +.x-tool-img.x-tool-expand-left, +.x-tool-tool-el.x-tool-maximize, +.x-tool-img.x-tool-maximize, +.x-tool-tool-el.x-tool-restore, +.x-tool-img.x-tool-restore, +.x-tool-tool-el.x-tool-gear, +.x-tool-img.x-tool-gear, +.x-tool-tool-el.x-tool-refresh, +.x-tool-img.x-tool-refresh, +.x-tool-tool-el.x-tool-close, +.x-tool-img.x-tool-close { + background-image: none !important; + font-family: "FontAwesome" !important; + font-size: 14px !important; + line-height: 16px !important; + text-align: center !important; + color: var(--pm-text-dim) !important; + transition: color 0.15s ease !important; + filter: none !important; + width: 16px !important; + height: 16px !important; + display: flex !important; + align-items: center !important; + justify-content: center !important; +} + +/* Close button - slightly larger */ +.x-tool-tool-el.x-tool-close, +.x-tool-img.x-tool-close { + font-size: 20px !important; +} + +/* Individual glyph assignments */ +.x-tool-tool-el.x-tool-minus::before, +.x-tool-img.x-tool-minus::before { + content: "\f010" !important; /* fa-search-minus (zoom out) */ +} + +.x-tool-tool-el.x-tool-collapse-right::before, +.x-tool-img.x-tool-collapse-right::before { + content: "\f054" !important; /* fa-chevron-right */ +} + +.x-tool-tool-el.x-tool-expand-left::before, +.x-tool-img.x-tool-expand-left::before { + content: "\f053" !important; /* fa-chevron-left */ +} + +.x-tool-tool-el.x-tool-collapse-left::before, +.x-tool-img.x-tool-collapse-left::before { + content: "\f053" !important; /* fa-chevron-left */ +} + +.x-tool-tool-el.x-tool-expand-right::before, +.x-tool-img.x-tool-expand-right::before { + content: "\f054" !important; /* fa-chevron-right */ +} + +.x-tool-tool-el.x-tool-maximize::before, +.x-tool-img.x-tool-maximize::before { + content: "\f065" !important; /* fa-expand */ +} + +.x-tool-tool-el.x-tool-restore::before, +.x-tool-img.x-tool-restore::before { + content: "\f066" !important; /* fa-compress */ +} + +.x-tool-tool-el.x-tool-gear::before, +.x-tool-img.x-tool-gear::before { + content: "\f013" !important; /* fa-cog */ +} + +.x-tool-tool-el.x-tool-refresh::before, +.x-tool-img.x-tool-refresh::before { + content: "\f021" !important; /* fa-refresh */ +} + +.x-tool-tool-el.x-tool-close::before, +.x-tool-img.x-tool-close::before { + content: "\f00d" !important; /* fa-times */ +} + +/* Hover state - all tool icons */ +.x-tool:hover .x-tool-tool-el.x-tool-minus, +.x-tool:hover .x-tool-img.x-tool-minus, +.x-tool:hover .x-tool-tool-el.x-tool-collapse-right, +.x-tool:hover .x-tool-img.x-tool-collapse-right, +.x-tool:hover .x-tool-tool-el.x-tool-collapse-left, +.x-tool:hover .x-tool-img.x-tool-collapse-left, +.x-tool:hover .x-tool-tool-el.x-tool-expand-right, +.x-tool:hover .x-tool-img.x-tool-expand-right, +.x-tool:hover .x-tool-tool-el.x-tool-expand-left, +.x-tool:hover .x-tool-img.x-tool-expand-left, +.x-tool:hover .x-tool-tool-el.x-tool-maximize, +.x-tool:hover .x-tool-img.x-tool-maximize, +.x-tool:hover .x-tool-tool-el.x-tool-restore, +.x-tool:hover .x-tool-img.x-tool-restore, +.x-tool:hover .x-tool-tool-el.x-tool-gear, +.x-tool:hover .x-tool-img.x-tool-gear, +.x-tool:hover .x-tool-tool-el.x-tool-refresh, +.x-tool:hover .x-tool-img.x-tool-refresh, +.x-tool:hover .x-tool-tool-el.x-tool-close, +.x-tool:hover .x-tool-img.x-tool-close { + color: var(--pm-text) !important; +} + +/* Disabled state */ +.x-tool-disabled .x-tool-tool-el, +.x-tool-disabled .x-tool-img { + opacity: 0.4 !important; + cursor: default !important; +} + +/* Inline FontAwesome tools (PVE-injected) */ +.x-tool-tool-el[style*="font-family:FontAwesome"], +.x-tool-tool-el[style*="font-family: FontAwesome"] { + color: var(--pm-text-dim) !important; + font-size: 14px !important; + line-height: 16px !important; + display: flex !important; + align-items: center !important; + justify-content: center !important; + width: 16px !important; + height: 16px !important; + transition: color 0.15s ease !important; + background-image: none !important; + background-color: transparent !important; +} + +.x-tool:not(.x-tool-disabled) .x-tool-tool-el[style*="font-family:FontAwesome"], +.x-tool:not(.x-tool-disabled) .x-tool-tool-el[style*="font-family: FontAwesome"] { + cursor: pointer !important; +} + +.x-tool.x-tool-disabled .x-tool-tool-el[style*="font-family:FontAwesome"], +.x-tool.x-tool-disabled .x-tool-tool-el[style*="font-family: FontAwesome"] { + cursor: default !important; + opacity: 0.4 !important; +} + +.x-tool .x-mask { + background-color: transparent !important; + backdrop-filter: none !important; + pointer-events: none !important; +} + +.x-tool:not(.x-tool-disabled):hover .x-tool-tool-el[style*="font-family:FontAwesome"], +.x-tool:not(.x-tool-disabled):hover .x-tool-tool-el[style*="font-family: FontAwesome"] { + color: var(--pm-text) !important; +} diff --git a/themes/theme-dracula-cyan.css b/themes/theme-dracula-cyan.css new file mode 100644 index 0000000..e81172c --- /dev/null +++ b/themes/theme-dracula-cyan.css @@ -0,0 +1,2378 @@ +/*!Dracula Cyan*/ +/* + * ProxMorph Theme: Dracula Cyan + * The canonical dark theme with Cyan accent — ported from the Dracula specification + * Version: 1.0.0 + * Author: ProxMorph / Dracula Theme (https://draculatheme.com) + * + * v1.0.0: Initial release — Tier 2 baseline with all fixes + * - Full Dracula palette with derived shades + * - All component sections ported from UniFi/Catppuccin reference + * - Console/Terminal, Charts, Progress bars, Buttons (28px), + * Dialog fixes, Tree cursor:pointer, APT repos, Tag checkmark + * + * ─── Dracula Specification Palette ───────────────────────────── + * Background: #282a36 Current Line: #44475a + * Foreground: #f8f8f2 Comment: #6272a4 + * Cyan: #8be9fd Green: #50fa7b + * Orange: #ffb86c Pink: #ff79c6 + * Purple: #bd93f9 Red: #ff5555 + * Yellow: #f1fa8c + * + * ─── Derived Shades (ProxMorph) ──────────────────────────────── + * Crust: #1e1f29 Mantle: #21222c + * Surface 0: #343746 Surface 1: #44475a (= Current Line) + * Surface 2: #565a72 Overlay 0: #6272a4 (= Comment) + * Overlay 1: #7c83a0 Overlay 2: #9298b8 + * Subtext 0: #b0b5c8 Subtext 1: #d0d4e0 + * Text: #f8f8f2 On-Accent: #282a36 + */ + +/* ===================================================== + CSS VARIABLES + ===================================================== */ +:root { + /* Dracula Specification Tokens */ + --drac-bg: #282a36; + --drac-current-line: #44475a; + --drac-fg: #f8f8f2; + --drac-comment: #6272a4; + --drac-cyan: #8be9fd; + --drac-green: #50fa7b; + --drac-orange: #ffb86c; + --drac-pink: #ff79c6; + --drac-purple: #bd93f9; + --drac-red: #ff5555; + --drac-yellow: #f1fa8c; + + /* Derived Neutral Scale */ + --drac-text: #f8f8f2; + --drac-subtext1: #d0d4e0; + --drac-subtext0: #b0b5c8; + --drac-overlay2: #9298b8; + --drac-overlay1: #7c83a0; + --drac-overlay0: #6272a4; + --drac-surface2: #565a72; + --drac-surface1: #44475a; + --drac-surface0: #343746; + --drac-base: #282a36; + --drac-mantle: #21222c; + --drac-crust: #1e1f29; + + /* ProxMorph Semantic Variables */ + --pm-accent: var(--drac-cyan); + --pm-bg-base: var(--drac-base); + --pm-bg-surface: var(--drac-surface0); + --pm-bg-elevated: var(--drac-surface1); + --pm-text: var(--drac-text); + --pm-text-dim: var(--drac-subtext1); + --pm-success: var(--drac-green); + --pm-warning: var(--drac-yellow); + --pm-error: var(--drac-red); + --pm-border: var(--drac-surface1); + --pm-radius-sm: 4px; + --pm-radius-md: 6px; + --pm-radius-lg: 8px; + + /* Proxmox Widget Toolkit Mappings (REQUIRED) */ + --pwt-panel-background: var(--drac-base); + --pwt-text-color: var(--drac-text); + --pwt-gauge-default: var(--drac-cyan); + --pwt-gauge-back: var(--drac-surface1); + --pwt-gauge-warn: var(--drac-yellow); + --pwt-gauge-crit: var(--drac-red); + --pwt-chart-primary: var(--drac-cyan); + --pwt-chart-grid-stroke: var(--drac-surface1); + + /* On Accent text — Background on colored backgrounds for contrast */ + --drac-on-accent: var(--drac-bg); + + /* Hover overlay — Comment@12% */ + --drac-hover-overlay: rgba(98, 114, 164, 0.12); + /* Selection overlay — Comment@25% */ + --drac-select-overlay: rgba(98, 114, 164, 0.25); + /* Accent muted (for focus rings) */ + --drac-accent-muted: rgba(139, 233, 253, 0.4); + --drac-accent-subtle: rgba(139, 233, 253, 0.15); + + color-scheme: dark; +} + +/* ===================================================== + GLOBAL BORDER-RADIUS ARCHITECTURE + (Ported from UniFi theme — reset everything, selectively re-apply) + ===================================================== */ +.x-border-box, +.x-border-box * { + border-radius: var(--pm-radius-lg); +} + +/* Remove rounded corners from grids/tables/lists */ +.x-grid, +.x-grid *, +.x-grid-header-ct, +.x-grid-header-ct *, +.x-grid-view, +.x-grid-view *, +.x-column-header, +.x-column-header *, +.x-grid-item, +.x-grid-cell, +.x-grid-cell-inner, +.x-grid-row, +table, +table *, +tr, +td, +th, +.x-legend, +.x-legend *, +.x-legend-container, +.x-legend-container *, +.x-legend-item, +.x-legend-horizontal .x-legend-item, +.x-legend-vertical .x-legend-item, +.x-legend-horizontal .x-legend-item:first-child, +.x-legend-horizontal .x-legend-item:last-child, +.x-legend-vertical .x-legend-item:first-child, +.x-legend-vertical .x-legend-item:last-child, +.x-tool, +.x-tool-tool-el, +.x-tool-default, +.x-tool-img { + border-radius: 0 !important; +} + +/* Form elements - exclude from global radius */ +.x-form-item, +.x-form-item-default, +.x-form-item-body, +.x-form-item-body-default, +.x-form-text-field-body, +.x-form-text-field-body-default, +.x-form-fieldcontainer, +.x-field, +.x-field-default, +.x-form-type-text { + border-radius: 0 !important; +} + +/* Reset layout containers that clip elements with overflow:hidden + radius */ +.x-box-layout-ct, +.x-panel-bodyWrap, +.x-panel-bodyWrap-default, +.x-autocontainer-innerCt, +.x-autocontainer-outerCt, +.x-panel.x-tabpanel-child, +.x-panel.x-box-item, +.x-box-inner, +.x-box-target, +.x-container, +.x-container-default, +.x-window .x-panel-body, +.x-window .x-window-body, +.x-window .x-window-bodyWrap { + border-radius: 0 !important; +} + +/* Reset everything inside windows to 0 — then re-apply specific radii */ +.x-window *, +.x-window .x-autocontainer-innerCt, +.x-window .x-autocontainer-outerCt, +.x-window .x-form-layout-wrap, +.x-window .x-form-layout-auto-label, +.x-window .x-form-layout-colgroup, +.x-window .x-form-layout-column, +.x-window .x-field, +.x-window .x-form-item, +.x-window .x-form-item-body { + border-radius: 0 !important; +} + +/* Chart canvas — no radius on data area */ +.x-chart-grid, +.x-chart-axis, +canvas.x-surface, +.x-chart canvas, +canvas.x-surface-canvas, +.x-surface-canvas, +.x-draw-component canvas, +.proxmox-rrd-chart canvas, +svg.x-surface, +.x-draw-container, +.x-surface { + border-radius: 0 !important; +} + +/* Legend color marker (dot) — keep circular */ +.x-legend-item-marker { + border-radius: 50% !important; +} + +/* ===================================================== + RE-APPLY BORDER RADII (selective) + ===================================================== */ + +/* Windows */ +.x-window, +.x-window-default { + border-radius: var(--pm-radius-lg) !important; +} + +.x-window-header, +.x-window-header-default { + border-radius: var(--pm-radius-lg) var(--pm-radius-lg) 0 0 !important; +} + +.x-window .x-window-body, +.x-window-body-default { + border-radius: 0 !important; +} + +/* Buttons inside windows */ +.x-window .x-btn { + border-radius: var(--pm-radius-md) !important; +} + +/* Checkboxes inside windows */ +.x-window .x-form-checkbox { + border-radius: 3px !important; +} + +/* Form inputs inside windows */ +.x-window .x-form-trigger-wrap, +.x-window .x-form-trigger-wrap-default { + border-radius: var(--pm-radius-sm) !important; +} + +.x-window .x-form-text-wrap, +.x-window .x-form-text { + border-radius: var(--pm-radius-sm) 0 0 var(--pm-radius-sm) !important; +} + +.x-window .x-form-arrow-trigger { + border-radius: 0 var(--pm-radius-sm) var(--pm-radius-sm) 0 !important; +} + +/* Form trigger/text wrap — reset and re-apply */ +.x-form-trigger-wrap, +.x-form-trigger-wrap *, +.x-form-text-wrap, +.x-form-text-wrap *, +.x-form-text, +.x-form-trigger { + border-radius: 0 !important; +} + +.x-form-trigger-wrap, +.x-form-trigger-wrap-default { + border-radius: var(--pm-radius-sm) !important; + overflow: hidden !important; +} + +.x-form-text-wrap, +.x-form-text-wrap-default { + border-radius: var(--pm-radius-sm) 0 0 var(--pm-radius-sm) !important; +} + +.x-form-text, +.x-form-text-default { + border-radius: var(--pm-radius-sm) 0 0 var(--pm-radius-sm) !important; +} + +.x-form-trigger, +.x-form-trigger-default, +.x-form-arrow-trigger, +.x-form-arrow-trigger-default { + border-radius: 0 var(--pm-radius-sm) var(--pm-radius-sm) 0 !important; +} + +/* Dialog form content padding — vertical only (horizontal causes ExtJS overflow) */ +.x-window .x-tabpanel-child .x-autocontainer-innerCt { + padding: 12px 0 !important; +} + +/* Allow column panel bodies to show overflowed form content */ +.x-window .x-panel-body:not(.x-scroller) { + overflow: visible !important; +} + +/* Side padding on column panel bodies inside windows */ +.x-window .x-panel.x-box-item .x-panel-body { + padding: 0 4px !important; +} + +/* Constrain autocontainer width inside windows */ +.x-window .x-autocontainer-outerCt { + max-width: 100% !important; +} + +/* Fix window header/body width consistency */ +.x-window > .x-window-header, +.x-window > .x-window-body, +.x-window > .x-window-bodyWrap, +.x-window-bodyWrap > .x-window-body { + width: 100% !important; +} + +.x-window-header > .x-box-inner, +.x-window-header > .x-box-inner > .x-box-target { + width: 100% !important; +} + +.x-window-header-title { + width: auto !important; + flex: 1 !important; + max-width: calc(100% - 30px) !important; +} + +/* Boundlists */ +.x-boundlist { + border-radius: var(--pm-radius-md) !important; + overflow: hidden !important; +} + +/* ===================================================== + BASE / BODY + ===================================================== */ +.x-body, +.x-viewport > .x-body, +body.x-border-layout-ct, +div.x-border-layout-ct { + background-color: var(--drac-base) !important; + color: var(--drac-text) !important; +} + +/* ===================================================== + MASKS & OVERLAYS + ===================================================== */ +.x-mask { + background-color: rgba(30, 31, 41, 0.6) !important; + backdrop-filter: blur(4px); +} + +.x-mask-msg { + background-color: var(--drac-mantle) !important; + border: 1px solid var(--drac-surface1) !important; + border-radius: var(--pm-radius-lg) !important; +} + +.x-mask-msg-text { + color: var(--drac-subtext0) !important; + filter: none !important; +} + +.x-css-shadow { + box-shadow: 0 8px 24px rgba(30, 31, 41, 0.6) !important; +} + +/* Loading indicators */ +.x-grid-row-loading, +.x-treelist-item-loading .x-treelist-item-icon, +.x-grid-tree-loading .x-tree-icon { + filter: invert(90%); +} + +/* ===================================================== + ICONS — Proxmox default colors for dark mode + ===================================================== */ + +/* General icon colors — neutral gray for dark backgrounds */ +.x-tree-icon-custom, +.x-grid-icon-custom, +.fa-tags::before, +.fa-file-o::before, +.fa-building::before, +.x-action-col-icon::before, +.fa-shield::before, +.fa-file-text-o::before, +.fa-clock-o::before, +.x-tab-icon-el-default, +.pve-icon-verify-lettering::after, +.x-tree-icon-leaf:not(.x-tree-icon-custom)::before, +.x-tree-icon-parent:not(.x-tree-icon-custom)::before, +.x-tree-icon-parent-expanded:not(.x-tree-icon-custom)::before, +.x-grid-filters-filtered-column .x-column-header-text::after { + color: var(--drac-overlay2) !important; +} + +/* Folder icons — invert for dark mode */ +.x-tree-icon-parent:not(.x-tree-icon-custom)::before, +.x-tree-icon-parent-expanded:not(.x-tree-icon-custom)::before { + filter: invert(90%); +} + +/* Various image-based icons — invert for visibility */ +.fa-ceph::before, +.fa-sdn::before, +.fa-network-wired::before, +.pve-itype-treelist-item-icon-cdrom, +.fa-chevron-right::before, +.x-grid-row-console, +.x-box-scroller-toolbar-default.x-box-scroller, +.x-tree-elbow-img, +.pve-itype-icon-qemu, +.x-tree-node-computer, +.x-grid-tree-node-expanded .x-tree-node-computer, +.pbs-icon-tape, +.pbs-icon-tape-drive, +.x-tree-icon-leaf:not(.x-tree-icon-custom), +.x-tree-icon-parent:not(.x-tree-icon-custom), +.x-tree-icon-parent-expanded:not(.x-tree-icon-custom) { + filter: invert(90%); +} + +/* Hardware icons */ +.pve-itype-icon-cpu, +.pve-itype-icon-cdrom, +.pve-itype-icon-memory, +.pve-itype-icon-pci, +.pve-itype-icon-serial, +.pve-itype-icon-die, +.pmx-itype-icon-processor, +.pmx-itype-icon-memory, +.pve-itype-icon-storage, +.x-tree-node-harddisk, +.x-grid-tree-node-expanded .x-tree-node-harddisk { + filter: invert(100%); +} + +/* Hardware icons — counter-invert for non-SVG icon cells */ +td.pve-itype-icon-storage .x-grid-cell-inner, +td.x-tree-node-harddisk .x-grid-cell-inner { + filter: invert(100%) !important; +} + +/* Hardware icons — hide inverted borders for non-SVG icon cells */ +td.pve-itype-icon-storage, +td.x-tree-node-harddisk { + border-color: transparent !important; +} + +/* Hardware grid icons — mask-image renders SVG icons in theme text color + Replaces filter:invert approach for pve-itype-icon-* and pmx-itype-icon-* grid cells */ +td.pve-itype-icon-cpu, +td.pve-itype-icon-cdrom, +td.pve-itype-icon-memory, +td.pve-itype-icon-pci, +td.pve-itype-icon-serial, +td.pve-itype-icon-die, +td.pmx-itype-icon-processor, +td.pmx-itype-icon-memory { + filter: none !important; + background-image: none !important; + padding-left: 0 !important; + border-color: transparent !important; +} + +td.pve-itype-icon-cpu .x-grid-cell-inner, +td.pve-itype-icon-cdrom .x-grid-cell-inner, +td.pve-itype-icon-memory .x-grid-cell-inner, +td.pve-itype-icon-pci .x-grid-cell-inner, +td.pve-itype-icon-serial .x-grid-cell-inner, +td.pve-itype-icon-die .x-grid-cell-inner, +td.pmx-itype-icon-processor .x-grid-cell-inner, +td.pmx-itype-icon-memory .x-grid-cell-inner { + padding-left: 3px !important; +} + +td.pve-itype-icon-cpu .x-grid-cell-inner::before, +td.pve-itype-icon-cdrom .x-grid-cell-inner::before, +td.pve-itype-icon-memory .x-grid-cell-inner::before, +td.pve-itype-icon-pci .x-grid-cell-inner::before, +td.pve-itype-icon-serial .x-grid-cell-inner::before, +td.pve-itype-icon-die .x-grid-cell-inner::before, +td.pmx-itype-icon-processor .x-grid-cell-inner::before, +td.pmx-itype-icon-memory .x-grid-cell-inner::before { + content: '' !important; + display: inline-block !important; + width: 18px !important; + height: 14px !important; + vertical-align: middle !important; + margin-right: 10px !important; + background-color: currentColor !important; + -webkit-mask-size: contain !important; + mask-size: contain !important; + -webkit-mask-repeat: no-repeat !important; + mask-repeat: no-repeat !important; + -webkit-mask-position: center !important; + mask-position: center !important; +} + +td.pve-itype-icon-cpu .x-grid-cell-inner::before { + -webkit-mask-image: url('/pve2/images/icon-cpu.svg') !important; + mask-image: url('/pve2/images/icon-cpu.svg') !important; +} + +td.pve-itype-icon-memory .x-grid-cell-inner::before { + -webkit-mask-image: url('/pve2/images/icon-memory.svg') !important; + mask-image: url('/pve2/images/icon-memory.svg') !important; +} + +td.pve-itype-icon-cdrom .x-grid-cell-inner::before { + -webkit-mask-image: url('/pve2/images/icon-cd-drive.svg') !important; + mask-image: url('/pve2/images/icon-cd-drive.svg') !important; +} + +td.pve-itype-icon-pci .x-grid-cell-inner::before { + -webkit-mask-image: url('/pve2/images/icon-pci.svg') !important; + mask-image: url('/pve2/images/icon-pci.svg') !important; +} + +td.pve-itype-icon-serial .x-grid-cell-inner::before { + -webkit-mask-image: url('/pve2/images/icon-serial.svg') !important; + mask-image: url('/pve2/images/icon-serial.svg') !important; +} + +td.pve-itype-icon-die .x-grid-cell-inner::before { + -webkit-mask-image: url('/pve2/images/icon-die.svg') !important; + mask-image: url('/pve2/images/icon-die.svg') !important; +} + +td.pmx-itype-icon-processor .x-grid-cell-inner::before { + -webkit-mask-image: url('../images/icon-cpu.svg') !important; + mask-image: url('../images/icon-cpu.svg') !important; +} + +td.pmx-itype-icon-memory .x-grid-cell-inner::before { + -webkit-mask-image: url('../images/icon-ram.svg') !important; + mask-image: url('../images/icon-ram.svg') !important; +} + + +/* Icon overlays — default */ +.x-tree-icon-custom::after, +.x-grid-icon-custom::after { + color: var(--drac-overlay2) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* RUNNING VMs/CTs — Dracula Green */ +.x-tree-icon-custom.running::after, +.x-grid-icon-custom.running::after, +.x-treelist-item-icon.running::after { + color: var(--drac-green) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* ONLINE state — Green */ +.x-tree-icon-custom.online::after, +.x-grid-icon-custom.online::after { + color: var(--drac-green) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* Stopped/offline — Overlay1 (muted gray) */ +.x-tree-icon-custom.stopped, +.x-tree-icon-custom.offline, +.x-grid-icon-custom.stopped, +.x-grid-icon-custom.offline { + color: var(--drac-overlay1) !important; +} + +/* Unknown state — Overlay1 */ +.x-tree-icon-custom.unknown::after, +.x-grid-icon-custom.unknown::after { + color: var(--drac-overlay1) !important; +} + +/* ERROR states — Dracula Red */ +.x-tree-icon-custom.error::after, +.x-tree-icon-custom.offline::after, +.x-tree-icon-custom.ha-error::after, +.x-grid-icon-custom.error::after, +.x-grid-icon-custom.offline::after, +.x-grid-icon-custom.ha-error::after { + color: var(--drac-red) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* PAUSED/SUSPENDED — Dracula Orange */ +.x-tree-icon-custom.paused::after, +.x-tree-icon-custom.suspended::after, +.x-tree-icon-custom.lock-suspending::after, +.x-grid-icon-custom.paused::after, +.x-grid-icon-custom.suspended::after, +.x-grid-icon-custom.lock-suspending::after { + color: var(--drac-orange) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* PENDING/WARNING states — Dracula Yellow */ +.x-tree-icon-custom.pending::after, +.x-tree-icon-custom.io-error::after, +.x-tree-icon-custom.internal-error::after, +.x-tree-icon-custom.guest-panicked::after, +.x-grid-icon-custom.pending::after, +.x-grid-icon-custom.io-error::after, +.x-grid-icon-custom.internal-error::after, +.x-grid-icon-custom.guest-panicked::after { + color: var(--drac-yellow) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* HA MAINTENANCE — Dracula Cyan */ +.x-tree-icon-custom.ha-maintenance::after, +.x-grid-icon-custom.ha-maintenance::after { + color: var(--drac-cyan) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* Locked icons */ +.x-tree-icon-custom.locked::after, +.x-tree-icon-custom.lock-backup::after, +.x-tree-icon-custom.lock-migrate::after, +.x-tree-icon-custom.lock-suspended::after, +.x-grid-icon-custom.locked::after, +.x-grid-icon-custom.lock-backup::after, +.x-grid-icon-custom.lock-migrate::after, +.x-grid-icon-custom.lock-suspended::after { + color: var(--drac-overlay2) !important; +} + +/* LXC/QEMU type indicators */ +.x-tree-icon-custom.lxc::after, +.x-tree-icon-custom.qemu::after, +.x-grid-icon-custom.lxc::after, +.x-grid-icon-custom.qemu::after { + background-color: transparent; + color: var(--drac-overlay1) !important; +} + +.x-treelist-item-icon.lxc::after, +.x-treelist-item-icon.qemu::after { + background-color: transparent; + color: var(--drac-overlay1) !important; +} + +/* Tree expander arrows */ +.x-tree-arrows .x-tree-expander { + filter: brightness(200%); +} + +/* Cancel sprite-inversion on custom controls (checkboxes/radios handled via CSS) */ +.x-form-checkbox-default, +.x-form-radio-default, +.x-column-header-checkbox .x-column-header-checkbox::after, +.x-grid-checkcolumn::after, +.x-menu-item-checked .x-menu-item-icon-default.x-menu-item-checkbox, +.x-menu-item-unchecked .x-menu-item-icon-default.x-menu-item-checkbox { + filter: none !important; +} + +/* ===================================================== + PANELS & HEADERS + ===================================================== */ +.x-panel, +.x-panel-default { + border-radius: var(--pm-radius-lg) !important; + padding: 0 !important; +} + +/* Column panels — native stacked layout (Issue #23 fix) */ +.x-panel.x-column { + padding: 5px !important; + margin: 0 !important; + max-width: none !important; + box-sizing: border-box !important; +} + +/* Column panel card styling — borders for summary + chart panels */ +.x-panel.x-panel-default.x-column { + border: 1px solid var(--drac-surface1) !important; + border-radius: var(--pm-radius-lg) !important; + overflow: hidden !important; +} + +/* Guest status + Notes panel borders */ +[id^="pveGuestStatusView-"].x-panel, +[id^="pveLxcStatusView-"].x-panel, +[id^="pveQemuStatusView-"].x-panel, +[id^="pmxNotesView-"].x-panel { + border: 1px solid var(--drac-surface1) !important; + border-radius: var(--pm-radius-lg) !important; +} + +.x-panel-body, +.x-panel-body-default { + background-color: var(--drac-base) !important; + color: var(--drac-text) !important; + border: none !important; +} + +/* Panel headers — bottom border only */ +.x-panel-header, +.x-panel-header-default { + background-color: var(--drac-mantle) !important; + border: none !important; + border-bottom: 1px solid var(--drac-surface1) !important; + border-radius: var(--pm-radius-lg) var(--pm-radius-lg) 0 0 !important; + margin: 0 !important; + padding: 8px 12px !important; + width: 100% !important; + box-sizing: border-box !important; + overflow: visible !important; +} + +/* Title text — prevent border-radius clipping */ +.x-title-text, +.x-title-text-default { + overflow: visible !important; +} + +.x-panel-bodyWrap, +.x-panel-bodyWrap-default { + margin: 0 !important; + padding: 0 !important; + overflow: visible !important; +} + +/* Remove borders from nested panels */ +.x-panel-body > .x-box-layout-ct, +.x-panel-body > .x-container, +.x-panel-body > .x-box-inner, +[id*="pmxGauge"] { + border: none !important; +} + +.x-panel-header-title-default, +.x-window-header-title-default { + color: var(--drac-text) !important; +} + +.x-panel-header-default .x-tool-tool-el { + background-color: transparent; +} + +.x-tool-img { + filter: brightness(175%); +} + +.x-tool-over .x-tool-img { + filter: brightness(200%); +} + +/* Resource tree — panel body border */ +div[id^="pveResourceTree-"][id$="-body"] { + border-color: var(--drac-base) !important; +} + +/* Resource tree — remove row separators */ +[id^="pveResourceTree-"].x-tree-panel td.x-grid-cell, +[id^="pveResourceTree-"].x-tree-panel .x-grid-td, +[id^="pveResourceTree-"].x-tree-panel .x-grid-cell { + border-bottom: none !important; +} + +/* Resource tree — row spacing */ +div[id^="pveResourceTree"] .x-grid-cell { + padding-top: 3px !important; + padding-bottom: 3px !important; +} + +/* Summary/stats panel radius overrides */ +.pveStatusPanel, +.x-panel-default-framed, +.x-panel-body-default-framed { + border-radius: 12px !important; +} + +.x-panel-header-default-framed { + border-radius: 12px 12px 0 0 !important; +} + +/* Column widget panel radius */ +.x-panel.x-column > .x-panel-bodyWrap > .x-panel-body.x-panel-body-default { + border-radius: var(--pm-radius-lg) !important; +} + +/* ===================================================== + SPLITTERS / SEPARATORS + ===================================================== */ +.x-splitter-vertical { + background-color: transparent !important; + border-left: 1px solid var(--drac-surface1) !important; + border-right: none !important; + width: 1px !important; +} + +.x-splitter-horizontal { + background-color: var(--drac-crust) !important; + border-top: 1px solid var(--drac-surface1) !important; +} + +.x-splitter { + background-color: var(--drac-crust) !important; +} + +.x-keyboard-mode .x-splitter-focus::after { + border-color: var(--drac-cyan) !important; +} + +.x-layout-split-bottom { + opacity: 0.7; +} + +/* Toolbox tree (pve-nav) right border — full height */ +.pve-toolbar-bg { + border-right: 1px solid var(--drac-surface1) !important; + z-index: 3 !important; +} + +.x-treelist.x-treelist-pve-nav { + border-right: none !important; +} + +/* ===================================================== + TOOLBARS + ===================================================== */ +.x-toolbar, +.x-toolbar-default { + background-color: var(--drac-base) !important; + border-color: var(--drac-surface1) !important; +} + +.x-toolbar-default.x-docked-top { + border: none !important; + border-bottom: 1px solid var(--drac-surface1) !important; +} + +.x-toolbar-default .x-toolbar-separator { + border-color: var(--drac-surface1); +} + +.x-toolbar-text-default { + color: var(--drac-subtext0); +} + +/* ===================================================== + PRIMARY BUTTONS — Dracula Purple + ===================================================== */ +.x-btn-default-small { + background-color: var(--drac-cyan) !important; + border: 1px solid rgba(139, 233, 253, 0.4) !important; + border-radius: var(--pm-radius-md) !important; + transition: background-color 0.15s ease, box-shadow 0.15s ease !important; +} + +.x-btn-default-small .x-btn-inner { + color: var(--drac-on-accent) !important; + font-weight: 600 !important; +} + +.x-btn-default-small .x-btn-icon-el { + color: var(--drac-on-accent) !important; +} + +.x-btn-default-small.x-btn-over, +.x-keyboard-mode .x-btn-default-small.x-btn-focus { + background-color: #a2eefe !important; + box-shadow: 0 0 0 3px var(--drac-accent-subtle) !important; +} + +.x-btn-default-small.x-btn.x-btn-disabled { + background-color: var(--drac-cyan) !important; + opacity: 0.4; +} + +.x-btn-default-small.x-btn.x-btn-pressed { + background-color: #72d8ed !important; +} + +/* Button height consistency — 28px with vertical centering */ +/* Exclude tag edit buttons (display:none when hidden, :has(.fa-check) for checkmark) */ +.x-btn.x-btn-default-small:not(.x-btn-default-toolbar-small):not([style*="display: none"]):not([style*="display:none"]):not(:has(.fa-check)) { + height: 28px !important; + min-height: 28px !important; + display: flex !important; + align-items: center !important; + padding: 3px 8px !important; +} + +/* Fix button inner element centering for proper icon alignment (issue #17) */ +.x-btn.x-btn-default-small:not(.x-btn-default-toolbar-small):not([style*="display: none"]):not([style*="display:none"]):not(:has(.fa-check)) .x-btn-wrap { + display: flex !important; + align-items: center !important; +} + +.x-btn.x-btn-default-small:not(.x-btn-default-toolbar-small):not([style*="display: none"]):not([style*="display:none"]):not(:has(.fa-check)) .x-btn-inner { + display: flex !important; + align-items: center !important; +} + +/* Fix dropdown arrows on split/arrow buttons */ +.x-btn-wrap.x-btn-arrow-right::after, +.x-btn-wrap.x-btn-split-right::after { + height: 16px !important; + min-height: 16px !important; + width: 20px !important; + display: flex !important; + align-items: center !important; +} + +/* Fix icon-only buttons — hide   inner element when button has no text */ +.x-btn-no-text .x-btn-inner, +.x-btn-button.x-btn-no-text .x-btn-inner, +.x-btn-button-default-toolbar-small.x-btn-no-text .x-btn-inner-default-toolbar-small, +.x-btn-button-default-small.x-btn-no-text .x-btn-inner-default-small, +.x-btn-button-default-small.x-btn-no-text > .x-btn-inner-default-small { + display: none !important; +} + +/* Specific fix for fa-desktop icon (Create VM) — visually bottom-heavy */ +.x-btn-icon-el.fa-desktop { + transform: translateY(1.1px) !important; +} + +/* ===================================================== + SECONDARY / TOOLBAR BUTTONS + ===================================================== */ +.x-btn-default-toolbar-small { + background-color: var(--drac-surface0) !important; + border: 1px solid var(--drac-surface1) !important; + border-radius: var(--pm-radius-md) !important; + transition: background-color 0.15s ease, border-color 0.15s ease !important; +} + +.x-btn-default-toolbar-small .x-btn-inner-default-toolbar-small, +.x-btn-default-toolbar-small .x-btn-icon-el-default-toolbar-small { + color: var(--drac-text) !important; +} + +.x-btn-default-toolbar-small .x-btn-wrap-default-toolbar-small.x-btn-arrow-right::after, +.x-btn-default-toolbar-small .x-btn-wrap-default-toolbar-small.x-btn-split-right::after { + filter: brightness(150%); +} + +.x-btn-default-toolbar-small.x-btn-over, +.x-keyboard-mode .x-btn-default-toolbar-small.x-btn-focus { + background-color: var(--drac-surface1) !important; + border-color: var(--drac-surface2) !important; +} + +.x-btn-default-toolbar-small.x-btn.x-btn-disabled { + background-color: var(--drac-surface0) !important; + opacity: 0.4; +} + +.x-btn-default-toolbar-small.x-btn.x-btn-menu-active, +.x-btn-default-toolbar-small.x-btn.x-btn-pressed { + background-color: var(--drac-cyan) !important; + border-color: var(--drac-cyan) !important; + padding: 4px 8px !important; /* Fix #30: prevent width change on dropdown */ +} + +.x-btn-default-toolbar-small.x-btn.x-btn-pressed .x-btn-inner-default-toolbar-small, +.x-btn-default-toolbar-small.x-btn.x-btn-pressed .x-btn-icon-el-default-toolbar-small, +.x-btn-default-toolbar-small.x-btn.x-btn-pressed .x-btn-inner-default-small, +.x-btn-default-toolbar-small.x-btn.x-btn-pressed .x-btn-icon-el-default-small { + color: var(--drac-on-accent) !important; +} + +/* Segmented buttons */ +.x-segmented-button { + border-radius: var(--pm-radius-md) !important; +} + +.x-segmented-button .x-btn, +.x-segmented-button .x-btn-default-small, +.x-segmented-button .x-btn-inner, +.x-segmented-button .x-btn-wrap { + border-radius: var(--pm-radius-md) !important; +} + +/* Inline buttons (Documentation, Help) */ +.proxmox-inline-button { + height: 28px !important; + min-height: 28px !important; + display: flex !important; + align-items: center !important; + padding: 3px 8px !important; + background-color: var(--drac-surface0) !important; + border: 1px solid var(--drac-surface1) !important; + border-radius: var(--pm-radius-md) !important; + color: var(--drac-text) !important; + transition: background-color 0.15s ease !important; +} + +.proxmox-inline-button:hover, +.proxmox-inline-button.x-btn-over { + background-color: var(--drac-surface1) !important; + border-color: var(--drac-overlay0) !important; +} + +.proxmox-inline-button:active, +.proxmox-inline-button.x-btn-pressed { + background-color: var(--drac-surface2) !important; +} + +.proxmox-inline-button .x-btn-inner, +.proxmox-inline-button .x-btn-icon-el { + color: var(--drac-text) !important; +} + +/* Pressed/active inline buttons — use on-accent text */ +.proxmox-inline-button.x-btn-pressed .x-btn-inner, +.proxmox-inline-button.x-btn-pressed .x-btn-icon-el, +.proxmox-inline-button.x-btn-menu-active .x-btn-inner, +.proxmox-inline-button.x-btn-menu-active .x-btn-icon-el { + color: var(--drac-on-accent) !important; +} + +/* ===================================================== + FORM ELEMENTS + ===================================================== */ +.x-form-trigger-default { + background-color: var(--drac-surface0) !important; +} + +.x-form-text-default { + background-color: var(--drac-surface0) !important; + color: var(--drac-text) !important; + border-radius: var(--pm-radius-sm) !important; +} + +.x-form-trigger-wrap, +.x-form-trigger-wrap-default { + border-color: var(--drac-surface1) !important; + background-color: var(--drac-surface0) !important; + border-radius: var(--pm-radius-sm) !important; + transition: border-color 0.15s ease !important; +} + +.x-form-trigger-wrap-default.x-form-trigger-wrap-focus { + border-color: var(--drac-cyan) !important; + box-shadow: 0 0 0 3px var(--drac-accent-subtle) !important; +} + +.x-form-item-label-default, +.x-form-cb-label-default { + color: var(--drac-text) !important; +} + +.x-form-display-field-default { + color: var(--drac-subtext0) !important; + border-radius: var(--pm-radius-md) !important; +} + +.x-form-spinner-default { + background-color: var(--drac-surface0) !important; +} + +.x-fieldset, +.x-fieldset-default { + border-color: var(--drac-surface1) !important; + border-radius: var(--pm-radius-lg) !important; +} + +.x-fieldset-header-default > .x-fieldset-header-text { + color: var(--drac-text) !important; +} + +/* ===================================================== + CHECKBOXES & RADIOS — Dracula styled + ===================================================== */ + +/* Base: remove sprite, styled as custom control */ +.x-form-checkbox, .x-form-checkbox-default, +.x-form-radio, .x-form-radio-default { + background-image: none !important; + background-color: var(--drac-surface0) !important; + border: 1.5px solid var(--drac-overlay0) !important; + width: 16px !important; + height: 16px !important; + display: inline-block !important; + box-sizing: border-box !important; + cursor: pointer !important; + transition: border-color 0.12s ease, background-color 0.12s ease !important; +} + +/* Checkbox: rounded square */ +.x-form-checkbox, .x-form-checkbox-default { + border-radius: 3px !important; +} + +/* Radio: circle + ::after inner dot */ +.x-form-radio, .x-form-radio-default { + border-radius: 50% !important; + position: relative !important; + transform: translateZ(0) !important; + box-shadow: inset 0 0 0 0 transparent !important; +} + +.x-form-radio::after { + content: '' !important; + position: absolute !important; + top: 50% !important; + left: 50% !important; + width: 7px !important; + height: 7px !important; + border-radius: 50% !important; + background: transparent !important; + transform: translate(-50%, -50%) scale(0) !important; + transition: transform 0.15s ease, background 0.15s ease !important; + pointer-events: none !important; +} + +/* Hover */ +.x-form-checkbox:hover, .x-form-checkbox-default:hover, +.x-form-cb-wrap:hover .x-form-checkbox { + border-color: var(--drac-cyan) !important; +} + +.x-form-radio:hover, .x-form-radio-default:hover, +.x-form-cb-wrap:hover .x-form-radio { + border-color: var(--drac-cyan) !important; +} + +/* CHECKED checkbox — Purple fill + dark SVG checkmark */ +.x-form-cb-checked .x-form-checkbox, +.x-form-cb-checked .x-form-checkbox-default { + background-color: var(--drac-cyan) !important; + border-color: var(--drac-cyan) !important; + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 8'%3E%3Cpath d='M1 4l3 3 5-6' fill='none' stroke='%23282a36' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") !important; + background-repeat: no-repeat !important; + background-position: center !important; + background-size: 9px 7px !important; +} + +/* SELECTED radio — Purple dot */ +.x-form-cb-checked .x-form-radio, +.x-form-cb-checked .x-form-radio-default { + border-color: var(--drac-cyan) !important; + background-color: var(--drac-base) !important; +} + +.x-form-cb-checked .x-form-radio::after { + background: var(--drac-cyan) !important; + transform: translate(-50%, -50%) scale(1) !important; +} + +/* ===================================================== + BOUNDLIST / DROPDOWNS + ===================================================== */ +.x-boundlist { + background-color: var(--drac-mantle) !important; + border: 1px solid var(--drac-surface1) !important; + border-radius: var(--pm-radius-md) !important; + box-shadow: 0 8px 24px rgba(30, 31, 41, 0.7) !important; + padding: 2px !important; + overflow: hidden !important; +} + +.x-boundlist-item { + background-color: transparent !important; + color: var(--drac-text) !important; + border-radius: var(--pm-radius-sm) !important; + padding: 2px 6px !important; + line-height: normal !important; + border: none !important; + cursor: pointer !important; + outline: none !important; + box-shadow: none !important; +} + +.x-boundlist-selected { + background-color: var(--drac-select-overlay) !important; + color: var(--drac-text) !important; +} + +.x-boundlist-item-over { + background-color: var(--drac-hover-overlay) !important; +} + +/* ===================================================== + GRIDS / TABLES + ===================================================== */ +.x-grid, +.x-grid-view { + border-radius: 0 !important; +} + +.x-column-header { + border-color: var(--drac-surface1) !important; + background-color: transparent !important; +} + +.x-column-header-inner, +.x-column-header-text { + color: var(--drac-text) !important; + font-weight: 600 !important; +} + +.x-column-header-trigger { + border-color: var(--drac-surface1) !important; +} + +.x-grid-item, +.x-column-header-default, +.x-grid-cell-row-numberer { + color: var(--drac-text) !important; + background-color: var(--drac-base) !important; +} + +.x-grid-cell-special { + border-color: var(--drac-surface1) !important; +} + +.x-grid-group-hd { + background-color: var(--drac-base) !important; + border-color: var(--drac-surface1) !important; +} + +.x-grid-group-title { + color: var(--drac-text) !important; +} + +.x-grid-header-ct { + background-color: var(--drac-mantle) !important; + border: 1px solid var(--drac-surface0) !important; + border-radius: var(--pm-radius-lg) var(--pm-radius-lg) 0 0 !important; +} + +.x-grid-item-alt { + background-color: var(--drac-crust) !important; +} + +.x-grid-with-row-lines .x-grid-item { + border-color: var(--drac-surface0) !important; +} + +.x-grid-cell { + border-bottom: 1px solid rgba(68, 71, 90, 0.4) !important; +} + +.x-grid-item-over, +.x-grid-with-row-lines .x-grid-item.x-grid-item-over { + background-color: var(--drac-hover-overlay) !important; +} + +.x-grid-item-selected, +.x-grid-with-row-lines .x-grid-item.x-grid-item-selected { + background-color: var(--drac-select-overlay) !important; +} + +.x-column-header-over, +.x-column-header-open { + background-color: var(--drac-hover-overlay) !important; +} + +.x-column-header-sort-ASC, +.x-column-header-sort-DESC { + background-color: var(--drac-hover-overlay) !important; +} + +.x-grid-row-summary .x-grid-cell, +.x-grid-row-summary .x-grid-rowwrap, +.x-grid-row-summary .x-grid-cell-rowbody { + background-color: var(--drac-base) !important; + border-color: var(--drac-surface1); +} + +.x-grid-with-col-lines .x-grid-cell, +.x-grid-with-col-lines .x-grid-item-over .x-grid-cell, +.x-grid-with-col-lines .x-grid-item-selected .x-grid-cell { + border-color: var(--drac-surface1) !important; +} + +.x-dd-drag-proxy { + background-color: var(--drac-mantle); + border-color: var(--drac-surface1); + color: var(--drac-text); +} + +.x-keyboard-mode .x-grid-item-focused { + background-color: var(--drac-hover-overlay) !important; + color: var(--drac-text) !important; +} + +/* Remove blue outline from focused/selected items in resource tree */ +.x-keyboard-mode .x-grid-item-focused .x-grid-cell-inner::before, +.x-keyboard-mode .x-grid-item-selected .x-grid-cell-inner::before, +.x-grid-item-selected .x-grid-cell-inner::before, +.x-grid-item-focused .x-grid-cell-inner::before, +[id^="pveResourceTree"] .x-grid-item-selected .x-grid-cell-inner::before, +[id^="pveResourceTree"] .x-grid-item-focused .x-grid-cell-inner::before { + content: none !important; + display: none !important; + border: none !important; +} + +.x-grid-empty { + background-color: var(--drac-base) !important; + color: var(--drac-subtext0) !important; +} + +/* Grid info (pve-info-grid) and RRD view */ +.pve-info-grid { + border-radius: 12px !important; +} + +.pve-rrdview, +.rrdview { + border-radius: 12px !important; +} + +.pve-summary-status, +.x-container .pve-status { + border-radius: var(--pm-radius-lg) !important; +} + +[id^="pveGuestStatusView-"][id$="-body"], +[id^="pmxNotesView-"] .x-panel-body { + border-radius: var(--pm-radius-lg) !important; +} + +.x-panel-default[id*="notes"], +.pve-notes-view { + border-radius: var(--pm-radius-lg) !important; +} + +/* Floating grid pickers (storage/ISO selectors) */ +.x-layer.x-grid .x-grid-view, +.x-panel.x-layer.x-grid .x-grid-view, +.x-panel.x-layer.x-grid, +.x-layer.x-panel.x-grid { + border-radius: var(--pm-radius-sm) !important; +} + +.x-layer.x-grid .x-grid-item-over, +.x-layer.x-grid .x-grid-item-selected, +.x-panel.x-layer.x-grid .x-grid-item-over, +.x-panel.x-layer.x-grid .x-grid-item-selected { + border-radius: var(--pm-radius-sm) !important; + outline: none !important; + box-shadow: none !important; +} + +.x-layer.x-grid .x-grid-item-over td, +.x-layer.x-grid .x-grid-item-selected td, +.x-layer.x-grid .x-grid-item-over .x-grid-cell, +.x-layer.x-grid .x-grid-item-selected .x-grid-cell, +.x-panel.x-layer.x-grid .x-grid-item-over td, +.x-panel.x-layer.x-grid .x-grid-item-selected td, +.x-panel.x-layer.x-grid .x-grid-item-over .x-grid-cell, +.x-panel.x-layer.x-grid .x-grid-item-selected .x-grid-cell { + border-radius: 0 !important; +} + +.x-layer.x-grid .x-grid-item-over td:first-child, +.x-layer.x-grid .x-grid-item-selected td:first-child, +.x-panel.x-layer.x-grid .x-grid-item-over td:first-child, +.x-panel.x-layer.x-grid .x-grid-item-selected td:first-child { + border-radius: var(--pm-radius-sm) 0 0 var(--pm-radius-sm) !important; +} + +.x-layer.x-grid .x-grid-item-over td:last-child, +.x-layer.x-grid .x-grid-item-selected td:last-child, +.x-panel.x-layer.x-grid .x-grid-item-over td:last-child, +.x-panel.x-layer.x-grid .x-grid-item-selected td:last-child { + border-radius: 0 var(--pm-radius-sm) var(--pm-radius-sm) 0 !important; +} + +/* ===================================================== + MENUS + ===================================================== */ +.x-menu, +.x-menu-default { + background-color: var(--drac-crust) !important; + border: 1px solid var(--drac-surface0) !important; + border-radius: var(--pm-radius-lg) !important; + box-shadow: 0 8px 24px rgba(30, 31, 41, 0.8) !important; + padding: 2px !important; + overflow: hidden !important; +} + +.x-menu-body-default { + background-color: transparent !important; + padding: 4px !important; +} + +.x-menu-header { + background-color: transparent !important; + color: var(--drac-text) !important; +} + +/* Menu icon separator — hide */ +.x-menu-icon-separator-default { + display: none !important; +} + +/* Menu item layout (flexbox reordering) */ +.x-menu-item-default > .x-menu-item-link { + display: flex !important; + align-items: center !important; + flex-direction: row !important; + gap: 4px !important; + justify-content: flex-start !important; + flex-wrap: nowrap !important; + border-radius: var(--pm-radius-md) !important; + padding: 4px 8px !important; + line-height: 20px !important; + cursor: pointer !important; + outline: none !important; + box-shadow: none !important; + white-space: nowrap !important; + text-decoration: none !important; +} + +.x-menu-item-text-default { + color: var(--drac-text) !important; + font-size: 13px !important; + order: 1 !important; + margin-left: 0 !important; + text-align: left !important; + line-height: 20px !important; + display: inline-flex !important; + align-items: center !important; + flex: 1 1 auto !important; + width: auto !important; + white-space: nowrap !important; +} + +.x-menu-item-icon-default { + color: var(--drac-subtext0) !important; + order: -1 !important; + position: relative !important; + float: none !important; + margin-right: 8px !important; + margin-left: 0 !important; + left: auto !important; + top: auto !important; + width: 16px !important; + text-align: center !important; + display: inline-flex !important; + align-items: center !important; + justify-content: center !important; + height: 20px !important; + line-height: 20px !important; + vertical-align: middle !important; + flex: 0 0 16px !important; + align-self: center !important; +} + +.x-menu-item-arrow, +.x-menu-item-arrow-default { + order: 2 !important; + margin-left: auto !important; +} + +.x-menu-item-default.x-menu-item-separator { + background-color: var(--drac-surface0) !important; + border: none !important; + height: 1px !important; + margin: 6px 4px !important; +} + +.x-menu-item-default.x-menu-item-focus, +.x-menu-item-default.x-menu-item-active, +.x-menu-item:hover { + background-color: var(--drac-surface0) !important; + color: var(--drac-text) !important; + border-radius: var(--pm-radius-md) !important; +} + +.x-menu-item-active .x-menu-item-text-default, +.x-menu-item-focus .x-menu-item-text-default { + color: var(--drac-text) !important; +} + +.x-menu-item-active .x-menu-item-icon-default, +.x-menu-item-focus .x-menu-item-icon-default { + color: var(--drac-cyan) !important; +} + +/* ===================================================== + PROGRESS BARS + ===================================================== */ + +/* Fix: Widget containers need overflow visible to not clip progress bars */ +.x-container[id^="pmxInfoWidget"], +.x-container.x-box-layout-ct { + overflow: visible !important; +} + +.x-progress, +.x-progress-default { + background-color: var(--drac-surface0) !important; + border-radius: 5px !important; +} + +.x-progress-default .x-progress-bar-default { + background-color: var(--drac-cyan) !important; + border-radius: 5px !important; + transition: width 0.4s ease !important; +} + +.x-progress-default .x-progress-text { + color: var(--drac-text) !important; +} + +/* Text overlaid on the progress bar fill — use on-accent for contrast */ +.x-progress-bar .x-progress-text { + color: var(--drac-on-accent) !important; +} + +.x-progress.warning .x-progress-bar { + background-color: var(--drac-yellow) !important; +} + +.x-progress.critical .x-progress-bar { + background-color: var(--drac-red) !important; +} + +/* ===================================================== + TABS — Dracula underline style + Flat tabs with Purple underline on active tab + ===================================================== */ +.x-tab-bar, +.x-tab-bar-default { + background-color: var(--drac-base) !important; + border-radius: 0 !important; + border-bottom: 1px solid var(--drac-surface1) !important; + padding-bottom: 0 !important; +} + +/* Overflow visible for the underline indicator */ +.x-tab-bar .x-box-inner, +.x-tab-bar .x-box-target, +.x-tab-bar-body, +.x-tab-bar-body-default { + overflow: visible !important; +} + +/* Base tab */ +.x-tab, +.x-tab-default, +.x-tab-default-top { + background-color: transparent !important; + border: none !important; + border-radius: var(--pm-radius-md) var(--pm-radius-md) 0 0 !important; + padding: 8px 16px 8px !important; + overflow: visible !important; + margin-bottom: 0 !important; + transition: color 0.15s ease !important; + outline: none !important; + box-shadow: none !important; +} + +/* Remove ::after from inactive tabs */ +.x-tab::after { + display: none !important; +} + +.x-tab-inner-default { + color: var(--drac-subtext0) !important; + font-size: 13px !important; +} + +.x-tab-default.x-tab-over { + background-color: transparent !important; +} + +.x-tab-default.x-tab-over .x-tab-inner-default { + color: var(--drac-text) !important; +} + +/* Active tab */ +.x-tab-default.x-tab.x-tab-active { + background-color: transparent !important; + border: none !important; + overflow: visible !important; + margin-bottom: 0 !important; + outline: none !important; + box-shadow: none !important; +} + +/* Purple underline indicator on active tab */ +.x-tab-default.x-tab.x-tab-active::after { + content: '' !important; + display: block !important; + position: absolute !important; + bottom: 0 !important; + left: 0 !important; + right: 0 !important; + height: 2px !important; + background: var(--drac-cyan) !important; + z-index: 10 !important; + border-radius: 2px 2px 0 0 !important; + pointer-events: none !important; +} + +.x-tab-active .x-tab-inner-default { + color: var(--drac-text) !important; + font-weight: 600 !important; +} + +.x-tab-default.x-tab.x-tab-disabled { + background-color: transparent !important; + border: none !important; + color: var(--drac-overlay0) !important; + margin-bottom: 0 !important; +} + +/* Focus states — no outline */ +.x-keyboard-mode .x-tab-default.x-tab-focus, +.x-keyboard-mode .x-tab-default.x-tab-focus.x-tab-active { + background-color: transparent !important; + border: none !important; + outline: none !important; + box-shadow: none !important; + margin-bottom: 0 !important; +} + +.x-keyboard-mode .x-tab-default.x-tab-focus.x-tab-active::after { + content: '' !important; + display: block !important; + position: absolute !important; + bottom: 0 !important; + left: 0 !important; + right: 0 !important; + height: 2px !important; + background: var(--drac-cyan) !important; + z-index: 10 !important; + pointer-events: none !important; +} + +/* Kill ALL tab interaction outlines/shadows */ +.x-tab:focus, +.x-tab *:focus, +.x-tab-focus, +.x-tab-active.x-tab-focus, +.x-tab-inner-focus, +.x-tab-button-focus, +.x-tab-pressed, +.x-tab-active.x-tab-pressed, +.x-tab-over, +.x-tab:active, +.x-tab *:active { + outline: none !important; + box-shadow: none !important; +} + +.x-tabpanel-child { + border-radius: 0 0 var(--pm-radius-lg) var(--pm-radius-lg) !important; +} + +/* Tab hover/active corners */ +.x-tab-default.x-tab-over, +.x-tab-default.x-tab.x-tab-active { + border-radius: var(--pm-radius-md) var(--pm-radius-md) 0 0 !important; +} + +/* ===================================================== + TOOLTIPS + ===================================================== */ +.x-tip, +.x-tip-default { + background-color: var(--drac-mantle) !important; + border: 1px solid var(--drac-surface1) !important; + border-radius: var(--pm-radius-md) !important; + box-shadow: 0 4px 12px rgba(30, 31, 41, 0.5); +} + +.x-tip-body-default { + color: var(--drac-text) !important; +} + +.x-tip-form-invalid { + background-color: var(--drac-mantle) !important; + border-color: var(--drac-red) !important; +} + +.x-tip-body-form-invalid { + color: var(--drac-red) !important; +} + +/* ===================================================== + TREE NAVIGATION (Sidebar) + ===================================================== */ +.x-treelist-item { + background-color: var(--drac-base) !important; + border-radius: var(--pm-radius-md) !important; +} + +/* Pseudo-element approach for hover/selected highlighting */ +.x-treelist-row { + border-radius: var(--pm-radius-md) !important; + background-color: transparent !important; + position: relative !important; + z-index: 0 !important; +} + +.x-treelist-row::before { + content: ""; + position: absolute; + top: 1px; + bottom: 1px; + left: 0; + right: 4px; + border-radius: var(--pm-radius-md); + background-color: transparent; + z-index: -1; + pointer-events: none; + transition: background-color 0.15s ease; +} + +/* Fix toolbox tree item text overlapping icons */ +.x-treelist-item-text { + margin-left: 28px !important; +} + +/* Toolbox tree items — bright text */ +.x-treelist-item-text, +.x-treelist-item-icon, +.x-treelist.x-treelist-pve-nav .x-treelist-item-text, +.x-treelist.x-treelist-pve-nav .x-treelist-item-icon { + color: var(--drac-subtext1) !important; +} + +/* Hover state — apply to pseudo-element */ +.x-treelist-row-over { + background-color: transparent !important; +} + +.x-treelist-row-over::before { + background-color: var(--drac-hover-overlay) !important; +} + +.x-treelist-row-over .x-treelist-item-icon, +.x-treelist-row-over .x-treelist-item-text { + background-color: transparent !important; + color: var(--drac-text) !important; +} + +/* Selected/active item — Purple highlight */ +.x-treelist-item-selected > .x-treelist-row { + background-color: transparent !important; +} + +.x-treelist-item-selected > .x-treelist-row::before, +.x-treelist-item-selected > .x-treelist-row:hover::before { + background-color: var(--drac-cyan) !important; +} + +.x-treelist-item-selected .x-treelist-item-text, +.x-treelist-item-selected .x-treelist-item-icon, +.x-treelist.x-treelist-pve-nav .x-treelist-item-selected .x-treelist-item-text, +.x-treelist.x-treelist-pve-nav .x-treelist-item-selected .x-treelist-item-icon { + color: var(--drac-on-accent) !important; +} + +.x-treelist-pve-nav { + background-color: var(--drac-base) !important; + border-color: var(--drac-surface1) !important; +} + +/* Tree navigation radius overrides */ +.x-treelist-item, +.x-treelist-item-tool { + border-radius: var(--pm-radius-sm) !important; +} + +.x-treelist-row, +.x-treelist-row:hover, +.x-treelist-row-over, +.x-treelist-item-selected > .x-treelist-row, +.x-treelist-item-selected > .x-treelist-row:hover, +.x-treelist-item-expanded > .x-treelist-row, +.x-treelist-item-expanded > .x-treelist-row-over, +.x-treelist-item-expandable > .x-treelist-row, +.x-treelist-item-expandable > .x-treelist-row-over { + border-radius: var(--pm-radius-sm) !important; +} + +.x-treelist-row::before { + border-radius: var(--pm-radius-sm) !important; +} + +.x-treelist-item-wrap, +.x-treelist-item-text, +.x-treelist-row, +.x-treelist-container, +.x-treelist-root-container, +.x-treelist, +.x-treelist-pve-nav { + border-radius: var(--pm-radius-sm) !important; +} + +/* Cursor pointer for interactive tree/grid items */ +.x-grid-cell, +.x-grid-cell-inner, +.x-tree-elbow-img, +.x-tree-icon, +.x-treelist-item, +.x-treelist-row, +.x-treelist-item-wrap, +.x-treelist-item-text, +.x-treelist-item-icon { + cursor: pointer !important; +} + +/* ===================================================== + WINDOWS / MODALS + ===================================================== */ +.x-window, +.x-window-default { + background-color: var(--drac-crust) !important; + border: 1px solid var(--drac-surface1) !important; + border-radius: var(--pm-radius-lg) !important; + box-shadow: 0 8px 24px rgba(30, 31, 41, 0.6) !important; + overflow: hidden !important; +} + +.x-window .x-window-header, +.x-window-header-default { + background-color: var(--drac-mantle) !important; + border-color: transparent !important; + border-radius: var(--pm-radius-lg) var(--pm-radius-lg) 0 0 !important; +} + +.x-window-header-default .x-mask { + background-color: rgba(30, 31, 41, 0.7); +} + +.x-window .x-window-body, +.x-window-body-default { + background-color: var(--drac-base) !important; + border-color: var(--drac-surface1) !important; + color: var(--drac-text) !important; + border-radius: 0 0 var(--pm-radius-lg) var(--pm-radius-lg) !important; +} + +.x-window-ghost { + background-color: var(--drac-base) !important; +} + +.x-window-header-default .x-tool-img { + background-color: transparent; +} + +.x-message-box .x-window-body { + background-color: var(--drac-mantle) !important; +} + +/* Respect ExtJS inline display:none on hidden dialog buttons */ +.x-message-box .x-btn.x-btn-default-small[style*="display: none"], +.x-message-box .x-btn.x-btn-default-small[style*="display:none"], +.x-window .x-toolbar-footer .x-btn[style*="display: none"], +.x-window .x-toolbar-footer .x-btn[style*="display:none"] { + display: none !important; +} + +/* Login dialog — clean inner panel borders */ +.x-window:has(#pveloginrealm) .x-panel-body { + border: none !important; + background: transparent !important; + width: auto !important; +} + +/* ===================================================== + CONSOLE / TERMINAL + ===================================================== */ +div.monitor { + border-color: var(--drac-surface1); +} + +.install-mask { + background-color: var(--drac-crust); + color: var(--drac-subtext0); +} + +.x-window.install-mask { + box-shadow: rgba(30, 31, 41, 0.5) 0 4px 20px !important; +} + +/* ===================================================== + LEGEND / CHARTS + ===================================================== */ +.x-legend-container { + background-color: var(--drac-base) !important; +} + +.x-legend-horizontal .x-legend-item { + background-color: var(--drac-mantle) !important; + color: var(--drac-text) !important; + border: 1px solid var(--drac-surface0) !important; +} + +/* Chart/RRD panel backgrounds */ +div[id*="rrdchart"], +.pve-rrddatastore, +.pmx-panel-rrd { + background-color: var(--drac-base) !important; +} + +.proxmox-rrd-panel canvas, +.proxmox-widget-toolkit canvas, +canvas.x-surface, +.x-surface canvas { + background-color: transparent !important; + opacity: 1 !important; +} + +.proxmox-rrd-panel, +.proxmox-rrd-chart { + background-color: var(--drac-base) !important; +} + +/* Chart text/labels */ +.x-surface text, +svg text { + fill: var(--drac-text) !important; +} + +/* ===================================================== + PROXMOX-SPECIFIC OVERRIDES + ===================================================== */ + +/* Logo inversion */ +img[id^="proxmoxlogo-"][id$="-img"], +img[id^="proxmoxLogoSvg-"][id$="-img"] { + filter: invert(1) hue-rotate(180deg); +} + +/* Invalid/warning/disabled rows */ +.proxmox-invalid-row { + background-color: rgba(255, 85, 85, 0.15) !important; +} + +.proxmox-warning-row { + background-color: rgba(255, 184, 108, 0.15) !important; +} + +.proxmox-disabled-row td { + color: var(--drac-overlay0) !important; +} + +/* Hints */ +.pmx-hint { + background-color: rgba(255, 184, 108, 0.15) !important; + white-space: nowrap !important; +} + +.pmx-hint a { + color: var(--drac-cyan) !important; +} + +/* Status text colors — Information → Cyan */ +.info-blue { + color: var(--drac-cyan) !important; +} + +.critical { + color: var(--drac-red) !important; +} + +/* Links */ +a { + color: var(--drac-cyan) !important; +} + +/* Markdown content */ +.pmx-md code { + background-color: var(--drac-mantle) !important; + color: var(--drac-pink) !important; + border-radius: var(--pm-radius-sm) !important; +} + +.pmx-md pre code { + border-color: var(--drac-surface1) !important; + background-color: var(--drac-crust) !important; +} + +.pmx-md a { + color: var(--drac-cyan) !important; +} + +.pmx-md table { + border-color: var(--drac-surface1) !important; +} + +.pmx-md th { + background-color: var(--drac-mantle) !important; + border-color: var(--drac-surface1) !important; +} + +.pmx-md td { + border-color: var(--drac-surface1) !important; +} + +/* APT repos */ +.proxmox-apt-repos .x-grid-group-hd { + background-color: var(--drac-base) !important; + border: none !important; +} + +.proxmox-apt-repos .x-grid-group-title { + color: var(--drac-text) !important; +} + +/* Tags */ +.pve-edit-tag { + border-radius: var(--pm-radius-md) !important; +} + +.pve-edit-tag.editable span { + background-color: var(--drac-mantle) !important; + color: var(--drac-text) !important; + border-color: var(--drac-surface1) !important; +} + +.x-tree-node-text .proxmox-tag-dark, +.x-tree-node-text .proxmox-tag-light, +.x-grid-cell-inner .proxmox-tag-dark, +.x-grid-cell-inner .proxmox-tag-light, +span.proxmox-tag-dark, +span.proxmox-tag-light { + border-radius: var(--pm-radius-md) !important; +} + +/* Checkmark button in tag edit — match toolbar button size */ +.x-btn.x-btn-default-small:has(.fa-check) { + min-height: 24px !important; + height: 24px !important; + padding: 3px 8px !important; + border-radius: var(--pm-radius-sm) !important; + background-color: var(--drac-cyan) !important; + border: none !important; +} + +.x-btn.x-btn-default-small:has(.fa-check).x-btn-disabled { + background-color: transparent !important; + border: 1px solid var(--drac-surface1) !important; + opacity: 0.5 !important; +} + +.x-btn.x-btn-default-small:has(.fa-check) .fa-check { + color: var(--drac-on-accent) !important; +} + +.x-btn.x-btn-default-small:has(.fa-check).x-btn-disabled .fa-check { + color: var(--drac-overlay1) !important; +} + +.x-btn.x-btn-default-small:has(.fa-check):not(.x-btn-disabled):hover { + background-color: #a2eefe !important; +} + +.x-btn.x-btn-default-small:has(.fa-check) .x-btn-inner { + display: none !important; +} + +/* Date picker */ +.x-datepicker, +.x-datepicker-column-header, +.x-monthpicker { + background-color: var(--drac-base) !important; + color: var(--drac-text) !important; + border-color: transparent !important; +} + +.x-datepicker-header, +.x-datepicker-footer, +.x-monthpicker-buttons { + background-color: var(--drac-mantle) !important; +} + +.x-datepicker-date, +.x-monthpicker-item-inner { + color: var(--drac-text) !important; +} + +.x-datepicker-selected div.x-datepicker-date, +.x-monthpicker-item a.x-monthpicker-selected, +a.x-monthpicker-item-inner:hover, +div.x-datepicker-date:hover { + background-color: var(--drac-hover-overlay) !important; + color: var(--drac-text) !important; +} + +.x-datepicker-today .x-datepicker-date { + border-color: var(--drac-cyan) !important; +} + +.x-datepicker-disabled .x-datepicker-date { + color: var(--drac-overlay0) !important; +} + +.x-datepicker-prev-day .x-datepicker-date, +.x-datepicker-next-day .x-datepicker-date { + color: var(--drac-overlay0) !important; +} + +/* Usage bars */ +.usage-wrapper, +.usage { + border-radius: 2px !important; +} + +.usage { + background-color: var(--drac-overlay2) !important; +} + +/* ===================================================== + SCROLLBARS + ===================================================== */ +::-webkit-scrollbar { + width: 8px; + height: 8px; +} + +::-webkit-scrollbar-track { + background: var(--drac-base); + border-radius: var(--pm-radius-sm); +} + +::-webkit-scrollbar-thumb { + background: var(--drac-surface2); + border-radius: var(--pm-radius-sm); + border: 1px solid transparent; + background-clip: padding-box; + transition: background 0.15s ease; +} + +::-webkit-scrollbar-thumb:hover { + background: var(--drac-overlay0); +} + +::-webkit-scrollbar-corner { + background: var(--drac-base); +} + +/* Firefox scrollbar */ +* { + scrollbar-width: thin; + scrollbar-color: var(--drac-surface2) var(--drac-base); +} + +/* ===================================================== + SELECTION HIGHLIGHT + ===================================================== */ +::selection { + background-color: rgba(98, 114, 164, 0.3); + color: var(--drac-text); +} + +/* ===================================================== + TRANSITIONS (smooth interactions) + ===================================================== */ + +/* Grid row transitions */ +.x-grid-item { + transition: background-color 0.15s ease !important; +} + +/* Tree pseudo-element transitions */ +.x-treelist-row::before { + transition: background-color 0.15s ease !important; +} + +/* Menu item transitions */ +.x-menu-item-default > .x-menu-item-link { + transition: background-color 0.12s ease !important; +} + +/* Boundlist item transitions */ +.x-boundlist-item { + transition: background-color 0.12s ease !important; +} + +/* Tab transitions */ +.x-tab { + transition: color 0.15s ease !important; +} + +/* Splitter transition */ +.x-splitter { + transition: background-color 0.15s ease !important; +} + +/* Tooltip transition */ +.x-tip { + transition: opacity 0.15s ease !important; +} + +/* Progress bar width transition */ +.x-progress-bar { + transition: width 0.4s ease !important; +} + +/* Scrollbar thumb transition */ +::-webkit-scrollbar-thumb { + transition: background 0.15s ease !important; +} + +/* Window close tool transition */ +.x-tool-img { + transition: filter 0.15s ease !important; +} + +/* ===================================================== + TOOL ICONS - FontAwesome Replacements + (Ported from UniFi v5.86) + Replace sprite-based ExtJS tool icons with crisp + FontAwesome icons for better consistency and clarity + ===================================================== */ + +/* Base styling for all tool icons - remove sprite backgrounds */ +.x-tool-tool-el.x-tool-minus, +.x-tool-img.x-tool-minus, +.x-tool-tool-el.x-tool-collapse-right, +.x-tool-img.x-tool-collapse-right, +.x-tool-tool-el.x-tool-collapse-left, +.x-tool-img.x-tool-collapse-left, +.x-tool-tool-el.x-tool-expand-right, +.x-tool-img.x-tool-expand-right, +.x-tool-tool-el.x-tool-expand-left, +.x-tool-img.x-tool-expand-left, +.x-tool-tool-el.x-tool-maximize, +.x-tool-img.x-tool-maximize, +.x-tool-tool-el.x-tool-restore, +.x-tool-img.x-tool-restore, +.x-tool-tool-el.x-tool-gear, +.x-tool-img.x-tool-gear, +.x-tool-tool-el.x-tool-refresh, +.x-tool-img.x-tool-refresh, +.x-tool-tool-el.x-tool-close, +.x-tool-img.x-tool-close { + background-image: none !important; + font-family: "FontAwesome" !important; + font-size: 14px !important; + line-height: 16px !important; + text-align: center !important; + color: var(--pm-text-dim) !important; + transition: color 0.15s ease !important; + filter: none !important; + width: 16px !important; + height: 16px !important; + display: flex !important; + align-items: center !important; + justify-content: center !important; +} + +/* Close button - slightly larger */ +.x-tool-tool-el.x-tool-close, +.x-tool-img.x-tool-close { + font-size: 20px !important; +} + +/* Individual glyph assignments */ +.x-tool-tool-el.x-tool-minus::before, +.x-tool-img.x-tool-minus::before { + content: "\f010" !important; /* fa-search-minus (zoom out) */ +} + +.x-tool-tool-el.x-tool-collapse-right::before, +.x-tool-img.x-tool-collapse-right::before { + content: "\f054" !important; /* fa-chevron-right */ +} + +.x-tool-tool-el.x-tool-expand-left::before, +.x-tool-img.x-tool-expand-left::before { + content: "\f053" !important; /* fa-chevron-left */ +} + +.x-tool-tool-el.x-tool-collapse-left::before, +.x-tool-img.x-tool-collapse-left::before { + content: "\f053" !important; /* fa-chevron-left */ +} + +.x-tool-tool-el.x-tool-expand-right::before, +.x-tool-img.x-tool-expand-right::before { + content: "\f054" !important; /* fa-chevron-right */ +} + +.x-tool-tool-el.x-tool-maximize::before, +.x-tool-img.x-tool-maximize::before { + content: "\f065" !important; /* fa-expand */ +} + +.x-tool-tool-el.x-tool-restore::before, +.x-tool-img.x-tool-restore::before { + content: "\f066" !important; /* fa-compress */ +} + +.x-tool-tool-el.x-tool-gear::before, +.x-tool-img.x-tool-gear::before { + content: "\f013" !important; /* fa-cog */ +} + +.x-tool-tool-el.x-tool-refresh::before, +.x-tool-img.x-tool-refresh::before { + content: "\f021" !important; /* fa-refresh */ +} + +.x-tool-tool-el.x-tool-close::before, +.x-tool-img.x-tool-close::before { + content: "\f00d" !important; /* fa-times */ +} + +/* Hover state - all tool icons */ +.x-tool:hover .x-tool-tool-el.x-tool-minus, +.x-tool:hover .x-tool-img.x-tool-minus, +.x-tool:hover .x-tool-tool-el.x-tool-collapse-right, +.x-tool:hover .x-tool-img.x-tool-collapse-right, +.x-tool:hover .x-tool-tool-el.x-tool-collapse-left, +.x-tool:hover .x-tool-img.x-tool-collapse-left, +.x-tool:hover .x-tool-tool-el.x-tool-expand-right, +.x-tool:hover .x-tool-img.x-tool-expand-right, +.x-tool:hover .x-tool-tool-el.x-tool-expand-left, +.x-tool:hover .x-tool-img.x-tool-expand-left, +.x-tool:hover .x-tool-tool-el.x-tool-maximize, +.x-tool:hover .x-tool-img.x-tool-maximize, +.x-tool:hover .x-tool-tool-el.x-tool-restore, +.x-tool:hover .x-tool-img.x-tool-restore, +.x-tool:hover .x-tool-tool-el.x-tool-gear, +.x-tool:hover .x-tool-img.x-tool-gear, +.x-tool:hover .x-tool-tool-el.x-tool-refresh, +.x-tool:hover .x-tool-img.x-tool-refresh, +.x-tool:hover .x-tool-tool-el.x-tool-close, +.x-tool:hover .x-tool-img.x-tool-close { + color: var(--pm-text) !important; +} + +/* Disabled state */ +.x-tool-disabled .x-tool-tool-el, +.x-tool-disabled .x-tool-img { + opacity: 0.4 !important; + cursor: default !important; +} + +/* Inline FontAwesome tools (PVE-injected) */ +.x-tool-tool-el[style*="font-family:FontAwesome"], +.x-tool-tool-el[style*="font-family: FontAwesome"] { + color: var(--pm-text-dim) !important; + font-size: 14px !important; + line-height: 16px !important; + display: flex !important; + align-items: center !important; + justify-content: center !important; + width: 16px !important; + height: 16px !important; + transition: color 0.15s ease !important; + background-image: none !important; + background-color: transparent !important; +} + +.x-tool:not(.x-tool-disabled) .x-tool-tool-el[style*="font-family:FontAwesome"], +.x-tool:not(.x-tool-disabled) .x-tool-tool-el[style*="font-family: FontAwesome"] { + cursor: pointer !important; +} + +.x-tool.x-tool-disabled .x-tool-tool-el[style*="font-family:FontAwesome"], +.x-tool.x-tool-disabled .x-tool-tool-el[style*="font-family: FontAwesome"] { + cursor: default !important; + opacity: 0.4 !important; +} + +.x-tool .x-mask { + background-color: transparent !important; + backdrop-filter: none !important; + pointer-events: none !important; +} + +.x-tool:not(.x-tool-disabled):hover .x-tool-tool-el[style*="font-family:FontAwesome"], +.x-tool:not(.x-tool-disabled):hover .x-tool-tool-el[style*="font-family: FontAwesome"] { + color: var(--pm-text) !important; +} diff --git a/themes/theme-dracula-green.css b/themes/theme-dracula-green.css new file mode 100644 index 0000000..3356a96 --- /dev/null +++ b/themes/theme-dracula-green.css @@ -0,0 +1,2378 @@ +/*!Dracula Green*/ +/* + * ProxMorph Theme: Dracula Green + * The canonical dark theme with Green accent and forest-tinted backgrounds — ported from the Dracula specification + * Version: 1.0.0 + * Author: ProxMorph / Dracula Theme (https://draculatheme.com) + * + * v1.0.0: Initial release — Tier 2 baseline with all fixes + * - Full Dracula palette with derived shades + * - All component sections ported from UniFi/Catppuccin reference + * - Console/Terminal, Charts, Progress bars, Buttons (28px), + * Dialog fixes, Tree cursor:pointer, APT repos, Tag checkmark + * + * ─── Dracula Specification Palette ───────────────────────────── + * Background: #1c2820 Current Line: #34413e + * Foreground: #f8f8f2 Comment: #6272a4 + * Cyan: #8be9fd Green: #50fa7b + * Orange: #ffb86c Pink: #ff79c6 + * Purple: #bd93f9 Red: #ff5555 + * Yellow: #f1fa8c + * + * ─── Derived Shades (ProxMorph) ──────────────────────────────── + * Crust: #141c17 Mantle: #182119 + * Surface 0: #273330 Surface 1: #34413e (= Current Line) + * Surface 2: #42524e Overlay 0: #6272a4 (= Comment) + * Overlay 1: #7c83a0 Overlay 2: #9298b8 + * Subtext 0: #b0b5c8 Subtext 1: #d0d4e0 + * Text: #f8f8f2 On-Accent: #1c2820 + */ + +/* ===================================================== + CSS VARIABLES + ===================================================== */ +:root { + /* Dracula Specification Tokens */ + --drac-bg: #1c2820; + --drac-current-line: #34413e; + --drac-fg: #f8f8f2; + --drac-comment: #6272a4; + --drac-cyan: #8be9fd; + --drac-green: #50fa7b; + --drac-orange: #ffb86c; + --drac-pink: #ff79c6; + --drac-purple: #bd93f9; + --drac-red: #ff5555; + --drac-yellow: #f1fa8c; + + /* Derived Neutral Scale */ + --drac-text: #f8f8f2; + --drac-subtext1: #d0d4e0; + --drac-subtext0: #b0b5c8; + --drac-overlay2: #9298b8; + --drac-overlay1: #7c83a0; + --drac-overlay0: #6272a4; + --drac-surface2: #42524e; + --drac-surface1: #34413e; + --drac-surface0: #273330; + --drac-base: #1c2820; + --drac-mantle: #182119; + --drac-crust: #141c17; + + /* ProxMorph Semantic Variables */ + --pm-accent: var(--drac-green); + --pm-bg-base: var(--drac-base); + --pm-bg-surface: var(--drac-surface0); + --pm-bg-elevated: var(--drac-surface1); + --pm-text: var(--drac-text); + --pm-text-dim: var(--drac-subtext1); + --pm-success: var(--drac-green); + --pm-warning: var(--drac-yellow); + --pm-error: var(--drac-red); + --pm-border: var(--drac-surface1); + --pm-radius-sm: 4px; + --pm-radius-md: 6px; + --pm-radius-lg: 8px; + + /* Proxmox Widget Toolkit Mappings (REQUIRED) */ + --pwt-panel-background: var(--drac-base); + --pwt-text-color: var(--drac-text); + --pwt-gauge-default: var(--drac-green); + --pwt-gauge-back: var(--drac-surface1); + --pwt-gauge-warn: var(--drac-yellow); + --pwt-gauge-crit: var(--drac-red); + --pwt-chart-primary: var(--drac-green); + --pwt-chart-grid-stroke: var(--drac-surface1); + + /* On Accent text — Background on colored backgrounds for contrast */ + --drac-on-accent: var(--drac-bg); + + /* Hover overlay — Comment@12% */ + --drac-hover-overlay: rgba(98, 114, 164, 0.12); + /* Selection overlay — Comment@25% */ + --drac-select-overlay: rgba(98, 114, 164, 0.25); + /* Accent muted (for focus rings) */ + --drac-accent-muted: rgba(80, 250, 123, 0.4); + --drac-accent-subtle: rgba(80, 250, 123, 0.15); + + color-scheme: dark; +} + +/* ===================================================== + GLOBAL BORDER-RADIUS ARCHITECTURE + (Ported from UniFi theme — reset everything, selectively re-apply) + ===================================================== */ +.x-border-box, +.x-border-box * { + border-radius: var(--pm-radius-lg); +} + +/* Remove rounded corners from grids/tables/lists */ +.x-grid, +.x-grid *, +.x-grid-header-ct, +.x-grid-header-ct *, +.x-grid-view, +.x-grid-view *, +.x-column-header, +.x-column-header *, +.x-grid-item, +.x-grid-cell, +.x-grid-cell-inner, +.x-grid-row, +table, +table *, +tr, +td, +th, +.x-legend, +.x-legend *, +.x-legend-container, +.x-legend-container *, +.x-legend-item, +.x-legend-horizontal .x-legend-item, +.x-legend-vertical .x-legend-item, +.x-legend-horizontal .x-legend-item:first-child, +.x-legend-horizontal .x-legend-item:last-child, +.x-legend-vertical .x-legend-item:first-child, +.x-legend-vertical .x-legend-item:last-child, +.x-tool, +.x-tool-tool-el, +.x-tool-default, +.x-tool-img { + border-radius: 0 !important; +} + +/* Form elements - exclude from global radius */ +.x-form-item, +.x-form-item-default, +.x-form-item-body, +.x-form-item-body-default, +.x-form-text-field-body, +.x-form-text-field-body-default, +.x-form-fieldcontainer, +.x-field, +.x-field-default, +.x-form-type-text { + border-radius: 0 !important; +} + +/* Reset layout containers that clip elements with overflow:hidden + radius */ +.x-box-layout-ct, +.x-panel-bodyWrap, +.x-panel-bodyWrap-default, +.x-autocontainer-innerCt, +.x-autocontainer-outerCt, +.x-panel.x-tabpanel-child, +.x-panel.x-box-item, +.x-box-inner, +.x-box-target, +.x-container, +.x-container-default, +.x-window .x-panel-body, +.x-window .x-window-body, +.x-window .x-window-bodyWrap { + border-radius: 0 !important; +} + +/* Reset everything inside windows to 0 — then re-apply specific radii */ +.x-window *, +.x-window .x-autocontainer-innerCt, +.x-window .x-autocontainer-outerCt, +.x-window .x-form-layout-wrap, +.x-window .x-form-layout-auto-label, +.x-window .x-form-layout-colgroup, +.x-window .x-form-layout-column, +.x-window .x-field, +.x-window .x-form-item, +.x-window .x-form-item-body { + border-radius: 0 !important; +} + +/* Chart canvas — no radius on data area */ +.x-chart-grid, +.x-chart-axis, +canvas.x-surface, +.x-chart canvas, +canvas.x-surface-canvas, +.x-surface-canvas, +.x-draw-component canvas, +.proxmox-rrd-chart canvas, +svg.x-surface, +.x-draw-container, +.x-surface { + border-radius: 0 !important; +} + +/* Legend color marker (dot) — keep circular */ +.x-legend-item-marker { + border-radius: 50% !important; +} + +/* ===================================================== + RE-APPLY BORDER RADII (selective) + ===================================================== */ + +/* Windows */ +.x-window, +.x-window-default { + border-radius: var(--pm-radius-lg) !important; +} + +.x-window-header, +.x-window-header-default { + border-radius: var(--pm-radius-lg) var(--pm-radius-lg) 0 0 !important; +} + +.x-window .x-window-body, +.x-window-body-default { + border-radius: 0 !important; +} + +/* Buttons inside windows */ +.x-window .x-btn { + border-radius: var(--pm-radius-md) !important; +} + +/* Checkboxes inside windows */ +.x-window .x-form-checkbox { + border-radius: 3px !important; +} + +/* Form inputs inside windows */ +.x-window .x-form-trigger-wrap, +.x-window .x-form-trigger-wrap-default { + border-radius: var(--pm-radius-sm) !important; +} + +.x-window .x-form-text-wrap, +.x-window .x-form-text { + border-radius: var(--pm-radius-sm) 0 0 var(--pm-radius-sm) !important; +} + +.x-window .x-form-arrow-trigger { + border-radius: 0 var(--pm-radius-sm) var(--pm-radius-sm) 0 !important; +} + +/* Form trigger/text wrap — reset and re-apply */ +.x-form-trigger-wrap, +.x-form-trigger-wrap *, +.x-form-text-wrap, +.x-form-text-wrap *, +.x-form-text, +.x-form-trigger { + border-radius: 0 !important; +} + +.x-form-trigger-wrap, +.x-form-trigger-wrap-default { + border-radius: var(--pm-radius-sm) !important; + overflow: hidden !important; +} + +.x-form-text-wrap, +.x-form-text-wrap-default { + border-radius: var(--pm-radius-sm) 0 0 var(--pm-radius-sm) !important; +} + +.x-form-text, +.x-form-text-default { + border-radius: var(--pm-radius-sm) 0 0 var(--pm-radius-sm) !important; +} + +.x-form-trigger, +.x-form-trigger-default, +.x-form-arrow-trigger, +.x-form-arrow-trigger-default { + border-radius: 0 var(--pm-radius-sm) var(--pm-radius-sm) 0 !important; +} + +/* Dialog form content padding — vertical only (horizontal causes ExtJS overflow) */ +.x-window .x-tabpanel-child .x-autocontainer-innerCt { + padding: 12px 0 !important; +} + +/* Allow column panel bodies to show overflowed form content */ +.x-window .x-panel-body:not(.x-scroller) { + overflow: visible !important; +} + +/* Side padding on column panel bodies inside windows */ +.x-window .x-panel.x-box-item .x-panel-body { + padding: 0 4px !important; +} + +/* Constrain autocontainer width inside windows */ +.x-window .x-autocontainer-outerCt { + max-width: 100% !important; +} + +/* Fix window header/body width consistency */ +.x-window > .x-window-header, +.x-window > .x-window-body, +.x-window > .x-window-bodyWrap, +.x-window-bodyWrap > .x-window-body { + width: 100% !important; +} + +.x-window-header > .x-box-inner, +.x-window-header > .x-box-inner > .x-box-target { + width: 100% !important; +} + +.x-window-header-title { + width: auto !important; + flex: 1 !important; + max-width: calc(100% - 30px) !important; +} + +/* Boundlists */ +.x-boundlist { + border-radius: var(--pm-radius-md) !important; + overflow: hidden !important; +} + +/* ===================================================== + BASE / BODY + ===================================================== */ +.x-body, +.x-viewport > .x-body, +body.x-border-layout-ct, +div.x-border-layout-ct { + background-color: var(--drac-base) !important; + color: var(--drac-text) !important; +} + +/* ===================================================== + MASKS & OVERLAYS + ===================================================== */ +.x-mask { + background-color: rgba(30, 31, 41, 0.6) !important; + backdrop-filter: blur(4px); +} + +.x-mask-msg { + background-color: var(--drac-mantle) !important; + border: 1px solid var(--drac-surface1) !important; + border-radius: var(--pm-radius-lg) !important; +} + +.x-mask-msg-text { + color: var(--drac-subtext0) !important; + filter: none !important; +} + +.x-css-shadow { + box-shadow: 0 8px 24px rgba(30, 31, 41, 0.6) !important; +} + +/* Loading indicators */ +.x-grid-row-loading, +.x-treelist-item-loading .x-treelist-item-icon, +.x-grid-tree-loading .x-tree-icon { + filter: invert(90%); +} + +/* ===================================================== + ICONS — Proxmox default colors for dark mode + ===================================================== */ + +/* General icon colors — neutral gray for dark backgrounds */ +.x-tree-icon-custom, +.x-grid-icon-custom, +.fa-tags::before, +.fa-file-o::before, +.fa-building::before, +.x-action-col-icon::before, +.fa-shield::before, +.fa-file-text-o::before, +.fa-clock-o::before, +.x-tab-icon-el-default, +.pve-icon-verify-lettering::after, +.x-tree-icon-leaf:not(.x-tree-icon-custom)::before, +.x-tree-icon-parent:not(.x-tree-icon-custom)::before, +.x-tree-icon-parent-expanded:not(.x-tree-icon-custom)::before, +.x-grid-filters-filtered-column .x-column-header-text::after { + color: var(--drac-overlay2) !important; +} + +/* Folder icons — invert for dark mode */ +.x-tree-icon-parent:not(.x-tree-icon-custom)::before, +.x-tree-icon-parent-expanded:not(.x-tree-icon-custom)::before { + filter: invert(90%); +} + +/* Various image-based icons — invert for visibility */ +.fa-ceph::before, +.fa-sdn::before, +.fa-network-wired::before, +.pve-itype-treelist-item-icon-cdrom, +.fa-chevron-right::before, +.x-grid-row-console, +.x-box-scroller-toolbar-default.x-box-scroller, +.x-tree-elbow-img, +.pve-itype-icon-qemu, +.x-tree-node-computer, +.x-grid-tree-node-expanded .x-tree-node-computer, +.pbs-icon-tape, +.pbs-icon-tape-drive, +.x-tree-icon-leaf:not(.x-tree-icon-custom), +.x-tree-icon-parent:not(.x-tree-icon-custom), +.x-tree-icon-parent-expanded:not(.x-tree-icon-custom) { + filter: invert(90%); +} + +/* Hardware icons */ +.pve-itype-icon-cpu, +.pve-itype-icon-cdrom, +.pve-itype-icon-memory, +.pve-itype-icon-pci, +.pve-itype-icon-serial, +.pve-itype-icon-die, +.pmx-itype-icon-processor, +.pmx-itype-icon-memory, +.pve-itype-icon-storage, +.x-tree-node-harddisk, +.x-grid-tree-node-expanded .x-tree-node-harddisk { + filter: invert(100%); +} + +/* Hardware icons — counter-invert for non-SVG icon cells */ +td.pve-itype-icon-storage .x-grid-cell-inner, +td.x-tree-node-harddisk .x-grid-cell-inner { + filter: invert(100%) !important; +} + +/* Hardware icons — hide inverted borders for non-SVG icon cells */ +td.pve-itype-icon-storage, +td.x-tree-node-harddisk { + border-color: transparent !important; +} + +/* Hardware grid icons — mask-image renders SVG icons in theme text color + Replaces filter:invert approach for pve-itype-icon-* and pmx-itype-icon-* grid cells */ +td.pve-itype-icon-cpu, +td.pve-itype-icon-cdrom, +td.pve-itype-icon-memory, +td.pve-itype-icon-pci, +td.pve-itype-icon-serial, +td.pve-itype-icon-die, +td.pmx-itype-icon-processor, +td.pmx-itype-icon-memory { + filter: none !important; + background-image: none !important; + padding-left: 0 !important; + border-color: transparent !important; +} + +td.pve-itype-icon-cpu .x-grid-cell-inner, +td.pve-itype-icon-cdrom .x-grid-cell-inner, +td.pve-itype-icon-memory .x-grid-cell-inner, +td.pve-itype-icon-pci .x-grid-cell-inner, +td.pve-itype-icon-serial .x-grid-cell-inner, +td.pve-itype-icon-die .x-grid-cell-inner, +td.pmx-itype-icon-processor .x-grid-cell-inner, +td.pmx-itype-icon-memory .x-grid-cell-inner { + padding-left: 3px !important; +} + +td.pve-itype-icon-cpu .x-grid-cell-inner::before, +td.pve-itype-icon-cdrom .x-grid-cell-inner::before, +td.pve-itype-icon-memory .x-grid-cell-inner::before, +td.pve-itype-icon-pci .x-grid-cell-inner::before, +td.pve-itype-icon-serial .x-grid-cell-inner::before, +td.pve-itype-icon-die .x-grid-cell-inner::before, +td.pmx-itype-icon-processor .x-grid-cell-inner::before, +td.pmx-itype-icon-memory .x-grid-cell-inner::before { + content: '' !important; + display: inline-block !important; + width: 18px !important; + height: 14px !important; + vertical-align: middle !important; + margin-right: 10px !important; + background-color: currentColor !important; + -webkit-mask-size: contain !important; + mask-size: contain !important; + -webkit-mask-repeat: no-repeat !important; + mask-repeat: no-repeat !important; + -webkit-mask-position: center !important; + mask-position: center !important; +} + +td.pve-itype-icon-cpu .x-grid-cell-inner::before { + -webkit-mask-image: url('/pve2/images/icon-cpu.svg') !important; + mask-image: url('/pve2/images/icon-cpu.svg') !important; +} + +td.pve-itype-icon-memory .x-grid-cell-inner::before { + -webkit-mask-image: url('/pve2/images/icon-memory.svg') !important; + mask-image: url('/pve2/images/icon-memory.svg') !important; +} + +td.pve-itype-icon-cdrom .x-grid-cell-inner::before { + -webkit-mask-image: url('/pve2/images/icon-cd-drive.svg') !important; + mask-image: url('/pve2/images/icon-cd-drive.svg') !important; +} + +td.pve-itype-icon-pci .x-grid-cell-inner::before { + -webkit-mask-image: url('/pve2/images/icon-pci.svg') !important; + mask-image: url('/pve2/images/icon-pci.svg') !important; +} + +td.pve-itype-icon-serial .x-grid-cell-inner::before { + -webkit-mask-image: url('/pve2/images/icon-serial.svg') !important; + mask-image: url('/pve2/images/icon-serial.svg') !important; +} + +td.pve-itype-icon-die .x-grid-cell-inner::before { + -webkit-mask-image: url('/pve2/images/icon-die.svg') !important; + mask-image: url('/pve2/images/icon-die.svg') !important; +} + +td.pmx-itype-icon-processor .x-grid-cell-inner::before { + -webkit-mask-image: url('../images/icon-cpu.svg') !important; + mask-image: url('../images/icon-cpu.svg') !important; +} + +td.pmx-itype-icon-memory .x-grid-cell-inner::before { + -webkit-mask-image: url('../images/icon-ram.svg') !important; + mask-image: url('../images/icon-ram.svg') !important; +} + + +/* Icon overlays — default */ +.x-tree-icon-custom::after, +.x-grid-icon-custom::after { + color: var(--drac-overlay2) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* RUNNING VMs/CTs — Dracula Green */ +.x-tree-icon-custom.running::after, +.x-grid-icon-custom.running::after, +.x-treelist-item-icon.running::after { + color: var(--drac-green) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* ONLINE state — Green */ +.x-tree-icon-custom.online::after, +.x-grid-icon-custom.online::after { + color: var(--drac-green) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* Stopped/offline — Overlay1 (muted gray) */ +.x-tree-icon-custom.stopped, +.x-tree-icon-custom.offline, +.x-grid-icon-custom.stopped, +.x-grid-icon-custom.offline { + color: var(--drac-overlay1) !important; +} + +/* Unknown state — Overlay1 */ +.x-tree-icon-custom.unknown::after, +.x-grid-icon-custom.unknown::after { + color: var(--drac-overlay1) !important; +} + +/* ERROR states — Dracula Red */ +.x-tree-icon-custom.error::after, +.x-tree-icon-custom.offline::after, +.x-tree-icon-custom.ha-error::after, +.x-grid-icon-custom.error::after, +.x-grid-icon-custom.offline::after, +.x-grid-icon-custom.ha-error::after { + color: var(--drac-red) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* PAUSED/SUSPENDED — Dracula Orange */ +.x-tree-icon-custom.paused::after, +.x-tree-icon-custom.suspended::after, +.x-tree-icon-custom.lock-suspending::after, +.x-grid-icon-custom.paused::after, +.x-grid-icon-custom.suspended::after, +.x-grid-icon-custom.lock-suspending::after { + color: var(--drac-orange) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* PENDING/WARNING states — Dracula Yellow */ +.x-tree-icon-custom.pending::after, +.x-tree-icon-custom.io-error::after, +.x-tree-icon-custom.internal-error::after, +.x-tree-icon-custom.guest-panicked::after, +.x-grid-icon-custom.pending::after, +.x-grid-icon-custom.io-error::after, +.x-grid-icon-custom.internal-error::after, +.x-grid-icon-custom.guest-panicked::after { + color: var(--drac-yellow) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* HA MAINTENANCE — Dracula Cyan */ +.x-tree-icon-custom.ha-maintenance::after, +.x-grid-icon-custom.ha-maintenance::after { + color: var(--drac-cyan) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* Locked icons */ +.x-tree-icon-custom.locked::after, +.x-tree-icon-custom.lock-backup::after, +.x-tree-icon-custom.lock-migrate::after, +.x-tree-icon-custom.lock-suspended::after, +.x-grid-icon-custom.locked::after, +.x-grid-icon-custom.lock-backup::after, +.x-grid-icon-custom.lock-migrate::after, +.x-grid-icon-custom.lock-suspended::after { + color: var(--drac-overlay2) !important; +} + +/* LXC/QEMU type indicators */ +.x-tree-icon-custom.lxc::after, +.x-tree-icon-custom.qemu::after, +.x-grid-icon-custom.lxc::after, +.x-grid-icon-custom.qemu::after { + background-color: transparent; + color: var(--drac-overlay1) !important; +} + +.x-treelist-item-icon.lxc::after, +.x-treelist-item-icon.qemu::after { + background-color: transparent; + color: var(--drac-overlay1) !important; +} + +/* Tree expander arrows */ +.x-tree-arrows .x-tree-expander { + filter: brightness(200%); +} + +/* Cancel sprite-inversion on custom controls (checkboxes/radios handled via CSS) */ +.x-form-checkbox-default, +.x-form-radio-default, +.x-column-header-checkbox .x-column-header-checkbox::after, +.x-grid-checkcolumn::after, +.x-menu-item-checked .x-menu-item-icon-default.x-menu-item-checkbox, +.x-menu-item-unchecked .x-menu-item-icon-default.x-menu-item-checkbox { + filter: none !important; +} + +/* ===================================================== + PANELS & HEADERS + ===================================================== */ +.x-panel, +.x-panel-default { + border-radius: var(--pm-radius-lg) !important; + padding: 0 !important; +} + +/* Column panels — native stacked layout (Issue #23 fix) */ +.x-panel.x-column { + padding: 5px !important; + margin: 0 !important; + max-width: none !important; + box-sizing: border-box !important; +} + +/* Column panel card styling — borders for summary + chart panels */ +.x-panel.x-panel-default.x-column { + border: 1px solid var(--drac-surface1) !important; + border-radius: var(--pm-radius-lg) !important; + overflow: hidden !important; +} + +/* Guest status + Notes panel borders */ +[id^="pveGuestStatusView-"].x-panel, +[id^="pveLxcStatusView-"].x-panel, +[id^="pveQemuStatusView-"].x-panel, +[id^="pmxNotesView-"].x-panel { + border: 1px solid var(--drac-surface1) !important; + border-radius: var(--pm-radius-lg) !important; +} + +.x-panel-body, +.x-panel-body-default { + background-color: var(--drac-base) !important; + color: var(--drac-text) !important; + border: none !important; +} + +/* Panel headers — bottom border only */ +.x-panel-header, +.x-panel-header-default { + background-color: var(--drac-mantle) !important; + border: none !important; + border-bottom: 1px solid var(--drac-surface1) !important; + border-radius: var(--pm-radius-lg) var(--pm-radius-lg) 0 0 !important; + margin: 0 !important; + padding: 8px 12px !important; + width: 100% !important; + box-sizing: border-box !important; + overflow: visible !important; +} + +/* Title text — prevent border-radius clipping */ +.x-title-text, +.x-title-text-default { + overflow: visible !important; +} + +.x-panel-bodyWrap, +.x-panel-bodyWrap-default { + margin: 0 !important; + padding: 0 !important; + overflow: visible !important; +} + +/* Remove borders from nested panels */ +.x-panel-body > .x-box-layout-ct, +.x-panel-body > .x-container, +.x-panel-body > .x-box-inner, +[id*="pmxGauge"] { + border: none !important; +} + +.x-panel-header-title-default, +.x-window-header-title-default { + color: var(--drac-text) !important; +} + +.x-panel-header-default .x-tool-tool-el { + background-color: transparent; +} + +.x-tool-img { + filter: brightness(175%); +} + +.x-tool-over .x-tool-img { + filter: brightness(200%); +} + +/* Resource tree — panel body border */ +div[id^="pveResourceTree-"][id$="-body"] { + border-color: var(--drac-base) !important; +} + +/* Resource tree — remove row separators */ +[id^="pveResourceTree-"].x-tree-panel td.x-grid-cell, +[id^="pveResourceTree-"].x-tree-panel .x-grid-td, +[id^="pveResourceTree-"].x-tree-panel .x-grid-cell { + border-bottom: none !important; +} + +/* Resource tree — row spacing */ +div[id^="pveResourceTree"] .x-grid-cell { + padding-top: 3px !important; + padding-bottom: 3px !important; +} + +/* Summary/stats panel radius overrides */ +.pveStatusPanel, +.x-panel-default-framed, +.x-panel-body-default-framed { + border-radius: 12px !important; +} + +.x-panel-header-default-framed { + border-radius: 12px 12px 0 0 !important; +} + +/* Column widget panel radius */ +.x-panel.x-column > .x-panel-bodyWrap > .x-panel-body.x-panel-body-default { + border-radius: var(--pm-radius-lg) !important; +} + +/* ===================================================== + SPLITTERS / SEPARATORS + ===================================================== */ +.x-splitter-vertical { + background-color: transparent !important; + border-left: 1px solid var(--drac-surface1) !important; + border-right: none !important; + width: 1px !important; +} + +.x-splitter-horizontal { + background-color: var(--drac-crust) !important; + border-top: 1px solid var(--drac-surface1) !important; +} + +.x-splitter { + background-color: var(--drac-crust) !important; +} + +.x-keyboard-mode .x-splitter-focus::after { + border-color: var(--drac-green) !important; +} + +.x-layout-split-bottom { + opacity: 0.7; +} + +/* Toolbox tree (pve-nav) right border — full height */ +.pve-toolbar-bg { + border-right: 1px solid var(--drac-surface1) !important; + z-index: 3 !important; +} + +.x-treelist.x-treelist-pve-nav { + border-right: none !important; +} + +/* ===================================================== + TOOLBARS + ===================================================== */ +.x-toolbar, +.x-toolbar-default { + background-color: var(--drac-base) !important; + border-color: var(--drac-surface1) !important; +} + +.x-toolbar-default.x-docked-top { + border: none !important; + border-bottom: 1px solid var(--drac-surface1) !important; +} + +.x-toolbar-default .x-toolbar-separator { + border-color: var(--drac-surface1); +} + +.x-toolbar-text-default { + color: var(--drac-subtext0); +} + +/* ===================================================== + PRIMARY BUTTONS — Dracula Purple + ===================================================== */ +.x-btn-default-small { + background-color: var(--drac-green) !important; + border: 1px solid rgba(80, 250, 123, 0.4) !important; + border-radius: var(--pm-radius-md) !important; + transition: background-color 0.15s ease, box-shadow 0.15s ease !important; +} + +.x-btn-default-small .x-btn-inner { + color: var(--drac-on-accent) !important; + font-weight: 600 !important; +} + +.x-btn-default-small .x-btn-icon-el { + color: var(--drac-on-accent) !important; +} + +.x-btn-default-small.x-btn-over, +.x-keyboard-mode .x-btn-default-small.x-btn-focus { + background-color: #6afb90 !important; + box-shadow: 0 0 0 3px var(--drac-accent-subtle) !important; +} + +.x-btn-default-small.x-btn.x-btn-disabled { + background-color: var(--drac-green) !important; + opacity: 0.4; +} + +.x-btn-default-small.x-btn.x-btn-pressed { + background-color: #40e069 !important; +} + +/* Button height consistency — 28px with vertical centering */ +/* Exclude tag edit buttons (display:none when hidden, :has(.fa-check) for checkmark) */ +.x-btn.x-btn-default-small:not(.x-btn-default-toolbar-small):not([style*="display: none"]):not([style*="display:none"]):not(:has(.fa-check)) { + height: 28px !important; + min-height: 28px !important; + display: flex !important; + align-items: center !important; + padding: 3px 8px !important; +} + +/* Fix button inner element centering for proper icon alignment (issue #17) */ +.x-btn.x-btn-default-small:not(.x-btn-default-toolbar-small):not([style*="display: none"]):not([style*="display:none"]):not(:has(.fa-check)) .x-btn-wrap { + display: flex !important; + align-items: center !important; +} + +.x-btn.x-btn-default-small:not(.x-btn-default-toolbar-small):not([style*="display: none"]):not([style*="display:none"]):not(:has(.fa-check)) .x-btn-inner { + display: flex !important; + align-items: center !important; +} + +/* Fix dropdown arrows on split/arrow buttons */ +.x-btn-wrap.x-btn-arrow-right::after, +.x-btn-wrap.x-btn-split-right::after { + height: 16px !important; + min-height: 16px !important; + width: 20px !important; + display: flex !important; + align-items: center !important; +} + +/* Fix icon-only buttons — hide   inner element when button has no text */ +.x-btn-no-text .x-btn-inner, +.x-btn-button.x-btn-no-text .x-btn-inner, +.x-btn-button-default-toolbar-small.x-btn-no-text .x-btn-inner-default-toolbar-small, +.x-btn-button-default-small.x-btn-no-text .x-btn-inner-default-small, +.x-btn-button-default-small.x-btn-no-text > .x-btn-inner-default-small { + display: none !important; +} + +/* Specific fix for fa-desktop icon (Create VM) — visually bottom-heavy */ +.x-btn-icon-el.fa-desktop { + transform: translateY(1.1px) !important; +} + +/* ===================================================== + SECONDARY / TOOLBAR BUTTONS + ===================================================== */ +.x-btn-default-toolbar-small { + background-color: var(--drac-surface0) !important; + border: 1px solid var(--drac-surface1) !important; + border-radius: var(--pm-radius-md) !important; + transition: background-color 0.15s ease, border-color 0.15s ease !important; +} + +.x-btn-default-toolbar-small .x-btn-inner-default-toolbar-small, +.x-btn-default-toolbar-small .x-btn-icon-el-default-toolbar-small { + color: var(--drac-text) !important; +} + +.x-btn-default-toolbar-small .x-btn-wrap-default-toolbar-small.x-btn-arrow-right::after, +.x-btn-default-toolbar-small .x-btn-wrap-default-toolbar-small.x-btn-split-right::after { + filter: brightness(150%); +} + +.x-btn-default-toolbar-small.x-btn-over, +.x-keyboard-mode .x-btn-default-toolbar-small.x-btn-focus { + background-color: var(--drac-surface1) !important; + border-color: var(--drac-surface2) !important; +} + +.x-btn-default-toolbar-small.x-btn.x-btn-disabled { + background-color: var(--drac-surface0) !important; + opacity: 0.4; +} + +.x-btn-default-toolbar-small.x-btn.x-btn-menu-active, +.x-btn-default-toolbar-small.x-btn.x-btn-pressed { + background-color: var(--drac-green) !important; + border-color: var(--drac-green) !important; + padding: 4px 8px !important; /* Fix #30: prevent width change on dropdown */ +} + +.x-btn-default-toolbar-small.x-btn.x-btn-pressed .x-btn-inner-default-toolbar-small, +.x-btn-default-toolbar-small.x-btn.x-btn-pressed .x-btn-icon-el-default-toolbar-small, +.x-btn-default-toolbar-small.x-btn.x-btn-pressed .x-btn-inner-default-small, +.x-btn-default-toolbar-small.x-btn.x-btn-pressed .x-btn-icon-el-default-small { + color: var(--drac-on-accent) !important; +} + +/* Segmented buttons */ +.x-segmented-button { + border-radius: var(--pm-radius-md) !important; +} + +.x-segmented-button .x-btn, +.x-segmented-button .x-btn-default-small, +.x-segmented-button .x-btn-inner, +.x-segmented-button .x-btn-wrap { + border-radius: var(--pm-radius-md) !important; +} + +/* Inline buttons (Documentation, Help) */ +.proxmox-inline-button { + height: 28px !important; + min-height: 28px !important; + display: flex !important; + align-items: center !important; + padding: 3px 8px !important; + background-color: var(--drac-surface0) !important; + border: 1px solid var(--drac-surface1) !important; + border-radius: var(--pm-radius-md) !important; + color: var(--drac-text) !important; + transition: background-color 0.15s ease !important; +} + +.proxmox-inline-button:hover, +.proxmox-inline-button.x-btn-over { + background-color: var(--drac-surface1) !important; + border-color: var(--drac-overlay0) !important; +} + +.proxmox-inline-button:active, +.proxmox-inline-button.x-btn-pressed { + background-color: var(--drac-surface2) !important; +} + +.proxmox-inline-button .x-btn-inner, +.proxmox-inline-button .x-btn-icon-el { + color: var(--drac-text) !important; +} + +/* Pressed/active inline buttons — use on-accent text */ +.proxmox-inline-button.x-btn-pressed .x-btn-inner, +.proxmox-inline-button.x-btn-pressed .x-btn-icon-el, +.proxmox-inline-button.x-btn-menu-active .x-btn-inner, +.proxmox-inline-button.x-btn-menu-active .x-btn-icon-el { + color: var(--drac-on-accent) !important; +} + +/* ===================================================== + FORM ELEMENTS + ===================================================== */ +.x-form-trigger-default { + background-color: var(--drac-surface0) !important; +} + +.x-form-text-default { + background-color: var(--drac-surface0) !important; + color: var(--drac-text) !important; + border-radius: var(--pm-radius-sm) !important; +} + +.x-form-trigger-wrap, +.x-form-trigger-wrap-default { + border-color: var(--drac-surface1) !important; + background-color: var(--drac-surface0) !important; + border-radius: var(--pm-radius-sm) !important; + transition: border-color 0.15s ease !important; +} + +.x-form-trigger-wrap-default.x-form-trigger-wrap-focus { + border-color: var(--drac-green) !important; + box-shadow: 0 0 0 3px var(--drac-accent-subtle) !important; +} + +.x-form-item-label-default, +.x-form-cb-label-default { + color: var(--drac-text) !important; +} + +.x-form-display-field-default { + color: var(--drac-subtext0) !important; + border-radius: var(--pm-radius-md) !important; +} + +.x-form-spinner-default { + background-color: var(--drac-surface0) !important; +} + +.x-fieldset, +.x-fieldset-default { + border-color: var(--drac-surface1) !important; + border-radius: var(--pm-radius-lg) !important; +} + +.x-fieldset-header-default > .x-fieldset-header-text { + color: var(--drac-text) !important; +} + +/* ===================================================== + CHECKBOXES & RADIOS — Dracula styled + ===================================================== */ + +/* Base: remove sprite, styled as custom control */ +.x-form-checkbox, .x-form-checkbox-default, +.x-form-radio, .x-form-radio-default { + background-image: none !important; + background-color: var(--drac-surface0) !important; + border: 1.5px solid var(--drac-overlay0) !important; + width: 16px !important; + height: 16px !important; + display: inline-block !important; + box-sizing: border-box !important; + cursor: pointer !important; + transition: border-color 0.12s ease, background-color 0.12s ease !important; +} + +/* Checkbox: rounded square */ +.x-form-checkbox, .x-form-checkbox-default { + border-radius: 3px !important; +} + +/* Radio: circle + ::after inner dot */ +.x-form-radio, .x-form-radio-default { + border-radius: 50% !important; + position: relative !important; + transform: translateZ(0) !important; + box-shadow: inset 0 0 0 0 transparent !important; +} + +.x-form-radio::after { + content: '' !important; + position: absolute !important; + top: 50% !important; + left: 50% !important; + width: 7px !important; + height: 7px !important; + border-radius: 50% !important; + background: transparent !important; + transform: translate(-50%, -50%) scale(0) !important; + transition: transform 0.15s ease, background 0.15s ease !important; + pointer-events: none !important; +} + +/* Hover */ +.x-form-checkbox:hover, .x-form-checkbox-default:hover, +.x-form-cb-wrap:hover .x-form-checkbox { + border-color: var(--drac-green) !important; +} + +.x-form-radio:hover, .x-form-radio-default:hover, +.x-form-cb-wrap:hover .x-form-radio { + border-color: var(--drac-green) !important; +} + +/* CHECKED checkbox — Purple fill + dark SVG checkmark */ +.x-form-cb-checked .x-form-checkbox, +.x-form-cb-checked .x-form-checkbox-default { + background-color: var(--drac-green) !important; + border-color: var(--drac-green) !important; + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 8'%3E%3Cpath d='M1 4l3 3 5-6' fill='none' stroke='%231c2820' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") !important; + background-repeat: no-repeat !important; + background-position: center !important; + background-size: 9px 7px !important; +} + +/* SELECTED radio — Purple dot */ +.x-form-cb-checked .x-form-radio, +.x-form-cb-checked .x-form-radio-default { + border-color: var(--drac-green) !important; + background-color: var(--drac-base) !important; +} + +.x-form-cb-checked .x-form-radio::after { + background: var(--drac-green) !important; + transform: translate(-50%, -50%) scale(1) !important; +} + +/* ===================================================== + BOUNDLIST / DROPDOWNS + ===================================================== */ +.x-boundlist { + background-color: var(--drac-mantle) !important; + border: 1px solid var(--drac-surface1) !important; + border-radius: var(--pm-radius-md) !important; + box-shadow: 0 8px 24px rgba(30, 31, 41, 0.7) !important; + padding: 2px !important; + overflow: hidden !important; +} + +.x-boundlist-item { + background-color: transparent !important; + color: var(--drac-text) !important; + border-radius: var(--pm-radius-sm) !important; + padding: 2px 6px !important; + line-height: normal !important; + border: none !important; + cursor: pointer !important; + outline: none !important; + box-shadow: none !important; +} + +.x-boundlist-selected { + background-color: var(--drac-select-overlay) !important; + color: var(--drac-text) !important; +} + +.x-boundlist-item-over { + background-color: var(--drac-hover-overlay) !important; +} + +/* ===================================================== + GRIDS / TABLES + ===================================================== */ +.x-grid, +.x-grid-view { + border-radius: 0 !important; +} + +.x-column-header { + border-color: var(--drac-surface1) !important; + background-color: transparent !important; +} + +.x-column-header-inner, +.x-column-header-text { + color: var(--drac-text) !important; + font-weight: 600 !important; +} + +.x-column-header-trigger { + border-color: var(--drac-surface1) !important; +} + +.x-grid-item, +.x-column-header-default, +.x-grid-cell-row-numberer { + color: var(--drac-text) !important; + background-color: var(--drac-base) !important; +} + +.x-grid-cell-special { + border-color: var(--drac-surface1) !important; +} + +.x-grid-group-hd { + background-color: var(--drac-base) !important; + border-color: var(--drac-surface1) !important; +} + +.x-grid-group-title { + color: var(--drac-text) !important; +} + +.x-grid-header-ct { + background-color: var(--drac-mantle) !important; + border: 1px solid var(--drac-surface0) !important; + border-radius: var(--pm-radius-lg) var(--pm-radius-lg) 0 0 !important; +} + +.x-grid-item-alt { + background-color: var(--drac-crust) !important; +} + +.x-grid-with-row-lines .x-grid-item { + border-color: var(--drac-surface0) !important; +} + +.x-grid-cell { + border-bottom: 1px solid rgba(68, 71, 90, 0.4) !important; +} + +.x-grid-item-over, +.x-grid-with-row-lines .x-grid-item.x-grid-item-over { + background-color: var(--drac-hover-overlay) !important; +} + +.x-grid-item-selected, +.x-grid-with-row-lines .x-grid-item.x-grid-item-selected { + background-color: var(--drac-select-overlay) !important; +} + +.x-column-header-over, +.x-column-header-open { + background-color: var(--drac-hover-overlay) !important; +} + +.x-column-header-sort-ASC, +.x-column-header-sort-DESC { + background-color: var(--drac-hover-overlay) !important; +} + +.x-grid-row-summary .x-grid-cell, +.x-grid-row-summary .x-grid-rowwrap, +.x-grid-row-summary .x-grid-cell-rowbody { + background-color: var(--drac-base) !important; + border-color: var(--drac-surface1); +} + +.x-grid-with-col-lines .x-grid-cell, +.x-grid-with-col-lines .x-grid-item-over .x-grid-cell, +.x-grid-with-col-lines .x-grid-item-selected .x-grid-cell { + border-color: var(--drac-surface1) !important; +} + +.x-dd-drag-proxy { + background-color: var(--drac-mantle); + border-color: var(--drac-surface1); + color: var(--drac-text); +} + +.x-keyboard-mode .x-grid-item-focused { + background-color: var(--drac-hover-overlay) !important; + color: var(--drac-text) !important; +} + +/* Remove blue outline from focused/selected items in resource tree */ +.x-keyboard-mode .x-grid-item-focused .x-grid-cell-inner::before, +.x-keyboard-mode .x-grid-item-selected .x-grid-cell-inner::before, +.x-grid-item-selected .x-grid-cell-inner::before, +.x-grid-item-focused .x-grid-cell-inner::before, +[id^="pveResourceTree"] .x-grid-item-selected .x-grid-cell-inner::before, +[id^="pveResourceTree"] .x-grid-item-focused .x-grid-cell-inner::before { + content: none !important; + display: none !important; + border: none !important; +} + +.x-grid-empty { + background-color: var(--drac-base) !important; + color: var(--drac-subtext0) !important; +} + +/* Grid info (pve-info-grid) and RRD view */ +.pve-info-grid { + border-radius: 12px !important; +} + +.pve-rrdview, +.rrdview { + border-radius: 12px !important; +} + +.pve-summary-status, +.x-container .pve-status { + border-radius: var(--pm-radius-lg) !important; +} + +[id^="pveGuestStatusView-"][id$="-body"], +[id^="pmxNotesView-"] .x-panel-body { + border-radius: var(--pm-radius-lg) !important; +} + +.x-panel-default[id*="notes"], +.pve-notes-view { + border-radius: var(--pm-radius-lg) !important; +} + +/* Floating grid pickers (storage/ISO selectors) */ +.x-layer.x-grid .x-grid-view, +.x-panel.x-layer.x-grid .x-grid-view, +.x-panel.x-layer.x-grid, +.x-layer.x-panel.x-grid { + border-radius: var(--pm-radius-sm) !important; +} + +.x-layer.x-grid .x-grid-item-over, +.x-layer.x-grid .x-grid-item-selected, +.x-panel.x-layer.x-grid .x-grid-item-over, +.x-panel.x-layer.x-grid .x-grid-item-selected { + border-radius: var(--pm-radius-sm) !important; + outline: none !important; + box-shadow: none !important; +} + +.x-layer.x-grid .x-grid-item-over td, +.x-layer.x-grid .x-grid-item-selected td, +.x-layer.x-grid .x-grid-item-over .x-grid-cell, +.x-layer.x-grid .x-grid-item-selected .x-grid-cell, +.x-panel.x-layer.x-grid .x-grid-item-over td, +.x-panel.x-layer.x-grid .x-grid-item-selected td, +.x-panel.x-layer.x-grid .x-grid-item-over .x-grid-cell, +.x-panel.x-layer.x-grid .x-grid-item-selected .x-grid-cell { + border-radius: 0 !important; +} + +.x-layer.x-grid .x-grid-item-over td:first-child, +.x-layer.x-grid .x-grid-item-selected td:first-child, +.x-panel.x-layer.x-grid .x-grid-item-over td:first-child, +.x-panel.x-layer.x-grid .x-grid-item-selected td:first-child { + border-radius: var(--pm-radius-sm) 0 0 var(--pm-radius-sm) !important; +} + +.x-layer.x-grid .x-grid-item-over td:last-child, +.x-layer.x-grid .x-grid-item-selected td:last-child, +.x-panel.x-layer.x-grid .x-grid-item-over td:last-child, +.x-panel.x-layer.x-grid .x-grid-item-selected td:last-child { + border-radius: 0 var(--pm-radius-sm) var(--pm-radius-sm) 0 !important; +} + +/* ===================================================== + MENUS + ===================================================== */ +.x-menu, +.x-menu-default { + background-color: var(--drac-crust) !important; + border: 1px solid var(--drac-surface0) !important; + border-radius: var(--pm-radius-lg) !important; + box-shadow: 0 8px 24px rgba(30, 31, 41, 0.8) !important; + padding: 2px !important; + overflow: hidden !important; +} + +.x-menu-body-default { + background-color: transparent !important; + padding: 4px !important; +} + +.x-menu-header { + background-color: transparent !important; + color: var(--drac-text) !important; +} + +/* Menu icon separator — hide */ +.x-menu-icon-separator-default { + display: none !important; +} + +/* Menu item layout (flexbox reordering) */ +.x-menu-item-default > .x-menu-item-link { + display: flex !important; + align-items: center !important; + flex-direction: row !important; + gap: 4px !important; + justify-content: flex-start !important; + flex-wrap: nowrap !important; + border-radius: var(--pm-radius-md) !important; + padding: 4px 8px !important; + line-height: 20px !important; + cursor: pointer !important; + outline: none !important; + box-shadow: none !important; + white-space: nowrap !important; + text-decoration: none !important; +} + +.x-menu-item-text-default { + color: var(--drac-text) !important; + font-size: 13px !important; + order: 1 !important; + margin-left: 0 !important; + text-align: left !important; + line-height: 20px !important; + display: inline-flex !important; + align-items: center !important; + flex: 1 1 auto !important; + width: auto !important; + white-space: nowrap !important; +} + +.x-menu-item-icon-default { + color: var(--drac-subtext0) !important; + order: -1 !important; + position: relative !important; + float: none !important; + margin-right: 8px !important; + margin-left: 0 !important; + left: auto !important; + top: auto !important; + width: 16px !important; + text-align: center !important; + display: inline-flex !important; + align-items: center !important; + justify-content: center !important; + height: 20px !important; + line-height: 20px !important; + vertical-align: middle !important; + flex: 0 0 16px !important; + align-self: center !important; +} + +.x-menu-item-arrow, +.x-menu-item-arrow-default { + order: 2 !important; + margin-left: auto !important; +} + +.x-menu-item-default.x-menu-item-separator { + background-color: var(--drac-surface0) !important; + border: none !important; + height: 1px !important; + margin: 6px 4px !important; +} + +.x-menu-item-default.x-menu-item-focus, +.x-menu-item-default.x-menu-item-active, +.x-menu-item:hover { + background-color: var(--drac-surface0) !important; + color: var(--drac-text) !important; + border-radius: var(--pm-radius-md) !important; +} + +.x-menu-item-active .x-menu-item-text-default, +.x-menu-item-focus .x-menu-item-text-default { + color: var(--drac-text) !important; +} + +.x-menu-item-active .x-menu-item-icon-default, +.x-menu-item-focus .x-menu-item-icon-default { + color: var(--drac-cyan) !important; +} + +/* ===================================================== + PROGRESS BARS + ===================================================== */ + +/* Fix: Widget containers need overflow visible to not clip progress bars */ +.x-container[id^="pmxInfoWidget"], +.x-container.x-box-layout-ct { + overflow: visible !important; +} + +.x-progress, +.x-progress-default { + background-color: var(--drac-surface0) !important; + border-radius: 5px !important; +} + +.x-progress-default .x-progress-bar-default { + background-color: var(--drac-green) !important; + border-radius: 5px !important; + transition: width 0.4s ease !important; +} + +.x-progress-default .x-progress-text { + color: var(--drac-text) !important; +} + +/* Text overlaid on the progress bar fill — use on-accent for contrast */ +.x-progress-bar .x-progress-text { + color: var(--drac-on-accent) !important; +} + +.x-progress.warning .x-progress-bar { + background-color: var(--drac-yellow) !important; +} + +.x-progress.critical .x-progress-bar { + background-color: var(--drac-red) !important; +} + +/* ===================================================== + TABS — Dracula underline style + Flat tabs with Purple underline on active tab + ===================================================== */ +.x-tab-bar, +.x-tab-bar-default { + background-color: var(--drac-base) !important; + border-radius: 0 !important; + border-bottom: 1px solid var(--drac-surface1) !important; + padding-bottom: 0 !important; +} + +/* Overflow visible for the underline indicator */ +.x-tab-bar .x-box-inner, +.x-tab-bar .x-box-target, +.x-tab-bar-body, +.x-tab-bar-body-default { + overflow: visible !important; +} + +/* Base tab */ +.x-tab, +.x-tab-default, +.x-tab-default-top { + background-color: transparent !important; + border: none !important; + border-radius: var(--pm-radius-md) var(--pm-radius-md) 0 0 !important; + padding: 8px 16px 8px !important; + overflow: visible !important; + margin-bottom: 0 !important; + transition: color 0.15s ease !important; + outline: none !important; + box-shadow: none !important; +} + +/* Remove ::after from inactive tabs */ +.x-tab::after { + display: none !important; +} + +.x-tab-inner-default { + color: var(--drac-subtext0) !important; + font-size: 13px !important; +} + +.x-tab-default.x-tab-over { + background-color: transparent !important; +} + +.x-tab-default.x-tab-over .x-tab-inner-default { + color: var(--drac-text) !important; +} + +/* Active tab */ +.x-tab-default.x-tab.x-tab-active { + background-color: transparent !important; + border: none !important; + overflow: visible !important; + margin-bottom: 0 !important; + outline: none !important; + box-shadow: none !important; +} + +/* Purple underline indicator on active tab */ +.x-tab-default.x-tab.x-tab-active::after { + content: '' !important; + display: block !important; + position: absolute !important; + bottom: 0 !important; + left: 0 !important; + right: 0 !important; + height: 2px !important; + background: var(--drac-green) !important; + z-index: 10 !important; + border-radius: 2px 2px 0 0 !important; + pointer-events: none !important; +} + +.x-tab-active .x-tab-inner-default { + color: var(--drac-text) !important; + font-weight: 600 !important; +} + +.x-tab-default.x-tab.x-tab-disabled { + background-color: transparent !important; + border: none !important; + color: var(--drac-overlay0) !important; + margin-bottom: 0 !important; +} + +/* Focus states — no outline */ +.x-keyboard-mode .x-tab-default.x-tab-focus, +.x-keyboard-mode .x-tab-default.x-tab-focus.x-tab-active { + background-color: transparent !important; + border: none !important; + outline: none !important; + box-shadow: none !important; + margin-bottom: 0 !important; +} + +.x-keyboard-mode .x-tab-default.x-tab-focus.x-tab-active::after { + content: '' !important; + display: block !important; + position: absolute !important; + bottom: 0 !important; + left: 0 !important; + right: 0 !important; + height: 2px !important; + background: var(--drac-green) !important; + z-index: 10 !important; + pointer-events: none !important; +} + +/* Kill ALL tab interaction outlines/shadows */ +.x-tab:focus, +.x-tab *:focus, +.x-tab-focus, +.x-tab-active.x-tab-focus, +.x-tab-inner-focus, +.x-tab-button-focus, +.x-tab-pressed, +.x-tab-active.x-tab-pressed, +.x-tab-over, +.x-tab:active, +.x-tab *:active { + outline: none !important; + box-shadow: none !important; +} + +.x-tabpanel-child { + border-radius: 0 0 var(--pm-radius-lg) var(--pm-radius-lg) !important; +} + +/* Tab hover/active corners */ +.x-tab-default.x-tab-over, +.x-tab-default.x-tab.x-tab-active { + border-radius: var(--pm-radius-md) var(--pm-radius-md) 0 0 !important; +} + +/* ===================================================== + TOOLTIPS + ===================================================== */ +.x-tip, +.x-tip-default { + background-color: var(--drac-mantle) !important; + border: 1px solid var(--drac-surface1) !important; + border-radius: var(--pm-radius-md) !important; + box-shadow: 0 4px 12px rgba(30, 31, 41, 0.5); +} + +.x-tip-body-default { + color: var(--drac-text) !important; +} + +.x-tip-form-invalid { + background-color: var(--drac-mantle) !important; + border-color: var(--drac-red) !important; +} + +.x-tip-body-form-invalid { + color: var(--drac-red) !important; +} + +/* ===================================================== + TREE NAVIGATION (Sidebar) + ===================================================== */ +.x-treelist-item { + background-color: var(--drac-base) !important; + border-radius: var(--pm-radius-md) !important; +} + +/* Pseudo-element approach for hover/selected highlighting */ +.x-treelist-row { + border-radius: var(--pm-radius-md) !important; + background-color: transparent !important; + position: relative !important; + z-index: 0 !important; +} + +.x-treelist-row::before { + content: ""; + position: absolute; + top: 1px; + bottom: 1px; + left: 0; + right: 4px; + border-radius: var(--pm-radius-md); + background-color: transparent; + z-index: -1; + pointer-events: none; + transition: background-color 0.15s ease; +} + +/* Fix toolbox tree item text overlapping icons */ +.x-treelist-item-text { + margin-left: 28px !important; +} + +/* Toolbox tree items — bright text */ +.x-treelist-item-text, +.x-treelist-item-icon, +.x-treelist.x-treelist-pve-nav .x-treelist-item-text, +.x-treelist.x-treelist-pve-nav .x-treelist-item-icon { + color: var(--drac-subtext1) !important; +} + +/* Hover state — apply to pseudo-element */ +.x-treelist-row-over { + background-color: transparent !important; +} + +.x-treelist-row-over::before { + background-color: var(--drac-hover-overlay) !important; +} + +.x-treelist-row-over .x-treelist-item-icon, +.x-treelist-row-over .x-treelist-item-text { + background-color: transparent !important; + color: var(--drac-text) !important; +} + +/* Selected/active item — Purple highlight */ +.x-treelist-item-selected > .x-treelist-row { + background-color: transparent !important; +} + +.x-treelist-item-selected > .x-treelist-row::before, +.x-treelist-item-selected > .x-treelist-row:hover::before { + background-color: var(--drac-green) !important; +} + +.x-treelist-item-selected .x-treelist-item-text, +.x-treelist-item-selected .x-treelist-item-icon, +.x-treelist.x-treelist-pve-nav .x-treelist-item-selected .x-treelist-item-text, +.x-treelist.x-treelist-pve-nav .x-treelist-item-selected .x-treelist-item-icon { + color: var(--drac-on-accent) !important; +} + +.x-treelist-pve-nav { + background-color: var(--drac-base) !important; + border-color: var(--drac-surface1) !important; +} + +/* Tree navigation radius overrides */ +.x-treelist-item, +.x-treelist-item-tool { + border-radius: var(--pm-radius-sm) !important; +} + +.x-treelist-row, +.x-treelist-row:hover, +.x-treelist-row-over, +.x-treelist-item-selected > .x-treelist-row, +.x-treelist-item-selected > .x-treelist-row:hover, +.x-treelist-item-expanded > .x-treelist-row, +.x-treelist-item-expanded > .x-treelist-row-over, +.x-treelist-item-expandable > .x-treelist-row, +.x-treelist-item-expandable > .x-treelist-row-over { + border-radius: var(--pm-radius-sm) !important; +} + +.x-treelist-row::before { + border-radius: var(--pm-radius-sm) !important; +} + +.x-treelist-item-wrap, +.x-treelist-item-text, +.x-treelist-row, +.x-treelist-container, +.x-treelist-root-container, +.x-treelist, +.x-treelist-pve-nav { + border-radius: var(--pm-radius-sm) !important; +} + +/* Cursor pointer for interactive tree/grid items */ +.x-grid-cell, +.x-grid-cell-inner, +.x-tree-elbow-img, +.x-tree-icon, +.x-treelist-item, +.x-treelist-row, +.x-treelist-item-wrap, +.x-treelist-item-text, +.x-treelist-item-icon { + cursor: pointer !important; +} + +/* ===================================================== + WINDOWS / MODALS + ===================================================== */ +.x-window, +.x-window-default { + background-color: var(--drac-crust) !important; + border: 1px solid var(--drac-surface1) !important; + border-radius: var(--pm-radius-lg) !important; + box-shadow: 0 8px 24px rgba(30, 31, 41, 0.6) !important; + overflow: hidden !important; +} + +.x-window .x-window-header, +.x-window-header-default { + background-color: var(--drac-mantle) !important; + border-color: transparent !important; + border-radius: var(--pm-radius-lg) var(--pm-radius-lg) 0 0 !important; +} + +.x-window-header-default .x-mask { + background-color: rgba(30, 31, 41, 0.7); +} + +.x-window .x-window-body, +.x-window-body-default { + background-color: var(--drac-base) !important; + border-color: var(--drac-surface1) !important; + color: var(--drac-text) !important; + border-radius: 0 0 var(--pm-radius-lg) var(--pm-radius-lg) !important; +} + +.x-window-ghost { + background-color: var(--drac-base) !important; +} + +.x-window-header-default .x-tool-img { + background-color: transparent; +} + +.x-message-box .x-window-body { + background-color: var(--drac-mantle) !important; +} + +/* Respect ExtJS inline display:none on hidden dialog buttons */ +.x-message-box .x-btn.x-btn-default-small[style*="display: none"], +.x-message-box .x-btn.x-btn-default-small[style*="display:none"], +.x-window .x-toolbar-footer .x-btn[style*="display: none"], +.x-window .x-toolbar-footer .x-btn[style*="display:none"] { + display: none !important; +} + +/* Login dialog — clean inner panel borders */ +.x-window:has(#pveloginrealm) .x-panel-body { + border: none !important; + background: transparent !important; + width: auto !important; +} + +/* ===================================================== + CONSOLE / TERMINAL + ===================================================== */ +div.monitor { + border-color: var(--drac-surface1); +} + +.install-mask { + background-color: var(--drac-crust); + color: var(--drac-subtext0); +} + +.x-window.install-mask { + box-shadow: rgba(30, 31, 41, 0.5) 0 4px 20px !important; +} + +/* ===================================================== + LEGEND / CHARTS + ===================================================== */ +.x-legend-container { + background-color: var(--drac-base) !important; +} + +.x-legend-horizontal .x-legend-item { + background-color: var(--drac-mantle) !important; + color: var(--drac-text) !important; + border: 1px solid var(--drac-surface0) !important; +} + +/* Chart/RRD panel backgrounds */ +div[id*="rrdchart"], +.pve-rrddatastore, +.pmx-panel-rrd { + background-color: var(--drac-base) !important; +} + +.proxmox-rrd-panel canvas, +.proxmox-widget-toolkit canvas, +canvas.x-surface, +.x-surface canvas { + background-color: transparent !important; + opacity: 1 !important; +} + +.proxmox-rrd-panel, +.proxmox-rrd-chart { + background-color: var(--drac-base) !important; +} + +/* Chart text/labels */ +.x-surface text, +svg text { + fill: var(--drac-text) !important; +} + +/* ===================================================== + PROXMOX-SPECIFIC OVERRIDES + ===================================================== */ + +/* Logo inversion */ +img[id^="proxmoxlogo-"][id$="-img"], +img[id^="proxmoxLogoSvg-"][id$="-img"] { + filter: invert(1) hue-rotate(180deg); +} + +/* Invalid/warning/disabled rows */ +.proxmox-invalid-row { + background-color: rgba(255, 85, 85, 0.15) !important; +} + +.proxmox-warning-row { + background-color: rgba(255, 184, 108, 0.15) !important; +} + +.proxmox-disabled-row td { + color: var(--drac-overlay0) !important; +} + +/* Hints */ +.pmx-hint { + background-color: rgba(255, 184, 108, 0.15) !important; + white-space: nowrap !important; +} + +.pmx-hint a { + color: var(--drac-cyan) !important; +} + +/* Status text colors — Information → Cyan */ +.info-blue { + color: var(--drac-cyan) !important; +} + +.critical { + color: var(--drac-red) !important; +} + +/* Links */ +a { + color: var(--drac-cyan) !important; +} + +/* Markdown content */ +.pmx-md code { + background-color: var(--drac-mantle) !important; + color: var(--drac-pink) !important; + border-radius: var(--pm-radius-sm) !important; +} + +.pmx-md pre code { + border-color: var(--drac-surface1) !important; + background-color: var(--drac-crust) !important; +} + +.pmx-md a { + color: var(--drac-cyan) !important; +} + +.pmx-md table { + border-color: var(--drac-surface1) !important; +} + +.pmx-md th { + background-color: var(--drac-mantle) !important; + border-color: var(--drac-surface1) !important; +} + +.pmx-md td { + border-color: var(--drac-surface1) !important; +} + +/* APT repos */ +.proxmox-apt-repos .x-grid-group-hd { + background-color: var(--drac-base) !important; + border: none !important; +} + +.proxmox-apt-repos .x-grid-group-title { + color: var(--drac-text) !important; +} + +/* Tags */ +.pve-edit-tag { + border-radius: var(--pm-radius-md) !important; +} + +.pve-edit-tag.editable span { + background-color: var(--drac-mantle) !important; + color: var(--drac-text) !important; + border-color: var(--drac-surface1) !important; +} + +.x-tree-node-text .proxmox-tag-dark, +.x-tree-node-text .proxmox-tag-light, +.x-grid-cell-inner .proxmox-tag-dark, +.x-grid-cell-inner .proxmox-tag-light, +span.proxmox-tag-dark, +span.proxmox-tag-light { + border-radius: var(--pm-radius-md) !important; +} + +/* Checkmark button in tag edit — match toolbar button size */ +.x-btn.x-btn-default-small:has(.fa-check) { + min-height: 24px !important; + height: 24px !important; + padding: 3px 8px !important; + border-radius: var(--pm-radius-sm) !important; + background-color: var(--drac-green) !important; + border: none !important; +} + +.x-btn.x-btn-default-small:has(.fa-check).x-btn-disabled { + background-color: transparent !important; + border: 1px solid var(--drac-surface1) !important; + opacity: 0.5 !important; +} + +.x-btn.x-btn-default-small:has(.fa-check) .fa-check { + color: var(--drac-on-accent) !important; +} + +.x-btn.x-btn-default-small:has(.fa-check).x-btn-disabled .fa-check { + color: var(--drac-overlay1) !important; +} + +.x-btn.x-btn-default-small:has(.fa-check):not(.x-btn-disabled):hover { + background-color: #6afb90 !important; +} + +.x-btn.x-btn-default-small:has(.fa-check) .x-btn-inner { + display: none !important; +} + +/* Date picker */ +.x-datepicker, +.x-datepicker-column-header, +.x-monthpicker { + background-color: var(--drac-base) !important; + color: var(--drac-text) !important; + border-color: transparent !important; +} + +.x-datepicker-header, +.x-datepicker-footer, +.x-monthpicker-buttons { + background-color: var(--drac-mantle) !important; +} + +.x-datepicker-date, +.x-monthpicker-item-inner { + color: var(--drac-text) !important; +} + +.x-datepicker-selected div.x-datepicker-date, +.x-monthpicker-item a.x-monthpicker-selected, +a.x-monthpicker-item-inner:hover, +div.x-datepicker-date:hover { + background-color: var(--drac-hover-overlay) !important; + color: var(--drac-text) !important; +} + +.x-datepicker-today .x-datepicker-date { + border-color: var(--drac-green) !important; +} + +.x-datepicker-disabled .x-datepicker-date { + color: var(--drac-overlay0) !important; +} + +.x-datepicker-prev-day .x-datepicker-date, +.x-datepicker-next-day .x-datepicker-date { + color: var(--drac-overlay0) !important; +} + +/* Usage bars */ +.usage-wrapper, +.usage { + border-radius: 2px !important; +} + +.usage { + background-color: var(--drac-overlay2) !important; +} + +/* ===================================================== + SCROLLBARS + ===================================================== */ +::-webkit-scrollbar { + width: 8px; + height: 8px; +} + +::-webkit-scrollbar-track { + background: var(--drac-base); + border-radius: var(--pm-radius-sm); +} + +::-webkit-scrollbar-thumb { + background: var(--drac-surface2); + border-radius: var(--pm-radius-sm); + border: 1px solid transparent; + background-clip: padding-box; + transition: background 0.15s ease; +} + +::-webkit-scrollbar-thumb:hover { + background: var(--drac-overlay0); +} + +::-webkit-scrollbar-corner { + background: var(--drac-base); +} + +/* Firefox scrollbar */ +* { + scrollbar-width: thin; + scrollbar-color: var(--drac-surface2) var(--drac-base); +} + +/* ===================================================== + SELECTION HIGHLIGHT + ===================================================== */ +::selection { + background-color: rgba(98, 114, 164, 0.3); + color: var(--drac-text); +} + +/* ===================================================== + TRANSITIONS (smooth interactions) + ===================================================== */ + +/* Grid row transitions */ +.x-grid-item { + transition: background-color 0.15s ease !important; +} + +/* Tree pseudo-element transitions */ +.x-treelist-row::before { + transition: background-color 0.15s ease !important; +} + +/* Menu item transitions */ +.x-menu-item-default > .x-menu-item-link { + transition: background-color 0.12s ease !important; +} + +/* Boundlist item transitions */ +.x-boundlist-item { + transition: background-color 0.12s ease !important; +} + +/* Tab transitions */ +.x-tab { + transition: color 0.15s ease !important; +} + +/* Splitter transition */ +.x-splitter { + transition: background-color 0.15s ease !important; +} + +/* Tooltip transition */ +.x-tip { + transition: opacity 0.15s ease !important; +} + +/* Progress bar width transition */ +.x-progress-bar { + transition: width 0.4s ease !important; +} + +/* Scrollbar thumb transition */ +::-webkit-scrollbar-thumb { + transition: background 0.15s ease !important; +} + +/* Window close tool transition */ +.x-tool-img { + transition: filter 0.15s ease !important; +} + +/* ===================================================== + TOOL ICONS - FontAwesome Replacements + (Ported from UniFi v5.86) + Replace sprite-based ExtJS tool icons with crisp + FontAwesome icons for better consistency and clarity + ===================================================== */ + +/* Base styling for all tool icons - remove sprite backgrounds */ +.x-tool-tool-el.x-tool-minus, +.x-tool-img.x-tool-minus, +.x-tool-tool-el.x-tool-collapse-right, +.x-tool-img.x-tool-collapse-right, +.x-tool-tool-el.x-tool-collapse-left, +.x-tool-img.x-tool-collapse-left, +.x-tool-tool-el.x-tool-expand-right, +.x-tool-img.x-tool-expand-right, +.x-tool-tool-el.x-tool-expand-left, +.x-tool-img.x-tool-expand-left, +.x-tool-tool-el.x-tool-maximize, +.x-tool-img.x-tool-maximize, +.x-tool-tool-el.x-tool-restore, +.x-tool-img.x-tool-restore, +.x-tool-tool-el.x-tool-gear, +.x-tool-img.x-tool-gear, +.x-tool-tool-el.x-tool-refresh, +.x-tool-img.x-tool-refresh, +.x-tool-tool-el.x-tool-close, +.x-tool-img.x-tool-close { + background-image: none !important; + font-family: "FontAwesome" !important; + font-size: 14px !important; + line-height: 16px !important; + text-align: center !important; + color: var(--pm-text-dim) !important; + transition: color 0.15s ease !important; + filter: none !important; + width: 16px !important; + height: 16px !important; + display: flex !important; + align-items: center !important; + justify-content: center !important; +} + +/* Close button - slightly larger */ +.x-tool-tool-el.x-tool-close, +.x-tool-img.x-tool-close { + font-size: 20px !important; +} + +/* Individual glyph assignments */ +.x-tool-tool-el.x-tool-minus::before, +.x-tool-img.x-tool-minus::before { + content: "\f010" !important; /* fa-search-minus (zoom out) */ +} + +.x-tool-tool-el.x-tool-collapse-right::before, +.x-tool-img.x-tool-collapse-right::before { + content: "\f054" !important; /* fa-chevron-right */ +} + +.x-tool-tool-el.x-tool-expand-left::before, +.x-tool-img.x-tool-expand-left::before { + content: "\f053" !important; /* fa-chevron-left */ +} + +.x-tool-tool-el.x-tool-collapse-left::before, +.x-tool-img.x-tool-collapse-left::before { + content: "\f053" !important; /* fa-chevron-left */ +} + +.x-tool-tool-el.x-tool-expand-right::before, +.x-tool-img.x-tool-expand-right::before { + content: "\f054" !important; /* fa-chevron-right */ +} + +.x-tool-tool-el.x-tool-maximize::before, +.x-tool-img.x-tool-maximize::before { + content: "\f065" !important; /* fa-expand */ +} + +.x-tool-tool-el.x-tool-restore::before, +.x-tool-img.x-tool-restore::before { + content: "\f066" !important; /* fa-compress */ +} + +.x-tool-tool-el.x-tool-gear::before, +.x-tool-img.x-tool-gear::before { + content: "\f013" !important; /* fa-cog */ +} + +.x-tool-tool-el.x-tool-refresh::before, +.x-tool-img.x-tool-refresh::before { + content: "\f021" !important; /* fa-refresh */ +} + +.x-tool-tool-el.x-tool-close::before, +.x-tool-img.x-tool-close::before { + content: "\f00d" !important; /* fa-times */ +} + +/* Hover state - all tool icons */ +.x-tool:hover .x-tool-tool-el.x-tool-minus, +.x-tool:hover .x-tool-img.x-tool-minus, +.x-tool:hover .x-tool-tool-el.x-tool-collapse-right, +.x-tool:hover .x-tool-img.x-tool-collapse-right, +.x-tool:hover .x-tool-tool-el.x-tool-collapse-left, +.x-tool:hover .x-tool-img.x-tool-collapse-left, +.x-tool:hover .x-tool-tool-el.x-tool-expand-right, +.x-tool:hover .x-tool-img.x-tool-expand-right, +.x-tool:hover .x-tool-tool-el.x-tool-expand-left, +.x-tool:hover .x-tool-img.x-tool-expand-left, +.x-tool:hover .x-tool-tool-el.x-tool-maximize, +.x-tool:hover .x-tool-img.x-tool-maximize, +.x-tool:hover .x-tool-tool-el.x-tool-restore, +.x-tool:hover .x-tool-img.x-tool-restore, +.x-tool:hover .x-tool-tool-el.x-tool-gear, +.x-tool:hover .x-tool-img.x-tool-gear, +.x-tool:hover .x-tool-tool-el.x-tool-refresh, +.x-tool:hover .x-tool-img.x-tool-refresh, +.x-tool:hover .x-tool-tool-el.x-tool-close, +.x-tool:hover .x-tool-img.x-tool-close { + color: var(--pm-text) !important; +} + +/* Disabled state */ +.x-tool-disabled .x-tool-tool-el, +.x-tool-disabled .x-tool-img { + opacity: 0.4 !important; + cursor: default !important; +} + +/* Inline FontAwesome tools (PVE-injected) */ +.x-tool-tool-el[style*="font-family:FontAwesome"], +.x-tool-tool-el[style*="font-family: FontAwesome"] { + color: var(--pm-text-dim) !important; + font-size: 14px !important; + line-height: 16px !important; + display: flex !important; + align-items: center !important; + justify-content: center !important; + width: 16px !important; + height: 16px !important; + transition: color 0.15s ease !important; + background-image: none !important; + background-color: transparent !important; +} + +.x-tool:not(.x-tool-disabled) .x-tool-tool-el[style*="font-family:FontAwesome"], +.x-tool:not(.x-tool-disabled) .x-tool-tool-el[style*="font-family: FontAwesome"] { + cursor: pointer !important; +} + +.x-tool.x-tool-disabled .x-tool-tool-el[style*="font-family:FontAwesome"], +.x-tool.x-tool-disabled .x-tool-tool-el[style*="font-family: FontAwesome"] { + cursor: default !important; + opacity: 0.4 !important; +} + +.x-tool .x-mask { + background-color: transparent !important; + backdrop-filter: none !important; + pointer-events: none !important; +} + +.x-tool:not(.x-tool-disabled):hover .x-tool-tool-el[style*="font-family:FontAwesome"], +.x-tool:not(.x-tool-disabled):hover .x-tool-tool-el[style*="font-family: FontAwesome"] { + color: var(--pm-text) !important; +} diff --git a/themes/theme-dracula-midnight.css b/themes/theme-dracula-midnight.css new file mode 100644 index 0000000..1ebd152 --- /dev/null +++ b/themes/theme-dracula-midnight.css @@ -0,0 +1,2378 @@ +/*!Dracula Midnight*/ +/* + * ProxMorph Theme: Dracula Midnight + * The canonical dark theme with near-black backgrounds from the Dracula UI palette — ported from the Dracula specification + * Version: 1.0.0 + * Author: ProxMorph / Dracula Theme (https://draculatheme.com) + * + * v1.0.0: Initial release — Tier 2 baseline with all fixes + * - Full Dracula palette with derived shades + * - All component sections ported from UniFi/Catppuccin reference + * - Console/Terminal, Charts, Progress bars, Buttons (28px), + * Dialog fixes, Tree cursor:pointer, APT repos, Tag checkmark + * + * ─── Dracula Specification Palette ───────────────────────────── + * Background: #191a21 Current Line: #282a36 + * Foreground: #f8f8f2 Comment: #6272a4 + * Cyan: #8be9fd Green: #50fa7b + * Orange: #ffb86c Pink: #ff79c6 + * Purple: #bd93f9 Red: #ff5555 + * Yellow: #f1fa8c + * + * ─── Derived Shades (ProxMorph) ──────────────────────────────── + * Crust: #121318 Mantle: #15161e + * Surface 0: #21222c Surface 1: #282a36 (= Current Line) + * Surface 2: #343746 Overlay 0: #6272a4 (= Comment) + * Overlay 1: #7c83a0 Overlay 2: #9298b8 + * Subtext 0: #b0b5c8 Subtext 1: #d0d4e0 + * Text: #f8f8f2 On-Accent: #191a21 + */ + +/* ===================================================== + CSS VARIABLES + ===================================================== */ +:root { + /* Dracula Specification Tokens */ + --drac-bg: #191a21; + --drac-current-line: #282a36; + --drac-fg: #f8f8f2; + --drac-comment: #6272a4; + --drac-cyan: #8be9fd; + --drac-green: #50fa7b; + --drac-orange: #ffb86c; + --drac-pink: #ff79c6; + --drac-purple: #bd93f9; + --drac-red: #ff5555; + --drac-yellow: #f1fa8c; + + /* Derived Neutral Scale */ + --drac-text: #f8f8f2; + --drac-subtext1: #d0d4e0; + --drac-subtext0: #b0b5c8; + --drac-overlay2: #9298b8; + --drac-overlay1: #7c83a0; + --drac-overlay0: #6272a4; + --drac-surface2: #343746; + --drac-surface1: #282a36; + --drac-surface0: #21222c; + --drac-base: #191a21; + --drac-mantle: #15161e; + --drac-crust: #121318; + + /* ProxMorph Semantic Variables */ + --pm-accent: var(--drac-purple); + --pm-bg-base: var(--drac-base); + --pm-bg-surface: var(--drac-surface0); + --pm-bg-elevated: var(--drac-surface1); + --pm-text: var(--drac-text); + --pm-text-dim: var(--drac-subtext1); + --pm-success: var(--drac-green); + --pm-warning: var(--drac-yellow); + --pm-error: var(--drac-red); + --pm-border: var(--drac-surface1); + --pm-radius-sm: 4px; + --pm-radius-md: 6px; + --pm-radius-lg: 8px; + + /* Proxmox Widget Toolkit Mappings (REQUIRED) */ + --pwt-panel-background: var(--drac-base); + --pwt-text-color: var(--drac-text); + --pwt-gauge-default: var(--drac-purple); + --pwt-gauge-back: var(--drac-surface1); + --pwt-gauge-warn: var(--drac-yellow); + --pwt-gauge-crit: var(--drac-red); + --pwt-chart-primary: var(--drac-purple); + --pwt-chart-grid-stroke: var(--drac-surface1); + + /* On Accent text — Background on colored backgrounds for contrast */ + --drac-on-accent: var(--drac-bg); + + /* Hover overlay — Comment@12% */ + --drac-hover-overlay: rgba(98, 114, 164, 0.12); + /* Selection overlay — Comment@25% */ + --drac-select-overlay: rgba(98, 114, 164, 0.25); + /* Accent muted (for focus rings) */ + --drac-accent-muted: rgba(189, 147, 249, 0.4); + --drac-accent-subtle: rgba(189, 147, 249, 0.15); + + color-scheme: dark; +} + +/* ===================================================== + GLOBAL BORDER-RADIUS ARCHITECTURE + (Ported from UniFi theme — reset everything, selectively re-apply) + ===================================================== */ +.x-border-box, +.x-border-box * { + border-radius: var(--pm-radius-lg); +} + +/* Remove rounded corners from grids/tables/lists */ +.x-grid, +.x-grid *, +.x-grid-header-ct, +.x-grid-header-ct *, +.x-grid-view, +.x-grid-view *, +.x-column-header, +.x-column-header *, +.x-grid-item, +.x-grid-cell, +.x-grid-cell-inner, +.x-grid-row, +table, +table *, +tr, +td, +th, +.x-legend, +.x-legend *, +.x-legend-container, +.x-legend-container *, +.x-legend-item, +.x-legend-horizontal .x-legend-item, +.x-legend-vertical .x-legend-item, +.x-legend-horizontal .x-legend-item:first-child, +.x-legend-horizontal .x-legend-item:last-child, +.x-legend-vertical .x-legend-item:first-child, +.x-legend-vertical .x-legend-item:last-child, +.x-tool, +.x-tool-tool-el, +.x-tool-default, +.x-tool-img { + border-radius: 0 !important; +} + +/* Form elements - exclude from global radius */ +.x-form-item, +.x-form-item-default, +.x-form-item-body, +.x-form-item-body-default, +.x-form-text-field-body, +.x-form-text-field-body-default, +.x-form-fieldcontainer, +.x-field, +.x-field-default, +.x-form-type-text { + border-radius: 0 !important; +} + +/* Reset layout containers that clip elements with overflow:hidden + radius */ +.x-box-layout-ct, +.x-panel-bodyWrap, +.x-panel-bodyWrap-default, +.x-autocontainer-innerCt, +.x-autocontainer-outerCt, +.x-panel.x-tabpanel-child, +.x-panel.x-box-item, +.x-box-inner, +.x-box-target, +.x-container, +.x-container-default, +.x-window .x-panel-body, +.x-window .x-window-body, +.x-window .x-window-bodyWrap { + border-radius: 0 !important; +} + +/* Reset everything inside windows to 0 — then re-apply specific radii */ +.x-window *, +.x-window .x-autocontainer-innerCt, +.x-window .x-autocontainer-outerCt, +.x-window .x-form-layout-wrap, +.x-window .x-form-layout-auto-label, +.x-window .x-form-layout-colgroup, +.x-window .x-form-layout-column, +.x-window .x-field, +.x-window .x-form-item, +.x-window .x-form-item-body { + border-radius: 0 !important; +} + +/* Chart canvas — no radius on data area */ +.x-chart-grid, +.x-chart-axis, +canvas.x-surface, +.x-chart canvas, +canvas.x-surface-canvas, +.x-surface-canvas, +.x-draw-component canvas, +.proxmox-rrd-chart canvas, +svg.x-surface, +.x-draw-container, +.x-surface { + border-radius: 0 !important; +} + +/* Legend color marker (dot) — keep circular */ +.x-legend-item-marker { + border-radius: 50% !important; +} + +/* ===================================================== + RE-APPLY BORDER RADII (selective) + ===================================================== */ + +/* Windows */ +.x-window, +.x-window-default { + border-radius: var(--pm-radius-lg) !important; +} + +.x-window-header, +.x-window-header-default { + border-radius: var(--pm-radius-lg) var(--pm-radius-lg) 0 0 !important; +} + +.x-window .x-window-body, +.x-window-body-default { + border-radius: 0 !important; +} + +/* Buttons inside windows */ +.x-window .x-btn { + border-radius: var(--pm-radius-md) !important; +} + +/* Checkboxes inside windows */ +.x-window .x-form-checkbox { + border-radius: 3px !important; +} + +/* Form inputs inside windows */ +.x-window .x-form-trigger-wrap, +.x-window .x-form-trigger-wrap-default { + border-radius: var(--pm-radius-sm) !important; +} + +.x-window .x-form-text-wrap, +.x-window .x-form-text { + border-radius: var(--pm-radius-sm) 0 0 var(--pm-radius-sm) !important; +} + +.x-window .x-form-arrow-trigger { + border-radius: 0 var(--pm-radius-sm) var(--pm-radius-sm) 0 !important; +} + +/* Form trigger/text wrap — reset and re-apply */ +.x-form-trigger-wrap, +.x-form-trigger-wrap *, +.x-form-text-wrap, +.x-form-text-wrap *, +.x-form-text, +.x-form-trigger { + border-radius: 0 !important; +} + +.x-form-trigger-wrap, +.x-form-trigger-wrap-default { + border-radius: var(--pm-radius-sm) !important; + overflow: hidden !important; +} + +.x-form-text-wrap, +.x-form-text-wrap-default { + border-radius: var(--pm-radius-sm) 0 0 var(--pm-radius-sm) !important; +} + +.x-form-text, +.x-form-text-default { + border-radius: var(--pm-radius-sm) 0 0 var(--pm-radius-sm) !important; +} + +.x-form-trigger, +.x-form-trigger-default, +.x-form-arrow-trigger, +.x-form-arrow-trigger-default { + border-radius: 0 var(--pm-radius-sm) var(--pm-radius-sm) 0 !important; +} + +/* Dialog form content padding — vertical only (horizontal causes ExtJS overflow) */ +.x-window .x-tabpanel-child .x-autocontainer-innerCt { + padding: 12px 0 !important; +} + +/* Allow column panel bodies to show overflowed form content */ +.x-window .x-panel-body:not(.x-scroller) { + overflow: visible !important; +} + +/* Side padding on column panel bodies inside windows */ +.x-window .x-panel.x-box-item .x-panel-body { + padding: 0 4px !important; +} + +/* Constrain autocontainer width inside windows */ +.x-window .x-autocontainer-outerCt { + max-width: 100% !important; +} + +/* Fix window header/body width consistency */ +.x-window > .x-window-header, +.x-window > .x-window-body, +.x-window > .x-window-bodyWrap, +.x-window-bodyWrap > .x-window-body { + width: 100% !important; +} + +.x-window-header > .x-box-inner, +.x-window-header > .x-box-inner > .x-box-target { + width: 100% !important; +} + +.x-window-header-title { + width: auto !important; + flex: 1 !important; + max-width: calc(100% - 30px) !important; +} + +/* Boundlists */ +.x-boundlist { + border-radius: var(--pm-radius-md) !important; + overflow: hidden !important; +} + +/* ===================================================== + BASE / BODY + ===================================================== */ +.x-body, +.x-viewport > .x-body, +body.x-border-layout-ct, +div.x-border-layout-ct { + background-color: var(--drac-base) !important; + color: var(--drac-text) !important; +} + +/* ===================================================== + MASKS & OVERLAYS + ===================================================== */ +.x-mask { + background-color: rgba(30, 31, 41, 0.6) !important; + backdrop-filter: blur(4px); +} + +.x-mask-msg { + background-color: var(--drac-mantle) !important; + border: 1px solid var(--drac-surface1) !important; + border-radius: var(--pm-radius-lg) !important; +} + +.x-mask-msg-text { + color: var(--drac-subtext0) !important; + filter: none !important; +} + +.x-css-shadow { + box-shadow: 0 8px 24px rgba(30, 31, 41, 0.6) !important; +} + +/* Loading indicators */ +.x-grid-row-loading, +.x-treelist-item-loading .x-treelist-item-icon, +.x-grid-tree-loading .x-tree-icon { + filter: invert(90%); +} + +/* ===================================================== + ICONS — Proxmox default colors for dark mode + ===================================================== */ + +/* General icon colors — neutral gray for dark backgrounds */ +.x-tree-icon-custom, +.x-grid-icon-custom, +.fa-tags::before, +.fa-file-o::before, +.fa-building::before, +.x-action-col-icon::before, +.fa-shield::before, +.fa-file-text-o::before, +.fa-clock-o::before, +.x-tab-icon-el-default, +.pve-icon-verify-lettering::after, +.x-tree-icon-leaf:not(.x-tree-icon-custom)::before, +.x-tree-icon-parent:not(.x-tree-icon-custom)::before, +.x-tree-icon-parent-expanded:not(.x-tree-icon-custom)::before, +.x-grid-filters-filtered-column .x-column-header-text::after { + color: var(--drac-overlay2) !important; +} + +/* Folder icons — invert for dark mode */ +.x-tree-icon-parent:not(.x-tree-icon-custom)::before, +.x-tree-icon-parent-expanded:not(.x-tree-icon-custom)::before { + filter: invert(90%); +} + +/* Various image-based icons — invert for visibility */ +.fa-ceph::before, +.fa-sdn::before, +.fa-network-wired::before, +.pve-itype-treelist-item-icon-cdrom, +.fa-chevron-right::before, +.x-grid-row-console, +.x-box-scroller-toolbar-default.x-box-scroller, +.x-tree-elbow-img, +.pve-itype-icon-qemu, +.x-tree-node-computer, +.x-grid-tree-node-expanded .x-tree-node-computer, +.pbs-icon-tape, +.pbs-icon-tape-drive, +.x-tree-icon-leaf:not(.x-tree-icon-custom), +.x-tree-icon-parent:not(.x-tree-icon-custom), +.x-tree-icon-parent-expanded:not(.x-tree-icon-custom) { + filter: invert(90%); +} + +/* Hardware icons */ +.pve-itype-icon-cpu, +.pve-itype-icon-cdrom, +.pve-itype-icon-memory, +.pve-itype-icon-pci, +.pve-itype-icon-serial, +.pve-itype-icon-die, +.pmx-itype-icon-processor, +.pmx-itype-icon-memory, +.pve-itype-icon-storage, +.x-tree-node-harddisk, +.x-grid-tree-node-expanded .x-tree-node-harddisk { + filter: invert(100%); +} + +/* Hardware icons — counter-invert for non-SVG icon cells */ +td.pve-itype-icon-storage .x-grid-cell-inner, +td.x-tree-node-harddisk .x-grid-cell-inner { + filter: invert(100%) !important; +} + +/* Hardware icons — hide inverted borders for non-SVG icon cells */ +td.pve-itype-icon-storage, +td.x-tree-node-harddisk { + border-color: transparent !important; +} + +/* Hardware grid icons — mask-image renders SVG icons in theme text color + Replaces filter:invert approach for pve-itype-icon-* and pmx-itype-icon-* grid cells */ +td.pve-itype-icon-cpu, +td.pve-itype-icon-cdrom, +td.pve-itype-icon-memory, +td.pve-itype-icon-pci, +td.pve-itype-icon-serial, +td.pve-itype-icon-die, +td.pmx-itype-icon-processor, +td.pmx-itype-icon-memory { + filter: none !important; + background-image: none !important; + padding-left: 0 !important; + border-color: transparent !important; +} + +td.pve-itype-icon-cpu .x-grid-cell-inner, +td.pve-itype-icon-cdrom .x-grid-cell-inner, +td.pve-itype-icon-memory .x-grid-cell-inner, +td.pve-itype-icon-pci .x-grid-cell-inner, +td.pve-itype-icon-serial .x-grid-cell-inner, +td.pve-itype-icon-die .x-grid-cell-inner, +td.pmx-itype-icon-processor .x-grid-cell-inner, +td.pmx-itype-icon-memory .x-grid-cell-inner { + padding-left: 3px !important; +} + +td.pve-itype-icon-cpu .x-grid-cell-inner::before, +td.pve-itype-icon-cdrom .x-grid-cell-inner::before, +td.pve-itype-icon-memory .x-grid-cell-inner::before, +td.pve-itype-icon-pci .x-grid-cell-inner::before, +td.pve-itype-icon-serial .x-grid-cell-inner::before, +td.pve-itype-icon-die .x-grid-cell-inner::before, +td.pmx-itype-icon-processor .x-grid-cell-inner::before, +td.pmx-itype-icon-memory .x-grid-cell-inner::before { + content: '' !important; + display: inline-block !important; + width: 18px !important; + height: 14px !important; + vertical-align: middle !important; + margin-right: 10px !important; + background-color: currentColor !important; + -webkit-mask-size: contain !important; + mask-size: contain !important; + -webkit-mask-repeat: no-repeat !important; + mask-repeat: no-repeat !important; + -webkit-mask-position: center !important; + mask-position: center !important; +} + +td.pve-itype-icon-cpu .x-grid-cell-inner::before { + -webkit-mask-image: url('/pve2/images/icon-cpu.svg') !important; + mask-image: url('/pve2/images/icon-cpu.svg') !important; +} + +td.pve-itype-icon-memory .x-grid-cell-inner::before { + -webkit-mask-image: url('/pve2/images/icon-memory.svg') !important; + mask-image: url('/pve2/images/icon-memory.svg') !important; +} + +td.pve-itype-icon-cdrom .x-grid-cell-inner::before { + -webkit-mask-image: url('/pve2/images/icon-cd-drive.svg') !important; + mask-image: url('/pve2/images/icon-cd-drive.svg') !important; +} + +td.pve-itype-icon-pci .x-grid-cell-inner::before { + -webkit-mask-image: url('/pve2/images/icon-pci.svg') !important; + mask-image: url('/pve2/images/icon-pci.svg') !important; +} + +td.pve-itype-icon-serial .x-grid-cell-inner::before { + -webkit-mask-image: url('/pve2/images/icon-serial.svg') !important; + mask-image: url('/pve2/images/icon-serial.svg') !important; +} + +td.pve-itype-icon-die .x-grid-cell-inner::before { + -webkit-mask-image: url('/pve2/images/icon-die.svg') !important; + mask-image: url('/pve2/images/icon-die.svg') !important; +} + +td.pmx-itype-icon-processor .x-grid-cell-inner::before { + -webkit-mask-image: url('../images/icon-cpu.svg') !important; + mask-image: url('../images/icon-cpu.svg') !important; +} + +td.pmx-itype-icon-memory .x-grid-cell-inner::before { + -webkit-mask-image: url('../images/icon-ram.svg') !important; + mask-image: url('../images/icon-ram.svg') !important; +} + + +/* Icon overlays — default */ +.x-tree-icon-custom::after, +.x-grid-icon-custom::after { + color: var(--drac-overlay2) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* RUNNING VMs/CTs — Dracula Green */ +.x-tree-icon-custom.running::after, +.x-grid-icon-custom.running::after, +.x-treelist-item-icon.running::after { + color: var(--drac-green) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* ONLINE state — Green */ +.x-tree-icon-custom.online::after, +.x-grid-icon-custom.online::after { + color: var(--drac-green) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* Stopped/offline — Overlay1 (muted gray) */ +.x-tree-icon-custom.stopped, +.x-tree-icon-custom.offline, +.x-grid-icon-custom.stopped, +.x-grid-icon-custom.offline { + color: var(--drac-overlay1) !important; +} + +/* Unknown state — Overlay1 */ +.x-tree-icon-custom.unknown::after, +.x-grid-icon-custom.unknown::after { + color: var(--drac-overlay1) !important; +} + +/* ERROR states — Dracula Red */ +.x-tree-icon-custom.error::after, +.x-tree-icon-custom.offline::after, +.x-tree-icon-custom.ha-error::after, +.x-grid-icon-custom.error::after, +.x-grid-icon-custom.offline::after, +.x-grid-icon-custom.ha-error::after { + color: var(--drac-red) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* PAUSED/SUSPENDED — Dracula Orange */ +.x-tree-icon-custom.paused::after, +.x-tree-icon-custom.suspended::after, +.x-tree-icon-custom.lock-suspending::after, +.x-grid-icon-custom.paused::after, +.x-grid-icon-custom.suspended::after, +.x-grid-icon-custom.lock-suspending::after { + color: var(--drac-orange) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* PENDING/WARNING states — Dracula Yellow */ +.x-tree-icon-custom.pending::after, +.x-tree-icon-custom.io-error::after, +.x-tree-icon-custom.internal-error::after, +.x-tree-icon-custom.guest-panicked::after, +.x-grid-icon-custom.pending::after, +.x-grid-icon-custom.io-error::after, +.x-grid-icon-custom.internal-error::after, +.x-grid-icon-custom.guest-panicked::after { + color: var(--drac-yellow) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* HA MAINTENANCE — Dracula Cyan */ +.x-tree-icon-custom.ha-maintenance::after, +.x-grid-icon-custom.ha-maintenance::after { + color: var(--drac-cyan) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* Locked icons */ +.x-tree-icon-custom.locked::after, +.x-tree-icon-custom.lock-backup::after, +.x-tree-icon-custom.lock-migrate::after, +.x-tree-icon-custom.lock-suspended::after, +.x-grid-icon-custom.locked::after, +.x-grid-icon-custom.lock-backup::after, +.x-grid-icon-custom.lock-migrate::after, +.x-grid-icon-custom.lock-suspended::after { + color: var(--drac-overlay2) !important; +} + +/* LXC/QEMU type indicators */ +.x-tree-icon-custom.lxc::after, +.x-tree-icon-custom.qemu::after, +.x-grid-icon-custom.lxc::after, +.x-grid-icon-custom.qemu::after { + background-color: transparent; + color: var(--drac-overlay1) !important; +} + +.x-treelist-item-icon.lxc::after, +.x-treelist-item-icon.qemu::after { + background-color: transparent; + color: var(--drac-overlay1) !important; +} + +/* Tree expander arrows */ +.x-tree-arrows .x-tree-expander { + filter: brightness(200%); +} + +/* Cancel sprite-inversion on custom controls (checkboxes/radios handled via CSS) */ +.x-form-checkbox-default, +.x-form-radio-default, +.x-column-header-checkbox .x-column-header-checkbox::after, +.x-grid-checkcolumn::after, +.x-menu-item-checked .x-menu-item-icon-default.x-menu-item-checkbox, +.x-menu-item-unchecked .x-menu-item-icon-default.x-menu-item-checkbox { + filter: none !important; +} + +/* ===================================================== + PANELS & HEADERS + ===================================================== */ +.x-panel, +.x-panel-default { + border-radius: var(--pm-radius-lg) !important; + padding: 0 !important; +} + +/* Column panels — native stacked layout (Issue #23 fix) */ +.x-panel.x-column { + padding: 5px !important; + margin: 0 !important; + max-width: none !important; + box-sizing: border-box !important; +} + +/* Column panel card styling — borders for summary + chart panels */ +.x-panel.x-panel-default.x-column { + border: 1px solid var(--drac-surface1) !important; + border-radius: var(--pm-radius-lg) !important; + overflow: hidden !important; +} + +/* Guest status + Notes panel borders */ +[id^="pveGuestStatusView-"].x-panel, +[id^="pveLxcStatusView-"].x-panel, +[id^="pveQemuStatusView-"].x-panel, +[id^="pmxNotesView-"].x-panel { + border: 1px solid var(--drac-surface1) !important; + border-radius: var(--pm-radius-lg) !important; +} + +.x-panel-body, +.x-panel-body-default { + background-color: var(--drac-base) !important; + color: var(--drac-text) !important; + border: none !important; +} + +/* Panel headers — bottom border only */ +.x-panel-header, +.x-panel-header-default { + background-color: var(--drac-mantle) !important; + border: none !important; + border-bottom: 1px solid var(--drac-surface1) !important; + border-radius: var(--pm-radius-lg) var(--pm-radius-lg) 0 0 !important; + margin: 0 !important; + padding: 8px 12px !important; + width: 100% !important; + box-sizing: border-box !important; + overflow: visible !important; +} + +/* Title text — prevent border-radius clipping */ +.x-title-text, +.x-title-text-default { + overflow: visible !important; +} + +.x-panel-bodyWrap, +.x-panel-bodyWrap-default { + margin: 0 !important; + padding: 0 !important; + overflow: visible !important; +} + +/* Remove borders from nested panels */ +.x-panel-body > .x-box-layout-ct, +.x-panel-body > .x-container, +.x-panel-body > .x-box-inner, +[id*="pmxGauge"] { + border: none !important; +} + +.x-panel-header-title-default, +.x-window-header-title-default { + color: var(--drac-text) !important; +} + +.x-panel-header-default .x-tool-tool-el { + background-color: transparent; +} + +.x-tool-img { + filter: brightness(175%); +} + +.x-tool-over .x-tool-img { + filter: brightness(200%); +} + +/* Resource tree — panel body border */ +div[id^="pveResourceTree-"][id$="-body"] { + border-color: var(--drac-base) !important; +} + +/* Resource tree — remove row separators */ +[id^="pveResourceTree-"].x-tree-panel td.x-grid-cell, +[id^="pveResourceTree-"].x-tree-panel .x-grid-td, +[id^="pveResourceTree-"].x-tree-panel .x-grid-cell { + border-bottom: none !important; +} + +/* Resource tree — row spacing */ +div[id^="pveResourceTree"] .x-grid-cell { + padding-top: 3px !important; + padding-bottom: 3px !important; +} + +/* Summary/stats panel radius overrides */ +.pveStatusPanel, +.x-panel-default-framed, +.x-panel-body-default-framed { + border-radius: 12px !important; +} + +.x-panel-header-default-framed { + border-radius: 12px 12px 0 0 !important; +} + +/* Column widget panel radius */ +.x-panel.x-column > .x-panel-bodyWrap > .x-panel-body.x-panel-body-default { + border-radius: var(--pm-radius-lg) !important; +} + +/* ===================================================== + SPLITTERS / SEPARATORS + ===================================================== */ +.x-splitter-vertical { + background-color: transparent !important; + border-left: 1px solid var(--drac-surface1) !important; + border-right: none !important; + width: 1px !important; +} + +.x-splitter-horizontal { + background-color: var(--drac-crust) !important; + border-top: 1px solid var(--drac-surface1) !important; +} + +.x-splitter { + background-color: var(--drac-crust) !important; +} + +.x-keyboard-mode .x-splitter-focus::after { + border-color: var(--drac-purple) !important; +} + +.x-layout-split-bottom { + opacity: 0.7; +} + +/* Toolbox tree (pve-nav) right border — full height */ +.pve-toolbar-bg { + border-right: 1px solid var(--drac-surface1) !important; + z-index: 3 !important; +} + +.x-treelist.x-treelist-pve-nav { + border-right: none !important; +} + +/* ===================================================== + TOOLBARS + ===================================================== */ +.x-toolbar, +.x-toolbar-default { + background-color: var(--drac-base) !important; + border-color: var(--drac-surface1) !important; +} + +.x-toolbar-default.x-docked-top { + border: none !important; + border-bottom: 1px solid var(--drac-surface1) !important; +} + +.x-toolbar-default .x-toolbar-separator { + border-color: var(--drac-surface1); +} + +.x-toolbar-text-default { + color: var(--drac-subtext0); +} + +/* ===================================================== + PRIMARY BUTTONS — Dracula Purple + ===================================================== */ +.x-btn-default-small { + background-color: var(--drac-purple) !important; + border: 1px solid rgba(189, 147, 249, 0.4) !important; + border-radius: var(--pm-radius-md) !important; + transition: background-color 0.15s ease, box-shadow 0.15s ease !important; +} + +.x-btn-default-small .x-btn-inner { + color: var(--drac-on-accent) !important; + font-weight: 600 !important; +} + +.x-btn-default-small .x-btn-icon-el { + color: var(--drac-on-accent) !important; +} + +.x-btn-default-small.x-btn-over, +.x-keyboard-mode .x-btn-default-small.x-btn-focus { + background-color: #caa9fa !important; + box-shadow: 0 0 0 3px var(--drac-accent-subtle) !important; +} + +.x-btn-default-small.x-btn.x-btn-disabled { + background-color: var(--drac-purple) !important; + opacity: 0.4; +} + +.x-btn-default-small.x-btn.x-btn-pressed { + background-color: #a986f0 !important; +} + +/* Button height consistency — 28px with vertical centering */ +/* Exclude tag edit buttons (display:none when hidden, :has(.fa-check) for checkmark) */ +.x-btn.x-btn-default-small:not(.x-btn-default-toolbar-small):not([style*="display: none"]):not([style*="display:none"]):not(:has(.fa-check)) { + height: 28px !important; + min-height: 28px !important; + display: flex !important; + align-items: center !important; + padding: 3px 8px !important; +} + +/* Fix button inner element centering for proper icon alignment (issue #17) */ +.x-btn.x-btn-default-small:not(.x-btn-default-toolbar-small):not([style*="display: none"]):not([style*="display:none"]):not(:has(.fa-check)) .x-btn-wrap { + display: flex !important; + align-items: center !important; +} + +.x-btn.x-btn-default-small:not(.x-btn-default-toolbar-small):not([style*="display: none"]):not([style*="display:none"]):not(:has(.fa-check)) .x-btn-inner { + display: flex !important; + align-items: center !important; +} + +/* Fix dropdown arrows on split/arrow buttons */ +.x-btn-wrap.x-btn-arrow-right::after, +.x-btn-wrap.x-btn-split-right::after { + height: 16px !important; + min-height: 16px !important; + width: 20px !important; + display: flex !important; + align-items: center !important; +} + +/* Fix icon-only buttons — hide   inner element when button has no text */ +.x-btn-no-text .x-btn-inner, +.x-btn-button.x-btn-no-text .x-btn-inner, +.x-btn-button-default-toolbar-small.x-btn-no-text .x-btn-inner-default-toolbar-small, +.x-btn-button-default-small.x-btn-no-text .x-btn-inner-default-small, +.x-btn-button-default-small.x-btn-no-text > .x-btn-inner-default-small { + display: none !important; +} + +/* Specific fix for fa-desktop icon (Create VM) — visually bottom-heavy */ +.x-btn-icon-el.fa-desktop { + transform: translateY(1.1px) !important; +} + +/* ===================================================== + SECONDARY / TOOLBAR BUTTONS + ===================================================== */ +.x-btn-default-toolbar-small { + background-color: var(--drac-surface0) !important; + border: 1px solid var(--drac-surface1) !important; + border-radius: var(--pm-radius-md) !important; + transition: background-color 0.15s ease, border-color 0.15s ease !important; +} + +.x-btn-default-toolbar-small .x-btn-inner-default-toolbar-small, +.x-btn-default-toolbar-small .x-btn-icon-el-default-toolbar-small { + color: var(--drac-text) !important; +} + +.x-btn-default-toolbar-small .x-btn-wrap-default-toolbar-small.x-btn-arrow-right::after, +.x-btn-default-toolbar-small .x-btn-wrap-default-toolbar-small.x-btn-split-right::after { + filter: brightness(150%); +} + +.x-btn-default-toolbar-small.x-btn-over, +.x-keyboard-mode .x-btn-default-toolbar-small.x-btn-focus { + background-color: var(--drac-surface1) !important; + border-color: var(--drac-surface2) !important; +} + +.x-btn-default-toolbar-small.x-btn.x-btn-disabled { + background-color: var(--drac-surface0) !important; + opacity: 0.4; +} + +.x-btn-default-toolbar-small.x-btn.x-btn-menu-active, +.x-btn-default-toolbar-small.x-btn.x-btn-pressed { + background-color: var(--drac-purple) !important; + border-color: var(--drac-purple) !important; + padding: 4px 8px !important; /* Fix #30: prevent width change on dropdown */ +} + +.x-btn-default-toolbar-small.x-btn.x-btn-pressed .x-btn-inner-default-toolbar-small, +.x-btn-default-toolbar-small.x-btn.x-btn-pressed .x-btn-icon-el-default-toolbar-small, +.x-btn-default-toolbar-small.x-btn.x-btn-pressed .x-btn-inner-default-small, +.x-btn-default-toolbar-small.x-btn.x-btn-pressed .x-btn-icon-el-default-small { + color: var(--drac-on-accent) !important; +} + +/* Segmented buttons */ +.x-segmented-button { + border-radius: var(--pm-radius-md) !important; +} + +.x-segmented-button .x-btn, +.x-segmented-button .x-btn-default-small, +.x-segmented-button .x-btn-inner, +.x-segmented-button .x-btn-wrap { + border-radius: var(--pm-radius-md) !important; +} + +/* Inline buttons (Documentation, Help) */ +.proxmox-inline-button { + height: 28px !important; + min-height: 28px !important; + display: flex !important; + align-items: center !important; + padding: 3px 8px !important; + background-color: var(--drac-surface0) !important; + border: 1px solid var(--drac-surface1) !important; + border-radius: var(--pm-radius-md) !important; + color: var(--drac-text) !important; + transition: background-color 0.15s ease !important; +} + +.proxmox-inline-button:hover, +.proxmox-inline-button.x-btn-over { + background-color: var(--drac-surface1) !important; + border-color: var(--drac-overlay0) !important; +} + +.proxmox-inline-button:active, +.proxmox-inline-button.x-btn-pressed { + background-color: var(--drac-surface2) !important; +} + +.proxmox-inline-button .x-btn-inner, +.proxmox-inline-button .x-btn-icon-el { + color: var(--drac-text) !important; +} + +/* Pressed/active inline buttons — use on-accent text */ +.proxmox-inline-button.x-btn-pressed .x-btn-inner, +.proxmox-inline-button.x-btn-pressed .x-btn-icon-el, +.proxmox-inline-button.x-btn-menu-active .x-btn-inner, +.proxmox-inline-button.x-btn-menu-active .x-btn-icon-el { + color: var(--drac-on-accent) !important; +} + +/* ===================================================== + FORM ELEMENTS + ===================================================== */ +.x-form-trigger-default { + background-color: var(--drac-surface0) !important; +} + +.x-form-text-default { + background-color: var(--drac-surface0) !important; + color: var(--drac-text) !important; + border-radius: var(--pm-radius-sm) !important; +} + +.x-form-trigger-wrap, +.x-form-trigger-wrap-default { + border-color: var(--drac-surface1) !important; + background-color: var(--drac-surface0) !important; + border-radius: var(--pm-radius-sm) !important; + transition: border-color 0.15s ease !important; +} + +.x-form-trigger-wrap-default.x-form-trigger-wrap-focus { + border-color: var(--drac-purple) !important; + box-shadow: 0 0 0 3px var(--drac-accent-subtle) !important; +} + +.x-form-item-label-default, +.x-form-cb-label-default { + color: var(--drac-text) !important; +} + +.x-form-display-field-default { + color: var(--drac-subtext0) !important; + border-radius: var(--pm-radius-md) !important; +} + +.x-form-spinner-default { + background-color: var(--drac-surface0) !important; +} + +.x-fieldset, +.x-fieldset-default { + border-color: var(--drac-surface1) !important; + border-radius: var(--pm-radius-lg) !important; +} + +.x-fieldset-header-default > .x-fieldset-header-text { + color: var(--drac-text) !important; +} + +/* ===================================================== + CHECKBOXES & RADIOS — Dracula styled + ===================================================== */ + +/* Base: remove sprite, styled as custom control */ +.x-form-checkbox, .x-form-checkbox-default, +.x-form-radio, .x-form-radio-default { + background-image: none !important; + background-color: var(--drac-surface0) !important; + border: 1.5px solid var(--drac-overlay0) !important; + width: 16px !important; + height: 16px !important; + display: inline-block !important; + box-sizing: border-box !important; + cursor: pointer !important; + transition: border-color 0.12s ease, background-color 0.12s ease !important; +} + +/* Checkbox: rounded square */ +.x-form-checkbox, .x-form-checkbox-default { + border-radius: 3px !important; +} + +/* Radio: circle + ::after inner dot */ +.x-form-radio, .x-form-radio-default { + border-radius: 50% !important; + position: relative !important; + transform: translateZ(0) !important; + box-shadow: inset 0 0 0 0 transparent !important; +} + +.x-form-radio::after { + content: '' !important; + position: absolute !important; + top: 50% !important; + left: 50% !important; + width: 7px !important; + height: 7px !important; + border-radius: 50% !important; + background: transparent !important; + transform: translate(-50%, -50%) scale(0) !important; + transition: transform 0.15s ease, background 0.15s ease !important; + pointer-events: none !important; +} + +/* Hover */ +.x-form-checkbox:hover, .x-form-checkbox-default:hover, +.x-form-cb-wrap:hover .x-form-checkbox { + border-color: var(--drac-purple) !important; +} + +.x-form-radio:hover, .x-form-radio-default:hover, +.x-form-cb-wrap:hover .x-form-radio { + border-color: var(--drac-purple) !important; +} + +/* CHECKED checkbox — Purple fill + dark SVG checkmark */ +.x-form-cb-checked .x-form-checkbox, +.x-form-cb-checked .x-form-checkbox-default { + background-color: var(--drac-purple) !important; + border-color: var(--drac-purple) !important; + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 8'%3E%3Cpath d='M1 4l3 3 5-6' fill='none' stroke='%23191a21' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") !important; + background-repeat: no-repeat !important; + background-position: center !important; + background-size: 9px 7px !important; +} + +/* SELECTED radio — Purple dot */ +.x-form-cb-checked .x-form-radio, +.x-form-cb-checked .x-form-radio-default { + border-color: var(--drac-purple) !important; + background-color: var(--drac-base) !important; +} + +.x-form-cb-checked .x-form-radio::after { + background: var(--drac-purple) !important; + transform: translate(-50%, -50%) scale(1) !important; +} + +/* ===================================================== + BOUNDLIST / DROPDOWNS + ===================================================== */ +.x-boundlist { + background-color: var(--drac-mantle) !important; + border: 1px solid var(--drac-surface1) !important; + border-radius: var(--pm-radius-md) !important; + box-shadow: 0 8px 24px rgba(30, 31, 41, 0.7) !important; + padding: 2px !important; + overflow: hidden !important; +} + +.x-boundlist-item { + background-color: transparent !important; + color: var(--drac-text) !important; + border-radius: var(--pm-radius-sm) !important; + padding: 2px 6px !important; + line-height: normal !important; + border: none !important; + cursor: pointer !important; + outline: none !important; + box-shadow: none !important; +} + +.x-boundlist-selected { + background-color: var(--drac-select-overlay) !important; + color: var(--drac-text) !important; +} + +.x-boundlist-item-over { + background-color: var(--drac-hover-overlay) !important; +} + +/* ===================================================== + GRIDS / TABLES + ===================================================== */ +.x-grid, +.x-grid-view { + border-radius: 0 !important; +} + +.x-column-header { + border-color: var(--drac-surface1) !important; + background-color: transparent !important; +} + +.x-column-header-inner, +.x-column-header-text { + color: var(--drac-text) !important; + font-weight: 600 !important; +} + +.x-column-header-trigger { + border-color: var(--drac-surface1) !important; +} + +.x-grid-item, +.x-column-header-default, +.x-grid-cell-row-numberer { + color: var(--drac-text) !important; + background-color: var(--drac-base) !important; +} + +.x-grid-cell-special { + border-color: var(--drac-surface1) !important; +} + +.x-grid-group-hd { + background-color: var(--drac-base) !important; + border-color: var(--drac-surface1) !important; +} + +.x-grid-group-title { + color: var(--drac-text) !important; +} + +.x-grid-header-ct { + background-color: var(--drac-mantle) !important; + border: 1px solid var(--drac-surface0) !important; + border-radius: var(--pm-radius-lg) var(--pm-radius-lg) 0 0 !important; +} + +.x-grid-item-alt { + background-color: var(--drac-crust) !important; +} + +.x-grid-with-row-lines .x-grid-item { + border-color: var(--drac-surface0) !important; +} + +.x-grid-cell { + border-bottom: 1px solid rgba(68, 71, 90, 0.4) !important; +} + +.x-grid-item-over, +.x-grid-with-row-lines .x-grid-item.x-grid-item-over { + background-color: var(--drac-hover-overlay) !important; +} + +.x-grid-item-selected, +.x-grid-with-row-lines .x-grid-item.x-grid-item-selected { + background-color: var(--drac-select-overlay) !important; +} + +.x-column-header-over, +.x-column-header-open { + background-color: var(--drac-hover-overlay) !important; +} + +.x-column-header-sort-ASC, +.x-column-header-sort-DESC { + background-color: var(--drac-hover-overlay) !important; +} + +.x-grid-row-summary .x-grid-cell, +.x-grid-row-summary .x-grid-rowwrap, +.x-grid-row-summary .x-grid-cell-rowbody { + background-color: var(--drac-base) !important; + border-color: var(--drac-surface1); +} + +.x-grid-with-col-lines .x-grid-cell, +.x-grid-with-col-lines .x-grid-item-over .x-grid-cell, +.x-grid-with-col-lines .x-grid-item-selected .x-grid-cell { + border-color: var(--drac-surface1) !important; +} + +.x-dd-drag-proxy { + background-color: var(--drac-mantle); + border-color: var(--drac-surface1); + color: var(--drac-text); +} + +.x-keyboard-mode .x-grid-item-focused { + background-color: var(--drac-hover-overlay) !important; + color: var(--drac-text) !important; +} + +/* Remove blue outline from focused/selected items in resource tree */ +.x-keyboard-mode .x-grid-item-focused .x-grid-cell-inner::before, +.x-keyboard-mode .x-grid-item-selected .x-grid-cell-inner::before, +.x-grid-item-selected .x-grid-cell-inner::before, +.x-grid-item-focused .x-grid-cell-inner::before, +[id^="pveResourceTree"] .x-grid-item-selected .x-grid-cell-inner::before, +[id^="pveResourceTree"] .x-grid-item-focused .x-grid-cell-inner::before { + content: none !important; + display: none !important; + border: none !important; +} + +.x-grid-empty { + background-color: var(--drac-base) !important; + color: var(--drac-subtext0) !important; +} + +/* Grid info (pve-info-grid) and RRD view */ +.pve-info-grid { + border-radius: 12px !important; +} + +.pve-rrdview, +.rrdview { + border-radius: 12px !important; +} + +.pve-summary-status, +.x-container .pve-status { + border-radius: var(--pm-radius-lg) !important; +} + +[id^="pveGuestStatusView-"][id$="-body"], +[id^="pmxNotesView-"] .x-panel-body { + border-radius: var(--pm-radius-lg) !important; +} + +.x-panel-default[id*="notes"], +.pve-notes-view { + border-radius: var(--pm-radius-lg) !important; +} + +/* Floating grid pickers (storage/ISO selectors) */ +.x-layer.x-grid .x-grid-view, +.x-panel.x-layer.x-grid .x-grid-view, +.x-panel.x-layer.x-grid, +.x-layer.x-panel.x-grid { + border-radius: var(--pm-radius-sm) !important; +} + +.x-layer.x-grid .x-grid-item-over, +.x-layer.x-grid .x-grid-item-selected, +.x-panel.x-layer.x-grid .x-grid-item-over, +.x-panel.x-layer.x-grid .x-grid-item-selected { + border-radius: var(--pm-radius-sm) !important; + outline: none !important; + box-shadow: none !important; +} + +.x-layer.x-grid .x-grid-item-over td, +.x-layer.x-grid .x-grid-item-selected td, +.x-layer.x-grid .x-grid-item-over .x-grid-cell, +.x-layer.x-grid .x-grid-item-selected .x-grid-cell, +.x-panel.x-layer.x-grid .x-grid-item-over td, +.x-panel.x-layer.x-grid .x-grid-item-selected td, +.x-panel.x-layer.x-grid .x-grid-item-over .x-grid-cell, +.x-panel.x-layer.x-grid .x-grid-item-selected .x-grid-cell { + border-radius: 0 !important; +} + +.x-layer.x-grid .x-grid-item-over td:first-child, +.x-layer.x-grid .x-grid-item-selected td:first-child, +.x-panel.x-layer.x-grid .x-grid-item-over td:first-child, +.x-panel.x-layer.x-grid .x-grid-item-selected td:first-child { + border-radius: var(--pm-radius-sm) 0 0 var(--pm-radius-sm) !important; +} + +.x-layer.x-grid .x-grid-item-over td:last-child, +.x-layer.x-grid .x-grid-item-selected td:last-child, +.x-panel.x-layer.x-grid .x-grid-item-over td:last-child, +.x-panel.x-layer.x-grid .x-grid-item-selected td:last-child { + border-radius: 0 var(--pm-radius-sm) var(--pm-radius-sm) 0 !important; +} + +/* ===================================================== + MENUS + ===================================================== */ +.x-menu, +.x-menu-default { + background-color: var(--drac-crust) !important; + border: 1px solid var(--drac-surface0) !important; + border-radius: var(--pm-radius-lg) !important; + box-shadow: 0 8px 24px rgba(30, 31, 41, 0.8) !important; + padding: 2px !important; + overflow: hidden !important; +} + +.x-menu-body-default { + background-color: transparent !important; + padding: 4px !important; +} + +.x-menu-header { + background-color: transparent !important; + color: var(--drac-text) !important; +} + +/* Menu icon separator — hide */ +.x-menu-icon-separator-default { + display: none !important; +} + +/* Menu item layout (flexbox reordering) */ +.x-menu-item-default > .x-menu-item-link { + display: flex !important; + align-items: center !important; + flex-direction: row !important; + gap: 4px !important; + justify-content: flex-start !important; + flex-wrap: nowrap !important; + border-radius: var(--pm-radius-md) !important; + padding: 4px 8px !important; + line-height: 20px !important; + cursor: pointer !important; + outline: none !important; + box-shadow: none !important; + white-space: nowrap !important; + text-decoration: none !important; +} + +.x-menu-item-text-default { + color: var(--drac-text) !important; + font-size: 13px !important; + order: 1 !important; + margin-left: 0 !important; + text-align: left !important; + line-height: 20px !important; + display: inline-flex !important; + align-items: center !important; + flex: 1 1 auto !important; + width: auto !important; + white-space: nowrap !important; +} + +.x-menu-item-icon-default { + color: var(--drac-subtext0) !important; + order: -1 !important; + position: relative !important; + float: none !important; + margin-right: 8px !important; + margin-left: 0 !important; + left: auto !important; + top: auto !important; + width: 16px !important; + text-align: center !important; + display: inline-flex !important; + align-items: center !important; + justify-content: center !important; + height: 20px !important; + line-height: 20px !important; + vertical-align: middle !important; + flex: 0 0 16px !important; + align-self: center !important; +} + +.x-menu-item-arrow, +.x-menu-item-arrow-default { + order: 2 !important; + margin-left: auto !important; +} + +.x-menu-item-default.x-menu-item-separator { + background-color: var(--drac-surface0) !important; + border: none !important; + height: 1px !important; + margin: 6px 4px !important; +} + +.x-menu-item-default.x-menu-item-focus, +.x-menu-item-default.x-menu-item-active, +.x-menu-item:hover { + background-color: var(--drac-surface0) !important; + color: var(--drac-text) !important; + border-radius: var(--pm-radius-md) !important; +} + +.x-menu-item-active .x-menu-item-text-default, +.x-menu-item-focus .x-menu-item-text-default { + color: var(--drac-text) !important; +} + +.x-menu-item-active .x-menu-item-icon-default, +.x-menu-item-focus .x-menu-item-icon-default { + color: var(--drac-cyan) !important; +} + +/* ===================================================== + PROGRESS BARS + ===================================================== */ + +/* Fix: Widget containers need overflow visible to not clip progress bars */ +.x-container[id^="pmxInfoWidget"], +.x-container.x-box-layout-ct { + overflow: visible !important; +} + +.x-progress, +.x-progress-default { + background-color: var(--drac-surface0) !important; + border-radius: 5px !important; +} + +.x-progress-default .x-progress-bar-default { + background-color: var(--drac-purple) !important; + border-radius: 5px !important; + transition: width 0.4s ease !important; +} + +.x-progress-default .x-progress-text { + color: var(--drac-text) !important; +} + +/* Text overlaid on the progress bar fill — use on-accent for contrast */ +.x-progress-bar .x-progress-text { + color: var(--drac-on-accent) !important; +} + +.x-progress.warning .x-progress-bar { + background-color: var(--drac-yellow) !important; +} + +.x-progress.critical .x-progress-bar { + background-color: var(--drac-red) !important; +} + +/* ===================================================== + TABS — Dracula underline style + Flat tabs with Purple underline on active tab + ===================================================== */ +.x-tab-bar, +.x-tab-bar-default { + background-color: var(--drac-base) !important; + border-radius: 0 !important; + border-bottom: 1px solid var(--drac-surface1) !important; + padding-bottom: 0 !important; +} + +/* Overflow visible for the underline indicator */ +.x-tab-bar .x-box-inner, +.x-tab-bar .x-box-target, +.x-tab-bar-body, +.x-tab-bar-body-default { + overflow: visible !important; +} + +/* Base tab */ +.x-tab, +.x-tab-default, +.x-tab-default-top { + background-color: transparent !important; + border: none !important; + border-radius: var(--pm-radius-md) var(--pm-radius-md) 0 0 !important; + padding: 8px 16px 8px !important; + overflow: visible !important; + margin-bottom: 0 !important; + transition: color 0.15s ease !important; + outline: none !important; + box-shadow: none !important; +} + +/* Remove ::after from inactive tabs */ +.x-tab::after { + display: none !important; +} + +.x-tab-inner-default { + color: var(--drac-subtext0) !important; + font-size: 13px !important; +} + +.x-tab-default.x-tab-over { + background-color: transparent !important; +} + +.x-tab-default.x-tab-over .x-tab-inner-default { + color: var(--drac-text) !important; +} + +/* Active tab */ +.x-tab-default.x-tab.x-tab-active { + background-color: transparent !important; + border: none !important; + overflow: visible !important; + margin-bottom: 0 !important; + outline: none !important; + box-shadow: none !important; +} + +/* Purple underline indicator on active tab */ +.x-tab-default.x-tab.x-tab-active::after { + content: '' !important; + display: block !important; + position: absolute !important; + bottom: 0 !important; + left: 0 !important; + right: 0 !important; + height: 2px !important; + background: var(--drac-purple) !important; + z-index: 10 !important; + border-radius: 2px 2px 0 0 !important; + pointer-events: none !important; +} + +.x-tab-active .x-tab-inner-default { + color: var(--drac-text) !important; + font-weight: 600 !important; +} + +.x-tab-default.x-tab.x-tab-disabled { + background-color: transparent !important; + border: none !important; + color: var(--drac-overlay0) !important; + margin-bottom: 0 !important; +} + +/* Focus states — no outline */ +.x-keyboard-mode .x-tab-default.x-tab-focus, +.x-keyboard-mode .x-tab-default.x-tab-focus.x-tab-active { + background-color: transparent !important; + border: none !important; + outline: none !important; + box-shadow: none !important; + margin-bottom: 0 !important; +} + +.x-keyboard-mode .x-tab-default.x-tab-focus.x-tab-active::after { + content: '' !important; + display: block !important; + position: absolute !important; + bottom: 0 !important; + left: 0 !important; + right: 0 !important; + height: 2px !important; + background: var(--drac-purple) !important; + z-index: 10 !important; + pointer-events: none !important; +} + +/* Kill ALL tab interaction outlines/shadows */ +.x-tab:focus, +.x-tab *:focus, +.x-tab-focus, +.x-tab-active.x-tab-focus, +.x-tab-inner-focus, +.x-tab-button-focus, +.x-tab-pressed, +.x-tab-active.x-tab-pressed, +.x-tab-over, +.x-tab:active, +.x-tab *:active { + outline: none !important; + box-shadow: none !important; +} + +.x-tabpanel-child { + border-radius: 0 0 var(--pm-radius-lg) var(--pm-radius-lg) !important; +} + +/* Tab hover/active corners */ +.x-tab-default.x-tab-over, +.x-tab-default.x-tab.x-tab-active { + border-radius: var(--pm-radius-md) var(--pm-radius-md) 0 0 !important; +} + +/* ===================================================== + TOOLTIPS + ===================================================== */ +.x-tip, +.x-tip-default { + background-color: var(--drac-mantle) !important; + border: 1px solid var(--drac-surface1) !important; + border-radius: var(--pm-radius-md) !important; + box-shadow: 0 4px 12px rgba(30, 31, 41, 0.5); +} + +.x-tip-body-default { + color: var(--drac-text) !important; +} + +.x-tip-form-invalid { + background-color: var(--drac-mantle) !important; + border-color: var(--drac-red) !important; +} + +.x-tip-body-form-invalid { + color: var(--drac-red) !important; +} + +/* ===================================================== + TREE NAVIGATION (Sidebar) + ===================================================== */ +.x-treelist-item { + background-color: var(--drac-base) !important; + border-radius: var(--pm-radius-md) !important; +} + +/* Pseudo-element approach for hover/selected highlighting */ +.x-treelist-row { + border-radius: var(--pm-radius-md) !important; + background-color: transparent !important; + position: relative !important; + z-index: 0 !important; +} + +.x-treelist-row::before { + content: ""; + position: absolute; + top: 1px; + bottom: 1px; + left: 0; + right: 4px; + border-radius: var(--pm-radius-md); + background-color: transparent; + z-index: -1; + pointer-events: none; + transition: background-color 0.15s ease; +} + +/* Fix toolbox tree item text overlapping icons */ +.x-treelist-item-text { + margin-left: 28px !important; +} + +/* Toolbox tree items — bright text */ +.x-treelist-item-text, +.x-treelist-item-icon, +.x-treelist.x-treelist-pve-nav .x-treelist-item-text, +.x-treelist.x-treelist-pve-nav .x-treelist-item-icon { + color: var(--drac-subtext1) !important; +} + +/* Hover state — apply to pseudo-element */ +.x-treelist-row-over { + background-color: transparent !important; +} + +.x-treelist-row-over::before { + background-color: var(--drac-hover-overlay) !important; +} + +.x-treelist-row-over .x-treelist-item-icon, +.x-treelist-row-over .x-treelist-item-text { + background-color: transparent !important; + color: var(--drac-text) !important; +} + +/* Selected/active item — Purple highlight */ +.x-treelist-item-selected > .x-treelist-row { + background-color: transparent !important; +} + +.x-treelist-item-selected > .x-treelist-row::before, +.x-treelist-item-selected > .x-treelist-row:hover::before { + background-color: var(--drac-purple) !important; +} + +.x-treelist-item-selected .x-treelist-item-text, +.x-treelist-item-selected .x-treelist-item-icon, +.x-treelist.x-treelist-pve-nav .x-treelist-item-selected .x-treelist-item-text, +.x-treelist.x-treelist-pve-nav .x-treelist-item-selected .x-treelist-item-icon { + color: var(--drac-on-accent) !important; +} + +.x-treelist-pve-nav { + background-color: var(--drac-base) !important; + border-color: var(--drac-surface1) !important; +} + +/* Tree navigation radius overrides */ +.x-treelist-item, +.x-treelist-item-tool { + border-radius: var(--pm-radius-sm) !important; +} + +.x-treelist-row, +.x-treelist-row:hover, +.x-treelist-row-over, +.x-treelist-item-selected > .x-treelist-row, +.x-treelist-item-selected > .x-treelist-row:hover, +.x-treelist-item-expanded > .x-treelist-row, +.x-treelist-item-expanded > .x-treelist-row-over, +.x-treelist-item-expandable > .x-treelist-row, +.x-treelist-item-expandable > .x-treelist-row-over { + border-radius: var(--pm-radius-sm) !important; +} + +.x-treelist-row::before { + border-radius: var(--pm-radius-sm) !important; +} + +.x-treelist-item-wrap, +.x-treelist-item-text, +.x-treelist-row, +.x-treelist-container, +.x-treelist-root-container, +.x-treelist, +.x-treelist-pve-nav { + border-radius: var(--pm-radius-sm) !important; +} + +/* Cursor pointer for interactive tree/grid items */ +.x-grid-cell, +.x-grid-cell-inner, +.x-tree-elbow-img, +.x-tree-icon, +.x-treelist-item, +.x-treelist-row, +.x-treelist-item-wrap, +.x-treelist-item-text, +.x-treelist-item-icon { + cursor: pointer !important; +} + +/* ===================================================== + WINDOWS / MODALS + ===================================================== */ +.x-window, +.x-window-default { + background-color: var(--drac-crust) !important; + border: 1px solid var(--drac-surface1) !important; + border-radius: var(--pm-radius-lg) !important; + box-shadow: 0 8px 24px rgba(30, 31, 41, 0.6) !important; + overflow: hidden !important; +} + +.x-window .x-window-header, +.x-window-header-default { + background-color: var(--drac-mantle) !important; + border-color: transparent !important; + border-radius: var(--pm-radius-lg) var(--pm-radius-lg) 0 0 !important; +} + +.x-window-header-default .x-mask { + background-color: rgba(30, 31, 41, 0.7); +} + +.x-window .x-window-body, +.x-window-body-default { + background-color: var(--drac-base) !important; + border-color: var(--drac-surface1) !important; + color: var(--drac-text) !important; + border-radius: 0 0 var(--pm-radius-lg) var(--pm-radius-lg) !important; +} + +.x-window-ghost { + background-color: var(--drac-base) !important; +} + +.x-window-header-default .x-tool-img { + background-color: transparent; +} + +.x-message-box .x-window-body { + background-color: var(--drac-mantle) !important; +} + +/* Respect ExtJS inline display:none on hidden dialog buttons */ +.x-message-box .x-btn.x-btn-default-small[style*="display: none"], +.x-message-box .x-btn.x-btn-default-small[style*="display:none"], +.x-window .x-toolbar-footer .x-btn[style*="display: none"], +.x-window .x-toolbar-footer .x-btn[style*="display:none"] { + display: none !important; +} + +/* Login dialog — clean inner panel borders */ +.x-window:has(#pveloginrealm) .x-panel-body { + border: none !important; + background: transparent !important; + width: auto !important; +} + +/* ===================================================== + CONSOLE / TERMINAL + ===================================================== */ +div.monitor { + border-color: var(--drac-surface1); +} + +.install-mask { + background-color: var(--drac-crust); + color: var(--drac-subtext0); +} + +.x-window.install-mask { + box-shadow: rgba(30, 31, 41, 0.5) 0 4px 20px !important; +} + +/* ===================================================== + LEGEND / CHARTS + ===================================================== */ +.x-legend-container { + background-color: var(--drac-base) !important; +} + +.x-legend-horizontal .x-legend-item { + background-color: var(--drac-mantle) !important; + color: var(--drac-text) !important; + border: 1px solid var(--drac-surface0) !important; +} + +/* Chart/RRD panel backgrounds */ +div[id*="rrdchart"], +.pve-rrddatastore, +.pmx-panel-rrd { + background-color: var(--drac-base) !important; +} + +.proxmox-rrd-panel canvas, +.proxmox-widget-toolkit canvas, +canvas.x-surface, +.x-surface canvas { + background-color: transparent !important; + opacity: 1 !important; +} + +.proxmox-rrd-panel, +.proxmox-rrd-chart { + background-color: var(--drac-base) !important; +} + +/* Chart text/labels */ +.x-surface text, +svg text { + fill: var(--drac-text) !important; +} + +/* ===================================================== + PROXMOX-SPECIFIC OVERRIDES + ===================================================== */ + +/* Logo inversion */ +img[id^="proxmoxlogo-"][id$="-img"], +img[id^="proxmoxLogoSvg-"][id$="-img"] { + filter: invert(1) hue-rotate(180deg); +} + +/* Invalid/warning/disabled rows */ +.proxmox-invalid-row { + background-color: rgba(255, 85, 85, 0.15) !important; +} + +.proxmox-warning-row { + background-color: rgba(255, 184, 108, 0.15) !important; +} + +.proxmox-disabled-row td { + color: var(--drac-overlay0) !important; +} + +/* Hints */ +.pmx-hint { + background-color: rgba(255, 184, 108, 0.15) !important; + white-space: nowrap !important; +} + +.pmx-hint a { + color: var(--drac-cyan) !important; +} + +/* Status text colors — Information → Cyan */ +.info-blue { + color: var(--drac-cyan) !important; +} + +.critical { + color: var(--drac-red) !important; +} + +/* Links */ +a { + color: var(--drac-cyan) !important; +} + +/* Markdown content */ +.pmx-md code { + background-color: var(--drac-mantle) !important; + color: var(--drac-pink) !important; + border-radius: var(--pm-radius-sm) !important; +} + +.pmx-md pre code { + border-color: var(--drac-surface1) !important; + background-color: var(--drac-crust) !important; +} + +.pmx-md a { + color: var(--drac-cyan) !important; +} + +.pmx-md table { + border-color: var(--drac-surface1) !important; +} + +.pmx-md th { + background-color: var(--drac-mantle) !important; + border-color: var(--drac-surface1) !important; +} + +.pmx-md td { + border-color: var(--drac-surface1) !important; +} + +/* APT repos */ +.proxmox-apt-repos .x-grid-group-hd { + background-color: var(--drac-base) !important; + border: none !important; +} + +.proxmox-apt-repos .x-grid-group-title { + color: var(--drac-text) !important; +} + +/* Tags */ +.pve-edit-tag { + border-radius: var(--pm-radius-md) !important; +} + +.pve-edit-tag.editable span { + background-color: var(--drac-mantle) !important; + color: var(--drac-text) !important; + border-color: var(--drac-surface1) !important; +} + +.x-tree-node-text .proxmox-tag-dark, +.x-tree-node-text .proxmox-tag-light, +.x-grid-cell-inner .proxmox-tag-dark, +.x-grid-cell-inner .proxmox-tag-light, +span.proxmox-tag-dark, +span.proxmox-tag-light { + border-radius: var(--pm-radius-md) !important; +} + +/* Checkmark button in tag edit — match toolbar button size */ +.x-btn.x-btn-default-small:has(.fa-check) { + min-height: 24px !important; + height: 24px !important; + padding: 3px 8px !important; + border-radius: var(--pm-radius-sm) !important; + background-color: var(--drac-purple) !important; + border: none !important; +} + +.x-btn.x-btn-default-small:has(.fa-check).x-btn-disabled { + background-color: transparent !important; + border: 1px solid var(--drac-surface1) !important; + opacity: 0.5 !important; +} + +.x-btn.x-btn-default-small:has(.fa-check) .fa-check { + color: var(--drac-on-accent) !important; +} + +.x-btn.x-btn-default-small:has(.fa-check).x-btn-disabled .fa-check { + color: var(--drac-overlay1) !important; +} + +.x-btn.x-btn-default-small:has(.fa-check):not(.x-btn-disabled):hover { + background-color: #caa9fa !important; +} + +.x-btn.x-btn-default-small:has(.fa-check) .x-btn-inner { + display: none !important; +} + +/* Date picker */ +.x-datepicker, +.x-datepicker-column-header, +.x-monthpicker { + background-color: var(--drac-base) !important; + color: var(--drac-text) !important; + border-color: transparent !important; +} + +.x-datepicker-header, +.x-datepicker-footer, +.x-monthpicker-buttons { + background-color: var(--drac-mantle) !important; +} + +.x-datepicker-date, +.x-monthpicker-item-inner { + color: var(--drac-text) !important; +} + +.x-datepicker-selected div.x-datepicker-date, +.x-monthpicker-item a.x-monthpicker-selected, +a.x-monthpicker-item-inner:hover, +div.x-datepicker-date:hover { + background-color: var(--drac-hover-overlay) !important; + color: var(--drac-text) !important; +} + +.x-datepicker-today .x-datepicker-date { + border-color: var(--drac-purple) !important; +} + +.x-datepicker-disabled .x-datepicker-date { + color: var(--drac-overlay0) !important; +} + +.x-datepicker-prev-day .x-datepicker-date, +.x-datepicker-next-day .x-datepicker-date { + color: var(--drac-overlay0) !important; +} + +/* Usage bars */ +.usage-wrapper, +.usage { + border-radius: 2px !important; +} + +.usage { + background-color: var(--drac-overlay2) !important; +} + +/* ===================================================== + SCROLLBARS + ===================================================== */ +::-webkit-scrollbar { + width: 8px; + height: 8px; +} + +::-webkit-scrollbar-track { + background: var(--drac-base); + border-radius: var(--pm-radius-sm); +} + +::-webkit-scrollbar-thumb { + background: var(--drac-surface2); + border-radius: var(--pm-radius-sm); + border: 1px solid transparent; + background-clip: padding-box; + transition: background 0.15s ease; +} + +::-webkit-scrollbar-thumb:hover { + background: var(--drac-overlay0); +} + +::-webkit-scrollbar-corner { + background: var(--drac-base); +} + +/* Firefox scrollbar */ +* { + scrollbar-width: thin; + scrollbar-color: var(--drac-surface2) var(--drac-base); +} + +/* ===================================================== + SELECTION HIGHLIGHT + ===================================================== */ +::selection { + background-color: rgba(98, 114, 164, 0.3); + color: var(--drac-text); +} + +/* ===================================================== + TRANSITIONS (smooth interactions) + ===================================================== */ + +/* Grid row transitions */ +.x-grid-item { + transition: background-color 0.15s ease !important; +} + +/* Tree pseudo-element transitions */ +.x-treelist-row::before { + transition: background-color 0.15s ease !important; +} + +/* Menu item transitions */ +.x-menu-item-default > .x-menu-item-link { + transition: background-color 0.12s ease !important; +} + +/* Boundlist item transitions */ +.x-boundlist-item { + transition: background-color 0.12s ease !important; +} + +/* Tab transitions */ +.x-tab { + transition: color 0.15s ease !important; +} + +/* Splitter transition */ +.x-splitter { + transition: background-color 0.15s ease !important; +} + +/* Tooltip transition */ +.x-tip { + transition: opacity 0.15s ease !important; +} + +/* Progress bar width transition */ +.x-progress-bar { + transition: width 0.4s ease !important; +} + +/* Scrollbar thumb transition */ +::-webkit-scrollbar-thumb { + transition: background 0.15s ease !important; +} + +/* Window close tool transition */ +.x-tool-img { + transition: filter 0.15s ease !important; +} + +/* ===================================================== + TOOL ICONS - FontAwesome Replacements + (Ported from UniFi v5.86) + Replace sprite-based ExtJS tool icons with crisp + FontAwesome icons for better consistency and clarity + ===================================================== */ + +/* Base styling for all tool icons - remove sprite backgrounds */ +.x-tool-tool-el.x-tool-minus, +.x-tool-img.x-tool-minus, +.x-tool-tool-el.x-tool-collapse-right, +.x-tool-img.x-tool-collapse-right, +.x-tool-tool-el.x-tool-collapse-left, +.x-tool-img.x-tool-collapse-left, +.x-tool-tool-el.x-tool-expand-right, +.x-tool-img.x-tool-expand-right, +.x-tool-tool-el.x-tool-expand-left, +.x-tool-img.x-tool-expand-left, +.x-tool-tool-el.x-tool-maximize, +.x-tool-img.x-tool-maximize, +.x-tool-tool-el.x-tool-restore, +.x-tool-img.x-tool-restore, +.x-tool-tool-el.x-tool-gear, +.x-tool-img.x-tool-gear, +.x-tool-tool-el.x-tool-refresh, +.x-tool-img.x-tool-refresh, +.x-tool-tool-el.x-tool-close, +.x-tool-img.x-tool-close { + background-image: none !important; + font-family: "FontAwesome" !important; + font-size: 14px !important; + line-height: 16px !important; + text-align: center !important; + color: var(--pm-text-dim) !important; + transition: color 0.15s ease !important; + filter: none !important; + width: 16px !important; + height: 16px !important; + display: flex !important; + align-items: center !important; + justify-content: center !important; +} + +/* Close button - slightly larger */ +.x-tool-tool-el.x-tool-close, +.x-tool-img.x-tool-close { + font-size: 20px !important; +} + +/* Individual glyph assignments */ +.x-tool-tool-el.x-tool-minus::before, +.x-tool-img.x-tool-minus::before { + content: "\f010" !important; /* fa-search-minus (zoom out) */ +} + +.x-tool-tool-el.x-tool-collapse-right::before, +.x-tool-img.x-tool-collapse-right::before { + content: "\f054" !important; /* fa-chevron-right */ +} + +.x-tool-tool-el.x-tool-expand-left::before, +.x-tool-img.x-tool-expand-left::before { + content: "\f053" !important; /* fa-chevron-left */ +} + +.x-tool-tool-el.x-tool-collapse-left::before, +.x-tool-img.x-tool-collapse-left::before { + content: "\f053" !important; /* fa-chevron-left */ +} + +.x-tool-tool-el.x-tool-expand-right::before, +.x-tool-img.x-tool-expand-right::before { + content: "\f054" !important; /* fa-chevron-right */ +} + +.x-tool-tool-el.x-tool-maximize::before, +.x-tool-img.x-tool-maximize::before { + content: "\f065" !important; /* fa-expand */ +} + +.x-tool-tool-el.x-tool-restore::before, +.x-tool-img.x-tool-restore::before { + content: "\f066" !important; /* fa-compress */ +} + +.x-tool-tool-el.x-tool-gear::before, +.x-tool-img.x-tool-gear::before { + content: "\f013" !important; /* fa-cog */ +} + +.x-tool-tool-el.x-tool-refresh::before, +.x-tool-img.x-tool-refresh::before { + content: "\f021" !important; /* fa-refresh */ +} + +.x-tool-tool-el.x-tool-close::before, +.x-tool-img.x-tool-close::before { + content: "\f00d" !important; /* fa-times */ +} + +/* Hover state - all tool icons */ +.x-tool:hover .x-tool-tool-el.x-tool-minus, +.x-tool:hover .x-tool-img.x-tool-minus, +.x-tool:hover .x-tool-tool-el.x-tool-collapse-right, +.x-tool:hover .x-tool-img.x-tool-collapse-right, +.x-tool:hover .x-tool-tool-el.x-tool-collapse-left, +.x-tool:hover .x-tool-img.x-tool-collapse-left, +.x-tool:hover .x-tool-tool-el.x-tool-expand-right, +.x-tool:hover .x-tool-img.x-tool-expand-right, +.x-tool:hover .x-tool-tool-el.x-tool-expand-left, +.x-tool:hover .x-tool-img.x-tool-expand-left, +.x-tool:hover .x-tool-tool-el.x-tool-maximize, +.x-tool:hover .x-tool-img.x-tool-maximize, +.x-tool:hover .x-tool-tool-el.x-tool-restore, +.x-tool:hover .x-tool-img.x-tool-restore, +.x-tool:hover .x-tool-tool-el.x-tool-gear, +.x-tool:hover .x-tool-img.x-tool-gear, +.x-tool:hover .x-tool-tool-el.x-tool-refresh, +.x-tool:hover .x-tool-img.x-tool-refresh, +.x-tool:hover .x-tool-tool-el.x-tool-close, +.x-tool:hover .x-tool-img.x-tool-close { + color: var(--pm-text) !important; +} + +/* Disabled state */ +.x-tool-disabled .x-tool-tool-el, +.x-tool-disabled .x-tool-img { + opacity: 0.4 !important; + cursor: default !important; +} + +/* Inline FontAwesome tools (PVE-injected) */ +.x-tool-tool-el[style*="font-family:FontAwesome"], +.x-tool-tool-el[style*="font-family: FontAwesome"] { + color: var(--pm-text-dim) !important; + font-size: 14px !important; + line-height: 16px !important; + display: flex !important; + align-items: center !important; + justify-content: center !important; + width: 16px !important; + height: 16px !important; + transition: color 0.15s ease !important; + background-image: none !important; + background-color: transparent !important; +} + +.x-tool:not(.x-tool-disabled) .x-tool-tool-el[style*="font-family:FontAwesome"], +.x-tool:not(.x-tool-disabled) .x-tool-tool-el[style*="font-family: FontAwesome"] { + cursor: pointer !important; +} + +.x-tool.x-tool-disabled .x-tool-tool-el[style*="font-family:FontAwesome"], +.x-tool.x-tool-disabled .x-tool-tool-el[style*="font-family: FontAwesome"] { + cursor: default !important; + opacity: 0.4 !important; +} + +.x-tool .x-mask { + background-color: transparent !important; + backdrop-filter: none !important; + pointer-events: none !important; +} + +.x-tool:not(.x-tool-disabled):hover .x-tool-tool-el[style*="font-family:FontAwesome"], +.x-tool:not(.x-tool-disabled):hover .x-tool-tool-el[style*="font-family: FontAwesome"] { + color: var(--pm-text) !important; +} diff --git a/themes/theme-dracula-orange.css b/themes/theme-dracula-orange.css new file mode 100644 index 0000000..743a621 --- /dev/null +++ b/themes/theme-dracula-orange.css @@ -0,0 +1,2378 @@ +/*!Dracula Orange*/ +/* + * ProxMorph Theme: Dracula Orange + * The canonical dark theme with Orange accent and warm-tinted backgrounds — ported from the Dracula specification + * Version: 1.0.0 + * Author: ProxMorph / Dracula Theme (https://draculatheme.com) + * + * v1.0.0: Initial release — Tier 2 baseline with all fixes + * - Full Dracula palette with derived shades + * - All component sections ported from UniFi/Catppuccin reference + * - Console/Terminal, Charts, Progress bars, Buttons (28px), + * Dialog fixes, Tree cursor:pointer, APT repos, Tag checkmark + * + * ─── Dracula Specification Palette ───────────────────────────── + * Background: #26201b Current Line: #433930 + * Foreground: #f8f8f2 Comment: #6272a4 + * Cyan: #8be9fd Green: #50fa7b + * Orange: #ffb86c Pink: #ff79c6 + * Purple: #bd93f9 Red: #ff5555 + * Yellow: #f1fa8c + * + * ─── Derived Shades (ProxMorph) ──────────────────────────────── + * Crust: #1a1613 Mantle: #1f1b17 + * Surface 0: #342c25 Surface 1: #433930 (= Current Line) + * Surface 2: #53483c Overlay 0: #6272a4 (= Comment) + * Overlay 1: #7c83a0 Overlay 2: #9298b8 + * Subtext 0: #b0b5c8 Subtext 1: #d0d4e0 + * Text: #f8f8f2 On-Accent: #26201b + */ + +/* ===================================================== + CSS VARIABLES + ===================================================== */ +:root { + /* Dracula Specification Tokens */ + --drac-bg: #26201b; + --drac-current-line: #433930; + --drac-fg: #f8f8f2; + --drac-comment: #6272a4; + --drac-cyan: #8be9fd; + --drac-green: #50fa7b; + --drac-orange: #ffb86c; + --drac-pink: #ff79c6; + --drac-purple: #bd93f9; + --drac-red: #ff5555; + --drac-yellow: #f1fa8c; + + /* Derived Neutral Scale */ + --drac-text: #f8f8f2; + --drac-subtext1: #d0d4e0; + --drac-subtext0: #b0b5c8; + --drac-overlay2: #9298b8; + --drac-overlay1: #7c83a0; + --drac-overlay0: #6272a4; + --drac-surface2: #53483c; + --drac-surface1: #433930; + --drac-surface0: #342c25; + --drac-base: #26201b; + --drac-mantle: #1f1b17; + --drac-crust: #1a1613; + + /* ProxMorph Semantic Variables */ + --pm-accent: var(--drac-orange); + --pm-bg-base: var(--drac-base); + --pm-bg-surface: var(--drac-surface0); + --pm-bg-elevated: var(--drac-surface1); + --pm-text: var(--drac-text); + --pm-text-dim: var(--drac-subtext1); + --pm-success: var(--drac-green); + --pm-warning: var(--drac-yellow); + --pm-error: var(--drac-red); + --pm-border: var(--drac-surface1); + --pm-radius-sm: 4px; + --pm-radius-md: 6px; + --pm-radius-lg: 8px; + + /* Proxmox Widget Toolkit Mappings (REQUIRED) */ + --pwt-panel-background: var(--drac-base); + --pwt-text-color: var(--drac-text); + --pwt-gauge-default: var(--drac-orange); + --pwt-gauge-back: var(--drac-surface1); + --pwt-gauge-warn: var(--drac-yellow); + --pwt-gauge-crit: var(--drac-red); + --pwt-chart-primary: var(--drac-orange); + --pwt-chart-grid-stroke: var(--drac-surface1); + + /* On Accent text — Background on colored backgrounds for contrast */ + --drac-on-accent: var(--drac-bg); + + /* Hover overlay — Comment@12% */ + --drac-hover-overlay: rgba(98, 114, 164, 0.12); + /* Selection overlay — Comment@25% */ + --drac-select-overlay: rgba(98, 114, 164, 0.25); + /* Accent muted (for focus rings) */ + --drac-accent-muted: rgba(255, 184, 108, 0.4); + --drac-accent-subtle: rgba(255, 184, 108, 0.15); + + color-scheme: dark; +} + +/* ===================================================== + GLOBAL BORDER-RADIUS ARCHITECTURE + (Ported from UniFi theme — reset everything, selectively re-apply) + ===================================================== */ +.x-border-box, +.x-border-box * { + border-radius: var(--pm-radius-lg); +} + +/* Remove rounded corners from grids/tables/lists */ +.x-grid, +.x-grid *, +.x-grid-header-ct, +.x-grid-header-ct *, +.x-grid-view, +.x-grid-view *, +.x-column-header, +.x-column-header *, +.x-grid-item, +.x-grid-cell, +.x-grid-cell-inner, +.x-grid-row, +table, +table *, +tr, +td, +th, +.x-legend, +.x-legend *, +.x-legend-container, +.x-legend-container *, +.x-legend-item, +.x-legend-horizontal .x-legend-item, +.x-legend-vertical .x-legend-item, +.x-legend-horizontal .x-legend-item:first-child, +.x-legend-horizontal .x-legend-item:last-child, +.x-legend-vertical .x-legend-item:first-child, +.x-legend-vertical .x-legend-item:last-child, +.x-tool, +.x-tool-tool-el, +.x-tool-default, +.x-tool-img { + border-radius: 0 !important; +} + +/* Form elements - exclude from global radius */ +.x-form-item, +.x-form-item-default, +.x-form-item-body, +.x-form-item-body-default, +.x-form-text-field-body, +.x-form-text-field-body-default, +.x-form-fieldcontainer, +.x-field, +.x-field-default, +.x-form-type-text { + border-radius: 0 !important; +} + +/* Reset layout containers that clip elements with overflow:hidden + radius */ +.x-box-layout-ct, +.x-panel-bodyWrap, +.x-panel-bodyWrap-default, +.x-autocontainer-innerCt, +.x-autocontainer-outerCt, +.x-panel.x-tabpanel-child, +.x-panel.x-box-item, +.x-box-inner, +.x-box-target, +.x-container, +.x-container-default, +.x-window .x-panel-body, +.x-window .x-window-body, +.x-window .x-window-bodyWrap { + border-radius: 0 !important; +} + +/* Reset everything inside windows to 0 — then re-apply specific radii */ +.x-window *, +.x-window .x-autocontainer-innerCt, +.x-window .x-autocontainer-outerCt, +.x-window .x-form-layout-wrap, +.x-window .x-form-layout-auto-label, +.x-window .x-form-layout-colgroup, +.x-window .x-form-layout-column, +.x-window .x-field, +.x-window .x-form-item, +.x-window .x-form-item-body { + border-radius: 0 !important; +} + +/* Chart canvas — no radius on data area */ +.x-chart-grid, +.x-chart-axis, +canvas.x-surface, +.x-chart canvas, +canvas.x-surface-canvas, +.x-surface-canvas, +.x-draw-component canvas, +.proxmox-rrd-chart canvas, +svg.x-surface, +.x-draw-container, +.x-surface { + border-radius: 0 !important; +} + +/* Legend color marker (dot) — keep circular */ +.x-legend-item-marker { + border-radius: 50% !important; +} + +/* ===================================================== + RE-APPLY BORDER RADII (selective) + ===================================================== */ + +/* Windows */ +.x-window, +.x-window-default { + border-radius: var(--pm-radius-lg) !important; +} + +.x-window-header, +.x-window-header-default { + border-radius: var(--pm-radius-lg) var(--pm-radius-lg) 0 0 !important; +} + +.x-window .x-window-body, +.x-window-body-default { + border-radius: 0 !important; +} + +/* Buttons inside windows */ +.x-window .x-btn { + border-radius: var(--pm-radius-md) !important; +} + +/* Checkboxes inside windows */ +.x-window .x-form-checkbox { + border-radius: 3px !important; +} + +/* Form inputs inside windows */ +.x-window .x-form-trigger-wrap, +.x-window .x-form-trigger-wrap-default { + border-radius: var(--pm-radius-sm) !important; +} + +.x-window .x-form-text-wrap, +.x-window .x-form-text { + border-radius: var(--pm-radius-sm) 0 0 var(--pm-radius-sm) !important; +} + +.x-window .x-form-arrow-trigger { + border-radius: 0 var(--pm-radius-sm) var(--pm-radius-sm) 0 !important; +} + +/* Form trigger/text wrap — reset and re-apply */ +.x-form-trigger-wrap, +.x-form-trigger-wrap *, +.x-form-text-wrap, +.x-form-text-wrap *, +.x-form-text, +.x-form-trigger { + border-radius: 0 !important; +} + +.x-form-trigger-wrap, +.x-form-trigger-wrap-default { + border-radius: var(--pm-radius-sm) !important; + overflow: hidden !important; +} + +.x-form-text-wrap, +.x-form-text-wrap-default { + border-radius: var(--pm-radius-sm) 0 0 var(--pm-radius-sm) !important; +} + +.x-form-text, +.x-form-text-default { + border-radius: var(--pm-radius-sm) 0 0 var(--pm-radius-sm) !important; +} + +.x-form-trigger, +.x-form-trigger-default, +.x-form-arrow-trigger, +.x-form-arrow-trigger-default { + border-radius: 0 var(--pm-radius-sm) var(--pm-radius-sm) 0 !important; +} + +/* Dialog form content padding — vertical only (horizontal causes ExtJS overflow) */ +.x-window .x-tabpanel-child .x-autocontainer-innerCt { + padding: 12px 0 !important; +} + +/* Allow column panel bodies to show overflowed form content */ +.x-window .x-panel-body:not(.x-scroller) { + overflow: visible !important; +} + +/* Side padding on column panel bodies inside windows */ +.x-window .x-panel.x-box-item .x-panel-body { + padding: 0 4px !important; +} + +/* Constrain autocontainer width inside windows */ +.x-window .x-autocontainer-outerCt { + max-width: 100% !important; +} + +/* Fix window header/body width consistency */ +.x-window > .x-window-header, +.x-window > .x-window-body, +.x-window > .x-window-bodyWrap, +.x-window-bodyWrap > .x-window-body { + width: 100% !important; +} + +.x-window-header > .x-box-inner, +.x-window-header > .x-box-inner > .x-box-target { + width: 100% !important; +} + +.x-window-header-title { + width: auto !important; + flex: 1 !important; + max-width: calc(100% - 30px) !important; +} + +/* Boundlists */ +.x-boundlist { + border-radius: var(--pm-radius-md) !important; + overflow: hidden !important; +} + +/* ===================================================== + BASE / BODY + ===================================================== */ +.x-body, +.x-viewport > .x-body, +body.x-border-layout-ct, +div.x-border-layout-ct { + background-color: var(--drac-base) !important; + color: var(--drac-text) !important; +} + +/* ===================================================== + MASKS & OVERLAYS + ===================================================== */ +.x-mask { + background-color: rgba(30, 31, 41, 0.6) !important; + backdrop-filter: blur(4px); +} + +.x-mask-msg { + background-color: var(--drac-mantle) !important; + border: 1px solid var(--drac-surface1) !important; + border-radius: var(--pm-radius-lg) !important; +} + +.x-mask-msg-text { + color: var(--drac-subtext0) !important; + filter: none !important; +} + +.x-css-shadow { + box-shadow: 0 8px 24px rgba(30, 31, 41, 0.6) !important; +} + +/* Loading indicators */ +.x-grid-row-loading, +.x-treelist-item-loading .x-treelist-item-icon, +.x-grid-tree-loading .x-tree-icon { + filter: invert(90%); +} + +/* ===================================================== + ICONS — Proxmox default colors for dark mode + ===================================================== */ + +/* General icon colors — neutral gray for dark backgrounds */ +.x-tree-icon-custom, +.x-grid-icon-custom, +.fa-tags::before, +.fa-file-o::before, +.fa-building::before, +.x-action-col-icon::before, +.fa-shield::before, +.fa-file-text-o::before, +.fa-clock-o::before, +.x-tab-icon-el-default, +.pve-icon-verify-lettering::after, +.x-tree-icon-leaf:not(.x-tree-icon-custom)::before, +.x-tree-icon-parent:not(.x-tree-icon-custom)::before, +.x-tree-icon-parent-expanded:not(.x-tree-icon-custom)::before, +.x-grid-filters-filtered-column .x-column-header-text::after { + color: var(--drac-overlay2) !important; +} + +/* Folder icons — invert for dark mode */ +.x-tree-icon-parent:not(.x-tree-icon-custom)::before, +.x-tree-icon-parent-expanded:not(.x-tree-icon-custom)::before { + filter: invert(90%); +} + +/* Various image-based icons — invert for visibility */ +.fa-ceph::before, +.fa-sdn::before, +.fa-network-wired::before, +.pve-itype-treelist-item-icon-cdrom, +.fa-chevron-right::before, +.x-grid-row-console, +.x-box-scroller-toolbar-default.x-box-scroller, +.x-tree-elbow-img, +.pve-itype-icon-qemu, +.x-tree-node-computer, +.x-grid-tree-node-expanded .x-tree-node-computer, +.pbs-icon-tape, +.pbs-icon-tape-drive, +.x-tree-icon-leaf:not(.x-tree-icon-custom), +.x-tree-icon-parent:not(.x-tree-icon-custom), +.x-tree-icon-parent-expanded:not(.x-tree-icon-custom) { + filter: invert(90%); +} + +/* Hardware icons */ +.pve-itype-icon-cpu, +.pve-itype-icon-cdrom, +.pve-itype-icon-memory, +.pve-itype-icon-pci, +.pve-itype-icon-serial, +.pve-itype-icon-die, +.pmx-itype-icon-processor, +.pmx-itype-icon-memory, +.pve-itype-icon-storage, +.x-tree-node-harddisk, +.x-grid-tree-node-expanded .x-tree-node-harddisk { + filter: invert(100%); +} + +/* Hardware icons — counter-invert for non-SVG icon cells */ +td.pve-itype-icon-storage .x-grid-cell-inner, +td.x-tree-node-harddisk .x-grid-cell-inner { + filter: invert(100%) !important; +} + +/* Hardware icons — hide inverted borders for non-SVG icon cells */ +td.pve-itype-icon-storage, +td.x-tree-node-harddisk { + border-color: transparent !important; +} + +/* Hardware grid icons — mask-image renders SVG icons in theme text color + Replaces filter:invert approach for pve-itype-icon-* and pmx-itype-icon-* grid cells */ +td.pve-itype-icon-cpu, +td.pve-itype-icon-cdrom, +td.pve-itype-icon-memory, +td.pve-itype-icon-pci, +td.pve-itype-icon-serial, +td.pve-itype-icon-die, +td.pmx-itype-icon-processor, +td.pmx-itype-icon-memory { + filter: none !important; + background-image: none !important; + padding-left: 0 !important; + border-color: transparent !important; +} + +td.pve-itype-icon-cpu .x-grid-cell-inner, +td.pve-itype-icon-cdrom .x-grid-cell-inner, +td.pve-itype-icon-memory .x-grid-cell-inner, +td.pve-itype-icon-pci .x-grid-cell-inner, +td.pve-itype-icon-serial .x-grid-cell-inner, +td.pve-itype-icon-die .x-grid-cell-inner, +td.pmx-itype-icon-processor .x-grid-cell-inner, +td.pmx-itype-icon-memory .x-grid-cell-inner { + padding-left: 3px !important; +} + +td.pve-itype-icon-cpu .x-grid-cell-inner::before, +td.pve-itype-icon-cdrom .x-grid-cell-inner::before, +td.pve-itype-icon-memory .x-grid-cell-inner::before, +td.pve-itype-icon-pci .x-grid-cell-inner::before, +td.pve-itype-icon-serial .x-grid-cell-inner::before, +td.pve-itype-icon-die .x-grid-cell-inner::before, +td.pmx-itype-icon-processor .x-grid-cell-inner::before, +td.pmx-itype-icon-memory .x-grid-cell-inner::before { + content: '' !important; + display: inline-block !important; + width: 18px !important; + height: 14px !important; + vertical-align: middle !important; + margin-right: 10px !important; + background-color: currentColor !important; + -webkit-mask-size: contain !important; + mask-size: contain !important; + -webkit-mask-repeat: no-repeat !important; + mask-repeat: no-repeat !important; + -webkit-mask-position: center !important; + mask-position: center !important; +} + +td.pve-itype-icon-cpu .x-grid-cell-inner::before { + -webkit-mask-image: url('/pve2/images/icon-cpu.svg') !important; + mask-image: url('/pve2/images/icon-cpu.svg') !important; +} + +td.pve-itype-icon-memory .x-grid-cell-inner::before { + -webkit-mask-image: url('/pve2/images/icon-memory.svg') !important; + mask-image: url('/pve2/images/icon-memory.svg') !important; +} + +td.pve-itype-icon-cdrom .x-grid-cell-inner::before { + -webkit-mask-image: url('/pve2/images/icon-cd-drive.svg') !important; + mask-image: url('/pve2/images/icon-cd-drive.svg') !important; +} + +td.pve-itype-icon-pci .x-grid-cell-inner::before { + -webkit-mask-image: url('/pve2/images/icon-pci.svg') !important; + mask-image: url('/pve2/images/icon-pci.svg') !important; +} + +td.pve-itype-icon-serial .x-grid-cell-inner::before { + -webkit-mask-image: url('/pve2/images/icon-serial.svg') !important; + mask-image: url('/pve2/images/icon-serial.svg') !important; +} + +td.pve-itype-icon-die .x-grid-cell-inner::before { + -webkit-mask-image: url('/pve2/images/icon-die.svg') !important; + mask-image: url('/pve2/images/icon-die.svg') !important; +} + +td.pmx-itype-icon-processor .x-grid-cell-inner::before { + -webkit-mask-image: url('../images/icon-cpu.svg') !important; + mask-image: url('../images/icon-cpu.svg') !important; +} + +td.pmx-itype-icon-memory .x-grid-cell-inner::before { + -webkit-mask-image: url('../images/icon-ram.svg') !important; + mask-image: url('../images/icon-ram.svg') !important; +} + + +/* Icon overlays — default */ +.x-tree-icon-custom::after, +.x-grid-icon-custom::after { + color: var(--drac-overlay2) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* RUNNING VMs/CTs — Dracula Green */ +.x-tree-icon-custom.running::after, +.x-grid-icon-custom.running::after, +.x-treelist-item-icon.running::after { + color: var(--drac-green) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* ONLINE state — Green */ +.x-tree-icon-custom.online::after, +.x-grid-icon-custom.online::after { + color: var(--drac-green) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* Stopped/offline — Overlay1 (muted gray) */ +.x-tree-icon-custom.stopped, +.x-tree-icon-custom.offline, +.x-grid-icon-custom.stopped, +.x-grid-icon-custom.offline { + color: var(--drac-overlay1) !important; +} + +/* Unknown state — Overlay1 */ +.x-tree-icon-custom.unknown::after, +.x-grid-icon-custom.unknown::after { + color: var(--drac-overlay1) !important; +} + +/* ERROR states — Dracula Red */ +.x-tree-icon-custom.error::after, +.x-tree-icon-custom.offline::after, +.x-tree-icon-custom.ha-error::after, +.x-grid-icon-custom.error::after, +.x-grid-icon-custom.offline::after, +.x-grid-icon-custom.ha-error::after { + color: var(--drac-red) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* PAUSED/SUSPENDED — Dracula Orange */ +.x-tree-icon-custom.paused::after, +.x-tree-icon-custom.suspended::after, +.x-tree-icon-custom.lock-suspending::after, +.x-grid-icon-custom.paused::after, +.x-grid-icon-custom.suspended::after, +.x-grid-icon-custom.lock-suspending::after { + color: var(--drac-orange) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* PENDING/WARNING states — Dracula Yellow */ +.x-tree-icon-custom.pending::after, +.x-tree-icon-custom.io-error::after, +.x-tree-icon-custom.internal-error::after, +.x-tree-icon-custom.guest-panicked::after, +.x-grid-icon-custom.pending::after, +.x-grid-icon-custom.io-error::after, +.x-grid-icon-custom.internal-error::after, +.x-grid-icon-custom.guest-panicked::after { + color: var(--drac-yellow) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* HA MAINTENANCE — Dracula Cyan */ +.x-tree-icon-custom.ha-maintenance::after, +.x-grid-icon-custom.ha-maintenance::after { + color: var(--drac-cyan) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* Locked icons */ +.x-tree-icon-custom.locked::after, +.x-tree-icon-custom.lock-backup::after, +.x-tree-icon-custom.lock-migrate::after, +.x-tree-icon-custom.lock-suspended::after, +.x-grid-icon-custom.locked::after, +.x-grid-icon-custom.lock-backup::after, +.x-grid-icon-custom.lock-migrate::after, +.x-grid-icon-custom.lock-suspended::after { + color: var(--drac-overlay2) !important; +} + +/* LXC/QEMU type indicators */ +.x-tree-icon-custom.lxc::after, +.x-tree-icon-custom.qemu::after, +.x-grid-icon-custom.lxc::after, +.x-grid-icon-custom.qemu::after { + background-color: transparent; + color: var(--drac-overlay1) !important; +} + +.x-treelist-item-icon.lxc::after, +.x-treelist-item-icon.qemu::after { + background-color: transparent; + color: var(--drac-overlay1) !important; +} + +/* Tree expander arrows */ +.x-tree-arrows .x-tree-expander { + filter: brightness(200%); +} + +/* Cancel sprite-inversion on custom controls (checkboxes/radios handled via CSS) */ +.x-form-checkbox-default, +.x-form-radio-default, +.x-column-header-checkbox .x-column-header-checkbox::after, +.x-grid-checkcolumn::after, +.x-menu-item-checked .x-menu-item-icon-default.x-menu-item-checkbox, +.x-menu-item-unchecked .x-menu-item-icon-default.x-menu-item-checkbox { + filter: none !important; +} + +/* ===================================================== + PANELS & HEADERS + ===================================================== */ +.x-panel, +.x-panel-default { + border-radius: var(--pm-radius-lg) !important; + padding: 0 !important; +} + +/* Column panels — native stacked layout (Issue #23 fix) */ +.x-panel.x-column { + padding: 5px !important; + margin: 0 !important; + max-width: none !important; + box-sizing: border-box !important; +} + +/* Column panel card styling — borders for summary + chart panels */ +.x-panel.x-panel-default.x-column { + border: 1px solid var(--drac-surface1) !important; + border-radius: var(--pm-radius-lg) !important; + overflow: hidden !important; +} + +/* Guest status + Notes panel borders */ +[id^="pveGuestStatusView-"].x-panel, +[id^="pveLxcStatusView-"].x-panel, +[id^="pveQemuStatusView-"].x-panel, +[id^="pmxNotesView-"].x-panel { + border: 1px solid var(--drac-surface1) !important; + border-radius: var(--pm-radius-lg) !important; +} + +.x-panel-body, +.x-panel-body-default { + background-color: var(--drac-base) !important; + color: var(--drac-text) !important; + border: none !important; +} + +/* Panel headers — bottom border only */ +.x-panel-header, +.x-panel-header-default { + background-color: var(--drac-mantle) !important; + border: none !important; + border-bottom: 1px solid var(--drac-surface1) !important; + border-radius: var(--pm-radius-lg) var(--pm-radius-lg) 0 0 !important; + margin: 0 !important; + padding: 8px 12px !important; + width: 100% !important; + box-sizing: border-box !important; + overflow: visible !important; +} + +/* Title text — prevent border-radius clipping */ +.x-title-text, +.x-title-text-default { + overflow: visible !important; +} + +.x-panel-bodyWrap, +.x-panel-bodyWrap-default { + margin: 0 !important; + padding: 0 !important; + overflow: visible !important; +} + +/* Remove borders from nested panels */ +.x-panel-body > .x-box-layout-ct, +.x-panel-body > .x-container, +.x-panel-body > .x-box-inner, +[id*="pmxGauge"] { + border: none !important; +} + +.x-panel-header-title-default, +.x-window-header-title-default { + color: var(--drac-text) !important; +} + +.x-panel-header-default .x-tool-tool-el { + background-color: transparent; +} + +.x-tool-img { + filter: brightness(175%); +} + +.x-tool-over .x-tool-img { + filter: brightness(200%); +} + +/* Resource tree — panel body border */ +div[id^="pveResourceTree-"][id$="-body"] { + border-color: var(--drac-base) !important; +} + +/* Resource tree — remove row separators */ +[id^="pveResourceTree-"].x-tree-panel td.x-grid-cell, +[id^="pveResourceTree-"].x-tree-panel .x-grid-td, +[id^="pveResourceTree-"].x-tree-panel .x-grid-cell { + border-bottom: none !important; +} + +/* Resource tree — row spacing */ +div[id^="pveResourceTree"] .x-grid-cell { + padding-top: 3px !important; + padding-bottom: 3px !important; +} + +/* Summary/stats panel radius overrides */ +.pveStatusPanel, +.x-panel-default-framed, +.x-panel-body-default-framed { + border-radius: 12px !important; +} + +.x-panel-header-default-framed { + border-radius: 12px 12px 0 0 !important; +} + +/* Column widget panel radius */ +.x-panel.x-column > .x-panel-bodyWrap > .x-panel-body.x-panel-body-default { + border-radius: var(--pm-radius-lg) !important; +} + +/* ===================================================== + SPLITTERS / SEPARATORS + ===================================================== */ +.x-splitter-vertical { + background-color: transparent !important; + border-left: 1px solid var(--drac-surface1) !important; + border-right: none !important; + width: 1px !important; +} + +.x-splitter-horizontal { + background-color: var(--drac-crust) !important; + border-top: 1px solid var(--drac-surface1) !important; +} + +.x-splitter { + background-color: var(--drac-crust) !important; +} + +.x-keyboard-mode .x-splitter-focus::after { + border-color: var(--drac-orange) !important; +} + +.x-layout-split-bottom { + opacity: 0.7; +} + +/* Toolbox tree (pve-nav) right border — full height */ +.pve-toolbar-bg { + border-right: 1px solid var(--drac-surface1) !important; + z-index: 3 !important; +} + +.x-treelist.x-treelist-pve-nav { + border-right: none !important; +} + +/* ===================================================== + TOOLBARS + ===================================================== */ +.x-toolbar, +.x-toolbar-default { + background-color: var(--drac-base) !important; + border-color: var(--drac-surface1) !important; +} + +.x-toolbar-default.x-docked-top { + border: none !important; + border-bottom: 1px solid var(--drac-surface1) !important; +} + +.x-toolbar-default .x-toolbar-separator { + border-color: var(--drac-surface1); +} + +.x-toolbar-text-default { + color: var(--drac-subtext0); +} + +/* ===================================================== + PRIMARY BUTTONS — Dracula Purple + ===================================================== */ +.x-btn-default-small { + background-color: var(--drac-orange) !important; + border: 1px solid rgba(255, 184, 108, 0.4) !important; + border-radius: var(--pm-radius-md) !important; + transition: background-color 0.15s ease, box-shadow 0.15s ease !important; +} + +.x-btn-default-small .x-btn-inner { + color: var(--drac-on-accent) !important; + font-weight: 600 !important; +} + +.x-btn-default-small .x-btn-icon-el { + color: var(--drac-on-accent) !important; +} + +.x-btn-default-small.x-btn-over, +.x-keyboard-mode .x-btn-default-small.x-btn-focus { + background-color: #ffc888 !important; + box-shadow: 0 0 0 3px var(--drac-accent-subtle) !important; +} + +.x-btn-default-small.x-btn.x-btn-disabled { + background-color: var(--drac-orange) !important; + opacity: 0.4; +} + +.x-btn-default-small.x-btn.x-btn-pressed { + background-color: #e5a55f !important; +} + +/* Button height consistency — 28px with vertical centering */ +/* Exclude tag edit buttons (display:none when hidden, :has(.fa-check) for checkmark) */ +.x-btn.x-btn-default-small:not(.x-btn-default-toolbar-small):not([style*="display: none"]):not([style*="display:none"]):not(:has(.fa-check)) { + height: 28px !important; + min-height: 28px !important; + display: flex !important; + align-items: center !important; + padding: 3px 8px !important; +} + +/* Fix button inner element centering for proper icon alignment (issue #17) */ +.x-btn.x-btn-default-small:not(.x-btn-default-toolbar-small):not([style*="display: none"]):not([style*="display:none"]):not(:has(.fa-check)) .x-btn-wrap { + display: flex !important; + align-items: center !important; +} + +.x-btn.x-btn-default-small:not(.x-btn-default-toolbar-small):not([style*="display: none"]):not([style*="display:none"]):not(:has(.fa-check)) .x-btn-inner { + display: flex !important; + align-items: center !important; +} + +/* Fix dropdown arrows on split/arrow buttons */ +.x-btn-wrap.x-btn-arrow-right::after, +.x-btn-wrap.x-btn-split-right::after { + height: 16px !important; + min-height: 16px !important; + width: 20px !important; + display: flex !important; + align-items: center !important; +} + +/* Fix icon-only buttons — hide   inner element when button has no text */ +.x-btn-no-text .x-btn-inner, +.x-btn-button.x-btn-no-text .x-btn-inner, +.x-btn-button-default-toolbar-small.x-btn-no-text .x-btn-inner-default-toolbar-small, +.x-btn-button-default-small.x-btn-no-text .x-btn-inner-default-small, +.x-btn-button-default-small.x-btn-no-text > .x-btn-inner-default-small { + display: none !important; +} + +/* Specific fix for fa-desktop icon (Create VM) — visually bottom-heavy */ +.x-btn-icon-el.fa-desktop { + transform: translateY(1.1px) !important; +} + +/* ===================================================== + SECONDARY / TOOLBAR BUTTONS + ===================================================== */ +.x-btn-default-toolbar-small { + background-color: var(--drac-surface0) !important; + border: 1px solid var(--drac-surface1) !important; + border-radius: var(--pm-radius-md) !important; + transition: background-color 0.15s ease, border-color 0.15s ease !important; +} + +.x-btn-default-toolbar-small .x-btn-inner-default-toolbar-small, +.x-btn-default-toolbar-small .x-btn-icon-el-default-toolbar-small { + color: var(--drac-text) !important; +} + +.x-btn-default-toolbar-small .x-btn-wrap-default-toolbar-small.x-btn-arrow-right::after, +.x-btn-default-toolbar-small .x-btn-wrap-default-toolbar-small.x-btn-split-right::after { + filter: brightness(150%); +} + +.x-btn-default-toolbar-small.x-btn-over, +.x-keyboard-mode .x-btn-default-toolbar-small.x-btn-focus { + background-color: var(--drac-surface1) !important; + border-color: var(--drac-surface2) !important; +} + +.x-btn-default-toolbar-small.x-btn.x-btn-disabled { + background-color: var(--drac-surface0) !important; + opacity: 0.4; +} + +.x-btn-default-toolbar-small.x-btn.x-btn-menu-active, +.x-btn-default-toolbar-small.x-btn.x-btn-pressed { + background-color: var(--drac-orange) !important; + border-color: var(--drac-orange) !important; + padding: 4px 8px !important; /* Fix #30: prevent width change on dropdown */ +} + +.x-btn-default-toolbar-small.x-btn.x-btn-pressed .x-btn-inner-default-toolbar-small, +.x-btn-default-toolbar-small.x-btn.x-btn-pressed .x-btn-icon-el-default-toolbar-small, +.x-btn-default-toolbar-small.x-btn.x-btn-pressed .x-btn-inner-default-small, +.x-btn-default-toolbar-small.x-btn.x-btn-pressed .x-btn-icon-el-default-small { + color: var(--drac-on-accent) !important; +} + +/* Segmented buttons */ +.x-segmented-button { + border-radius: var(--pm-radius-md) !important; +} + +.x-segmented-button .x-btn, +.x-segmented-button .x-btn-default-small, +.x-segmented-button .x-btn-inner, +.x-segmented-button .x-btn-wrap { + border-radius: var(--pm-radius-md) !important; +} + +/* Inline buttons (Documentation, Help) */ +.proxmox-inline-button { + height: 28px !important; + min-height: 28px !important; + display: flex !important; + align-items: center !important; + padding: 3px 8px !important; + background-color: var(--drac-surface0) !important; + border: 1px solid var(--drac-surface1) !important; + border-radius: var(--pm-radius-md) !important; + color: var(--drac-text) !important; + transition: background-color 0.15s ease !important; +} + +.proxmox-inline-button:hover, +.proxmox-inline-button.x-btn-over { + background-color: var(--drac-surface1) !important; + border-color: var(--drac-overlay0) !important; +} + +.proxmox-inline-button:active, +.proxmox-inline-button.x-btn-pressed { + background-color: var(--drac-surface2) !important; +} + +.proxmox-inline-button .x-btn-inner, +.proxmox-inline-button .x-btn-icon-el { + color: var(--drac-text) !important; +} + +/* Pressed/active inline buttons — use on-accent text */ +.proxmox-inline-button.x-btn-pressed .x-btn-inner, +.proxmox-inline-button.x-btn-pressed .x-btn-icon-el, +.proxmox-inline-button.x-btn-menu-active .x-btn-inner, +.proxmox-inline-button.x-btn-menu-active .x-btn-icon-el { + color: var(--drac-on-accent) !important; +} + +/* ===================================================== + FORM ELEMENTS + ===================================================== */ +.x-form-trigger-default { + background-color: var(--drac-surface0) !important; +} + +.x-form-text-default { + background-color: var(--drac-surface0) !important; + color: var(--drac-text) !important; + border-radius: var(--pm-radius-sm) !important; +} + +.x-form-trigger-wrap, +.x-form-trigger-wrap-default { + border-color: var(--drac-surface1) !important; + background-color: var(--drac-surface0) !important; + border-radius: var(--pm-radius-sm) !important; + transition: border-color 0.15s ease !important; +} + +.x-form-trigger-wrap-default.x-form-trigger-wrap-focus { + border-color: var(--drac-orange) !important; + box-shadow: 0 0 0 3px var(--drac-accent-subtle) !important; +} + +.x-form-item-label-default, +.x-form-cb-label-default { + color: var(--drac-text) !important; +} + +.x-form-display-field-default { + color: var(--drac-subtext0) !important; + border-radius: var(--pm-radius-md) !important; +} + +.x-form-spinner-default { + background-color: var(--drac-surface0) !important; +} + +.x-fieldset, +.x-fieldset-default { + border-color: var(--drac-surface1) !important; + border-radius: var(--pm-radius-lg) !important; +} + +.x-fieldset-header-default > .x-fieldset-header-text { + color: var(--drac-text) !important; +} + +/* ===================================================== + CHECKBOXES & RADIOS — Dracula styled + ===================================================== */ + +/* Base: remove sprite, styled as custom control */ +.x-form-checkbox, .x-form-checkbox-default, +.x-form-radio, .x-form-radio-default { + background-image: none !important; + background-color: var(--drac-surface0) !important; + border: 1.5px solid var(--drac-overlay0) !important; + width: 16px !important; + height: 16px !important; + display: inline-block !important; + box-sizing: border-box !important; + cursor: pointer !important; + transition: border-color 0.12s ease, background-color 0.12s ease !important; +} + +/* Checkbox: rounded square */ +.x-form-checkbox, .x-form-checkbox-default { + border-radius: 3px !important; +} + +/* Radio: circle + ::after inner dot */ +.x-form-radio, .x-form-radio-default { + border-radius: 50% !important; + position: relative !important; + transform: translateZ(0) !important; + box-shadow: inset 0 0 0 0 transparent !important; +} + +.x-form-radio::after { + content: '' !important; + position: absolute !important; + top: 50% !important; + left: 50% !important; + width: 7px !important; + height: 7px !important; + border-radius: 50% !important; + background: transparent !important; + transform: translate(-50%, -50%) scale(0) !important; + transition: transform 0.15s ease, background 0.15s ease !important; + pointer-events: none !important; +} + +/* Hover */ +.x-form-checkbox:hover, .x-form-checkbox-default:hover, +.x-form-cb-wrap:hover .x-form-checkbox { + border-color: var(--drac-orange) !important; +} + +.x-form-radio:hover, .x-form-radio-default:hover, +.x-form-cb-wrap:hover .x-form-radio { + border-color: var(--drac-orange) !important; +} + +/* CHECKED checkbox — Purple fill + dark SVG checkmark */ +.x-form-cb-checked .x-form-checkbox, +.x-form-cb-checked .x-form-checkbox-default { + background-color: var(--drac-orange) !important; + border-color: var(--drac-orange) !important; + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 8'%3E%3Cpath d='M1 4l3 3 5-6' fill='none' stroke='%2326201b' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") !important; + background-repeat: no-repeat !important; + background-position: center !important; + background-size: 9px 7px !important; +} + +/* SELECTED radio — Purple dot */ +.x-form-cb-checked .x-form-radio, +.x-form-cb-checked .x-form-radio-default { + border-color: var(--drac-orange) !important; + background-color: var(--drac-base) !important; +} + +.x-form-cb-checked .x-form-radio::after { + background: var(--drac-orange) !important; + transform: translate(-50%, -50%) scale(1) !important; +} + +/* ===================================================== + BOUNDLIST / DROPDOWNS + ===================================================== */ +.x-boundlist { + background-color: var(--drac-mantle) !important; + border: 1px solid var(--drac-surface1) !important; + border-radius: var(--pm-radius-md) !important; + box-shadow: 0 8px 24px rgba(30, 31, 41, 0.7) !important; + padding: 2px !important; + overflow: hidden !important; +} + +.x-boundlist-item { + background-color: transparent !important; + color: var(--drac-text) !important; + border-radius: var(--pm-radius-sm) !important; + padding: 2px 6px !important; + line-height: normal !important; + border: none !important; + cursor: pointer !important; + outline: none !important; + box-shadow: none !important; +} + +.x-boundlist-selected { + background-color: var(--drac-select-overlay) !important; + color: var(--drac-text) !important; +} + +.x-boundlist-item-over { + background-color: var(--drac-hover-overlay) !important; +} + +/* ===================================================== + GRIDS / TABLES + ===================================================== */ +.x-grid, +.x-grid-view { + border-radius: 0 !important; +} + +.x-column-header { + border-color: var(--drac-surface1) !important; + background-color: transparent !important; +} + +.x-column-header-inner, +.x-column-header-text { + color: var(--drac-text) !important; + font-weight: 600 !important; +} + +.x-column-header-trigger { + border-color: var(--drac-surface1) !important; +} + +.x-grid-item, +.x-column-header-default, +.x-grid-cell-row-numberer { + color: var(--drac-text) !important; + background-color: var(--drac-base) !important; +} + +.x-grid-cell-special { + border-color: var(--drac-surface1) !important; +} + +.x-grid-group-hd { + background-color: var(--drac-base) !important; + border-color: var(--drac-surface1) !important; +} + +.x-grid-group-title { + color: var(--drac-text) !important; +} + +.x-grid-header-ct { + background-color: var(--drac-mantle) !important; + border: 1px solid var(--drac-surface0) !important; + border-radius: var(--pm-radius-lg) var(--pm-radius-lg) 0 0 !important; +} + +.x-grid-item-alt { + background-color: var(--drac-crust) !important; +} + +.x-grid-with-row-lines .x-grid-item { + border-color: var(--drac-surface0) !important; +} + +.x-grid-cell { + border-bottom: 1px solid rgba(68, 71, 90, 0.4) !important; +} + +.x-grid-item-over, +.x-grid-with-row-lines .x-grid-item.x-grid-item-over { + background-color: var(--drac-hover-overlay) !important; +} + +.x-grid-item-selected, +.x-grid-with-row-lines .x-grid-item.x-grid-item-selected { + background-color: var(--drac-select-overlay) !important; +} + +.x-column-header-over, +.x-column-header-open { + background-color: var(--drac-hover-overlay) !important; +} + +.x-column-header-sort-ASC, +.x-column-header-sort-DESC { + background-color: var(--drac-hover-overlay) !important; +} + +.x-grid-row-summary .x-grid-cell, +.x-grid-row-summary .x-grid-rowwrap, +.x-grid-row-summary .x-grid-cell-rowbody { + background-color: var(--drac-base) !important; + border-color: var(--drac-surface1); +} + +.x-grid-with-col-lines .x-grid-cell, +.x-grid-with-col-lines .x-grid-item-over .x-grid-cell, +.x-grid-with-col-lines .x-grid-item-selected .x-grid-cell { + border-color: var(--drac-surface1) !important; +} + +.x-dd-drag-proxy { + background-color: var(--drac-mantle); + border-color: var(--drac-surface1); + color: var(--drac-text); +} + +.x-keyboard-mode .x-grid-item-focused { + background-color: var(--drac-hover-overlay) !important; + color: var(--drac-text) !important; +} + +/* Remove blue outline from focused/selected items in resource tree */ +.x-keyboard-mode .x-grid-item-focused .x-grid-cell-inner::before, +.x-keyboard-mode .x-grid-item-selected .x-grid-cell-inner::before, +.x-grid-item-selected .x-grid-cell-inner::before, +.x-grid-item-focused .x-grid-cell-inner::before, +[id^="pveResourceTree"] .x-grid-item-selected .x-grid-cell-inner::before, +[id^="pveResourceTree"] .x-grid-item-focused .x-grid-cell-inner::before { + content: none !important; + display: none !important; + border: none !important; +} + +.x-grid-empty { + background-color: var(--drac-base) !important; + color: var(--drac-subtext0) !important; +} + +/* Grid info (pve-info-grid) and RRD view */ +.pve-info-grid { + border-radius: 12px !important; +} + +.pve-rrdview, +.rrdview { + border-radius: 12px !important; +} + +.pve-summary-status, +.x-container .pve-status { + border-radius: var(--pm-radius-lg) !important; +} + +[id^="pveGuestStatusView-"][id$="-body"], +[id^="pmxNotesView-"] .x-panel-body { + border-radius: var(--pm-radius-lg) !important; +} + +.x-panel-default[id*="notes"], +.pve-notes-view { + border-radius: var(--pm-radius-lg) !important; +} + +/* Floating grid pickers (storage/ISO selectors) */ +.x-layer.x-grid .x-grid-view, +.x-panel.x-layer.x-grid .x-grid-view, +.x-panel.x-layer.x-grid, +.x-layer.x-panel.x-grid { + border-radius: var(--pm-radius-sm) !important; +} + +.x-layer.x-grid .x-grid-item-over, +.x-layer.x-grid .x-grid-item-selected, +.x-panel.x-layer.x-grid .x-grid-item-over, +.x-panel.x-layer.x-grid .x-grid-item-selected { + border-radius: var(--pm-radius-sm) !important; + outline: none !important; + box-shadow: none !important; +} + +.x-layer.x-grid .x-grid-item-over td, +.x-layer.x-grid .x-grid-item-selected td, +.x-layer.x-grid .x-grid-item-over .x-grid-cell, +.x-layer.x-grid .x-grid-item-selected .x-grid-cell, +.x-panel.x-layer.x-grid .x-grid-item-over td, +.x-panel.x-layer.x-grid .x-grid-item-selected td, +.x-panel.x-layer.x-grid .x-grid-item-over .x-grid-cell, +.x-panel.x-layer.x-grid .x-grid-item-selected .x-grid-cell { + border-radius: 0 !important; +} + +.x-layer.x-grid .x-grid-item-over td:first-child, +.x-layer.x-grid .x-grid-item-selected td:first-child, +.x-panel.x-layer.x-grid .x-grid-item-over td:first-child, +.x-panel.x-layer.x-grid .x-grid-item-selected td:first-child { + border-radius: var(--pm-radius-sm) 0 0 var(--pm-radius-sm) !important; +} + +.x-layer.x-grid .x-grid-item-over td:last-child, +.x-layer.x-grid .x-grid-item-selected td:last-child, +.x-panel.x-layer.x-grid .x-grid-item-over td:last-child, +.x-panel.x-layer.x-grid .x-grid-item-selected td:last-child { + border-radius: 0 var(--pm-radius-sm) var(--pm-radius-sm) 0 !important; +} + +/* ===================================================== + MENUS + ===================================================== */ +.x-menu, +.x-menu-default { + background-color: var(--drac-crust) !important; + border: 1px solid var(--drac-surface0) !important; + border-radius: var(--pm-radius-lg) !important; + box-shadow: 0 8px 24px rgba(30, 31, 41, 0.8) !important; + padding: 2px !important; + overflow: hidden !important; +} + +.x-menu-body-default { + background-color: transparent !important; + padding: 4px !important; +} + +.x-menu-header { + background-color: transparent !important; + color: var(--drac-text) !important; +} + +/* Menu icon separator — hide */ +.x-menu-icon-separator-default { + display: none !important; +} + +/* Menu item layout (flexbox reordering) */ +.x-menu-item-default > .x-menu-item-link { + display: flex !important; + align-items: center !important; + flex-direction: row !important; + gap: 4px !important; + justify-content: flex-start !important; + flex-wrap: nowrap !important; + border-radius: var(--pm-radius-md) !important; + padding: 4px 8px !important; + line-height: 20px !important; + cursor: pointer !important; + outline: none !important; + box-shadow: none !important; + white-space: nowrap !important; + text-decoration: none !important; +} + +.x-menu-item-text-default { + color: var(--drac-text) !important; + font-size: 13px !important; + order: 1 !important; + margin-left: 0 !important; + text-align: left !important; + line-height: 20px !important; + display: inline-flex !important; + align-items: center !important; + flex: 1 1 auto !important; + width: auto !important; + white-space: nowrap !important; +} + +.x-menu-item-icon-default { + color: var(--drac-subtext0) !important; + order: -1 !important; + position: relative !important; + float: none !important; + margin-right: 8px !important; + margin-left: 0 !important; + left: auto !important; + top: auto !important; + width: 16px !important; + text-align: center !important; + display: inline-flex !important; + align-items: center !important; + justify-content: center !important; + height: 20px !important; + line-height: 20px !important; + vertical-align: middle !important; + flex: 0 0 16px !important; + align-self: center !important; +} + +.x-menu-item-arrow, +.x-menu-item-arrow-default { + order: 2 !important; + margin-left: auto !important; +} + +.x-menu-item-default.x-menu-item-separator { + background-color: var(--drac-surface0) !important; + border: none !important; + height: 1px !important; + margin: 6px 4px !important; +} + +.x-menu-item-default.x-menu-item-focus, +.x-menu-item-default.x-menu-item-active, +.x-menu-item:hover { + background-color: var(--drac-surface0) !important; + color: var(--drac-text) !important; + border-radius: var(--pm-radius-md) !important; +} + +.x-menu-item-active .x-menu-item-text-default, +.x-menu-item-focus .x-menu-item-text-default { + color: var(--drac-text) !important; +} + +.x-menu-item-active .x-menu-item-icon-default, +.x-menu-item-focus .x-menu-item-icon-default { + color: var(--drac-cyan) !important; +} + +/* ===================================================== + PROGRESS BARS + ===================================================== */ + +/* Fix: Widget containers need overflow visible to not clip progress bars */ +.x-container[id^="pmxInfoWidget"], +.x-container.x-box-layout-ct { + overflow: visible !important; +} + +.x-progress, +.x-progress-default { + background-color: var(--drac-surface0) !important; + border-radius: 5px !important; +} + +.x-progress-default .x-progress-bar-default { + background-color: var(--drac-orange) !important; + border-radius: 5px !important; + transition: width 0.4s ease !important; +} + +.x-progress-default .x-progress-text { + color: var(--drac-text) !important; +} + +/* Text overlaid on the progress bar fill — use on-accent for contrast */ +.x-progress-bar .x-progress-text { + color: var(--drac-on-accent) !important; +} + +.x-progress.warning .x-progress-bar { + background-color: var(--drac-yellow) !important; +} + +.x-progress.critical .x-progress-bar { + background-color: var(--drac-red) !important; +} + +/* ===================================================== + TABS — Dracula underline style + Flat tabs with Purple underline on active tab + ===================================================== */ +.x-tab-bar, +.x-tab-bar-default { + background-color: var(--drac-base) !important; + border-radius: 0 !important; + border-bottom: 1px solid var(--drac-surface1) !important; + padding-bottom: 0 !important; +} + +/* Overflow visible for the underline indicator */ +.x-tab-bar .x-box-inner, +.x-tab-bar .x-box-target, +.x-tab-bar-body, +.x-tab-bar-body-default { + overflow: visible !important; +} + +/* Base tab */ +.x-tab, +.x-tab-default, +.x-tab-default-top { + background-color: transparent !important; + border: none !important; + border-radius: var(--pm-radius-md) var(--pm-radius-md) 0 0 !important; + padding: 8px 16px 8px !important; + overflow: visible !important; + margin-bottom: 0 !important; + transition: color 0.15s ease !important; + outline: none !important; + box-shadow: none !important; +} + +/* Remove ::after from inactive tabs */ +.x-tab::after { + display: none !important; +} + +.x-tab-inner-default { + color: var(--drac-subtext0) !important; + font-size: 13px !important; +} + +.x-tab-default.x-tab-over { + background-color: transparent !important; +} + +.x-tab-default.x-tab-over .x-tab-inner-default { + color: var(--drac-text) !important; +} + +/* Active tab */ +.x-tab-default.x-tab.x-tab-active { + background-color: transparent !important; + border: none !important; + overflow: visible !important; + margin-bottom: 0 !important; + outline: none !important; + box-shadow: none !important; +} + +/* Purple underline indicator on active tab */ +.x-tab-default.x-tab.x-tab-active::after { + content: '' !important; + display: block !important; + position: absolute !important; + bottom: 0 !important; + left: 0 !important; + right: 0 !important; + height: 2px !important; + background: var(--drac-orange) !important; + z-index: 10 !important; + border-radius: 2px 2px 0 0 !important; + pointer-events: none !important; +} + +.x-tab-active .x-tab-inner-default { + color: var(--drac-text) !important; + font-weight: 600 !important; +} + +.x-tab-default.x-tab.x-tab-disabled { + background-color: transparent !important; + border: none !important; + color: var(--drac-overlay0) !important; + margin-bottom: 0 !important; +} + +/* Focus states — no outline */ +.x-keyboard-mode .x-tab-default.x-tab-focus, +.x-keyboard-mode .x-tab-default.x-tab-focus.x-tab-active { + background-color: transparent !important; + border: none !important; + outline: none !important; + box-shadow: none !important; + margin-bottom: 0 !important; +} + +.x-keyboard-mode .x-tab-default.x-tab-focus.x-tab-active::after { + content: '' !important; + display: block !important; + position: absolute !important; + bottom: 0 !important; + left: 0 !important; + right: 0 !important; + height: 2px !important; + background: var(--drac-orange) !important; + z-index: 10 !important; + pointer-events: none !important; +} + +/* Kill ALL tab interaction outlines/shadows */ +.x-tab:focus, +.x-tab *:focus, +.x-tab-focus, +.x-tab-active.x-tab-focus, +.x-tab-inner-focus, +.x-tab-button-focus, +.x-tab-pressed, +.x-tab-active.x-tab-pressed, +.x-tab-over, +.x-tab:active, +.x-tab *:active { + outline: none !important; + box-shadow: none !important; +} + +.x-tabpanel-child { + border-radius: 0 0 var(--pm-radius-lg) var(--pm-radius-lg) !important; +} + +/* Tab hover/active corners */ +.x-tab-default.x-tab-over, +.x-tab-default.x-tab.x-tab-active { + border-radius: var(--pm-radius-md) var(--pm-radius-md) 0 0 !important; +} + +/* ===================================================== + TOOLTIPS + ===================================================== */ +.x-tip, +.x-tip-default { + background-color: var(--drac-mantle) !important; + border: 1px solid var(--drac-surface1) !important; + border-radius: var(--pm-radius-md) !important; + box-shadow: 0 4px 12px rgba(30, 31, 41, 0.5); +} + +.x-tip-body-default { + color: var(--drac-text) !important; +} + +.x-tip-form-invalid { + background-color: var(--drac-mantle) !important; + border-color: var(--drac-red) !important; +} + +.x-tip-body-form-invalid { + color: var(--drac-red) !important; +} + +/* ===================================================== + TREE NAVIGATION (Sidebar) + ===================================================== */ +.x-treelist-item { + background-color: var(--drac-base) !important; + border-radius: var(--pm-radius-md) !important; +} + +/* Pseudo-element approach for hover/selected highlighting */ +.x-treelist-row { + border-radius: var(--pm-radius-md) !important; + background-color: transparent !important; + position: relative !important; + z-index: 0 !important; +} + +.x-treelist-row::before { + content: ""; + position: absolute; + top: 1px; + bottom: 1px; + left: 0; + right: 4px; + border-radius: var(--pm-radius-md); + background-color: transparent; + z-index: -1; + pointer-events: none; + transition: background-color 0.15s ease; +} + +/* Fix toolbox tree item text overlapping icons */ +.x-treelist-item-text { + margin-left: 28px !important; +} + +/* Toolbox tree items — bright text */ +.x-treelist-item-text, +.x-treelist-item-icon, +.x-treelist.x-treelist-pve-nav .x-treelist-item-text, +.x-treelist.x-treelist-pve-nav .x-treelist-item-icon { + color: var(--drac-subtext1) !important; +} + +/* Hover state — apply to pseudo-element */ +.x-treelist-row-over { + background-color: transparent !important; +} + +.x-treelist-row-over::before { + background-color: var(--drac-hover-overlay) !important; +} + +.x-treelist-row-over .x-treelist-item-icon, +.x-treelist-row-over .x-treelist-item-text { + background-color: transparent !important; + color: var(--drac-text) !important; +} + +/* Selected/active item — Purple highlight */ +.x-treelist-item-selected > .x-treelist-row { + background-color: transparent !important; +} + +.x-treelist-item-selected > .x-treelist-row::before, +.x-treelist-item-selected > .x-treelist-row:hover::before { + background-color: var(--drac-orange) !important; +} + +.x-treelist-item-selected .x-treelist-item-text, +.x-treelist-item-selected .x-treelist-item-icon, +.x-treelist.x-treelist-pve-nav .x-treelist-item-selected .x-treelist-item-text, +.x-treelist.x-treelist-pve-nav .x-treelist-item-selected .x-treelist-item-icon { + color: var(--drac-on-accent) !important; +} + +.x-treelist-pve-nav { + background-color: var(--drac-base) !important; + border-color: var(--drac-surface1) !important; +} + +/* Tree navigation radius overrides */ +.x-treelist-item, +.x-treelist-item-tool { + border-radius: var(--pm-radius-sm) !important; +} + +.x-treelist-row, +.x-treelist-row:hover, +.x-treelist-row-over, +.x-treelist-item-selected > .x-treelist-row, +.x-treelist-item-selected > .x-treelist-row:hover, +.x-treelist-item-expanded > .x-treelist-row, +.x-treelist-item-expanded > .x-treelist-row-over, +.x-treelist-item-expandable > .x-treelist-row, +.x-treelist-item-expandable > .x-treelist-row-over { + border-radius: var(--pm-radius-sm) !important; +} + +.x-treelist-row::before { + border-radius: var(--pm-radius-sm) !important; +} + +.x-treelist-item-wrap, +.x-treelist-item-text, +.x-treelist-row, +.x-treelist-container, +.x-treelist-root-container, +.x-treelist, +.x-treelist-pve-nav { + border-radius: var(--pm-radius-sm) !important; +} + +/* Cursor pointer for interactive tree/grid items */ +.x-grid-cell, +.x-grid-cell-inner, +.x-tree-elbow-img, +.x-tree-icon, +.x-treelist-item, +.x-treelist-row, +.x-treelist-item-wrap, +.x-treelist-item-text, +.x-treelist-item-icon { + cursor: pointer !important; +} + +/* ===================================================== + WINDOWS / MODALS + ===================================================== */ +.x-window, +.x-window-default { + background-color: var(--drac-crust) !important; + border: 1px solid var(--drac-surface1) !important; + border-radius: var(--pm-radius-lg) !important; + box-shadow: 0 8px 24px rgba(30, 31, 41, 0.6) !important; + overflow: hidden !important; +} + +.x-window .x-window-header, +.x-window-header-default { + background-color: var(--drac-mantle) !important; + border-color: transparent !important; + border-radius: var(--pm-radius-lg) var(--pm-radius-lg) 0 0 !important; +} + +.x-window-header-default .x-mask { + background-color: rgba(30, 31, 41, 0.7); +} + +.x-window .x-window-body, +.x-window-body-default { + background-color: var(--drac-base) !important; + border-color: var(--drac-surface1) !important; + color: var(--drac-text) !important; + border-radius: 0 0 var(--pm-radius-lg) var(--pm-radius-lg) !important; +} + +.x-window-ghost { + background-color: var(--drac-base) !important; +} + +.x-window-header-default .x-tool-img { + background-color: transparent; +} + +.x-message-box .x-window-body { + background-color: var(--drac-mantle) !important; +} + +/* Respect ExtJS inline display:none on hidden dialog buttons */ +.x-message-box .x-btn.x-btn-default-small[style*="display: none"], +.x-message-box .x-btn.x-btn-default-small[style*="display:none"], +.x-window .x-toolbar-footer .x-btn[style*="display: none"], +.x-window .x-toolbar-footer .x-btn[style*="display:none"] { + display: none !important; +} + +/* Login dialog — clean inner panel borders */ +.x-window:has(#pveloginrealm) .x-panel-body { + border: none !important; + background: transparent !important; + width: auto !important; +} + +/* ===================================================== + CONSOLE / TERMINAL + ===================================================== */ +div.monitor { + border-color: var(--drac-surface1); +} + +.install-mask { + background-color: var(--drac-crust); + color: var(--drac-subtext0); +} + +.x-window.install-mask { + box-shadow: rgba(30, 31, 41, 0.5) 0 4px 20px !important; +} + +/* ===================================================== + LEGEND / CHARTS + ===================================================== */ +.x-legend-container { + background-color: var(--drac-base) !important; +} + +.x-legend-horizontal .x-legend-item { + background-color: var(--drac-mantle) !important; + color: var(--drac-text) !important; + border: 1px solid var(--drac-surface0) !important; +} + +/* Chart/RRD panel backgrounds */ +div[id*="rrdchart"], +.pve-rrddatastore, +.pmx-panel-rrd { + background-color: var(--drac-base) !important; +} + +.proxmox-rrd-panel canvas, +.proxmox-widget-toolkit canvas, +canvas.x-surface, +.x-surface canvas { + background-color: transparent !important; + opacity: 1 !important; +} + +.proxmox-rrd-panel, +.proxmox-rrd-chart { + background-color: var(--drac-base) !important; +} + +/* Chart text/labels */ +.x-surface text, +svg text { + fill: var(--drac-text) !important; +} + +/* ===================================================== + PROXMOX-SPECIFIC OVERRIDES + ===================================================== */ + +/* Logo inversion */ +img[id^="proxmoxlogo-"][id$="-img"], +img[id^="proxmoxLogoSvg-"][id$="-img"] { + filter: invert(1) hue-rotate(180deg); +} + +/* Invalid/warning/disabled rows */ +.proxmox-invalid-row { + background-color: rgba(255, 85, 85, 0.15) !important; +} + +.proxmox-warning-row { + background-color: rgba(255, 184, 108, 0.15) !important; +} + +.proxmox-disabled-row td { + color: var(--drac-overlay0) !important; +} + +/* Hints */ +.pmx-hint { + background-color: rgba(255, 184, 108, 0.15) !important; + white-space: nowrap !important; +} + +.pmx-hint a { + color: var(--drac-cyan) !important; +} + +/* Status text colors — Information → Cyan */ +.info-blue { + color: var(--drac-cyan) !important; +} + +.critical { + color: var(--drac-red) !important; +} + +/* Links */ +a { + color: var(--drac-cyan) !important; +} + +/* Markdown content */ +.pmx-md code { + background-color: var(--drac-mantle) !important; + color: var(--drac-pink) !important; + border-radius: var(--pm-radius-sm) !important; +} + +.pmx-md pre code { + border-color: var(--drac-surface1) !important; + background-color: var(--drac-crust) !important; +} + +.pmx-md a { + color: var(--drac-cyan) !important; +} + +.pmx-md table { + border-color: var(--drac-surface1) !important; +} + +.pmx-md th { + background-color: var(--drac-mantle) !important; + border-color: var(--drac-surface1) !important; +} + +.pmx-md td { + border-color: var(--drac-surface1) !important; +} + +/* APT repos */ +.proxmox-apt-repos .x-grid-group-hd { + background-color: var(--drac-base) !important; + border: none !important; +} + +.proxmox-apt-repos .x-grid-group-title { + color: var(--drac-text) !important; +} + +/* Tags */ +.pve-edit-tag { + border-radius: var(--pm-radius-md) !important; +} + +.pve-edit-tag.editable span { + background-color: var(--drac-mantle) !important; + color: var(--drac-text) !important; + border-color: var(--drac-surface1) !important; +} + +.x-tree-node-text .proxmox-tag-dark, +.x-tree-node-text .proxmox-tag-light, +.x-grid-cell-inner .proxmox-tag-dark, +.x-grid-cell-inner .proxmox-tag-light, +span.proxmox-tag-dark, +span.proxmox-tag-light { + border-radius: var(--pm-radius-md) !important; +} + +/* Checkmark button in tag edit — match toolbar button size */ +.x-btn.x-btn-default-small:has(.fa-check) { + min-height: 24px !important; + height: 24px !important; + padding: 3px 8px !important; + border-radius: var(--pm-radius-sm) !important; + background-color: var(--drac-orange) !important; + border: none !important; +} + +.x-btn.x-btn-default-small:has(.fa-check).x-btn-disabled { + background-color: transparent !important; + border: 1px solid var(--drac-surface1) !important; + opacity: 0.5 !important; +} + +.x-btn.x-btn-default-small:has(.fa-check) .fa-check { + color: var(--drac-on-accent) !important; +} + +.x-btn.x-btn-default-small:has(.fa-check).x-btn-disabled .fa-check { + color: var(--drac-overlay1) !important; +} + +.x-btn.x-btn-default-small:has(.fa-check):not(.x-btn-disabled):hover { + background-color: #ffc888 !important; +} + +.x-btn.x-btn-default-small:has(.fa-check) .x-btn-inner { + display: none !important; +} + +/* Date picker */ +.x-datepicker, +.x-datepicker-column-header, +.x-monthpicker { + background-color: var(--drac-base) !important; + color: var(--drac-text) !important; + border-color: transparent !important; +} + +.x-datepicker-header, +.x-datepicker-footer, +.x-monthpicker-buttons { + background-color: var(--drac-mantle) !important; +} + +.x-datepicker-date, +.x-monthpicker-item-inner { + color: var(--drac-text) !important; +} + +.x-datepicker-selected div.x-datepicker-date, +.x-monthpicker-item a.x-monthpicker-selected, +a.x-monthpicker-item-inner:hover, +div.x-datepicker-date:hover { + background-color: var(--drac-hover-overlay) !important; + color: var(--drac-text) !important; +} + +.x-datepicker-today .x-datepicker-date { + border-color: var(--drac-orange) !important; +} + +.x-datepicker-disabled .x-datepicker-date { + color: var(--drac-overlay0) !important; +} + +.x-datepicker-prev-day .x-datepicker-date, +.x-datepicker-next-day .x-datepicker-date { + color: var(--drac-overlay0) !important; +} + +/* Usage bars */ +.usage-wrapper, +.usage { + border-radius: 2px !important; +} + +.usage { + background-color: var(--drac-overlay2) !important; +} + +/* ===================================================== + SCROLLBARS + ===================================================== */ +::-webkit-scrollbar { + width: 8px; + height: 8px; +} + +::-webkit-scrollbar-track { + background: var(--drac-base); + border-radius: var(--pm-radius-sm); +} + +::-webkit-scrollbar-thumb { + background: var(--drac-surface2); + border-radius: var(--pm-radius-sm); + border: 1px solid transparent; + background-clip: padding-box; + transition: background 0.15s ease; +} + +::-webkit-scrollbar-thumb:hover { + background: var(--drac-overlay0); +} + +::-webkit-scrollbar-corner { + background: var(--drac-base); +} + +/* Firefox scrollbar */ +* { + scrollbar-width: thin; + scrollbar-color: var(--drac-surface2) var(--drac-base); +} + +/* ===================================================== + SELECTION HIGHLIGHT + ===================================================== */ +::selection { + background-color: rgba(98, 114, 164, 0.3); + color: var(--drac-text); +} + +/* ===================================================== + TRANSITIONS (smooth interactions) + ===================================================== */ + +/* Grid row transitions */ +.x-grid-item { + transition: background-color 0.15s ease !important; +} + +/* Tree pseudo-element transitions */ +.x-treelist-row::before { + transition: background-color 0.15s ease !important; +} + +/* Menu item transitions */ +.x-menu-item-default > .x-menu-item-link { + transition: background-color 0.12s ease !important; +} + +/* Boundlist item transitions */ +.x-boundlist-item { + transition: background-color 0.12s ease !important; +} + +/* Tab transitions */ +.x-tab { + transition: color 0.15s ease !important; +} + +/* Splitter transition */ +.x-splitter { + transition: background-color 0.15s ease !important; +} + +/* Tooltip transition */ +.x-tip { + transition: opacity 0.15s ease !important; +} + +/* Progress bar width transition */ +.x-progress-bar { + transition: width 0.4s ease !important; +} + +/* Scrollbar thumb transition */ +::-webkit-scrollbar-thumb { + transition: background 0.15s ease !important; +} + +/* Window close tool transition */ +.x-tool-img { + transition: filter 0.15s ease !important; +} + +/* ===================================================== + TOOL ICONS - FontAwesome Replacements + (Ported from UniFi v5.86) + Replace sprite-based ExtJS tool icons with crisp + FontAwesome icons for better consistency and clarity + ===================================================== */ + +/* Base styling for all tool icons - remove sprite backgrounds */ +.x-tool-tool-el.x-tool-minus, +.x-tool-img.x-tool-minus, +.x-tool-tool-el.x-tool-collapse-right, +.x-tool-img.x-tool-collapse-right, +.x-tool-tool-el.x-tool-collapse-left, +.x-tool-img.x-tool-collapse-left, +.x-tool-tool-el.x-tool-expand-right, +.x-tool-img.x-tool-expand-right, +.x-tool-tool-el.x-tool-expand-left, +.x-tool-img.x-tool-expand-left, +.x-tool-tool-el.x-tool-maximize, +.x-tool-img.x-tool-maximize, +.x-tool-tool-el.x-tool-restore, +.x-tool-img.x-tool-restore, +.x-tool-tool-el.x-tool-gear, +.x-tool-img.x-tool-gear, +.x-tool-tool-el.x-tool-refresh, +.x-tool-img.x-tool-refresh, +.x-tool-tool-el.x-tool-close, +.x-tool-img.x-tool-close { + background-image: none !important; + font-family: "FontAwesome" !important; + font-size: 14px !important; + line-height: 16px !important; + text-align: center !important; + color: var(--pm-text-dim) !important; + transition: color 0.15s ease !important; + filter: none !important; + width: 16px !important; + height: 16px !important; + display: flex !important; + align-items: center !important; + justify-content: center !important; +} + +/* Close button - slightly larger */ +.x-tool-tool-el.x-tool-close, +.x-tool-img.x-tool-close { + font-size: 20px !important; +} + +/* Individual glyph assignments */ +.x-tool-tool-el.x-tool-minus::before, +.x-tool-img.x-tool-minus::before { + content: "\f010" !important; /* fa-search-minus (zoom out) */ +} + +.x-tool-tool-el.x-tool-collapse-right::before, +.x-tool-img.x-tool-collapse-right::before { + content: "\f054" !important; /* fa-chevron-right */ +} + +.x-tool-tool-el.x-tool-expand-left::before, +.x-tool-img.x-tool-expand-left::before { + content: "\f053" !important; /* fa-chevron-left */ +} + +.x-tool-tool-el.x-tool-collapse-left::before, +.x-tool-img.x-tool-collapse-left::before { + content: "\f053" !important; /* fa-chevron-left */ +} + +.x-tool-tool-el.x-tool-expand-right::before, +.x-tool-img.x-tool-expand-right::before { + content: "\f054" !important; /* fa-chevron-right */ +} + +.x-tool-tool-el.x-tool-maximize::before, +.x-tool-img.x-tool-maximize::before { + content: "\f065" !important; /* fa-expand */ +} + +.x-tool-tool-el.x-tool-restore::before, +.x-tool-img.x-tool-restore::before { + content: "\f066" !important; /* fa-compress */ +} + +.x-tool-tool-el.x-tool-gear::before, +.x-tool-img.x-tool-gear::before { + content: "\f013" !important; /* fa-cog */ +} + +.x-tool-tool-el.x-tool-refresh::before, +.x-tool-img.x-tool-refresh::before { + content: "\f021" !important; /* fa-refresh */ +} + +.x-tool-tool-el.x-tool-close::before, +.x-tool-img.x-tool-close::before { + content: "\f00d" !important; /* fa-times */ +} + +/* Hover state - all tool icons */ +.x-tool:hover .x-tool-tool-el.x-tool-minus, +.x-tool:hover .x-tool-img.x-tool-minus, +.x-tool:hover .x-tool-tool-el.x-tool-collapse-right, +.x-tool:hover .x-tool-img.x-tool-collapse-right, +.x-tool:hover .x-tool-tool-el.x-tool-collapse-left, +.x-tool:hover .x-tool-img.x-tool-collapse-left, +.x-tool:hover .x-tool-tool-el.x-tool-expand-right, +.x-tool:hover .x-tool-img.x-tool-expand-right, +.x-tool:hover .x-tool-tool-el.x-tool-expand-left, +.x-tool:hover .x-tool-img.x-tool-expand-left, +.x-tool:hover .x-tool-tool-el.x-tool-maximize, +.x-tool:hover .x-tool-img.x-tool-maximize, +.x-tool:hover .x-tool-tool-el.x-tool-restore, +.x-tool:hover .x-tool-img.x-tool-restore, +.x-tool:hover .x-tool-tool-el.x-tool-gear, +.x-tool:hover .x-tool-img.x-tool-gear, +.x-tool:hover .x-tool-tool-el.x-tool-refresh, +.x-tool:hover .x-tool-img.x-tool-refresh, +.x-tool:hover .x-tool-tool-el.x-tool-close, +.x-tool:hover .x-tool-img.x-tool-close { + color: var(--pm-text) !important; +} + +/* Disabled state */ +.x-tool-disabled .x-tool-tool-el, +.x-tool-disabled .x-tool-img { + opacity: 0.4 !important; + cursor: default !important; +} + +/* Inline FontAwesome tools (PVE-injected) */ +.x-tool-tool-el[style*="font-family:FontAwesome"], +.x-tool-tool-el[style*="font-family: FontAwesome"] { + color: var(--pm-text-dim) !important; + font-size: 14px !important; + line-height: 16px !important; + display: flex !important; + align-items: center !important; + justify-content: center !important; + width: 16px !important; + height: 16px !important; + transition: color 0.15s ease !important; + background-image: none !important; + background-color: transparent !important; +} + +.x-tool:not(.x-tool-disabled) .x-tool-tool-el[style*="font-family:FontAwesome"], +.x-tool:not(.x-tool-disabled) .x-tool-tool-el[style*="font-family: FontAwesome"] { + cursor: pointer !important; +} + +.x-tool.x-tool-disabled .x-tool-tool-el[style*="font-family:FontAwesome"], +.x-tool.x-tool-disabled .x-tool-tool-el[style*="font-family: FontAwesome"] { + cursor: default !important; + opacity: 0.4 !important; +} + +.x-tool .x-mask { + background-color: transparent !important; + backdrop-filter: none !important; + pointer-events: none !important; +} + +.x-tool:not(.x-tool-disabled):hover .x-tool-tool-el[style*="font-family:FontAwesome"], +.x-tool:not(.x-tool-disabled):hover .x-tool-tool-el[style*="font-family: FontAwesome"] { + color: var(--pm-text) !important; +} diff --git a/themes/theme-dracula-pink.css b/themes/theme-dracula-pink.css new file mode 100644 index 0000000..7935bf7 --- /dev/null +++ b/themes/theme-dracula-pink.css @@ -0,0 +1,2378 @@ +/*!Dracula Pink*/ +/* + * ProxMorph Theme: Dracula Pink + * The canonical dark theme with Pink accent — ported from the Dracula specification + * Version: 1.0.0 + * Author: ProxMorph / Dracula Theme (https://draculatheme.com) + * + * v1.0.0: Initial release — Tier 2 baseline with all fixes + * - Full Dracula palette with derived shades + * - All component sections ported from UniFi/Catppuccin reference + * - Console/Terminal, Charts, Progress bars, Buttons (28px), + * Dialog fixes, Tree cursor:pointer, APT repos, Tag checkmark + * + * ─── Dracula Specification Palette ───────────────────────────── + * Background: #282a36 Current Line: #44475a + * Foreground: #f8f8f2 Comment: #6272a4 + * Cyan: #8be9fd Green: #50fa7b + * Orange: #ffb86c Pink: #ff79c6 + * Purple: #bd93f9 Red: #ff5555 + * Yellow: #f1fa8c + * + * ─── Derived Shades (ProxMorph) ──────────────────────────────── + * Crust: #1e1f29 Mantle: #21222c + * Surface 0: #343746 Surface 1: #44475a (= Current Line) + * Surface 2: #565a72 Overlay 0: #6272a4 (= Comment) + * Overlay 1: #7c83a0 Overlay 2: #9298b8 + * Subtext 0: #b0b5c8 Subtext 1: #d0d4e0 + * Text: #f8f8f2 On-Accent: #282a36 + */ + +/* ===================================================== + CSS VARIABLES + ===================================================== */ +:root { + /* Dracula Specification Tokens */ + --drac-bg: #282a36; + --drac-current-line: #44475a; + --drac-fg: #f8f8f2; + --drac-comment: #6272a4; + --drac-cyan: #8be9fd; + --drac-green: #50fa7b; + --drac-orange: #ffb86c; + --drac-pink: #ff79c6; + --drac-purple: #bd93f9; + --drac-red: #ff5555; + --drac-yellow: #f1fa8c; + + /* Derived Neutral Scale */ + --drac-text: #f8f8f2; + --drac-subtext1: #d0d4e0; + --drac-subtext0: #b0b5c8; + --drac-overlay2: #9298b8; + --drac-overlay1: #7c83a0; + --drac-overlay0: #6272a4; + --drac-surface2: #565a72; + --drac-surface1: #44475a; + --drac-surface0: #343746; + --drac-base: #282a36; + --drac-mantle: #21222c; + --drac-crust: #1e1f29; + + /* ProxMorph Semantic Variables */ + --pm-accent: var(--drac-pink); + --pm-bg-base: var(--drac-base); + --pm-bg-surface: var(--drac-surface0); + --pm-bg-elevated: var(--drac-surface1); + --pm-text: var(--drac-text); + --pm-text-dim: var(--drac-subtext1); + --pm-success: var(--drac-green); + --pm-warning: var(--drac-yellow); + --pm-error: var(--drac-red); + --pm-border: var(--drac-surface1); + --pm-radius-sm: 4px; + --pm-radius-md: 6px; + --pm-radius-lg: 8px; + + /* Proxmox Widget Toolkit Mappings (REQUIRED) */ + --pwt-panel-background: var(--drac-base); + --pwt-text-color: var(--drac-text); + --pwt-gauge-default: var(--drac-pink); + --pwt-gauge-back: var(--drac-surface1); + --pwt-gauge-warn: var(--drac-yellow); + --pwt-gauge-crit: var(--drac-red); + --pwt-chart-primary: var(--drac-pink); + --pwt-chart-grid-stroke: var(--drac-surface1); + + /* On Accent text — Background on colored backgrounds for contrast */ + --drac-on-accent: var(--drac-bg); + + /* Hover overlay — Comment@12% */ + --drac-hover-overlay: rgba(98, 114, 164, 0.12); + /* Selection overlay — Comment@25% */ + --drac-select-overlay: rgba(98, 114, 164, 0.25); + /* Accent muted (for focus rings) */ + --drac-accent-muted: rgba(255, 121, 198, 0.4); + --drac-accent-subtle: rgba(255, 121, 198, 0.15); + + color-scheme: dark; +} + +/* ===================================================== + GLOBAL BORDER-RADIUS ARCHITECTURE + (Ported from UniFi theme — reset everything, selectively re-apply) + ===================================================== */ +.x-border-box, +.x-border-box * { + border-radius: var(--pm-radius-lg); +} + +/* Remove rounded corners from grids/tables/lists */ +.x-grid, +.x-grid *, +.x-grid-header-ct, +.x-grid-header-ct *, +.x-grid-view, +.x-grid-view *, +.x-column-header, +.x-column-header *, +.x-grid-item, +.x-grid-cell, +.x-grid-cell-inner, +.x-grid-row, +table, +table *, +tr, +td, +th, +.x-legend, +.x-legend *, +.x-legend-container, +.x-legend-container *, +.x-legend-item, +.x-legend-horizontal .x-legend-item, +.x-legend-vertical .x-legend-item, +.x-legend-horizontal .x-legend-item:first-child, +.x-legend-horizontal .x-legend-item:last-child, +.x-legend-vertical .x-legend-item:first-child, +.x-legend-vertical .x-legend-item:last-child, +.x-tool, +.x-tool-tool-el, +.x-tool-default, +.x-tool-img { + border-radius: 0 !important; +} + +/* Form elements - exclude from global radius */ +.x-form-item, +.x-form-item-default, +.x-form-item-body, +.x-form-item-body-default, +.x-form-text-field-body, +.x-form-text-field-body-default, +.x-form-fieldcontainer, +.x-field, +.x-field-default, +.x-form-type-text { + border-radius: 0 !important; +} + +/* Reset layout containers that clip elements with overflow:hidden + radius */ +.x-box-layout-ct, +.x-panel-bodyWrap, +.x-panel-bodyWrap-default, +.x-autocontainer-innerCt, +.x-autocontainer-outerCt, +.x-panel.x-tabpanel-child, +.x-panel.x-box-item, +.x-box-inner, +.x-box-target, +.x-container, +.x-container-default, +.x-window .x-panel-body, +.x-window .x-window-body, +.x-window .x-window-bodyWrap { + border-radius: 0 !important; +} + +/* Reset everything inside windows to 0 — then re-apply specific radii */ +.x-window *, +.x-window .x-autocontainer-innerCt, +.x-window .x-autocontainer-outerCt, +.x-window .x-form-layout-wrap, +.x-window .x-form-layout-auto-label, +.x-window .x-form-layout-colgroup, +.x-window .x-form-layout-column, +.x-window .x-field, +.x-window .x-form-item, +.x-window .x-form-item-body { + border-radius: 0 !important; +} + +/* Chart canvas — no radius on data area */ +.x-chart-grid, +.x-chart-axis, +canvas.x-surface, +.x-chart canvas, +canvas.x-surface-canvas, +.x-surface-canvas, +.x-draw-component canvas, +.proxmox-rrd-chart canvas, +svg.x-surface, +.x-draw-container, +.x-surface { + border-radius: 0 !important; +} + +/* Legend color marker (dot) — keep circular */ +.x-legend-item-marker { + border-radius: 50% !important; +} + +/* ===================================================== + RE-APPLY BORDER RADII (selective) + ===================================================== */ + +/* Windows */ +.x-window, +.x-window-default { + border-radius: var(--pm-radius-lg) !important; +} + +.x-window-header, +.x-window-header-default { + border-radius: var(--pm-radius-lg) var(--pm-radius-lg) 0 0 !important; +} + +.x-window .x-window-body, +.x-window-body-default { + border-radius: 0 !important; +} + +/* Buttons inside windows */ +.x-window .x-btn { + border-radius: var(--pm-radius-md) !important; +} + +/* Checkboxes inside windows */ +.x-window .x-form-checkbox { + border-radius: 3px !important; +} + +/* Form inputs inside windows */ +.x-window .x-form-trigger-wrap, +.x-window .x-form-trigger-wrap-default { + border-radius: var(--pm-radius-sm) !important; +} + +.x-window .x-form-text-wrap, +.x-window .x-form-text { + border-radius: var(--pm-radius-sm) 0 0 var(--pm-radius-sm) !important; +} + +.x-window .x-form-arrow-trigger { + border-radius: 0 var(--pm-radius-sm) var(--pm-radius-sm) 0 !important; +} + +/* Form trigger/text wrap — reset and re-apply */ +.x-form-trigger-wrap, +.x-form-trigger-wrap *, +.x-form-text-wrap, +.x-form-text-wrap *, +.x-form-text, +.x-form-trigger { + border-radius: 0 !important; +} + +.x-form-trigger-wrap, +.x-form-trigger-wrap-default { + border-radius: var(--pm-radius-sm) !important; + overflow: hidden !important; +} + +.x-form-text-wrap, +.x-form-text-wrap-default { + border-radius: var(--pm-radius-sm) 0 0 var(--pm-radius-sm) !important; +} + +.x-form-text, +.x-form-text-default { + border-radius: var(--pm-radius-sm) 0 0 var(--pm-radius-sm) !important; +} + +.x-form-trigger, +.x-form-trigger-default, +.x-form-arrow-trigger, +.x-form-arrow-trigger-default { + border-radius: 0 var(--pm-radius-sm) var(--pm-radius-sm) 0 !important; +} + +/* Dialog form content padding — vertical only (horizontal causes ExtJS overflow) */ +.x-window .x-tabpanel-child .x-autocontainer-innerCt { + padding: 12px 0 !important; +} + +/* Allow column panel bodies to show overflowed form content */ +.x-window .x-panel-body:not(.x-scroller) { + overflow: visible !important; +} + +/* Side padding on column panel bodies inside windows */ +.x-window .x-panel.x-box-item .x-panel-body { + padding: 0 4px !important; +} + +/* Constrain autocontainer width inside windows */ +.x-window .x-autocontainer-outerCt { + max-width: 100% !important; +} + +/* Fix window header/body width consistency */ +.x-window > .x-window-header, +.x-window > .x-window-body, +.x-window > .x-window-bodyWrap, +.x-window-bodyWrap > .x-window-body { + width: 100% !important; +} + +.x-window-header > .x-box-inner, +.x-window-header > .x-box-inner > .x-box-target { + width: 100% !important; +} + +.x-window-header-title { + width: auto !important; + flex: 1 !important; + max-width: calc(100% - 30px) !important; +} + +/* Boundlists */ +.x-boundlist { + border-radius: var(--pm-radius-md) !important; + overflow: hidden !important; +} + +/* ===================================================== + BASE / BODY + ===================================================== */ +.x-body, +.x-viewport > .x-body, +body.x-border-layout-ct, +div.x-border-layout-ct { + background-color: var(--drac-base) !important; + color: var(--drac-text) !important; +} + +/* ===================================================== + MASKS & OVERLAYS + ===================================================== */ +.x-mask { + background-color: rgba(30, 31, 41, 0.6) !important; + backdrop-filter: blur(4px); +} + +.x-mask-msg { + background-color: var(--drac-mantle) !important; + border: 1px solid var(--drac-surface1) !important; + border-radius: var(--pm-radius-lg) !important; +} + +.x-mask-msg-text { + color: var(--drac-subtext0) !important; + filter: none !important; +} + +.x-css-shadow { + box-shadow: 0 8px 24px rgba(30, 31, 41, 0.6) !important; +} + +/* Loading indicators */ +.x-grid-row-loading, +.x-treelist-item-loading .x-treelist-item-icon, +.x-grid-tree-loading .x-tree-icon { + filter: invert(90%); +} + +/* ===================================================== + ICONS — Proxmox default colors for dark mode + ===================================================== */ + +/* General icon colors — neutral gray for dark backgrounds */ +.x-tree-icon-custom, +.x-grid-icon-custom, +.fa-tags::before, +.fa-file-o::before, +.fa-building::before, +.x-action-col-icon::before, +.fa-shield::before, +.fa-file-text-o::before, +.fa-clock-o::before, +.x-tab-icon-el-default, +.pve-icon-verify-lettering::after, +.x-tree-icon-leaf:not(.x-tree-icon-custom)::before, +.x-tree-icon-parent:not(.x-tree-icon-custom)::before, +.x-tree-icon-parent-expanded:not(.x-tree-icon-custom)::before, +.x-grid-filters-filtered-column .x-column-header-text::after { + color: var(--drac-overlay2) !important; +} + +/* Folder icons — invert for dark mode */ +.x-tree-icon-parent:not(.x-tree-icon-custom)::before, +.x-tree-icon-parent-expanded:not(.x-tree-icon-custom)::before { + filter: invert(90%); +} + +/* Various image-based icons — invert for visibility */ +.fa-ceph::before, +.fa-sdn::before, +.fa-network-wired::before, +.pve-itype-treelist-item-icon-cdrom, +.fa-chevron-right::before, +.x-grid-row-console, +.x-box-scroller-toolbar-default.x-box-scroller, +.x-tree-elbow-img, +.pve-itype-icon-qemu, +.x-tree-node-computer, +.x-grid-tree-node-expanded .x-tree-node-computer, +.pbs-icon-tape, +.pbs-icon-tape-drive, +.x-tree-icon-leaf:not(.x-tree-icon-custom), +.x-tree-icon-parent:not(.x-tree-icon-custom), +.x-tree-icon-parent-expanded:not(.x-tree-icon-custom) { + filter: invert(90%); +} + +/* Hardware icons */ +.pve-itype-icon-cpu, +.pve-itype-icon-cdrom, +.pve-itype-icon-memory, +.pve-itype-icon-pci, +.pve-itype-icon-serial, +.pve-itype-icon-die, +.pmx-itype-icon-processor, +.pmx-itype-icon-memory, +.pve-itype-icon-storage, +.x-tree-node-harddisk, +.x-grid-tree-node-expanded .x-tree-node-harddisk { + filter: invert(100%); +} + +/* Hardware icons — counter-invert for non-SVG icon cells */ +td.pve-itype-icon-storage .x-grid-cell-inner, +td.x-tree-node-harddisk .x-grid-cell-inner { + filter: invert(100%) !important; +} + +/* Hardware icons — hide inverted borders for non-SVG icon cells */ +td.pve-itype-icon-storage, +td.x-tree-node-harddisk { + border-color: transparent !important; +} + +/* Hardware grid icons — mask-image renders SVG icons in theme text color + Replaces filter:invert approach for pve-itype-icon-* and pmx-itype-icon-* grid cells */ +td.pve-itype-icon-cpu, +td.pve-itype-icon-cdrom, +td.pve-itype-icon-memory, +td.pve-itype-icon-pci, +td.pve-itype-icon-serial, +td.pve-itype-icon-die, +td.pmx-itype-icon-processor, +td.pmx-itype-icon-memory { + filter: none !important; + background-image: none !important; + padding-left: 0 !important; + border-color: transparent !important; +} + +td.pve-itype-icon-cpu .x-grid-cell-inner, +td.pve-itype-icon-cdrom .x-grid-cell-inner, +td.pve-itype-icon-memory .x-grid-cell-inner, +td.pve-itype-icon-pci .x-grid-cell-inner, +td.pve-itype-icon-serial .x-grid-cell-inner, +td.pve-itype-icon-die .x-grid-cell-inner, +td.pmx-itype-icon-processor .x-grid-cell-inner, +td.pmx-itype-icon-memory .x-grid-cell-inner { + padding-left: 3px !important; +} + +td.pve-itype-icon-cpu .x-grid-cell-inner::before, +td.pve-itype-icon-cdrom .x-grid-cell-inner::before, +td.pve-itype-icon-memory .x-grid-cell-inner::before, +td.pve-itype-icon-pci .x-grid-cell-inner::before, +td.pve-itype-icon-serial .x-grid-cell-inner::before, +td.pve-itype-icon-die .x-grid-cell-inner::before, +td.pmx-itype-icon-processor .x-grid-cell-inner::before, +td.pmx-itype-icon-memory .x-grid-cell-inner::before { + content: '' !important; + display: inline-block !important; + width: 18px !important; + height: 14px !important; + vertical-align: middle !important; + margin-right: 10px !important; + background-color: currentColor !important; + -webkit-mask-size: contain !important; + mask-size: contain !important; + -webkit-mask-repeat: no-repeat !important; + mask-repeat: no-repeat !important; + -webkit-mask-position: center !important; + mask-position: center !important; +} + +td.pve-itype-icon-cpu .x-grid-cell-inner::before { + -webkit-mask-image: url('/pve2/images/icon-cpu.svg') !important; + mask-image: url('/pve2/images/icon-cpu.svg') !important; +} + +td.pve-itype-icon-memory .x-grid-cell-inner::before { + -webkit-mask-image: url('/pve2/images/icon-memory.svg') !important; + mask-image: url('/pve2/images/icon-memory.svg') !important; +} + +td.pve-itype-icon-cdrom .x-grid-cell-inner::before { + -webkit-mask-image: url('/pve2/images/icon-cd-drive.svg') !important; + mask-image: url('/pve2/images/icon-cd-drive.svg') !important; +} + +td.pve-itype-icon-pci .x-grid-cell-inner::before { + -webkit-mask-image: url('/pve2/images/icon-pci.svg') !important; + mask-image: url('/pve2/images/icon-pci.svg') !important; +} + +td.pve-itype-icon-serial .x-grid-cell-inner::before { + -webkit-mask-image: url('/pve2/images/icon-serial.svg') !important; + mask-image: url('/pve2/images/icon-serial.svg') !important; +} + +td.pve-itype-icon-die .x-grid-cell-inner::before { + -webkit-mask-image: url('/pve2/images/icon-die.svg') !important; + mask-image: url('/pve2/images/icon-die.svg') !important; +} + +td.pmx-itype-icon-processor .x-grid-cell-inner::before { + -webkit-mask-image: url('../images/icon-cpu.svg') !important; + mask-image: url('../images/icon-cpu.svg') !important; +} + +td.pmx-itype-icon-memory .x-grid-cell-inner::before { + -webkit-mask-image: url('../images/icon-ram.svg') !important; + mask-image: url('../images/icon-ram.svg') !important; +} + + +/* Icon overlays — default */ +.x-tree-icon-custom::after, +.x-grid-icon-custom::after { + color: var(--drac-overlay2) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* RUNNING VMs/CTs — Dracula Green */ +.x-tree-icon-custom.running::after, +.x-grid-icon-custom.running::after, +.x-treelist-item-icon.running::after { + color: var(--drac-green) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* ONLINE state — Green */ +.x-tree-icon-custom.online::after, +.x-grid-icon-custom.online::after { + color: var(--drac-green) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* Stopped/offline — Overlay1 (muted gray) */ +.x-tree-icon-custom.stopped, +.x-tree-icon-custom.offline, +.x-grid-icon-custom.stopped, +.x-grid-icon-custom.offline { + color: var(--drac-overlay1) !important; +} + +/* Unknown state — Overlay1 */ +.x-tree-icon-custom.unknown::after, +.x-grid-icon-custom.unknown::after { + color: var(--drac-overlay1) !important; +} + +/* ERROR states — Dracula Red */ +.x-tree-icon-custom.error::after, +.x-tree-icon-custom.offline::after, +.x-tree-icon-custom.ha-error::after, +.x-grid-icon-custom.error::after, +.x-grid-icon-custom.offline::after, +.x-grid-icon-custom.ha-error::after { + color: var(--drac-red) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* PAUSED/SUSPENDED — Dracula Orange */ +.x-tree-icon-custom.paused::after, +.x-tree-icon-custom.suspended::after, +.x-tree-icon-custom.lock-suspending::after, +.x-grid-icon-custom.paused::after, +.x-grid-icon-custom.suspended::after, +.x-grid-icon-custom.lock-suspending::after { + color: var(--drac-orange) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* PENDING/WARNING states — Dracula Yellow */ +.x-tree-icon-custom.pending::after, +.x-tree-icon-custom.io-error::after, +.x-tree-icon-custom.internal-error::after, +.x-tree-icon-custom.guest-panicked::after, +.x-grid-icon-custom.pending::after, +.x-grid-icon-custom.io-error::after, +.x-grid-icon-custom.internal-error::after, +.x-grid-icon-custom.guest-panicked::after { + color: var(--drac-yellow) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* HA MAINTENANCE — Dracula Cyan */ +.x-tree-icon-custom.ha-maintenance::after, +.x-grid-icon-custom.ha-maintenance::after { + color: var(--drac-cyan) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* Locked icons */ +.x-tree-icon-custom.locked::after, +.x-tree-icon-custom.lock-backup::after, +.x-tree-icon-custom.lock-migrate::after, +.x-tree-icon-custom.lock-suspended::after, +.x-grid-icon-custom.locked::after, +.x-grid-icon-custom.lock-backup::after, +.x-grid-icon-custom.lock-migrate::after, +.x-grid-icon-custom.lock-suspended::after { + color: var(--drac-overlay2) !important; +} + +/* LXC/QEMU type indicators */ +.x-tree-icon-custom.lxc::after, +.x-tree-icon-custom.qemu::after, +.x-grid-icon-custom.lxc::after, +.x-grid-icon-custom.qemu::after { + background-color: transparent; + color: var(--drac-overlay1) !important; +} + +.x-treelist-item-icon.lxc::after, +.x-treelist-item-icon.qemu::after { + background-color: transparent; + color: var(--drac-overlay1) !important; +} + +/* Tree expander arrows */ +.x-tree-arrows .x-tree-expander { + filter: brightness(200%); +} + +/* Cancel sprite-inversion on custom controls (checkboxes/radios handled via CSS) */ +.x-form-checkbox-default, +.x-form-radio-default, +.x-column-header-checkbox .x-column-header-checkbox::after, +.x-grid-checkcolumn::after, +.x-menu-item-checked .x-menu-item-icon-default.x-menu-item-checkbox, +.x-menu-item-unchecked .x-menu-item-icon-default.x-menu-item-checkbox { + filter: none !important; +} + +/* ===================================================== + PANELS & HEADERS + ===================================================== */ +.x-panel, +.x-panel-default { + border-radius: var(--pm-radius-lg) !important; + padding: 0 !important; +} + +/* Column panels — native stacked layout (Issue #23 fix) */ +.x-panel.x-column { + padding: 5px !important; + margin: 0 !important; + max-width: none !important; + box-sizing: border-box !important; +} + +/* Column panel card styling — borders for summary + chart panels */ +.x-panel.x-panel-default.x-column { + border: 1px solid var(--drac-surface1) !important; + border-radius: var(--pm-radius-lg) !important; + overflow: hidden !important; +} + +/* Guest status + Notes panel borders */ +[id^="pveGuestStatusView-"].x-panel, +[id^="pveLxcStatusView-"].x-panel, +[id^="pveQemuStatusView-"].x-panel, +[id^="pmxNotesView-"].x-panel { + border: 1px solid var(--drac-surface1) !important; + border-radius: var(--pm-radius-lg) !important; +} + +.x-panel-body, +.x-panel-body-default { + background-color: var(--drac-base) !important; + color: var(--drac-text) !important; + border: none !important; +} + +/* Panel headers — bottom border only */ +.x-panel-header, +.x-panel-header-default { + background-color: var(--drac-mantle) !important; + border: none !important; + border-bottom: 1px solid var(--drac-surface1) !important; + border-radius: var(--pm-radius-lg) var(--pm-radius-lg) 0 0 !important; + margin: 0 !important; + padding: 8px 12px !important; + width: 100% !important; + box-sizing: border-box !important; + overflow: visible !important; +} + +/* Title text — prevent border-radius clipping */ +.x-title-text, +.x-title-text-default { + overflow: visible !important; +} + +.x-panel-bodyWrap, +.x-panel-bodyWrap-default { + margin: 0 !important; + padding: 0 !important; + overflow: visible !important; +} + +/* Remove borders from nested panels */ +.x-panel-body > .x-box-layout-ct, +.x-panel-body > .x-container, +.x-panel-body > .x-box-inner, +[id*="pmxGauge"] { + border: none !important; +} + +.x-panel-header-title-default, +.x-window-header-title-default { + color: var(--drac-text) !important; +} + +.x-panel-header-default .x-tool-tool-el { + background-color: transparent; +} + +.x-tool-img { + filter: brightness(175%); +} + +.x-tool-over .x-tool-img { + filter: brightness(200%); +} + +/* Resource tree — panel body border */ +div[id^="pveResourceTree-"][id$="-body"] { + border-color: var(--drac-base) !important; +} + +/* Resource tree — remove row separators */ +[id^="pveResourceTree-"].x-tree-panel td.x-grid-cell, +[id^="pveResourceTree-"].x-tree-panel .x-grid-td, +[id^="pveResourceTree-"].x-tree-panel .x-grid-cell { + border-bottom: none !important; +} + +/* Resource tree — row spacing */ +div[id^="pveResourceTree"] .x-grid-cell { + padding-top: 3px !important; + padding-bottom: 3px !important; +} + +/* Summary/stats panel radius overrides */ +.pveStatusPanel, +.x-panel-default-framed, +.x-panel-body-default-framed { + border-radius: 12px !important; +} + +.x-panel-header-default-framed { + border-radius: 12px 12px 0 0 !important; +} + +/* Column widget panel radius */ +.x-panel.x-column > .x-panel-bodyWrap > .x-panel-body.x-panel-body-default { + border-radius: var(--pm-radius-lg) !important; +} + +/* ===================================================== + SPLITTERS / SEPARATORS + ===================================================== */ +.x-splitter-vertical { + background-color: transparent !important; + border-left: 1px solid var(--drac-surface1) !important; + border-right: none !important; + width: 1px !important; +} + +.x-splitter-horizontal { + background-color: var(--drac-crust) !important; + border-top: 1px solid var(--drac-surface1) !important; +} + +.x-splitter { + background-color: var(--drac-crust) !important; +} + +.x-keyboard-mode .x-splitter-focus::after { + border-color: var(--drac-pink) !important; +} + +.x-layout-split-bottom { + opacity: 0.7; +} + +/* Toolbox tree (pve-nav) right border — full height */ +.pve-toolbar-bg { + border-right: 1px solid var(--drac-surface1) !important; + z-index: 3 !important; +} + +.x-treelist.x-treelist-pve-nav { + border-right: none !important; +} + +/* ===================================================== + TOOLBARS + ===================================================== */ +.x-toolbar, +.x-toolbar-default { + background-color: var(--drac-base) !important; + border-color: var(--drac-surface1) !important; +} + +.x-toolbar-default.x-docked-top { + border: none !important; + border-bottom: 1px solid var(--drac-surface1) !important; +} + +.x-toolbar-default .x-toolbar-separator { + border-color: var(--drac-surface1); +} + +.x-toolbar-text-default { + color: var(--drac-subtext0); +} + +/* ===================================================== + PRIMARY BUTTONS — Dracula Purple + ===================================================== */ +.x-btn-default-small { + background-color: var(--drac-pink) !important; + border: 1px solid rgba(255, 121, 198, 0.4) !important; + border-radius: var(--pm-radius-md) !important; + transition: background-color 0.15s ease, box-shadow 0.15s ease !important; +} + +.x-btn-default-small .x-btn-inner { + color: var(--drac-on-accent) !important; + font-weight: 600 !important; +} + +.x-btn-default-small .x-btn-icon-el { + color: var(--drac-on-accent) !important; +} + +.x-btn-default-small.x-btn-over, +.x-keyboard-mode .x-btn-default-small.x-btn-focus { + background-color: #ff92d0 !important; + box-shadow: 0 0 0 3px var(--drac-accent-subtle) !important; +} + +.x-btn-default-small.x-btn.x-btn-disabled { + background-color: var(--drac-pink) !important; + opacity: 0.4; +} + +.x-btn-default-small.x-btn.x-btn-pressed { + background-color: #e56fb3 !important; +} + +/* Button height consistency — 28px with vertical centering */ +/* Exclude tag edit buttons (display:none when hidden, :has(.fa-check) for checkmark) */ +.x-btn.x-btn-default-small:not(.x-btn-default-toolbar-small):not([style*="display: none"]):not([style*="display:none"]):not(:has(.fa-check)) { + height: 28px !important; + min-height: 28px !important; + display: flex !important; + align-items: center !important; + padding: 3px 8px !important; +} + +/* Fix button inner element centering for proper icon alignment (issue #17) */ +.x-btn.x-btn-default-small:not(.x-btn-default-toolbar-small):not([style*="display: none"]):not([style*="display:none"]):not(:has(.fa-check)) .x-btn-wrap { + display: flex !important; + align-items: center !important; +} + +.x-btn.x-btn-default-small:not(.x-btn-default-toolbar-small):not([style*="display: none"]):not([style*="display:none"]):not(:has(.fa-check)) .x-btn-inner { + display: flex !important; + align-items: center !important; +} + +/* Fix dropdown arrows on split/arrow buttons */ +.x-btn-wrap.x-btn-arrow-right::after, +.x-btn-wrap.x-btn-split-right::after { + height: 16px !important; + min-height: 16px !important; + width: 20px !important; + display: flex !important; + align-items: center !important; +} + +/* Fix icon-only buttons — hide   inner element when button has no text */ +.x-btn-no-text .x-btn-inner, +.x-btn-button.x-btn-no-text .x-btn-inner, +.x-btn-button-default-toolbar-small.x-btn-no-text .x-btn-inner-default-toolbar-small, +.x-btn-button-default-small.x-btn-no-text .x-btn-inner-default-small, +.x-btn-button-default-small.x-btn-no-text > .x-btn-inner-default-small { + display: none !important; +} + +/* Specific fix for fa-desktop icon (Create VM) — visually bottom-heavy */ +.x-btn-icon-el.fa-desktop { + transform: translateY(1.1px) !important; +} + +/* ===================================================== + SECONDARY / TOOLBAR BUTTONS + ===================================================== */ +.x-btn-default-toolbar-small { + background-color: var(--drac-surface0) !important; + border: 1px solid var(--drac-surface1) !important; + border-radius: var(--pm-radius-md) !important; + transition: background-color 0.15s ease, border-color 0.15s ease !important; +} + +.x-btn-default-toolbar-small .x-btn-inner-default-toolbar-small, +.x-btn-default-toolbar-small .x-btn-icon-el-default-toolbar-small { + color: var(--drac-text) !important; +} + +.x-btn-default-toolbar-small .x-btn-wrap-default-toolbar-small.x-btn-arrow-right::after, +.x-btn-default-toolbar-small .x-btn-wrap-default-toolbar-small.x-btn-split-right::after { + filter: brightness(150%); +} + +.x-btn-default-toolbar-small.x-btn-over, +.x-keyboard-mode .x-btn-default-toolbar-small.x-btn-focus { + background-color: var(--drac-surface1) !important; + border-color: var(--drac-surface2) !important; +} + +.x-btn-default-toolbar-small.x-btn.x-btn-disabled { + background-color: var(--drac-surface0) !important; + opacity: 0.4; +} + +.x-btn-default-toolbar-small.x-btn.x-btn-menu-active, +.x-btn-default-toolbar-small.x-btn.x-btn-pressed { + background-color: var(--drac-pink) !important; + border-color: var(--drac-pink) !important; + padding: 4px 8px !important; /* Fix #30: prevent width change on dropdown */ +} + +.x-btn-default-toolbar-small.x-btn.x-btn-pressed .x-btn-inner-default-toolbar-small, +.x-btn-default-toolbar-small.x-btn.x-btn-pressed .x-btn-icon-el-default-toolbar-small, +.x-btn-default-toolbar-small.x-btn.x-btn-pressed .x-btn-inner-default-small, +.x-btn-default-toolbar-small.x-btn.x-btn-pressed .x-btn-icon-el-default-small { + color: var(--drac-on-accent) !important; +} + +/* Segmented buttons */ +.x-segmented-button { + border-radius: var(--pm-radius-md) !important; +} + +.x-segmented-button .x-btn, +.x-segmented-button .x-btn-default-small, +.x-segmented-button .x-btn-inner, +.x-segmented-button .x-btn-wrap { + border-radius: var(--pm-radius-md) !important; +} + +/* Inline buttons (Documentation, Help) */ +.proxmox-inline-button { + height: 28px !important; + min-height: 28px !important; + display: flex !important; + align-items: center !important; + padding: 3px 8px !important; + background-color: var(--drac-surface0) !important; + border: 1px solid var(--drac-surface1) !important; + border-radius: var(--pm-radius-md) !important; + color: var(--drac-text) !important; + transition: background-color 0.15s ease !important; +} + +.proxmox-inline-button:hover, +.proxmox-inline-button.x-btn-over { + background-color: var(--drac-surface1) !important; + border-color: var(--drac-overlay0) !important; +} + +.proxmox-inline-button:active, +.proxmox-inline-button.x-btn-pressed { + background-color: var(--drac-surface2) !important; +} + +.proxmox-inline-button .x-btn-inner, +.proxmox-inline-button .x-btn-icon-el { + color: var(--drac-text) !important; +} + +/* Pressed/active inline buttons — use on-accent text */ +.proxmox-inline-button.x-btn-pressed .x-btn-inner, +.proxmox-inline-button.x-btn-pressed .x-btn-icon-el, +.proxmox-inline-button.x-btn-menu-active .x-btn-inner, +.proxmox-inline-button.x-btn-menu-active .x-btn-icon-el { + color: var(--drac-on-accent) !important; +} + +/* ===================================================== + FORM ELEMENTS + ===================================================== */ +.x-form-trigger-default { + background-color: var(--drac-surface0) !important; +} + +.x-form-text-default { + background-color: var(--drac-surface0) !important; + color: var(--drac-text) !important; + border-radius: var(--pm-radius-sm) !important; +} + +.x-form-trigger-wrap, +.x-form-trigger-wrap-default { + border-color: var(--drac-surface1) !important; + background-color: var(--drac-surface0) !important; + border-radius: var(--pm-radius-sm) !important; + transition: border-color 0.15s ease !important; +} + +.x-form-trigger-wrap-default.x-form-trigger-wrap-focus { + border-color: var(--drac-pink) !important; + box-shadow: 0 0 0 3px var(--drac-accent-subtle) !important; +} + +.x-form-item-label-default, +.x-form-cb-label-default { + color: var(--drac-text) !important; +} + +.x-form-display-field-default { + color: var(--drac-subtext0) !important; + border-radius: var(--pm-radius-md) !important; +} + +.x-form-spinner-default { + background-color: var(--drac-surface0) !important; +} + +.x-fieldset, +.x-fieldset-default { + border-color: var(--drac-surface1) !important; + border-radius: var(--pm-radius-lg) !important; +} + +.x-fieldset-header-default > .x-fieldset-header-text { + color: var(--drac-text) !important; +} + +/* ===================================================== + CHECKBOXES & RADIOS — Dracula styled + ===================================================== */ + +/* Base: remove sprite, styled as custom control */ +.x-form-checkbox, .x-form-checkbox-default, +.x-form-radio, .x-form-radio-default { + background-image: none !important; + background-color: var(--drac-surface0) !important; + border: 1.5px solid var(--drac-overlay0) !important; + width: 16px !important; + height: 16px !important; + display: inline-block !important; + box-sizing: border-box !important; + cursor: pointer !important; + transition: border-color 0.12s ease, background-color 0.12s ease !important; +} + +/* Checkbox: rounded square */ +.x-form-checkbox, .x-form-checkbox-default { + border-radius: 3px !important; +} + +/* Radio: circle + ::after inner dot */ +.x-form-radio, .x-form-radio-default { + border-radius: 50% !important; + position: relative !important; + transform: translateZ(0) !important; + box-shadow: inset 0 0 0 0 transparent !important; +} + +.x-form-radio::after { + content: '' !important; + position: absolute !important; + top: 50% !important; + left: 50% !important; + width: 7px !important; + height: 7px !important; + border-radius: 50% !important; + background: transparent !important; + transform: translate(-50%, -50%) scale(0) !important; + transition: transform 0.15s ease, background 0.15s ease !important; + pointer-events: none !important; +} + +/* Hover */ +.x-form-checkbox:hover, .x-form-checkbox-default:hover, +.x-form-cb-wrap:hover .x-form-checkbox { + border-color: var(--drac-pink) !important; +} + +.x-form-radio:hover, .x-form-radio-default:hover, +.x-form-cb-wrap:hover .x-form-radio { + border-color: var(--drac-pink) !important; +} + +/* CHECKED checkbox — Purple fill + dark SVG checkmark */ +.x-form-cb-checked .x-form-checkbox, +.x-form-cb-checked .x-form-checkbox-default { + background-color: var(--drac-pink) !important; + border-color: var(--drac-pink) !important; + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 8'%3E%3Cpath d='M1 4l3 3 5-6' fill='none' stroke='%23282a36' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") !important; + background-repeat: no-repeat !important; + background-position: center !important; + background-size: 9px 7px !important; +} + +/* SELECTED radio — Purple dot */ +.x-form-cb-checked .x-form-radio, +.x-form-cb-checked .x-form-radio-default { + border-color: var(--drac-pink) !important; + background-color: var(--drac-base) !important; +} + +.x-form-cb-checked .x-form-radio::after { + background: var(--drac-pink) !important; + transform: translate(-50%, -50%) scale(1) !important; +} + +/* ===================================================== + BOUNDLIST / DROPDOWNS + ===================================================== */ +.x-boundlist { + background-color: var(--drac-mantle) !important; + border: 1px solid var(--drac-surface1) !important; + border-radius: var(--pm-radius-md) !important; + box-shadow: 0 8px 24px rgba(30, 31, 41, 0.7) !important; + padding: 2px !important; + overflow: hidden !important; +} + +.x-boundlist-item { + background-color: transparent !important; + color: var(--drac-text) !important; + border-radius: var(--pm-radius-sm) !important; + padding: 2px 6px !important; + line-height: normal !important; + border: none !important; + cursor: pointer !important; + outline: none !important; + box-shadow: none !important; +} + +.x-boundlist-selected { + background-color: var(--drac-select-overlay) !important; + color: var(--drac-text) !important; +} + +.x-boundlist-item-over { + background-color: var(--drac-hover-overlay) !important; +} + +/* ===================================================== + GRIDS / TABLES + ===================================================== */ +.x-grid, +.x-grid-view { + border-radius: 0 !important; +} + +.x-column-header { + border-color: var(--drac-surface1) !important; + background-color: transparent !important; +} + +.x-column-header-inner, +.x-column-header-text { + color: var(--drac-text) !important; + font-weight: 600 !important; +} + +.x-column-header-trigger { + border-color: var(--drac-surface1) !important; +} + +.x-grid-item, +.x-column-header-default, +.x-grid-cell-row-numberer { + color: var(--drac-text) !important; + background-color: var(--drac-base) !important; +} + +.x-grid-cell-special { + border-color: var(--drac-surface1) !important; +} + +.x-grid-group-hd { + background-color: var(--drac-base) !important; + border-color: var(--drac-surface1) !important; +} + +.x-grid-group-title { + color: var(--drac-text) !important; +} + +.x-grid-header-ct { + background-color: var(--drac-mantle) !important; + border: 1px solid var(--drac-surface0) !important; + border-radius: var(--pm-radius-lg) var(--pm-radius-lg) 0 0 !important; +} + +.x-grid-item-alt { + background-color: var(--drac-crust) !important; +} + +.x-grid-with-row-lines .x-grid-item { + border-color: var(--drac-surface0) !important; +} + +.x-grid-cell { + border-bottom: 1px solid rgba(68, 71, 90, 0.4) !important; +} + +.x-grid-item-over, +.x-grid-with-row-lines .x-grid-item.x-grid-item-over { + background-color: var(--drac-hover-overlay) !important; +} + +.x-grid-item-selected, +.x-grid-with-row-lines .x-grid-item.x-grid-item-selected { + background-color: var(--drac-select-overlay) !important; +} + +.x-column-header-over, +.x-column-header-open { + background-color: var(--drac-hover-overlay) !important; +} + +.x-column-header-sort-ASC, +.x-column-header-sort-DESC { + background-color: var(--drac-hover-overlay) !important; +} + +.x-grid-row-summary .x-grid-cell, +.x-grid-row-summary .x-grid-rowwrap, +.x-grid-row-summary .x-grid-cell-rowbody { + background-color: var(--drac-base) !important; + border-color: var(--drac-surface1); +} + +.x-grid-with-col-lines .x-grid-cell, +.x-grid-with-col-lines .x-grid-item-over .x-grid-cell, +.x-grid-with-col-lines .x-grid-item-selected .x-grid-cell { + border-color: var(--drac-surface1) !important; +} + +.x-dd-drag-proxy { + background-color: var(--drac-mantle); + border-color: var(--drac-surface1); + color: var(--drac-text); +} + +.x-keyboard-mode .x-grid-item-focused { + background-color: var(--drac-hover-overlay) !important; + color: var(--drac-text) !important; +} + +/* Remove blue outline from focused/selected items in resource tree */ +.x-keyboard-mode .x-grid-item-focused .x-grid-cell-inner::before, +.x-keyboard-mode .x-grid-item-selected .x-grid-cell-inner::before, +.x-grid-item-selected .x-grid-cell-inner::before, +.x-grid-item-focused .x-grid-cell-inner::before, +[id^="pveResourceTree"] .x-grid-item-selected .x-grid-cell-inner::before, +[id^="pveResourceTree"] .x-grid-item-focused .x-grid-cell-inner::before { + content: none !important; + display: none !important; + border: none !important; +} + +.x-grid-empty { + background-color: var(--drac-base) !important; + color: var(--drac-subtext0) !important; +} + +/* Grid info (pve-info-grid) and RRD view */ +.pve-info-grid { + border-radius: 12px !important; +} + +.pve-rrdview, +.rrdview { + border-radius: 12px !important; +} + +.pve-summary-status, +.x-container .pve-status { + border-radius: var(--pm-radius-lg) !important; +} + +[id^="pveGuestStatusView-"][id$="-body"], +[id^="pmxNotesView-"] .x-panel-body { + border-radius: var(--pm-radius-lg) !important; +} + +.x-panel-default[id*="notes"], +.pve-notes-view { + border-radius: var(--pm-radius-lg) !important; +} + +/* Floating grid pickers (storage/ISO selectors) */ +.x-layer.x-grid .x-grid-view, +.x-panel.x-layer.x-grid .x-grid-view, +.x-panel.x-layer.x-grid, +.x-layer.x-panel.x-grid { + border-radius: var(--pm-radius-sm) !important; +} + +.x-layer.x-grid .x-grid-item-over, +.x-layer.x-grid .x-grid-item-selected, +.x-panel.x-layer.x-grid .x-grid-item-over, +.x-panel.x-layer.x-grid .x-grid-item-selected { + border-radius: var(--pm-radius-sm) !important; + outline: none !important; + box-shadow: none !important; +} + +.x-layer.x-grid .x-grid-item-over td, +.x-layer.x-grid .x-grid-item-selected td, +.x-layer.x-grid .x-grid-item-over .x-grid-cell, +.x-layer.x-grid .x-grid-item-selected .x-grid-cell, +.x-panel.x-layer.x-grid .x-grid-item-over td, +.x-panel.x-layer.x-grid .x-grid-item-selected td, +.x-panel.x-layer.x-grid .x-grid-item-over .x-grid-cell, +.x-panel.x-layer.x-grid .x-grid-item-selected .x-grid-cell { + border-radius: 0 !important; +} + +.x-layer.x-grid .x-grid-item-over td:first-child, +.x-layer.x-grid .x-grid-item-selected td:first-child, +.x-panel.x-layer.x-grid .x-grid-item-over td:first-child, +.x-panel.x-layer.x-grid .x-grid-item-selected td:first-child { + border-radius: var(--pm-radius-sm) 0 0 var(--pm-radius-sm) !important; +} + +.x-layer.x-grid .x-grid-item-over td:last-child, +.x-layer.x-grid .x-grid-item-selected td:last-child, +.x-panel.x-layer.x-grid .x-grid-item-over td:last-child, +.x-panel.x-layer.x-grid .x-grid-item-selected td:last-child { + border-radius: 0 var(--pm-radius-sm) var(--pm-radius-sm) 0 !important; +} + +/* ===================================================== + MENUS + ===================================================== */ +.x-menu, +.x-menu-default { + background-color: var(--drac-crust) !important; + border: 1px solid var(--drac-surface0) !important; + border-radius: var(--pm-radius-lg) !important; + box-shadow: 0 8px 24px rgba(30, 31, 41, 0.8) !important; + padding: 2px !important; + overflow: hidden !important; +} + +.x-menu-body-default { + background-color: transparent !important; + padding: 4px !important; +} + +.x-menu-header { + background-color: transparent !important; + color: var(--drac-text) !important; +} + +/* Menu icon separator — hide */ +.x-menu-icon-separator-default { + display: none !important; +} + +/* Menu item layout (flexbox reordering) */ +.x-menu-item-default > .x-menu-item-link { + display: flex !important; + align-items: center !important; + flex-direction: row !important; + gap: 4px !important; + justify-content: flex-start !important; + flex-wrap: nowrap !important; + border-radius: var(--pm-radius-md) !important; + padding: 4px 8px !important; + line-height: 20px !important; + cursor: pointer !important; + outline: none !important; + box-shadow: none !important; + white-space: nowrap !important; + text-decoration: none !important; +} + +.x-menu-item-text-default { + color: var(--drac-text) !important; + font-size: 13px !important; + order: 1 !important; + margin-left: 0 !important; + text-align: left !important; + line-height: 20px !important; + display: inline-flex !important; + align-items: center !important; + flex: 1 1 auto !important; + width: auto !important; + white-space: nowrap !important; +} + +.x-menu-item-icon-default { + color: var(--drac-subtext0) !important; + order: -1 !important; + position: relative !important; + float: none !important; + margin-right: 8px !important; + margin-left: 0 !important; + left: auto !important; + top: auto !important; + width: 16px !important; + text-align: center !important; + display: inline-flex !important; + align-items: center !important; + justify-content: center !important; + height: 20px !important; + line-height: 20px !important; + vertical-align: middle !important; + flex: 0 0 16px !important; + align-self: center !important; +} + +.x-menu-item-arrow, +.x-menu-item-arrow-default { + order: 2 !important; + margin-left: auto !important; +} + +.x-menu-item-default.x-menu-item-separator { + background-color: var(--drac-surface0) !important; + border: none !important; + height: 1px !important; + margin: 6px 4px !important; +} + +.x-menu-item-default.x-menu-item-focus, +.x-menu-item-default.x-menu-item-active, +.x-menu-item:hover { + background-color: var(--drac-surface0) !important; + color: var(--drac-text) !important; + border-radius: var(--pm-radius-md) !important; +} + +.x-menu-item-active .x-menu-item-text-default, +.x-menu-item-focus .x-menu-item-text-default { + color: var(--drac-text) !important; +} + +.x-menu-item-active .x-menu-item-icon-default, +.x-menu-item-focus .x-menu-item-icon-default { + color: var(--drac-cyan) !important; +} + +/* ===================================================== + PROGRESS BARS + ===================================================== */ + +/* Fix: Widget containers need overflow visible to not clip progress bars */ +.x-container[id^="pmxInfoWidget"], +.x-container.x-box-layout-ct { + overflow: visible !important; +} + +.x-progress, +.x-progress-default { + background-color: var(--drac-surface0) !important; + border-radius: 5px !important; +} + +.x-progress-default .x-progress-bar-default { + background-color: var(--drac-pink) !important; + border-radius: 5px !important; + transition: width 0.4s ease !important; +} + +.x-progress-default .x-progress-text { + color: var(--drac-text) !important; +} + +/* Text overlaid on the progress bar fill — use on-accent for contrast */ +.x-progress-bar .x-progress-text { + color: var(--drac-on-accent) !important; +} + +.x-progress.warning .x-progress-bar { + background-color: var(--drac-yellow) !important; +} + +.x-progress.critical .x-progress-bar { + background-color: var(--drac-red) !important; +} + +/* ===================================================== + TABS — Dracula underline style + Flat tabs with Purple underline on active tab + ===================================================== */ +.x-tab-bar, +.x-tab-bar-default { + background-color: var(--drac-base) !important; + border-radius: 0 !important; + border-bottom: 1px solid var(--drac-surface1) !important; + padding-bottom: 0 !important; +} + +/* Overflow visible for the underline indicator */ +.x-tab-bar .x-box-inner, +.x-tab-bar .x-box-target, +.x-tab-bar-body, +.x-tab-bar-body-default { + overflow: visible !important; +} + +/* Base tab */ +.x-tab, +.x-tab-default, +.x-tab-default-top { + background-color: transparent !important; + border: none !important; + border-radius: var(--pm-radius-md) var(--pm-radius-md) 0 0 !important; + padding: 8px 16px 8px !important; + overflow: visible !important; + margin-bottom: 0 !important; + transition: color 0.15s ease !important; + outline: none !important; + box-shadow: none !important; +} + +/* Remove ::after from inactive tabs */ +.x-tab::after { + display: none !important; +} + +.x-tab-inner-default { + color: var(--drac-subtext0) !important; + font-size: 13px !important; +} + +.x-tab-default.x-tab-over { + background-color: transparent !important; +} + +.x-tab-default.x-tab-over .x-tab-inner-default { + color: var(--drac-text) !important; +} + +/* Active tab */ +.x-tab-default.x-tab.x-tab-active { + background-color: transparent !important; + border: none !important; + overflow: visible !important; + margin-bottom: 0 !important; + outline: none !important; + box-shadow: none !important; +} + +/* Purple underline indicator on active tab */ +.x-tab-default.x-tab.x-tab-active::after { + content: '' !important; + display: block !important; + position: absolute !important; + bottom: 0 !important; + left: 0 !important; + right: 0 !important; + height: 2px !important; + background: var(--drac-pink) !important; + z-index: 10 !important; + border-radius: 2px 2px 0 0 !important; + pointer-events: none !important; +} + +.x-tab-active .x-tab-inner-default { + color: var(--drac-text) !important; + font-weight: 600 !important; +} + +.x-tab-default.x-tab.x-tab-disabled { + background-color: transparent !important; + border: none !important; + color: var(--drac-overlay0) !important; + margin-bottom: 0 !important; +} + +/* Focus states — no outline */ +.x-keyboard-mode .x-tab-default.x-tab-focus, +.x-keyboard-mode .x-tab-default.x-tab-focus.x-tab-active { + background-color: transparent !important; + border: none !important; + outline: none !important; + box-shadow: none !important; + margin-bottom: 0 !important; +} + +.x-keyboard-mode .x-tab-default.x-tab-focus.x-tab-active::after { + content: '' !important; + display: block !important; + position: absolute !important; + bottom: 0 !important; + left: 0 !important; + right: 0 !important; + height: 2px !important; + background: var(--drac-pink) !important; + z-index: 10 !important; + pointer-events: none !important; +} + +/* Kill ALL tab interaction outlines/shadows */ +.x-tab:focus, +.x-tab *:focus, +.x-tab-focus, +.x-tab-active.x-tab-focus, +.x-tab-inner-focus, +.x-tab-button-focus, +.x-tab-pressed, +.x-tab-active.x-tab-pressed, +.x-tab-over, +.x-tab:active, +.x-tab *:active { + outline: none !important; + box-shadow: none !important; +} + +.x-tabpanel-child { + border-radius: 0 0 var(--pm-radius-lg) var(--pm-radius-lg) !important; +} + +/* Tab hover/active corners */ +.x-tab-default.x-tab-over, +.x-tab-default.x-tab.x-tab-active { + border-radius: var(--pm-radius-md) var(--pm-radius-md) 0 0 !important; +} + +/* ===================================================== + TOOLTIPS + ===================================================== */ +.x-tip, +.x-tip-default { + background-color: var(--drac-mantle) !important; + border: 1px solid var(--drac-surface1) !important; + border-radius: var(--pm-radius-md) !important; + box-shadow: 0 4px 12px rgba(30, 31, 41, 0.5); +} + +.x-tip-body-default { + color: var(--drac-text) !important; +} + +.x-tip-form-invalid { + background-color: var(--drac-mantle) !important; + border-color: var(--drac-red) !important; +} + +.x-tip-body-form-invalid { + color: var(--drac-red) !important; +} + +/* ===================================================== + TREE NAVIGATION (Sidebar) + ===================================================== */ +.x-treelist-item { + background-color: var(--drac-base) !important; + border-radius: var(--pm-radius-md) !important; +} + +/* Pseudo-element approach for hover/selected highlighting */ +.x-treelist-row { + border-radius: var(--pm-radius-md) !important; + background-color: transparent !important; + position: relative !important; + z-index: 0 !important; +} + +.x-treelist-row::before { + content: ""; + position: absolute; + top: 1px; + bottom: 1px; + left: 0; + right: 4px; + border-radius: var(--pm-radius-md); + background-color: transparent; + z-index: -1; + pointer-events: none; + transition: background-color 0.15s ease; +} + +/* Fix toolbox tree item text overlapping icons */ +.x-treelist-item-text { + margin-left: 28px !important; +} + +/* Toolbox tree items — bright text */ +.x-treelist-item-text, +.x-treelist-item-icon, +.x-treelist.x-treelist-pve-nav .x-treelist-item-text, +.x-treelist.x-treelist-pve-nav .x-treelist-item-icon { + color: var(--drac-subtext1) !important; +} + +/* Hover state — apply to pseudo-element */ +.x-treelist-row-over { + background-color: transparent !important; +} + +.x-treelist-row-over::before { + background-color: var(--drac-hover-overlay) !important; +} + +.x-treelist-row-over .x-treelist-item-icon, +.x-treelist-row-over .x-treelist-item-text { + background-color: transparent !important; + color: var(--drac-text) !important; +} + +/* Selected/active item — Purple highlight */ +.x-treelist-item-selected > .x-treelist-row { + background-color: transparent !important; +} + +.x-treelist-item-selected > .x-treelist-row::before, +.x-treelist-item-selected > .x-treelist-row:hover::before { + background-color: var(--drac-pink) !important; +} + +.x-treelist-item-selected .x-treelist-item-text, +.x-treelist-item-selected .x-treelist-item-icon, +.x-treelist.x-treelist-pve-nav .x-treelist-item-selected .x-treelist-item-text, +.x-treelist.x-treelist-pve-nav .x-treelist-item-selected .x-treelist-item-icon { + color: var(--drac-on-accent) !important; +} + +.x-treelist-pve-nav { + background-color: var(--drac-base) !important; + border-color: var(--drac-surface1) !important; +} + +/* Tree navigation radius overrides */ +.x-treelist-item, +.x-treelist-item-tool { + border-radius: var(--pm-radius-sm) !important; +} + +.x-treelist-row, +.x-treelist-row:hover, +.x-treelist-row-over, +.x-treelist-item-selected > .x-treelist-row, +.x-treelist-item-selected > .x-treelist-row:hover, +.x-treelist-item-expanded > .x-treelist-row, +.x-treelist-item-expanded > .x-treelist-row-over, +.x-treelist-item-expandable > .x-treelist-row, +.x-treelist-item-expandable > .x-treelist-row-over { + border-radius: var(--pm-radius-sm) !important; +} + +.x-treelist-row::before { + border-radius: var(--pm-radius-sm) !important; +} + +.x-treelist-item-wrap, +.x-treelist-item-text, +.x-treelist-row, +.x-treelist-container, +.x-treelist-root-container, +.x-treelist, +.x-treelist-pve-nav { + border-radius: var(--pm-radius-sm) !important; +} + +/* Cursor pointer for interactive tree/grid items */ +.x-grid-cell, +.x-grid-cell-inner, +.x-tree-elbow-img, +.x-tree-icon, +.x-treelist-item, +.x-treelist-row, +.x-treelist-item-wrap, +.x-treelist-item-text, +.x-treelist-item-icon { + cursor: pointer !important; +} + +/* ===================================================== + WINDOWS / MODALS + ===================================================== */ +.x-window, +.x-window-default { + background-color: var(--drac-crust) !important; + border: 1px solid var(--drac-surface1) !important; + border-radius: var(--pm-radius-lg) !important; + box-shadow: 0 8px 24px rgba(30, 31, 41, 0.6) !important; + overflow: hidden !important; +} + +.x-window .x-window-header, +.x-window-header-default { + background-color: var(--drac-mantle) !important; + border-color: transparent !important; + border-radius: var(--pm-radius-lg) var(--pm-radius-lg) 0 0 !important; +} + +.x-window-header-default .x-mask { + background-color: rgba(30, 31, 41, 0.7); +} + +.x-window .x-window-body, +.x-window-body-default { + background-color: var(--drac-base) !important; + border-color: var(--drac-surface1) !important; + color: var(--drac-text) !important; + border-radius: 0 0 var(--pm-radius-lg) var(--pm-radius-lg) !important; +} + +.x-window-ghost { + background-color: var(--drac-base) !important; +} + +.x-window-header-default .x-tool-img { + background-color: transparent; +} + +.x-message-box .x-window-body { + background-color: var(--drac-mantle) !important; +} + +/* Respect ExtJS inline display:none on hidden dialog buttons */ +.x-message-box .x-btn.x-btn-default-small[style*="display: none"], +.x-message-box .x-btn.x-btn-default-small[style*="display:none"], +.x-window .x-toolbar-footer .x-btn[style*="display: none"], +.x-window .x-toolbar-footer .x-btn[style*="display:none"] { + display: none !important; +} + +/* Login dialog — clean inner panel borders */ +.x-window:has(#pveloginrealm) .x-panel-body { + border: none !important; + background: transparent !important; + width: auto !important; +} + +/* ===================================================== + CONSOLE / TERMINAL + ===================================================== */ +div.monitor { + border-color: var(--drac-surface1); +} + +.install-mask { + background-color: var(--drac-crust); + color: var(--drac-subtext0); +} + +.x-window.install-mask { + box-shadow: rgba(30, 31, 41, 0.5) 0 4px 20px !important; +} + +/* ===================================================== + LEGEND / CHARTS + ===================================================== */ +.x-legend-container { + background-color: var(--drac-base) !important; +} + +.x-legend-horizontal .x-legend-item { + background-color: var(--drac-mantle) !important; + color: var(--drac-text) !important; + border: 1px solid var(--drac-surface0) !important; +} + +/* Chart/RRD panel backgrounds */ +div[id*="rrdchart"], +.pve-rrddatastore, +.pmx-panel-rrd { + background-color: var(--drac-base) !important; +} + +.proxmox-rrd-panel canvas, +.proxmox-widget-toolkit canvas, +canvas.x-surface, +.x-surface canvas { + background-color: transparent !important; + opacity: 1 !important; +} + +.proxmox-rrd-panel, +.proxmox-rrd-chart { + background-color: var(--drac-base) !important; +} + +/* Chart text/labels */ +.x-surface text, +svg text { + fill: var(--drac-text) !important; +} + +/* ===================================================== + PROXMOX-SPECIFIC OVERRIDES + ===================================================== */ + +/* Logo inversion */ +img[id^="proxmoxlogo-"][id$="-img"], +img[id^="proxmoxLogoSvg-"][id$="-img"] { + filter: invert(1) hue-rotate(180deg); +} + +/* Invalid/warning/disabled rows */ +.proxmox-invalid-row { + background-color: rgba(255, 85, 85, 0.15) !important; +} + +.proxmox-warning-row { + background-color: rgba(255, 184, 108, 0.15) !important; +} + +.proxmox-disabled-row td { + color: var(--drac-overlay0) !important; +} + +/* Hints */ +.pmx-hint { + background-color: rgba(255, 184, 108, 0.15) !important; + white-space: nowrap !important; +} + +.pmx-hint a { + color: var(--drac-cyan) !important; +} + +/* Status text colors — Information → Cyan */ +.info-blue { + color: var(--drac-cyan) !important; +} + +.critical { + color: var(--drac-red) !important; +} + +/* Links */ +a { + color: var(--drac-cyan) !important; +} + +/* Markdown content */ +.pmx-md code { + background-color: var(--drac-mantle) !important; + color: var(--drac-pink) !important; + border-radius: var(--pm-radius-sm) !important; +} + +.pmx-md pre code { + border-color: var(--drac-surface1) !important; + background-color: var(--drac-crust) !important; +} + +.pmx-md a { + color: var(--drac-cyan) !important; +} + +.pmx-md table { + border-color: var(--drac-surface1) !important; +} + +.pmx-md th { + background-color: var(--drac-mantle) !important; + border-color: var(--drac-surface1) !important; +} + +.pmx-md td { + border-color: var(--drac-surface1) !important; +} + +/* APT repos */ +.proxmox-apt-repos .x-grid-group-hd { + background-color: var(--drac-base) !important; + border: none !important; +} + +.proxmox-apt-repos .x-grid-group-title { + color: var(--drac-text) !important; +} + +/* Tags */ +.pve-edit-tag { + border-radius: var(--pm-radius-md) !important; +} + +.pve-edit-tag.editable span { + background-color: var(--drac-mantle) !important; + color: var(--drac-text) !important; + border-color: var(--drac-surface1) !important; +} + +.x-tree-node-text .proxmox-tag-dark, +.x-tree-node-text .proxmox-tag-light, +.x-grid-cell-inner .proxmox-tag-dark, +.x-grid-cell-inner .proxmox-tag-light, +span.proxmox-tag-dark, +span.proxmox-tag-light { + border-radius: var(--pm-radius-md) !important; +} + +/* Checkmark button in tag edit — match toolbar button size */ +.x-btn.x-btn-default-small:has(.fa-check) { + min-height: 24px !important; + height: 24px !important; + padding: 3px 8px !important; + border-radius: var(--pm-radius-sm) !important; + background-color: var(--drac-pink) !important; + border: none !important; +} + +.x-btn.x-btn-default-small:has(.fa-check).x-btn-disabled { + background-color: transparent !important; + border: 1px solid var(--drac-surface1) !important; + opacity: 0.5 !important; +} + +.x-btn.x-btn-default-small:has(.fa-check) .fa-check { + color: var(--drac-on-accent) !important; +} + +.x-btn.x-btn-default-small:has(.fa-check).x-btn-disabled .fa-check { + color: var(--drac-overlay1) !important; +} + +.x-btn.x-btn-default-small:has(.fa-check):not(.x-btn-disabled):hover { + background-color: #ff92d0 !important; +} + +.x-btn.x-btn-default-small:has(.fa-check) .x-btn-inner { + display: none !important; +} + +/* Date picker */ +.x-datepicker, +.x-datepicker-column-header, +.x-monthpicker { + background-color: var(--drac-base) !important; + color: var(--drac-text) !important; + border-color: transparent !important; +} + +.x-datepicker-header, +.x-datepicker-footer, +.x-monthpicker-buttons { + background-color: var(--drac-mantle) !important; +} + +.x-datepicker-date, +.x-monthpicker-item-inner { + color: var(--drac-text) !important; +} + +.x-datepicker-selected div.x-datepicker-date, +.x-monthpicker-item a.x-monthpicker-selected, +a.x-monthpicker-item-inner:hover, +div.x-datepicker-date:hover { + background-color: var(--drac-hover-overlay) !important; + color: var(--drac-text) !important; +} + +.x-datepicker-today .x-datepicker-date { + border-color: var(--drac-pink) !important; +} + +.x-datepicker-disabled .x-datepicker-date { + color: var(--drac-overlay0) !important; +} + +.x-datepicker-prev-day .x-datepicker-date, +.x-datepicker-next-day .x-datepicker-date { + color: var(--drac-overlay0) !important; +} + +/* Usage bars */ +.usage-wrapper, +.usage { + border-radius: 2px !important; +} + +.usage { + background-color: var(--drac-overlay2) !important; +} + +/* ===================================================== + SCROLLBARS + ===================================================== */ +::-webkit-scrollbar { + width: 8px; + height: 8px; +} + +::-webkit-scrollbar-track { + background: var(--drac-base); + border-radius: var(--pm-radius-sm); +} + +::-webkit-scrollbar-thumb { + background: var(--drac-surface2); + border-radius: var(--pm-radius-sm); + border: 1px solid transparent; + background-clip: padding-box; + transition: background 0.15s ease; +} + +::-webkit-scrollbar-thumb:hover { + background: var(--drac-overlay0); +} + +::-webkit-scrollbar-corner { + background: var(--drac-base); +} + +/* Firefox scrollbar */ +* { + scrollbar-width: thin; + scrollbar-color: var(--drac-surface2) var(--drac-base); +} + +/* ===================================================== + SELECTION HIGHLIGHT + ===================================================== */ +::selection { + background-color: rgba(98, 114, 164, 0.3); + color: var(--drac-text); +} + +/* ===================================================== + TRANSITIONS (smooth interactions) + ===================================================== */ + +/* Grid row transitions */ +.x-grid-item { + transition: background-color 0.15s ease !important; +} + +/* Tree pseudo-element transitions */ +.x-treelist-row::before { + transition: background-color 0.15s ease !important; +} + +/* Menu item transitions */ +.x-menu-item-default > .x-menu-item-link { + transition: background-color 0.12s ease !important; +} + +/* Boundlist item transitions */ +.x-boundlist-item { + transition: background-color 0.12s ease !important; +} + +/* Tab transitions */ +.x-tab { + transition: color 0.15s ease !important; +} + +/* Splitter transition */ +.x-splitter { + transition: background-color 0.15s ease !important; +} + +/* Tooltip transition */ +.x-tip { + transition: opacity 0.15s ease !important; +} + +/* Progress bar width transition */ +.x-progress-bar { + transition: width 0.4s ease !important; +} + +/* Scrollbar thumb transition */ +::-webkit-scrollbar-thumb { + transition: background 0.15s ease !important; +} + +/* Window close tool transition */ +.x-tool-img { + transition: filter 0.15s ease !important; +} + +/* ===================================================== + TOOL ICONS - FontAwesome Replacements + (Ported from UniFi v5.86) + Replace sprite-based ExtJS tool icons with crisp + FontAwesome icons for better consistency and clarity + ===================================================== */ + +/* Base styling for all tool icons - remove sprite backgrounds */ +.x-tool-tool-el.x-tool-minus, +.x-tool-img.x-tool-minus, +.x-tool-tool-el.x-tool-collapse-right, +.x-tool-img.x-tool-collapse-right, +.x-tool-tool-el.x-tool-collapse-left, +.x-tool-img.x-tool-collapse-left, +.x-tool-tool-el.x-tool-expand-right, +.x-tool-img.x-tool-expand-right, +.x-tool-tool-el.x-tool-expand-left, +.x-tool-img.x-tool-expand-left, +.x-tool-tool-el.x-tool-maximize, +.x-tool-img.x-tool-maximize, +.x-tool-tool-el.x-tool-restore, +.x-tool-img.x-tool-restore, +.x-tool-tool-el.x-tool-gear, +.x-tool-img.x-tool-gear, +.x-tool-tool-el.x-tool-refresh, +.x-tool-img.x-tool-refresh, +.x-tool-tool-el.x-tool-close, +.x-tool-img.x-tool-close { + background-image: none !important; + font-family: "FontAwesome" !important; + font-size: 14px !important; + line-height: 16px !important; + text-align: center !important; + color: var(--pm-text-dim) !important; + transition: color 0.15s ease !important; + filter: none !important; + width: 16px !important; + height: 16px !important; + display: flex !important; + align-items: center !important; + justify-content: center !important; +} + +/* Close button - slightly larger */ +.x-tool-tool-el.x-tool-close, +.x-tool-img.x-tool-close { + font-size: 20px !important; +} + +/* Individual glyph assignments */ +.x-tool-tool-el.x-tool-minus::before, +.x-tool-img.x-tool-minus::before { + content: "\f010" !important; /* fa-search-minus (zoom out) */ +} + +.x-tool-tool-el.x-tool-collapse-right::before, +.x-tool-img.x-tool-collapse-right::before { + content: "\f054" !important; /* fa-chevron-right */ +} + +.x-tool-tool-el.x-tool-expand-left::before, +.x-tool-img.x-tool-expand-left::before { + content: "\f053" !important; /* fa-chevron-left */ +} + +.x-tool-tool-el.x-tool-collapse-left::before, +.x-tool-img.x-tool-collapse-left::before { + content: "\f053" !important; /* fa-chevron-left */ +} + +.x-tool-tool-el.x-tool-expand-right::before, +.x-tool-img.x-tool-expand-right::before { + content: "\f054" !important; /* fa-chevron-right */ +} + +.x-tool-tool-el.x-tool-maximize::before, +.x-tool-img.x-tool-maximize::before { + content: "\f065" !important; /* fa-expand */ +} + +.x-tool-tool-el.x-tool-restore::before, +.x-tool-img.x-tool-restore::before { + content: "\f066" !important; /* fa-compress */ +} + +.x-tool-tool-el.x-tool-gear::before, +.x-tool-img.x-tool-gear::before { + content: "\f013" !important; /* fa-cog */ +} + +.x-tool-tool-el.x-tool-refresh::before, +.x-tool-img.x-tool-refresh::before { + content: "\f021" !important; /* fa-refresh */ +} + +.x-tool-tool-el.x-tool-close::before, +.x-tool-img.x-tool-close::before { + content: "\f00d" !important; /* fa-times */ +} + +/* Hover state - all tool icons */ +.x-tool:hover .x-tool-tool-el.x-tool-minus, +.x-tool:hover .x-tool-img.x-tool-minus, +.x-tool:hover .x-tool-tool-el.x-tool-collapse-right, +.x-tool:hover .x-tool-img.x-tool-collapse-right, +.x-tool:hover .x-tool-tool-el.x-tool-collapse-left, +.x-tool:hover .x-tool-img.x-tool-collapse-left, +.x-tool:hover .x-tool-tool-el.x-tool-expand-right, +.x-tool:hover .x-tool-img.x-tool-expand-right, +.x-tool:hover .x-tool-tool-el.x-tool-expand-left, +.x-tool:hover .x-tool-img.x-tool-expand-left, +.x-tool:hover .x-tool-tool-el.x-tool-maximize, +.x-tool:hover .x-tool-img.x-tool-maximize, +.x-tool:hover .x-tool-tool-el.x-tool-restore, +.x-tool:hover .x-tool-img.x-tool-restore, +.x-tool:hover .x-tool-tool-el.x-tool-gear, +.x-tool:hover .x-tool-img.x-tool-gear, +.x-tool:hover .x-tool-tool-el.x-tool-refresh, +.x-tool:hover .x-tool-img.x-tool-refresh, +.x-tool:hover .x-tool-tool-el.x-tool-close, +.x-tool:hover .x-tool-img.x-tool-close { + color: var(--pm-text) !important; +} + +/* Disabled state */ +.x-tool-disabled .x-tool-tool-el, +.x-tool-disabled .x-tool-img { + opacity: 0.4 !important; + cursor: default !important; +} + +/* Inline FontAwesome tools (PVE-injected) */ +.x-tool-tool-el[style*="font-family:FontAwesome"], +.x-tool-tool-el[style*="font-family: FontAwesome"] { + color: var(--pm-text-dim) !important; + font-size: 14px !important; + line-height: 16px !important; + display: flex !important; + align-items: center !important; + justify-content: center !important; + width: 16px !important; + height: 16px !important; + transition: color 0.15s ease !important; + background-image: none !important; + background-color: transparent !important; +} + +.x-tool:not(.x-tool-disabled) .x-tool-tool-el[style*="font-family:FontAwesome"], +.x-tool:not(.x-tool-disabled) .x-tool-tool-el[style*="font-family: FontAwesome"] { + cursor: pointer !important; +} + +.x-tool.x-tool-disabled .x-tool-tool-el[style*="font-family:FontAwesome"], +.x-tool.x-tool-disabled .x-tool-tool-el[style*="font-family: FontAwesome"] { + cursor: default !important; + opacity: 0.4 !important; +} + +.x-tool .x-mask { + background-color: transparent !important; + backdrop-filter: none !important; + pointer-events: none !important; +} + +.x-tool:not(.x-tool-disabled):hover .x-tool-tool-el[style*="font-family:FontAwesome"], +.x-tool:not(.x-tool-disabled):hover .x-tool-tool-el[style*="font-family: FontAwesome"] { + color: var(--pm-text) !important; +} diff --git a/themes/theme-dracula.css b/themes/theme-dracula.css new file mode 100644 index 0000000..e30ef1d --- /dev/null +++ b/themes/theme-dracula.css @@ -0,0 +1,2378 @@ +/*!Dracula*/ +/* + * ProxMorph Theme: Dracula + * The canonical dark theme with Purple accent — ported from the Dracula specification + * Version: 1.0.0 + * Author: ProxMorph / Dracula Theme (https://draculatheme.com) + * + * v1.0.0: Initial release — Tier 2 baseline with all fixes + * - Full Dracula palette with derived shades + * - All component sections ported from UniFi/Catppuccin reference + * - Console/Terminal, Charts, Progress bars, Buttons (28px), + * Dialog fixes, Tree cursor:pointer, APT repos, Tag checkmark + * + * ─── Dracula Specification Palette ───────────────────────────── + * Background: #282a36 Current Line: #44475a + * Foreground: #f8f8f2 Comment: #6272a4 + * Cyan: #8be9fd Green: #50fa7b + * Orange: #ffb86c Pink: #ff79c6 + * Purple: #bd93f9 Red: #ff5555 + * Yellow: #f1fa8c + * + * ─── Derived Shades (ProxMorph) ──────────────────────────────── + * Crust: #1e1f29 Mantle: #21222c + * Surface 0: #343746 Surface 1: #44475a (= Current Line) + * Surface 2: #565a72 Overlay 0: #6272a4 (= Comment) + * Overlay 1: #7c83a0 Overlay 2: #9298b8 + * Subtext 0: #b0b5c8 Subtext 1: #d0d4e0 + * Text: #f8f8f2 On-Accent: #282a36 + */ + +/* ===================================================== + CSS VARIABLES + ===================================================== */ +:root { + /* Dracula Specification Tokens */ + --drac-bg: #282a36; + --drac-current-line: #44475a; + --drac-fg: #f8f8f2; + --drac-comment: #6272a4; + --drac-cyan: #8be9fd; + --drac-green: #50fa7b; + --drac-orange: #ffb86c; + --drac-pink: #ff79c6; + --drac-purple: #bd93f9; + --drac-red: #ff5555; + --drac-yellow: #f1fa8c; + + /* Derived Neutral Scale */ + --drac-text: #f8f8f2; + --drac-subtext1: #d0d4e0; + --drac-subtext0: #b0b5c8; + --drac-overlay2: #9298b8; + --drac-overlay1: #7c83a0; + --drac-overlay0: #6272a4; + --drac-surface2: #565a72; + --drac-surface1: #44475a; + --drac-surface0: #343746; + --drac-base: #282a36; + --drac-mantle: #21222c; + --drac-crust: #1e1f29; + + /* ProxMorph Semantic Variables */ + --pm-accent: var(--drac-purple); + --pm-bg-base: var(--drac-base); + --pm-bg-surface: var(--drac-surface0); + --pm-bg-elevated: var(--drac-surface1); + --pm-text: var(--drac-text); + --pm-text-dim: var(--drac-subtext1); + --pm-success: var(--drac-green); + --pm-warning: var(--drac-yellow); + --pm-error: var(--drac-red); + --pm-border: var(--drac-surface1); + --pm-radius-sm: 4px; + --pm-radius-md: 6px; + --pm-radius-lg: 8px; + + /* Proxmox Widget Toolkit Mappings (REQUIRED) */ + --pwt-panel-background: var(--drac-base); + --pwt-text-color: var(--drac-text); + --pwt-gauge-default: var(--drac-purple); + --pwt-gauge-back: var(--drac-surface1); + --pwt-gauge-warn: var(--drac-yellow); + --pwt-gauge-crit: var(--drac-red); + --pwt-chart-primary: var(--drac-purple); + --pwt-chart-grid-stroke: var(--drac-surface1); + + /* On Accent text — Background on colored backgrounds for contrast */ + --drac-on-accent: var(--drac-bg); + + /* Hover overlay — Comment@12% */ + --drac-hover-overlay: rgba(98, 114, 164, 0.12); + /* Selection overlay — Comment@25% */ + --drac-select-overlay: rgba(98, 114, 164, 0.25); + /* Accent muted (for focus rings) */ + --drac-accent-muted: rgba(189, 147, 249, 0.4); + --drac-accent-subtle: rgba(189, 147, 249, 0.15); + + color-scheme: dark; +} + +/* ===================================================== + GLOBAL BORDER-RADIUS ARCHITECTURE + (Ported from UniFi theme — reset everything, selectively re-apply) + ===================================================== */ +.x-border-box, +.x-border-box * { + border-radius: var(--pm-radius-lg); +} + +/* Remove rounded corners from grids/tables/lists */ +.x-grid, +.x-grid *, +.x-grid-header-ct, +.x-grid-header-ct *, +.x-grid-view, +.x-grid-view *, +.x-column-header, +.x-column-header *, +.x-grid-item, +.x-grid-cell, +.x-grid-cell-inner, +.x-grid-row, +table, +table *, +tr, +td, +th, +.x-legend, +.x-legend *, +.x-legend-container, +.x-legend-container *, +.x-legend-item, +.x-legend-horizontal .x-legend-item, +.x-legend-vertical .x-legend-item, +.x-legend-horizontal .x-legend-item:first-child, +.x-legend-horizontal .x-legend-item:last-child, +.x-legend-vertical .x-legend-item:first-child, +.x-legend-vertical .x-legend-item:last-child, +.x-tool, +.x-tool-tool-el, +.x-tool-default, +.x-tool-img { + border-radius: 0 !important; +} + +/* Form elements - exclude from global radius */ +.x-form-item, +.x-form-item-default, +.x-form-item-body, +.x-form-item-body-default, +.x-form-text-field-body, +.x-form-text-field-body-default, +.x-form-fieldcontainer, +.x-field, +.x-field-default, +.x-form-type-text { + border-radius: 0 !important; +} + +/* Reset layout containers that clip elements with overflow:hidden + radius */ +.x-box-layout-ct, +.x-panel-bodyWrap, +.x-panel-bodyWrap-default, +.x-autocontainer-innerCt, +.x-autocontainer-outerCt, +.x-panel.x-tabpanel-child, +.x-panel.x-box-item, +.x-box-inner, +.x-box-target, +.x-container, +.x-container-default, +.x-window .x-panel-body, +.x-window .x-window-body, +.x-window .x-window-bodyWrap { + border-radius: 0 !important; +} + +/* Reset everything inside windows to 0 — then re-apply specific radii */ +.x-window *, +.x-window .x-autocontainer-innerCt, +.x-window .x-autocontainer-outerCt, +.x-window .x-form-layout-wrap, +.x-window .x-form-layout-auto-label, +.x-window .x-form-layout-colgroup, +.x-window .x-form-layout-column, +.x-window .x-field, +.x-window .x-form-item, +.x-window .x-form-item-body { + border-radius: 0 !important; +} + +/* Chart canvas — no radius on data area */ +.x-chart-grid, +.x-chart-axis, +canvas.x-surface, +.x-chart canvas, +canvas.x-surface-canvas, +.x-surface-canvas, +.x-draw-component canvas, +.proxmox-rrd-chart canvas, +svg.x-surface, +.x-draw-container, +.x-surface { + border-radius: 0 !important; +} + +/* Legend color marker (dot) — keep circular */ +.x-legend-item-marker { + border-radius: 50% !important; +} + +/* ===================================================== + RE-APPLY BORDER RADII (selective) + ===================================================== */ + +/* Windows */ +.x-window, +.x-window-default { + border-radius: var(--pm-radius-lg) !important; +} + +.x-window-header, +.x-window-header-default { + border-radius: var(--pm-radius-lg) var(--pm-radius-lg) 0 0 !important; +} + +.x-window .x-window-body, +.x-window-body-default { + border-radius: 0 !important; +} + +/* Buttons inside windows */ +.x-window .x-btn { + border-radius: var(--pm-radius-md) !important; +} + +/* Checkboxes inside windows */ +.x-window .x-form-checkbox { + border-radius: 3px !important; +} + +/* Form inputs inside windows */ +.x-window .x-form-trigger-wrap, +.x-window .x-form-trigger-wrap-default { + border-radius: var(--pm-radius-sm) !important; +} + +.x-window .x-form-text-wrap, +.x-window .x-form-text { + border-radius: var(--pm-radius-sm) 0 0 var(--pm-radius-sm) !important; +} + +.x-window .x-form-arrow-trigger { + border-radius: 0 var(--pm-radius-sm) var(--pm-radius-sm) 0 !important; +} + +/* Form trigger/text wrap — reset and re-apply */ +.x-form-trigger-wrap, +.x-form-trigger-wrap *, +.x-form-text-wrap, +.x-form-text-wrap *, +.x-form-text, +.x-form-trigger { + border-radius: 0 !important; +} + +.x-form-trigger-wrap, +.x-form-trigger-wrap-default { + border-radius: var(--pm-radius-sm) !important; + overflow: hidden !important; +} + +.x-form-text-wrap, +.x-form-text-wrap-default { + border-radius: var(--pm-radius-sm) 0 0 var(--pm-radius-sm) !important; +} + +.x-form-text, +.x-form-text-default { + border-radius: var(--pm-radius-sm) 0 0 var(--pm-radius-sm) !important; +} + +.x-form-trigger, +.x-form-trigger-default, +.x-form-arrow-trigger, +.x-form-arrow-trigger-default { + border-radius: 0 var(--pm-radius-sm) var(--pm-radius-sm) 0 !important; +} + +/* Dialog form content padding — vertical only (horizontal causes ExtJS overflow) */ +.x-window .x-tabpanel-child .x-autocontainer-innerCt { + padding: 12px 0 !important; +} + +/* Allow column panel bodies to show overflowed form content */ +.x-window .x-panel-body:not(.x-scroller) { + overflow: visible !important; +} + +/* Side padding on column panel bodies inside windows */ +.x-window .x-panel.x-box-item .x-panel-body { + padding: 0 4px !important; +} + +/* Constrain autocontainer width inside windows */ +.x-window .x-autocontainer-outerCt { + max-width: 100% !important; +} + +/* Fix window header/body width consistency */ +.x-window > .x-window-header, +.x-window > .x-window-body, +.x-window > .x-window-bodyWrap, +.x-window-bodyWrap > .x-window-body { + width: 100% !important; +} + +.x-window-header > .x-box-inner, +.x-window-header > .x-box-inner > .x-box-target { + width: 100% !important; +} + +.x-window-header-title { + width: auto !important; + flex: 1 !important; + max-width: calc(100% - 30px) !important; +} + +/* Boundlists */ +.x-boundlist { + border-radius: var(--pm-radius-md) !important; + overflow: hidden !important; +} + +/* ===================================================== + BASE / BODY + ===================================================== */ +.x-body, +.x-viewport > .x-body, +body.x-border-layout-ct, +div.x-border-layout-ct { + background-color: var(--drac-base) !important; + color: var(--drac-text) !important; +} + +/* ===================================================== + MASKS & OVERLAYS + ===================================================== */ +.x-mask { + background-color: rgba(30, 31, 41, 0.6) !important; + backdrop-filter: blur(4px); +} + +.x-mask-msg { + background-color: var(--drac-mantle) !important; + border: 1px solid var(--drac-surface1) !important; + border-radius: var(--pm-radius-lg) !important; +} + +.x-mask-msg-text { + color: var(--drac-subtext0) !important; + filter: none !important; +} + +.x-css-shadow { + box-shadow: 0 8px 24px rgba(30, 31, 41, 0.6) !important; +} + +/* Loading indicators */ +.x-grid-row-loading, +.x-treelist-item-loading .x-treelist-item-icon, +.x-grid-tree-loading .x-tree-icon { + filter: invert(90%); +} + +/* ===================================================== + ICONS — Proxmox default colors for dark mode + ===================================================== */ + +/* General icon colors — neutral gray for dark backgrounds */ +.x-tree-icon-custom, +.x-grid-icon-custom, +.fa-tags::before, +.fa-file-o::before, +.fa-building::before, +.x-action-col-icon::before, +.fa-shield::before, +.fa-file-text-o::before, +.fa-clock-o::before, +.x-tab-icon-el-default, +.pve-icon-verify-lettering::after, +.x-tree-icon-leaf:not(.x-tree-icon-custom)::before, +.x-tree-icon-parent:not(.x-tree-icon-custom)::before, +.x-tree-icon-parent-expanded:not(.x-tree-icon-custom)::before, +.x-grid-filters-filtered-column .x-column-header-text::after { + color: var(--drac-overlay2) !important; +} + +/* Folder icons — invert for dark mode */ +.x-tree-icon-parent:not(.x-tree-icon-custom)::before, +.x-tree-icon-parent-expanded:not(.x-tree-icon-custom)::before { + filter: invert(90%); +} + +/* Various image-based icons — invert for visibility */ +.fa-ceph::before, +.fa-sdn::before, +.fa-network-wired::before, +.pve-itype-treelist-item-icon-cdrom, +.fa-chevron-right::before, +.x-grid-row-console, +.x-box-scroller-toolbar-default.x-box-scroller, +.x-tree-elbow-img, +.pve-itype-icon-qemu, +.x-tree-node-computer, +.x-grid-tree-node-expanded .x-tree-node-computer, +.pbs-icon-tape, +.pbs-icon-tape-drive, +.x-tree-icon-leaf:not(.x-tree-icon-custom), +.x-tree-icon-parent:not(.x-tree-icon-custom), +.x-tree-icon-parent-expanded:not(.x-tree-icon-custom) { + filter: invert(90%); +} + +/* Hardware icons */ +.pve-itype-icon-cpu, +.pve-itype-icon-cdrom, +.pve-itype-icon-memory, +.pve-itype-icon-pci, +.pve-itype-icon-serial, +.pve-itype-icon-die, +.pmx-itype-icon-processor, +.pmx-itype-icon-memory, +.pve-itype-icon-storage, +.x-tree-node-harddisk, +.x-grid-tree-node-expanded .x-tree-node-harddisk { + filter: invert(100%); +} + +/* Hardware icons — counter-invert for non-SVG icon cells */ +td.pve-itype-icon-storage .x-grid-cell-inner, +td.x-tree-node-harddisk .x-grid-cell-inner { + filter: invert(100%) !important; +} + +/* Hardware icons — hide inverted borders for non-SVG icon cells */ +td.pve-itype-icon-storage, +td.x-tree-node-harddisk { + border-color: transparent !important; +} + +/* Hardware grid icons — mask-image renders SVG icons in theme text color + Replaces filter:invert approach for pve-itype-icon-* and pmx-itype-icon-* grid cells */ +td.pve-itype-icon-cpu, +td.pve-itype-icon-cdrom, +td.pve-itype-icon-memory, +td.pve-itype-icon-pci, +td.pve-itype-icon-serial, +td.pve-itype-icon-die, +td.pmx-itype-icon-processor, +td.pmx-itype-icon-memory { + filter: none !important; + background-image: none !important; + padding-left: 0 !important; + border-color: transparent !important; +} + +td.pve-itype-icon-cpu .x-grid-cell-inner, +td.pve-itype-icon-cdrom .x-grid-cell-inner, +td.pve-itype-icon-memory .x-grid-cell-inner, +td.pve-itype-icon-pci .x-grid-cell-inner, +td.pve-itype-icon-serial .x-grid-cell-inner, +td.pve-itype-icon-die .x-grid-cell-inner, +td.pmx-itype-icon-processor .x-grid-cell-inner, +td.pmx-itype-icon-memory .x-grid-cell-inner { + padding-left: 3px !important; +} + +td.pve-itype-icon-cpu .x-grid-cell-inner::before, +td.pve-itype-icon-cdrom .x-grid-cell-inner::before, +td.pve-itype-icon-memory .x-grid-cell-inner::before, +td.pve-itype-icon-pci .x-grid-cell-inner::before, +td.pve-itype-icon-serial .x-grid-cell-inner::before, +td.pve-itype-icon-die .x-grid-cell-inner::before, +td.pmx-itype-icon-processor .x-grid-cell-inner::before, +td.pmx-itype-icon-memory .x-grid-cell-inner::before { + content: '' !important; + display: inline-block !important; + width: 18px !important; + height: 14px !important; + vertical-align: middle !important; + margin-right: 10px !important; + background-color: currentColor !important; + -webkit-mask-size: contain !important; + mask-size: contain !important; + -webkit-mask-repeat: no-repeat !important; + mask-repeat: no-repeat !important; + -webkit-mask-position: center !important; + mask-position: center !important; +} + +td.pve-itype-icon-cpu .x-grid-cell-inner::before { + -webkit-mask-image: url('/pve2/images/icon-cpu.svg') !important; + mask-image: url('/pve2/images/icon-cpu.svg') !important; +} + +td.pve-itype-icon-memory .x-grid-cell-inner::before { + -webkit-mask-image: url('/pve2/images/icon-memory.svg') !important; + mask-image: url('/pve2/images/icon-memory.svg') !important; +} + +td.pve-itype-icon-cdrom .x-grid-cell-inner::before { + -webkit-mask-image: url('/pve2/images/icon-cd-drive.svg') !important; + mask-image: url('/pve2/images/icon-cd-drive.svg') !important; +} + +td.pve-itype-icon-pci .x-grid-cell-inner::before { + -webkit-mask-image: url('/pve2/images/icon-pci.svg') !important; + mask-image: url('/pve2/images/icon-pci.svg') !important; +} + +td.pve-itype-icon-serial .x-grid-cell-inner::before { + -webkit-mask-image: url('/pve2/images/icon-serial.svg') !important; + mask-image: url('/pve2/images/icon-serial.svg') !important; +} + +td.pve-itype-icon-die .x-grid-cell-inner::before { + -webkit-mask-image: url('/pve2/images/icon-die.svg') !important; + mask-image: url('/pve2/images/icon-die.svg') !important; +} + +td.pmx-itype-icon-processor .x-grid-cell-inner::before { + -webkit-mask-image: url('../images/icon-cpu.svg') !important; + mask-image: url('../images/icon-cpu.svg') !important; +} + +td.pmx-itype-icon-memory .x-grid-cell-inner::before { + -webkit-mask-image: url('../images/icon-ram.svg') !important; + mask-image: url('../images/icon-ram.svg') !important; +} + + +/* Icon overlays — default */ +.x-tree-icon-custom::after, +.x-grid-icon-custom::after { + color: var(--drac-overlay2) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* RUNNING VMs/CTs — Dracula Green */ +.x-tree-icon-custom.running::after, +.x-grid-icon-custom.running::after, +.x-treelist-item-icon.running::after { + color: var(--drac-green) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* ONLINE state — Green */ +.x-tree-icon-custom.online::after, +.x-grid-icon-custom.online::after { + color: var(--drac-green) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* Stopped/offline — Overlay1 (muted gray) */ +.x-tree-icon-custom.stopped, +.x-tree-icon-custom.offline, +.x-grid-icon-custom.stopped, +.x-grid-icon-custom.offline { + color: var(--drac-overlay1) !important; +} + +/* Unknown state — Overlay1 */ +.x-tree-icon-custom.unknown::after, +.x-grid-icon-custom.unknown::after { + color: var(--drac-overlay1) !important; +} + +/* ERROR states — Dracula Red */ +.x-tree-icon-custom.error::after, +.x-tree-icon-custom.offline::after, +.x-tree-icon-custom.ha-error::after, +.x-grid-icon-custom.error::after, +.x-grid-icon-custom.offline::after, +.x-grid-icon-custom.ha-error::after { + color: var(--drac-red) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* PAUSED/SUSPENDED — Dracula Orange */ +.x-tree-icon-custom.paused::after, +.x-tree-icon-custom.suspended::after, +.x-tree-icon-custom.lock-suspending::after, +.x-grid-icon-custom.paused::after, +.x-grid-icon-custom.suspended::after, +.x-grid-icon-custom.lock-suspending::after { + color: var(--drac-orange) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* PENDING/WARNING states — Dracula Yellow */ +.x-tree-icon-custom.pending::after, +.x-tree-icon-custom.io-error::after, +.x-tree-icon-custom.internal-error::after, +.x-tree-icon-custom.guest-panicked::after, +.x-grid-icon-custom.pending::after, +.x-grid-icon-custom.io-error::after, +.x-grid-icon-custom.internal-error::after, +.x-grid-icon-custom.guest-panicked::after { + color: var(--drac-yellow) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* HA MAINTENANCE — Dracula Cyan */ +.x-tree-icon-custom.ha-maintenance::after, +.x-grid-icon-custom.ha-maintenance::after { + color: var(--drac-cyan) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* Locked icons */ +.x-tree-icon-custom.locked::after, +.x-tree-icon-custom.lock-backup::after, +.x-tree-icon-custom.lock-migrate::after, +.x-tree-icon-custom.lock-suspended::after, +.x-grid-icon-custom.locked::after, +.x-grid-icon-custom.lock-backup::after, +.x-grid-icon-custom.lock-migrate::after, +.x-grid-icon-custom.lock-suspended::after { + color: var(--drac-overlay2) !important; +} + +/* LXC/QEMU type indicators */ +.x-tree-icon-custom.lxc::after, +.x-tree-icon-custom.qemu::after, +.x-grid-icon-custom.lxc::after, +.x-grid-icon-custom.qemu::after { + background-color: transparent; + color: var(--drac-overlay1) !important; +} + +.x-treelist-item-icon.lxc::after, +.x-treelist-item-icon.qemu::after { + background-color: transparent; + color: var(--drac-overlay1) !important; +} + +/* Tree expander arrows */ +.x-tree-arrows .x-tree-expander { + filter: brightness(200%); +} + +/* Cancel sprite-inversion on custom controls (checkboxes/radios handled via CSS) */ +.x-form-checkbox-default, +.x-form-radio-default, +.x-column-header-checkbox .x-column-header-checkbox::after, +.x-grid-checkcolumn::after, +.x-menu-item-checked .x-menu-item-icon-default.x-menu-item-checkbox, +.x-menu-item-unchecked .x-menu-item-icon-default.x-menu-item-checkbox { + filter: none !important; +} + +/* ===================================================== + PANELS & HEADERS + ===================================================== */ +.x-panel, +.x-panel-default { + border-radius: var(--pm-radius-lg) !important; + padding: 0 !important; +} + +/* Column panels — native stacked layout (Issue #23 fix) */ +.x-panel.x-column { + padding: 5px !important; + margin: 0 !important; + max-width: none !important; + box-sizing: border-box !important; +} + +/* Column panel card styling — borders for summary + chart panels */ +.x-panel.x-panel-default.x-column { + border: 1px solid var(--drac-surface1) !important; + border-radius: var(--pm-radius-lg) !important; + overflow: hidden !important; +} + +/* Guest status + Notes panel borders */ +[id^="pveGuestStatusView-"].x-panel, +[id^="pveLxcStatusView-"].x-panel, +[id^="pveQemuStatusView-"].x-panel, +[id^="pmxNotesView-"].x-panel { + border: 1px solid var(--drac-surface1) !important; + border-radius: var(--pm-radius-lg) !important; +} + +.x-panel-body, +.x-panel-body-default { + background-color: var(--drac-base) !important; + color: var(--drac-text) !important; + border: none !important; +} + +/* Panel headers — bottom border only */ +.x-panel-header, +.x-panel-header-default { + background-color: var(--drac-mantle) !important; + border: none !important; + border-bottom: 1px solid var(--drac-surface1) !important; + border-radius: var(--pm-radius-lg) var(--pm-radius-lg) 0 0 !important; + margin: 0 !important; + padding: 8px 12px !important; + width: 100% !important; + box-sizing: border-box !important; + overflow: visible !important; +} + +/* Title text — prevent border-radius clipping */ +.x-title-text, +.x-title-text-default { + overflow: visible !important; +} + +.x-panel-bodyWrap, +.x-panel-bodyWrap-default { + margin: 0 !important; + padding: 0 !important; + overflow: visible !important; +} + +/* Remove borders from nested panels */ +.x-panel-body > .x-box-layout-ct, +.x-panel-body > .x-container, +.x-panel-body > .x-box-inner, +[id*="pmxGauge"] { + border: none !important; +} + +.x-panel-header-title-default, +.x-window-header-title-default { + color: var(--drac-text) !important; +} + +.x-panel-header-default .x-tool-tool-el { + background-color: transparent; +} + +.x-tool-img { + filter: brightness(175%); +} + +.x-tool-over .x-tool-img { + filter: brightness(200%); +} + +/* Resource tree — panel body border */ +div[id^="pveResourceTree-"][id$="-body"] { + border-color: var(--drac-base) !important; +} + +/* Resource tree — remove row separators */ +[id^="pveResourceTree-"].x-tree-panel td.x-grid-cell, +[id^="pveResourceTree-"].x-tree-panel .x-grid-td, +[id^="pveResourceTree-"].x-tree-panel .x-grid-cell { + border-bottom: none !important; +} + +/* Resource tree — row spacing */ +div[id^="pveResourceTree"] .x-grid-cell { + padding-top: 3px !important; + padding-bottom: 3px !important; +} + +/* Summary/stats panel radius overrides */ +.pveStatusPanel, +.x-panel-default-framed, +.x-panel-body-default-framed { + border-radius: 12px !important; +} + +.x-panel-header-default-framed { + border-radius: 12px 12px 0 0 !important; +} + +/* Column widget panel radius */ +.x-panel.x-column > .x-panel-bodyWrap > .x-panel-body.x-panel-body-default { + border-radius: var(--pm-radius-lg) !important; +} + +/* ===================================================== + SPLITTERS / SEPARATORS + ===================================================== */ +.x-splitter-vertical { + background-color: transparent !important; + border-left: 1px solid var(--drac-surface1) !important; + border-right: none !important; + width: 1px !important; +} + +.x-splitter-horizontal { + background-color: var(--drac-crust) !important; + border-top: 1px solid var(--drac-surface1) !important; +} + +.x-splitter { + background-color: var(--drac-crust) !important; +} + +.x-keyboard-mode .x-splitter-focus::after { + border-color: var(--drac-purple) !important; +} + +.x-layout-split-bottom { + opacity: 0.7; +} + +/* Toolbox tree (pve-nav) right border — full height */ +.pve-toolbar-bg { + border-right: 1px solid var(--drac-surface1) !important; + z-index: 3 !important; +} + +.x-treelist.x-treelist-pve-nav { + border-right: none !important; +} + +/* ===================================================== + TOOLBARS + ===================================================== */ +.x-toolbar, +.x-toolbar-default { + background-color: var(--drac-base) !important; + border-color: var(--drac-surface1) !important; +} + +.x-toolbar-default.x-docked-top { + border: none !important; + border-bottom: 1px solid var(--drac-surface1) !important; +} + +.x-toolbar-default .x-toolbar-separator { + border-color: var(--drac-surface1); +} + +.x-toolbar-text-default { + color: var(--drac-subtext0); +} + +/* ===================================================== + PRIMARY BUTTONS — Dracula Purple + ===================================================== */ +.x-btn-default-small { + background-color: var(--drac-purple) !important; + border: 1px solid rgba(189, 147, 249, 0.4) !important; + border-radius: var(--pm-radius-md) !important; + transition: background-color 0.15s ease, box-shadow 0.15s ease !important; +} + +.x-btn-default-small .x-btn-inner { + color: var(--drac-on-accent) !important; + font-weight: 600 !important; +} + +.x-btn-default-small .x-btn-icon-el { + color: var(--drac-on-accent) !important; +} + +.x-btn-default-small.x-btn-over, +.x-keyboard-mode .x-btn-default-small.x-btn-focus { + background-color: #caa9fa !important; + box-shadow: 0 0 0 3px var(--drac-accent-subtle) !important; +} + +.x-btn-default-small.x-btn.x-btn-disabled { + background-color: var(--drac-purple) !important; + opacity: 0.4; +} + +.x-btn-default-small.x-btn.x-btn-pressed { + background-color: #a986f0 !important; +} + +/* Button height consistency — 28px with vertical centering */ +/* Exclude tag edit buttons (display:none when hidden, :has(.fa-check) for checkmark) */ +.x-btn.x-btn-default-small:not(.x-btn-default-toolbar-small):not([style*="display: none"]):not([style*="display:none"]):not(:has(.fa-check)) { + height: 28px !important; + min-height: 28px !important; + display: flex !important; + align-items: center !important; + padding: 3px 8px !important; +} + +/* Fix button inner element centering for proper icon alignment (issue #17) */ +.x-btn.x-btn-default-small:not(.x-btn-default-toolbar-small):not([style*="display: none"]):not([style*="display:none"]):not(:has(.fa-check)) .x-btn-wrap { + display: flex !important; + align-items: center !important; +} + +.x-btn.x-btn-default-small:not(.x-btn-default-toolbar-small):not([style*="display: none"]):not([style*="display:none"]):not(:has(.fa-check)) .x-btn-inner { + display: flex !important; + align-items: center !important; +} + +/* Fix dropdown arrows on split/arrow buttons */ +.x-btn-wrap.x-btn-arrow-right::after, +.x-btn-wrap.x-btn-split-right::after { + height: 16px !important; + min-height: 16px !important; + width: 20px !important; + display: flex !important; + align-items: center !important; +} + +/* Fix icon-only buttons — hide   inner element when button has no text */ +.x-btn-no-text .x-btn-inner, +.x-btn-button.x-btn-no-text .x-btn-inner, +.x-btn-button-default-toolbar-small.x-btn-no-text .x-btn-inner-default-toolbar-small, +.x-btn-button-default-small.x-btn-no-text .x-btn-inner-default-small, +.x-btn-button-default-small.x-btn-no-text > .x-btn-inner-default-small { + display: none !important; +} + +/* Specific fix for fa-desktop icon (Create VM) — visually bottom-heavy */ +.x-btn-icon-el.fa-desktop { + transform: translateY(1.1px) !important; +} + +/* ===================================================== + SECONDARY / TOOLBAR BUTTONS + ===================================================== */ +.x-btn-default-toolbar-small { + background-color: var(--drac-surface0) !important; + border: 1px solid var(--drac-surface1) !important; + border-radius: var(--pm-radius-md) !important; + transition: background-color 0.15s ease, border-color 0.15s ease !important; +} + +.x-btn-default-toolbar-small .x-btn-inner-default-toolbar-small, +.x-btn-default-toolbar-small .x-btn-icon-el-default-toolbar-small { + color: var(--drac-text) !important; +} + +.x-btn-default-toolbar-small .x-btn-wrap-default-toolbar-small.x-btn-arrow-right::after, +.x-btn-default-toolbar-small .x-btn-wrap-default-toolbar-small.x-btn-split-right::after { + filter: brightness(150%); +} + +.x-btn-default-toolbar-small.x-btn-over, +.x-keyboard-mode .x-btn-default-toolbar-small.x-btn-focus { + background-color: var(--drac-surface1) !important; + border-color: var(--drac-surface2) !important; +} + +.x-btn-default-toolbar-small.x-btn.x-btn-disabled { + background-color: var(--drac-surface0) !important; + opacity: 0.4; +} + +.x-btn-default-toolbar-small.x-btn.x-btn-menu-active, +.x-btn-default-toolbar-small.x-btn.x-btn-pressed { + background-color: var(--drac-purple) !important; + border-color: var(--drac-purple) !important; + padding: 4px 8px !important; /* Fix #30: prevent width change on dropdown */ +} + +.x-btn-default-toolbar-small.x-btn.x-btn-pressed .x-btn-inner-default-toolbar-small, +.x-btn-default-toolbar-small.x-btn.x-btn-pressed .x-btn-icon-el-default-toolbar-small, +.x-btn-default-toolbar-small.x-btn.x-btn-pressed .x-btn-inner-default-small, +.x-btn-default-toolbar-small.x-btn.x-btn-pressed .x-btn-icon-el-default-small { + color: var(--drac-on-accent) !important; +} + +/* Segmented buttons */ +.x-segmented-button { + border-radius: var(--pm-radius-md) !important; +} + +.x-segmented-button .x-btn, +.x-segmented-button .x-btn-default-small, +.x-segmented-button .x-btn-inner, +.x-segmented-button .x-btn-wrap { + border-radius: var(--pm-radius-md) !important; +} + +/* Inline buttons (Documentation, Help) */ +.proxmox-inline-button { + height: 28px !important; + min-height: 28px !important; + display: flex !important; + align-items: center !important; + padding: 3px 8px !important; + background-color: var(--drac-surface0) !important; + border: 1px solid var(--drac-surface1) !important; + border-radius: var(--pm-radius-md) !important; + color: var(--drac-text) !important; + transition: background-color 0.15s ease !important; +} + +.proxmox-inline-button:hover, +.proxmox-inline-button.x-btn-over { + background-color: var(--drac-surface1) !important; + border-color: var(--drac-overlay0) !important; +} + +.proxmox-inline-button:active, +.proxmox-inline-button.x-btn-pressed { + background-color: var(--drac-surface2) !important; +} + +.proxmox-inline-button .x-btn-inner, +.proxmox-inline-button .x-btn-icon-el { + color: var(--drac-text) !important; +} + +/* Pressed/active inline buttons — use on-accent text */ +.proxmox-inline-button.x-btn-pressed .x-btn-inner, +.proxmox-inline-button.x-btn-pressed .x-btn-icon-el, +.proxmox-inline-button.x-btn-menu-active .x-btn-inner, +.proxmox-inline-button.x-btn-menu-active .x-btn-icon-el { + color: var(--drac-on-accent) !important; +} + +/* ===================================================== + FORM ELEMENTS + ===================================================== */ +.x-form-trigger-default { + background-color: var(--drac-surface0) !important; +} + +.x-form-text-default { + background-color: var(--drac-surface0) !important; + color: var(--drac-text) !important; + border-radius: var(--pm-radius-sm) !important; +} + +.x-form-trigger-wrap, +.x-form-trigger-wrap-default { + border-color: var(--drac-surface1) !important; + background-color: var(--drac-surface0) !important; + border-radius: var(--pm-radius-sm) !important; + transition: border-color 0.15s ease !important; +} + +.x-form-trigger-wrap-default.x-form-trigger-wrap-focus { + border-color: var(--drac-purple) !important; + box-shadow: 0 0 0 3px var(--drac-accent-subtle) !important; +} + +.x-form-item-label-default, +.x-form-cb-label-default { + color: var(--drac-text) !important; +} + +.x-form-display-field-default { + color: var(--drac-subtext0) !important; + border-radius: var(--pm-radius-md) !important; +} + +.x-form-spinner-default { + background-color: var(--drac-surface0) !important; +} + +.x-fieldset, +.x-fieldset-default { + border-color: var(--drac-surface1) !important; + border-radius: var(--pm-radius-lg) !important; +} + +.x-fieldset-header-default > .x-fieldset-header-text { + color: var(--drac-text) !important; +} + +/* ===================================================== + CHECKBOXES & RADIOS — Dracula styled + ===================================================== */ + +/* Base: remove sprite, styled as custom control */ +.x-form-checkbox, .x-form-checkbox-default, +.x-form-radio, .x-form-radio-default { + background-image: none !important; + background-color: var(--drac-surface0) !important; + border: 1.5px solid var(--drac-overlay0) !important; + width: 16px !important; + height: 16px !important; + display: inline-block !important; + box-sizing: border-box !important; + cursor: pointer !important; + transition: border-color 0.12s ease, background-color 0.12s ease !important; +} + +/* Checkbox: rounded square */ +.x-form-checkbox, .x-form-checkbox-default { + border-radius: 3px !important; +} + +/* Radio: circle + ::after inner dot */ +.x-form-radio, .x-form-radio-default { + border-radius: 50% !important; + position: relative !important; + transform: translateZ(0) !important; + box-shadow: inset 0 0 0 0 transparent !important; +} + +.x-form-radio::after { + content: '' !important; + position: absolute !important; + top: 50% !important; + left: 50% !important; + width: 7px !important; + height: 7px !important; + border-radius: 50% !important; + background: transparent !important; + transform: translate(-50%, -50%) scale(0) !important; + transition: transform 0.15s ease, background 0.15s ease !important; + pointer-events: none !important; +} + +/* Hover */ +.x-form-checkbox:hover, .x-form-checkbox-default:hover, +.x-form-cb-wrap:hover .x-form-checkbox { + border-color: var(--drac-purple) !important; +} + +.x-form-radio:hover, .x-form-radio-default:hover, +.x-form-cb-wrap:hover .x-form-radio { + border-color: var(--drac-purple) !important; +} + +/* CHECKED checkbox — Purple fill + dark SVG checkmark */ +.x-form-cb-checked .x-form-checkbox, +.x-form-cb-checked .x-form-checkbox-default { + background-color: var(--drac-purple) !important; + border-color: var(--drac-purple) !important; + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 8'%3E%3Cpath d='M1 4l3 3 5-6' fill='none' stroke='%23282a36' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") !important; + background-repeat: no-repeat !important; + background-position: center !important; + background-size: 9px 7px !important; +} + +/* SELECTED radio — Purple dot */ +.x-form-cb-checked .x-form-radio, +.x-form-cb-checked .x-form-radio-default { + border-color: var(--drac-purple) !important; + background-color: var(--drac-base) !important; +} + +.x-form-cb-checked .x-form-radio::after { + background: var(--drac-purple) !important; + transform: translate(-50%, -50%) scale(1) !important; +} + +/* ===================================================== + BOUNDLIST / DROPDOWNS + ===================================================== */ +.x-boundlist { + background-color: var(--drac-mantle) !important; + border: 1px solid var(--drac-surface1) !important; + border-radius: var(--pm-radius-md) !important; + box-shadow: 0 8px 24px rgba(30, 31, 41, 0.7) !important; + padding: 2px !important; + overflow: hidden !important; +} + +.x-boundlist-item { + background-color: transparent !important; + color: var(--drac-text) !important; + border-radius: var(--pm-radius-sm) !important; + padding: 2px 6px !important; + line-height: normal !important; + border: none !important; + cursor: pointer !important; + outline: none !important; + box-shadow: none !important; +} + +.x-boundlist-selected { + background-color: var(--drac-select-overlay) !important; + color: var(--drac-text) !important; +} + +.x-boundlist-item-over { + background-color: var(--drac-hover-overlay) !important; +} + +/* ===================================================== + GRIDS / TABLES + ===================================================== */ +.x-grid, +.x-grid-view { + border-radius: 0 !important; +} + +.x-column-header { + border-color: var(--drac-surface1) !important; + background-color: transparent !important; +} + +.x-column-header-inner, +.x-column-header-text { + color: var(--drac-text) !important; + font-weight: 600 !important; +} + +.x-column-header-trigger { + border-color: var(--drac-surface1) !important; +} + +.x-grid-item, +.x-column-header-default, +.x-grid-cell-row-numberer { + color: var(--drac-text) !important; + background-color: var(--drac-base) !important; +} + +.x-grid-cell-special { + border-color: var(--drac-surface1) !important; +} + +.x-grid-group-hd { + background-color: var(--drac-base) !important; + border-color: var(--drac-surface1) !important; +} + +.x-grid-group-title { + color: var(--drac-text) !important; +} + +.x-grid-header-ct { + background-color: var(--drac-mantle) !important; + border: 1px solid var(--drac-surface0) !important; + border-radius: var(--pm-radius-lg) var(--pm-radius-lg) 0 0 !important; +} + +.x-grid-item-alt { + background-color: var(--drac-crust) !important; +} + +.x-grid-with-row-lines .x-grid-item { + border-color: var(--drac-surface0) !important; +} + +.x-grid-cell { + border-bottom: 1px solid rgba(68, 71, 90, 0.4) !important; +} + +.x-grid-item-over, +.x-grid-with-row-lines .x-grid-item.x-grid-item-over { + background-color: var(--drac-hover-overlay) !important; +} + +.x-grid-item-selected, +.x-grid-with-row-lines .x-grid-item.x-grid-item-selected { + background-color: var(--drac-select-overlay) !important; +} + +.x-column-header-over, +.x-column-header-open { + background-color: var(--drac-hover-overlay) !important; +} + +.x-column-header-sort-ASC, +.x-column-header-sort-DESC { + background-color: var(--drac-hover-overlay) !important; +} + +.x-grid-row-summary .x-grid-cell, +.x-grid-row-summary .x-grid-rowwrap, +.x-grid-row-summary .x-grid-cell-rowbody { + background-color: var(--drac-base) !important; + border-color: var(--drac-surface1); +} + +.x-grid-with-col-lines .x-grid-cell, +.x-grid-with-col-lines .x-grid-item-over .x-grid-cell, +.x-grid-with-col-lines .x-grid-item-selected .x-grid-cell { + border-color: var(--drac-surface1) !important; +} + +.x-dd-drag-proxy { + background-color: var(--drac-mantle); + border-color: var(--drac-surface1); + color: var(--drac-text); +} + +.x-keyboard-mode .x-grid-item-focused { + background-color: var(--drac-hover-overlay) !important; + color: var(--drac-text) !important; +} + +/* Remove blue outline from focused/selected items in resource tree */ +.x-keyboard-mode .x-grid-item-focused .x-grid-cell-inner::before, +.x-keyboard-mode .x-grid-item-selected .x-grid-cell-inner::before, +.x-grid-item-selected .x-grid-cell-inner::before, +.x-grid-item-focused .x-grid-cell-inner::before, +[id^="pveResourceTree"] .x-grid-item-selected .x-grid-cell-inner::before, +[id^="pveResourceTree"] .x-grid-item-focused .x-grid-cell-inner::before { + content: none !important; + display: none !important; + border: none !important; +} + +.x-grid-empty { + background-color: var(--drac-base) !important; + color: var(--drac-subtext0) !important; +} + +/* Grid info (pve-info-grid) and RRD view */ +.pve-info-grid { + border-radius: 12px !important; +} + +.pve-rrdview, +.rrdview { + border-radius: 12px !important; +} + +.pve-summary-status, +.x-container .pve-status { + border-radius: var(--pm-radius-lg) !important; +} + +[id^="pveGuestStatusView-"][id$="-body"], +[id^="pmxNotesView-"] .x-panel-body { + border-radius: var(--pm-radius-lg) !important; +} + +.x-panel-default[id*="notes"], +.pve-notes-view { + border-radius: var(--pm-radius-lg) !important; +} + +/* Floating grid pickers (storage/ISO selectors) */ +.x-layer.x-grid .x-grid-view, +.x-panel.x-layer.x-grid .x-grid-view, +.x-panel.x-layer.x-grid, +.x-layer.x-panel.x-grid { + border-radius: var(--pm-radius-sm) !important; +} + +.x-layer.x-grid .x-grid-item-over, +.x-layer.x-grid .x-grid-item-selected, +.x-panel.x-layer.x-grid .x-grid-item-over, +.x-panel.x-layer.x-grid .x-grid-item-selected { + border-radius: var(--pm-radius-sm) !important; + outline: none !important; + box-shadow: none !important; +} + +.x-layer.x-grid .x-grid-item-over td, +.x-layer.x-grid .x-grid-item-selected td, +.x-layer.x-grid .x-grid-item-over .x-grid-cell, +.x-layer.x-grid .x-grid-item-selected .x-grid-cell, +.x-panel.x-layer.x-grid .x-grid-item-over td, +.x-panel.x-layer.x-grid .x-grid-item-selected td, +.x-panel.x-layer.x-grid .x-grid-item-over .x-grid-cell, +.x-panel.x-layer.x-grid .x-grid-item-selected .x-grid-cell { + border-radius: 0 !important; +} + +.x-layer.x-grid .x-grid-item-over td:first-child, +.x-layer.x-grid .x-grid-item-selected td:first-child, +.x-panel.x-layer.x-grid .x-grid-item-over td:first-child, +.x-panel.x-layer.x-grid .x-grid-item-selected td:first-child { + border-radius: var(--pm-radius-sm) 0 0 var(--pm-radius-sm) !important; +} + +.x-layer.x-grid .x-grid-item-over td:last-child, +.x-layer.x-grid .x-grid-item-selected td:last-child, +.x-panel.x-layer.x-grid .x-grid-item-over td:last-child, +.x-panel.x-layer.x-grid .x-grid-item-selected td:last-child { + border-radius: 0 var(--pm-radius-sm) var(--pm-radius-sm) 0 !important; +} + +/* ===================================================== + MENUS + ===================================================== */ +.x-menu, +.x-menu-default { + background-color: var(--drac-crust) !important; + border: 1px solid var(--drac-surface0) !important; + border-radius: var(--pm-radius-lg) !important; + box-shadow: 0 8px 24px rgba(30, 31, 41, 0.8) !important; + padding: 2px !important; + overflow: hidden !important; +} + +.x-menu-body-default { + background-color: transparent !important; + padding: 4px !important; +} + +.x-menu-header { + background-color: transparent !important; + color: var(--drac-text) !important; +} + +/* Menu icon separator — hide */ +.x-menu-icon-separator-default { + display: none !important; +} + +/* Menu item layout (flexbox reordering) */ +.x-menu-item-default > .x-menu-item-link { + display: flex !important; + align-items: center !important; + flex-direction: row !important; + gap: 4px !important; + justify-content: flex-start !important; + flex-wrap: nowrap !important; + border-radius: var(--pm-radius-md) !important; + padding: 4px 8px !important; + line-height: 20px !important; + cursor: pointer !important; + outline: none !important; + box-shadow: none !important; + white-space: nowrap !important; + text-decoration: none !important; +} + +.x-menu-item-text-default { + color: var(--drac-text) !important; + font-size: 13px !important; + order: 1 !important; + margin-left: 0 !important; + text-align: left !important; + line-height: 20px !important; + display: inline-flex !important; + align-items: center !important; + flex: 1 1 auto !important; + width: auto !important; + white-space: nowrap !important; +} + +.x-menu-item-icon-default { + color: var(--drac-subtext0) !important; + order: -1 !important; + position: relative !important; + float: none !important; + margin-right: 8px !important; + margin-left: 0 !important; + left: auto !important; + top: auto !important; + width: 16px !important; + text-align: center !important; + display: inline-flex !important; + align-items: center !important; + justify-content: center !important; + height: 20px !important; + line-height: 20px !important; + vertical-align: middle !important; + flex: 0 0 16px !important; + align-self: center !important; +} + +.x-menu-item-arrow, +.x-menu-item-arrow-default { + order: 2 !important; + margin-left: auto !important; +} + +.x-menu-item-default.x-menu-item-separator { + background-color: var(--drac-surface0) !important; + border: none !important; + height: 1px !important; + margin: 6px 4px !important; +} + +.x-menu-item-default.x-menu-item-focus, +.x-menu-item-default.x-menu-item-active, +.x-menu-item:hover { + background-color: var(--drac-surface0) !important; + color: var(--drac-text) !important; + border-radius: var(--pm-radius-md) !important; +} + +.x-menu-item-active .x-menu-item-text-default, +.x-menu-item-focus .x-menu-item-text-default { + color: var(--drac-text) !important; +} + +.x-menu-item-active .x-menu-item-icon-default, +.x-menu-item-focus .x-menu-item-icon-default { + color: var(--drac-cyan) !important; +} + +/* ===================================================== + PROGRESS BARS + ===================================================== */ + +/* Fix: Widget containers need overflow visible to not clip progress bars */ +.x-container[id^="pmxInfoWidget"], +.x-container.x-box-layout-ct { + overflow: visible !important; +} + +.x-progress, +.x-progress-default { + background-color: var(--drac-surface0) !important; + border-radius: 5px !important; +} + +.x-progress-default .x-progress-bar-default { + background-color: var(--drac-purple) !important; + border-radius: 5px !important; + transition: width 0.4s ease !important; +} + +.x-progress-default .x-progress-text { + color: var(--drac-text) !important; +} + +/* Text overlaid on the progress bar fill — use on-accent for contrast */ +.x-progress-bar .x-progress-text { + color: var(--drac-on-accent) !important; +} + +.x-progress.warning .x-progress-bar { + background-color: var(--drac-yellow) !important; +} + +.x-progress.critical .x-progress-bar { + background-color: var(--drac-red) !important; +} + +/* ===================================================== + TABS — Dracula underline style + Flat tabs with Purple underline on active tab + ===================================================== */ +.x-tab-bar, +.x-tab-bar-default { + background-color: var(--drac-base) !important; + border-radius: 0 !important; + border-bottom: 1px solid var(--drac-surface1) !important; + padding-bottom: 0 !important; +} + +/* Overflow visible for the underline indicator */ +.x-tab-bar .x-box-inner, +.x-tab-bar .x-box-target, +.x-tab-bar-body, +.x-tab-bar-body-default { + overflow: visible !important; +} + +/* Base tab */ +.x-tab, +.x-tab-default, +.x-tab-default-top { + background-color: transparent !important; + border: none !important; + border-radius: var(--pm-radius-md) var(--pm-radius-md) 0 0 !important; + padding: 8px 16px 8px !important; + overflow: visible !important; + margin-bottom: 0 !important; + transition: color 0.15s ease !important; + outline: none !important; + box-shadow: none !important; +} + +/* Remove ::after from inactive tabs */ +.x-tab::after { + display: none !important; +} + +.x-tab-inner-default { + color: var(--drac-subtext0) !important; + font-size: 13px !important; +} + +.x-tab-default.x-tab-over { + background-color: transparent !important; +} + +.x-tab-default.x-tab-over .x-tab-inner-default { + color: var(--drac-text) !important; +} + +/* Active tab */ +.x-tab-default.x-tab.x-tab-active { + background-color: transparent !important; + border: none !important; + overflow: visible !important; + margin-bottom: 0 !important; + outline: none !important; + box-shadow: none !important; +} + +/* Purple underline indicator on active tab */ +.x-tab-default.x-tab.x-tab-active::after { + content: '' !important; + display: block !important; + position: absolute !important; + bottom: 0 !important; + left: 0 !important; + right: 0 !important; + height: 2px !important; + background: var(--drac-purple) !important; + z-index: 10 !important; + border-radius: 2px 2px 0 0 !important; + pointer-events: none !important; +} + +.x-tab-active .x-tab-inner-default { + color: var(--drac-text) !important; + font-weight: 600 !important; +} + +.x-tab-default.x-tab.x-tab-disabled { + background-color: transparent !important; + border: none !important; + color: var(--drac-overlay0) !important; + margin-bottom: 0 !important; +} + +/* Focus states — no outline */ +.x-keyboard-mode .x-tab-default.x-tab-focus, +.x-keyboard-mode .x-tab-default.x-tab-focus.x-tab-active { + background-color: transparent !important; + border: none !important; + outline: none !important; + box-shadow: none !important; + margin-bottom: 0 !important; +} + +.x-keyboard-mode .x-tab-default.x-tab-focus.x-tab-active::after { + content: '' !important; + display: block !important; + position: absolute !important; + bottom: 0 !important; + left: 0 !important; + right: 0 !important; + height: 2px !important; + background: var(--drac-purple) !important; + z-index: 10 !important; + pointer-events: none !important; +} + +/* Kill ALL tab interaction outlines/shadows */ +.x-tab:focus, +.x-tab *:focus, +.x-tab-focus, +.x-tab-active.x-tab-focus, +.x-tab-inner-focus, +.x-tab-button-focus, +.x-tab-pressed, +.x-tab-active.x-tab-pressed, +.x-tab-over, +.x-tab:active, +.x-tab *:active { + outline: none !important; + box-shadow: none !important; +} + +.x-tabpanel-child { + border-radius: 0 0 var(--pm-radius-lg) var(--pm-radius-lg) !important; +} + +/* Tab hover/active corners */ +.x-tab-default.x-tab-over, +.x-tab-default.x-tab.x-tab-active { + border-radius: var(--pm-radius-md) var(--pm-radius-md) 0 0 !important; +} + +/* ===================================================== + TOOLTIPS + ===================================================== */ +.x-tip, +.x-tip-default { + background-color: var(--drac-mantle) !important; + border: 1px solid var(--drac-surface1) !important; + border-radius: var(--pm-radius-md) !important; + box-shadow: 0 4px 12px rgba(30, 31, 41, 0.5); +} + +.x-tip-body-default { + color: var(--drac-text) !important; +} + +.x-tip-form-invalid { + background-color: var(--drac-mantle) !important; + border-color: var(--drac-red) !important; +} + +.x-tip-body-form-invalid { + color: var(--drac-red) !important; +} + +/* ===================================================== + TREE NAVIGATION (Sidebar) + ===================================================== */ +.x-treelist-item { + background-color: var(--drac-base) !important; + border-radius: var(--pm-radius-md) !important; +} + +/* Pseudo-element approach for hover/selected highlighting */ +.x-treelist-row { + border-radius: var(--pm-radius-md) !important; + background-color: transparent !important; + position: relative !important; + z-index: 0 !important; +} + +.x-treelist-row::before { + content: ""; + position: absolute; + top: 1px; + bottom: 1px; + left: 0; + right: 4px; + border-radius: var(--pm-radius-md); + background-color: transparent; + z-index: -1; + pointer-events: none; + transition: background-color 0.15s ease; +} + +/* Fix toolbox tree item text overlapping icons */ +.x-treelist-item-text { + margin-left: 28px !important; +} + +/* Toolbox tree items — bright text */ +.x-treelist-item-text, +.x-treelist-item-icon, +.x-treelist.x-treelist-pve-nav .x-treelist-item-text, +.x-treelist.x-treelist-pve-nav .x-treelist-item-icon { + color: var(--drac-subtext1) !important; +} + +/* Hover state — apply to pseudo-element */ +.x-treelist-row-over { + background-color: transparent !important; +} + +.x-treelist-row-over::before { + background-color: var(--drac-hover-overlay) !important; +} + +.x-treelist-row-over .x-treelist-item-icon, +.x-treelist-row-over .x-treelist-item-text { + background-color: transparent !important; + color: var(--drac-text) !important; +} + +/* Selected/active item — Purple highlight */ +.x-treelist-item-selected > .x-treelist-row { + background-color: transparent !important; +} + +.x-treelist-item-selected > .x-treelist-row::before, +.x-treelist-item-selected > .x-treelist-row:hover::before { + background-color: var(--drac-purple) !important; +} + +.x-treelist-item-selected .x-treelist-item-text, +.x-treelist-item-selected .x-treelist-item-icon, +.x-treelist.x-treelist-pve-nav .x-treelist-item-selected .x-treelist-item-text, +.x-treelist.x-treelist-pve-nav .x-treelist-item-selected .x-treelist-item-icon { + color: var(--drac-on-accent) !important; +} + +.x-treelist-pve-nav { + background-color: var(--drac-base) !important; + border-color: var(--drac-surface1) !important; +} + +/* Tree navigation radius overrides */ +.x-treelist-item, +.x-treelist-item-tool { + border-radius: var(--pm-radius-sm) !important; +} + +.x-treelist-row, +.x-treelist-row:hover, +.x-treelist-row-over, +.x-treelist-item-selected > .x-treelist-row, +.x-treelist-item-selected > .x-treelist-row:hover, +.x-treelist-item-expanded > .x-treelist-row, +.x-treelist-item-expanded > .x-treelist-row-over, +.x-treelist-item-expandable > .x-treelist-row, +.x-treelist-item-expandable > .x-treelist-row-over { + border-radius: var(--pm-radius-sm) !important; +} + +.x-treelist-row::before { + border-radius: var(--pm-radius-sm) !important; +} + +.x-treelist-item-wrap, +.x-treelist-item-text, +.x-treelist-row, +.x-treelist-container, +.x-treelist-root-container, +.x-treelist, +.x-treelist-pve-nav { + border-radius: var(--pm-radius-sm) !important; +} + +/* Cursor pointer for interactive tree/grid items */ +.x-grid-cell, +.x-grid-cell-inner, +.x-tree-elbow-img, +.x-tree-icon, +.x-treelist-item, +.x-treelist-row, +.x-treelist-item-wrap, +.x-treelist-item-text, +.x-treelist-item-icon { + cursor: pointer !important; +} + +/* ===================================================== + WINDOWS / MODALS + ===================================================== */ +.x-window, +.x-window-default { + background-color: var(--drac-crust) !important; + border: 1px solid var(--drac-surface1) !important; + border-radius: var(--pm-radius-lg) !important; + box-shadow: 0 8px 24px rgba(30, 31, 41, 0.6) !important; + overflow: hidden !important; +} + +.x-window .x-window-header, +.x-window-header-default { + background-color: var(--drac-mantle) !important; + border-color: transparent !important; + border-radius: var(--pm-radius-lg) var(--pm-radius-lg) 0 0 !important; +} + +.x-window-header-default .x-mask { + background-color: rgba(30, 31, 41, 0.7); +} + +.x-window .x-window-body, +.x-window-body-default { + background-color: var(--drac-base) !important; + border-color: var(--drac-surface1) !important; + color: var(--drac-text) !important; + border-radius: 0 0 var(--pm-radius-lg) var(--pm-radius-lg) !important; +} + +.x-window-ghost { + background-color: var(--drac-base) !important; +} + +.x-window-header-default .x-tool-img { + background-color: transparent; +} + +.x-message-box .x-window-body { + background-color: var(--drac-mantle) !important; +} + +/* Respect ExtJS inline display:none on hidden dialog buttons */ +.x-message-box .x-btn.x-btn-default-small[style*="display: none"], +.x-message-box .x-btn.x-btn-default-small[style*="display:none"], +.x-window .x-toolbar-footer .x-btn[style*="display: none"], +.x-window .x-toolbar-footer .x-btn[style*="display:none"] { + display: none !important; +} + +/* Login dialog — clean inner panel borders */ +.x-window:has(#pveloginrealm) .x-panel-body { + border: none !important; + background: transparent !important; + width: auto !important; +} + +/* ===================================================== + CONSOLE / TERMINAL + ===================================================== */ +div.monitor { + border-color: var(--drac-surface1); +} + +.install-mask { + background-color: var(--drac-crust); + color: var(--drac-subtext0); +} + +.x-window.install-mask { + box-shadow: rgba(30, 31, 41, 0.5) 0 4px 20px !important; +} + +/* ===================================================== + LEGEND / CHARTS + ===================================================== */ +.x-legend-container { + background-color: var(--drac-base) !important; +} + +.x-legend-horizontal .x-legend-item { + background-color: var(--drac-mantle) !important; + color: var(--drac-text) !important; + border: 1px solid var(--drac-surface0) !important; +} + +/* Chart/RRD panel backgrounds */ +div[id*="rrdchart"], +.pve-rrddatastore, +.pmx-panel-rrd { + background-color: var(--drac-base) !important; +} + +.proxmox-rrd-panel canvas, +.proxmox-widget-toolkit canvas, +canvas.x-surface, +.x-surface canvas { + background-color: transparent !important; + opacity: 1 !important; +} + +.proxmox-rrd-panel, +.proxmox-rrd-chart { + background-color: var(--drac-base) !important; +} + +/* Chart text/labels */ +.x-surface text, +svg text { + fill: var(--drac-text) !important; +} + +/* ===================================================== + PROXMOX-SPECIFIC OVERRIDES + ===================================================== */ + +/* Logo inversion */ +img[id^="proxmoxlogo-"][id$="-img"], +img[id^="proxmoxLogoSvg-"][id$="-img"] { + filter: invert(1) hue-rotate(180deg); +} + +/* Invalid/warning/disabled rows */ +.proxmox-invalid-row { + background-color: rgba(255, 85, 85, 0.15) !important; +} + +.proxmox-warning-row { + background-color: rgba(255, 184, 108, 0.15) !important; +} + +.proxmox-disabled-row td { + color: var(--drac-overlay0) !important; +} + +/* Hints */ +.pmx-hint { + background-color: rgba(255, 184, 108, 0.15) !important; + white-space: nowrap !important; +} + +.pmx-hint a { + color: var(--drac-cyan) !important; +} + +/* Status text colors — Information → Cyan */ +.info-blue { + color: var(--drac-cyan) !important; +} + +.critical { + color: var(--drac-red) !important; +} + +/* Links */ +a { + color: var(--drac-cyan) !important; +} + +/* Markdown content */ +.pmx-md code { + background-color: var(--drac-mantle) !important; + color: var(--drac-pink) !important; + border-radius: var(--pm-radius-sm) !important; +} + +.pmx-md pre code { + border-color: var(--drac-surface1) !important; + background-color: var(--drac-crust) !important; +} + +.pmx-md a { + color: var(--drac-cyan) !important; +} + +.pmx-md table { + border-color: var(--drac-surface1) !important; +} + +.pmx-md th { + background-color: var(--drac-mantle) !important; + border-color: var(--drac-surface1) !important; +} + +.pmx-md td { + border-color: var(--drac-surface1) !important; +} + +/* APT repos */ +.proxmox-apt-repos .x-grid-group-hd { + background-color: var(--drac-base) !important; + border: none !important; +} + +.proxmox-apt-repos .x-grid-group-title { + color: var(--drac-text) !important; +} + +/* Tags */ +.pve-edit-tag { + border-radius: var(--pm-radius-md) !important; +} + +.pve-edit-tag.editable span { + background-color: var(--drac-mantle) !important; + color: var(--drac-text) !important; + border-color: var(--drac-surface1) !important; +} + +.x-tree-node-text .proxmox-tag-dark, +.x-tree-node-text .proxmox-tag-light, +.x-grid-cell-inner .proxmox-tag-dark, +.x-grid-cell-inner .proxmox-tag-light, +span.proxmox-tag-dark, +span.proxmox-tag-light { + border-radius: var(--pm-radius-md) !important; +} + +/* Checkmark button in tag edit — match toolbar button size */ +.x-btn.x-btn-default-small:has(.fa-check) { + min-height: 24px !important; + height: 24px !important; + padding: 3px 8px !important; + border-radius: var(--pm-radius-sm) !important; + background-color: var(--drac-purple) !important; + border: none !important; +} + +.x-btn.x-btn-default-small:has(.fa-check).x-btn-disabled { + background-color: transparent !important; + border: 1px solid var(--drac-surface1) !important; + opacity: 0.5 !important; +} + +.x-btn.x-btn-default-small:has(.fa-check) .fa-check { + color: var(--drac-on-accent) !important; +} + +.x-btn.x-btn-default-small:has(.fa-check).x-btn-disabled .fa-check { + color: var(--drac-overlay1) !important; +} + +.x-btn.x-btn-default-small:has(.fa-check):not(.x-btn-disabled):hover { + background-color: #caa9fa !important; +} + +.x-btn.x-btn-default-small:has(.fa-check) .x-btn-inner { + display: none !important; +} + +/* Date picker */ +.x-datepicker, +.x-datepicker-column-header, +.x-monthpicker { + background-color: var(--drac-base) !important; + color: var(--drac-text) !important; + border-color: transparent !important; +} + +.x-datepicker-header, +.x-datepicker-footer, +.x-monthpicker-buttons { + background-color: var(--drac-mantle) !important; +} + +.x-datepicker-date, +.x-monthpicker-item-inner { + color: var(--drac-text) !important; +} + +.x-datepicker-selected div.x-datepicker-date, +.x-monthpicker-item a.x-monthpicker-selected, +a.x-monthpicker-item-inner:hover, +div.x-datepicker-date:hover { + background-color: var(--drac-hover-overlay) !important; + color: var(--drac-text) !important; +} + +.x-datepicker-today .x-datepicker-date { + border-color: var(--drac-purple) !important; +} + +.x-datepicker-disabled .x-datepicker-date { + color: var(--drac-overlay0) !important; +} + +.x-datepicker-prev-day .x-datepicker-date, +.x-datepicker-next-day .x-datepicker-date { + color: var(--drac-overlay0) !important; +} + +/* Usage bars */ +.usage-wrapper, +.usage { + border-radius: 2px !important; +} + +.usage { + background-color: var(--drac-overlay2) !important; +} + +/* ===================================================== + SCROLLBARS + ===================================================== */ +::-webkit-scrollbar { + width: 8px; + height: 8px; +} + +::-webkit-scrollbar-track { + background: var(--drac-base); + border-radius: var(--pm-radius-sm); +} + +::-webkit-scrollbar-thumb { + background: var(--drac-surface2); + border-radius: var(--pm-radius-sm); + border: 1px solid transparent; + background-clip: padding-box; + transition: background 0.15s ease; +} + +::-webkit-scrollbar-thumb:hover { + background: var(--drac-overlay0); +} + +::-webkit-scrollbar-corner { + background: var(--drac-base); +} + +/* Firefox scrollbar */ +* { + scrollbar-width: thin; + scrollbar-color: var(--drac-surface2) var(--drac-base); +} + +/* ===================================================== + SELECTION HIGHLIGHT + ===================================================== */ +::selection { + background-color: rgba(98, 114, 164, 0.3); + color: var(--drac-text); +} + +/* ===================================================== + TRANSITIONS (smooth interactions) + ===================================================== */ + +/* Grid row transitions */ +.x-grid-item { + transition: background-color 0.15s ease !important; +} + +/* Tree pseudo-element transitions */ +.x-treelist-row::before { + transition: background-color 0.15s ease !important; +} + +/* Menu item transitions */ +.x-menu-item-default > .x-menu-item-link { + transition: background-color 0.12s ease !important; +} + +/* Boundlist item transitions */ +.x-boundlist-item { + transition: background-color 0.12s ease !important; +} + +/* Tab transitions */ +.x-tab { + transition: color 0.15s ease !important; +} + +/* Splitter transition */ +.x-splitter { + transition: background-color 0.15s ease !important; +} + +/* Tooltip transition */ +.x-tip { + transition: opacity 0.15s ease !important; +} + +/* Progress bar width transition */ +.x-progress-bar { + transition: width 0.4s ease !important; +} + +/* Scrollbar thumb transition */ +::-webkit-scrollbar-thumb { + transition: background 0.15s ease !important; +} + +/* Window close tool transition */ +.x-tool-img { + transition: filter 0.15s ease !important; +} + +/* ===================================================== + TOOL ICONS - FontAwesome Replacements + (Ported from UniFi v5.86) + Replace sprite-based ExtJS tool icons with crisp + FontAwesome icons for better consistency and clarity + ===================================================== */ + +/* Base styling for all tool icons - remove sprite backgrounds */ +.x-tool-tool-el.x-tool-minus, +.x-tool-img.x-tool-minus, +.x-tool-tool-el.x-tool-collapse-right, +.x-tool-img.x-tool-collapse-right, +.x-tool-tool-el.x-tool-collapse-left, +.x-tool-img.x-tool-collapse-left, +.x-tool-tool-el.x-tool-expand-right, +.x-tool-img.x-tool-expand-right, +.x-tool-tool-el.x-tool-expand-left, +.x-tool-img.x-tool-expand-left, +.x-tool-tool-el.x-tool-maximize, +.x-tool-img.x-tool-maximize, +.x-tool-tool-el.x-tool-restore, +.x-tool-img.x-tool-restore, +.x-tool-tool-el.x-tool-gear, +.x-tool-img.x-tool-gear, +.x-tool-tool-el.x-tool-refresh, +.x-tool-img.x-tool-refresh, +.x-tool-tool-el.x-tool-close, +.x-tool-img.x-tool-close { + background-image: none !important; + font-family: "FontAwesome" !important; + font-size: 14px !important; + line-height: 16px !important; + text-align: center !important; + color: var(--pm-text-dim) !important; + transition: color 0.15s ease !important; + filter: none !important; + width: 16px !important; + height: 16px !important; + display: flex !important; + align-items: center !important; + justify-content: center !important; +} + +/* Close button - slightly larger */ +.x-tool-tool-el.x-tool-close, +.x-tool-img.x-tool-close { + font-size: 20px !important; +} + +/* Individual glyph assignments */ +.x-tool-tool-el.x-tool-minus::before, +.x-tool-img.x-tool-minus::before { + content: "\f010" !important; /* fa-search-minus (zoom out) */ +} + +.x-tool-tool-el.x-tool-collapse-right::before, +.x-tool-img.x-tool-collapse-right::before { + content: "\f054" !important; /* fa-chevron-right */ +} + +.x-tool-tool-el.x-tool-expand-left::before, +.x-tool-img.x-tool-expand-left::before { + content: "\f053" !important; /* fa-chevron-left */ +} + +.x-tool-tool-el.x-tool-collapse-left::before, +.x-tool-img.x-tool-collapse-left::before { + content: "\f053" !important; /* fa-chevron-left */ +} + +.x-tool-tool-el.x-tool-expand-right::before, +.x-tool-img.x-tool-expand-right::before { + content: "\f054" !important; /* fa-chevron-right */ +} + +.x-tool-tool-el.x-tool-maximize::before, +.x-tool-img.x-tool-maximize::before { + content: "\f065" !important; /* fa-expand */ +} + +.x-tool-tool-el.x-tool-restore::before, +.x-tool-img.x-tool-restore::before { + content: "\f066" !important; /* fa-compress */ +} + +.x-tool-tool-el.x-tool-gear::before, +.x-tool-img.x-tool-gear::before { + content: "\f013" !important; /* fa-cog */ +} + +.x-tool-tool-el.x-tool-refresh::before, +.x-tool-img.x-tool-refresh::before { + content: "\f021" !important; /* fa-refresh */ +} + +.x-tool-tool-el.x-tool-close::before, +.x-tool-img.x-tool-close::before { + content: "\f00d" !important; /* fa-times */ +} + +/* Hover state - all tool icons */ +.x-tool:hover .x-tool-tool-el.x-tool-minus, +.x-tool:hover .x-tool-img.x-tool-minus, +.x-tool:hover .x-tool-tool-el.x-tool-collapse-right, +.x-tool:hover .x-tool-img.x-tool-collapse-right, +.x-tool:hover .x-tool-tool-el.x-tool-collapse-left, +.x-tool:hover .x-tool-img.x-tool-collapse-left, +.x-tool:hover .x-tool-tool-el.x-tool-expand-right, +.x-tool:hover .x-tool-img.x-tool-expand-right, +.x-tool:hover .x-tool-tool-el.x-tool-expand-left, +.x-tool:hover .x-tool-img.x-tool-expand-left, +.x-tool:hover .x-tool-tool-el.x-tool-maximize, +.x-tool:hover .x-tool-img.x-tool-maximize, +.x-tool:hover .x-tool-tool-el.x-tool-restore, +.x-tool:hover .x-tool-img.x-tool-restore, +.x-tool:hover .x-tool-tool-el.x-tool-gear, +.x-tool:hover .x-tool-img.x-tool-gear, +.x-tool:hover .x-tool-tool-el.x-tool-refresh, +.x-tool:hover .x-tool-img.x-tool-refresh, +.x-tool:hover .x-tool-tool-el.x-tool-close, +.x-tool:hover .x-tool-img.x-tool-close { + color: var(--pm-text) !important; +} + +/* Disabled state */ +.x-tool-disabled .x-tool-tool-el, +.x-tool-disabled .x-tool-img { + opacity: 0.4 !important; + cursor: default !important; +} + +/* Inline FontAwesome tools (PVE-injected) */ +.x-tool-tool-el[style*="font-family:FontAwesome"], +.x-tool-tool-el[style*="font-family: FontAwesome"] { + color: var(--pm-text-dim) !important; + font-size: 14px !important; + line-height: 16px !important; + display: flex !important; + align-items: center !important; + justify-content: center !important; + width: 16px !important; + height: 16px !important; + transition: color 0.15s ease !important; + background-image: none !important; + background-color: transparent !important; +} + +.x-tool:not(.x-tool-disabled) .x-tool-tool-el[style*="font-family:FontAwesome"], +.x-tool:not(.x-tool-disabled) .x-tool-tool-el[style*="font-family: FontAwesome"] { + cursor: pointer !important; +} + +.x-tool.x-tool-disabled .x-tool-tool-el[style*="font-family:FontAwesome"], +.x-tool.x-tool-disabled .x-tool-tool-el[style*="font-family: FontAwesome"] { + cursor: default !important; + opacity: 0.4 !important; +} + +.x-tool .x-mask { + background-color: transparent !important; + backdrop-filter: none !important; + pointer-events: none !important; +} + +.x-tool:not(.x-tool-disabled):hover .x-tool-tool-el[style*="font-family:FontAwesome"], +.x-tool:not(.x-tool-disabled):hover .x-tool-tool-el[style*="font-family: FontAwesome"] { + color: var(--pm-text) !important; +} diff --git a/themes/theme-github-dark.css b/themes/theme-github-dark.css new file mode 100644 index 0000000..1e091f7 --- /dev/null +++ b/themes/theme-github-dark.css @@ -0,0 +1,2494 @@ +/*!GitHub Dark*/ +/* + * ProxMorph Theme: GitHub Dark + * Authentic recreation of GitHub's Dark Mode using Primer Design System + * Version: 2.2.23 + * + * v2.2.23: Redesign tab indicator — position ::after at bottom:0 (inside tab box) + * instead of bottom:-2px (outside, clipped by ExtJS containers). Remove + * margin-bottom:-2px hack that caused layout shifts on click. Add overflow: + * visible on .x-box-inner/.x-box-target within .x-tab-bar to prevent clipping. + * pointer-events:none on indicator for clean click-through. + * v2.2.22: Fix ExtJS tab click outline effect — aggressively remove outline and box-shadow + * from all tab focus and pressed states (.x-tab-focus, .x-tab-pressed, etc.). + * v2.2.21: Fix GitHub tab underline — switch from border-bottom to ::after pseudo-element + * (ExtJS overrides border-bottom: none, but cannot override ::after). Add + * overflow:visible on .x-tab-bar-body (ExtJS default clips the indicator). + * Fix white focus outline on tab click (outline:none on .x-tab and focus states). + * v2.2.20: GitHub underline-nav tab style — flat tabs, muted inactive text (#848d97), + * bold white active text (#e6edf3), coral underline indicator (#f47067, 2px) + * via border-bottom + margin-bottom: -2px overlap trick. Tab bar gets + * 1px bottom border (#21262d) matching GitHub's separator. Overflow: visible + * on tabs for the border to render past the bar edge. + * v2.2.19: Polish checkbox/radio appearance — brighter unchecked state (bg #161b22, + * border #6e7681 at 1.5px) to match GitHub's actual Primer control look; + * enlarge to 16×16 for crisp circle rendering; translateZ(0) on radios + * for GPU-accelerated anti-aliasing; inner dot 7px to match new size. + * v2.2.18: GitHub Primer checkboxes & radios — replace sprite-inversion approach with + * native CSS custom controls. Checkbox: 14×14 rounded square, blue fill + SVG + * checkmark when checked. Radio: 14×14 circle, blue inner dot via ::after when + * selected. Hover highlights border in #388bfd. Includes github-dark-init.js patch + * to detect ExtJS initial-state (bgPos:-15px) and add .x-form-cb-checked class. + * v2.2.17: Fix System tab dropdown fields clipped on right side in Create VM dialog + * Root cause: padding: 12px 16px on .x-autocontainer-innerCt shifts form items rightward + * by 16px, but ExtJS uses offsetWidth (not clientWidth) so form items are sized to full + * column width AND shifted — overflowing 16px past column boundary. Right column panel body + * (bg: #0d1117) starts at exact column edge, painting over the overflow trigger buttons. + * Solution: Remove horizontal innerCt padding; add overflow:visible on .x-window .x-panel-body; + * add 0 4px on column panel bodies for breathing room (ExtJS reads getPaddingInfo here). + * v2.2.16: Fix nav tree right border cut-off where Edit/Revert toolbar overlaps + * Root cause: content toolbar (z-index:2) renders on top of nav's right border (same z-index) + * Solution: raise .pve-toolbar-bg to z-index:3 so border paints above overlapping content + * v2.2.15: Fix nav tree right border not extending full panel height + * Root cause: border was on .x-treelist (only item-height tall) not the full sidebar toolbar + * Solution: Move border to .pve-toolbar-bg which spans the full docked toolbar height + * v2.2.14: Force dropdown icons left (order override) + * v2.2.13: Fix dropdown icon/text line breaks + * v2.2.12: Fix dropdown icon/text line wrapping + * v2.2.11: Fine-tune dropdown icon vertical alignment + * v2.2.10: Force dropdown icons left alignment + * v2.2.9: Fix dropdown icons left + remove dotted item borders + * v2.2.8: GitHub-profile dropdown styling for menus/boundlists + * v2.2.7: Port full UniFi border-radius rules to element styles + * v2.2.6: Apply UniFi border radius values (4px/6px/8px) for visual consistency + * v2.2.5: Remove hover effect on already-selected treelist items + * v2.2.4: Toolbox tree item hover/selected highlighting using pseudo-element + * for balanced left/right spacing regardless of row padding + * v2.2.1: Remove blue outline from selected/focused items in resource tree + * Add borders to Guest Status panel and Notes panel + * v2.2.0: Dialog form content padding - prevent content flushing against edges + * v2.1.5: Ported layout container reset rules from UniFi theme (prevent ExtJS clipping) + * v2.1.4: Fixed toolbox tree item text overlapping icons (margin-left: 28px) + * v2.1.3: Toolbox tree active item uses GitHub green instead of blue + * v2.1.2: Vertical usage bars (storage progress) use Proxmox default color #e6e6e6 + * v2.1.1: Resource tree icons use Proxmox default colors (green=running, red=error, etc.) + * + * GitHub Primer Dark Mode Color Palette: + * + * CANVAS (Backgrounds): + * - canvas-default: #0d1117 - Main page background + * - canvas-muted: #151b23 - Muted/card backgrounds + * - canvas-inset: #010409 - Header, inset areas + * - canvas-subtle: #161b22 - Subtle backgrounds + * + * FOREGROUND (Text): + * - fg-default: #f0f6fc - Primary text + * - fg-muted: #9198a1 - Secondary/muted text + * - fg-subtle: #6e7681 - Tertiary text + * - fg-onEmphasis: #ffffff - Text on colored backgrounds + * + * BORDERS: + * - border-default: #3d444d - Default borders + * - border-muted: rgba(61, 68, 77, 0.7) - Muted borders + * - border-subtle: rgba(240, 246, 252, 0.1) - Subtle borders + * + * ACCENT (Blue): + * - accent-fg: #4493f8 - Links, accent text + * - accent-emphasis: #1f6feb - Active states + * + * SUCCESS (Green): + * - success-fg: #3fb950 - Success text + * - success-emphasis: #238636 - Primary buttons + * + * BORDER RADII (UniFi-aligned): + * - radius-sm: 4px - Form inputs, checkboxes + * - radius-md: 6px - Buttons + * - radius-lg: 8px - Windows, panels, cards + */ + +/* ===================================================== + CSS VARIABLES + ===================================================== */ +:root { + /* GitHub Primer Dark Mode Tokens */ + --gh-canvas-default: #0d1117; + --gh-canvas-muted: #151b23; + --gh-canvas-inset: #010409; + --gh-canvas-subtle: #161b22; + + --gh-fg-default: #f0f6fc; + --gh-fg-muted: #9198a1; + --gh-fg-subtle: #6e7681; + --gh-fg-on-emphasis: #ffffff; + + --gh-border-default: #3d444d; + --gh-border-muted: rgba(61, 68, 77, 0.7); + --gh-border-subtle: rgba(240, 246, 252, 0.1); + + --gh-accent-fg: #4493f8; + --gh-accent-emphasis: #1f6feb; + --gh-accent-muted: rgba(56, 139, 253, 0.4); + --gh-accent-subtle: rgba(56, 139, 253, 0.15); + + --gh-success-fg: #3fb950; + --gh-success-emphasis: #238636; + --gh-success-hover: #29903b; + --gh-success-active: #2ea043; + + --gh-danger-fg: #f85149; + --gh-danger-emphasis: #da3633; + + --gh-attention-fg: #d29922; + --gh-attention-emphasis: #9e6a03; + + /* Select menu active (Primer dark) */ + --gh-selectmenu-active: #0c2d6b; + + /* Border Radii - UniFi aligned */ + --gh-radius-sm: 4px; + --gh-radius-md: 6px; + --gh-radius-lg: 8px; + + /* Hover overlay */ + --gh-hover-overlay: rgba(101, 108, 118, 0.2); + + /* Map to Proxmox widget toolkit vars */ + --pwt-panel-background: var(--gh-canvas-default); + --pwt-text-color: var(--gh-fg-default); + --pwt-gauge-default: var(--gh-accent-emphasis); + --pwt-gauge-back: #21262d; + --pwt-gauge-warn: var(--gh-attention-fg); + --pwt-gauge-crit: var(--gh-danger-emphasis); + --pwt-chart-primary: var(--gh-accent-emphasis); + --pwt-chart-grid-stroke: var(--gh-border-default); + + color-scheme: dark; +} + +/* ===================================================== + BASE / BODY + ===================================================== */ +.x-body, +.x-viewport>.x-body, +body.x-border-layout-ct, +div.x-border-layout-ct { + background-color: var(--gh-canvas-default) !important; + color: var(--gh-fg-default) !important; +} + +/* ===================================================== + LAYOUT CONTAINER RESET (Prevent ExtJS clipping) + v2.1.5: Ported from UniFi theme for consistent border handling + ===================================================== */ + +/* Tool icons - no rounded corners */ +.x-tool, +.x-tool-tool-el, +.x-tool-default, +.x-tool-img { + border-radius: 0 !important; +} + +/* Form elements - exclude from global radius, apply 6px (GitHub style) */ +.x-form-item, +.x-form-item-default, +.x-form-item-body, +.x-form-item-body-default, +.x-form-text-field-body, +.x-form-text-field-body-default, +.x-form-fieldcontainer, +.x-field, +.x-field-default, +.x-form-type-text { + border-radius: 0 !important; +} + +/* Reset layout containers that clip elements with overflow:hidden + radius */ +.x-box-layout-ct, +.x-panel-bodyWrap, +.x-panel-bodyWrap-default, +.x-autocontainer-innerCt, +.x-autocontainer-outerCt, +.x-panel.x-tabpanel-child, +.x-panel.x-box-item, +.x-box-inner, +.x-box-target, +.x-container, +.x-container-default, +.x-window .x-panel-body, +.x-window .x-window-body, +.x-window .x-window-bodyWrap { + border-radius: 0 !important; +} + +/* Reset everything inside windows to 0 - then re-apply specific radii */ +.x-window *, +.x-window .x-autocontainer-innerCt, +.x-window .x-autocontainer-outerCt, +.x-window .x-form-layout-wrap, +.x-window .x-form-layout-auto-label, +.x-window .x-form-layout-colgroup, +.x-window .x-form-layout-column, +.x-window .x-field, +.x-window .x-form-item, +.x-window .x-form-item-body { + border-radius: 0 !important; +} + +/* v2.2.0: Dialog form content padding - vertical only (horizontal causes ExtJS layout overflow). + Root cause: ExtJS uses offsetWidth for layout → CSS horizontal padding shifts form items + rightward but doesn't narrow their computed width, causing trigger wraps to overflow 16px past + the column boundary where the adjacent column's opaque background covers them. */ +.x-window .x-tabpanel-child .x-autocontainer-innerCt { + padding: 12px 0 !important; +} + +/* v2.2.17: Allow column panel bodies to show overflowed form content (e.g. trigger wraps). + overflow:visible prevents the panel's own clipping from hiding elements that extend + slightly past the panel boundary during ExtJS layout calculation. */ +.x-window .x-panel-body:not(.x-scroller) { + overflow: visible !important; +} + +/* v2.2.17: 4px side padding on column panel bodies for visual breathing room. + ExtJS reads getPaddingInfo() on panel-body when sizing child form items, so this + correctly reduces item widths by 8px total without causing any overflow. */ +.x-window .x-panel.x-box-item .x-panel-body { + padding: 0 4px !important; +} + +/* Re-apply button styling inside windows (6px) */ +.x-window .x-btn { + border-radius: var(--gh-radius-md) !important; +} + +/* Re-apply checkbox styling inside windows */ +.x-window .x-form-checkbox { + border-radius: var(--gh-radius-sm) !important; +} + +/* Re-apply form inputs inside windows (4px with split corners - UniFi style) */ +.x-window .x-form-trigger-wrap, +.x-window .x-form-trigger-wrap-default { + border-radius: var(--gh-radius-sm) !important; +} + +.x-window .x-form-text-wrap, +.x-window .x-form-text { + border-radius: var(--gh-radius-sm) 0 0 var(--gh-radius-sm) !important; +} + +.x-window .x-form-arrow-trigger { + border-radius: 0 var(--gh-radius-sm) var(--gh-radius-sm) 0 !important; +} + +/* Form trigger/text wrap - reset and re-apply */ +.x-form-trigger-wrap, +.x-form-trigger-wrap *, +.x-form-text-wrap, +.x-form-text-wrap *, +.x-form-text, +.x-form-trigger { + border-radius: 0 !important; +} + +.x-form-trigger-wrap, +.x-form-trigger-wrap-default { + border-radius: var(--gh-radius-sm) !important; + overflow: hidden !important; +} + +.x-form-text-wrap, +.x-form-text-wrap-default { + border-radius: var(--gh-radius-sm) 0 0 var(--gh-radius-sm) !important; +} + +.x-form-text, +.x-form-text-default { + border-radius: var(--gh-radius-sm) 0 0 var(--gh-radius-sm) !important; +} + +.x-form-trigger, +.x-form-trigger-default, +.x-form-arrow-trigger, +.x-form-arrow-trigger-default { + border-radius: 0 var(--gh-radius-sm) var(--gh-radius-sm) 0 !important; +} + +/* Legend items - no rounded corners */ +.x-legend-container, +.x-legend-horizontal .x-legend-item, +.x-legend-item { + border-radius: 0 !important; +} + +/* Legend color marker (dot) - keep circular */ +.x-legend-item-marker { + border-radius: 50% !important; +} + +/* Boundlist - prevent clipping (applied to parent) */ +.x-boundlist { + border-radius: var(--gh-radius-lg) !important; + overflow: hidden !important; +} + +/* Chart canvas - no rounded corners on data area */ +.x-chart-grid, +.x-chart-axis, +canvas.x-surface, +.x-chart canvas { + border-radius: 0 !important; +} + +/* Constrain autocontainer width inside windows */ +.x-window .x-autocontainer-outerCt { + max-width: 100% !important; +} + +/* Fix window header/body width consistency */ +.x-window > .x-window-header, +.x-window > .x-window-body, +.x-window > .x-window-bodyWrap, +.x-window-bodyWrap > .x-window-body { + width: 100% !important; +} + +.x-window-header > .x-box-inner, +.x-window-header > .x-box-inner > .x-box-target { + width: 100% !important; +} + +.x-window-header-title { + width: auto !important; + flex: 1 !important; + max-width: calc(100% - 30px) !important; +} + +/* ===================================================== + MASKS & OVERLAYS + ===================================================== */ +.x-mask { + background-color: rgba(1, 4, 9, 0.5) !important; +} + +.x-tool .x-mask { + backdrop-filter: blur(4px); + background-color: var(--gh-canvas-muted); + opacity: 0.6; +} + +.x-css-shadow { + box-shadow: 0 8px 24px rgba(1, 4, 9, 0.5) !important; +} + +/* ===================================================== + ICONS - Using Proxmox default colors for dark mode + v2.1.1: Restored PVE base color scheme + ===================================================== */ + +/* General icon colors - visible gray for dark backgrounds */ +.x-tree-icon-custom, +.x-grid-icon-custom, +.fa-tags::before, +.fa-file-o::before, +.fa-building::before, +.x-action-col-icon::before, +.fa-shield::before, +.fa-file-text-o::before, +.fa-clock-o::before, +.x-tab-icon-el-default, +.pve-icon-verify-lettering::after, +.x-tree-icon-leaf:not(.x-tree-icon-custom)::before, +.x-tree-icon-parent:not(.x-tree-icon-custom)::before, +.x-tree-icon-parent-expanded:not(.x-tree-icon-custom)::before, +.x-grid-filters-filtered-column .x-column-header-text::after { + color: #aaaaaa !important; +} + +/* Folder icons - invert for dark mode */ +.x-tree-icon-parent:not(.x-tree-icon-custom)::before, +.x-tree-icon-parent-expanded:not(.x-tree-icon-custom)::before { + filter: invert(90%); +} + +/* Various image-based icons - invert for visibility */ +.fa-ceph::before, +.fa-sdn::before, +.fa-network-wired::before, +.pve-itype-treelist-item-icon-cdrom, +.fa-chevron-right::before, +.x-grid-row-console, +.x-box-scroller-toolbar-default.x-box-scroller, +.x-tree-elbow-img, +.pve-itype-icon-qemu, +.x-tree-node-computer, +.x-grid-tree-node-expanded .x-tree-node-computer, +.pbs-icon-tape, +.pbs-icon-tape-drive, +.x-tree-icon-leaf:not(.x-tree-icon-custom), +.x-tree-icon-parent:not(.x-tree-icon-custom), +.x-tree-icon-parent-expanded:not(.x-tree-icon-custom) { + filter: invert(90%); +} + +/* Hardware icons */ +.pve-itype-icon-cpu, +.pve-itype-icon-cdrom, +.pve-itype-icon-memory, +.pve-itype-icon-pci, +.pve-itype-icon-serial, +.pve-itype-icon-die, +.pmx-itype-icon-processor, +.pmx-itype-icon-memory, +.pve-itype-icon-storage, +.x-tree-node-harddisk, +.x-grid-tree-node-expanded .x-tree-node-harddisk { + filter: invert(100%); +} + +/* Hardware icons — counter-invert for non-SVG icon cells */ +td.pve-itype-icon-storage .x-grid-cell-inner, +td.x-tree-node-harddisk .x-grid-cell-inner { + filter: invert(100%) !important; +} + +/* Hardware icons — hide inverted borders for non-SVG icon cells */ +td.pve-itype-icon-storage, +td.x-tree-node-harddisk { + border-color: transparent !important; +} + +/* Hardware grid icons — mask-image renders SVG icons in theme text color + Replaces filter:invert approach for pve-itype-icon-* and pmx-itype-icon-* grid cells */ +td.pve-itype-icon-cpu, +td.pve-itype-icon-cdrom, +td.pve-itype-icon-memory, +td.pve-itype-icon-pci, +td.pve-itype-icon-serial, +td.pve-itype-icon-die, +td.pmx-itype-icon-processor, +td.pmx-itype-icon-memory { + filter: none !important; + background-image: none !important; + padding-left: 0 !important; + border-color: transparent !important; +} + +td.pve-itype-icon-cpu .x-grid-cell-inner, +td.pve-itype-icon-cdrom .x-grid-cell-inner, +td.pve-itype-icon-memory .x-grid-cell-inner, +td.pve-itype-icon-pci .x-grid-cell-inner, +td.pve-itype-icon-serial .x-grid-cell-inner, +td.pve-itype-icon-die .x-grid-cell-inner, +td.pmx-itype-icon-processor .x-grid-cell-inner, +td.pmx-itype-icon-memory .x-grid-cell-inner { + padding-left: 3px !important; +} + +td.pve-itype-icon-cpu .x-grid-cell-inner::before, +td.pve-itype-icon-cdrom .x-grid-cell-inner::before, +td.pve-itype-icon-memory .x-grid-cell-inner::before, +td.pve-itype-icon-pci .x-grid-cell-inner::before, +td.pve-itype-icon-serial .x-grid-cell-inner::before, +td.pve-itype-icon-die .x-grid-cell-inner::before, +td.pmx-itype-icon-processor .x-grid-cell-inner::before, +td.pmx-itype-icon-memory .x-grid-cell-inner::before { + content: '' !important; + display: inline-block !important; + width: 18px !important; + height: 14px !important; + vertical-align: middle !important; + margin-right: 10px !important; + background-color: currentColor !important; + -webkit-mask-size: contain !important; + mask-size: contain !important; + -webkit-mask-repeat: no-repeat !important; + mask-repeat: no-repeat !important; + -webkit-mask-position: center !important; + mask-position: center !important; +} + +td.pve-itype-icon-cpu .x-grid-cell-inner::before { + -webkit-mask-image: url('/pve2/images/icon-cpu.svg') !important; + mask-image: url('/pve2/images/icon-cpu.svg') !important; +} + +td.pve-itype-icon-memory .x-grid-cell-inner::before { + -webkit-mask-image: url('/pve2/images/icon-memory.svg') !important; + mask-image: url('/pve2/images/icon-memory.svg') !important; +} + +td.pve-itype-icon-cdrom .x-grid-cell-inner::before { + -webkit-mask-image: url('/pve2/images/icon-cd-drive.svg') !important; + mask-image: url('/pve2/images/icon-cd-drive.svg') !important; +} + +td.pve-itype-icon-pci .x-grid-cell-inner::before { + -webkit-mask-image: url('/pve2/images/icon-pci.svg') !important; + mask-image: url('/pve2/images/icon-pci.svg') !important; +} + +td.pve-itype-icon-serial .x-grid-cell-inner::before { + -webkit-mask-image: url('/pve2/images/icon-serial.svg') !important; + mask-image: url('/pve2/images/icon-serial.svg') !important; +} + +td.pve-itype-icon-die .x-grid-cell-inner::before { + -webkit-mask-image: url('/pve2/images/icon-die.svg') !important; + mask-image: url('/pve2/images/icon-die.svg') !important; +} + +td.pmx-itype-icon-processor .x-grid-cell-inner::before { + -webkit-mask-image: url('../images/icon-cpu.svg') !important; + mask-image: url('../images/icon-cpu.svg') !important; +} + +td.pmx-itype-icon-memory .x-grid-cell-inner::before { + -webkit-mask-image: url('../images/icon-ram.svg') !important; + mask-image: url('../images/icon-ram.svg') !important; +} + + +/* Icon overlays - default styling */ +.x-tree-icon-custom::after, +.x-grid-icon-custom::after { + color: #aaaaaa !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* RUNNING VMs/CTs - Green status indicator (PVE default) */ +.x-tree-icon-custom.running::after, +.x-grid-icon-custom.running::after, +.x-treelist-item-icon.running::after { + color: rgb(33, 191, 75) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* ONLINE state - Green */ +.x-tree-icon-custom.online::after, +.x-grid-icon-custom.online::after { + color: rgb(33, 191, 75) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* Stopped/offline - Muted gray */ +.x-tree-icon-custom.stopped, +.x-tree-icon-custom.offline, +.x-grid-icon-custom.stopped, +.x-grid-icon-custom.offline { + color: #888888 !important; +} + +/* Unknown state - Gray */ +.x-tree-icon-custom.unknown::after, +.x-grid-icon-custom.unknown::after { + color: #888888 !important; +} + +/* ERROR states - Red (PVE default) */ +.x-tree-icon-custom.error::after, +.x-tree-icon-custom.offline::after, +.x-tree-icon-custom.ha-error::after, +.x-grid-icon-custom.error::after, +.x-grid-icon-custom.offline::after, +.x-grid-icon-custom.ha-error::after { + color: rgb(204, 24, 0) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* PAUSED/SUSPENDED - Amber (PVE default) */ +.x-tree-icon-custom.paused::after, +.x-tree-icon-custom.suspended::after, +.x-tree-icon-custom.lock-suspending::after, +.x-grid-icon-custom.paused::after, +.x-grid-icon-custom.suspended::after, +.x-grid-icon-custom.lock-suspending::after { + color: rgb(204, 142, 0) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* PENDING/WARNING states - Yellow (PVE default) */ +.x-tree-icon-custom.pending::after, +.x-tree-icon-custom.io-error::after, +.x-tree-icon-custom.internal-error::after, +.x-tree-icon-custom.guest-panicked::after, +.x-grid-icon-custom.pending::after, +.x-grid-icon-custom.io-error::after, +.x-grid-icon-custom.internal-error::after, +.x-grid-icon-custom.guest-panicked::after { + color: rgb(255, 204, 0) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* HA MAINTENANCE - Blue (PVE default) */ +.x-tree-icon-custom.ha-maintenance::after, +.x-grid-icon-custom.ha-maintenance::after { + color: rgb(56, 146, 212) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* Locked icons */ +.x-tree-icon-custom.locked::after, +.x-tree-icon-custom.lock-backup::after, +.x-tree-icon-custom.lock-migrate::after, +.x-tree-icon-custom.lock-suspended::after, +.x-grid-icon-custom.locked::after, +.x-grid-icon-custom.lock-backup::after, +.x-grid-icon-custom.lock-migrate::after, +.x-grid-icon-custom.lock-suspended::after { + color: #aaaaaa !important; +} + +/* LXC/QEMU type indicators */ +.x-tree-icon-custom.lxc::after, +.x-tree-icon-custom.qemu::after, +.x-grid-icon-custom.lxc::after, +.x-grid-icon-custom.qemu::after { + background-color: transparent; + color: #888888 !important; +} + +.x-treelist-item-icon.lxc::after, +.x-treelist-item-icon.qemu::after { + background-color: transparent; + color: #888888 !important; +} + +/* Tree expander arrows */ +.x-tree-arrows .x-tree-expander { + filter: brightness(200%); +} + +/* v2.2.18: cancel old sprite-inversion; custom CSS controls handle appearance now */ +.x-form-checkbox-default, +.x-form-radio-default, +.x-column-header-checkbox .x-column-header-checkbox::after, +.x-grid-checkcolumn::after, +.x-menu-item-checked .x-menu-item-icon-default.x-menu-item-checkbox, +.x-menu-item-unchecked .x-menu-item-icon-default.x-menu-item-checkbox { + filter: none !important; +} + +/* ===================================================== + PANELS - UniFi base radius (8px) + ===================================================== */ +.x-panel, +.x-panel-default { + border-radius: var(--gh-radius-lg) !important; + padding: 0 !important; +} + +/* Column panels — native stacked layout (Issue #23 fix) */ +.x-panel.x-column { + padding: 5px !important; + margin: 0 !important; + max-width: none !important; + box-sizing: border-box !important; +} + +/* Column panel card styling — borders for summary + chart panels */ +.x-panel.x-panel-default.x-column { + border: 1px solid var(--gh-border-default) !important; + border-radius: var(--gh-radius-lg) !important; + overflow: hidden !important; +} + +/* v2.2.1: Guest status panel and Notes panel borders */ +[id^="pveGuestStatusView-"].x-panel, +[id^="pveLxcStatusView-"].x-panel, +[id^="pveQemuStatusView-"].x-panel, +[id^="pmxNotesView-"].x-panel { + border: 1px solid var(--gh-border-default) !important; + border-radius: var(--gh-radius-lg) !important; +} + +.x-panel-body, +.x-panel-body-default { + background-color: var(--gh-canvas-default) !important; + color: var(--gh-fg-default) !important; + border: none !important; +} + +/* Panel headers - only bottom border, flush with edges */ +.x-panel-header, +.x-panel-header-default { + background-color: var(--gh-canvas-muted) !important; + border: none !important; + border-bottom: 1px solid var(--gh-border-default) !important; + border-radius: var(--gh-radius-lg) var(--gh-radius-lg) 0 0 !important; + margin: 0 !important; + padding: 8px 12px !important; + width: 100% !important; + box-sizing: border-box !important; + overflow: visible !important; +} + +/* Title text — prevent border-radius clipping */ +.x-title-text, +.x-title-text-default { + overflow: visible !important; +} + +.x-panel-bodyWrap, +.x-panel-bodyWrap-default { + margin: 0 !important; + padding: 0 !important; +} + +/* Remove borders from nested panels (like gauge widgets inside Resources) */ +.x-panel-body>.x-box-layout-ct, +.x-panel-body>.x-container, +.x-panel-body>.x-box-inner, +[id*="pmxGauge"] { + border: none !important; +} + +.x-panel-header-title-default, +.x-window-header-title-default { + color: var(--gh-fg-default) !important; +} + +.x-panel-header-default .x-tool-tool-el { + background-color: transparent; +} + +.x-tool-img { + filter: brightness(175%); +} + +.x-tool-over .x-tool-img { + filter: brightness(200%); +} + +div[id^="pveResourceTree-"][id$="-body"] { + border-color: var(--gh-canvas-default) !important; +} + +/* Resource tree: remove row separators/borders */ +[id^="pveResourceTree-"].x-tree-panel td.x-grid-cell, +[id^="pveResourceTree-"].x-tree-panel .x-grid-td, +[id^="pveResourceTree-"].x-tree-panel .x-grid-cell { + border-bottom: none !important; +} + +/* Resource tree: slightly increased row spacing */ +div[id^="pveResourceTree"] .x-grid-cell { + padding-top: 3px !important; + padding-bottom: 3px !important; +} + +.x-panel-bodyWrap { + overflow: visible !important; +} + +/* ===================================================== + SPLITTERS / SEPARATORS + v2.1.1: Fixed double border issue + ===================================================== */ +.x-splitter-vertical { + background-color: transparent !important; + border-left: 1px solid var(--gh-border-default) !important; + border-right: none !important; + width: 1px !important; +} + +.x-splitter-horizontal { + background-color: var(--gh-canvas-inset) !important; + border-top: 1px solid var(--gh-border-default) !important; +} + +/* Toolbox tree (pve-nav) right border - full height */ +/* Fix: border must be on .pve-toolbar-bg (the full-height docked toolbar), + not on .x-treelist which only stretches to cover its items. + z-index: 3 needed because content toolbar (z-index: 2, same as nav) renders + on top (later in DOM), covering the nav right border. */ +.pve-toolbar-bg { + border-right: 1px solid var(--gh-border-default) !important; + z-index: 3 !important; +} + +.x-treelist.x-treelist-pve-nav { + border-right: none !important; +} + +/* ===================================================== + TOOLBARS + ===================================================== */ +.x-toolbar, +.x-toolbar-default { + background-color: var(--gh-canvas-default) !important; + border-color: var(--gh-border-default) !important; +} + +.x-toolbar-default.x-docked-top { + border: none !important; + border-bottom: 1px solid var(--gh-border-default) !important; +} + +.x-toolbar-default .x-toolbar-separator { + border-color: var(--gh-border-default); +} + +.x-toolbar-text-default { + color: var(--gh-fg-muted); +} + +/* ===================================================== + PRIMARY BUTTONS - GitHub Green (6px radius) + ===================================================== */ +.x-btn-default-small { + background-color: var(--gh-success-emphasis) !important; + border: 1px solid rgba(255, 255, 255, 0.15) !important; + border-radius: var(--gh-radius-md) !important; +} + +.x-btn-default-small .x-btn-inner { + color: var(--gh-fg-on-emphasis) !important; +} + +.x-btn-default-small.x-btn-over, +.x-keyboard-mode .x-btn-default-small.x-btn-focus { + background-color: var(--gh-success-hover) !important; +} + +.x-btn-default-small.x-btn.x-btn-disabled { + background-color: var(--gh-success-emphasis) !important; + opacity: 0.5; +} + +.x-btn-default-small.x-btn.x-btn-pressed { + background-color: var(--gh-success-active) !important; +} + +/* ===================================================== + SECONDARY/TOOLBAR BUTTONS (4px radius) + ===================================================== */ +.x-btn-default-toolbar-small { + background-color: #21262d !important; + border: 1px solid var(--gh-border-default) !important; + border-radius: var(--gh-radius-md) !important; +} + +.x-btn-default-toolbar-small .x-btn-inner-default-toolbar-small, +.x-btn-default-toolbar-small .x-btn-icon-el-default-toolbar-small { + color: #f0f6fc !important; /* GitHub Primer default button text color */ +} + +.x-btn-default-toolbar-small .x-btn-wrap-default-toolbar-small.x-btn-arrow-right::after, +.x-btn-default-toolbar-small .x-btn-wrap-default-toolbar-small.x-btn-split-right::after { + filter: brightness(150%); +} + +.x-btn-default-toolbar-small.x-btn-over, +.x-keyboard-mode .x-btn-default-toolbar-small.x-btn-focus { + background-color: #262c36 !important; + border-color: var(--gh-border-default) !important; +} + +.x-btn-default-toolbar-small.x-btn.x-btn-disabled { + background-color: #21262d !important; + opacity: 0.5; +} + +.x-btn-default-toolbar-small.x-btn.x-btn-menu-active, +.x-btn-default-toolbar-small.x-btn.x-btn-pressed { + background-color: var(--gh-accent-emphasis) !important; + border-color: var(--gh-accent-emphasis) !important; + padding: 4px 8px !important; /* Fix #30: prevent width change on dropdown */ +} + +.x-btn-default-toolbar-small.x-btn.x-btn-pressed .x-btn-inner-default-toolbar-small, +.x-btn-default-toolbar-small.x-btn.x-btn-pressed .x-btn-icon-el-default-toolbar-small { + color: var(--gh-fg-on-emphasis) !important; +} + +/* ===================================================== + FORM ELEMENTS (4px radius) + ===================================================== */ +.x-form-trigger-default { + background-color: #21262d !important; +} + +.x-form-text-default { + background-color: #21262d !important; + color: var(--gh-fg-default) !important; + border-radius: var(--gh-radius-sm) !important; +} + +.x-form-trigger-wrap, +.x-form-trigger-wrap-default { + border-color: var(--gh-border-default) !important; + background-color: #21262d !important; + border-radius: var(--gh-radius-sm) !important; +} + +.x-form-trigger-wrap-default.x-form-trigger-wrap-focus { + border-color: var(--gh-accent-emphasis) !important; + box-shadow: 0 0 0 3px var(--gh-accent-subtle) !important; +} + +.x-form-item-label-default, +.x-form-cb-label-default { + color: var(--gh-fg-default) !important; +} + +.x-form-display-field-default { + color: var(--gh-fg-muted) !important; +} + +.x-form-spinner-default { + background-color: #21262d !important; +} + +.x-fieldset, +.x-fieldset-default { + border-color: var(--gh-border-default) !important; + border-radius: var(--gh-radius-lg) !important; +} + +.x-fieldset-header-default>.x-fieldset-header-text { + color: var(--gh-fg-default) !important; +} + +/* ===================================================== + BOUNDLIST / DROPDOWNS (4px radius) + ===================================================== */ +.x-boundlist { + background-color: var(--gh-canvas-muted) !important; + border: 1px solid var(--gh-border-default) !important; + border-radius: var(--gh-radius-lg) !important; + box-shadow: 0 8px 24px rgba(1, 4, 9, 0.5); + overflow: hidden !important; +} + +.x-boundlist-item { + background-color: transparent !important; + color: var(--gh-fg-default) !important; +} + +.x-boundlist-selected { + background-color: var(--gh-accent-subtle) !important; +} + +.x-boundlist-item-over { + background-color: var(--gh-hover-overlay) !important; +} + +/* ===================================================== + GRIDS / TABLES (square corners) + ===================================================== */ +.x-grid, +.x-grid-view { + border-radius: 0 !important; +} + +.x-column-header { + border-color: var(--gh-border-default) !important; + background-color: transparent !important; +} + +.x-column-header-inner, +.x-column-header-text { + color: var(--gh-fg-default) !important; + font-weight: 600 !important; +} + +.x-column-header-trigger { + border-color: var(--gh-border-muted) !important; +} + +.x-grid-item, +.x-column-header-default, +.x-grid-cell-row-numberer { + color: var(--gh-fg-default) !important; + background-color: var(--gh-canvas-default) !important; +} + +.x-grid-cell-special { + border-color: var(--gh-border-default) !important; +} + +.x-grid-group-hd { + background-color: var(--gh-canvas-default) !important; + border-color: var(--gh-border-default) !important; +} + +.x-grid-group-title { + color: var(--gh-fg-default) !important; +} + +.x-grid-header-ct { + background-color: var(--gh-canvas-muted) !important; + border: 1px solid var(--gh-border-muted) !important; + border-radius: var(--gh-radius-lg) var(--gh-radius-lg) 0 0 !important; +} + +.x-grid-item-alt { + background-color: #0b0f14 !important; /* Slightly darker than canvas-default */ +} + +.x-grid-with-row-lines .x-grid-item { + border-color: var(--gh-border-muted) !important; +} + +.x-grid-cell { + border-bottom: 1px solid var(--gh-border-subtle) !important; +} + +.x-grid-item-over, +.x-grid-with-row-lines .x-grid-item.x-grid-item-over { + background-color: var(--gh-hover-overlay) !important; +} + +.x-grid-item-selected, +.x-grid-with-row-lines .x-grid-item.x-grid-item-selected { + background-color: var(--gh-accent-subtle) !important; +} + +.x-column-header-over, +.x-column-header-open { + background-color: var(--gh-hover-overlay) !important; +} + +.x-column-header-sort-ASC, +.x-column-header-sort-DESC { + background-color: #1b384c !important; +} + +.x-grid-row-summary .x-grid-cell, +.x-grid-row-summary .x-grid-rowwrap, +.x-grid-row-summary .x-grid-cell-rowbody { + background-color: var(--gh-canvas-default) !important; + border-color: var(--gh-border-default); +} + +.x-grid-with-col-lines .x-grid-cell, +.x-grid-with-col-lines .x-grid-item-over .x-grid-cell, +.x-grid-with-col-lines .x-grid-item-selected .x-grid-cell { + border-color: var(--gh-border-default) !important; +} + +.x-dd-drag-proxy { + background-color: var(--gh-canvas-muted); + border-color: var(--gh-border-default); + color: var(--gh-fg-default); +} + +.x-keyboard-mode .x-grid-item-focused { + background-color: var(--gh-hover-overlay) !important; + color: var(--gh-fg-on-emphasis) !important; +} + +/* v2.2.1: Remove blue outline from selected/focused items in resource tree */ +.x-keyboard-mode .x-grid-item-focused .x-grid-cell-inner::before, +.x-keyboard-mode .x-grid-item-selected .x-grid-cell-inner::before, +.x-grid-item-selected .x-grid-cell-inner::before, +.x-grid-item-focused .x-grid-cell-inner::before, +[id^="pveResourceTree"] .x-grid-item-selected .x-grid-cell-inner::before, +[id^="pveResourceTree"] .x-grid-item-focused .x-grid-cell-inner::before { + content: none !important; + display: none !important; + border: none !important; +} + +.x-grid-empty { + background-color: var(--gh-canvas-default) !important; + color: var(--gh-fg-muted) !important; +} + +/* ===================================================== +/* ===================================================== + MENUS (variable radius) + ===================================================== */ +.x-menu, +.x-menu-default { + border: 1px solid var(--gh-border-default) !important; + border-radius: var(--gh-radius-lg) !important; + box-shadow: 0 8px 24px rgba(1, 4, 9, 0.5) !important; + overflow: hidden !important; +} + +.x-menu-body-default { + background-color: var(--gh-canvas-muted) !important; +} + +.x-menu-header { + background-color: var(--gh-accent-emphasis) !important; +} + +/* Menu Layout Fix (Flexbox reordering) */ +.x-menu-item-default > .x-menu-item-link { + display: flex !important; + align-items: center !important; + flex-direction: row !important; + padding: 6px 8px !important; + line-height: 20px !important; + text-decoration: none !important; +} + +.x-menu-item-text-default { + color: var(--gh-fg-default) !important; + font-size: 14px !important; + margin-left: 0 !important; +} + +.x-menu-item-icon-default { + color: var(--gh-fg-muted) !important; + order: -1 !important; /* Move icon to start */ + position: relative !important; + float: none !important; + margin-right: 8px !important; + margin-left: 0 !important; + left: auto !important; + top: auto !important; + width: 16px !important; + text-align: center !important; +} + +/* Remove the gutter/separator line */ +.x-menu-icon-separator-default { + display: none !important; +} + +.x-menu-item-default.x-menu-item-separator { + background-color: var(--gh-canvas-muted); + border-color: var(--gh-border-default); + margin: 4px 0 !important; +} + +.x-menu-item-default.x-menu-item-focus, +.x-menu-item-default.x-menu-item-active { + background-color: var(--gh-accent-emphasis) !important; + color: var(--gh-fg-on-emphasis) !important; +} + +.x-menu-item-active .x-menu-item-text-default, +.x-menu-item-focus .x-menu-item-text-default, +.x-menu-item-active .x-menu-item-icon-default, +.x-menu-item-focus .x-menu-item-icon-default { + color: var(--gh-fg-on-emphasis) !important; +} + +/* ===================================================== + PROGRESS BARS (5px radius) + ===================================================== */ +.x-progress, +.x-progress-default { + background-color: #21262d !important; + border-radius: var(--gh-radius-md) !important; +} + +.x-progress-default .x-progress-bar-default { + background-color: var(--gh-accent-emphasis) !important; + border-radius: var(--gh-radius-md) !important; +} + +.x-progress-default .x-progress-text { + color: var(--gh-fg-default) !important; +} + +.x-progress.warning .x-progress-bar { + background-color: var(--pwt-gauge-warn) !important; +} + +.x-progress.critical .x-progress-bar { + background-color: var(--pwt-gauge-crit) !important; +} + +/* ===================================================== + SPLITTERS + ===================================================== */ +.x-splitter { + background-color: var(--gh-canvas-inset) !important; +} + +.x-splitter-horizontal { + background-color: var(--gh-canvas-inset) !important; + border-top: 1px solid var(--gh-border-default) !important; +} + +.x-keyboard-mode .x-splitter-focus::after { + border-color: var(--gh-accent-emphasis) !important; +} + +.x-layout-split-bottom { + opacity: 0.7; +} + +/* ===================================================== + TABS — GitHub UnderlineNav style (v2.2.21) + Flat tabs, coral ::after underline on active tab. + Uses ::after (not border-bottom — ExtJS overrides it). + ===================================================== */ +.x-tab-bar, +.x-tab-bar-default { + background-color: var(--gh-canvas-default) !important; + border-radius: 0 !important; + border-bottom: 1px solid #21262d !important; + padding-bottom: 0 !important; +} + +/* v2.2.23: overflow visible on ALL containers within tab bar to prevent clipping */ +.x-tab-bar .x-box-inner, +.x-tab-bar .x-box-target, +.x-tab-bar-body, +.x-tab-bar-body-default { + overflow: visible !important; +} + +/* Base tab — no margin-bottom hack, position relative, no outlines */ +.x-tab, +.x-tab-default, +.x-tab-default-top { + background-color: transparent !important; + border: none !important; + border-radius: 0 !important; + padding: 8px 16px 8px !important; + overflow: visible !important; + margin-bottom: 0 !important; + transition: color .12s ease !important; + outline: none !important; + box-shadow: none !important; +} + +/* Remove ::after from inactive tabs */ +.x-tab::after { + display: none !important; +} + +.x-tab-inner-default { + color: #848d97 !important; + font-size: 13px !important; +} + +.x-tab-default.x-tab-over { + background-color: transparent !important; +} +.x-tab-default.x-tab-over .x-tab-inner-default { + color: #e6edf3 !important; +} + +/* Active tab */ +.x-tab-default.x-tab.x-tab-active { + background-color: transparent !important; + border: none !important; + overflow: visible !important; + margin-bottom: 0 !important; + outline: none !important; + box-shadow: none !important; +} + +/* v2.2.23: coral underline INSIDE the tab at bottom:0 — immune to parent clipping */ +.x-tab-default.x-tab.x-tab-active::after { + content: '' !important; + display: block !important; + position: absolute !important; + bottom: 0 !important; + left: 0 !important; + right: 0 !important; + height: 2px !important; + background: #f47067 !important; + z-index: 10 !important; + border-radius: 0 !important; + pointer-events: none !important; +} + +.x-tab-active .x-tab-inner-default { + color: #e6edf3 !important; + font-weight: 600 !important; +} + +.x-tab-default.x-tab.x-tab-disabled { + background-color: transparent !important; + border: none !important; + color: var(--gh-fg-subtle) !important; + margin-bottom: 0 !important; +} + +/* Keyboard mode focus: keep the same indicator, no outline */ +.x-keyboard-mode .x-tab-default.x-tab-focus, +.x-keyboard-mode .x-tab-default.x-tab-focus.x-tab-active { + background-color: transparent !important; + border: none !important; + outline: none !important; + box-shadow: none !important; + margin-bottom: 0 !important; +} +.x-keyboard-mode .x-tab-default.x-tab-focus.x-tab-active::after { + content: '' !important; + display: block !important; + position: absolute !important; + bottom: 0 !important; + left: 0 !important; + right: 0 !important; + height: 2px !important; + background: #f47067 !important; + z-index: 10 !important; + pointer-events: none !important; +} + +/* Kill ALL interaction outlines/shadows — every possible state */ +.x-tab:focus, +.x-tab *:focus, +.x-tab-focus, +.x-tab-active.x-tab-focus, +.x-tab-inner-focus, +.x-tab-button-focus, +.x-tab-pressed, +.x-tab-active.x-tab-pressed, +.x-tab-over, +.x-tab:active, +.x-tab *:active { + outline: none !important; + box-shadow: none !important; +} + +.x-tabpanel-child { + border-radius: 0 0 var(--gh-radius-lg) var(--gh-radius-lg) !important; +} + +/* ===================================================== + TOOLTIPS (6px radius) + ===================================================== */ +.x-tip, +.x-tip-default { + background-color: var(--gh-canvas-muted) !important; + border: 1px solid var(--gh-border-default) !important; + border-radius: var(--gh-radius-md) !important; + box-shadow: 0 4px 12px rgba(1, 4, 9, 0.4); +} + +.x-tip-body-default { + color: var(--gh-fg-default) !important; +} + +.x-tip-form-invalid { + background-color: var(--gh-canvas-muted) !important; + border-color: var(--gh-danger-emphasis) !important; +} + +.x-tip-body-form-invalid { + color: var(--gh-danger-fg) !important; +} + +/* ===================================================== + TREE NAVIGATION (4px radius) + ===================================================== */ +.x-treelist-item { + background-color: var(--gh-canvas-default) !important; + border-radius: var(--gh-radius-md) !important; +} + +/* v2.2.4: Pseudo-element approach for balanced hover/selected highlighting */ +.x-treelist-row { + border-radius: var(--gh-radius-md) !important; + background-color: transparent !important; + position: relative !important; + z-index: 0 !important; +} + +.x-treelist-row::before { + content: ""; + position: absolute; + top: 1px; + bottom: 1px; + left: 0; + right: 4px; + border-radius: var(--gh-radius-md); + background-color: transparent; + z-index: -1; + pointer-events: none; +} + +/* v2.1.4: Fix toolbox tree item text overlapping icons (icon is 24px absolute positioned) */ +.x-treelist-item-text { + margin-left: 28px !important; +} + +/* Toolbox tree items - increased visibility */ +.x-treelist-item-text, +.x-treelist-item-icon, +.x-treelist.x-treelist-pve-nav .x-treelist-item-text, +.x-treelist.x-treelist-pve-nav .x-treelist-item-icon { + color: #b1bac4 !important; /* Brighter than --gh-fg-muted */ +} + +/* Hover state - apply to pseudo-element */ +.x-treelist-row-over { + background-color: transparent !important; +} + +.x-treelist-row-over::before { + background-color: var(--gh-hover-overlay) !important; +} + +.x-treelist-row-over .x-treelist-item-icon, +.x-treelist-row-over .x-treelist-item-text { + background-color: transparent !important; + color: var(--gh-fg-default) !important; +} + +/* Toolbox tree - selected/active item uses GitHub green (pseudo-element) */ +.x-treelist-item-selected>.x-treelist-row { + background-color: transparent !important; +} + +.x-treelist-item-selected>.x-treelist-row::before, +.x-treelist-item-selected>.x-treelist-row:hover::before { + background-color: var(--gh-success-emphasis) !important; +} + +.x-treelist-item-selected .x-treelist-item-text, +.x-treelist-item-selected .x-treelist-item-icon { + color: var(--gh-fg-on-emphasis) !important; +} + +.x-treelist-pve-nav { + background-color: var(--gh-canvas-default) !important; + border-color: var(--gh-border-default) !important; +} + +/* ===================================================== + WINDOWS / MODALS (variable radius) + ===================================================== */ +.x-window, +.x-window-default { + background-color: var(--gh-canvas-inset) !important; + border: 1px solid var(--gh-border-default) !important; + border-radius: var(--gh-radius-lg) !important; + box-shadow: 0 8px 24px rgba(1, 4, 9, 0.5) !important; + overflow: hidden !important; +} + +.x-window .x-window-header, +.x-window-header-default { + background-color: var(--gh-canvas-muted) !important; + border-color: transparent !important; + border-radius: var(--gh-radius-lg) var(--gh-radius-lg) 0 0 !important; +} + +.x-window-header-default .x-mask { + background-color: rgba(1, 4, 9, 0.7); +} + +.x-window .x-window-body, +.x-window-body-default { + background-color: var(--gh-canvas-default) !important; + border-color: var(--gh-border-default) !important; + color: var(--gh-fg-default) !important; + border-radius: 0 0 var(--gh-radius-lg) var(--gh-radius-lg) !important; +} + +.x-window-ghost { + background-color: var(--gh-canvas-default) !important; +} + +.x-window-header-default .x-tool-img { + background-color: transparent; +} + +.x-message-box .x-window-body { + background-color: var(--gh-canvas-muted) !important; +} + +/* ===================================================== + LEGEND / CHARTS + ===================================================== */ +.x-legend-container { + background-color: var(--gh-canvas-default) !important; +} + +.x-legend-horizontal .x-legend-item { + background-color: var(--gh-canvas-muted) !important; + color: var(--gh-fg-default) !important; + border: 1px solid var(--gh-border-muted) !important; +} + +/* ===================================================== + PROXMOX-SPECIFIC + ===================================================== */ +img[id^="proxmoxlogo-"][id$="-img"], +img[id^="proxmoxLogoSvg-"][id$="-img"] { + filter: invert(1) hue-rotate(180deg); +} + +.proxmox-invalid-row { + background-color: #521414 !important; +} + +.proxmox-warning-row { + background-color: #640 !important; +} + +.proxmox-disabled-row td { + color: var(--gh-fg-subtle) !important; +} + +.pmx-hint { + background-color: #640 !important; +} + +.pmx-hint a { + color: var(--gh-accent-fg) !important; +} + +.info-blue { + color: var(--gh-accent-fg) !important; +} + +.critical { + color: var(--gh-danger-fg) !important; +} + +/* Inline buttons (Documentation, Help) - GitHub Primer dark secondary button style */ +.proxmox-inline-button { + height: 28px !important; + min-height: 28px !important; + display: flex !important; + align-items: center !important; + padding: 3px 8px !important; + background-color: #21262d !important; + border: 1px solid #3d444d !important; + border-radius: var(--gh-radius-md) !important; + color: #f0f6fc !important; + transition: background 0.08s cubic-bezier(0.33, 1, 0.68, 1) !important; +} + +.proxmox-inline-button:hover, +.proxmox-inline-button.x-btn-over { + background-color: #262c36 !important; + border-color: #6e7681 !important; +} + +.proxmox-inline-button:active, +.proxmox-inline-button.x-btn-pressed { + background-color: #2a313c !important; +} + +.proxmox-inline-button .x-btn-inner, +.proxmox-inline-button .x-btn-icon-el { + color: #f0f6fc !important; +} + +/* Loading states */ +.x-grid-row-loading, +.x-treelist-item-loading .x-treelist-item-icon, +.x-mask-msg-text, +.x-grid-tree-loading .x-tree-icon { + filter: invert(90%); +} + +.x-mask-msg { + background-color: var(--gh-canvas-muted) !important; + border: 1px solid var(--gh-border-default) !important; +} + +/* Markdown */ +.pmx-md code { + background-color: var(--gh-canvas-muted) !important; +} + +.pmx-md pre code { + border-color: var(--gh-border-default) !important; +} + +.pmx-md a { + color: var(--gh-accent-fg) !important; +} + +/* Tags */ +.pve-edit-tag.editable span { + background-color: var(--gh-canvas-muted) !important; + color: var(--gh-fg-default) !important; + border-color: var(--gh-border-default) !important; +} + +/* Datepicker */ +.x-datepicker, +.x-datepicker-column-header, +.x-monthpicker { + background-color: var(--gh-canvas-default) !important; + color: var(--gh-fg-default) !important; + border-color: transparent !important; +} + +.x-datepicker-header, +.x-datepicker-footer, +.x-monthpicker-buttons { + background-color: var(--gh-canvas-inset) !important; +} + +.x-datepicker-date, +.x-monthpicker-item-inner { + color: var(--gh-fg-default) !important; +} + +.x-datepicker-selected div.x-datepicker-date, +.x-monthpicker-item a.x-monthpicker-selected, +a.x-monthpicker-item-inner:hover, +div.x-datepicker-date:hover { + background-color: var(--gh-hover-overlay) !important; + color: var(--gh-fg-on-emphasis) !important; +} + +/* ===================================================== + SCROLLBARS - Modern minimal styling + v2.1.1: Reduced width, GitHub Dark colors + ===================================================== */ +::-webkit-scrollbar { + width: 6px; + height: 6px; +} + +::-webkit-scrollbar-track { + background: var(--gh-canvas-default); + border-radius: var(--gh-radius-sm); +} + +::-webkit-scrollbar-thumb { + background: var(--gh-border-default); + border-radius: var(--gh-radius-sm); + border: 1px solid transparent; + background-clip: padding-box; +} + +::-webkit-scrollbar-thumb:hover { + background: var(--gh-border-muted); +} + +::-webkit-scrollbar-corner { + background: var(--gh-canvas-default); +} + +/* Firefox scrollbar styling */ +* { + scrollbar-width: thin; + scrollbar-color: var(--gh-border-default) var(--gh-canvas-default); +} + +/* ===================================================== + USAGE BARS (Vertical progress indicators) + v2.1.2: Using Proxmox dark theme default #e6e6e6 + ===================================================== */ +.usage { + background-color: #e6e6e6 !important; +} + +/* ===================================================== + DROPDOWNS - GitHub profile menu styling (dark) + ===================================================== */ +.x-menu, +.x-menu-default { + background-color: var(--gh-canvas-inset) !important; /* #010409 */ + border: 1px solid var(--gh-border-muted) !important; /* #3d444db3 */ + border-radius: 6px !important; + box-shadow: 0 8px 24px rgba(1, 4, 9, 0.8) !important; + padding: 4px !important; +} + +.x-menu-body-default { + background-color: transparent !important; + padding: 4px !important; +} + +.x-menu-header { + background-color: transparent !important; + color: var(--gh-fg-default) !important; +} + +.x-menu-item-default > .x-menu-item-link { + display: flex !important; + align-items: center !important; + flex-direction: row !important; + gap: 8px !important; + justify-content: flex-start !important; + flex-wrap: nowrap !important; + min-height: 28px !important; + border-radius: 6px !important; + padding: 6px 8px !important; + line-height: 20px !important; + border: none !important; + cursor: pointer !important; + outline: none !important; + box-shadow: none !important; + white-space: nowrap !important; +} + +.x-menu-item-text-default { + color: var(--gh-fg-default) !important; + font-size: 13px !important; +} + +.x-menu-item-icon-default { + color: var(--gh-fg-muted) !important; + order: -1 !important; + margin-left: 0 !important; + margin-right: 8px !important; + position: relative !important; + left: 0 !important; + right: auto !important; + text-align: left !important; + display: inline-flex !important; + align-items: center !important; + justify-content: center !important; + height: 20px !important; + line-height: 20px !important; + vertical-align: middle !important; + top: 1px !important; + flex: 0 0 16px !important; + width: 16px !important; + align-self: center !important; + float: none !important; +} + +.x-menu-item-text-default { + order: 1 !important; + margin-left: 0 !important; + text-align: left !important; + line-height: 20px !important; + display: inline-flex !important; + align-items: center !important; + flex: 1 1 auto !important; + width: auto !important; + white-space: nowrap !important; +} + +.x-menu-item-default > .x-menu-item-link > .x-menu-item-icon-default, +.x-menu-item-default > .x-menu-item-link > .x-menu-item-text-default { + width: auto !important; + max-width: none !important; +} + +.x-menu-item-arrow, +.x-menu-item-arrow-default { + order: 2 !important; + margin-left: auto !important; +} + +.x-menu-item-default.x-menu-item-separator { + background-color: #21262d !important; + border: none !important; + height: 1px !important; + margin: 6px 4px !important; +} + +.x-menu-item-default.x-menu-item-focus, +.x-menu-item-default.x-menu-item-active, +.x-menu-item:hover { + background-color: var(--gh-canvas-muted) !important; /* #151b23 */ + color: var(--gh-fg-default) !important; + border-radius: 6px !important; +} + +.x-menu-item-active .x-menu-item-text-default, +.x-menu-item-focus .x-menu-item-text-default { + color: var(--gh-fg-default) !important; +} + +/* Combo dropdowns (selects, boundlists) */ +.x-boundlist { + background-color: var(--gh-canvas-inset) !important; + border: 1px solid var(--gh-border-muted) !important; + border-radius: 6px !important; + box-shadow: 0 8px 24px rgba(1, 4, 9, 0.8) !important; + padding: 2px !important; + overflow: hidden !important; +} + +.x-boundlist-item { + border-radius: 6px !important; + padding: 2px 6px !important; + line-height: normal !important; + border: none !important; + cursor: pointer !important; + outline: none !important; + box-shadow: none !important; +} + +.x-boundlist-item-over { + background-color: var(--gh-canvas-muted) !important; /* #151b23 */ +} + +.x-boundlist-selected { + background-color: var(--gh-selectmenu-active) !important; /* #0c2d6b */ + color: var(--gh-fg-on-emphasis) !important; +} + +/* Floating grid pickers (storage/ISO selectors) */ +.x-layer.x-grid .x-grid-view, +.x-panel.x-layer.x-grid .x-grid-view, +.x-panel.x-layer.x-grid, +.x-layer.x-panel.x-grid { + border-radius: 6px !important; +} + +.x-layer.x-grid .x-grid-item-over, +.x-layer.x-grid .x-grid-item-selected, +.x-panel.x-layer.x-grid .x-grid-item-over, +.x-panel.x-layer.x-grid .x-grid-item-selected { + border-radius: 6px !important; + outline: none !important; + box-shadow: none !important; +} + +.x-layer.x-grid .x-grid-item-over td:first-child, +.x-layer.x-grid .x-grid-item-selected td:first-child, +.x-panel.x-layer.x-grid .x-grid-item-over td:first-child, +.x-panel.x-layer.x-grid .x-grid-item-selected td:first-child { + border-radius: 6px 0 0 6px !important; +} + +.x-layer.x-grid .x-grid-item-over td:last-child, +.x-layer.x-grid .x-grid-item-selected td:last-child, +.x-panel.x-layer.x-grid .x-grid-item-over td:last-child, +.x-panel.x-layer.x-grid .x-grid-item-selected td:last-child { + border-radius: 0 6px 6px 0 !important; +} + +/* ===================================================== + UNIFI BORDER-RADIUS PARITY (ported from theme-unifi.css) + ===================================================== */ +.x-border-box, +.x-border-box * { + border-radius: var(--gh-radius-lg); +} + +/* Remove rounded corners from grids/tables/lists (Tasks, logs) */ +.x-grid, +.x-grid *, +.x-grid-header-ct, +.x-grid-header-ct *, +.x-grid-view, +.x-grid-view *, +.x-column-header, +.x-column-header *, +.x-grid-item, +.x-grid-cell, +.x-grid-cell-inner, +.x-grid-row, +table, +table *, +tr, +td, +th, +.x-legend, +.x-legend *, +.x-legend-container, +.x-legend-container *, +.x-legend-item, +.x-legend-horizontal .x-legend-item, +.x-legend-vertical .x-legend-item, +.x-legend-horizontal .x-legend-item:first-child, +.x-legend-horizontal .x-legend-item:last-child, +.x-legend-vertical .x-legend-item:first-child, +.x-legend-vertical .x-legend-item:last-child, +.x-tool, +.x-tool-tool-el, +.x-tool-default, +.x-tool-img { + border-radius: 0 !important; +} + +/* Form elements - exclude from global radius */ +.x-form-item, +.x-form-item-default, +.x-form-item-body, +.x-form-item-body-default, +.x-form-text-field-body, +.x-form-text-field-body-default, +.x-form-fieldcontainer, +.x-field, +.x-field-default, +.x-form-type-text { + border-radius: 0 !important; +} + +/* Reset layout containers that clip form elements */ +.x-box-layout-ct, +.x-panel-bodyWrap, +.x-panel-bodyWrap-default, +.x-autocontainer-innerCt, +.x-autocontainer-outerCt, +.x-panel.x-tabpanel-child, +.x-panel.x-box-item, +.x-box-inner, +.x-box-target, +.x-container, +.x-container-default, +.x-window .x-panel-body, +.x-window .x-window-body, +.x-window .x-window-bodyWrap { + border-radius: 0 !important; +} + +/* Reset everything inside windows to 0 - then re-apply specific radii */ +.x-window *, +.x-window .x-autocontainer-innerCt, +.x-window .x-autocontainer-outerCt, +.x-window .x-form-layout-wrap, +.x-window .x-form-layout-auto-label, +.x-window .x-form-layout-colgroup, +.x-window .x-form-layout-column, +.x-window .x-field, +.x-window .x-form-item, +.x-window .x-form-item-body { + border-radius: 0 !important; +} + +.x-window, +.x-window-default { + border-radius: 8px !important; +} + +.x-window-header, +.x-window-header-default { + border-radius: 8px 8px 0 0 !important; +} + +.x-window .x-window-body, +.x-window-body-default { + border-radius: 0 !important; +} + +.x-window .x-btn { + border-radius: 6px !important; +} + +.x-window .x-form-checkbox { + border-radius: 4px !important; +} + +.x-window .x-form-trigger-wrap, +.x-window .x-form-trigger-wrap-default { + border-radius: 4px !important; +} + +.x-window .x-form-text-wrap, +.x-window .x-form-text { + border-radius: 4px 0 0 4px !important; +} + +.x-window .x-form-arrow-trigger { + border-radius: 0 4px 4px 0 !important; +} + +.x-form-trigger-wrap, +.x-form-trigger-wrap *, +.x-form-text-wrap, +.x-form-text-wrap *, +.x-form-text, +.x-form-trigger { + border-radius: 0 !important; +} + +.x-form-trigger-wrap, +.x-form-trigger-wrap-default { + border-radius: 4px !important; +} + +.x-form-text-wrap, +.x-form-text-wrap-default { + border-radius: 4px 0 0 4px !important; +} + +.x-form-text, +.x-form-text-default { + border-radius: 4px 0 0 4px !important; +} + +.x-form-trigger, +.x-form-trigger-default, +.x-form-arrow-trigger, +.x-form-arrow-trigger-default { + border-radius: 0 4px 4px 0 !important; +} + +.x-legend-item-marker { + border-radius: 50% !important; +} + +/* ===================================================== + CHECKBOXES & RADIOS — GitHub Primer (v2.2.18) + ===================================================== */ + +/* Base: remove sprite, styled as clean custom control */ +.x-form-checkbox, .x-form-checkbox-default, +.x-form-radio, .x-form-radio-default { + background-image: none !important; + background-color: #161b22 !important; + border: 1.5px solid #6e7681 !important; + width: 16px !important; + height: 16px !important; + display: inline-block !important; + box-sizing: border-box !important; + cursor: pointer !important; + transition: border-color .12s ease, background-color .12s ease !important; +} + +/* Checkbox: rounded square */ +.x-form-checkbox, .x-form-checkbox-default { + border-radius: 3px !important; +} + +/* Radio: circle + ::after inner dot */ +.x-form-radio, .x-form-radio-default { + border-radius: 50% !important; + position: relative !important; + transform: translateZ(0) !important; + box-shadow: inset 0 0 0 0 transparent !important; +} + +.x-form-radio::after { + content: '' !important; + position: absolute !important; + top: 50% !important; + left: 50% !important; + width: 7px !important; + height: 7px !important; + border-radius: 50% !important; + background: transparent !important; + transform: translate(-50%, -50%) scale(0) !important; + transition: transform .15s ease, background .15s ease !important; + pointer-events: none !important; +} + +/* Hover */ +.x-form-checkbox:hover, .x-form-checkbox-default:hover, +.x-form-cb-wrap:hover .x-form-checkbox { + border-color: #388bfd !important; +} + +.x-form-radio:hover, .x-form-radio-default:hover, +.x-form-cb-wrap:hover .x-form-radio { + border-color: #388bfd !important; +} + +/* CHECKED checkbox — .x-form-cb-checked lives on the .x-form-item ancestor */ +.x-form-cb-checked .x-form-checkbox, +.x-form-cb-checked .x-form-checkbox-default { + background-color: #1f6feb !important; + border-color: #1f6feb !important; + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 8'%3E%3Cpath d='M1 4l3 3 5-6' fill='none' stroke='%23fff' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") !important; + background-repeat: no-repeat !important; + background-position: center !important; + background-size: 9px 7px !important; +} + +/* SELECTED radio */ +.x-form-cb-checked .x-form-radio, +.x-form-cb-checked .x-form-radio-default { + border-color: #1f6feb !important; + background-color: #0d1117 !important; +} + +.x-form-cb-checked .x-form-radio::after { + background: #1f6feb !important; + transform: translate(-50%, -50%) scale(1) !important; +} + +/* Buttons */ +.x-btn-default-small { + border-radius: 6px !important; +} + +.x-btn-default-toolbar-small { + border-radius: 4px !important; +} + +.x-btn.x-btn-default-small:has(.fa-check) { + border-radius: 4px !important; +} + +/* Boundlist dropdowns */ +.x-boundlist { + border-radius: 4px !important; +} + +.x-boundlist-item { + border-radius: 4px !important; +} + +.x-boundlist-list-ct { + border-radius: 4px !important; +} + +.x-boundlist-item-over, +.x-boundlist-selected { + border-radius: 4px !important; +} + +/* Menus */ +.x-menu, +.x-menu-default { + border-radius: 8px !important; +} + +.x-menu-item-default.x-menu-item-focus, +.x-menu-item-default.x-menu-item-active, +.x-menu-item:hover { + border-radius: 6px !important; +} + +/* Tooltips */ +.x-tip-default { + border-radius: 6px !important; +} + +/* Tree list items */ +.x-treelist-item, +.x-treelist-item-tool { + border-radius: 4px !important; +} + +.x-treelist-row, +.x-treelist-row:hover, +.x-treelist-row-over, +.x-treelist-item-selected>.x-treelist-row, +.x-treelist-item-selected>.x-treelist-row:hover, +.x-treelist-item-expanded>.x-treelist-row, +.x-treelist-item-expanded>.x-treelist-row-over, +.x-treelist-item-expandable>.x-treelist-row, +.x-treelist-item-expandable>.x-treelist-row-over { + border-radius: 4px !important; +} + +.x-treelist-row::before { + border-radius: 4px !important; +} + +.x-treelist-item-wrap, +.x-treelist-item-text, +.x-treelist-row, +.x-treelist-container, +.x-treelist-root-container, +.x-treelist, +.x-treelist-pve-nav { + border-radius: 4px !important; +} + +/* Window message mask */ +.x-mask-msg { + border-radius: 8px !important; +} + +/* Tags */ +.pve-edit-tag { + border-radius: 6px !important; +} + +.x-tree-node-text .proxmox-tag-dark, +.x-tree-node-text .proxmox-tag-light, +.x-grid-cell-inner .proxmox-tag-dark, +.x-grid-cell-inner .proxmox-tag-light, +span.proxmox-tag-dark, +span.proxmox-tag-light { + border-radius: 6px !important; +} + +/* Usage bars */ +.usage-wrapper, +.usage { + border-radius: 2px !important; +} + +/* Progress bars */ +.x-progress, +.x-progress-default { + border-radius: 5px !important; +} + +.x-progress-bar, +.x-progress-bar-default, +.x-progress-default .x-progress-bar-default { + border-radius: 5px !important; +} + +/* Scrollbar thumb */ +::-webkit-scrollbar-thumb { + border-radius: 4px !important; +} + +/* Summary/stats panels */ +.pveStatusPanel, +.x-panel-default-framed, +.x-panel-body-default-framed { + border-radius: 12px !important; +} + +[id^="pveGuestStatusView-"][id$="-body"], +[id^="pmxNotesView-"] .x-panel-body { + border-radius: 8px !important; +} + +.x-panel-header-default-framed { + border-radius: 12px 12px 0 0 !important; +} + +.pve-info-grid { + border-radius: 12px !important; +} + +.x-form-display-field-default { + border-radius: 6px !important; +} + +.pve-rrdview, +.rrdview { + border-radius: 12px !important; +} + +.pve-summary-status, +.x-container .pve-status { + border-radius: 8px !important; +} + +.x-panel-default[id*="notes"], +.pve-notes-view { + border-radius: 8px !important; +} + +.x-fieldset { + border-radius: 8px !important; +} + +/* Tab hover/active corners */ +.x-tab-default.x-tab-over, +.x-tab-default.x-tab.x-tab-active { + border-radius: 6px 6px 0 0 !important; +} + +/* Segmented buttons */ +.x-segmented-button { + border-radius: 6px !important; +} + +.x-segmented-button .x-btn, +.x-segmented-button .x-btn-default-small, +.x-segmented-button .x-btn-inner, +.x-segmented-button .x-btn-wrap { + border-radius: 6px !important; +} + +/* Summary page widget panels */ +.x-panel.x-column>.x-panel-bodyWrap>.x-panel-body.x-panel-body-default { + border-radius: 8px !important; +} + +/* Floating grid pickers (storage/ISO selectors) */ +.x-layer.x-grid .x-grid-view, +.x-panel.x-layer.x-grid .x-grid-view { + border-radius: 4px !important; +} + +.x-panel.x-layer.x-grid, +.x-layer.x-panel.x-grid { + border-radius: 4px !important; +} + +.x-layer.x-grid .x-grid-item-over, +.x-layer.x-grid .x-grid-item-selected, +.x-panel.x-layer.x-grid .x-grid-item-over, +.x-panel.x-layer.x-grid .x-grid-item-selected { + border-radius: 4px !important; +} + +.x-layer.x-grid .x-grid-item-over td, +.x-layer.x-grid .x-grid-item-selected td, +.x-layer.x-grid .x-grid-item-over .x-grid-cell, +.x-layer.x-grid .x-grid-item-selected .x-grid-cell, +.x-panel.x-layer.x-grid .x-grid-item-over td, +.x-panel.x-layer.x-grid .x-grid-item-selected td, +.x-panel.x-layer.x-grid .x-grid-item-over .x-grid-cell, +.x-panel.x-layer.x-grid .x-grid-item-selected .x-grid-cell { + border-radius: 0 !important; +} + +.x-layer.x-grid .x-grid-item-over td:first-child, +.x-layer.x-grid .x-grid-item-selected td:first-child, +.x-panel.x-layer.x-grid .x-grid-item-over td:first-child, +.x-panel.x-layer.x-grid .x-grid-item-selected td:first-child { + border-radius: 4px 0 0 4px !important; +} + +.x-layer.x-grid .x-grid-item-over td:last-child, +.x-layer.x-grid .x-grid-item-selected td:last-child, +.x-panel.x-layer.x-grid .x-grid-item-over td:last-child, +.x-panel.x-layer.x-grid .x-grid-item-selected td:last-child { + border-radius: 0 4px 4px 0 !important; +} + +/* Charts - remove border-radius from data area only */ +canvas.x-surface-canvas, +.x-surface-canvas, +.x-draw-component canvas, +.proxmox-rrd-chart canvas { + border-radius: 0 !important; +} + +svg.x-surface { + border-radius: 0 !important; +} + +.x-draw-container, +.x-surface { + border-radius: 0 !important; +} +/* ===================================================== + TOOL ICONS - FontAwesome Replacements + (Ported from UniFi v5.86) + Replace sprite-based ExtJS tool icons with crisp + FontAwesome icons for better consistency and clarity + ===================================================== */ + +/* Base styling for all tool icons - remove sprite backgrounds */ +.x-tool-tool-el.x-tool-minus, +.x-tool-img.x-tool-minus, +.x-tool-tool-el.x-tool-collapse-right, +.x-tool-img.x-tool-collapse-right, +.x-tool-tool-el.x-tool-collapse-left, +.x-tool-img.x-tool-collapse-left, +.x-tool-tool-el.x-tool-expand-right, +.x-tool-img.x-tool-expand-right, +.x-tool-tool-el.x-tool-expand-left, +.x-tool-img.x-tool-expand-left, +.x-tool-tool-el.x-tool-maximize, +.x-tool-img.x-tool-maximize, +.x-tool-tool-el.x-tool-restore, +.x-tool-img.x-tool-restore, +.x-tool-tool-el.x-tool-gear, +.x-tool-img.x-tool-gear, +.x-tool-tool-el.x-tool-refresh, +.x-tool-img.x-tool-refresh, +.x-tool-tool-el.x-tool-close, +.x-tool-img.x-tool-close { + background-image: none !important; + font-family: "FontAwesome" !important; + font-size: 14px !important; + line-height: 16px !important; + text-align: center !important; + color: var(--pm-text-dim) !important; + transition: color 0.15s ease !important; + filter: none !important; + width: 16px !important; + height: 16px !important; + display: flex !important; + align-items: center !important; + justify-content: center !important; +} + +/* Close button - slightly larger */ +.x-tool-tool-el.x-tool-close, +.x-tool-img.x-tool-close { + font-size: 20px !important; +} + +/* Individual glyph assignments */ +.x-tool-tool-el.x-tool-minus::before, +.x-tool-img.x-tool-minus::before { + content: "\f010" !important; /* fa-search-minus (zoom out) */ +} + +.x-tool-tool-el.x-tool-collapse-right::before, +.x-tool-img.x-tool-collapse-right::before { + content: "\f054" !important; /* fa-chevron-right */ +} + +.x-tool-tool-el.x-tool-expand-left::before, +.x-tool-img.x-tool-expand-left::before { + content: "\f053" !important; /* fa-chevron-left */ +} + +.x-tool-tool-el.x-tool-collapse-left::before, +.x-tool-img.x-tool-collapse-left::before { + content: "\f053" !important; /* fa-chevron-left */ +} + +.x-tool-tool-el.x-tool-expand-right::before, +.x-tool-img.x-tool-expand-right::before { + content: "\f054" !important; /* fa-chevron-right */ +} + +.x-tool-tool-el.x-tool-maximize::before, +.x-tool-img.x-tool-maximize::before { + content: "\f065" !important; /* fa-expand */ +} + +.x-tool-tool-el.x-tool-restore::before, +.x-tool-img.x-tool-restore::before { + content: "\f066" !important; /* fa-compress */ +} + +.x-tool-tool-el.x-tool-gear::before, +.x-tool-img.x-tool-gear::before { + content: "\f013" !important; /* fa-cog */ +} + +.x-tool-tool-el.x-tool-refresh::before, +.x-tool-img.x-tool-refresh::before { + content: "\f021" !important; /* fa-refresh */ +} + +.x-tool-tool-el.x-tool-close::before, +.x-tool-img.x-tool-close::before { + content: "\f00d" !important; /* fa-times */ +} + +/* Hover state - all tool icons */ +.x-tool:hover .x-tool-tool-el.x-tool-minus, +.x-tool:hover .x-tool-img.x-tool-minus, +.x-tool:hover .x-tool-tool-el.x-tool-collapse-right, +.x-tool:hover .x-tool-img.x-tool-collapse-right, +.x-tool:hover .x-tool-tool-el.x-tool-collapse-left, +.x-tool:hover .x-tool-img.x-tool-collapse-left, +.x-tool:hover .x-tool-tool-el.x-tool-expand-right, +.x-tool:hover .x-tool-img.x-tool-expand-right, +.x-tool:hover .x-tool-tool-el.x-tool-expand-left, +.x-tool:hover .x-tool-img.x-tool-expand-left, +.x-tool:hover .x-tool-tool-el.x-tool-maximize, +.x-tool:hover .x-tool-img.x-tool-maximize, +.x-tool:hover .x-tool-tool-el.x-tool-restore, +.x-tool:hover .x-tool-img.x-tool-restore, +.x-tool:hover .x-tool-tool-el.x-tool-gear, +.x-tool:hover .x-tool-img.x-tool-gear, +.x-tool:hover .x-tool-tool-el.x-tool-refresh, +.x-tool:hover .x-tool-img.x-tool-refresh, +.x-tool:hover .x-tool-tool-el.x-tool-close, +.x-tool:hover .x-tool-img.x-tool-close { + color: var(--pm-text) !important; +} + +/* Disabled state */ +.x-tool-disabled .x-tool-tool-el, +.x-tool-disabled .x-tool-img { + opacity: 0.4 !important; + cursor: default !important; +} + +/* Inline FontAwesome tools (PVE-injected) */ +.x-tool-tool-el[style*="font-family:FontAwesome"], +.x-tool-tool-el[style*="font-family: FontAwesome"] { + color: var(--pm-text-dim) !important; + font-size: 14px !important; + line-height: 16px !important; + display: flex !important; + align-items: center !important; + justify-content: center !important; + width: 16px !important; + height: 16px !important; + transition: color 0.15s ease !important; + background-image: none !important; + background-color: transparent !important; +} + +.x-tool:not(.x-tool-disabled) .x-tool-tool-el[style*="font-family:FontAwesome"], +.x-tool:not(.x-tool-disabled) .x-tool-tool-el[style*="font-family: FontAwesome"] { + cursor: pointer !important; +} + +.x-tool.x-tool-disabled .x-tool-tool-el[style*="font-family:FontAwesome"], +.x-tool.x-tool-disabled .x-tool-tool-el[style*="font-family: FontAwesome"] { + cursor: default !important; + opacity: 0.4 !important; +} + +.x-tool .x-mask { + background-color: transparent !important; + backdrop-filter: none !important; + pointer-events: none !important; +} + +.x-tool:not(.x-tool-disabled):hover .x-tool-tool-el[style*="font-family:FontAwesome"], +.x-tool:not(.x-tool-disabled):hover .x-tool-tool-el[style*="font-family: FontAwesome"] { + color: var(--pm-text) !important; +} diff --git a/themes/theme-gruvbox-dark.css b/themes/theme-gruvbox-dark.css new file mode 100644 index 0000000..71d0eb3 --- /dev/null +++ b/themes/theme-gruvbox-dark.css @@ -0,0 +1,2340 @@ +/*!Gruvbox Dark*/ + +/* ===================================================== + CSS VARIABLES + ===================================================== */ +:root { + /* Theme: Gruvbox Dark */ + --pm-accent: #fabd2f; + --pm-bg-base: #282828; + --pm-bg-surface: #3c3836; + --pm-bg-elevated: #504945; + --pm-text: #ebdbb2; + --pm-text-dim: #d5c4a1; + --pm-success: #b8bb26; + --pm-warning: #fe8019; + --pm-error: #fb4934; + --pm-border: #504945; + --pm-radius-sm: 4px; + --pm-radius-md: 6px; + --pm-radius-lg: 8px; + + /* Proxmox Widget Toolkit Mappings */ + --pwt-panel-background: var(--pm-bg-base); + --pwt-text-color: var(--pm-text); + --pwt-gauge-default: var(--pm-accent); + --pwt-gauge-back: var(--pm-bg-elevated); + --pwt-gauge-warn: var(--pm-warning); + --pwt-gauge-crit: var(--pm-error); + --pwt-chart-primary: var(--pm-accent); + --pwt-chart-grid-stroke: var(--pm-bg-elevated); + + /* Gruvbox theme internal variables (based on Dracula template structure) */ + --grv-text: var(--pm-text); + --grv-subtext0: var(--pm-text-dim); + --grv-subtext1: var(--pm-text-dim); + --grv-overlay0: var(--pm-border); + --grv-overlay1: var(--pm-text-dim); + --grv-overlay2: var(--pm-text-dim); + --grv-surface0: var(--pm-bg-surface); + --grv-surface1: var(--pm-bg-elevated); + --grv-surface2: var(--pm-bg-elevated); + --grv-base: var(--pm-bg-base); + --grv-mantle: #1d2021; + --grv-crust: #1d2021; + + --grv-on-accent: #282828; + --grv-hover-overlay: rgba(128, 128, 128, 0.12); + --grv-select-overlay: rgba(128, 128, 128, 0.25); + --grv-accent-muted: rgba(128, 128, 128, 0.4); + --grv-accent-subtle: rgba(128, 128, 128, 0.15); + + --grv-cyan: var(--pm-accent); + --grv-green: var(--pm-success); + --grv-orange: var(--pm-warning); + --grv-pink: var(--pm-accent); + --grv-purple: var(--pm-accent); + --grv-red: var(--pm-error); + --grv-yellow: var(--pm-warning); + + color-scheme: dark; +} + +/* ===================================================== + GLOBAL BORDER-RADIUS ARCHITECTURE + (Ported from UniFi theme — reset everything, selectively re-apply) + ===================================================== */ +.x-border-box, +.x-border-box * { + border-radius: var(--pm-radius-lg); +} + +/* Remove rounded corners from grids/tables/lists */ +.x-grid, +.x-grid *, +.x-grid-header-ct, +.x-grid-header-ct *, +.x-grid-view, +.x-grid-view *, +.x-column-header, +.x-column-header *, +.x-grid-item, +.x-grid-cell, +.x-grid-cell-inner, +.x-grid-row, +table, +table *, +tr, +td, +th, +.x-legend, +.x-legend *, +.x-legend-container, +.x-legend-container *, +.x-legend-item, +.x-legend-horizontal .x-legend-item, +.x-legend-vertical .x-legend-item, +.x-legend-horizontal .x-legend-item:first-child, +.x-legend-horizontal .x-legend-item:last-child, +.x-legend-vertical .x-legend-item:first-child, +.x-legend-vertical .x-legend-item:last-child, +.x-tool, +.x-tool-tool-el, +.x-tool-default, +.x-tool-img { + border-radius: 0 !important; +} + +/* Form elements - exclude from global radius */ +.x-form-item, +.x-form-item-default, +.x-form-item-body, +.x-form-item-body-default, +.x-form-text-field-body, +.x-form-text-field-body-default, +.x-form-fieldcontainer, +.x-field, +.x-field-default, +.x-form-type-text { + border-radius: 0 !important; +} + +/* Reset layout containers that clip elements with overflow:hidden + radius */ +.x-box-layout-ct, +.x-panel-bodyWrap, +.x-panel-bodyWrap-default, +.x-autocontainer-innerCt, +.x-autocontainer-outerCt, +.x-panel.x-tabpanel-child, +.x-panel.x-box-item, +.x-box-inner, +.x-box-target, +.x-container, +.x-container-default, +.x-window .x-panel-body, +.x-window .x-window-body, +.x-window .x-window-bodyWrap { + border-radius: 0 !important; +} + +/* Reset everything inside windows to 0 — then re-apply specific radii */ +.x-window *, +.x-window .x-autocontainer-innerCt, +.x-window .x-autocontainer-outerCt, +.x-window .x-form-layout-wrap, +.x-window .x-form-layout-auto-label, +.x-window .x-form-layout-colgroup, +.x-window .x-form-layout-column, +.x-window .x-field, +.x-window .x-form-item, +.x-window .x-form-item-body { + border-radius: 0 !important; +} + +/* Chart canvas — no radius on data area */ +.x-chart-grid, +.x-chart-axis, +canvas.x-surface, +.x-chart canvas, +canvas.x-surface-canvas, +.x-surface-canvas, +.x-draw-component canvas, +.proxmox-rrd-chart canvas, +svg.x-surface, +.x-draw-container, +.x-surface { + border-radius: 0 !important; +} + +/* Legend color marker (dot) — keep circular */ +.x-legend-item-marker { + border-radius: 50% !important; +} + +/* ===================================================== + RE-APPLY BORDER RADII (selective) + ===================================================== */ + +/* Windows */ +.x-window, +.x-window-default { + border-radius: var(--pm-radius-lg) !important; +} + +.x-window-header, +.x-window-header-default { + border-radius: var(--pm-radius-lg) var(--pm-radius-lg) 0 0 !important; +} + +.x-window .x-window-body, +.x-window-body-default { + border-radius: 0 !important; +} + +/* Buttons inside windows */ +.x-window .x-btn { + border-radius: var(--pm-radius-md) !important; +} + +/* Checkboxes inside windows */ +.x-window .x-form-checkbox { + border-radius: 3px !important; +} + +/* Form inputs inside windows */ +.x-window .x-form-trigger-wrap, +.x-window .x-form-trigger-wrap-default { + border-radius: var(--pm-radius-sm) !important; +} + +.x-window .x-form-text-wrap, +.x-window .x-form-text { + border-radius: var(--pm-radius-sm) 0 0 var(--pm-radius-sm) !important; +} + +.x-window .x-form-arrow-trigger { + border-radius: 0 var(--pm-radius-sm) var(--pm-radius-sm) 0 !important; +} + +/* Form trigger/text wrap — reset and re-apply */ +.x-form-trigger-wrap, +.x-form-trigger-wrap *, +.x-form-text-wrap, +.x-form-text-wrap *, +.x-form-text, +.x-form-trigger { + border-radius: 0 !important; +} + +.x-form-trigger-wrap, +.x-form-trigger-wrap-default { + border-radius: var(--pm-radius-sm) !important; + overflow: hidden !important; +} + +.x-form-text-wrap, +.x-form-text-wrap-default { + border-radius: var(--pm-radius-sm) 0 0 var(--pm-radius-sm) !important; +} + +.x-form-text, +.x-form-text-default { + border-radius: var(--pm-radius-sm) 0 0 var(--pm-radius-sm) !important; +} + +.x-form-trigger, +.x-form-trigger-default, +.x-form-arrow-trigger, +.x-form-arrow-trigger-default { + border-radius: 0 var(--pm-radius-sm) var(--pm-radius-sm) 0 !important; +} + +/* Dialog form content padding — vertical only (horizontal causes ExtJS overflow) */ +.x-window .x-tabpanel-child .x-autocontainer-innerCt { + padding: 12px 0 !important; +} + +/* Allow column panel bodies to show overflowed form content */ +.x-window .x-panel-body:not(.x-scroller) { + overflow: visible !important; +} + +/* Side padding on column panel bodies inside windows */ +.x-window .x-panel.x-box-item .x-panel-body { + padding: 0 4px !important; +} + +/* Constrain autocontainer width inside windows */ +.x-window .x-autocontainer-outerCt { + max-width: 100% !important; +} + +/* Fix window header/body width consistency */ +.x-window > .x-window-header, +.x-window > .x-window-body, +.x-window > .x-window-bodyWrap, +.x-window-bodyWrap > .x-window-body { + width: 100% !important; +} + +.x-window-header > .x-box-inner, +.x-window-header > .x-box-inner > .x-box-target { + width: 100% !important; +} + +.x-window-header-title { + width: auto !important; + flex: 1 !important; + max-width: calc(100% - 30px) !important; +} + +/* Boundlists */ +.x-boundlist { + border-radius: var(--pm-radius-md) !important; + overflow: hidden !important; +} + +/* ===================================================== + BASE / BODY + ===================================================== */ +.x-body, +.x-viewport > .x-body, +body.x-border-layout-ct, +div.x-border-layout-ct { + background-color: var(--grv-base) !important; + color: var(--grv-text) !important; +} + +/* ===================================================== + MASKS & OVERLAYS + ===================================================== */ +.x-mask { + background-color: rgba(30, 31, 41, 0.6) !important; + backdrop-filter: blur(4px); +} + +.x-mask-msg { + background-color: var(--grv-mantle) !important; + border: 1px solid var(--grv-surface1) !important; + border-radius: var(--pm-radius-lg) !important; +} + +.x-mask-msg-text { + color: var(--grv-subtext0) !important; + filter: none !important; +} + +.x-css-shadow { + box-shadow: 0 8px 24px rgba(30, 31, 41, 0.6) !important; +} + +/* Loading indicators */ +.x-grid-row-loading, +.x-treelist-item-loading .x-treelist-item-icon, +.x-grid-tree-loading .x-tree-icon { + filter: invert(90%); +} + +/* ===================================================== + ICONS — Proxmox default colors for dark mode + ===================================================== */ + +/* General icon colors — neutral gray for dark backgrounds */ +.x-tree-icon-custom, +.x-grid-icon-custom, +.fa-tags::before, +.fa-file-o::before, +.fa-building::before, +.x-action-col-icon::before, +.fa-shield::before, +.fa-file-text-o::before, +.fa-clock-o::before, +.x-tab-icon-el-default, +.pve-icon-verify-lettering::after, +.x-tree-icon-leaf:not(.x-tree-icon-custom)::before, +.x-tree-icon-parent:not(.x-tree-icon-custom)::before, +.x-tree-icon-parent-expanded:not(.x-tree-icon-custom)::before, +.x-grid-filters-filtered-column .x-column-header-text::after { + color: var(--grv-overlay2) !important; +} + +/* Folder icons — invert for dark mode */ +.x-tree-icon-parent:not(.x-tree-icon-custom)::before, +.x-tree-icon-parent-expanded:not(.x-tree-icon-custom)::before { + filter: invert(90%); +} + +/* Various image-based icons — invert for visibility */ +.fa-ceph::before, +.fa-sdn::before, +.fa-network-wired::before, +.pve-itype-treelist-item-icon-cdrom, +.fa-chevron-right::before, +.x-grid-row-console, +.x-box-scroller-toolbar-default.x-box-scroller, +.x-tree-elbow-img, +.pve-itype-icon-qemu, +.x-tree-node-computer, +.x-grid-tree-node-expanded .x-tree-node-computer, +.pbs-icon-tape, +.pbs-icon-tape-drive, +.x-tree-icon-leaf:not(.x-tree-icon-custom), +.x-tree-icon-parent:not(.x-tree-icon-custom), +.x-tree-icon-parent-expanded:not(.x-tree-icon-custom) { + filter: invert(90%); +} + +/* Hardware icons */ +.pve-itype-icon-cpu, +.pve-itype-icon-cdrom, +.pve-itype-icon-memory, +.pve-itype-icon-pci, +.pve-itype-icon-serial, +.pve-itype-icon-die, +.pmx-itype-icon-processor, +.pmx-itype-icon-memory, +.pve-itype-icon-storage, +.x-tree-node-harddisk, +.x-grid-tree-node-expanded .x-tree-node-harddisk { + filter: invert(100%); +} + +/* Hardware icons — counter-invert for non-SVG icon cells */ +td.pve-itype-icon-storage .x-grid-cell-inner, +td.x-tree-node-harddisk .x-grid-cell-inner { + filter: invert(100%) !important; +} + +/* Hardware icons — hide inverted borders for non-SVG icon cells */ +td.pve-itype-icon-storage, +td.x-tree-node-harddisk { + border-color: transparent !important; +} + +/* Hardware grid icons — mask-image renders SVG icons in theme text color + Replaces filter:invert approach for pve-itype-icon-* and pmx-itype-icon-* grid cells */ +td.pve-itype-icon-cpu, +td.pve-itype-icon-cdrom, +td.pve-itype-icon-memory, +td.pve-itype-icon-pci, +td.pve-itype-icon-serial, +td.pve-itype-icon-die, +td.pmx-itype-icon-processor, +td.pmx-itype-icon-memory { + filter: none !important; + background-image: none !important; + padding-left: 0 !important; + border-color: transparent !important; +} + +td.pve-itype-icon-cpu .x-grid-cell-inner, +td.pve-itype-icon-cdrom .x-grid-cell-inner, +td.pve-itype-icon-memory .x-grid-cell-inner, +td.pve-itype-icon-pci .x-grid-cell-inner, +td.pve-itype-icon-serial .x-grid-cell-inner, +td.pve-itype-icon-die .x-grid-cell-inner, +td.pmx-itype-icon-processor .x-grid-cell-inner, +td.pmx-itype-icon-memory .x-grid-cell-inner { + padding-left: 3px !important; +} + +td.pve-itype-icon-cpu .x-grid-cell-inner::before, +td.pve-itype-icon-cdrom .x-grid-cell-inner::before, +td.pve-itype-icon-memory .x-grid-cell-inner::before, +td.pve-itype-icon-pci .x-grid-cell-inner::before, +td.pve-itype-icon-serial .x-grid-cell-inner::before, +td.pve-itype-icon-die .x-grid-cell-inner::before, +td.pmx-itype-icon-processor .x-grid-cell-inner::before, +td.pmx-itype-icon-memory .x-grid-cell-inner::before { + content: '' !important; + display: inline-block !important; + width: 18px !important; + height: 14px !important; + vertical-align: middle !important; + margin-right: 10px !important; + background-color: currentColor !important; + -webkit-mask-size: contain !important; + mask-size: contain !important; + -webkit-mask-repeat: no-repeat !important; + mask-repeat: no-repeat !important; + -webkit-mask-position: center !important; + mask-position: center !important; +} + +td.pve-itype-icon-cpu .x-grid-cell-inner::before { + -webkit-mask-image: url('/pve2/images/icon-cpu.svg') !important; + mask-image: url('/pve2/images/icon-cpu.svg') !important; +} + +td.pve-itype-icon-memory .x-grid-cell-inner::before { + -webkit-mask-image: url('/pve2/images/icon-memory.svg') !important; + mask-image: url('/pve2/images/icon-memory.svg') !important; +} + +td.pve-itype-icon-cdrom .x-grid-cell-inner::before { + -webkit-mask-image: url('/pve2/images/icon-cd-drive.svg') !important; + mask-image: url('/pve2/images/icon-cd-drive.svg') !important; +} + +td.pve-itype-icon-pci .x-grid-cell-inner::before { + -webkit-mask-image: url('/pve2/images/icon-pci.svg') !important; + mask-image: url('/pve2/images/icon-pci.svg') !important; +} + +td.pve-itype-icon-serial .x-grid-cell-inner::before { + -webkit-mask-image: url('/pve2/images/icon-serial.svg') !important; + mask-image: url('/pve2/images/icon-serial.svg') !important; +} + +td.pve-itype-icon-die .x-grid-cell-inner::before { + -webkit-mask-image: url('/pve2/images/icon-die.svg') !important; + mask-image: url('/pve2/images/icon-die.svg') !important; +} + +td.pmx-itype-icon-processor .x-grid-cell-inner::before { + -webkit-mask-image: url('../images/icon-cpu.svg') !important; + mask-image: url('../images/icon-cpu.svg') !important; +} + +td.pmx-itype-icon-memory .x-grid-cell-inner::before { + -webkit-mask-image: url('../images/icon-ram.svg') !important; + mask-image: url('../images/icon-ram.svg') !important; +} + + +/* Icon overlays — default */ +.x-tree-icon-custom::after, +.x-grid-icon-custom::after { + color: var(--grv-overlay2) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* RUNNING VMs/CTs — Dracula Green */ +.x-tree-icon-custom.running::after, +.x-grid-icon-custom.running::after, +.x-treelist-item-icon.running::after { + color: var(--grv-green) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* ONLINE state — Green */ +.x-tree-icon-custom.online::after, +.x-grid-icon-custom.online::after { + color: var(--grv-green) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* Stopped/offline — Overlay1 (muted gray) */ +.x-tree-icon-custom.stopped, +.x-tree-icon-custom.offline, +.x-grid-icon-custom.stopped, +.x-grid-icon-custom.offline { + color: var(--grv-overlay1) !important; +} + +/* Unknown state — Overlay1 */ +.x-tree-icon-custom.unknown::after, +.x-grid-icon-custom.unknown::after { + color: var(--grv-overlay1) !important; +} + +/* ERROR states — Dracula Red */ +.x-tree-icon-custom.error::after, +.x-tree-icon-custom.offline::after, +.x-tree-icon-custom.ha-error::after, +.x-grid-icon-custom.error::after, +.x-grid-icon-custom.offline::after, +.x-grid-icon-custom.ha-error::after { + color: var(--grv-red) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* PAUSED/SUSPENDED — Dracula Orange */ +.x-tree-icon-custom.paused::after, +.x-tree-icon-custom.suspended::after, +.x-tree-icon-custom.lock-suspending::after, +.x-grid-icon-custom.paused::after, +.x-grid-icon-custom.suspended::after, +.x-grid-icon-custom.lock-suspending::after { + color: var(--grv-orange) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* PENDING/WARNING states — Dracula Yellow */ +.x-tree-icon-custom.pending::after, +.x-tree-icon-custom.io-error::after, +.x-tree-icon-custom.internal-error::after, +.x-tree-icon-custom.guest-panicked::after, +.x-grid-icon-custom.pending::after, +.x-grid-icon-custom.io-error::after, +.x-grid-icon-custom.internal-error::after, +.x-grid-icon-custom.guest-panicked::after { + color: var(--grv-yellow) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* HA MAINTENANCE — Dracula Cyan */ +.x-tree-icon-custom.ha-maintenance::after, +.x-grid-icon-custom.ha-maintenance::after { + color: var(--grv-cyan) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* Locked icons */ +.x-tree-icon-custom.locked::after, +.x-tree-icon-custom.lock-backup::after, +.x-tree-icon-custom.lock-migrate::after, +.x-tree-icon-custom.lock-suspended::after, +.x-grid-icon-custom.locked::after, +.x-grid-icon-custom.lock-backup::after, +.x-grid-icon-custom.lock-migrate::after, +.x-grid-icon-custom.lock-suspended::after { + color: var(--grv-overlay2) !important; +} + +/* LXC/QEMU type indicators */ +.x-tree-icon-custom.lxc::after, +.x-tree-icon-custom.qemu::after, +.x-grid-icon-custom.lxc::after, +.x-grid-icon-custom.qemu::after { + background-color: transparent; + color: var(--grv-overlay1) !important; +} + +.x-treelist-item-icon.lxc::after, +.x-treelist-item-icon.qemu::after { + background-color: transparent; + color: var(--grv-overlay1) !important; +} + +/* Tree expander arrows */ +.x-tree-arrows .x-tree-expander { + filter: brightness(200%); +} + +/* Cancel sprite-inversion on custom controls (checkboxes/radios handled via CSS) */ +.x-form-checkbox-default, +.x-form-radio-default, +.x-column-header-checkbox .x-column-header-checkbox::after, +.x-grid-checkcolumn::after, +.x-menu-item-checked .x-menu-item-icon-default.x-menu-item-checkbox, +.x-menu-item-unchecked .x-menu-item-icon-default.x-menu-item-checkbox { + filter: none !important; +} + +/* ===================================================== + PANELS & HEADERS + ===================================================== */ +.x-panel, +.x-panel-default { + border-radius: var(--pm-radius-lg) !important; + padding: 0 !important; +} + +/* Column panels — native stacked layout (Issue #23 fix) */ +.x-panel.x-column { + padding: 5px !important; + margin: 0 !important; + max-width: none !important; + box-sizing: border-box !important; +} + +/* Column panel card styling — borders for summary + chart panels */ +.x-panel.x-panel-default.x-column { + border: 1px solid var(--grv-surface1) !important; + border-radius: var(--pm-radius-lg) !important; + overflow: hidden !important; +} + +/* Guest status + Notes panel borders */ +[id^="pveGuestStatusView-"].x-panel, +[id^="pveLxcStatusView-"].x-panel, +[id^="pveQemuStatusView-"].x-panel, +[id^="pmxNotesView-"].x-panel { + border: 1px solid var(--grv-surface1) !important; + border-radius: var(--pm-radius-lg) !important; +} + +.x-panel-body, +.x-panel-body-default { + background-color: var(--grv-base) !important; + color: var(--grv-text) !important; + border: none !important; +} + +/* Panel headers — bottom border only */ +.x-panel-header, +.x-panel-header-default { + background-color: var(--grv-mantle) !important; + border: none !important; + border-bottom: 1px solid var(--grv-surface1) !important; + border-radius: var(--pm-radius-lg) var(--pm-radius-lg) 0 0 !important; + margin: 0 !important; + padding: 8px 12px !important; + width: 100% !important; + box-sizing: border-box !important; + overflow: visible !important; +} + +/* Title text — prevent border-radius clipping */ +.x-title-text, +.x-title-text-default { + overflow: visible !important; +} + +.x-panel-bodyWrap, +.x-panel-bodyWrap-default { + margin: 0 !important; + padding: 0 !important; + overflow: visible !important; +} + +/* Remove borders from nested panels */ +.x-panel-body > .x-box-layout-ct, +.x-panel-body > .x-container, +.x-panel-body > .x-box-inner, +[id*="pmxGauge"] { + border: none !important; +} + +.x-panel-header-title-default, +.x-window-header-title-default { + color: var(--grv-text) !important; +} + +.x-panel-header-default .x-tool-tool-el { + background-color: transparent; +} + +.x-tool-img { + filter: brightness(175%); +} + +.x-tool-over .x-tool-img { + filter: brightness(200%); +} + +/* Resource tree — panel body border */ +div[id^="pveResourceTree-"][id$="-body"] { + border-color: var(--grv-base) !important; +} + +/* Resource tree — remove row separators */ +[id^="pveResourceTree-"].x-tree-panel td.x-grid-cell, +[id^="pveResourceTree-"].x-tree-panel .x-grid-td, +[id^="pveResourceTree-"].x-tree-panel .x-grid-cell { + border-bottom: none !important; +} + +/* Resource tree — row spacing */ +div[id^="pveResourceTree"] .x-grid-cell { + padding-top: 3px !important; + padding-bottom: 3px !important; +} + +/* Summary/stats panel radius overrides */ +.pveStatusPanel, +.x-panel-default-framed, +.x-panel-body-default-framed { + border-radius: 12px !important; +} + +.x-panel-header-default-framed { + border-radius: 12px 12px 0 0 !important; +} + +/* Column widget panel radius */ +.x-panel.x-column > .x-panel-bodyWrap > .x-panel-body.x-panel-body-default { + border-radius: var(--pm-radius-lg) !important; +} + +/* ===================================================== + SPLITTERS / SEPARATORS + ===================================================== */ +.x-splitter-vertical { + background-color: transparent !important; + border-left: 1px solid var(--grv-surface1) !important; + border-right: none !important; + width: 1px !important; +} + +.x-splitter-horizontal { + background-color: var(--grv-crust) !important; + border-top: 1px solid var(--grv-surface1) !important; +} + +.x-splitter { + background-color: var(--grv-crust) !important; +} + +.x-keyboard-mode .x-splitter-focus::after { + border-color: var(--grv-purple) !important; +} + +.x-layout-split-bottom { + opacity: 0.7; +} + +/* Toolbox tree (pve-nav) right border — full height */ +.pve-toolbar-bg { + border-right: 1px solid var(--grv-surface1) !important; + z-index: 3 !important; +} + +.x-treelist.x-treelist-pve-nav { + border-right: none !important; +} + +/* ===================================================== + TOOLBARS + ===================================================== */ +.x-toolbar, +.x-toolbar-default { + background-color: var(--grv-base) !important; + border-color: var(--grv-surface1) !important; +} + +.x-toolbar-default.x-docked-top { + border: none !important; + border-bottom: 1px solid var(--grv-surface1) !important; +} + +.x-toolbar-default .x-toolbar-separator { + border-color: var(--grv-surface1); +} + +.x-toolbar-text-default { + color: var(--grv-subtext0); +} + +/* ===================================================== + PRIMARY BUTTONS — Dracula Purple + ===================================================== */ +.x-btn-default-small { + background-color: var(--grv-purple) !important; + border: 1px solid rgba(189, 147, 249, 0.4) !important; + border-radius: var(--pm-radius-md) !important; + transition: background-color 0.15s ease, box-shadow 0.15s ease !important; +} + +.x-btn-default-small .x-btn-inner { + color: var(--grv-on-accent) !important; + font-weight: 600 !important; +} + +.x-btn-default-small .x-btn-icon-el { + color: var(--grv-on-accent) !important; +} + +.x-btn-default-small.x-btn-over, +.x-keyboard-mode .x-btn-default-small.x-btn-focus { + background-color: #caa9fa !important; + box-shadow: 0 0 0 3px var(--grv-accent-subtle) !important; +} + +.x-btn-default-small.x-btn.x-btn-disabled { + background-color: var(--grv-purple) !important; + opacity: 0.4; +} + +.x-btn-default-small.x-btn.x-btn-pressed { + background-color: #a986f0 !important; +} + +/* Button height consistency — 28px with vertical centering */ +/* Exclude tag edit buttons (display:none when hidden, :has(.fa-check) for checkmark) */ +.x-btn.x-btn-default-small:not(.x-btn-default-toolbar-small):not([style*="display: none"]):not([style*="display:none"]):not(:has(.fa-check)) { + height: 28px !important; + min-height: 28px !important; + display: flex !important; + align-items: center !important; + padding: 3px 8px !important; +} + +/* Fix button inner element centering for proper icon alignment (issue #17) */ +.x-btn.x-btn-default-small:not(.x-btn-default-toolbar-small):not([style*="display: none"]):not([style*="display:none"]):not(:has(.fa-check)) .x-btn-wrap { + display: flex !important; + align-items: center !important; +} + +.x-btn.x-btn-default-small:not(.x-btn-default-toolbar-small):not([style*="display: none"]):not([style*="display:none"]):not(:has(.fa-check)) .x-btn-inner { + display: flex !important; + align-items: center !important; +} + +/* Fix dropdown arrows on split/arrow buttons */ +.x-btn-wrap.x-btn-arrow-right::after, +.x-btn-wrap.x-btn-split-right::after { + height: 16px !important; + min-height: 16px !important; + width: 20px !important; + display: flex !important; + align-items: center !important; +} + +/* Fix icon-only buttons — hide   inner element when button has no text */ +.x-btn-no-text .x-btn-inner, +.x-btn-button.x-btn-no-text .x-btn-inner, +.x-btn-button-default-toolbar-small.x-btn-no-text .x-btn-inner-default-toolbar-small, +.x-btn-button-default-small.x-btn-no-text .x-btn-inner-default-small, +.x-btn-button-default-small.x-btn-no-text > .x-btn-inner-default-small { + display: none !important; +} + +/* Specific fix for fa-desktop icon (Create VM) — visually bottom-heavy */ +.x-btn-icon-el.fa-desktop { + transform: translateY(1.1px) !important; +} + +/* ===================================================== + SECONDARY / TOOLBAR BUTTONS + ===================================================== */ +.x-btn-default-toolbar-small { + background-color: var(--grv-surface0) !important; + border: 1px solid var(--grv-surface1) !important; + border-radius: var(--pm-radius-md) !important; + transition: background-color 0.15s ease, border-color 0.15s ease !important; +} + +.x-btn-default-toolbar-small .x-btn-inner-default-toolbar-small, +.x-btn-default-toolbar-small .x-btn-icon-el-default-toolbar-small { + color: var(--grv-text) !important; +} + +.x-btn-default-toolbar-small .x-btn-wrap-default-toolbar-small.x-btn-arrow-right::after, +.x-btn-default-toolbar-small .x-btn-wrap-default-toolbar-small.x-btn-split-right::after { + filter: brightness(150%); +} + +.x-btn-default-toolbar-small.x-btn-over, +.x-keyboard-mode .x-btn-default-toolbar-small.x-btn-focus { + background-color: var(--grv-surface1) !important; + border-color: var(--grv-surface2) !important; +} + +.x-btn-default-toolbar-small.x-btn.x-btn-disabled { + background-color: var(--grv-surface0) !important; + opacity: 0.4; +} + +.x-btn-default-toolbar-small.x-btn.x-btn-menu-active, +.x-btn-default-toolbar-small.x-btn.x-btn-pressed { + background-color: var(--grv-purple) !important; + border-color: var(--grv-purple) !important; + padding: 4px 8px !important; /* Fix #30: prevent width change on dropdown */ +} + +.x-btn-default-toolbar-small.x-btn.x-btn-pressed .x-btn-inner-default-toolbar-small, +.x-btn-default-toolbar-small.x-btn.x-btn-pressed .x-btn-icon-el-default-toolbar-small, +.x-btn-default-toolbar-small.x-btn.x-btn-pressed .x-btn-inner-default-small, +.x-btn-default-toolbar-small.x-btn.x-btn-pressed .x-btn-icon-el-default-small { + color: var(--grv-on-accent) !important; +} + +/* Segmented buttons */ +.x-segmented-button { + border-radius: var(--pm-radius-md) !important; +} + +.x-segmented-button .x-btn, +.x-segmented-button .x-btn-default-small, +.x-segmented-button .x-btn-inner, +.x-segmented-button .x-btn-wrap { + border-radius: var(--pm-radius-md) !important; +} + +/* Inline buttons (Documentation, Help) */ +.proxmox-inline-button { + height: 28px !important; + min-height: 28px !important; + display: flex !important; + align-items: center !important; + padding: 3px 8px !important; + background-color: var(--grv-surface0) !important; + border: 1px solid var(--grv-surface1) !important; + border-radius: var(--pm-radius-md) !important; + color: var(--grv-text) !important; + transition: background-color 0.15s ease !important; +} + +.proxmox-inline-button:hover, +.proxmox-inline-button.x-btn-over { + background-color: var(--grv-surface1) !important; + border-color: var(--grv-overlay0) !important; +} + +.proxmox-inline-button:active, +.proxmox-inline-button.x-btn-pressed { + background-color: var(--grv-surface2) !important; +} + +.proxmox-inline-button .x-btn-inner, +.proxmox-inline-button .x-btn-icon-el { + color: var(--grv-text) !important; +} + +/* Pressed/active inline buttons — use on-accent text */ +.proxmox-inline-button.x-btn-pressed .x-btn-inner, +.proxmox-inline-button.x-btn-pressed .x-btn-icon-el, +.proxmox-inline-button.x-btn-menu-active .x-btn-inner, +.proxmox-inline-button.x-btn-menu-active .x-btn-icon-el { + color: var(--grv-on-accent) !important; +} + +/* ===================================================== + FORM ELEMENTS + ===================================================== */ +.x-form-trigger-default { + background-color: var(--grv-surface0) !important; +} + +.x-form-text-default { + background-color: var(--grv-surface0) !important; + color: var(--grv-text) !important; + border-radius: var(--pm-radius-sm) !important; +} + +.x-form-trigger-wrap, +.x-form-trigger-wrap-default { + border-color: var(--grv-surface1) !important; + background-color: var(--grv-surface0) !important; + border-radius: var(--pm-radius-sm) !important; + transition: border-color 0.15s ease !important; +} + +.x-form-trigger-wrap-default.x-form-trigger-wrap-focus { + border-color: var(--grv-purple) !important; + box-shadow: 0 0 0 3px var(--grv-accent-subtle) !important; +} + +.x-form-item-label-default, +.x-form-cb-label-default { + color: var(--grv-text) !important; +} + +.x-form-display-field-default { + color: var(--grv-subtext0) !important; + border-radius: var(--pm-radius-md) !important; +} + +.x-form-spinner-default { + background-color: var(--grv-surface0) !important; +} + +.x-fieldset, +.x-fieldset-default { + border-color: var(--grv-surface1) !important; + border-radius: var(--pm-radius-lg) !important; +} + +.x-fieldset-header-default > .x-fieldset-header-text { + color: var(--grv-text) !important; +} + +/* ===================================================== + CHECKBOXES & RADIOS — Dracula styled + ===================================================== */ + +/* Base: remove sprite, styled as custom control */ +.x-form-checkbox, .x-form-checkbox-default, +.x-form-radio, .x-form-radio-default { + background-image: none !important; + background-color: var(--grv-surface0) !important; + border: 1.5px solid var(--grv-overlay0) !important; + width: 16px !important; + height: 16px !important; + display: inline-block !important; + box-sizing: border-box !important; + cursor: pointer !important; + transition: border-color 0.12s ease, background-color 0.12s ease !important; +} + +/* Checkbox: rounded square */ +.x-form-checkbox, .x-form-checkbox-default { + border-radius: 3px !important; +} + +/* Radio: circle + ::after inner dot */ +.x-form-radio, .x-form-radio-default { + border-radius: 50% !important; + position: relative !important; + transform: translateZ(0) !important; + box-shadow: inset 0 0 0 0 transparent !important; +} + +.x-form-radio::after { + content: '' !important; + position: absolute !important; + top: 50% !important; + left: 50% !important; + width: 7px !important; + height: 7px !important; + border-radius: 50% !important; + background: transparent !important; + transform: translate(-50%, -50%) scale(0) !important; + transition: transform 0.15s ease, background 0.15s ease !important; + pointer-events: none !important; +} + +/* Hover */ +.x-form-checkbox:hover, .x-form-checkbox-default:hover, +.x-form-cb-wrap:hover .x-form-checkbox { + border-color: var(--grv-purple) !important; +} + +.x-form-radio:hover, .x-form-radio-default:hover, +.x-form-cb-wrap:hover .x-form-radio { + border-color: var(--grv-purple) !important; +} + +/* CHECKED checkbox — Purple fill + dark SVG checkmark */ +.x-form-cb-checked .x-form-checkbox, +.x-form-cb-checked .x-form-checkbox-default { + background-color: var(--grv-purple) !important; + border-color: var(--grv-purple) !important; + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 8'%3E%3Cpath d='M1 4l3 3 5-6' fill='none' stroke='%23282828' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") !important; + background-repeat: no-repeat !important; + background-position: center !important; + background-size: 9px 7px !important; +} + +/* SELECTED radio — Purple dot */ +.x-form-cb-checked .x-form-radio, +.x-form-cb-checked .x-form-radio-default { + border-color: var(--grv-purple) !important; + background-color: var(--grv-base) !important; +} + +.x-form-cb-checked .x-form-radio::after { + background: var(--grv-purple) !important; + transform: translate(-50%, -50%) scale(1) !important; +} + +/* ===================================================== + BOUNDLIST / DROPDOWNS + ===================================================== */ +.x-boundlist { + background-color: var(--grv-mantle) !important; + border: 1px solid var(--grv-surface1) !important; + border-radius: var(--pm-radius-md) !important; + box-shadow: 0 8px 24px rgba(30, 31, 41, 0.7) !important; + padding: 2px !important; + overflow: hidden !important; +} + +.x-boundlist-item { + background-color: transparent !important; + color: var(--grv-text) !important; + border-radius: var(--pm-radius-sm) !important; + padding: 2px 6px !important; + line-height: normal !important; + border: none !important; + cursor: pointer !important; + outline: none !important; + box-shadow: none !important; +} + +.x-boundlist-selected { + background-color: var(--grv-select-overlay) !important; + color: var(--grv-text) !important; +} + +.x-boundlist-item-over { + background-color: var(--grv-hover-overlay) !important; +} + +/* ===================================================== + GRIDS / TABLES + ===================================================== */ +.x-grid, +.x-grid-view { + border-radius: 0 !important; +} + +.x-column-header { + border-color: var(--grv-surface1) !important; + background-color: transparent !important; +} + +.x-column-header-inner, +.x-column-header-text { + color: var(--grv-text) !important; + font-weight: 600 !important; +} + +.x-column-header-trigger { + border-color: var(--grv-surface1) !important; +} + +.x-grid-item, +.x-column-header-default, +.x-grid-cell-row-numberer { + color: var(--grv-text) !important; + background-color: var(--grv-base) !important; +} + +.x-grid-cell-special { + border-color: var(--grv-surface1) !important; +} + +.x-grid-group-hd { + background-color: var(--grv-base) !important; + border-color: var(--grv-surface1) !important; +} + +.x-grid-group-title { + color: var(--grv-text) !important; +} + +.x-grid-header-ct { + background-color: var(--grv-mantle) !important; + border: 1px solid var(--grv-surface0) !important; + border-radius: var(--pm-radius-lg) var(--pm-radius-lg) 0 0 !important; +} + +.x-grid-item-alt { + background-color: var(--grv-crust) !important; +} + +.x-grid-with-row-lines .x-grid-item { + border-color: var(--grv-surface0) !important; +} + +.x-grid-cell { + border-bottom: 1px solid rgba(68, 71, 90, 0.4) !important; +} + +.x-grid-item-over, +.x-grid-with-row-lines .x-grid-item.x-grid-item-over { + background-color: var(--grv-hover-overlay) !important; +} + +.x-grid-item-selected, +.x-grid-with-row-lines .x-grid-item.x-grid-item-selected { + background-color: var(--grv-select-overlay) !important; +} + +.x-column-header-over, +.x-column-header-open { + background-color: var(--grv-hover-overlay) !important; +} + +.x-column-header-sort-ASC, +.x-column-header-sort-DESC { + background-color: var(--grv-hover-overlay) !important; +} + +.x-grid-row-summary .x-grid-cell, +.x-grid-row-summary .x-grid-rowwrap, +.x-grid-row-summary .x-grid-cell-rowbody { + background-color: var(--grv-base) !important; + border-color: var(--grv-surface1); +} + +.x-grid-with-col-lines .x-grid-cell, +.x-grid-with-col-lines .x-grid-item-over .x-grid-cell, +.x-grid-with-col-lines .x-grid-item-selected .x-grid-cell { + border-color: var(--grv-surface1) !important; +} + +.x-dd-drag-proxy { + background-color: var(--grv-mantle); + border-color: var(--grv-surface1); + color: var(--grv-text); +} + +.x-keyboard-mode .x-grid-item-focused { + background-color: var(--grv-hover-overlay) !important; + color: var(--grv-text) !important; +} + +/* Remove blue outline from focused/selected items in resource tree */ +.x-keyboard-mode .x-grid-item-focused .x-grid-cell-inner::before, +.x-keyboard-mode .x-grid-item-selected .x-grid-cell-inner::before, +.x-grid-item-selected .x-grid-cell-inner::before, +.x-grid-item-focused .x-grid-cell-inner::before, +[id^="pveResourceTree"] .x-grid-item-selected .x-grid-cell-inner::before, +[id^="pveResourceTree"] .x-grid-item-focused .x-grid-cell-inner::before { + content: none !important; + display: none !important; + border: none !important; +} + +.x-grid-empty { + background-color: var(--grv-base) !important; + color: var(--grv-subtext0) !important; +} + +/* Grid info (pve-info-grid) and RRD view */ +.pve-info-grid { + border-radius: 12px !important; +} + +.pve-rrdview, +.rrdview { + border-radius: 12px !important; +} + +.pve-summary-status, +.x-container .pve-status { + border-radius: var(--pm-radius-lg) !important; +} + +[id^="pveGuestStatusView-"][id$="-body"], +[id^="pmxNotesView-"] .x-panel-body { + border-radius: var(--pm-radius-lg) !important; +} + +.x-panel-default[id*="notes"], +.pve-notes-view { + border-radius: var(--pm-radius-lg) !important; +} + +/* Floating grid pickers (storage/ISO selectors) */ +.x-layer.x-grid .x-grid-view, +.x-panel.x-layer.x-grid .x-grid-view, +.x-panel.x-layer.x-grid, +.x-layer.x-panel.x-grid { + border-radius: var(--pm-radius-sm) !important; +} + +.x-layer.x-grid .x-grid-item-over, +.x-layer.x-grid .x-grid-item-selected, +.x-panel.x-layer.x-grid .x-grid-item-over, +.x-panel.x-layer.x-grid .x-grid-item-selected { + border-radius: var(--pm-radius-sm) !important; + outline: none !important; + box-shadow: none !important; +} + +.x-layer.x-grid .x-grid-item-over td, +.x-layer.x-grid .x-grid-item-selected td, +.x-layer.x-grid .x-grid-item-over .x-grid-cell, +.x-layer.x-grid .x-grid-item-selected .x-grid-cell, +.x-panel.x-layer.x-grid .x-grid-item-over td, +.x-panel.x-layer.x-grid .x-grid-item-selected td, +.x-panel.x-layer.x-grid .x-grid-item-over .x-grid-cell, +.x-panel.x-layer.x-grid .x-grid-item-selected .x-grid-cell { + border-radius: 0 !important; +} + +.x-layer.x-grid .x-grid-item-over td:first-child, +.x-layer.x-grid .x-grid-item-selected td:first-child, +.x-panel.x-layer.x-grid .x-grid-item-over td:first-child, +.x-panel.x-layer.x-grid .x-grid-item-selected td:first-child { + border-radius: var(--pm-radius-sm) 0 0 var(--pm-radius-sm) !important; +} + +.x-layer.x-grid .x-grid-item-over td:last-child, +.x-layer.x-grid .x-grid-item-selected td:last-child, +.x-panel.x-layer.x-grid .x-grid-item-over td:last-child, +.x-panel.x-layer.x-grid .x-grid-item-selected td:last-child { + border-radius: 0 var(--pm-radius-sm) var(--pm-radius-sm) 0 !important; +} + +/* ===================================================== + MENUS + ===================================================== */ +.x-menu, +.x-menu-default { + background-color: var(--grv-crust) !important; + border: 1px solid var(--grv-surface0) !important; + border-radius: var(--pm-radius-lg) !important; + box-shadow: 0 8px 24px rgba(30, 31, 41, 0.8) !important; + padding: 4px !important; + overflow: hidden !important; +} + +.x-menu-body-default { + background-color: transparent !important; + padding: 4px !important; +} + +.x-menu-header { + background-color: transparent !important; + color: var(--grv-text) !important; +} + +/* Menu icon separator — hide */ +.x-menu-icon-separator-default { + display: none !important; +} + +/* Menu item layout (flexbox reordering) */ +.x-menu-item-default > .x-menu-item-link { + display: flex !important; + align-items: center !important; + flex-direction: row !important; + gap: 4px !important; + justify-content: flex-start !important; + flex-wrap: nowrap !important; + border-radius: var(--pm-radius-md) !important; + padding: 4px 8px !important; + line-height: 20px !important; + border: none !important; + cursor: pointer !important; + outline: none !important; + box-shadow: none !important; + white-space: nowrap !important; + text-decoration: none !important; +} + +.x-menu-item-text-default { + color: var(--grv-text) !important; + font-size: 13px !important; + order: 1 !important; + margin-left: 0 !important; + text-align: left !important; + line-height: 20px !important; + display: inline-flex !important; + align-items: center !important; + flex: 1 1 auto !important; + width: auto !important; + white-space: nowrap !important; +} + +.x-menu-item-icon-default { + color: var(--grv-subtext0) !important; + order: -1 !important; + position: relative !important; + float: none !important; + margin-right: 8px !important; + margin-left: 0 !important; + left: auto !important; + top: auto !important; + width: 16px !important; + text-align: center !important; + display: inline-flex !important; + align-items: center !important; + justify-content: center !important; + height: 20px !important; + line-height: 20px !important; + vertical-align: middle !important; + flex: 0 0 16px !important; + align-self: center !important; +} + +.x-menu-item-arrow, +.x-menu-item-arrow-default { + order: 2 !important; + margin-left: auto !important; +} + +.x-menu-item-default.x-menu-item-separator { + background-color: var(--grv-surface0) !important; + border: none !important; + height: 1px !important; + margin: 6px 4px !important; +} + +.x-menu-item-default.x-menu-item-focus, +.x-menu-item-default.x-menu-item-active, +.x-menu-item:hover { + background-color: var(--grv-surface0) !important; + color: var(--grv-text) !important; + border-radius: var(--pm-radius-md) !important; +} + +.x-menu-item-active .x-menu-item-text-default, +.x-menu-item-focus .x-menu-item-text-default { + color: var(--grv-text) !important; +} + +.x-menu-item-active .x-menu-item-icon-default, +.x-menu-item-focus .x-menu-item-icon-default { + color: var(--grv-cyan) !important; +} + +/* ===================================================== + PROGRESS BARS + ===================================================== */ + +/* Fix: Widget containers need overflow visible to not clip progress bars */ +.x-container[id^="pmxInfoWidget"], +.x-container.x-box-layout-ct { + overflow: visible !important; +} + +.x-progress, +.x-progress-default { + background-color: var(--grv-surface0) !important; + border-radius: 5px !important; +} + +.x-progress-default .x-progress-bar-default { + background-color: var(--grv-purple) !important; + border-radius: 5px !important; + transition: width 0.4s ease !important; +} + +.x-progress-default .x-progress-text { + color: var(--grv-text) !important; +} + +/* Text overlaid on the progress bar fill — use on-accent for contrast */ +.x-progress-bar .x-progress-text { + color: var(--grv-on-accent) !important; +} + +.x-progress.warning .x-progress-bar { + background-color: var(--grv-yellow) !important; +} + +.x-progress.critical .x-progress-bar { + background-color: var(--grv-red) !important; +} + +/* ===================================================== + TABS — Dracula underline style + Flat tabs with Purple underline on active tab + ===================================================== */ +.x-tab-bar, +.x-tab-bar-default { + background-color: var(--grv-base) !important; + border-radius: 0 !important; + border-bottom: 1px solid var(--grv-surface1) !important; + padding-bottom: 0 !important; +} + +/* Overflow visible for the underline indicator */ +.x-tab-bar .x-box-inner, +.x-tab-bar .x-box-target, +.x-tab-bar-body, +.x-tab-bar-body-default { + overflow: visible !important; +} + +/* Base tab */ +.x-tab, +.x-tab-default, +.x-tab-default-top { + background-color: transparent !important; + border: none !important; + border-radius: var(--pm-radius-md) var(--pm-radius-md) 0 0 !important; + padding: 8px 16px 8px !important; + overflow: visible !important; + margin-bottom: 0 !important; + transition: color 0.15s ease !important; + outline: none !important; + box-shadow: none !important; +} + +/* Remove ::after from inactive tabs */ +.x-tab::after { + display: none !important; +} + +.x-tab-inner-default { + color: var(--grv-subtext0) !important; + font-size: 13px !important; +} + +.x-tab-default.x-tab-over { + background-color: transparent !important; +} + +.x-tab-default.x-tab-over .x-tab-inner-default { + color: var(--grv-text) !important; +} + +/* Active tab */ +.x-tab-default.x-tab.x-tab-active { + background-color: transparent !important; + border: none !important; + overflow: visible !important; + margin-bottom: 0 !important; + outline: none !important; + box-shadow: none !important; +} + +/* Purple underline indicator on active tab */ +.x-tab-default.x-tab.x-tab-active::after { + content: '' !important; + display: block !important; + position: absolute !important; + bottom: 0 !important; + left: 0 !important; + right: 0 !important; + height: 2px !important; + background: var(--grv-purple) !important; + z-index: 10 !important; + border-radius: 2px 2px 0 0 !important; + pointer-events: none !important; +} + +.x-tab-active .x-tab-inner-default { + color: var(--grv-text) !important; + font-weight: 600 !important; +} + +.x-tab-default.x-tab.x-tab-disabled { + background-color: transparent !important; + border: none !important; + color: var(--grv-overlay0) !important; + margin-bottom: 0 !important; +} + +/* Focus states — no outline */ +.x-keyboard-mode .x-tab-default.x-tab-focus, +.x-keyboard-mode .x-tab-default.x-tab-focus.x-tab-active { + background-color: transparent !important; + border: none !important; + outline: none !important; + box-shadow: none !important; + margin-bottom: 0 !important; +} + +.x-keyboard-mode .x-tab-default.x-tab-focus.x-tab-active::after { + content: '' !important; + display: block !important; + position: absolute !important; + bottom: 0 !important; + left: 0 !important; + right: 0 !important; + height: 2px !important; + background: var(--grv-purple) !important; + z-index: 10 !important; + pointer-events: none !important; +} + +/* Kill ALL tab interaction outlines/shadows */ +.x-tab:focus, +.x-tab *:focus, +.x-tab-focus, +.x-tab-active.x-tab-focus, +.x-tab-inner-focus, +.x-tab-button-focus, +.x-tab-pressed, +.x-tab-active.x-tab-pressed, +.x-tab-over, +.x-tab:active, +.x-tab *:active { + outline: none !important; + box-shadow: none !important; +} + +.x-tabpanel-child { + border-radius: 0 0 var(--pm-radius-lg) var(--pm-radius-lg) !important; +} + +/* Tab hover/active corners */ +.x-tab-default.x-tab-over, +.x-tab-default.x-tab.x-tab-active { + border-radius: var(--pm-radius-md) var(--pm-radius-md) 0 0 !important; +} + +/* ===================================================== + TOOLTIPS + ===================================================== */ +.x-tip, +.x-tip-default { + background-color: var(--grv-mantle) !important; + border: 1px solid var(--grv-surface1) !important; + border-radius: var(--pm-radius-md) !important; + box-shadow: 0 4px 12px rgba(30, 31, 41, 0.5); +} + +.x-tip-body-default { + color: var(--grv-text) !important; +} + +.x-tip-form-invalid { + background-color: var(--grv-mantle) !important; + border-color: var(--grv-red) !important; +} + +.x-tip-body-form-invalid { + color: var(--grv-red) !important; +} + +/* ===================================================== + TREE NAVIGATION (Sidebar) + ===================================================== */ +.x-treelist-item { + background-color: var(--grv-base) !important; + border-radius: var(--pm-radius-md) !important; +} + +/* Pseudo-element approach for hover/selected highlighting */ +.x-treelist-row { + border-radius: var(--pm-radius-md) !important; + background-color: transparent !important; + position: relative !important; + z-index: 0 !important; +} + +.x-treelist-row::before { + content: ""; + position: absolute; + top: 1px; + bottom: 1px; + left: 0; + right: 4px; + border-radius: var(--pm-radius-md); + background-color: transparent; + z-index: -1; + pointer-events: none; + transition: background-color 0.15s ease; +} + +/* Fix toolbox tree item text overlapping icons */ +.x-treelist-item-text { + margin-left: 28px !important; +} + +/* Toolbox tree items — bright text */ +.x-treelist-item-text, +.x-treelist-item-icon, +.x-treelist.x-treelist-pve-nav .x-treelist-item-text, +.x-treelist.x-treelist-pve-nav .x-treelist-item-icon { + color: var(--grv-subtext1) !important; +} + +/* Hover state — apply to pseudo-element */ +.x-treelist-row-over { + background-color: transparent !important; +} + +.x-treelist-row-over::before { + background-color: var(--grv-hover-overlay) !important; +} + +.x-treelist-row-over .x-treelist-item-icon, +.x-treelist-row-over .x-treelist-item-text { + background-color: transparent !important; + color: var(--grv-text) !important; +} + +/* Selected/active item — Purple highlight */ +.x-treelist-item-selected > .x-treelist-row { + background-color: transparent !important; +} + +.x-treelist-item-selected > .x-treelist-row::before, +.x-treelist-item-selected > .x-treelist-row:hover::before { + background-color: var(--grv-purple) !important; +} + +.x-treelist-item-selected .x-treelist-item-text, +.x-treelist-item-selected .x-treelist-item-icon, +.x-treelist.x-treelist-pve-nav .x-treelist-item-selected .x-treelist-item-text, +.x-treelist.x-treelist-pve-nav .x-treelist-item-selected .x-treelist-item-icon { + color: var(--grv-on-accent) !important; +} + +.x-treelist-pve-nav { + background-color: var(--grv-base) !important; + border-color: var(--grv-surface1) !important; +} + +/* Tree navigation radius overrides */ +.x-treelist-item, +.x-treelist-item-tool { + border-radius: var(--pm-radius-sm) !important; +} + +.x-treelist-row, +.x-treelist-row:hover, +.x-treelist-row-over, +.x-treelist-item-selected > .x-treelist-row, +.x-treelist-item-selected > .x-treelist-row:hover, +.x-treelist-item-expanded > .x-treelist-row, +.x-treelist-item-expanded > .x-treelist-row-over, +.x-treelist-item-expandable > .x-treelist-row, +.x-treelist-item-expandable > .x-treelist-row-over { + border-radius: var(--pm-radius-sm) !important; +} + +.x-treelist-row::before { + border-radius: var(--pm-radius-sm) !important; +} + +.x-treelist-item-wrap, +.x-treelist-item-text, +.x-treelist-row, +.x-treelist-container, +.x-treelist-root-container, +.x-treelist, +.x-treelist-pve-nav { + border-radius: var(--pm-radius-sm) !important; +} + +/* Cursor pointer for interactive tree/grid items */ +.x-grid-cell, +.x-grid-cell-inner, +.x-tree-elbow-img, +.x-tree-icon, +.x-treelist-item, +.x-treelist-row, +.x-treelist-item-wrap, +.x-treelist-item-text, +.x-treelist-item-icon { + cursor: pointer !important; +} + +/* ===================================================== + WINDOWS / MODALS + ===================================================== */ +.x-window, +.x-window-default { + background-color: var(--grv-crust) !important; + border: 1px solid var(--grv-surface1) !important; + border-radius: var(--pm-radius-lg) !important; + box-shadow: 0 8px 24px rgba(30, 31, 41, 0.6) !important; + overflow: hidden !important; +} + +.x-window .x-window-header, +.x-window-header-default { + background-color: var(--grv-mantle) !important; + border-color: transparent !important; + border-radius: var(--pm-radius-lg) var(--pm-radius-lg) 0 0 !important; +} + +.x-window-header-default .x-mask { + background-color: rgba(30, 31, 41, 0.7); +} + +.x-window .x-window-body, +.x-window-body-default { + background-color: var(--grv-base) !important; + border-color: var(--grv-surface1) !important; + color: var(--grv-text) !important; + border-radius: 0 0 var(--pm-radius-lg) var(--pm-radius-lg) !important; +} + +.x-window-ghost { + background-color: var(--grv-base) !important; +} + +.x-window-header-default .x-tool-img { + background-color: transparent; +} + +.x-message-box .x-window-body { + background-color: var(--grv-mantle) !important; +} + +/* Respect ExtJS inline display:none on hidden dialog buttons */ +.x-message-box .x-btn.x-btn-default-small[style*="display: none"], +.x-message-box .x-btn.x-btn-default-small[style*="display:none"], +.x-window .x-toolbar-footer .x-btn[style*="display: none"], +.x-window .x-toolbar-footer .x-btn[style*="display:none"] { + display: none !important; +} + +/* Login dialog — clean inner panel borders */ +.x-window:has(#pveloginrealm) .x-panel-body { + border: none !important; + background: transparent !important; + width: auto !important; +} + +/* ===================================================== + CONSOLE / TERMINAL + ===================================================== */ +div.monitor { + border-color: var(--grv-surface1); +} + +.install-mask { + background-color: var(--grv-crust); + color: var(--grv-subtext0); +} + +.x-window.install-mask { + box-shadow: rgba(30, 31, 41, 0.5) 0 4px 20px !important; +} + +/* ===================================================== + LEGEND / CHARTS + ===================================================== */ +.x-legend-container { + background-color: var(--grv-base) !important; +} + +.x-legend-horizontal .x-legend-item { + background-color: var(--grv-mantle) !important; + color: var(--grv-text) !important; + border: 1px solid var(--grv-surface0) !important; +} + +/* Chart/RRD panel backgrounds */ +div[id*="rrdchart"], +.pve-rrddatastore, +.pmx-panel-rrd { + background-color: var(--grv-base) !important; +} + +.proxmox-rrd-panel canvas, +.proxmox-widget-toolkit canvas, +canvas.x-surface, +.x-surface canvas { + background-color: transparent !important; + opacity: 1 !important; +} + +.proxmox-rrd-panel, +.proxmox-rrd-chart { + background-color: var(--grv-base) !important; +} + +/* Chart text/labels */ +.x-surface text, +svg text { + fill: var(--grv-text) !important; +} + +/* ===================================================== + PROXMOX-SPECIFIC OVERRIDES + ===================================================== */ + +/* Logo inversion */ +img[id^="proxmoxlogo-"][id$="-img"], +img[id^="proxmoxLogoSvg-"][id$="-img"] { + filter: invert(1) hue-rotate(180deg); +} + +/* Invalid/warning/disabled rows */ +.proxmox-invalid-row { + background-color: rgba(255, 85, 85, 0.15) !important; +} + +.proxmox-warning-row { + background-color: rgba(255, 184, 108, 0.15) !important; +} + +.proxmox-disabled-row td { + color: var(--grv-overlay0) !important; +} + +/* Hints */ +.pmx-hint { + background-color: rgba(255, 184, 108, 0.15) !important; + white-space: nowrap !important; +} + +.pmx-hint a { + color: var(--grv-cyan) !important; +} + +/* Status text colors — Information → Cyan */ +.info-blue { + color: var(--grv-cyan) !important; +} + +.critical { + color: var(--grv-red) !important; +} + +/* Links */ +a { + color: var(--grv-cyan) !important; +} + +/* Markdown content */ +.pmx-md code { + background-color: var(--grv-mantle) !important; + color: var(--grv-pink) !important; + border-radius: var(--pm-radius-sm) !important; +} + +.pmx-md pre code { + border-color: var(--grv-surface1) !important; + background-color: var(--grv-crust) !important; +} + +.pmx-md a { + color: var(--grv-cyan) !important; +} + +.pmx-md table { + border-color: var(--grv-surface1) !important; +} + +.pmx-md th { + background-color: var(--grv-mantle) !important; + border-color: var(--grv-surface1) !important; +} + +.pmx-md td { + border-color: var(--grv-surface1) !important; +} + +/* APT repos */ +.proxmox-apt-repos .x-grid-group-hd { + background-color: var(--grv-base) !important; + border: none !important; +} + +.proxmox-apt-repos .x-grid-group-title { + color: var(--grv-text) !important; +} + +/* Tags */ +.pve-edit-tag { + border-radius: var(--pm-radius-md) !important; +} + +.pve-edit-tag.editable span { + background-color: var(--grv-mantle) !important; + color: var(--grv-text) !important; + border-color: var(--grv-surface1) !important; +} + +.x-tree-node-text .proxmox-tag-dark, +.x-tree-node-text .proxmox-tag-light, +.x-grid-cell-inner .proxmox-tag-dark, +.x-grid-cell-inner .proxmox-tag-light, +span.proxmox-tag-dark, +span.proxmox-tag-light { + border-radius: var(--pm-radius-md) !important; +} + +/* Checkmark button in tag edit — match toolbar button size */ +.x-btn.x-btn-default-small:has(.fa-check) { + min-height: 24px !important; + height: 24px !important; + padding: 3px 8px !important; + border-radius: var(--pm-radius-sm) !important; + background-color: var(--grv-purple) !important; + border: none !important; +} + +.x-btn.x-btn-default-small:has(.fa-check).x-btn-disabled { + background-color: transparent !important; + border: 1px solid var(--grv-surface1) !important; + opacity: 0.5 !important; +} + +.x-btn.x-btn-default-small:has(.fa-check) .fa-check { + color: var(--grv-on-accent) !important; +} + +.x-btn.x-btn-default-small:has(.fa-check).x-btn-disabled .fa-check { + color: var(--grv-overlay1) !important; +} + +.x-btn.x-btn-default-small:has(.fa-check):not(.x-btn-disabled):hover { + background-color: #caa9fa !important; +} + +.x-btn.x-btn-default-small:has(.fa-check) .x-btn-inner { + display: none !important; +} + +/* Date picker */ +.x-datepicker, +.x-datepicker-column-header, +.x-monthpicker { + background-color: var(--grv-base) !important; + color: var(--grv-text) !important; + border-color: transparent !important; +} + +.x-datepicker-header, +.x-datepicker-footer, +.x-monthpicker-buttons { + background-color: var(--grv-mantle) !important; +} + +.x-datepicker-date, +.x-monthpicker-item-inner { + color: var(--grv-text) !important; +} + +.x-datepicker-selected div.x-datepicker-date, +.x-monthpicker-item a.x-monthpicker-selected, +a.x-monthpicker-item-inner:hover, +div.x-datepicker-date:hover { + background-color: var(--grv-hover-overlay) !important; + color: var(--grv-text) !important; +} + +.x-datepicker-today .x-datepicker-date { + border-color: var(--grv-purple) !important; +} + +.x-datepicker-disabled .x-datepicker-date { + color: var(--grv-overlay0) !important; +} + +.x-datepicker-prev-day .x-datepicker-date, +.x-datepicker-next-day .x-datepicker-date { + color: var(--grv-overlay0) !important; +} + +/* Usage bars */ +.usage-wrapper, +.usage { + border-radius: 2px !important; +} + +.usage { + background-color: var(--grv-overlay2) !important; +} + +/* ===================================================== + SCROLLBARS + ===================================================== */ +::-webkit-scrollbar { + width: 8px; + height: 8px; +} + +::-webkit-scrollbar-track { + background: var(--grv-base); + border-radius: var(--pm-radius-sm); +} + +::-webkit-scrollbar-thumb { + background: var(--grv-surface2); + border-radius: var(--pm-radius-sm); + border: 1px solid transparent; + background-clip: padding-box; + transition: background 0.15s ease; +} + +::-webkit-scrollbar-thumb:hover { + background: var(--grv-overlay0); +} + +::-webkit-scrollbar-corner { + background: var(--grv-base); +} + +/* Firefox scrollbar */ +* { + scrollbar-width: thin; + scrollbar-color: var(--grv-surface2) var(--grv-base); +} + +/* ===================================================== + SELECTION HIGHLIGHT + ===================================================== */ +::selection { + background-color: rgba(98, 114, 164, 0.3); + color: var(--grv-text); +} + +/* ===================================================== + TRANSITIONS (smooth interactions) + ===================================================== */ + +/* Grid row transitions */ +.x-grid-item { + transition: background-color 0.15s ease !important; +} + +/* Tree pseudo-element transitions */ +.x-treelist-row::before { + transition: background-color 0.15s ease !important; +} + +/* Menu item transitions */ +.x-menu-item-default > .x-menu-item-link { + transition: background-color 0.12s ease !important; +} + +/* Boundlist item transitions */ +.x-boundlist-item { + transition: background-color 0.12s ease !important; +} + +/* Tab transitions */ +.x-tab { + transition: color 0.15s ease !important; +} + +/* Splitter transition */ +.x-splitter { + transition: background-color 0.15s ease !important; +} + +/* Tooltip transition */ +.x-tip { + transition: opacity 0.15s ease !important; +} + +/* Progress bar width transition */ +.x-progress-bar { + transition: width 0.4s ease !important; +} + +/* Scrollbar thumb transition */ +::-webkit-scrollbar-thumb { + transition: background 0.15s ease !important; +} + +/* Window close tool transition */ +.x-tool-img { + transition: filter 0.15s ease !important; +} +/* ===================================================== + TOOL ICONS - FontAwesome Replacements + (Ported from UniFi v5.86) + Replace sprite-based ExtJS tool icons with crisp + FontAwesome icons for better consistency and clarity + ===================================================== */ + +/* Base styling for all tool icons - remove sprite backgrounds */ +.x-tool-tool-el.x-tool-minus, +.x-tool-img.x-tool-minus, +.x-tool-tool-el.x-tool-collapse-right, +.x-tool-img.x-tool-collapse-right, +.x-tool-tool-el.x-tool-collapse-left, +.x-tool-img.x-tool-collapse-left, +.x-tool-tool-el.x-tool-expand-right, +.x-tool-img.x-tool-expand-right, +.x-tool-tool-el.x-tool-expand-left, +.x-tool-img.x-tool-expand-left, +.x-tool-tool-el.x-tool-maximize, +.x-tool-img.x-tool-maximize, +.x-tool-tool-el.x-tool-restore, +.x-tool-img.x-tool-restore, +.x-tool-tool-el.x-tool-gear, +.x-tool-img.x-tool-gear, +.x-tool-tool-el.x-tool-refresh, +.x-tool-img.x-tool-refresh, +.x-tool-tool-el.x-tool-close, +.x-tool-img.x-tool-close { + background-image: none !important; + font-family: "FontAwesome" !important; + font-size: 14px !important; + line-height: 16px !important; + text-align: center !important; + color: var(--pm-text-dim) !important; + transition: color 0.15s ease !important; + filter: none !important; + width: 16px !important; + height: 16px !important; + display: flex !important; + align-items: center !important; + justify-content: center !important; +} + +/* Close button - slightly larger */ +.x-tool-tool-el.x-tool-close, +.x-tool-img.x-tool-close { + font-size: 20px !important; +} + +/* Individual glyph assignments */ +.x-tool-tool-el.x-tool-minus::before, +.x-tool-img.x-tool-minus::before { + content: "\f010" !important; /* fa-search-minus (zoom out) */ +} + +.x-tool-tool-el.x-tool-collapse-right::before, +.x-tool-img.x-tool-collapse-right::before { + content: "\f054" !important; /* fa-chevron-right */ +} + +.x-tool-tool-el.x-tool-expand-left::before, +.x-tool-img.x-tool-expand-left::before { + content: "\f053" !important; /* fa-chevron-left */ +} + +.x-tool-tool-el.x-tool-collapse-left::before, +.x-tool-img.x-tool-collapse-left::before { + content: "\f053" !important; /* fa-chevron-left */ +} + +.x-tool-tool-el.x-tool-expand-right::before, +.x-tool-img.x-tool-expand-right::before { + content: "\f054" !important; /* fa-chevron-right */ +} + +.x-tool-tool-el.x-tool-maximize::before, +.x-tool-img.x-tool-maximize::before { + content: "\f065" !important; /* fa-expand */ +} + +.x-tool-tool-el.x-tool-restore::before, +.x-tool-img.x-tool-restore::before { + content: "\f066" !important; /* fa-compress */ +} + +.x-tool-tool-el.x-tool-gear::before, +.x-tool-img.x-tool-gear::before { + content: "\f013" !important; /* fa-cog */ +} + +.x-tool-tool-el.x-tool-refresh::before, +.x-tool-img.x-tool-refresh::before { + content: "\f021" !important; /* fa-refresh */ +} + +.x-tool-tool-el.x-tool-close::before, +.x-tool-img.x-tool-close::before { + content: "\f00d" !important; /* fa-times */ +} + +/* Hover state - all tool icons */ +.x-tool:hover .x-tool-tool-el.x-tool-minus, +.x-tool:hover .x-tool-img.x-tool-minus, +.x-tool:hover .x-tool-tool-el.x-tool-collapse-right, +.x-tool:hover .x-tool-img.x-tool-collapse-right, +.x-tool:hover .x-tool-tool-el.x-tool-collapse-left, +.x-tool:hover .x-tool-img.x-tool-collapse-left, +.x-tool:hover .x-tool-tool-el.x-tool-expand-right, +.x-tool:hover .x-tool-img.x-tool-expand-right, +.x-tool:hover .x-tool-tool-el.x-tool-expand-left, +.x-tool:hover .x-tool-img.x-tool-expand-left, +.x-tool:hover .x-tool-tool-el.x-tool-maximize, +.x-tool:hover .x-tool-img.x-tool-maximize, +.x-tool:hover .x-tool-tool-el.x-tool-restore, +.x-tool:hover .x-tool-img.x-tool-restore, +.x-tool:hover .x-tool-tool-el.x-tool-gear, +.x-tool:hover .x-tool-img.x-tool-gear, +.x-tool:hover .x-tool-tool-el.x-tool-refresh, +.x-tool:hover .x-tool-img.x-tool-refresh, +.x-tool:hover .x-tool-tool-el.x-tool-close, +.x-tool:hover .x-tool-img.x-tool-close { + color: var(--pm-text) !important; +} + +/* Disabled state */ +.x-tool-disabled .x-tool-tool-el, +.x-tool-disabled .x-tool-img { + opacity: 0.4 !important; + cursor: default !important; +} + +/* Inline FontAwesome tools (PVE-injected) */ +.x-tool-tool-el[style*="font-family:FontAwesome"], +.x-tool-tool-el[style*="font-family: FontAwesome"] { + color: var(--pm-text-dim) !important; + font-size: 14px !important; + line-height: 16px !important; + display: flex !important; + align-items: center !important; + justify-content: center !important; + width: 16px !important; + height: 16px !important; + transition: color 0.15s ease !important; + background-image: none !important; + background-color: transparent !important; +} + +.x-tool:not(.x-tool-disabled) .x-tool-tool-el[style*="font-family:FontAwesome"], +.x-tool:not(.x-tool-disabled) .x-tool-tool-el[style*="font-family: FontAwesome"] { + cursor: pointer !important; +} + +.x-tool.x-tool-disabled .x-tool-tool-el[style*="font-family:FontAwesome"], +.x-tool.x-tool-disabled .x-tool-tool-el[style*="font-family: FontAwesome"] { + cursor: default !important; + opacity: 0.4 !important; +} + +.x-tool .x-mask { + background-color: transparent !important; + backdrop-filter: none !important; + pointer-events: none !important; +} + +.x-tool:not(.x-tool-disabled):hover .x-tool-tool-el[style*="font-family:FontAwesome"], +.x-tool:not(.x-tool-disabled):hover .x-tool-tool-el[style*="font-family: FontAwesome"] { + color: var(--pm-text) !important; +} diff --git a/themes/theme-gruvbox-light.css b/themes/theme-gruvbox-light.css new file mode 100644 index 0000000..675a6b0 --- /dev/null +++ b/themes/theme-gruvbox-light.css @@ -0,0 +1,2237 @@ +/*!Gruvbox Light*/ + +/* ===================================================== + CSS VARIABLES + ===================================================== */ +:root { + /* Theme: Gruvbox Light */ + --pm-accent: #d79921; + --pm-bg-base: #fbf1c7; + --pm-bg-surface: #ebdbb2; + --pm-bg-elevated: #d5c4a1; + --pm-text: #282828; + --pm-text-dim: #3c3836; + --pm-success: #98971a; + --pm-warning: #d65d0e; + --pm-error: #cc241d; + --pm-border: #d5c4a1; + --pm-radius-sm: 4px; + --pm-radius-md: 6px; + --pm-radius-lg: 8px; + + /* Proxmox Widget Toolkit Mappings */ + --pwt-panel-background: var(--pm-bg-base); + --pwt-text-color: var(--pm-text); + --pwt-gauge-default: var(--pm-accent); + --pwt-gauge-back: var(--pm-bg-elevated); + --pwt-gauge-warn: var(--pm-warning); + --pwt-gauge-crit: var(--pm-error); + --pwt-chart-primary: var(--pm-accent); + --pwt-chart-grid-stroke: var(--pm-bg-elevated); + + /* Gruvbox theme internal variables (based on Dracula template structure) */ + --grv-text: var(--pm-text); + --grv-subtext0: var(--pm-text-dim); + --grv-subtext1: var(--pm-text-dim); + --grv-overlay0: var(--pm-border); + --grv-overlay1: var(--pm-text-dim); + --grv-overlay2: var(--pm-text-dim); + --grv-surface0: var(--pm-bg-surface); + --grv-surface1: var(--pm-bg-elevated); + --grv-surface2: var(--pm-bg-elevated); + --grv-base: var(--pm-bg-base); + --grv-mantle: #ebdbb2; + --grv-crust: #ebdbb2; + + --grv-on-accent: #fbf1c7; + --grv-hover-overlay: rgba(128, 128, 128, 0.12); + --grv-select-overlay: rgba(128, 128, 128, 0.25); + --grv-accent-muted: rgba(128, 128, 128, 0.4); + --grv-accent-subtle: rgba(128, 128, 128, 0.15); + + --grv-cyan: var(--pm-accent); + --grv-green: var(--pm-success); + --grv-orange: var(--pm-warning); + --grv-pink: var(--pm-accent); + --grv-purple: var(--pm-accent); + --grv-red: var(--pm-error); + --grv-yellow: var(--pm-warning); + + color-scheme: light; +} + +/* ===================================================== + GLOBAL BORDER-RADIUS ARCHITECTURE + (Ported from UniFi theme — reset everything, selectively re-apply) + ===================================================== */ +.x-border-box, +.x-border-box * { + border-radius: var(--pm-radius-lg); +} + +/* Remove rounded corners from grids/tables/lists */ +.x-grid, +.x-grid *, +.x-grid-header-ct, +.x-grid-header-ct *, +.x-grid-view, +.x-grid-view *, +.x-column-header, +.x-column-header *, +.x-grid-item, +.x-grid-cell, +.x-grid-cell-inner, +.x-grid-row, +table, +table *, +tr, +td, +th, +.x-legend, +.x-legend *, +.x-legend-container, +.x-legend-container *, +.x-legend-item, +.x-legend-horizontal .x-legend-item, +.x-legend-vertical .x-legend-item, +.x-legend-horizontal .x-legend-item:first-child, +.x-legend-horizontal .x-legend-item:last-child, +.x-legend-vertical .x-legend-item:first-child, +.x-legend-vertical .x-legend-item:last-child, +.x-tool, +.x-tool-tool-el, +.x-tool-default, +.x-tool-img { + border-radius: 0 !important; +} + +/* Form elements - exclude from global radius */ +.x-form-item, +.x-form-item-default, +.x-form-item-body, +.x-form-item-body-default, +.x-form-text-field-body, +.x-form-text-field-body-default, +.x-form-fieldcontainer, +.x-field, +.x-field-default, +.x-form-type-text { + border-radius: 0 !important; +} + +/* Reset layout containers that clip elements with overflow:hidden + radius */ +.x-box-layout-ct, +.x-panel-bodyWrap, +.x-panel-bodyWrap-default, +.x-autocontainer-innerCt, +.x-autocontainer-outerCt, +.x-panel.x-tabpanel-child, +.x-panel.x-box-item, +.x-box-inner, +.x-box-target, +.x-container, +.x-container-default, +.x-window .x-panel-body, +.x-window .x-window-body, +.x-window .x-window-bodyWrap { + border-radius: 0 !important; +} + +/* Reset everything inside windows to 0 — then re-apply specific radii */ +.x-window *, +.x-window .x-autocontainer-innerCt, +.x-window .x-autocontainer-outerCt, +.x-window .x-form-layout-wrap, +.x-window .x-form-layout-auto-label, +.x-window .x-form-layout-colgroup, +.x-window .x-form-layout-column, +.x-window .x-field, +.x-window .x-form-item, +.x-window .x-form-item-body { + border-radius: 0 !important; +} + +/* Chart canvas — no radius on data area */ +.x-chart-grid, +.x-chart-axis, +canvas.x-surface, +.x-chart canvas, +canvas.x-surface-canvas, +.x-surface-canvas, +.x-draw-component canvas, +.proxmox-rrd-chart canvas, +svg.x-surface, +.x-draw-container, +.x-surface { + border-radius: 0 !important; +} + +/* Legend color marker (dot) — keep circular */ +.x-legend-item-marker { + border-radius: 50% !important; +} + +/* ===================================================== + RE-APPLY BORDER RADII (selective) + ===================================================== */ + +/* Windows */ +.x-window, +.x-window-default { + border-radius: var(--pm-radius-lg) !important; +} + +.x-window-header, +.x-window-header-default { + border-radius: var(--pm-radius-lg) var(--pm-radius-lg) 0 0 !important; +} + +.x-window .x-window-body, +.x-window-body-default { + border-radius: 0 !important; +} + +/* Buttons inside windows */ +.x-window .x-btn { + border-radius: var(--pm-radius-md) !important; +} + +/* Checkboxes inside windows */ +.x-window .x-form-checkbox { + border-radius: 3px !important; +} + +/* Form inputs inside windows */ +.x-window .x-form-trigger-wrap, +.x-window .x-form-trigger-wrap-default { + border-radius: var(--pm-radius-sm) !important; +} + +.x-window .x-form-text-wrap, +.x-window .x-form-text { + border-radius: var(--pm-radius-sm) 0 0 var(--pm-radius-sm) !important; +} + +.x-window .x-form-arrow-trigger { + border-radius: 0 var(--pm-radius-sm) var(--pm-radius-sm) 0 !important; +} + +/* Form trigger/text wrap — reset and re-apply */ +.x-form-trigger-wrap, +.x-form-trigger-wrap *, +.x-form-text-wrap, +.x-form-text-wrap *, +.x-form-text, +.x-form-trigger { + border-radius: 0 !important; +} + +.x-form-trigger-wrap, +.x-form-trigger-wrap-default { + border-radius: var(--pm-radius-sm) !important; + overflow: hidden !important; +} + +.x-form-text-wrap, +.x-form-text-wrap-default { + border-radius: var(--pm-radius-sm) 0 0 var(--pm-radius-sm) !important; +} + +.x-form-text, +.x-form-text-default { + border-radius: var(--pm-radius-sm) 0 0 var(--pm-radius-sm) !important; +} + +.x-form-trigger, +.x-form-trigger-default, +.x-form-arrow-trigger, +.x-form-arrow-trigger-default { + border-radius: 0 var(--pm-radius-sm) var(--pm-radius-sm) 0 !important; +} + +/* Dialog form content padding — vertical only (horizontal causes ExtJS overflow) */ +.x-window .x-tabpanel-child .x-autocontainer-innerCt { + padding: 12px 0 !important; +} + +/* Allow column panel bodies to show overflowed form content */ +.x-window .x-panel-body:not(.x-scroller) { + overflow: visible !important; +} + +/* Side padding on column panel bodies inside windows */ +.x-window .x-panel.x-box-item .x-panel-body { + padding: 0 4px !important; +} + +/* Constrain autocontainer width inside windows */ +.x-window .x-autocontainer-outerCt { + max-width: 100% !important; +} + +/* Fix window header/body width consistency */ +.x-window > .x-window-header, +.x-window > .x-window-body, +.x-window > .x-window-bodyWrap, +.x-window-bodyWrap > .x-window-body { + width: 100% !important; +} + +.x-window-header > .x-box-inner, +.x-window-header > .x-box-inner > .x-box-target { + width: 100% !important; +} + +.x-window-header-title { + width: auto !important; + flex: 1 !important; + max-width: calc(100% - 30px) !important; +} + +/* Boundlists */ +.x-boundlist { + border-radius: var(--pm-radius-md) !important; + overflow: hidden !important; +} + +/* ===================================================== + BASE / BODY + ===================================================== */ +.x-body, +.x-viewport > .x-body, +body.x-border-layout-ct, +div.x-border-layout-ct { + background-color: var(--grv-base) !important; + color: var(--grv-text) !important; +} + +/* ===================================================== + MASKS & OVERLAYS + ===================================================== */ +.x-mask { + background-color: rgba(30, 31, 41, 0.6) !important; + backdrop-filter: blur(4px); +} + +.x-mask-msg { + background-color: var(--grv-mantle) !important; + border: 1px solid var(--grv-surface1) !important; + border-radius: var(--pm-radius-lg) !important; +} + +.x-mask-msg-text { + color: var(--grv-subtext0) !important; + filter: none !important; +} + +.x-css-shadow { + box-shadow: 0 8px 24px rgba(30, 31, 41, 0.6) !important; +} + +/* Loading indicators */ +.x-grid-row-loading, +.x-treelist-item-loading .x-treelist-item-icon, +.x-grid-tree-loading .x-tree-icon { + filter: none; +} + +/* ===================================================== + ICONS — Proxmox default colors for dark mode + ===================================================== */ + +/* General icon colors — neutral gray for dark backgrounds */ +.x-tree-icon-custom, +.x-grid-icon-custom, +.fa-tags::before, +.fa-file-o::before, +.fa-building::before, +.x-action-col-icon::before, +.fa-shield::before, +.fa-file-text-o::before, +.fa-clock-o::before, +.x-tab-icon-el-default, +.pve-icon-verify-lettering::after, +.x-tree-icon-leaf:not(.x-tree-icon-custom)::before, +.x-tree-icon-parent:not(.x-tree-icon-custom)::before, +.x-tree-icon-parent-expanded:not(.x-tree-icon-custom)::before, +.x-grid-filters-filtered-column .x-column-header-text::after { + color: var(--grv-overlay2) !important; +} + +/* Folder icons — invert for dark mode */ +.x-tree-icon-parent:not(.x-tree-icon-custom)::before, +.x-tree-icon-parent-expanded:not(.x-tree-icon-custom)::before { + filter: none; +} + +/* Various image-based icons — invert for visibility */ +.fa-ceph::before, +.fa-sdn::before, +.fa-network-wired::before, +.pve-itype-treelist-item-icon-cdrom, +.fa-chevron-right::before, +.x-grid-row-console, +.x-box-scroller-toolbar-default.x-box-scroller, +.x-tree-elbow-img, +.pve-itype-icon-qemu, +.x-tree-node-computer, +.x-grid-tree-node-expanded .x-tree-node-computer, +.pbs-icon-tape, +.pbs-icon-tape-drive, +.x-tree-icon-leaf:not(.x-tree-icon-custom), +.x-tree-icon-parent:not(.x-tree-icon-custom), +.x-tree-icon-parent-expanded:not(.x-tree-icon-custom) { + filter: none; +} + +/* Hardware icons */ +.pve-itype-icon-cpu, +.pve-itype-icon-cdrom, +.pve-itype-icon-memory, +.pve-itype-icon-pci, +.pve-itype-icon-serial, +.pve-itype-icon-die, +.pmx-itype-icon-processor, +.pmx-itype-icon-memory, +.pve-itype-icon-storage, +.x-tree-node-harddisk, +.x-grid-tree-node-expanded .x-tree-node-harddisk { + filter: none; +} + +/* Icon overlays — default */ +.x-tree-icon-custom::after, +.x-grid-icon-custom::after { + color: var(--grv-overlay2) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* RUNNING VMs/CTs — Dracula Green */ +.x-tree-icon-custom.running::after, +.x-grid-icon-custom.running::after, +.x-treelist-item-icon.running::after { + color: var(--grv-green) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* ONLINE state — Green */ +.x-tree-icon-custom.online::after, +.x-grid-icon-custom.online::after { + color: var(--grv-green) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* Stopped/offline — Overlay1 (muted gray) */ +.x-tree-icon-custom.stopped, +.x-tree-icon-custom.offline, +.x-grid-icon-custom.stopped, +.x-grid-icon-custom.offline { + color: var(--grv-overlay1) !important; +} + +/* Unknown state — Overlay1 */ +.x-tree-icon-custom.unknown::after, +.x-grid-icon-custom.unknown::after { + color: var(--grv-overlay1) !important; +} + +/* ERROR states — Dracula Red */ +.x-tree-icon-custom.error::after, +.x-tree-icon-custom.offline::after, +.x-tree-icon-custom.ha-error::after, +.x-grid-icon-custom.error::after, +.x-grid-icon-custom.offline::after, +.x-grid-icon-custom.ha-error::after { + color: var(--grv-red) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* PAUSED/SUSPENDED — Dracula Orange */ +.x-tree-icon-custom.paused::after, +.x-tree-icon-custom.suspended::after, +.x-tree-icon-custom.lock-suspending::after, +.x-grid-icon-custom.paused::after, +.x-grid-icon-custom.suspended::after, +.x-grid-icon-custom.lock-suspending::after { + color: var(--grv-orange) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* PENDING/WARNING states — Dracula Yellow */ +.x-tree-icon-custom.pending::after, +.x-tree-icon-custom.io-error::after, +.x-tree-icon-custom.internal-error::after, +.x-tree-icon-custom.guest-panicked::after, +.x-grid-icon-custom.pending::after, +.x-grid-icon-custom.io-error::after, +.x-grid-icon-custom.internal-error::after, +.x-grid-icon-custom.guest-panicked::after { + color: var(--grv-yellow) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* HA MAINTENANCE — Dracula Cyan */ +.x-tree-icon-custom.ha-maintenance::after, +.x-grid-icon-custom.ha-maintenance::after { + color: var(--grv-cyan) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* Locked icons */ +.x-tree-icon-custom.locked::after, +.x-tree-icon-custom.lock-backup::after, +.x-tree-icon-custom.lock-migrate::after, +.x-tree-icon-custom.lock-suspended::after, +.x-grid-icon-custom.locked::after, +.x-grid-icon-custom.lock-backup::after, +.x-grid-icon-custom.lock-migrate::after, +.x-grid-icon-custom.lock-suspended::after { + color: var(--grv-overlay2) !important; +} + +/* LXC/QEMU type indicators */ +.x-tree-icon-custom.lxc::after, +.x-tree-icon-custom.qemu::after, +.x-grid-icon-custom.lxc::after, +.x-grid-icon-custom.qemu::after { + background-color: transparent; + color: var(--grv-overlay1) !important; +} + +.x-treelist-item-icon.lxc::after, +.x-treelist-item-icon.qemu::after { + background-color: transparent; + color: var(--grv-overlay1) !important; +} + +/* Tree expander arrows */ +.x-tree-arrows .x-tree-expander { + filter: none; +} + +/* Cancel sprite-inversion on custom controls (checkboxes/radios handled via CSS) */ +.x-form-checkbox-default, +.x-form-radio-default, +.x-column-header-checkbox .x-column-header-checkbox::after, +.x-grid-checkcolumn::after, +.x-menu-item-checked .x-menu-item-icon-default.x-menu-item-checkbox, +.x-menu-item-unchecked .x-menu-item-icon-default.x-menu-item-checkbox { + filter: none !important; +} + +/* ===================================================== + PANELS & HEADERS + ===================================================== */ +.x-panel, +.x-panel-default { + border-radius: var(--pm-radius-lg) !important; + padding: 0 !important; +} + +/* Column panels — gaps + max-width prevents scrollbar-induced sub-pixel overflow */ +.x-panel.x-column { + padding: 5px !important; + margin: 0 !important; + max-width: none !important; + box-sizing: border-box !important; +} + +/* Column panel card styling — borders for summary + chart panels */ +.x-panel.x-panel-default.x-column { + border: 1px solid var(--grv-surface1) !important; + border-radius: var(--pm-radius-lg) !important; + overflow: hidden !important; +} + +/* Guest status + Notes panel borders */ +[id^="pveGuestStatusView-"].x-panel, +[id^="pveLxcStatusView-"].x-panel, +[id^="pveQemuStatusView-"].x-panel, +[id^="pmxNotesView-"].x-panel { + border: 1px solid var(--grv-surface1) !important; + border-radius: var(--pm-radius-lg) !important; +} + +.x-panel-body, +.x-panel-body-default { + background-color: var(--grv-base) !important; + color: var(--grv-text) !important; + border: none !important; +} + +/* Panel headers — bottom border only */ +.x-panel-header, +.x-panel-header-default { + background-color: var(--grv-mantle) !important; + border: none !important; + border-bottom: 1px solid var(--grv-surface1) !important; + border-radius: var(--pm-radius-lg) var(--pm-radius-lg) 0 0 !important; + margin: 0 !important; + padding: 8px 12px !important; + width: 100% !important; + box-sizing: border-box !important; + overflow: visible !important; +} + +/* Title text — prevent border-radius clipping */ +.x-title-text, +.x-title-text-default { + overflow: visible !important; +} + +.x-panel-bodyWrap, +.x-panel-bodyWrap-default { + margin: 0 !important; + padding: 0 !important; + overflow: visible !important; +} + +/* Remove borders from nested panels */ +.x-panel-body > .x-box-layout-ct, +.x-panel-body > .x-container, +.x-panel-body > .x-box-inner, +[id*="pmxGauge"] { + border: none !important; +} + +.x-panel-header-title-default, +.x-window-header-title-default { + color: var(--grv-text) !important; +} + +.x-panel-header-default .x-tool-tool-el { + background-color: transparent; +} + +.x-tool-img { + filter: none; +} + +.x-tool-over .x-tool-img { + filter: none; +} + +/* Resource tree — panel body border */ +div[id^="pveResourceTree-"][id$="-body"] { + border-color: var(--grv-base) !important; +} + +/* Resource tree — remove row separators */ +[id^="pveResourceTree-"].x-tree-panel td.x-grid-cell, +[id^="pveResourceTree-"].x-tree-panel .x-grid-td, +[id^="pveResourceTree-"].x-tree-panel .x-grid-cell { + border-bottom: none !important; +} + +/* Resource tree — row spacing */ +div[id^="pveResourceTree"] .x-grid-cell { + padding-top: 3px !important; + padding-bottom: 3px !important; +} + +/* Summary/stats panel radius overrides */ +.pveStatusPanel, +.x-panel-default-framed, +.x-panel-body-default-framed { + border-radius: 12px !important; +} + +.x-panel-header-default-framed { + border-radius: 12px 12px 0 0 !important; +} + +/* Column widget panel radius */ +.x-panel.x-column > .x-panel-bodyWrap > .x-panel-body.x-panel-body-default { + border-radius: var(--pm-radius-lg) !important; +} + +/* ===================================================== + SPLITTERS / SEPARATORS + ===================================================== */ +.x-splitter-vertical { + background-color: transparent !important; + border-left: 1px solid var(--grv-surface1) !important; + border-right: none !important; + width: 1px !important; +} + +.x-splitter-horizontal { + background-color: var(--grv-crust) !important; + border-top: 1px solid var(--grv-surface1) !important; +} + +.x-splitter { + background-color: var(--grv-crust) !important; +} + +.x-keyboard-mode .x-splitter-focus::after { + border-color: var(--grv-purple) !important; +} + +.x-layout-split-bottom { + opacity: 0.7; +} + +/* Toolbox tree (pve-nav) right border — full height */ +.pve-toolbar-bg { + border-right: 1px solid var(--grv-surface1) !important; + z-index: 3 !important; +} + +.x-treelist.x-treelist-pve-nav { + border-right: none !important; +} + +/* ===================================================== + TOOLBARS + ===================================================== */ +.x-toolbar, +.x-toolbar-default { + background-color: var(--grv-base) !important; + border-color: var(--grv-surface1) !important; +} + +.x-toolbar-default.x-docked-top { + border: none !important; + border-bottom: 1px solid var(--grv-surface1) !important; +} + +.x-toolbar-default .x-toolbar-separator { + border-color: var(--grv-surface1); +} + +.x-toolbar-text-default { + color: var(--grv-subtext0); +} + +/* ===================================================== + PRIMARY BUTTONS — Dracula Purple + ===================================================== */ +.x-btn-default-small { + background-color: var(--grv-purple) !important; + border: 1px solid rgba(189, 147, 249, 0.4) !important; + border-radius: var(--pm-radius-md) !important; + transition: background-color 0.15s ease, box-shadow 0.15s ease !important; +} + +.x-btn-default-small .x-btn-inner { + color: var(--grv-on-accent) !important; + font-weight: 600 !important; +} + +.x-btn-default-small .x-btn-icon-el { + color: var(--grv-on-accent) !important; +} + +.x-btn-default-small.x-btn-over, +.x-keyboard-mode .x-btn-default-small.x-btn-focus { + background-color: #caa9fa !important; + box-shadow: 0 0 0 3px var(--grv-accent-subtle) !important; +} + +.x-btn-default-small.x-btn.x-btn-disabled { + background-color: var(--grv-purple) !important; + opacity: 0.4; +} + +.x-btn-default-small.x-btn.x-btn-pressed { + background-color: #a986f0 !important; +} + +/* Button height consistency — 28px with vertical centering */ +/* Exclude tag edit buttons (display:none when hidden, :has(.fa-check) for checkmark) */ +.x-btn.x-btn-default-small:not(.x-btn-default-toolbar-small):not([style*="display: none"]):not([style*="display:none"]):not(:has(.fa-check)) { + height: 28px !important; + min-height: 28px !important; + display: flex !important; + align-items: center !important; + padding: 3px 8px !important; +} + +/* Fix button inner element centering for proper icon alignment (issue #17) */ +.x-btn.x-btn-default-small:not(.x-btn-default-toolbar-small):not([style*="display: none"]):not([style*="display:none"]):not(:has(.fa-check)) .x-btn-wrap { + display: flex !important; + align-items: center !important; +} + +.x-btn.x-btn-default-small:not(.x-btn-default-toolbar-small):not([style*="display: none"]):not([style*="display:none"]):not(:has(.fa-check)) .x-btn-inner { + display: flex !important; + align-items: center !important; +} + +/* Fix dropdown arrows on split/arrow buttons */ +.x-btn-wrap.x-btn-arrow-right::after, +.x-btn-wrap.x-btn-split-right::after { + height: 16px !important; + min-height: 16px !important; + width: 20px !important; + display: flex !important; + align-items: center !important; +} + +/* Fix icon-only buttons — hide   inner element when button has no text */ +.x-btn-no-text .x-btn-inner, +.x-btn-button.x-btn-no-text .x-btn-inner, +.x-btn-button-default-toolbar-small.x-btn-no-text .x-btn-inner-default-toolbar-small, +.x-btn-button-default-small.x-btn-no-text .x-btn-inner-default-small, +.x-btn-button-default-small.x-btn-no-text > .x-btn-inner-default-small { + display: none !important; +} + +/* Specific fix for fa-desktop icon (Create VM) — visually bottom-heavy */ +.x-btn-icon-el.fa-desktop { + transform: translateY(1.1px) !important; +} + +/* ===================================================== + SECONDARY / TOOLBAR BUTTONS + ===================================================== */ +.x-btn-default-toolbar-small { + background-color: var(--grv-surface0) !important; + border: 1px solid var(--grv-surface1) !important; + border-radius: var(--pm-radius-md) !important; + transition: background-color 0.15s ease, border-color 0.15s ease !important; +} + +.x-btn-default-toolbar-small .x-btn-inner-default-toolbar-small, +.x-btn-default-toolbar-small .x-btn-icon-el-default-toolbar-small { + color: var(--grv-text) !important; +} + +.x-btn-default-toolbar-small .x-btn-wrap-default-toolbar-small.x-btn-arrow-right::after, +.x-btn-default-toolbar-small .x-btn-wrap-default-toolbar-small.x-btn-split-right::after { + filter: none; +} + +.x-btn-default-toolbar-small.x-btn-over, +.x-keyboard-mode .x-btn-default-toolbar-small.x-btn-focus { + background-color: var(--grv-surface1) !important; + border-color: var(--grv-surface2) !important; +} + +.x-btn-default-toolbar-small.x-btn.x-btn-disabled { + background-color: var(--grv-surface0) !important; + opacity: 0.4; +} + +.x-btn-default-toolbar-small.x-btn.x-btn-menu-active, +.x-btn-default-toolbar-small.x-btn.x-btn-pressed { + background-color: var(--grv-purple) !important; + border-color: var(--grv-purple) !important; + padding: 4px 8px !important; /* Fix #30: prevent width change on dropdown */ +} + +.x-btn-default-toolbar-small.x-btn.x-btn-pressed .x-btn-inner-default-toolbar-small, +.x-btn-default-toolbar-small.x-btn.x-btn-pressed .x-btn-icon-el-default-toolbar-small, +.x-btn-default-toolbar-small.x-btn.x-btn-pressed .x-btn-inner-default-small, +.x-btn-default-toolbar-small.x-btn.x-btn-pressed .x-btn-icon-el-default-small { + color: var(--grv-on-accent) !important; +} + +/* Segmented buttons */ +.x-segmented-button { + border-radius: var(--pm-radius-md) !important; +} + +.x-segmented-button .x-btn, +.x-segmented-button .x-btn-default-small, +.x-segmented-button .x-btn-inner, +.x-segmented-button .x-btn-wrap { + border-radius: var(--pm-radius-md) !important; +} + +/* Inline buttons (Documentation, Help) */ +.proxmox-inline-button { + height: 28px !important; + min-height: 28px !important; + display: flex !important; + align-items: center !important; + padding: 3px 8px !important; + background-color: var(--grv-surface0) !important; + border: 1px solid var(--grv-surface1) !important; + border-radius: var(--pm-radius-md) !important; + color: var(--grv-text) !important; + transition: background-color 0.15s ease !important; +} + +.proxmox-inline-button:hover, +.proxmox-inline-button.x-btn-over { + background-color: var(--grv-surface1) !important; + border-color: var(--grv-overlay0) !important; +} + +.proxmox-inline-button:active, +.proxmox-inline-button.x-btn-pressed { + background-color: var(--grv-surface2) !important; +} + +.proxmox-inline-button .x-btn-inner, +.proxmox-inline-button .x-btn-icon-el { + color: var(--grv-text) !important; +} + +/* Pressed/active inline buttons — use on-accent text */ +.proxmox-inline-button.x-btn-pressed .x-btn-inner, +.proxmox-inline-button.x-btn-pressed .x-btn-icon-el, +.proxmox-inline-button.x-btn-menu-active .x-btn-inner, +.proxmox-inline-button.x-btn-menu-active .x-btn-icon-el { + color: var(--grv-on-accent) !important; +} + +/* ===================================================== + FORM ELEMENTS + ===================================================== */ +.x-form-trigger-default { + background-color: var(--grv-surface0) !important; +} + +.x-form-text-default { + background-color: var(--grv-surface0) !important; + color: var(--grv-text) !important; + border-radius: var(--pm-radius-sm) !important; +} + +.x-form-trigger-wrap, +.x-form-trigger-wrap-default { + border-color: var(--grv-surface1) !important; + background-color: var(--grv-surface0) !important; + border-radius: var(--pm-radius-sm) !important; + transition: border-color 0.15s ease !important; +} + +.x-form-trigger-wrap-default.x-form-trigger-wrap-focus { + border-color: var(--grv-purple) !important; + box-shadow: 0 0 0 3px var(--grv-accent-subtle) !important; +} + +.x-form-item-label-default, +.x-form-cb-label-default { + color: var(--grv-text) !important; +} + +.x-form-display-field-default { + color: var(--grv-subtext0) !important; + border-radius: var(--pm-radius-md) !important; +} + +.x-form-spinner-default { + background-color: var(--grv-surface0) !important; +} + +.x-fieldset, +.x-fieldset-default { + border-color: var(--grv-surface1) !important; + border-radius: var(--pm-radius-lg) !important; +} + +.x-fieldset-header-default > .x-fieldset-header-text { + color: var(--grv-text) !important; +} + +/* ===================================================== + CHECKBOXES & RADIOS — Dracula styled + ===================================================== */ + +/* Base: remove sprite, styled as custom control */ +.x-form-checkbox, .x-form-checkbox-default, +.x-form-radio, .x-form-radio-default { + background-image: none !important; + background-color: var(--grv-surface0) !important; + border: 1.5px solid var(--grv-overlay0) !important; + width: 16px !important; + height: 16px !important; + display: inline-block !important; + box-sizing: border-box !important; + cursor: pointer !important; + transition: border-color 0.12s ease, background-color 0.12s ease !important; +} + +/* Checkbox: rounded square */ +.x-form-checkbox, .x-form-checkbox-default { + border-radius: 3px !important; +} + +/* Radio: circle + ::after inner dot */ +.x-form-radio, .x-form-radio-default { + border-radius: 50% !important; + position: relative !important; + transform: translateZ(0) !important; + box-shadow: inset 0 0 0 0 transparent !important; +} + +.x-form-radio::after { + content: '' !important; + position: absolute !important; + top: 50% !important; + left: 50% !important; + width: 7px !important; + height: 7px !important; + border-radius: 50% !important; + background: transparent !important; + transform: translate(-50%, -50%) scale(0) !important; + transition: transform 0.15s ease, background 0.15s ease !important; + pointer-events: none !important; +} + +/* Hover */ +.x-form-checkbox:hover, .x-form-checkbox-default:hover, +.x-form-cb-wrap:hover .x-form-checkbox { + border-color: var(--grv-purple) !important; +} + +.x-form-radio:hover, .x-form-radio-default:hover, +.x-form-cb-wrap:hover .x-form-radio { + border-color: var(--grv-purple) !important; +} + +/* CHECKED checkbox — Purple fill + dark SVG checkmark */ +.x-form-cb-checked .x-form-checkbox, +.x-form-cb-checked .x-form-checkbox-default { + background-color: var(--grv-purple) !important; + border-color: var(--grv-purple) !important; + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 8'%3E%3Cpath d='M1 4l3 3 5-6' fill='none' stroke='%23fbf1c7' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") !important; + background-repeat: no-repeat !important; + background-position: center !important; + background-size: 9px 7px !important; +} + +/* SELECTED radio — Purple dot */ +.x-form-cb-checked .x-form-radio, +.x-form-cb-checked .x-form-radio-default { + border-color: var(--grv-purple) !important; + background-color: var(--grv-base) !important; +} + +.x-form-cb-checked .x-form-radio::after { + background: var(--grv-purple) !important; + transform: translate(-50%, -50%) scale(1) !important; +} + +/* ===================================================== + BOUNDLIST / DROPDOWNS + ===================================================== */ +.x-boundlist { + background-color: var(--grv-mantle) !important; + border: 1px solid var(--grv-surface1) !important; + border-radius: var(--pm-radius-md) !important; + box-shadow: 0 8px 24px rgba(30, 31, 41, 0.7) !important; + padding: 2px !important; + overflow: hidden !important; +} + +.x-boundlist-item { + background-color: transparent !important; + color: var(--grv-text) !important; + border-radius: var(--pm-radius-sm) !important; + padding: 2px 6px !important; + line-height: normal !important; + border: none !important; + cursor: pointer !important; + outline: none !important; + box-shadow: none !important; +} + +.x-boundlist-selected { + background-color: var(--grv-select-overlay) !important; + color: var(--grv-text) !important; +} + +.x-boundlist-item-over { + background-color: var(--grv-hover-overlay) !important; +} + +/* ===================================================== + GRIDS / TABLES + ===================================================== */ +.x-grid, +.x-grid-view { + border-radius: 0 !important; +} + +.x-column-header { + border-color: var(--grv-surface1) !important; + background-color: transparent !important; +} + +.x-column-header-inner, +.x-column-header-text { + color: var(--grv-text) !important; + font-weight: 600 !important; +} + +.x-column-header-trigger { + border-color: var(--grv-surface1) !important; +} + +.x-grid-item, +.x-column-header-default, +.x-grid-cell-row-numberer { + color: var(--grv-text) !important; + background-color: var(--grv-base) !important; +} + +.x-grid-cell-special { + border-color: var(--grv-surface1) !important; +} + +.x-grid-group-hd { + background-color: var(--grv-base) !important; + border-color: var(--grv-surface1) !important; +} + +.x-grid-group-title { + color: var(--grv-text) !important; +} + +.x-grid-header-ct { + background-color: var(--grv-mantle) !important; + border: 1px solid var(--grv-surface0) !important; + border-radius: var(--pm-radius-lg) var(--pm-radius-lg) 0 0 !important; +} + +.x-grid-item-alt { + background-color: var(--grv-crust) !important; +} + +.x-grid-with-row-lines .x-grid-item { + border-color: var(--grv-surface0) !important; +} + +.x-grid-cell { + border-bottom: 1px solid rgba(68, 71, 90, 0.4) !important; +} + +.x-grid-item-over, +.x-grid-with-row-lines .x-grid-item.x-grid-item-over { + background-color: var(--grv-hover-overlay) !important; +} + +.x-grid-item-selected, +.x-grid-with-row-lines .x-grid-item.x-grid-item-selected { + background-color: var(--grv-select-overlay) !important; +} + +.x-column-header-over, +.x-column-header-open { + background-color: var(--grv-hover-overlay) !important; +} + +.x-column-header-sort-ASC, +.x-column-header-sort-DESC { + background-color: var(--grv-hover-overlay) !important; +} + +.x-grid-row-summary .x-grid-cell, +.x-grid-row-summary .x-grid-rowwrap, +.x-grid-row-summary .x-grid-cell-rowbody { + background-color: var(--grv-base) !important; + border-color: var(--grv-surface1); +} + +.x-grid-with-col-lines .x-grid-cell, +.x-grid-with-col-lines .x-grid-item-over .x-grid-cell, +.x-grid-with-col-lines .x-grid-item-selected .x-grid-cell { + border-color: var(--grv-surface1) !important; +} + +.x-dd-drag-proxy { + background-color: var(--grv-mantle); + border-color: var(--grv-surface1); + color: var(--grv-text); +} + +.x-keyboard-mode .x-grid-item-focused { + background-color: var(--grv-hover-overlay) !important; + color: var(--grv-text) !important; +} + +/* Remove blue outline from focused/selected items in resource tree */ +.x-keyboard-mode .x-grid-item-focused .x-grid-cell-inner::before, +.x-keyboard-mode .x-grid-item-selected .x-grid-cell-inner::before, +.x-grid-item-selected .x-grid-cell-inner::before, +.x-grid-item-focused .x-grid-cell-inner::before, +[id^="pveResourceTree"] .x-grid-item-selected .x-grid-cell-inner::before, +[id^="pveResourceTree"] .x-grid-item-focused .x-grid-cell-inner::before { + content: none !important; + display: none !important; + border: none !important; +} + +.x-grid-empty { + background-color: var(--grv-base) !important; + color: var(--grv-subtext0) !important; +} + +/* Grid info (pve-info-grid) and RRD view */ +.pve-info-grid { + border-radius: 12px !important; +} + +.pve-rrdview, +.rrdview { + border-radius: 12px !important; +} + +.pve-summary-status, +.x-container .pve-status { + border-radius: var(--pm-radius-lg) !important; +} + +[id^="pveGuestStatusView-"][id$="-body"], +[id^="pmxNotesView-"] .x-panel-body { + border-radius: var(--pm-radius-lg) !important; +} + +.x-panel-default[id*="notes"], +.pve-notes-view { + border-radius: var(--pm-radius-lg) !important; +} + +/* Floating grid pickers (storage/ISO selectors) */ +.x-layer.x-grid .x-grid-view, +.x-panel.x-layer.x-grid .x-grid-view, +.x-panel.x-layer.x-grid, +.x-layer.x-panel.x-grid { + border-radius: var(--pm-radius-sm) !important; +} + +.x-layer.x-grid .x-grid-item-over, +.x-layer.x-grid .x-grid-item-selected, +.x-panel.x-layer.x-grid .x-grid-item-over, +.x-panel.x-layer.x-grid .x-grid-item-selected { + border-radius: var(--pm-radius-sm) !important; + outline: none !important; + box-shadow: none !important; +} + +.x-layer.x-grid .x-grid-item-over td, +.x-layer.x-grid .x-grid-item-selected td, +.x-layer.x-grid .x-grid-item-over .x-grid-cell, +.x-layer.x-grid .x-grid-item-selected .x-grid-cell, +.x-panel.x-layer.x-grid .x-grid-item-over td, +.x-panel.x-layer.x-grid .x-grid-item-selected td, +.x-panel.x-layer.x-grid .x-grid-item-over .x-grid-cell, +.x-panel.x-layer.x-grid .x-grid-item-selected .x-grid-cell { + border-radius: 0 !important; +} + +.x-layer.x-grid .x-grid-item-over td:first-child, +.x-layer.x-grid .x-grid-item-selected td:first-child, +.x-panel.x-layer.x-grid .x-grid-item-over td:first-child, +.x-panel.x-layer.x-grid .x-grid-item-selected td:first-child { + border-radius: var(--pm-radius-sm) 0 0 var(--pm-radius-sm) !important; +} + +.x-layer.x-grid .x-grid-item-over td:last-child, +.x-layer.x-grid .x-grid-item-selected td:last-child, +.x-panel.x-layer.x-grid .x-grid-item-over td:last-child, +.x-panel.x-layer.x-grid .x-grid-item-selected td:last-child { + border-radius: 0 var(--pm-radius-sm) var(--pm-radius-sm) 0 !important; +} + +/* ===================================================== + MENUS + ===================================================== */ +.x-menu, +.x-menu-default { + background-color: var(--grv-crust) !important; + border: 1px solid var(--grv-surface0) !important; + border-radius: var(--pm-radius-lg) !important; + box-shadow: 0 8px 24px rgba(30, 31, 41, 0.8) !important; + padding: 4px !important; + overflow: hidden !important; +} + +.x-menu-body-default { + background-color: transparent !important; + padding: 4px !important; +} + +.x-menu-header { + background-color: transparent !important; + color: var(--grv-text) !important; +} + +/* Menu icon separator — hide */ +.x-menu-icon-separator-default { + display: none !important; +} + +/* Menu item layout (flexbox reordering) */ +.x-menu-item-default > .x-menu-item-link { + display: flex !important; + align-items: center !important; + flex-direction: row !important; + gap: 4px !important; + justify-content: flex-start !important; + flex-wrap: nowrap !important; + border-radius: var(--pm-radius-md) !important; + padding: 4px 8px !important; + line-height: 20px !important; + border: none !important; + cursor: pointer !important; + outline: none !important; + box-shadow: none !important; + white-space: nowrap !important; + text-decoration: none !important; +} + +.x-menu-item-text-default { + color: var(--grv-text) !important; + font-size: 13px !important; + order: 1 !important; + margin-left: 0 !important; + text-align: left !important; + line-height: 20px !important; + display: inline-flex !important; + align-items: center !important; + flex: 1 1 auto !important; + width: auto !important; + white-space: nowrap !important; +} + +.x-menu-item-icon-default { + color: var(--grv-subtext0) !important; + order: -1 !important; + position: relative !important; + float: none !important; + margin-right: 8px !important; + margin-left: 0 !important; + left: auto !important; + top: auto !important; + width: 16px !important; + text-align: center !important; + display: inline-flex !important; + align-items: center !important; + justify-content: center !important; + height: 20px !important; + line-height: 20px !important; + vertical-align: middle !important; + flex: 0 0 16px !important; + align-self: center !important; +} + +.x-menu-item-arrow, +.x-menu-item-arrow-default { + order: 2 !important; + margin-left: auto !important; +} + +.x-menu-item-default.x-menu-item-separator { + background-color: var(--grv-surface0) !important; + border: none !important; + height: 1px !important; + margin: 6px 4px !important; +} + +.x-menu-item-default.x-menu-item-focus, +.x-menu-item-default.x-menu-item-active, +.x-menu-item:hover { + background-color: var(--grv-surface0) !important; + color: var(--grv-text) !important; + border-radius: var(--pm-radius-md) !important; +} + +.x-menu-item-active .x-menu-item-text-default, +.x-menu-item-focus .x-menu-item-text-default { + color: var(--grv-text) !important; +} + +.x-menu-item-active .x-menu-item-icon-default, +.x-menu-item-focus .x-menu-item-icon-default { + color: var(--grv-cyan) !important; +} + +/* ===================================================== + PROGRESS BARS + ===================================================== */ + +/* Fix: Widget containers need overflow visible to not clip progress bars */ +.x-container[id^="pmxInfoWidget"], +.x-container.x-box-layout-ct { + overflow: visible !important; +} + +.x-progress, +.x-progress-default { + background-color: var(--grv-surface0) !important; + border-radius: 5px !important; +} + +.x-progress-default .x-progress-bar-default { + background-color: var(--grv-purple) !important; + border-radius: 5px !important; + transition: width 0.4s ease !important; +} + +.x-progress-default .x-progress-text { + color: var(--grv-text) !important; +} + +/* Text overlaid on the progress bar fill — use on-accent for contrast */ +.x-progress-bar .x-progress-text { + color: var(--grv-on-accent) !important; +} + +.x-progress.warning .x-progress-bar { + background-color: var(--grv-yellow) !important; +} + +.x-progress.critical .x-progress-bar { + background-color: var(--grv-red) !important; +} + +/* ===================================================== + TABS — Dracula underline style + Flat tabs with Purple underline on active tab + ===================================================== */ +.x-tab-bar, +.x-tab-bar-default { + background-color: var(--grv-base) !important; + border-radius: 0 !important; + border-bottom: 1px solid var(--grv-surface1) !important; + padding-bottom: 0 !important; +} + +/* Overflow visible for the underline indicator */ +.x-tab-bar .x-box-inner, +.x-tab-bar .x-box-target, +.x-tab-bar-body, +.x-tab-bar-body-default { + overflow: visible !important; +} + +/* Base tab */ +.x-tab, +.x-tab-default, +.x-tab-default-top { + background-color: transparent !important; + border: none !important; + border-radius: var(--pm-radius-md) var(--pm-radius-md) 0 0 !important; + padding: 8px 16px 8px !important; + overflow: visible !important; + margin-bottom: 0 !important; + transition: color 0.15s ease !important; + outline: none !important; + box-shadow: none !important; +} + +/* Remove ::after from inactive tabs */ +.x-tab::after { + display: none !important; +} + +.x-tab-inner-default { + color: var(--grv-subtext0) !important; + font-size: 13px !important; +} + +.x-tab-default.x-tab-over { + background-color: transparent !important; +} + +.x-tab-default.x-tab-over .x-tab-inner-default { + color: var(--grv-text) !important; +} + +/* Active tab */ +.x-tab-default.x-tab.x-tab-active { + background-color: transparent !important; + border: none !important; + overflow: visible !important; + margin-bottom: 0 !important; + outline: none !important; + box-shadow: none !important; +} + +/* Purple underline indicator on active tab */ +.x-tab-default.x-tab.x-tab-active::after { + content: '' !important; + display: block !important; + position: absolute !important; + bottom: 0 !important; + left: 0 !important; + right: 0 !important; + height: 2px !important; + background: var(--grv-purple) !important; + z-index: 10 !important; + border-radius: 2px 2px 0 0 !important; + pointer-events: none !important; +} + +.x-tab-active .x-tab-inner-default { + color: var(--grv-text) !important; + font-weight: 600 !important; +} + +.x-tab-default.x-tab.x-tab-disabled { + background-color: transparent !important; + border: none !important; + color: var(--grv-overlay0) !important; + margin-bottom: 0 !important; +} + +/* Focus states — no outline */ +.x-keyboard-mode .x-tab-default.x-tab-focus, +.x-keyboard-mode .x-tab-default.x-tab-focus.x-tab-active { + background-color: transparent !important; + border: none !important; + outline: none !important; + box-shadow: none !important; + margin-bottom: 0 !important; +} + +.x-keyboard-mode .x-tab-default.x-tab-focus.x-tab-active::after { + content: '' !important; + display: block !important; + position: absolute !important; + bottom: 0 !important; + left: 0 !important; + right: 0 !important; + height: 2px !important; + background: var(--grv-purple) !important; + z-index: 10 !important; + pointer-events: none !important; +} + +/* Kill ALL tab interaction outlines/shadows */ +.x-tab:focus, +.x-tab *:focus, +.x-tab-focus, +.x-tab-active.x-tab-focus, +.x-tab-inner-focus, +.x-tab-button-focus, +.x-tab-pressed, +.x-tab-active.x-tab-pressed, +.x-tab-over, +.x-tab:active, +.x-tab *:active { + outline: none !important; + box-shadow: none !important; +} + +.x-tabpanel-child { + border-radius: 0 0 var(--pm-radius-lg) var(--pm-radius-lg) !important; +} + +/* Tab hover/active corners */ +.x-tab-default.x-tab-over, +.x-tab-default.x-tab.x-tab-active { + border-radius: var(--pm-radius-md) var(--pm-radius-md) 0 0 !important; +} + +/* ===================================================== + TOOLTIPS + ===================================================== */ +.x-tip, +.x-tip-default { + background-color: var(--grv-mantle) !important; + border: 1px solid var(--grv-surface1) !important; + border-radius: var(--pm-radius-md) !important; + box-shadow: 0 4px 12px rgba(30, 31, 41, 0.5); +} + +.x-tip-body-default { + color: var(--grv-text) !important; +} + +.x-tip-form-invalid { + background-color: var(--grv-mantle) !important; + border-color: var(--grv-red) !important; +} + +.x-tip-body-form-invalid { + color: var(--grv-red) !important; +} + +/* ===================================================== + TREE NAVIGATION (Sidebar) + ===================================================== */ +.x-treelist-item { + background-color: var(--grv-base) !important; + border-radius: var(--pm-radius-md) !important; +} + +/* Pseudo-element approach for hover/selected highlighting */ +.x-treelist-row { + border-radius: var(--pm-radius-md) !important; + background-color: transparent !important; + position: relative !important; + z-index: 0 !important; +} + +.x-treelist-row::before { + content: ""; + position: absolute; + top: 1px; + bottom: 1px; + left: 0; + right: 4px; + border-radius: var(--pm-radius-md); + background-color: transparent; + z-index: -1; + pointer-events: none; + transition: background-color 0.15s ease; +} + +/* Fix toolbox tree item text overlapping icons */ +.x-treelist-item-text { + margin-left: 28px !important; +} + +/* Toolbox tree items — bright text */ +.x-treelist-item-text, +.x-treelist-item-icon, +.x-treelist.x-treelist-pve-nav .x-treelist-item-text, +.x-treelist.x-treelist-pve-nav .x-treelist-item-icon { + color: var(--grv-subtext1) !important; +} + +/* Hover state — apply to pseudo-element */ +.x-treelist-row-over { + background-color: transparent !important; +} + +.x-treelist-row-over::before { + background-color: var(--grv-hover-overlay) !important; +} + +.x-treelist-row-over .x-treelist-item-icon, +.x-treelist-row-over .x-treelist-item-text { + background-color: transparent !important; + color: var(--grv-text) !important; +} + +/* Selected/active item — Purple highlight */ +.x-treelist-item-selected > .x-treelist-row { + background-color: transparent !important; +} + +.x-treelist-item-selected > .x-treelist-row::before, +.x-treelist-item-selected > .x-treelist-row:hover::before { + background-color: var(--grv-purple) !important; +} + +.x-treelist-item-selected .x-treelist-item-text, +.x-treelist-item-selected .x-treelist-item-icon, +.x-treelist.x-treelist-pve-nav .x-treelist-item-selected .x-treelist-item-text, +.x-treelist.x-treelist-pve-nav .x-treelist-item-selected .x-treelist-item-icon { + color: var(--grv-on-accent) !important; +} + +.x-treelist-pve-nav { + background-color: var(--grv-base) !important; + border-color: var(--grv-surface1) !important; +} + +/* Tree navigation radius overrides */ +.x-treelist-item, +.x-treelist-item-tool { + border-radius: var(--pm-radius-sm) !important; +} + +.x-treelist-row, +.x-treelist-row:hover, +.x-treelist-row-over, +.x-treelist-item-selected > .x-treelist-row, +.x-treelist-item-selected > .x-treelist-row:hover, +.x-treelist-item-expanded > .x-treelist-row, +.x-treelist-item-expanded > .x-treelist-row-over, +.x-treelist-item-expandable > .x-treelist-row, +.x-treelist-item-expandable > .x-treelist-row-over { + border-radius: var(--pm-radius-sm) !important; +} + +.x-treelist-row::before { + border-radius: var(--pm-radius-sm) !important; +} + +.x-treelist-item-wrap, +.x-treelist-item-text, +.x-treelist-row, +.x-treelist-container, +.x-treelist-root-container, +.x-treelist, +.x-treelist-pve-nav { + border-radius: var(--pm-radius-sm) !important; +} + +/* Cursor pointer for interactive tree/grid items */ +.x-grid-cell, +.x-grid-cell-inner, +.x-tree-elbow-img, +.x-tree-icon, +.x-treelist-item, +.x-treelist-row, +.x-treelist-item-wrap, +.x-treelist-item-text, +.x-treelist-item-icon { + cursor: pointer !important; +} + +/* ===================================================== + WINDOWS / MODALS + ===================================================== */ +.x-window, +.x-window-default { + background-color: var(--grv-crust) !important; + border: 1px solid var(--grv-surface1) !important; + border-radius: var(--pm-radius-lg) !important; + box-shadow: 0 8px 24px rgba(30, 31, 41, 0.6) !important; + overflow: hidden !important; +} + +.x-window .x-window-header, +.x-window-header-default { + background-color: var(--grv-mantle) !important; + border-color: transparent !important; + border-radius: var(--pm-radius-lg) var(--pm-radius-lg) 0 0 !important; +} + +.x-window-header-default .x-mask { + background-color: rgba(30, 31, 41, 0.7); +} + +.x-window .x-window-body, +.x-window-body-default { + background-color: var(--grv-base) !important; + border-color: var(--grv-surface1) !important; + color: var(--grv-text) !important; + border-radius: 0 0 var(--pm-radius-lg) var(--pm-radius-lg) !important; +} + +.x-window-ghost { + background-color: var(--grv-base) !important; +} + +.x-window-header-default .x-tool-img { + background-color: transparent; +} + +.x-message-box .x-window-body { + background-color: var(--grv-mantle) !important; +} + +/* Respect ExtJS inline display:none on hidden dialog buttons */ +.x-message-box .x-btn.x-btn-default-small[style*="display: none"], +.x-message-box .x-btn.x-btn-default-small[style*="display:none"], +.x-window .x-toolbar-footer .x-btn[style*="display: none"], +.x-window .x-toolbar-footer .x-btn[style*="display:none"] { + display: none !important; +} + +/* Login dialog — clean inner panel borders */ +.x-window:has(#pveloginrealm) .x-panel-body { + border: none !important; + background: transparent !important; + width: auto !important; +} + +/* ===================================================== + CONSOLE / TERMINAL + ===================================================== */ +div.monitor { + border-color: var(--grv-surface1); +} + +.install-mask { + background-color: var(--grv-crust); + color: var(--grv-subtext0); +} + +.x-window.install-mask { + box-shadow: rgba(30, 31, 41, 0.5) 0 4px 20px !important; +} + +/* ===================================================== + LEGEND / CHARTS + ===================================================== */ +.x-legend-container { + background-color: var(--grv-base) !important; +} + +.x-legend-horizontal .x-legend-item { + background-color: var(--grv-mantle) !important; + color: var(--grv-text) !important; + border: 1px solid var(--grv-surface0) !important; +} + +/* Chart/RRD panel backgrounds */ +div[id*="rrdchart"], +.pve-rrddatastore, +.pmx-panel-rrd { + background-color: var(--grv-base) !important; +} + +.proxmox-rrd-panel canvas, +.proxmox-widget-toolkit canvas, +canvas.x-surface, +.x-surface canvas { + background-color: transparent !important; + opacity: 1 !important; +} + +.proxmox-rrd-panel, +.proxmox-rrd-chart { + background-color: var(--grv-base) !important; +} + +/* Chart text/labels */ +.x-surface text, +svg text { + fill: var(--grv-text) !important; +} + +/* ===================================================== + PROXMOX-SPECIFIC OVERRIDES + ===================================================== */ + +/* Logo inversion */ +img[id^="proxmoxlogo-"][id$="-img"], +img[id^="proxmoxLogoSvg-"][id$="-img"] { + filter: none; +} + +/* Invalid/warning/disabled rows */ +.proxmox-invalid-row { + background-color: rgba(255, 85, 85, 0.15) !important; +} + +.proxmox-warning-row { + background-color: rgba(255, 184, 108, 0.15) !important; +} + +.proxmox-disabled-row td { + color: var(--grv-overlay0) !important; +} + +/* Hints */ +.pmx-hint { + background-color: rgba(255, 184, 108, 0.15) !important; + white-space: nowrap !important; +} + +.pmx-hint a { + color: var(--grv-cyan) !important; +} + +/* Status text colors — Information → Cyan */ +.info-blue { + color: var(--grv-cyan) !important; +} + +.critical { + color: var(--grv-red) !important; +} + +/* Links */ +a { + color: var(--grv-cyan) !important; +} + +/* Markdown content */ +.pmx-md code { + background-color: var(--grv-mantle) !important; + color: var(--grv-pink) !important; + border-radius: var(--pm-radius-sm) !important; +} + +.pmx-md pre code { + border-color: var(--grv-surface1) !important; + background-color: var(--grv-crust) !important; +} + +.pmx-md a { + color: var(--grv-cyan) !important; +} + +.pmx-md table { + border-color: var(--grv-surface1) !important; +} + +.pmx-md th { + background-color: var(--grv-mantle) !important; + border-color: var(--grv-surface1) !important; +} + +.pmx-md td { + border-color: var(--grv-surface1) !important; +} + +/* APT repos */ +.proxmox-apt-repos .x-grid-group-hd { + background-color: var(--grv-base) !important; + border: none !important; +} + +.proxmox-apt-repos .x-grid-group-title { + color: var(--grv-text) !important; +} + +/* Tags */ +.pve-edit-tag { + border-radius: var(--pm-radius-md) !important; +} + +.pve-edit-tag.editable span { + background-color: var(--grv-mantle) !important; + color: var(--grv-text) !important; + border-color: var(--grv-surface1) !important; +} + +.x-tree-node-text .proxmox-tag-dark, +.x-tree-node-text .proxmox-tag-light, +.x-grid-cell-inner .proxmox-tag-dark, +.x-grid-cell-inner .proxmox-tag-light, +span.proxmox-tag-dark, +span.proxmox-tag-light { + border-radius: var(--pm-radius-md) !important; +} + +/* Checkmark button in tag edit — match toolbar button size */ +.x-btn.x-btn-default-small:has(.fa-check) { + min-height: 24px !important; + height: 24px !important; + padding: 3px 8px !important; + border-radius: var(--pm-radius-sm) !important; + background-color: var(--grv-purple) !important; + border: none !important; +} + +.x-btn.x-btn-default-small:has(.fa-check).x-btn-disabled { + background-color: transparent !important; + border: 1px solid var(--grv-surface1) !important; + opacity: 0.5 !important; +} + +.x-btn.x-btn-default-small:has(.fa-check) .fa-check { + color: var(--grv-on-accent) !important; +} + +.x-btn.x-btn-default-small:has(.fa-check).x-btn-disabled .fa-check { + color: var(--grv-overlay1) !important; +} + +.x-btn.x-btn-default-small:has(.fa-check):not(.x-btn-disabled):hover { + background-color: #caa9fa !important; +} + +.x-btn.x-btn-default-small:has(.fa-check) .x-btn-inner { + display: none !important; +} + +/* Date picker */ +.x-datepicker, +.x-datepicker-column-header, +.x-monthpicker { + background-color: var(--grv-base) !important; + color: var(--grv-text) !important; + border-color: transparent !important; +} + +.x-datepicker-header, +.x-datepicker-footer, +.x-monthpicker-buttons { + background-color: var(--grv-mantle) !important; +} + +.x-datepicker-date, +.x-monthpicker-item-inner { + color: var(--grv-text) !important; +} + +.x-datepicker-selected div.x-datepicker-date, +.x-monthpicker-item a.x-monthpicker-selected, +a.x-monthpicker-item-inner:hover, +div.x-datepicker-date:hover { + background-color: var(--grv-hover-overlay) !important; + color: var(--grv-text) !important; +} + +.x-datepicker-today .x-datepicker-date { + border-color: var(--grv-purple) !important; +} + +.x-datepicker-disabled .x-datepicker-date { + color: var(--grv-overlay0) !important; +} + +.x-datepicker-prev-day .x-datepicker-date, +.x-datepicker-next-day .x-datepicker-date { + color: var(--grv-overlay0) !important; +} + +/* Usage bars */ +.usage-wrapper, +.usage { + border-radius: 2px !important; +} + +.usage { + background-color: var(--grv-overlay2) !important; +} + +/* ===================================================== + SCROLLBARS + ===================================================== */ +::-webkit-scrollbar { + width: 8px; + height: 8px; +} + +::-webkit-scrollbar-track { + background: var(--grv-base); + border-radius: var(--pm-radius-sm); +} + +::-webkit-scrollbar-thumb { + background: var(--grv-surface2); + border-radius: var(--pm-radius-sm); + border: 1px solid transparent; + background-clip: padding-box; + transition: background 0.15s ease; +} + +::-webkit-scrollbar-thumb:hover { + background: var(--grv-overlay0); +} + +::-webkit-scrollbar-corner { + background: var(--grv-base); +} + +/* Firefox scrollbar */ +* { + scrollbar-width: thin; + scrollbar-color: var(--grv-surface2) var(--grv-base); +} + +/* ===================================================== + SELECTION HIGHLIGHT + ===================================================== */ +::selection { + background-color: rgba(98, 114, 164, 0.3); + color: var(--grv-text); +} + +/* ===================================================== + TRANSITIONS (smooth interactions) + ===================================================== */ + +/* Grid row transitions */ +.x-grid-item { + transition: background-color 0.15s ease !important; +} + +/* Tree pseudo-element transitions */ +.x-treelist-row::before { + transition: background-color 0.15s ease !important; +} + +/* Menu item transitions */ +.x-menu-item-default > .x-menu-item-link { + transition: background-color 0.12s ease !important; +} + +/* Boundlist item transitions */ +.x-boundlist-item { + transition: background-color 0.12s ease !important; +} + +/* Tab transitions */ +.x-tab { + transition: color 0.15s ease !important; +} + +/* Splitter transition */ +.x-splitter { + transition: background-color 0.15s ease !important; +} + +/* Tooltip transition */ +.x-tip { + transition: opacity 0.15s ease !important; +} + +/* Progress bar width transition */ +.x-progress-bar { + transition: width 0.4s ease !important; +} + +/* Scrollbar thumb transition */ +::-webkit-scrollbar-thumb { + transition: background 0.15s ease !important; +} + +/* Window close tool transition */ +.x-tool-img { + transition: filter 0.15s ease !important; +} +/* ===================================================== + TOOL ICONS - FontAwesome Replacements + (Ported from UniFi v5.86) + Replace sprite-based ExtJS tool icons with crisp + FontAwesome icons for better consistency and clarity + ===================================================== */ + +/* Base styling for all tool icons - remove sprite backgrounds */ +.x-tool-tool-el.x-tool-minus, +.x-tool-img.x-tool-minus, +.x-tool-tool-el.x-tool-collapse-right, +.x-tool-img.x-tool-collapse-right, +.x-tool-tool-el.x-tool-collapse-left, +.x-tool-img.x-tool-collapse-left, +.x-tool-tool-el.x-tool-expand-right, +.x-tool-img.x-tool-expand-right, +.x-tool-tool-el.x-tool-expand-left, +.x-tool-img.x-tool-expand-left, +.x-tool-tool-el.x-tool-maximize, +.x-tool-img.x-tool-maximize, +.x-tool-tool-el.x-tool-restore, +.x-tool-img.x-tool-restore, +.x-tool-tool-el.x-tool-gear, +.x-tool-img.x-tool-gear, +.x-tool-tool-el.x-tool-refresh, +.x-tool-img.x-tool-refresh, +.x-tool-tool-el.x-tool-close, +.x-tool-img.x-tool-close { + background-image: none !important; + font-family: "FontAwesome" !important; + font-size: 14px !important; + line-height: 16px !important; + text-align: center !important; + color: var(--pm-text-dim) !important; + transition: color 0.15s ease !important; + filter: none !important; + width: 16px !important; + height: 16px !important; + display: flex !important; + align-items: center !important; + justify-content: center !important; +} + +/* Close button - slightly larger */ +.x-tool-tool-el.x-tool-close, +.x-tool-img.x-tool-close { + font-size: 20px !important; +} + +/* Individual glyph assignments */ +.x-tool-tool-el.x-tool-minus::before, +.x-tool-img.x-tool-minus::before { + content: "\f010" !important; /* fa-search-minus (zoom out) */ +} + +.x-tool-tool-el.x-tool-collapse-right::before, +.x-tool-img.x-tool-collapse-right::before { + content: "\f054" !important; /* fa-chevron-right */ +} + +.x-tool-tool-el.x-tool-expand-left::before, +.x-tool-img.x-tool-expand-left::before { + content: "\f053" !important; /* fa-chevron-left */ +} + +.x-tool-tool-el.x-tool-collapse-left::before, +.x-tool-img.x-tool-collapse-left::before { + content: "\f053" !important; /* fa-chevron-left */ +} + +.x-tool-tool-el.x-tool-expand-right::before, +.x-tool-img.x-tool-expand-right::before { + content: "\f054" !important; /* fa-chevron-right */ +} + +.x-tool-tool-el.x-tool-maximize::before, +.x-tool-img.x-tool-maximize::before { + content: "\f065" !important; /* fa-expand */ +} + +.x-tool-tool-el.x-tool-restore::before, +.x-tool-img.x-tool-restore::before { + content: "\f066" !important; /* fa-compress */ +} + +.x-tool-tool-el.x-tool-gear::before, +.x-tool-img.x-tool-gear::before { + content: "\f013" !important; /* fa-cog */ +} + +.x-tool-tool-el.x-tool-refresh::before, +.x-tool-img.x-tool-refresh::before { + content: "\f021" !important; /* fa-refresh */ +} + +.x-tool-tool-el.x-tool-close::before, +.x-tool-img.x-tool-close::before { + content: "\f00d" !important; /* fa-times */ +} + +/* Hover state - all tool icons */ +.x-tool:hover .x-tool-tool-el.x-tool-minus, +.x-tool:hover .x-tool-img.x-tool-minus, +.x-tool:hover .x-tool-tool-el.x-tool-collapse-right, +.x-tool:hover .x-tool-img.x-tool-collapse-right, +.x-tool:hover .x-tool-tool-el.x-tool-collapse-left, +.x-tool:hover .x-tool-img.x-tool-collapse-left, +.x-tool:hover .x-tool-tool-el.x-tool-expand-right, +.x-tool:hover .x-tool-img.x-tool-expand-right, +.x-tool:hover .x-tool-tool-el.x-tool-expand-left, +.x-tool:hover .x-tool-img.x-tool-expand-left, +.x-tool:hover .x-tool-tool-el.x-tool-maximize, +.x-tool:hover .x-tool-img.x-tool-maximize, +.x-tool:hover .x-tool-tool-el.x-tool-restore, +.x-tool:hover .x-tool-img.x-tool-restore, +.x-tool:hover .x-tool-tool-el.x-tool-gear, +.x-tool:hover .x-tool-img.x-tool-gear, +.x-tool:hover .x-tool-tool-el.x-tool-refresh, +.x-tool:hover .x-tool-img.x-tool-refresh, +.x-tool:hover .x-tool-tool-el.x-tool-close, +.x-tool:hover .x-tool-img.x-tool-close { + color: var(--pm-text) !important; +} + +/* Disabled state */ +.x-tool-disabled .x-tool-tool-el, +.x-tool-disabled .x-tool-img { + opacity: 0.4 !important; + cursor: default !important; +} + +/* Inline FontAwesome tools (PVE-injected) */ +.x-tool-tool-el[style*="font-family:FontAwesome"], +.x-tool-tool-el[style*="font-family: FontAwesome"] { + color: var(--pm-text-dim) !important; + font-size: 14px !important; + line-height: 16px !important; + display: flex !important; + align-items: center !important; + justify-content: center !important; + width: 16px !important; + height: 16px !important; + transition: color 0.15s ease !important; + background-image: none !important; + background-color: transparent !important; +} + +.x-tool:not(.x-tool-disabled) .x-tool-tool-el[style*="font-family:FontAwesome"], +.x-tool:not(.x-tool-disabled) .x-tool-tool-el[style*="font-family: FontAwesome"] { + cursor: pointer !important; +} + +.x-tool.x-tool-disabled .x-tool-tool-el[style*="font-family:FontAwesome"], +.x-tool.x-tool-disabled .x-tool-tool-el[style*="font-family: FontAwesome"] { + cursor: default !important; + opacity: 0.4 !important; +} + +.x-tool .x-mask { + background-color: transparent !important; + backdrop-filter: none !important; + pointer-events: none !important; +} + +.x-tool:not(.x-tool-disabled):hover .x-tool-tool-el[style*="font-family:FontAwesome"], +.x-tool:not(.x-tool-disabled):hover .x-tool-tool-el[style*="font-family: FontAwesome"] { + color: var(--pm-text) !important; +} diff --git a/themes/theme-nord-dark.css b/themes/theme-nord-dark.css new file mode 100644 index 0000000..425b0a9 --- /dev/null +++ b/themes/theme-nord-dark.css @@ -0,0 +1,2340 @@ +/*!Nord Dark*/ + +/* ===================================================== + CSS VARIABLES + ===================================================== */ +:root { + /* Theme: Nord Dark */ + --pm-accent: #88c0d0; + --pm-bg-base: #2e3440; + --pm-bg-surface: #3b4252; + --pm-bg-elevated: #434c5e; + --pm-text: #e5e9f0; + --pm-text-dim: #d8dee9; + --pm-success: #a3be8c; + --pm-warning: #ebcb8b; + --pm-error: #bf616a; + --pm-border: #434c5e; + --pm-radius-sm: 4px; + --pm-radius-md: 6px; + --pm-radius-lg: 8px; + + /* Proxmox Widget Toolkit Mappings */ + --pwt-panel-background: var(--pm-bg-base); + --pwt-text-color: var(--pm-text); + --pwt-gauge-default: var(--pm-accent); + --pwt-gauge-back: var(--pm-bg-elevated); + --pwt-gauge-warn: var(--pm-warning); + --pwt-gauge-crit: var(--pm-error); + --pwt-chart-primary: var(--pm-accent); + --pwt-chart-grid-stroke: var(--pm-bg-elevated); + + /* Nord theme internal variables (based on Dracula template structure) */ + --nord-text: var(--pm-text); + --nord-subtext0: var(--pm-text-dim); + --nord-subtext1: var(--pm-text-dim); + --nord-overlay0: var(--pm-border); + --nord-overlay1: var(--pm-text-dim); + --nord-overlay2: var(--pm-text-dim); + --nord-surface0: var(--pm-bg-surface); + --nord-surface1: var(--pm-bg-elevated); + --nord-surface2: var(--pm-bg-elevated); + --nord-base: var(--pm-bg-base); + --nord-mantle: #292e39; + --nord-crust: #292e39; + + --nord-on-accent: #2e3440; + --nord-hover-overlay: rgba(128, 128, 128, 0.12); + --nord-select-overlay: rgba(128, 128, 128, 0.25); + --nord-accent-muted: rgba(128, 128, 128, 0.4); + --nord-accent-subtle: rgba(128, 128, 128, 0.15); + + --nord-cyan: var(--pm-accent); + --nord-green: var(--pm-success); + --nord-orange: var(--pm-warning); + --nord-pink: var(--pm-accent); + --nord-purple: var(--pm-accent); + --nord-red: var(--pm-error); + --nord-yellow: var(--pm-warning); + + color-scheme: dark; +} + +/* ===================================================== + GLOBAL BORDER-RADIUS ARCHITECTURE + (Ported from UniFi theme — reset everything, selectively re-apply) + ===================================================== */ +.x-border-box, +.x-border-box * { + border-radius: var(--pm-radius-lg); +} + +/* Remove rounded corners from grids/tables/lists */ +.x-grid, +.x-grid *, +.x-grid-header-ct, +.x-grid-header-ct *, +.x-grid-view, +.x-grid-view *, +.x-column-header, +.x-column-header *, +.x-grid-item, +.x-grid-cell, +.x-grid-cell-inner, +.x-grid-row, +table, +table *, +tr, +td, +th, +.x-legend, +.x-legend *, +.x-legend-container, +.x-legend-container *, +.x-legend-item, +.x-legend-horizontal .x-legend-item, +.x-legend-vertical .x-legend-item, +.x-legend-horizontal .x-legend-item:first-child, +.x-legend-horizontal .x-legend-item:last-child, +.x-legend-vertical .x-legend-item:first-child, +.x-legend-vertical .x-legend-item:last-child, +.x-tool, +.x-tool-tool-el, +.x-tool-default, +.x-tool-img { + border-radius: 0 !important; +} + +/* Form elements - exclude from global radius */ +.x-form-item, +.x-form-item-default, +.x-form-item-body, +.x-form-item-body-default, +.x-form-text-field-body, +.x-form-text-field-body-default, +.x-form-fieldcontainer, +.x-field, +.x-field-default, +.x-form-type-text { + border-radius: 0 !important; +} + +/* Reset layout containers that clip elements with overflow:hidden + radius */ +.x-box-layout-ct, +.x-panel-bodyWrap, +.x-panel-bodyWrap-default, +.x-autocontainer-innerCt, +.x-autocontainer-outerCt, +.x-panel.x-tabpanel-child, +.x-panel.x-box-item, +.x-box-inner, +.x-box-target, +.x-container, +.x-container-default, +.x-window .x-panel-body, +.x-window .x-window-body, +.x-window .x-window-bodyWrap { + border-radius: 0 !important; +} + +/* Reset everything inside windows to 0 — then re-apply specific radii */ +.x-window *, +.x-window .x-autocontainer-innerCt, +.x-window .x-autocontainer-outerCt, +.x-window .x-form-layout-wrap, +.x-window .x-form-layout-auto-label, +.x-window .x-form-layout-colgroup, +.x-window .x-form-layout-column, +.x-window .x-field, +.x-window .x-form-item, +.x-window .x-form-item-body { + border-radius: 0 !important; +} + +/* Chart canvas — no radius on data area */ +.x-chart-grid, +.x-chart-axis, +canvas.x-surface, +.x-chart canvas, +canvas.x-surface-canvas, +.x-surface-canvas, +.x-draw-component canvas, +.proxmox-rrd-chart canvas, +svg.x-surface, +.x-draw-container, +.x-surface { + border-radius: 0 !important; +} + +/* Legend color marker (dot) — keep circular */ +.x-legend-item-marker { + border-radius: 50% !important; +} + +/* ===================================================== + RE-APPLY BORDER RADII (selective) + ===================================================== */ + +/* Windows */ +.x-window, +.x-window-default { + border-radius: var(--pm-radius-lg) !important; +} + +.x-window-header, +.x-window-header-default { + border-radius: var(--pm-radius-lg) var(--pm-radius-lg) 0 0 !important; +} + +.x-window .x-window-body, +.x-window-body-default { + border-radius: 0 !important; +} + +/* Buttons inside windows */ +.x-window .x-btn { + border-radius: var(--pm-radius-md) !important; +} + +/* Checkboxes inside windows */ +.x-window .x-form-checkbox { + border-radius: 3px !important; +} + +/* Form inputs inside windows */ +.x-window .x-form-trigger-wrap, +.x-window .x-form-trigger-wrap-default { + border-radius: var(--pm-radius-sm) !important; +} + +.x-window .x-form-text-wrap, +.x-window .x-form-text { + border-radius: var(--pm-radius-sm) 0 0 var(--pm-radius-sm) !important; +} + +.x-window .x-form-arrow-trigger { + border-radius: 0 var(--pm-radius-sm) var(--pm-radius-sm) 0 !important; +} + +/* Form trigger/text wrap — reset and re-apply */ +.x-form-trigger-wrap, +.x-form-trigger-wrap *, +.x-form-text-wrap, +.x-form-text-wrap *, +.x-form-text, +.x-form-trigger { + border-radius: 0 !important; +} + +.x-form-trigger-wrap, +.x-form-trigger-wrap-default { + border-radius: var(--pm-radius-sm) !important; + overflow: hidden !important; +} + +.x-form-text-wrap, +.x-form-text-wrap-default { + border-radius: var(--pm-radius-sm) 0 0 var(--pm-radius-sm) !important; +} + +.x-form-text, +.x-form-text-default { + border-radius: var(--pm-radius-sm) 0 0 var(--pm-radius-sm) !important; +} + +.x-form-trigger, +.x-form-trigger-default, +.x-form-arrow-trigger, +.x-form-arrow-trigger-default { + border-radius: 0 var(--pm-radius-sm) var(--pm-radius-sm) 0 !important; +} + +/* Dialog form content padding — vertical only (horizontal causes ExtJS overflow) */ +.x-window .x-tabpanel-child .x-autocontainer-innerCt { + padding: 12px 0 !important; +} + +/* Allow column panel bodies to show overflowed form content */ +.x-window .x-panel-body:not(.x-scroller) { + overflow: visible !important; +} + +/* Side padding on column panel bodies inside windows */ +.x-window .x-panel.x-box-item .x-panel-body { + padding: 0 4px !important; +} + +/* Constrain autocontainer width inside windows */ +.x-window .x-autocontainer-outerCt { + max-width: 100% !important; +} + +/* Fix window header/body width consistency */ +.x-window > .x-window-header, +.x-window > .x-window-body, +.x-window > .x-window-bodyWrap, +.x-window-bodyWrap > .x-window-body { + width: 100% !important; +} + +.x-window-header > .x-box-inner, +.x-window-header > .x-box-inner > .x-box-target { + width: 100% !important; +} + +.x-window-header-title { + width: auto !important; + flex: 1 !important; + max-width: calc(100% - 30px) !important; +} + +/* Boundlists */ +.x-boundlist { + border-radius: var(--pm-radius-md) !important; + overflow: hidden !important; +} + +/* ===================================================== + BASE / BODY + ===================================================== */ +.x-body, +.x-viewport > .x-body, +body.x-border-layout-ct, +div.x-border-layout-ct { + background-color: var(--nord-base) !important; + color: var(--nord-text) !important; +} + +/* ===================================================== + MASKS & OVERLAYS + ===================================================== */ +.x-mask { + background-color: rgba(30, 31, 41, 0.6) !important; + backdrop-filter: blur(4px); +} + +.x-mask-msg { + background-color: var(--nord-mantle) !important; + border: 1px solid var(--nord-surface1) !important; + border-radius: var(--pm-radius-lg) !important; +} + +.x-mask-msg-text { + color: var(--nord-subtext0) !important; + filter: none !important; +} + +.x-css-shadow { + box-shadow: 0 8px 24px rgba(30, 31, 41, 0.6) !important; +} + +/* Loading indicators */ +.x-grid-row-loading, +.x-treelist-item-loading .x-treelist-item-icon, +.x-grid-tree-loading .x-tree-icon { + filter: invert(90%); +} + +/* ===================================================== + ICONS — Proxmox default colors for dark mode + ===================================================== */ + +/* General icon colors — neutral gray for dark backgrounds */ +.x-tree-icon-custom, +.x-grid-icon-custom, +.fa-tags::before, +.fa-file-o::before, +.fa-building::before, +.x-action-col-icon::before, +.fa-shield::before, +.fa-file-text-o::before, +.fa-clock-o::before, +.x-tab-icon-el-default, +.pve-icon-verify-lettering::after, +.x-tree-icon-leaf:not(.x-tree-icon-custom)::before, +.x-tree-icon-parent:not(.x-tree-icon-custom)::before, +.x-tree-icon-parent-expanded:not(.x-tree-icon-custom)::before, +.x-grid-filters-filtered-column .x-column-header-text::after { + color: var(--nord-overlay2) !important; +} + +/* Folder icons — invert for dark mode */ +.x-tree-icon-parent:not(.x-tree-icon-custom)::before, +.x-tree-icon-parent-expanded:not(.x-tree-icon-custom)::before { + filter: invert(90%); +} + +/* Various image-based icons — invert for visibility */ +.fa-ceph::before, +.fa-sdn::before, +.fa-network-wired::before, +.pve-itype-treelist-item-icon-cdrom, +.fa-chevron-right::before, +.x-grid-row-console, +.x-box-scroller-toolbar-default.x-box-scroller, +.x-tree-elbow-img, +.pve-itype-icon-qemu, +.x-tree-node-computer, +.x-grid-tree-node-expanded .x-tree-node-computer, +.pbs-icon-tape, +.pbs-icon-tape-drive, +.x-tree-icon-leaf:not(.x-tree-icon-custom), +.x-tree-icon-parent:not(.x-tree-icon-custom), +.x-tree-icon-parent-expanded:not(.x-tree-icon-custom) { + filter: invert(90%); +} + +/* Hardware icons */ +.pve-itype-icon-cpu, +.pve-itype-icon-cdrom, +.pve-itype-icon-memory, +.pve-itype-icon-pci, +.pve-itype-icon-serial, +.pve-itype-icon-die, +.pmx-itype-icon-processor, +.pmx-itype-icon-memory, +.pve-itype-icon-storage, +.x-tree-node-harddisk, +.x-grid-tree-node-expanded .x-tree-node-harddisk { + filter: invert(100%); +} + +/* Hardware icons — counter-invert for non-SVG icon cells */ +td.pve-itype-icon-storage .x-grid-cell-inner, +td.x-tree-node-harddisk .x-grid-cell-inner { + filter: invert(100%) !important; +} + +/* Hardware icons — hide inverted borders for non-SVG icon cells */ +td.pve-itype-icon-storage, +td.x-tree-node-harddisk { + border-color: transparent !important; +} + +/* Hardware grid icons — mask-image renders SVG icons in theme text color + Replaces filter:invert approach for pve-itype-icon-* and pmx-itype-icon-* grid cells */ +td.pve-itype-icon-cpu, +td.pve-itype-icon-cdrom, +td.pve-itype-icon-memory, +td.pve-itype-icon-pci, +td.pve-itype-icon-serial, +td.pve-itype-icon-die, +td.pmx-itype-icon-processor, +td.pmx-itype-icon-memory { + filter: none !important; + background-image: none !important; + padding-left: 0 !important; + border-color: transparent !important; +} + +td.pve-itype-icon-cpu .x-grid-cell-inner, +td.pve-itype-icon-cdrom .x-grid-cell-inner, +td.pve-itype-icon-memory .x-grid-cell-inner, +td.pve-itype-icon-pci .x-grid-cell-inner, +td.pve-itype-icon-serial .x-grid-cell-inner, +td.pve-itype-icon-die .x-grid-cell-inner, +td.pmx-itype-icon-processor .x-grid-cell-inner, +td.pmx-itype-icon-memory .x-grid-cell-inner { + padding-left: 3px !important; +} + +td.pve-itype-icon-cpu .x-grid-cell-inner::before, +td.pve-itype-icon-cdrom .x-grid-cell-inner::before, +td.pve-itype-icon-memory .x-grid-cell-inner::before, +td.pve-itype-icon-pci .x-grid-cell-inner::before, +td.pve-itype-icon-serial .x-grid-cell-inner::before, +td.pve-itype-icon-die .x-grid-cell-inner::before, +td.pmx-itype-icon-processor .x-grid-cell-inner::before, +td.pmx-itype-icon-memory .x-grid-cell-inner::before { + content: '' !important; + display: inline-block !important; + width: 18px !important; + height: 14px !important; + vertical-align: middle !important; + margin-right: 10px !important; + background-color: currentColor !important; + -webkit-mask-size: contain !important; + mask-size: contain !important; + -webkit-mask-repeat: no-repeat !important; + mask-repeat: no-repeat !important; + -webkit-mask-position: center !important; + mask-position: center !important; +} + +td.pve-itype-icon-cpu .x-grid-cell-inner::before { + -webkit-mask-image: url('/pve2/images/icon-cpu.svg') !important; + mask-image: url('/pve2/images/icon-cpu.svg') !important; +} + +td.pve-itype-icon-memory .x-grid-cell-inner::before { + -webkit-mask-image: url('/pve2/images/icon-memory.svg') !important; + mask-image: url('/pve2/images/icon-memory.svg') !important; +} + +td.pve-itype-icon-cdrom .x-grid-cell-inner::before { + -webkit-mask-image: url('/pve2/images/icon-cd-drive.svg') !important; + mask-image: url('/pve2/images/icon-cd-drive.svg') !important; +} + +td.pve-itype-icon-pci .x-grid-cell-inner::before { + -webkit-mask-image: url('/pve2/images/icon-pci.svg') !important; + mask-image: url('/pve2/images/icon-pci.svg') !important; +} + +td.pve-itype-icon-serial .x-grid-cell-inner::before { + -webkit-mask-image: url('/pve2/images/icon-serial.svg') !important; + mask-image: url('/pve2/images/icon-serial.svg') !important; +} + +td.pve-itype-icon-die .x-grid-cell-inner::before { + -webkit-mask-image: url('/pve2/images/icon-die.svg') !important; + mask-image: url('/pve2/images/icon-die.svg') !important; +} + +td.pmx-itype-icon-processor .x-grid-cell-inner::before { + -webkit-mask-image: url('../images/icon-cpu.svg') !important; + mask-image: url('../images/icon-cpu.svg') !important; +} + +td.pmx-itype-icon-memory .x-grid-cell-inner::before { + -webkit-mask-image: url('../images/icon-ram.svg') !important; + mask-image: url('../images/icon-ram.svg') !important; +} + + +/* Icon overlays — default */ +.x-tree-icon-custom::after, +.x-grid-icon-custom::after { + color: var(--nord-overlay2) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* RUNNING VMs/CTs — Dracula Green */ +.x-tree-icon-custom.running::after, +.x-grid-icon-custom.running::after, +.x-treelist-item-icon.running::after { + color: var(--nord-green) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* ONLINE state — Green */ +.x-tree-icon-custom.online::after, +.x-grid-icon-custom.online::after { + color: var(--nord-green) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* Stopped/offline — Overlay1 (muted gray) */ +.x-tree-icon-custom.stopped, +.x-tree-icon-custom.offline, +.x-grid-icon-custom.stopped, +.x-grid-icon-custom.offline { + color: var(--nord-overlay1) !important; +} + +/* Unknown state — Overlay1 */ +.x-tree-icon-custom.unknown::after, +.x-grid-icon-custom.unknown::after { + color: var(--nord-overlay1) !important; +} + +/* ERROR states — Dracula Red */ +.x-tree-icon-custom.error::after, +.x-tree-icon-custom.offline::after, +.x-tree-icon-custom.ha-error::after, +.x-grid-icon-custom.error::after, +.x-grid-icon-custom.offline::after, +.x-grid-icon-custom.ha-error::after { + color: var(--nord-red) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* PAUSED/SUSPENDED — Dracula Orange */ +.x-tree-icon-custom.paused::after, +.x-tree-icon-custom.suspended::after, +.x-tree-icon-custom.lock-suspending::after, +.x-grid-icon-custom.paused::after, +.x-grid-icon-custom.suspended::after, +.x-grid-icon-custom.lock-suspending::after { + color: var(--nord-orange) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* PENDING/WARNING states — Dracula Yellow */ +.x-tree-icon-custom.pending::after, +.x-tree-icon-custom.io-error::after, +.x-tree-icon-custom.internal-error::after, +.x-tree-icon-custom.guest-panicked::after, +.x-grid-icon-custom.pending::after, +.x-grid-icon-custom.io-error::after, +.x-grid-icon-custom.internal-error::after, +.x-grid-icon-custom.guest-panicked::after { + color: var(--nord-yellow) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* HA MAINTENANCE — Dracula Cyan */ +.x-tree-icon-custom.ha-maintenance::after, +.x-grid-icon-custom.ha-maintenance::after { + color: var(--nord-cyan) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* Locked icons */ +.x-tree-icon-custom.locked::after, +.x-tree-icon-custom.lock-backup::after, +.x-tree-icon-custom.lock-migrate::after, +.x-tree-icon-custom.lock-suspended::after, +.x-grid-icon-custom.locked::after, +.x-grid-icon-custom.lock-backup::after, +.x-grid-icon-custom.lock-migrate::after, +.x-grid-icon-custom.lock-suspended::after { + color: var(--nord-overlay2) !important; +} + +/* LXC/QEMU type indicators */ +.x-tree-icon-custom.lxc::after, +.x-tree-icon-custom.qemu::after, +.x-grid-icon-custom.lxc::after, +.x-grid-icon-custom.qemu::after { + background-color: transparent; + color: var(--nord-overlay1) !important; +} + +.x-treelist-item-icon.lxc::after, +.x-treelist-item-icon.qemu::after { + background-color: transparent; + color: var(--nord-overlay1) !important; +} + +/* Tree expander arrows */ +.x-tree-arrows .x-tree-expander { + filter: brightness(200%); +} + +/* Cancel sprite-inversion on custom controls (checkboxes/radios handled via CSS) */ +.x-form-checkbox-default, +.x-form-radio-default, +.x-column-header-checkbox .x-column-header-checkbox::after, +.x-grid-checkcolumn::after, +.x-menu-item-checked .x-menu-item-icon-default.x-menu-item-checkbox, +.x-menu-item-unchecked .x-menu-item-icon-default.x-menu-item-checkbox { + filter: none !important; +} + +/* ===================================================== + PANELS & HEADERS + ===================================================== */ +.x-panel, +.x-panel-default { + border-radius: var(--pm-radius-lg) !important; + padding: 0 !important; +} + +/* Column panels — native stacked layout (Issue #23 fix) */ +.x-panel.x-column { + padding: 5px !important; + margin: 0 !important; + max-width: none !important; + box-sizing: border-box !important; +} + +/* Column panel card styling — borders for summary + chart panels */ +.x-panel.x-panel-default.x-column { + border: 1px solid var(--nord-surface1) !important; + border-radius: var(--pm-radius-lg) !important; + overflow: hidden !important; +} + +/* Guest status + Notes panel borders */ +[id^="pveGuestStatusView-"].x-panel, +[id^="pveLxcStatusView-"].x-panel, +[id^="pveQemuStatusView-"].x-panel, +[id^="pmxNotesView-"].x-panel { + border: 1px solid var(--nord-surface1) !important; + border-radius: var(--pm-radius-lg) !important; +} + +.x-panel-body, +.x-panel-body-default { + background-color: var(--nord-base) !important; + color: var(--nord-text) !important; + border: none !important; +} + +/* Panel headers — bottom border only */ +.x-panel-header, +.x-panel-header-default { + background-color: var(--nord-mantle) !important; + border: none !important; + border-bottom: 1px solid var(--nord-surface1) !important; + border-radius: var(--pm-radius-lg) var(--pm-radius-lg) 0 0 !important; + margin: 0 !important; + padding: 8px 12px !important; + width: 100% !important; + box-sizing: border-box !important; + overflow: visible !important; +} + +/* Title text — prevent border-radius clipping */ +.x-title-text, +.x-title-text-default { + overflow: visible !important; +} + +.x-panel-bodyWrap, +.x-panel-bodyWrap-default { + margin: 0 !important; + padding: 0 !important; + overflow: visible !important; +} + +/* Remove borders from nested panels */ +.x-panel-body > .x-box-layout-ct, +.x-panel-body > .x-container, +.x-panel-body > .x-box-inner, +[id*="pmxGauge"] { + border: none !important; +} + +.x-panel-header-title-default, +.x-window-header-title-default { + color: var(--nord-text) !important; +} + +.x-panel-header-default .x-tool-tool-el { + background-color: transparent; +} + +.x-tool-img { + filter: brightness(175%); +} + +.x-tool-over .x-tool-img { + filter: brightness(200%); +} + +/* Resource tree — panel body border */ +div[id^="pveResourceTree-"][id$="-body"] { + border-color: var(--nord-base) !important; +} + +/* Resource tree — remove row separators */ +[id^="pveResourceTree-"].x-tree-panel td.x-grid-cell, +[id^="pveResourceTree-"].x-tree-panel .x-grid-td, +[id^="pveResourceTree-"].x-tree-panel .x-grid-cell { + border-bottom: none !important; +} + +/* Resource tree — row spacing */ +div[id^="pveResourceTree"] .x-grid-cell { + padding-top: 3px !important; + padding-bottom: 3px !important; +} + +/* Summary/stats panel radius overrides */ +.pveStatusPanel, +.x-panel-default-framed, +.x-panel-body-default-framed { + border-radius: 12px !important; +} + +.x-panel-header-default-framed { + border-radius: 12px 12px 0 0 !important; +} + +/* Column widget panel radius */ +.x-panel.x-column > .x-panel-bodyWrap > .x-panel-body.x-panel-body-default { + border-radius: var(--pm-radius-lg) !important; +} + +/* ===================================================== + SPLITTERS / SEPARATORS + ===================================================== */ +.x-splitter-vertical { + background-color: transparent !important; + border-left: 1px solid var(--nord-surface1) !important; + border-right: none !important; + width: 1px !important; +} + +.x-splitter-horizontal { + background-color: var(--nord-crust) !important; + border-top: 1px solid var(--nord-surface1) !important; +} + +.x-splitter { + background-color: var(--nord-crust) !important; +} + +.x-keyboard-mode .x-splitter-focus::after { + border-color: var(--nord-purple) !important; +} + +.x-layout-split-bottom { + opacity: 0.7; +} + +/* Toolbox tree (pve-nav) right border — full height */ +.pve-toolbar-bg { + border-right: 1px solid var(--nord-surface1) !important; + z-index: 3 !important; +} + +.x-treelist.x-treelist-pve-nav { + border-right: none !important; +} + +/* ===================================================== + TOOLBARS + ===================================================== */ +.x-toolbar, +.x-toolbar-default { + background-color: var(--nord-base) !important; + border-color: var(--nord-surface1) !important; +} + +.x-toolbar-default.x-docked-top { + border: none !important; + border-bottom: 1px solid var(--nord-surface1) !important; +} + +.x-toolbar-default .x-toolbar-separator { + border-color: var(--nord-surface1); +} + +.x-toolbar-text-default { + color: var(--nord-subtext0); +} + +/* ===================================================== + PRIMARY BUTTONS — Dracula Purple + ===================================================== */ +.x-btn-default-small { + background-color: var(--nord-purple) !important; + border: 1px solid rgba(189, 147, 249, 0.4) !important; + border-radius: var(--pm-radius-md) !important; + transition: background-color 0.15s ease, box-shadow 0.15s ease !important; +} + +.x-btn-default-small .x-btn-inner { + color: var(--nord-on-accent) !important; + font-weight: 600 !important; +} + +.x-btn-default-small .x-btn-icon-el { + color: var(--nord-on-accent) !important; +} + +.x-btn-default-small.x-btn-over, +.x-keyboard-mode .x-btn-default-small.x-btn-focus { + background-color: #caa9fa !important; + box-shadow: 0 0 0 3px var(--nord-accent-subtle) !important; +} + +.x-btn-default-small.x-btn.x-btn-disabled { + background-color: var(--nord-purple) !important; + opacity: 0.4; +} + +.x-btn-default-small.x-btn.x-btn-pressed { + background-color: #a986f0 !important; +} + +/* Button height consistency — 28px with vertical centering */ +/* Exclude tag edit buttons (display:none when hidden, :has(.fa-check) for checkmark) */ +.x-btn.x-btn-default-small:not(.x-btn-default-toolbar-small):not([style*="display: none"]):not([style*="display:none"]):not(:has(.fa-check)) { + height: 28px !important; + min-height: 28px !important; + display: flex !important; + align-items: center !important; + padding: 3px 8px !important; +} + +/* Fix button inner element centering for proper icon alignment (issue #17) */ +.x-btn.x-btn-default-small:not(.x-btn-default-toolbar-small):not([style*="display: none"]):not([style*="display:none"]):not(:has(.fa-check)) .x-btn-wrap { + display: flex !important; + align-items: center !important; +} + +.x-btn.x-btn-default-small:not(.x-btn-default-toolbar-small):not([style*="display: none"]):not([style*="display:none"]):not(:has(.fa-check)) .x-btn-inner { + display: flex !important; + align-items: center !important; +} + +/* Fix dropdown arrows on split/arrow buttons */ +.x-btn-wrap.x-btn-arrow-right::after, +.x-btn-wrap.x-btn-split-right::after { + height: 16px !important; + min-height: 16px !important; + width: 20px !important; + display: flex !important; + align-items: center !important; +} + +/* Fix icon-only buttons — hide   inner element when button has no text */ +.x-btn-no-text .x-btn-inner, +.x-btn-button.x-btn-no-text .x-btn-inner, +.x-btn-button-default-toolbar-small.x-btn-no-text .x-btn-inner-default-toolbar-small, +.x-btn-button-default-small.x-btn-no-text .x-btn-inner-default-small, +.x-btn-button-default-small.x-btn-no-text > .x-btn-inner-default-small { + display: none !important; +} + +/* Specific fix for fa-desktop icon (Create VM) — visually bottom-heavy */ +.x-btn-icon-el.fa-desktop { + transform: translateY(1.1px) !important; +} + +/* ===================================================== + SECONDARY / TOOLBAR BUTTONS + ===================================================== */ +.x-btn-default-toolbar-small { + background-color: var(--nord-surface0) !important; + border: 1px solid var(--nord-surface1) !important; + border-radius: var(--pm-radius-md) !important; + transition: background-color 0.15s ease, border-color 0.15s ease !important; +} + +.x-btn-default-toolbar-small .x-btn-inner-default-toolbar-small, +.x-btn-default-toolbar-small .x-btn-icon-el-default-toolbar-small { + color: var(--nord-text) !important; +} + +.x-btn-default-toolbar-small .x-btn-wrap-default-toolbar-small.x-btn-arrow-right::after, +.x-btn-default-toolbar-small .x-btn-wrap-default-toolbar-small.x-btn-split-right::after { + filter: brightness(150%); +} + +.x-btn-default-toolbar-small.x-btn-over, +.x-keyboard-mode .x-btn-default-toolbar-small.x-btn-focus { + background-color: var(--nord-surface1) !important; + border-color: var(--nord-surface2) !important; +} + +.x-btn-default-toolbar-small.x-btn.x-btn-disabled { + background-color: var(--nord-surface0) !important; + opacity: 0.4; +} + +.x-btn-default-toolbar-small.x-btn.x-btn-menu-active, +.x-btn-default-toolbar-small.x-btn.x-btn-pressed { + background-color: var(--nord-purple) !important; + border-color: var(--nord-purple) !important; + padding: 4px 8px !important; /* Fix #30: prevent width change on dropdown */ +} + +.x-btn-default-toolbar-small.x-btn.x-btn-pressed .x-btn-inner-default-toolbar-small, +.x-btn-default-toolbar-small.x-btn.x-btn-pressed .x-btn-icon-el-default-toolbar-small, +.x-btn-default-toolbar-small.x-btn.x-btn-pressed .x-btn-inner-default-small, +.x-btn-default-toolbar-small.x-btn.x-btn-pressed .x-btn-icon-el-default-small { + color: var(--nord-on-accent) !important; +} + +/* Segmented buttons */ +.x-segmented-button { + border-radius: var(--pm-radius-md) !important; +} + +.x-segmented-button .x-btn, +.x-segmented-button .x-btn-default-small, +.x-segmented-button .x-btn-inner, +.x-segmented-button .x-btn-wrap { + border-radius: var(--pm-radius-md) !important; +} + +/* Inline buttons (Documentation, Help) */ +.proxmox-inline-button { + height: 28px !important; + min-height: 28px !important; + display: flex !important; + align-items: center !important; + padding: 3px 8px !important; + background-color: var(--nord-surface0) !important; + border: 1px solid var(--nord-surface1) !important; + border-radius: var(--pm-radius-md) !important; + color: var(--nord-text) !important; + transition: background-color 0.15s ease !important; +} + +.proxmox-inline-button:hover, +.proxmox-inline-button.x-btn-over { + background-color: var(--nord-surface1) !important; + border-color: var(--nord-overlay0) !important; +} + +.proxmox-inline-button:active, +.proxmox-inline-button.x-btn-pressed { + background-color: var(--nord-surface2) !important; +} + +.proxmox-inline-button .x-btn-inner, +.proxmox-inline-button .x-btn-icon-el { + color: var(--nord-text) !important; +} + +/* Pressed/active inline buttons — use on-accent text */ +.proxmox-inline-button.x-btn-pressed .x-btn-inner, +.proxmox-inline-button.x-btn-pressed .x-btn-icon-el, +.proxmox-inline-button.x-btn-menu-active .x-btn-inner, +.proxmox-inline-button.x-btn-menu-active .x-btn-icon-el { + color: var(--nord-on-accent) !important; +} + +/* ===================================================== + FORM ELEMENTS + ===================================================== */ +.x-form-trigger-default { + background-color: var(--nord-surface0) !important; +} + +.x-form-text-default { + background-color: var(--nord-surface0) !important; + color: var(--nord-text) !important; + border-radius: var(--pm-radius-sm) !important; +} + +.x-form-trigger-wrap, +.x-form-trigger-wrap-default { + border-color: var(--nord-surface1) !important; + background-color: var(--nord-surface0) !important; + border-radius: var(--pm-radius-sm) !important; + transition: border-color 0.15s ease !important; +} + +.x-form-trigger-wrap-default.x-form-trigger-wrap-focus { + border-color: var(--nord-purple) !important; + box-shadow: 0 0 0 3px var(--nord-accent-subtle) !important; +} + +.x-form-item-label-default, +.x-form-cb-label-default { + color: var(--nord-text) !important; +} + +.x-form-display-field-default { + color: var(--nord-subtext0) !important; + border-radius: var(--pm-radius-md) !important; +} + +.x-form-spinner-default { + background-color: var(--nord-surface0) !important; +} + +.x-fieldset, +.x-fieldset-default { + border-color: var(--nord-surface1) !important; + border-radius: var(--pm-radius-lg) !important; +} + +.x-fieldset-header-default > .x-fieldset-header-text { + color: var(--nord-text) !important; +} + +/* ===================================================== + CHECKBOXES & RADIOS — Dracula styled + ===================================================== */ + +/* Base: remove sprite, styled as custom control */ +.x-form-checkbox, .x-form-checkbox-default, +.x-form-radio, .x-form-radio-default { + background-image: none !important; + background-color: var(--nord-surface0) !important; + border: 1.5px solid var(--nord-overlay0) !important; + width: 16px !important; + height: 16px !important; + display: inline-block !important; + box-sizing: border-box !important; + cursor: pointer !important; + transition: border-color 0.12s ease, background-color 0.12s ease !important; +} + +/* Checkbox: rounded square */ +.x-form-checkbox, .x-form-checkbox-default { + border-radius: 3px !important; +} + +/* Radio: circle + ::after inner dot */ +.x-form-radio, .x-form-radio-default { + border-radius: 50% !important; + position: relative !important; + transform: translateZ(0) !important; + box-shadow: inset 0 0 0 0 transparent !important; +} + +.x-form-radio::after { + content: '' !important; + position: absolute !important; + top: 50% !important; + left: 50% !important; + width: 7px !important; + height: 7px !important; + border-radius: 50% !important; + background: transparent !important; + transform: translate(-50%, -50%) scale(0) !important; + transition: transform 0.15s ease, background 0.15s ease !important; + pointer-events: none !important; +} + +/* Hover */ +.x-form-checkbox:hover, .x-form-checkbox-default:hover, +.x-form-cb-wrap:hover .x-form-checkbox { + border-color: var(--nord-purple) !important; +} + +.x-form-radio:hover, .x-form-radio-default:hover, +.x-form-cb-wrap:hover .x-form-radio { + border-color: var(--nord-purple) !important; +} + +/* CHECKED checkbox — Purple fill + dark SVG checkmark */ +.x-form-cb-checked .x-form-checkbox, +.x-form-cb-checked .x-form-checkbox-default { + background-color: var(--nord-purple) !important; + border-color: var(--nord-purple) !important; + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 8'%3E%3Cpath d='M1 4l3 3 5-6' fill='none' stroke='%232e3440' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") !important; + background-repeat: no-repeat !important; + background-position: center !important; + background-size: 9px 7px !important; +} + +/* SELECTED radio — Purple dot */ +.x-form-cb-checked .x-form-radio, +.x-form-cb-checked .x-form-radio-default { + border-color: var(--nord-purple) !important; + background-color: var(--nord-base) !important; +} + +.x-form-cb-checked .x-form-radio::after { + background: var(--nord-purple) !important; + transform: translate(-50%, -50%) scale(1) !important; +} + +/* ===================================================== + BOUNDLIST / DROPDOWNS + ===================================================== */ +.x-boundlist { + background-color: var(--nord-mantle) !important; + border: 1px solid var(--nord-surface1) !important; + border-radius: var(--pm-radius-md) !important; + box-shadow: 0 8px 24px rgba(30, 31, 41, 0.7) !important; + padding: 2px !important; + overflow: hidden !important; +} + +.x-boundlist-item { + background-color: transparent !important; + color: var(--nord-text) !important; + border-radius: var(--pm-radius-sm) !important; + padding: 2px 6px !important; + line-height: normal !important; + border: none !important; + cursor: pointer !important; + outline: none !important; + box-shadow: none !important; +} + +.x-boundlist-selected { + background-color: var(--nord-select-overlay) !important; + color: var(--nord-text) !important; +} + +.x-boundlist-item-over { + background-color: var(--nord-hover-overlay) !important; +} + +/* ===================================================== + GRIDS / TABLES + ===================================================== */ +.x-grid, +.x-grid-view { + border-radius: 0 !important; +} + +.x-column-header { + border-color: var(--nord-surface1) !important; + background-color: transparent !important; +} + +.x-column-header-inner, +.x-column-header-text { + color: var(--nord-text) !important; + font-weight: 600 !important; +} + +.x-column-header-trigger { + border-color: var(--nord-surface1) !important; +} + +.x-grid-item, +.x-column-header-default, +.x-grid-cell-row-numberer { + color: var(--nord-text) !important; + background-color: var(--nord-base) !important; +} + +.x-grid-cell-special { + border-color: var(--nord-surface1) !important; +} + +.x-grid-group-hd { + background-color: var(--nord-base) !important; + border-color: var(--nord-surface1) !important; +} + +.x-grid-group-title { + color: var(--nord-text) !important; +} + +.x-grid-header-ct { + background-color: var(--nord-mantle) !important; + border: 1px solid var(--nord-surface0) !important; + border-radius: var(--pm-radius-lg) var(--pm-radius-lg) 0 0 !important; +} + +.x-grid-item-alt { + background-color: var(--nord-crust) !important; +} + +.x-grid-with-row-lines .x-grid-item { + border-color: var(--nord-surface0) !important; +} + +.x-grid-cell { + border-bottom: 1px solid rgba(68, 71, 90, 0.4) !important; +} + +.x-grid-item-over, +.x-grid-with-row-lines .x-grid-item.x-grid-item-over { + background-color: var(--nord-hover-overlay) !important; +} + +.x-grid-item-selected, +.x-grid-with-row-lines .x-grid-item.x-grid-item-selected { + background-color: var(--nord-select-overlay) !important; +} + +.x-column-header-over, +.x-column-header-open { + background-color: var(--nord-hover-overlay) !important; +} + +.x-column-header-sort-ASC, +.x-column-header-sort-DESC { + background-color: var(--nord-hover-overlay) !important; +} + +.x-grid-row-summary .x-grid-cell, +.x-grid-row-summary .x-grid-rowwrap, +.x-grid-row-summary .x-grid-cell-rowbody { + background-color: var(--nord-base) !important; + border-color: var(--nord-surface1); +} + +.x-grid-with-col-lines .x-grid-cell, +.x-grid-with-col-lines .x-grid-item-over .x-grid-cell, +.x-grid-with-col-lines .x-grid-item-selected .x-grid-cell { + border-color: var(--nord-surface1) !important; +} + +.x-dd-drag-proxy { + background-color: var(--nord-mantle); + border-color: var(--nord-surface1); + color: var(--nord-text); +} + +.x-keyboard-mode .x-grid-item-focused { + background-color: var(--nord-hover-overlay) !important; + color: var(--nord-text) !important; +} + +/* Remove blue outline from focused/selected items in resource tree */ +.x-keyboard-mode .x-grid-item-focused .x-grid-cell-inner::before, +.x-keyboard-mode .x-grid-item-selected .x-grid-cell-inner::before, +.x-grid-item-selected .x-grid-cell-inner::before, +.x-grid-item-focused .x-grid-cell-inner::before, +[id^="pveResourceTree"] .x-grid-item-selected .x-grid-cell-inner::before, +[id^="pveResourceTree"] .x-grid-item-focused .x-grid-cell-inner::before { + content: none !important; + display: none !important; + border: none !important; +} + +.x-grid-empty { + background-color: var(--nord-base) !important; + color: var(--nord-subtext0) !important; +} + +/* Grid info (pve-info-grid) and RRD view */ +.pve-info-grid { + border-radius: 12px !important; +} + +.pve-rrdview, +.rrdview { + border-radius: 12px !important; +} + +.pve-summary-status, +.x-container .pve-status { + border-radius: var(--pm-radius-lg) !important; +} + +[id^="pveGuestStatusView-"][id$="-body"], +[id^="pmxNotesView-"] .x-panel-body { + border-radius: var(--pm-radius-lg) !important; +} + +.x-panel-default[id*="notes"], +.pve-notes-view { + border-radius: var(--pm-radius-lg) !important; +} + +/* Floating grid pickers (storage/ISO selectors) */ +.x-layer.x-grid .x-grid-view, +.x-panel.x-layer.x-grid .x-grid-view, +.x-panel.x-layer.x-grid, +.x-layer.x-panel.x-grid { + border-radius: var(--pm-radius-sm) !important; +} + +.x-layer.x-grid .x-grid-item-over, +.x-layer.x-grid .x-grid-item-selected, +.x-panel.x-layer.x-grid .x-grid-item-over, +.x-panel.x-layer.x-grid .x-grid-item-selected { + border-radius: var(--pm-radius-sm) !important; + outline: none !important; + box-shadow: none !important; +} + +.x-layer.x-grid .x-grid-item-over td, +.x-layer.x-grid .x-grid-item-selected td, +.x-layer.x-grid .x-grid-item-over .x-grid-cell, +.x-layer.x-grid .x-grid-item-selected .x-grid-cell, +.x-panel.x-layer.x-grid .x-grid-item-over td, +.x-panel.x-layer.x-grid .x-grid-item-selected td, +.x-panel.x-layer.x-grid .x-grid-item-over .x-grid-cell, +.x-panel.x-layer.x-grid .x-grid-item-selected .x-grid-cell { + border-radius: 0 !important; +} + +.x-layer.x-grid .x-grid-item-over td:first-child, +.x-layer.x-grid .x-grid-item-selected td:first-child, +.x-panel.x-layer.x-grid .x-grid-item-over td:first-child, +.x-panel.x-layer.x-grid .x-grid-item-selected td:first-child { + border-radius: var(--pm-radius-sm) 0 0 var(--pm-radius-sm) !important; +} + +.x-layer.x-grid .x-grid-item-over td:last-child, +.x-layer.x-grid .x-grid-item-selected td:last-child, +.x-panel.x-layer.x-grid .x-grid-item-over td:last-child, +.x-panel.x-layer.x-grid .x-grid-item-selected td:last-child { + border-radius: 0 var(--pm-radius-sm) var(--pm-radius-sm) 0 !important; +} + +/* ===================================================== + MENUS + ===================================================== */ +.x-menu, +.x-menu-default { + background-color: var(--nord-crust) !important; + border: 1px solid var(--nord-surface0) !important; + border-radius: var(--pm-radius-lg) !important; + box-shadow: 0 8px 24px rgba(30, 31, 41, 0.8) !important; + padding: 4px !important; + overflow: hidden !important; +} + +.x-menu-body-default { + background-color: transparent !important; + padding: 4px !important; +} + +.x-menu-header { + background-color: transparent !important; + color: var(--nord-text) !important; +} + +/* Menu icon separator — hide */ +.x-menu-icon-separator-default { + display: none !important; +} + +/* Menu item layout (flexbox reordering) */ +.x-menu-item-default > .x-menu-item-link { + display: flex !important; + align-items: center !important; + flex-direction: row !important; + gap: 4px !important; + justify-content: flex-start !important; + flex-wrap: nowrap !important; + border-radius: var(--pm-radius-md) !important; + padding: 4px 8px !important; + line-height: 20px !important; + border: none !important; + cursor: pointer !important; + outline: none !important; + box-shadow: none !important; + white-space: nowrap !important; + text-decoration: none !important; +} + +.x-menu-item-text-default { + color: var(--nord-text) !important; + font-size: 13px !important; + order: 1 !important; + margin-left: 0 !important; + text-align: left !important; + line-height: 20px !important; + display: inline-flex !important; + align-items: center !important; + flex: 1 1 auto !important; + width: auto !important; + white-space: nowrap !important; +} + +.x-menu-item-icon-default { + color: var(--nord-subtext0) !important; + order: -1 !important; + position: relative !important; + float: none !important; + margin-right: 8px !important; + margin-left: 0 !important; + left: auto !important; + top: auto !important; + width: 16px !important; + text-align: center !important; + display: inline-flex !important; + align-items: center !important; + justify-content: center !important; + height: 20px !important; + line-height: 20px !important; + vertical-align: middle !important; + flex: 0 0 16px !important; + align-self: center !important; +} + +.x-menu-item-arrow, +.x-menu-item-arrow-default { + order: 2 !important; + margin-left: auto !important; +} + +.x-menu-item-default.x-menu-item-separator { + background-color: var(--nord-surface0) !important; + border: none !important; + height: 1px !important; + margin: 6px 4px !important; +} + +.x-menu-item-default.x-menu-item-focus, +.x-menu-item-default.x-menu-item-active, +.x-menu-item:hover { + background-color: var(--nord-surface0) !important; + color: var(--nord-text) !important; + border-radius: var(--pm-radius-md) !important; +} + +.x-menu-item-active .x-menu-item-text-default, +.x-menu-item-focus .x-menu-item-text-default { + color: var(--nord-text) !important; +} + +.x-menu-item-active .x-menu-item-icon-default, +.x-menu-item-focus .x-menu-item-icon-default { + color: var(--nord-cyan) !important; +} + +/* ===================================================== + PROGRESS BARS + ===================================================== */ + +/* Fix: Widget containers need overflow visible to not clip progress bars */ +.x-container[id^="pmxInfoWidget"], +.x-container.x-box-layout-ct { + overflow: visible !important; +} + +.x-progress, +.x-progress-default { + background-color: var(--nord-surface0) !important; + border-radius: 5px !important; +} + +.x-progress-default .x-progress-bar-default { + background-color: var(--nord-purple) !important; + border-radius: 5px !important; + transition: width 0.4s ease !important; +} + +.x-progress-default .x-progress-text { + color: var(--nord-text) !important; +} + +/* Text overlaid on the progress bar fill — use on-accent for contrast */ +.x-progress-bar .x-progress-text { + color: var(--nord-on-accent) !important; +} + +.x-progress.warning .x-progress-bar { + background-color: var(--nord-yellow) !important; +} + +.x-progress.critical .x-progress-bar { + background-color: var(--nord-red) !important; +} + +/* ===================================================== + TABS — Dracula underline style + Flat tabs with Purple underline on active tab + ===================================================== */ +.x-tab-bar, +.x-tab-bar-default { + background-color: var(--nord-base) !important; + border-radius: 0 !important; + border-bottom: 1px solid var(--nord-surface1) !important; + padding-bottom: 0 !important; +} + +/* Overflow visible for the underline indicator */ +.x-tab-bar .x-box-inner, +.x-tab-bar .x-box-target, +.x-tab-bar-body, +.x-tab-bar-body-default { + overflow: visible !important; +} + +/* Base tab */ +.x-tab, +.x-tab-default, +.x-tab-default-top { + background-color: transparent !important; + border: none !important; + border-radius: var(--pm-radius-md) var(--pm-radius-md) 0 0 !important; + padding: 8px 16px 8px !important; + overflow: visible !important; + margin-bottom: 0 !important; + transition: color 0.15s ease !important; + outline: none !important; + box-shadow: none !important; +} + +/* Remove ::after from inactive tabs */ +.x-tab::after { + display: none !important; +} + +.x-tab-inner-default { + color: var(--nord-subtext0) !important; + font-size: 13px !important; +} + +.x-tab-default.x-tab-over { + background-color: transparent !important; +} + +.x-tab-default.x-tab-over .x-tab-inner-default { + color: var(--nord-text) !important; +} + +/* Active tab */ +.x-tab-default.x-tab.x-tab-active { + background-color: transparent !important; + border: none !important; + overflow: visible !important; + margin-bottom: 0 !important; + outline: none !important; + box-shadow: none !important; +} + +/* Purple underline indicator on active tab */ +.x-tab-default.x-tab.x-tab-active::after { + content: '' !important; + display: block !important; + position: absolute !important; + bottom: 0 !important; + left: 0 !important; + right: 0 !important; + height: 2px !important; + background: var(--nord-purple) !important; + z-index: 10 !important; + border-radius: 2px 2px 0 0 !important; + pointer-events: none !important; +} + +.x-tab-active .x-tab-inner-default { + color: var(--nord-text) !important; + font-weight: 600 !important; +} + +.x-tab-default.x-tab.x-tab-disabled { + background-color: transparent !important; + border: none !important; + color: var(--nord-overlay0) !important; + margin-bottom: 0 !important; +} + +/* Focus states — no outline */ +.x-keyboard-mode .x-tab-default.x-tab-focus, +.x-keyboard-mode .x-tab-default.x-tab-focus.x-tab-active { + background-color: transparent !important; + border: none !important; + outline: none !important; + box-shadow: none !important; + margin-bottom: 0 !important; +} + +.x-keyboard-mode .x-tab-default.x-tab-focus.x-tab-active::after { + content: '' !important; + display: block !important; + position: absolute !important; + bottom: 0 !important; + left: 0 !important; + right: 0 !important; + height: 2px !important; + background: var(--nord-purple) !important; + z-index: 10 !important; + pointer-events: none !important; +} + +/* Kill ALL tab interaction outlines/shadows */ +.x-tab:focus, +.x-tab *:focus, +.x-tab-focus, +.x-tab-active.x-tab-focus, +.x-tab-inner-focus, +.x-tab-button-focus, +.x-tab-pressed, +.x-tab-active.x-tab-pressed, +.x-tab-over, +.x-tab:active, +.x-tab *:active { + outline: none !important; + box-shadow: none !important; +} + +.x-tabpanel-child { + border-radius: 0 0 var(--pm-radius-lg) var(--pm-radius-lg) !important; +} + +/* Tab hover/active corners */ +.x-tab-default.x-tab-over, +.x-tab-default.x-tab.x-tab-active { + border-radius: var(--pm-radius-md) var(--pm-radius-md) 0 0 !important; +} + +/* ===================================================== + TOOLTIPS + ===================================================== */ +.x-tip, +.x-tip-default { + background-color: var(--nord-mantle) !important; + border: 1px solid var(--nord-surface1) !important; + border-radius: var(--pm-radius-md) !important; + box-shadow: 0 4px 12px rgba(30, 31, 41, 0.5); +} + +.x-tip-body-default { + color: var(--nord-text) !important; +} + +.x-tip-form-invalid { + background-color: var(--nord-mantle) !important; + border-color: var(--nord-red) !important; +} + +.x-tip-body-form-invalid { + color: var(--nord-red) !important; +} + +/* ===================================================== + TREE NAVIGATION (Sidebar) + ===================================================== */ +.x-treelist-item { + background-color: var(--nord-base) !important; + border-radius: var(--pm-radius-md) !important; +} + +/* Pseudo-element approach for hover/selected highlighting */ +.x-treelist-row { + border-radius: var(--pm-radius-md) !important; + background-color: transparent !important; + position: relative !important; + z-index: 0 !important; +} + +.x-treelist-row::before { + content: ""; + position: absolute; + top: 1px; + bottom: 1px; + left: 0; + right: 4px; + border-radius: var(--pm-radius-md); + background-color: transparent; + z-index: -1; + pointer-events: none; + transition: background-color 0.15s ease; +} + +/* Fix toolbox tree item text overlapping icons */ +.x-treelist-item-text { + margin-left: 28px !important; +} + +/* Toolbox tree items — bright text */ +.x-treelist-item-text, +.x-treelist-item-icon, +.x-treelist.x-treelist-pve-nav .x-treelist-item-text, +.x-treelist.x-treelist-pve-nav .x-treelist-item-icon { + color: var(--nord-subtext1) !important; +} + +/* Hover state — apply to pseudo-element */ +.x-treelist-row-over { + background-color: transparent !important; +} + +.x-treelist-row-over::before { + background-color: var(--nord-hover-overlay) !important; +} + +.x-treelist-row-over .x-treelist-item-icon, +.x-treelist-row-over .x-treelist-item-text { + background-color: transparent !important; + color: var(--nord-text) !important; +} + +/* Selected/active item — Purple highlight */ +.x-treelist-item-selected > .x-treelist-row { + background-color: transparent !important; +} + +.x-treelist-item-selected > .x-treelist-row::before, +.x-treelist-item-selected > .x-treelist-row:hover::before { + background-color: var(--nord-purple) !important; +} + +.x-treelist-item-selected .x-treelist-item-text, +.x-treelist-item-selected .x-treelist-item-icon, +.x-treelist.x-treelist-pve-nav .x-treelist-item-selected .x-treelist-item-text, +.x-treelist.x-treelist-pve-nav .x-treelist-item-selected .x-treelist-item-icon { + color: var(--nord-on-accent) !important; +} + +.x-treelist-pve-nav { + background-color: var(--nord-base) !important; + border-color: var(--nord-surface1) !important; +} + +/* Tree navigation radius overrides */ +.x-treelist-item, +.x-treelist-item-tool { + border-radius: var(--pm-radius-sm) !important; +} + +.x-treelist-row, +.x-treelist-row:hover, +.x-treelist-row-over, +.x-treelist-item-selected > .x-treelist-row, +.x-treelist-item-selected > .x-treelist-row:hover, +.x-treelist-item-expanded > .x-treelist-row, +.x-treelist-item-expanded > .x-treelist-row-over, +.x-treelist-item-expandable > .x-treelist-row, +.x-treelist-item-expandable > .x-treelist-row-over { + border-radius: var(--pm-radius-sm) !important; +} + +.x-treelist-row::before { + border-radius: var(--pm-radius-sm) !important; +} + +.x-treelist-item-wrap, +.x-treelist-item-text, +.x-treelist-row, +.x-treelist-container, +.x-treelist-root-container, +.x-treelist, +.x-treelist-pve-nav { + border-radius: var(--pm-radius-sm) !important; +} + +/* Cursor pointer for interactive tree/grid items */ +.x-grid-cell, +.x-grid-cell-inner, +.x-tree-elbow-img, +.x-tree-icon, +.x-treelist-item, +.x-treelist-row, +.x-treelist-item-wrap, +.x-treelist-item-text, +.x-treelist-item-icon { + cursor: pointer !important; +} + +/* ===================================================== + WINDOWS / MODALS + ===================================================== */ +.x-window, +.x-window-default { + background-color: var(--nord-crust) !important; + border: 1px solid var(--nord-surface1) !important; + border-radius: var(--pm-radius-lg) !important; + box-shadow: 0 8px 24px rgba(30, 31, 41, 0.6) !important; + overflow: hidden !important; +} + +.x-window .x-window-header, +.x-window-header-default { + background-color: var(--nord-mantle) !important; + border-color: transparent !important; + border-radius: var(--pm-radius-lg) var(--pm-radius-lg) 0 0 !important; +} + +.x-window-header-default .x-mask { + background-color: rgba(30, 31, 41, 0.7); +} + +.x-window .x-window-body, +.x-window-body-default { + background-color: var(--nord-base) !important; + border-color: var(--nord-surface1) !important; + color: var(--nord-text) !important; + border-radius: 0 0 var(--pm-radius-lg) var(--pm-radius-lg) !important; +} + +.x-window-ghost { + background-color: var(--nord-base) !important; +} + +.x-window-header-default .x-tool-img { + background-color: transparent; +} + +.x-message-box .x-window-body { + background-color: var(--nord-mantle) !important; +} + +/* Respect ExtJS inline display:none on hidden dialog buttons */ +.x-message-box .x-btn.x-btn-default-small[style*="display: none"], +.x-message-box .x-btn.x-btn-default-small[style*="display:none"], +.x-window .x-toolbar-footer .x-btn[style*="display: none"], +.x-window .x-toolbar-footer .x-btn[style*="display:none"] { + display: none !important; +} + +/* Login dialog — clean inner panel borders */ +.x-window:has(#pveloginrealm) .x-panel-body { + border: none !important; + background: transparent !important; + width: auto !important; +} + +/* ===================================================== + CONSOLE / TERMINAL + ===================================================== */ +div.monitor { + border-color: var(--nord-surface1); +} + +.install-mask { + background-color: var(--nord-crust); + color: var(--nord-subtext0); +} + +.x-window.install-mask { + box-shadow: rgba(30, 31, 41, 0.5) 0 4px 20px !important; +} + +/* ===================================================== + LEGEND / CHARTS + ===================================================== */ +.x-legend-container { + background-color: var(--nord-base) !important; +} + +.x-legend-horizontal .x-legend-item { + background-color: var(--nord-mantle) !important; + color: var(--nord-text) !important; + border: 1px solid var(--nord-surface0) !important; +} + +/* Chart/RRD panel backgrounds */ +div[id*="rrdchart"], +.pve-rrddatastore, +.pmx-panel-rrd { + background-color: var(--nord-base) !important; +} + +.proxmox-rrd-panel canvas, +.proxmox-widget-toolkit canvas, +canvas.x-surface, +.x-surface canvas { + background-color: transparent !important; + opacity: 1 !important; +} + +.proxmox-rrd-panel, +.proxmox-rrd-chart { + background-color: var(--nord-base) !important; +} + +/* Chart text/labels */ +.x-surface text, +svg text { + fill: var(--nord-text) !important; +} + +/* ===================================================== + PROXMOX-SPECIFIC OVERRIDES + ===================================================== */ + +/* Logo inversion */ +img[id^="proxmoxlogo-"][id$="-img"], +img[id^="proxmoxLogoSvg-"][id$="-img"] { + filter: invert(1) hue-rotate(180deg); +} + +/* Invalid/warning/disabled rows */ +.proxmox-invalid-row { + background-color: rgba(255, 85, 85, 0.15) !important; +} + +.proxmox-warning-row { + background-color: rgba(255, 184, 108, 0.15) !important; +} + +.proxmox-disabled-row td { + color: var(--nord-overlay0) !important; +} + +/* Hints */ +.pmx-hint { + background-color: rgba(255, 184, 108, 0.15) !important; + white-space: nowrap !important; +} + +.pmx-hint a { + color: var(--nord-cyan) !important; +} + +/* Status text colors — Information → Cyan */ +.info-blue { + color: var(--nord-cyan) !important; +} + +.critical { + color: var(--nord-red) !important; +} + +/* Links */ +a { + color: var(--nord-cyan) !important; +} + +/* Markdown content */ +.pmx-md code { + background-color: var(--nord-mantle) !important; + color: var(--nord-pink) !important; + border-radius: var(--pm-radius-sm) !important; +} + +.pmx-md pre code { + border-color: var(--nord-surface1) !important; + background-color: var(--nord-crust) !important; +} + +.pmx-md a { + color: var(--nord-cyan) !important; +} + +.pmx-md table { + border-color: var(--nord-surface1) !important; +} + +.pmx-md th { + background-color: var(--nord-mantle) !important; + border-color: var(--nord-surface1) !important; +} + +.pmx-md td { + border-color: var(--nord-surface1) !important; +} + +/* APT repos */ +.proxmox-apt-repos .x-grid-group-hd { + background-color: var(--nord-base) !important; + border: none !important; +} + +.proxmox-apt-repos .x-grid-group-title { + color: var(--nord-text) !important; +} + +/* Tags */ +.pve-edit-tag { + border-radius: var(--pm-radius-md) !important; +} + +.pve-edit-tag.editable span { + background-color: var(--nord-mantle) !important; + color: var(--nord-text) !important; + border-color: var(--nord-surface1) !important; +} + +.x-tree-node-text .proxmox-tag-dark, +.x-tree-node-text .proxmox-tag-light, +.x-grid-cell-inner .proxmox-tag-dark, +.x-grid-cell-inner .proxmox-tag-light, +span.proxmox-tag-dark, +span.proxmox-tag-light { + border-radius: var(--pm-radius-md) !important; +} + +/* Checkmark button in tag edit — match toolbar button size */ +.x-btn.x-btn-default-small:has(.fa-check) { + min-height: 24px !important; + height: 24px !important; + padding: 3px 8px !important; + border-radius: var(--pm-radius-sm) !important; + background-color: var(--nord-purple) !important; + border: none !important; +} + +.x-btn.x-btn-default-small:has(.fa-check).x-btn-disabled { + background-color: transparent !important; + border: 1px solid var(--nord-surface1) !important; + opacity: 0.5 !important; +} + +.x-btn.x-btn-default-small:has(.fa-check) .fa-check { + color: var(--nord-on-accent) !important; +} + +.x-btn.x-btn-default-small:has(.fa-check).x-btn-disabled .fa-check { + color: var(--nord-overlay1) !important; +} + +.x-btn.x-btn-default-small:has(.fa-check):not(.x-btn-disabled):hover { + background-color: #caa9fa !important; +} + +.x-btn.x-btn-default-small:has(.fa-check) .x-btn-inner { + display: none !important; +} + +/* Date picker */ +.x-datepicker, +.x-datepicker-column-header, +.x-monthpicker { + background-color: var(--nord-base) !important; + color: var(--nord-text) !important; + border-color: transparent !important; +} + +.x-datepicker-header, +.x-datepicker-footer, +.x-monthpicker-buttons { + background-color: var(--nord-mantle) !important; +} + +.x-datepicker-date, +.x-monthpicker-item-inner { + color: var(--nord-text) !important; +} + +.x-datepicker-selected div.x-datepicker-date, +.x-monthpicker-item a.x-monthpicker-selected, +a.x-monthpicker-item-inner:hover, +div.x-datepicker-date:hover { + background-color: var(--nord-hover-overlay) !important; + color: var(--nord-text) !important; +} + +.x-datepicker-today .x-datepicker-date { + border-color: var(--nord-purple) !important; +} + +.x-datepicker-disabled .x-datepicker-date { + color: var(--nord-overlay0) !important; +} + +.x-datepicker-prev-day .x-datepicker-date, +.x-datepicker-next-day .x-datepicker-date { + color: var(--nord-overlay0) !important; +} + +/* Usage bars */ +.usage-wrapper, +.usage { + border-radius: 2px !important; +} + +.usage { + background-color: var(--nord-overlay2) !important; +} + +/* ===================================================== + SCROLLBARS + ===================================================== */ +::-webkit-scrollbar { + width: 8px; + height: 8px; +} + +::-webkit-scrollbar-track { + background: var(--nord-base); + border-radius: var(--pm-radius-sm); +} + +::-webkit-scrollbar-thumb { + background: var(--nord-surface2); + border-radius: var(--pm-radius-sm); + border: 1px solid transparent; + background-clip: padding-box; + transition: background 0.15s ease; +} + +::-webkit-scrollbar-thumb:hover { + background: var(--nord-overlay0); +} + +::-webkit-scrollbar-corner { + background: var(--nord-base); +} + +/* Firefox scrollbar */ +* { + scrollbar-width: thin; + scrollbar-color: var(--nord-surface2) var(--nord-base); +} + +/* ===================================================== + SELECTION HIGHLIGHT + ===================================================== */ +::selection { + background-color: rgba(98, 114, 164, 0.3); + color: var(--nord-text); +} + +/* ===================================================== + TRANSITIONS (smooth interactions) + ===================================================== */ + +/* Grid row transitions */ +.x-grid-item { + transition: background-color 0.15s ease !important; +} + +/* Tree pseudo-element transitions */ +.x-treelist-row::before { + transition: background-color 0.15s ease !important; +} + +/* Menu item transitions */ +.x-menu-item-default > .x-menu-item-link { + transition: background-color 0.12s ease !important; +} + +/* Boundlist item transitions */ +.x-boundlist-item { + transition: background-color 0.12s ease !important; +} + +/* Tab transitions */ +.x-tab { + transition: color 0.15s ease !important; +} + +/* Splitter transition */ +.x-splitter { + transition: background-color 0.15s ease !important; +} + +/* Tooltip transition */ +.x-tip { + transition: opacity 0.15s ease !important; +} + +/* Progress bar width transition */ +.x-progress-bar { + transition: width 0.4s ease !important; +} + +/* Scrollbar thumb transition */ +::-webkit-scrollbar-thumb { + transition: background 0.15s ease !important; +} + +/* Window close tool transition */ +.x-tool-img { + transition: filter 0.15s ease !important; +} +/* ===================================================== + TOOL ICONS - FontAwesome Replacements + (Ported from UniFi v5.86) + Replace sprite-based ExtJS tool icons with crisp + FontAwesome icons for better consistency and clarity + ===================================================== */ + +/* Base styling for all tool icons - remove sprite backgrounds */ +.x-tool-tool-el.x-tool-minus, +.x-tool-img.x-tool-minus, +.x-tool-tool-el.x-tool-collapse-right, +.x-tool-img.x-tool-collapse-right, +.x-tool-tool-el.x-tool-collapse-left, +.x-tool-img.x-tool-collapse-left, +.x-tool-tool-el.x-tool-expand-right, +.x-tool-img.x-tool-expand-right, +.x-tool-tool-el.x-tool-expand-left, +.x-tool-img.x-tool-expand-left, +.x-tool-tool-el.x-tool-maximize, +.x-tool-img.x-tool-maximize, +.x-tool-tool-el.x-tool-restore, +.x-tool-img.x-tool-restore, +.x-tool-tool-el.x-tool-gear, +.x-tool-img.x-tool-gear, +.x-tool-tool-el.x-tool-refresh, +.x-tool-img.x-tool-refresh, +.x-tool-tool-el.x-tool-close, +.x-tool-img.x-tool-close { + background-image: none !important; + font-family: "FontAwesome" !important; + font-size: 14px !important; + line-height: 16px !important; + text-align: center !important; + color: var(--pm-text-dim) !important; + transition: color 0.15s ease !important; + filter: none !important; + width: 16px !important; + height: 16px !important; + display: flex !important; + align-items: center !important; + justify-content: center !important; +} + +/* Close button - slightly larger */ +.x-tool-tool-el.x-tool-close, +.x-tool-img.x-tool-close { + font-size: 20px !important; +} + +/* Individual glyph assignments */ +.x-tool-tool-el.x-tool-minus::before, +.x-tool-img.x-tool-minus::before { + content: "\f010" !important; /* fa-search-minus (zoom out) */ +} + +.x-tool-tool-el.x-tool-collapse-right::before, +.x-tool-img.x-tool-collapse-right::before { + content: "\f054" !important; /* fa-chevron-right */ +} + +.x-tool-tool-el.x-tool-expand-left::before, +.x-tool-img.x-tool-expand-left::before { + content: "\f053" !important; /* fa-chevron-left */ +} + +.x-tool-tool-el.x-tool-collapse-left::before, +.x-tool-img.x-tool-collapse-left::before { + content: "\f053" !important; /* fa-chevron-left */ +} + +.x-tool-tool-el.x-tool-expand-right::before, +.x-tool-img.x-tool-expand-right::before { + content: "\f054" !important; /* fa-chevron-right */ +} + +.x-tool-tool-el.x-tool-maximize::before, +.x-tool-img.x-tool-maximize::before { + content: "\f065" !important; /* fa-expand */ +} + +.x-tool-tool-el.x-tool-restore::before, +.x-tool-img.x-tool-restore::before { + content: "\f066" !important; /* fa-compress */ +} + +.x-tool-tool-el.x-tool-gear::before, +.x-tool-img.x-tool-gear::before { + content: "\f013" !important; /* fa-cog */ +} + +.x-tool-tool-el.x-tool-refresh::before, +.x-tool-img.x-tool-refresh::before { + content: "\f021" !important; /* fa-refresh */ +} + +.x-tool-tool-el.x-tool-close::before, +.x-tool-img.x-tool-close::before { + content: "\f00d" !important; /* fa-times */ +} + +/* Hover state - all tool icons */ +.x-tool:hover .x-tool-tool-el.x-tool-minus, +.x-tool:hover .x-tool-img.x-tool-minus, +.x-tool:hover .x-tool-tool-el.x-tool-collapse-right, +.x-tool:hover .x-tool-img.x-tool-collapse-right, +.x-tool:hover .x-tool-tool-el.x-tool-collapse-left, +.x-tool:hover .x-tool-img.x-tool-collapse-left, +.x-tool:hover .x-tool-tool-el.x-tool-expand-right, +.x-tool:hover .x-tool-img.x-tool-expand-right, +.x-tool:hover .x-tool-tool-el.x-tool-expand-left, +.x-tool:hover .x-tool-img.x-tool-expand-left, +.x-tool:hover .x-tool-tool-el.x-tool-maximize, +.x-tool:hover .x-tool-img.x-tool-maximize, +.x-tool:hover .x-tool-tool-el.x-tool-restore, +.x-tool:hover .x-tool-img.x-tool-restore, +.x-tool:hover .x-tool-tool-el.x-tool-gear, +.x-tool:hover .x-tool-img.x-tool-gear, +.x-tool:hover .x-tool-tool-el.x-tool-refresh, +.x-tool:hover .x-tool-img.x-tool-refresh, +.x-tool:hover .x-tool-tool-el.x-tool-close, +.x-tool:hover .x-tool-img.x-tool-close { + color: var(--pm-text) !important; +} + +/* Disabled state */ +.x-tool-disabled .x-tool-tool-el, +.x-tool-disabled .x-tool-img { + opacity: 0.4 !important; + cursor: default !important; +} + +/* Inline FontAwesome tools (PVE-injected) */ +.x-tool-tool-el[style*="font-family:FontAwesome"], +.x-tool-tool-el[style*="font-family: FontAwesome"] { + color: var(--pm-text-dim) !important; + font-size: 14px !important; + line-height: 16px !important; + display: flex !important; + align-items: center !important; + justify-content: center !important; + width: 16px !important; + height: 16px !important; + transition: color 0.15s ease !important; + background-image: none !important; + background-color: transparent !important; +} + +.x-tool:not(.x-tool-disabled) .x-tool-tool-el[style*="font-family:FontAwesome"], +.x-tool:not(.x-tool-disabled) .x-tool-tool-el[style*="font-family: FontAwesome"] { + cursor: pointer !important; +} + +.x-tool.x-tool-disabled .x-tool-tool-el[style*="font-family:FontAwesome"], +.x-tool.x-tool-disabled .x-tool-tool-el[style*="font-family: FontAwesome"] { + cursor: default !important; + opacity: 0.4 !important; +} + +.x-tool .x-mask { + background-color: transparent !important; + backdrop-filter: none !important; + pointer-events: none !important; +} + +.x-tool:not(.x-tool-disabled):hover .x-tool-tool-el[style*="font-family:FontAwesome"], +.x-tool:not(.x-tool-disabled):hover .x-tool-tool-el[style*="font-family: FontAwesome"] { + color: var(--pm-text) !important; +} diff --git a/themes/theme-nord-light.css b/themes/theme-nord-light.css new file mode 100644 index 0000000..a079fe4 --- /dev/null +++ b/themes/theme-nord-light.css @@ -0,0 +1,2237 @@ +/*!Nord Light*/ + +/* ===================================================== + CSS VARIABLES + ===================================================== */ +:root { + /* Theme: Nord Light */ + --pm-accent: #5e81ac; + --pm-bg-base: #eceff4; + --pm-bg-surface: #e5e9f0; + --pm-bg-elevated: #d8dee9; + --pm-text: #2e3440; + --pm-text-dim: #3b4252; + --pm-success: #8fbcbb; + --pm-warning: #d08770; + --pm-error: #bf616a; + --pm-border: #d8dee9; + --pm-radius-sm: 4px; + --pm-radius-md: 6px; + --pm-radius-lg: 8px; + + /* Proxmox Widget Toolkit Mappings */ + --pwt-panel-background: var(--pm-bg-base); + --pwt-text-color: var(--pm-text); + --pwt-gauge-default: var(--pm-accent); + --pwt-gauge-back: var(--pm-bg-elevated); + --pwt-gauge-warn: var(--pm-warning); + --pwt-gauge-crit: var(--pm-error); + --pwt-chart-primary: var(--pm-accent); + --pwt-chart-grid-stroke: var(--pm-bg-elevated); + + /* Nord theme internal variables (based on Dracula template structure) */ + --nord-text: var(--pm-text); + --nord-subtext0: var(--pm-text-dim); + --nord-subtext1: var(--pm-text-dim); + --nord-overlay0: var(--pm-border); + --nord-overlay1: var(--pm-text-dim); + --nord-overlay2: var(--pm-text-dim); + --nord-surface0: var(--pm-bg-surface); + --nord-surface1: var(--pm-bg-elevated); + --nord-surface2: var(--pm-bg-elevated); + --nord-base: var(--pm-bg-base); + --nord-mantle: #e5e9f0; + --nord-crust: #e5e9f0; + + --nord-on-accent: #eceff4; + --nord-hover-overlay: rgba(128, 128, 128, 0.12); + --nord-select-overlay: rgba(128, 128, 128, 0.25); + --nord-accent-muted: rgba(128, 128, 128, 0.4); + --nord-accent-subtle: rgba(128, 128, 128, 0.15); + + --nord-cyan: var(--pm-accent); + --nord-green: var(--pm-success); + --nord-orange: var(--pm-warning); + --nord-pink: var(--pm-accent); + --nord-purple: var(--pm-accent); + --nord-red: var(--pm-error); + --nord-yellow: var(--pm-warning); + + color-scheme: light; +} + +/* ===================================================== + GLOBAL BORDER-RADIUS ARCHITECTURE + (Ported from UniFi theme — reset everything, selectively re-apply) + ===================================================== */ +.x-border-box, +.x-border-box * { + border-radius: var(--pm-radius-lg); +} + +/* Remove rounded corners from grids/tables/lists */ +.x-grid, +.x-grid *, +.x-grid-header-ct, +.x-grid-header-ct *, +.x-grid-view, +.x-grid-view *, +.x-column-header, +.x-column-header *, +.x-grid-item, +.x-grid-cell, +.x-grid-cell-inner, +.x-grid-row, +table, +table *, +tr, +td, +th, +.x-legend, +.x-legend *, +.x-legend-container, +.x-legend-container *, +.x-legend-item, +.x-legend-horizontal .x-legend-item, +.x-legend-vertical .x-legend-item, +.x-legend-horizontal .x-legend-item:first-child, +.x-legend-horizontal .x-legend-item:last-child, +.x-legend-vertical .x-legend-item:first-child, +.x-legend-vertical .x-legend-item:last-child, +.x-tool, +.x-tool-tool-el, +.x-tool-default, +.x-tool-img { + border-radius: 0 !important; +} + +/* Form elements - exclude from global radius */ +.x-form-item, +.x-form-item-default, +.x-form-item-body, +.x-form-item-body-default, +.x-form-text-field-body, +.x-form-text-field-body-default, +.x-form-fieldcontainer, +.x-field, +.x-field-default, +.x-form-type-text { + border-radius: 0 !important; +} + +/* Reset layout containers that clip elements with overflow:hidden + radius */ +.x-box-layout-ct, +.x-panel-bodyWrap, +.x-panel-bodyWrap-default, +.x-autocontainer-innerCt, +.x-autocontainer-outerCt, +.x-panel.x-tabpanel-child, +.x-panel.x-box-item, +.x-box-inner, +.x-box-target, +.x-container, +.x-container-default, +.x-window .x-panel-body, +.x-window .x-window-body, +.x-window .x-window-bodyWrap { + border-radius: 0 !important; +} + +/* Reset everything inside windows to 0 — then re-apply specific radii */ +.x-window *, +.x-window .x-autocontainer-innerCt, +.x-window .x-autocontainer-outerCt, +.x-window .x-form-layout-wrap, +.x-window .x-form-layout-auto-label, +.x-window .x-form-layout-colgroup, +.x-window .x-form-layout-column, +.x-window .x-field, +.x-window .x-form-item, +.x-window .x-form-item-body { + border-radius: 0 !important; +} + +/* Chart canvas — no radius on data area */ +.x-chart-grid, +.x-chart-axis, +canvas.x-surface, +.x-chart canvas, +canvas.x-surface-canvas, +.x-surface-canvas, +.x-draw-component canvas, +.proxmox-rrd-chart canvas, +svg.x-surface, +.x-draw-container, +.x-surface { + border-radius: 0 !important; +} + +/* Legend color marker (dot) — keep circular */ +.x-legend-item-marker { + border-radius: 50% !important; +} + +/* ===================================================== + RE-APPLY BORDER RADII (selective) + ===================================================== */ + +/* Windows */ +.x-window, +.x-window-default { + border-radius: var(--pm-radius-lg) !important; +} + +.x-window-header, +.x-window-header-default { + border-radius: var(--pm-radius-lg) var(--pm-radius-lg) 0 0 !important; +} + +.x-window .x-window-body, +.x-window-body-default { + border-radius: 0 !important; +} + +/* Buttons inside windows */ +.x-window .x-btn { + border-radius: var(--pm-radius-md) !important; +} + +/* Checkboxes inside windows */ +.x-window .x-form-checkbox { + border-radius: 3px !important; +} + +/* Form inputs inside windows */ +.x-window .x-form-trigger-wrap, +.x-window .x-form-trigger-wrap-default { + border-radius: var(--pm-radius-sm) !important; +} + +.x-window .x-form-text-wrap, +.x-window .x-form-text { + border-radius: var(--pm-radius-sm) 0 0 var(--pm-radius-sm) !important; +} + +.x-window .x-form-arrow-trigger { + border-radius: 0 var(--pm-radius-sm) var(--pm-radius-sm) 0 !important; +} + +/* Form trigger/text wrap — reset and re-apply */ +.x-form-trigger-wrap, +.x-form-trigger-wrap *, +.x-form-text-wrap, +.x-form-text-wrap *, +.x-form-text, +.x-form-trigger { + border-radius: 0 !important; +} + +.x-form-trigger-wrap, +.x-form-trigger-wrap-default { + border-radius: var(--pm-radius-sm) !important; + overflow: hidden !important; +} + +.x-form-text-wrap, +.x-form-text-wrap-default { + border-radius: var(--pm-radius-sm) 0 0 var(--pm-radius-sm) !important; +} + +.x-form-text, +.x-form-text-default { + border-radius: var(--pm-radius-sm) 0 0 var(--pm-radius-sm) !important; +} + +.x-form-trigger, +.x-form-trigger-default, +.x-form-arrow-trigger, +.x-form-arrow-trigger-default { + border-radius: 0 var(--pm-radius-sm) var(--pm-radius-sm) 0 !important; +} + +/* Dialog form content padding — vertical only (horizontal causes ExtJS overflow) */ +.x-window .x-tabpanel-child .x-autocontainer-innerCt { + padding: 12px 0 !important; +} + +/* Allow column panel bodies to show overflowed form content */ +.x-window .x-panel-body:not(.x-scroller) { + overflow: visible !important; +} + +/* Side padding on column panel bodies inside windows */ +.x-window .x-panel.x-box-item .x-panel-body { + padding: 0 4px !important; +} + +/* Constrain autocontainer width inside windows */ +.x-window .x-autocontainer-outerCt { + max-width: 100% !important; +} + +/* Fix window header/body width consistency */ +.x-window > .x-window-header, +.x-window > .x-window-body, +.x-window > .x-window-bodyWrap, +.x-window-bodyWrap > .x-window-body { + width: 100% !important; +} + +.x-window-header > .x-box-inner, +.x-window-header > .x-box-inner > .x-box-target { + width: 100% !important; +} + +.x-window-header-title { + width: auto !important; + flex: 1 !important; + max-width: calc(100% - 30px) !important; +} + +/* Boundlists */ +.x-boundlist { + border-radius: var(--pm-radius-md) !important; + overflow: hidden !important; +} + +/* ===================================================== + BASE / BODY + ===================================================== */ +.x-body, +.x-viewport > .x-body, +body.x-border-layout-ct, +div.x-border-layout-ct { + background-color: var(--nord-base) !important; + color: var(--nord-text) !important; +} + +/* ===================================================== + MASKS & OVERLAYS + ===================================================== */ +.x-mask { + background-color: rgba(30, 31, 41, 0.6) !important; + backdrop-filter: blur(4px); +} + +.x-mask-msg { + background-color: var(--nord-mantle) !important; + border: 1px solid var(--nord-surface1) !important; + border-radius: var(--pm-radius-lg) !important; +} + +.x-mask-msg-text { + color: var(--nord-subtext0) !important; + filter: none !important; +} + +.x-css-shadow { + box-shadow: 0 8px 24px rgba(30, 31, 41, 0.6) !important; +} + +/* Loading indicators */ +.x-grid-row-loading, +.x-treelist-item-loading .x-treelist-item-icon, +.x-grid-tree-loading .x-tree-icon { + filter: none; +} + +/* ===================================================== + ICONS — Proxmox default colors for dark mode + ===================================================== */ + +/* General icon colors — neutral gray for dark backgrounds */ +.x-tree-icon-custom, +.x-grid-icon-custom, +.fa-tags::before, +.fa-file-o::before, +.fa-building::before, +.x-action-col-icon::before, +.fa-shield::before, +.fa-file-text-o::before, +.fa-clock-o::before, +.x-tab-icon-el-default, +.pve-icon-verify-lettering::after, +.x-tree-icon-leaf:not(.x-tree-icon-custom)::before, +.x-tree-icon-parent:not(.x-tree-icon-custom)::before, +.x-tree-icon-parent-expanded:not(.x-tree-icon-custom)::before, +.x-grid-filters-filtered-column .x-column-header-text::after { + color: var(--nord-overlay2) !important; +} + +/* Folder icons — invert for dark mode */ +.x-tree-icon-parent:not(.x-tree-icon-custom)::before, +.x-tree-icon-parent-expanded:not(.x-tree-icon-custom)::before { + filter: none; +} + +/* Various image-based icons — invert for visibility */ +.fa-ceph::before, +.fa-sdn::before, +.fa-network-wired::before, +.pve-itype-treelist-item-icon-cdrom, +.fa-chevron-right::before, +.x-grid-row-console, +.x-box-scroller-toolbar-default.x-box-scroller, +.x-tree-elbow-img, +.pve-itype-icon-qemu, +.x-tree-node-computer, +.x-grid-tree-node-expanded .x-tree-node-computer, +.pbs-icon-tape, +.pbs-icon-tape-drive, +.x-tree-icon-leaf:not(.x-tree-icon-custom), +.x-tree-icon-parent:not(.x-tree-icon-custom), +.x-tree-icon-parent-expanded:not(.x-tree-icon-custom) { + filter: none; +} + +/* Hardware icons */ +.pve-itype-icon-cpu, +.pve-itype-icon-cdrom, +.pve-itype-icon-memory, +.pve-itype-icon-pci, +.pve-itype-icon-serial, +.pve-itype-icon-die, +.pmx-itype-icon-processor, +.pmx-itype-icon-memory, +.pve-itype-icon-storage, +.x-tree-node-harddisk, +.x-grid-tree-node-expanded .x-tree-node-harddisk { + filter: none; +} + +/* Icon overlays — default */ +.x-tree-icon-custom::after, +.x-grid-icon-custom::after { + color: var(--nord-overlay2) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* RUNNING VMs/CTs — Dracula Green */ +.x-tree-icon-custom.running::after, +.x-grid-icon-custom.running::after, +.x-treelist-item-icon.running::after { + color: var(--nord-green) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* ONLINE state — Green */ +.x-tree-icon-custom.online::after, +.x-grid-icon-custom.online::after { + color: var(--nord-green) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* Stopped/offline — Overlay1 (muted gray) */ +.x-tree-icon-custom.stopped, +.x-tree-icon-custom.offline, +.x-grid-icon-custom.stopped, +.x-grid-icon-custom.offline { + color: var(--nord-overlay1) !important; +} + +/* Unknown state — Overlay1 */ +.x-tree-icon-custom.unknown::after, +.x-grid-icon-custom.unknown::after { + color: var(--nord-overlay1) !important; +} + +/* ERROR states — Dracula Red */ +.x-tree-icon-custom.error::after, +.x-tree-icon-custom.offline::after, +.x-tree-icon-custom.ha-error::after, +.x-grid-icon-custom.error::after, +.x-grid-icon-custom.offline::after, +.x-grid-icon-custom.ha-error::after { + color: var(--nord-red) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* PAUSED/SUSPENDED — Dracula Orange */ +.x-tree-icon-custom.paused::after, +.x-tree-icon-custom.suspended::after, +.x-tree-icon-custom.lock-suspending::after, +.x-grid-icon-custom.paused::after, +.x-grid-icon-custom.suspended::after, +.x-grid-icon-custom.lock-suspending::after { + color: var(--nord-orange) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* PENDING/WARNING states — Dracula Yellow */ +.x-tree-icon-custom.pending::after, +.x-tree-icon-custom.io-error::after, +.x-tree-icon-custom.internal-error::after, +.x-tree-icon-custom.guest-panicked::after, +.x-grid-icon-custom.pending::after, +.x-grid-icon-custom.io-error::after, +.x-grid-icon-custom.internal-error::after, +.x-grid-icon-custom.guest-panicked::after { + color: var(--nord-yellow) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* HA MAINTENANCE — Dracula Cyan */ +.x-tree-icon-custom.ha-maintenance::after, +.x-grid-icon-custom.ha-maintenance::after { + color: var(--nord-cyan) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* Locked icons */ +.x-tree-icon-custom.locked::after, +.x-tree-icon-custom.lock-backup::after, +.x-tree-icon-custom.lock-migrate::after, +.x-tree-icon-custom.lock-suspended::after, +.x-grid-icon-custom.locked::after, +.x-grid-icon-custom.lock-backup::after, +.x-grid-icon-custom.lock-migrate::after, +.x-grid-icon-custom.lock-suspended::after { + color: var(--nord-overlay2) !important; +} + +/* LXC/QEMU type indicators */ +.x-tree-icon-custom.lxc::after, +.x-tree-icon-custom.qemu::after, +.x-grid-icon-custom.lxc::after, +.x-grid-icon-custom.qemu::after { + background-color: transparent; + color: var(--nord-overlay1) !important; +} + +.x-treelist-item-icon.lxc::after, +.x-treelist-item-icon.qemu::after { + background-color: transparent; + color: var(--nord-overlay1) !important; +} + +/* Tree expander arrows */ +.x-tree-arrows .x-tree-expander { + filter: none; +} + +/* Cancel sprite-inversion on custom controls (checkboxes/radios handled via CSS) */ +.x-form-checkbox-default, +.x-form-radio-default, +.x-column-header-checkbox .x-column-header-checkbox::after, +.x-grid-checkcolumn::after, +.x-menu-item-checked .x-menu-item-icon-default.x-menu-item-checkbox, +.x-menu-item-unchecked .x-menu-item-icon-default.x-menu-item-checkbox { + filter: none !important; +} + +/* ===================================================== + PANELS & HEADERS + ===================================================== */ +.x-panel, +.x-panel-default { + border-radius: var(--pm-radius-lg) !important; + padding: 0 !important; +} + +/* Column panels — gaps + max-width prevents scrollbar-induced sub-pixel overflow */ +.x-panel.x-column { + padding: 5px !important; + margin: 0 !important; + max-width: none !important; + box-sizing: border-box !important; +} + +/* Column panel card styling — borders for summary + chart panels */ +.x-panel.x-panel-default.x-column { + border: 1px solid var(--nord-surface1) !important; + border-radius: var(--pm-radius-lg) !important; + overflow: hidden !important; +} + +/* Guest status + Notes panel borders */ +[id^="pveGuestStatusView-"].x-panel, +[id^="pveLxcStatusView-"].x-panel, +[id^="pveQemuStatusView-"].x-panel, +[id^="pmxNotesView-"].x-panel { + border: 1px solid var(--nord-surface1) !important; + border-radius: var(--pm-radius-lg) !important; +} + +.x-panel-body, +.x-panel-body-default { + background-color: var(--nord-base) !important; + color: var(--nord-text) !important; + border: none !important; +} + +/* Panel headers — bottom border only */ +.x-panel-header, +.x-panel-header-default { + background-color: var(--nord-mantle) !important; + border: none !important; + border-bottom: 1px solid var(--nord-surface1) !important; + border-radius: var(--pm-radius-lg) var(--pm-radius-lg) 0 0 !important; + margin: 0 !important; + padding: 8px 12px !important; + width: 100% !important; + box-sizing: border-box !important; + overflow: visible !important; +} + +/* Title text — prevent border-radius clipping */ +.x-title-text, +.x-title-text-default { + overflow: visible !important; +} + +.x-panel-bodyWrap, +.x-panel-bodyWrap-default { + margin: 0 !important; + padding: 0 !important; + overflow: visible !important; +} + +/* Remove borders from nested panels */ +.x-panel-body > .x-box-layout-ct, +.x-panel-body > .x-container, +.x-panel-body > .x-box-inner, +[id*="pmxGauge"] { + border: none !important; +} + +.x-panel-header-title-default, +.x-window-header-title-default { + color: var(--nord-text) !important; +} + +.x-panel-header-default .x-tool-tool-el { + background-color: transparent; +} + +.x-tool-img { + filter: none; +} + +.x-tool-over .x-tool-img { + filter: none; +} + +/* Resource tree — panel body border */ +div[id^="pveResourceTree-"][id$="-body"] { + border-color: var(--nord-base) !important; +} + +/* Resource tree — remove row separators */ +[id^="pveResourceTree-"].x-tree-panel td.x-grid-cell, +[id^="pveResourceTree-"].x-tree-panel .x-grid-td, +[id^="pveResourceTree-"].x-tree-panel .x-grid-cell { + border-bottom: none !important; +} + +/* Resource tree — row spacing */ +div[id^="pveResourceTree"] .x-grid-cell { + padding-top: 3px !important; + padding-bottom: 3px !important; +} + +/* Summary/stats panel radius overrides */ +.pveStatusPanel, +.x-panel-default-framed, +.x-panel-body-default-framed { + border-radius: 12px !important; +} + +.x-panel-header-default-framed { + border-radius: 12px 12px 0 0 !important; +} + +/* Column widget panel radius */ +.x-panel.x-column > .x-panel-bodyWrap > .x-panel-body.x-panel-body-default { + border-radius: var(--pm-radius-lg) !important; +} + +/* ===================================================== + SPLITTERS / SEPARATORS + ===================================================== */ +.x-splitter-vertical { + background-color: transparent !important; + border-left: 1px solid var(--nord-surface1) !important; + border-right: none !important; + width: 1px !important; +} + +.x-splitter-horizontal { + background-color: var(--nord-crust) !important; + border-top: 1px solid var(--nord-surface1) !important; +} + +.x-splitter { + background-color: var(--nord-crust) !important; +} + +.x-keyboard-mode .x-splitter-focus::after { + border-color: var(--nord-purple) !important; +} + +.x-layout-split-bottom { + opacity: 0.7; +} + +/* Toolbox tree (pve-nav) right border — full height */ +.pve-toolbar-bg { + border-right: 1px solid var(--nord-surface1) !important; + z-index: 3 !important; +} + +.x-treelist.x-treelist-pve-nav { + border-right: none !important; +} + +/* ===================================================== + TOOLBARS + ===================================================== */ +.x-toolbar, +.x-toolbar-default { + background-color: var(--nord-base) !important; + border-color: var(--nord-surface1) !important; +} + +.x-toolbar-default.x-docked-top { + border: none !important; + border-bottom: 1px solid var(--nord-surface1) !important; +} + +.x-toolbar-default .x-toolbar-separator { + border-color: var(--nord-surface1); +} + +.x-toolbar-text-default { + color: var(--nord-subtext0); +} + +/* ===================================================== + PRIMARY BUTTONS — Dracula Purple + ===================================================== */ +.x-btn-default-small { + background-color: var(--nord-purple) !important; + border: 1px solid rgba(189, 147, 249, 0.4) !important; + border-radius: var(--pm-radius-md) !important; + transition: background-color 0.15s ease, box-shadow 0.15s ease !important; +} + +.x-btn-default-small .x-btn-inner { + color: var(--nord-on-accent) !important; + font-weight: 600 !important; +} + +.x-btn-default-small .x-btn-icon-el { + color: var(--nord-on-accent) !important; +} + +.x-btn-default-small.x-btn-over, +.x-keyboard-mode .x-btn-default-small.x-btn-focus { + background-color: #caa9fa !important; + box-shadow: 0 0 0 3px var(--nord-accent-subtle) !important; +} + +.x-btn-default-small.x-btn.x-btn-disabled { + background-color: var(--nord-purple) !important; + opacity: 0.4; +} + +.x-btn-default-small.x-btn.x-btn-pressed { + background-color: #a986f0 !important; +} + +/* Button height consistency — 28px with vertical centering */ +/* Exclude tag edit buttons (display:none when hidden, :has(.fa-check) for checkmark) */ +.x-btn.x-btn-default-small:not(.x-btn-default-toolbar-small):not([style*="display: none"]):not([style*="display:none"]):not(:has(.fa-check)) { + height: 28px !important; + min-height: 28px !important; + display: flex !important; + align-items: center !important; + padding: 3px 8px !important; +} + +/* Fix button inner element centering for proper icon alignment (issue #17) */ +.x-btn.x-btn-default-small:not(.x-btn-default-toolbar-small):not([style*="display: none"]):not([style*="display:none"]):not(:has(.fa-check)) .x-btn-wrap { + display: flex !important; + align-items: center !important; +} + +.x-btn.x-btn-default-small:not(.x-btn-default-toolbar-small):not([style*="display: none"]):not([style*="display:none"]):not(:has(.fa-check)) .x-btn-inner { + display: flex !important; + align-items: center !important; +} + +/* Fix dropdown arrows on split/arrow buttons */ +.x-btn-wrap.x-btn-arrow-right::after, +.x-btn-wrap.x-btn-split-right::after { + height: 16px !important; + min-height: 16px !important; + width: 20px !important; + display: flex !important; + align-items: center !important; +} + +/* Fix icon-only buttons — hide   inner element when button has no text */ +.x-btn-no-text .x-btn-inner, +.x-btn-button.x-btn-no-text .x-btn-inner, +.x-btn-button-default-toolbar-small.x-btn-no-text .x-btn-inner-default-toolbar-small, +.x-btn-button-default-small.x-btn-no-text .x-btn-inner-default-small, +.x-btn-button-default-small.x-btn-no-text > .x-btn-inner-default-small { + display: none !important; +} + +/* Specific fix for fa-desktop icon (Create VM) — visually bottom-heavy */ +.x-btn-icon-el.fa-desktop { + transform: translateY(1.1px) !important; +} + +/* ===================================================== + SECONDARY / TOOLBAR BUTTONS + ===================================================== */ +.x-btn-default-toolbar-small { + background-color: var(--nord-surface0) !important; + border: 1px solid var(--nord-surface1) !important; + border-radius: var(--pm-radius-md) !important; + transition: background-color 0.15s ease, border-color 0.15s ease !important; +} + +.x-btn-default-toolbar-small .x-btn-inner-default-toolbar-small, +.x-btn-default-toolbar-small .x-btn-icon-el-default-toolbar-small { + color: var(--nord-text) !important; +} + +.x-btn-default-toolbar-small .x-btn-wrap-default-toolbar-small.x-btn-arrow-right::after, +.x-btn-default-toolbar-small .x-btn-wrap-default-toolbar-small.x-btn-split-right::after { + filter: none; +} + +.x-btn-default-toolbar-small.x-btn-over, +.x-keyboard-mode .x-btn-default-toolbar-small.x-btn-focus { + background-color: var(--nord-surface1) !important; + border-color: var(--nord-surface2) !important; +} + +.x-btn-default-toolbar-small.x-btn.x-btn-disabled { + background-color: var(--nord-surface0) !important; + opacity: 0.4; +} + +.x-btn-default-toolbar-small.x-btn.x-btn-menu-active, +.x-btn-default-toolbar-small.x-btn.x-btn-pressed { + background-color: var(--nord-purple) !important; + border-color: var(--nord-purple) !important; + padding: 4px 8px !important; /* Fix #30: prevent width change on dropdown */ +} + +.x-btn-default-toolbar-small.x-btn.x-btn-pressed .x-btn-inner-default-toolbar-small, +.x-btn-default-toolbar-small.x-btn.x-btn-pressed .x-btn-icon-el-default-toolbar-small, +.x-btn-default-toolbar-small.x-btn.x-btn-pressed .x-btn-inner-default-small, +.x-btn-default-toolbar-small.x-btn.x-btn-pressed .x-btn-icon-el-default-small { + color: var(--nord-on-accent) !important; +} + +/* Segmented buttons */ +.x-segmented-button { + border-radius: var(--pm-radius-md) !important; +} + +.x-segmented-button .x-btn, +.x-segmented-button .x-btn-default-small, +.x-segmented-button .x-btn-inner, +.x-segmented-button .x-btn-wrap { + border-radius: var(--pm-radius-md) !important; +} + +/* Inline buttons (Documentation, Help) */ +.proxmox-inline-button { + height: 28px !important; + min-height: 28px !important; + display: flex !important; + align-items: center !important; + padding: 3px 8px !important; + background-color: var(--nord-surface0) !important; + border: 1px solid var(--nord-surface1) !important; + border-radius: var(--pm-radius-md) !important; + color: var(--nord-text) !important; + transition: background-color 0.15s ease !important; +} + +.proxmox-inline-button:hover, +.proxmox-inline-button.x-btn-over { + background-color: var(--nord-surface1) !important; + border-color: var(--nord-overlay0) !important; +} + +.proxmox-inline-button:active, +.proxmox-inline-button.x-btn-pressed { + background-color: var(--nord-surface2) !important; +} + +.proxmox-inline-button .x-btn-inner, +.proxmox-inline-button .x-btn-icon-el { + color: var(--nord-text) !important; +} + +/* Pressed/active inline buttons — use on-accent text */ +.proxmox-inline-button.x-btn-pressed .x-btn-inner, +.proxmox-inline-button.x-btn-pressed .x-btn-icon-el, +.proxmox-inline-button.x-btn-menu-active .x-btn-inner, +.proxmox-inline-button.x-btn-menu-active .x-btn-icon-el { + color: var(--nord-on-accent) !important; +} + +/* ===================================================== + FORM ELEMENTS + ===================================================== */ +.x-form-trigger-default { + background-color: var(--nord-surface0) !important; +} + +.x-form-text-default { + background-color: var(--nord-surface0) !important; + color: var(--nord-text) !important; + border-radius: var(--pm-radius-sm) !important; +} + +.x-form-trigger-wrap, +.x-form-trigger-wrap-default { + border-color: var(--nord-surface1) !important; + background-color: var(--nord-surface0) !important; + border-radius: var(--pm-radius-sm) !important; + transition: border-color 0.15s ease !important; +} + +.x-form-trigger-wrap-default.x-form-trigger-wrap-focus { + border-color: var(--nord-purple) !important; + box-shadow: 0 0 0 3px var(--nord-accent-subtle) !important; +} + +.x-form-item-label-default, +.x-form-cb-label-default { + color: var(--nord-text) !important; +} + +.x-form-display-field-default { + color: var(--nord-subtext0) !important; + border-radius: var(--pm-radius-md) !important; +} + +.x-form-spinner-default { + background-color: var(--nord-surface0) !important; +} + +.x-fieldset, +.x-fieldset-default { + border-color: var(--nord-surface1) !important; + border-radius: var(--pm-radius-lg) !important; +} + +.x-fieldset-header-default > .x-fieldset-header-text { + color: var(--nord-text) !important; +} + +/* ===================================================== + CHECKBOXES & RADIOS — Dracula styled + ===================================================== */ + +/* Base: remove sprite, styled as custom control */ +.x-form-checkbox, .x-form-checkbox-default, +.x-form-radio, .x-form-radio-default { + background-image: none !important; + background-color: var(--nord-surface0) !important; + border: 1.5px solid var(--nord-overlay0) !important; + width: 16px !important; + height: 16px !important; + display: inline-block !important; + box-sizing: border-box !important; + cursor: pointer !important; + transition: border-color 0.12s ease, background-color 0.12s ease !important; +} + +/* Checkbox: rounded square */ +.x-form-checkbox, .x-form-checkbox-default { + border-radius: 3px !important; +} + +/* Radio: circle + ::after inner dot */ +.x-form-radio, .x-form-radio-default { + border-radius: 50% !important; + position: relative !important; + transform: translateZ(0) !important; + box-shadow: inset 0 0 0 0 transparent !important; +} + +.x-form-radio::after { + content: '' !important; + position: absolute !important; + top: 50% !important; + left: 50% !important; + width: 7px !important; + height: 7px !important; + border-radius: 50% !important; + background: transparent !important; + transform: translate(-50%, -50%) scale(0) !important; + transition: transform 0.15s ease, background 0.15s ease !important; + pointer-events: none !important; +} + +/* Hover */ +.x-form-checkbox:hover, .x-form-checkbox-default:hover, +.x-form-cb-wrap:hover .x-form-checkbox { + border-color: var(--nord-purple) !important; +} + +.x-form-radio:hover, .x-form-radio-default:hover, +.x-form-cb-wrap:hover .x-form-radio { + border-color: var(--nord-purple) !important; +} + +/* CHECKED checkbox — Purple fill + dark SVG checkmark */ +.x-form-cb-checked .x-form-checkbox, +.x-form-cb-checked .x-form-checkbox-default { + background-color: var(--nord-purple) !important; + border-color: var(--nord-purple) !important; + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 8'%3E%3Cpath d='M1 4l3 3 5-6' fill='none' stroke='%23eceff4' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") !important; + background-repeat: no-repeat !important; + background-position: center !important; + background-size: 9px 7px !important; +} + +/* SELECTED radio — Purple dot */ +.x-form-cb-checked .x-form-radio, +.x-form-cb-checked .x-form-radio-default { + border-color: var(--nord-purple) !important; + background-color: var(--nord-base) !important; +} + +.x-form-cb-checked .x-form-radio::after { + background: var(--nord-purple) !important; + transform: translate(-50%, -50%) scale(1) !important; +} + +/* ===================================================== + BOUNDLIST / DROPDOWNS + ===================================================== */ +.x-boundlist { + background-color: var(--nord-mantle) !important; + border: 1px solid var(--nord-surface1) !important; + border-radius: var(--pm-radius-md) !important; + box-shadow: 0 8px 24px rgba(30, 31, 41, 0.7) !important; + padding: 2px !important; + overflow: hidden !important; +} + +.x-boundlist-item { + background-color: transparent !important; + color: var(--nord-text) !important; + border-radius: var(--pm-radius-sm) !important; + padding: 2px 6px !important; + line-height: normal !important; + border: none !important; + cursor: pointer !important; + outline: none !important; + box-shadow: none !important; +} + +.x-boundlist-selected { + background-color: var(--nord-select-overlay) !important; + color: var(--nord-text) !important; +} + +.x-boundlist-item-over { + background-color: var(--nord-hover-overlay) !important; +} + +/* ===================================================== + GRIDS / TABLES + ===================================================== */ +.x-grid, +.x-grid-view { + border-radius: 0 !important; +} + +.x-column-header { + border-color: var(--nord-surface1) !important; + background-color: transparent !important; +} + +.x-column-header-inner, +.x-column-header-text { + color: var(--nord-text) !important; + font-weight: 600 !important; +} + +.x-column-header-trigger { + border-color: var(--nord-surface1) !important; +} + +.x-grid-item, +.x-column-header-default, +.x-grid-cell-row-numberer { + color: var(--nord-text) !important; + background-color: var(--nord-base) !important; +} + +.x-grid-cell-special { + border-color: var(--nord-surface1) !important; +} + +.x-grid-group-hd { + background-color: var(--nord-base) !important; + border-color: var(--nord-surface1) !important; +} + +.x-grid-group-title { + color: var(--nord-text) !important; +} + +.x-grid-header-ct { + background-color: var(--nord-mantle) !important; + border: 1px solid var(--nord-surface0) !important; + border-radius: var(--pm-radius-lg) var(--pm-radius-lg) 0 0 !important; +} + +.x-grid-item-alt { + background-color: var(--nord-crust) !important; +} + +.x-grid-with-row-lines .x-grid-item { + border-color: var(--nord-surface0) !important; +} + +.x-grid-cell { + border-bottom: 1px solid rgba(68, 71, 90, 0.4) !important; +} + +.x-grid-item-over, +.x-grid-with-row-lines .x-grid-item.x-grid-item-over { + background-color: var(--nord-hover-overlay) !important; +} + +.x-grid-item-selected, +.x-grid-with-row-lines .x-grid-item.x-grid-item-selected { + background-color: var(--nord-select-overlay) !important; +} + +.x-column-header-over, +.x-column-header-open { + background-color: var(--nord-hover-overlay) !important; +} + +.x-column-header-sort-ASC, +.x-column-header-sort-DESC { + background-color: var(--nord-hover-overlay) !important; +} + +.x-grid-row-summary .x-grid-cell, +.x-grid-row-summary .x-grid-rowwrap, +.x-grid-row-summary .x-grid-cell-rowbody { + background-color: var(--nord-base) !important; + border-color: var(--nord-surface1); +} + +.x-grid-with-col-lines .x-grid-cell, +.x-grid-with-col-lines .x-grid-item-over .x-grid-cell, +.x-grid-with-col-lines .x-grid-item-selected .x-grid-cell { + border-color: var(--nord-surface1) !important; +} + +.x-dd-drag-proxy { + background-color: var(--nord-mantle); + border-color: var(--nord-surface1); + color: var(--nord-text); +} + +.x-keyboard-mode .x-grid-item-focused { + background-color: var(--nord-hover-overlay) !important; + color: var(--nord-text) !important; +} + +/* Remove blue outline from focused/selected items in resource tree */ +.x-keyboard-mode .x-grid-item-focused .x-grid-cell-inner::before, +.x-keyboard-mode .x-grid-item-selected .x-grid-cell-inner::before, +.x-grid-item-selected .x-grid-cell-inner::before, +.x-grid-item-focused .x-grid-cell-inner::before, +[id^="pveResourceTree"] .x-grid-item-selected .x-grid-cell-inner::before, +[id^="pveResourceTree"] .x-grid-item-focused .x-grid-cell-inner::before { + content: none !important; + display: none !important; + border: none !important; +} + +.x-grid-empty { + background-color: var(--nord-base) !important; + color: var(--nord-subtext0) !important; +} + +/* Grid info (pve-info-grid) and RRD view */ +.pve-info-grid { + border-radius: 12px !important; +} + +.pve-rrdview, +.rrdview { + border-radius: 12px !important; +} + +.pve-summary-status, +.x-container .pve-status { + border-radius: var(--pm-radius-lg) !important; +} + +[id^="pveGuestStatusView-"][id$="-body"], +[id^="pmxNotesView-"] .x-panel-body { + border-radius: var(--pm-radius-lg) !important; +} + +.x-panel-default[id*="notes"], +.pve-notes-view { + border-radius: var(--pm-radius-lg) !important; +} + +/* Floating grid pickers (storage/ISO selectors) */ +.x-layer.x-grid .x-grid-view, +.x-panel.x-layer.x-grid .x-grid-view, +.x-panel.x-layer.x-grid, +.x-layer.x-panel.x-grid { + border-radius: var(--pm-radius-sm) !important; +} + +.x-layer.x-grid .x-grid-item-over, +.x-layer.x-grid .x-grid-item-selected, +.x-panel.x-layer.x-grid .x-grid-item-over, +.x-panel.x-layer.x-grid .x-grid-item-selected { + border-radius: var(--pm-radius-sm) !important; + outline: none !important; + box-shadow: none !important; +} + +.x-layer.x-grid .x-grid-item-over td, +.x-layer.x-grid .x-grid-item-selected td, +.x-layer.x-grid .x-grid-item-over .x-grid-cell, +.x-layer.x-grid .x-grid-item-selected .x-grid-cell, +.x-panel.x-layer.x-grid .x-grid-item-over td, +.x-panel.x-layer.x-grid .x-grid-item-selected td, +.x-panel.x-layer.x-grid .x-grid-item-over .x-grid-cell, +.x-panel.x-layer.x-grid .x-grid-item-selected .x-grid-cell { + border-radius: 0 !important; +} + +.x-layer.x-grid .x-grid-item-over td:first-child, +.x-layer.x-grid .x-grid-item-selected td:first-child, +.x-panel.x-layer.x-grid .x-grid-item-over td:first-child, +.x-panel.x-layer.x-grid .x-grid-item-selected td:first-child { + border-radius: var(--pm-radius-sm) 0 0 var(--pm-radius-sm) !important; +} + +.x-layer.x-grid .x-grid-item-over td:last-child, +.x-layer.x-grid .x-grid-item-selected td:last-child, +.x-panel.x-layer.x-grid .x-grid-item-over td:last-child, +.x-panel.x-layer.x-grid .x-grid-item-selected td:last-child { + border-radius: 0 var(--pm-radius-sm) var(--pm-radius-sm) 0 !important; +} + +/* ===================================================== + MENUS + ===================================================== */ +.x-menu, +.x-menu-default { + background-color: var(--nord-crust) !important; + border: 1px solid var(--nord-surface0) !important; + border-radius: var(--pm-radius-lg) !important; + box-shadow: 0 8px 24px rgba(30, 31, 41, 0.8) !important; + padding: 4px !important; + overflow: hidden !important; +} + +.x-menu-body-default { + background-color: transparent !important; + padding: 4px !important; +} + +.x-menu-header { + background-color: transparent !important; + color: var(--nord-text) !important; +} + +/* Menu icon separator — hide */ +.x-menu-icon-separator-default { + display: none !important; +} + +/* Menu item layout (flexbox reordering) */ +.x-menu-item-default > .x-menu-item-link { + display: flex !important; + align-items: center !important; + flex-direction: row !important; + gap: 4px !important; + justify-content: flex-start !important; + flex-wrap: nowrap !important; + border-radius: var(--pm-radius-md) !important; + padding: 4px 8px !important; + line-height: 20px !important; + border: none !important; + cursor: pointer !important; + outline: none !important; + box-shadow: none !important; + white-space: nowrap !important; + text-decoration: none !important; +} + +.x-menu-item-text-default { + color: var(--nord-text) !important; + font-size: 13px !important; + order: 1 !important; + margin-left: 0 !important; + text-align: left !important; + line-height: 20px !important; + display: inline-flex !important; + align-items: center !important; + flex: 1 1 auto !important; + width: auto !important; + white-space: nowrap !important; +} + +.x-menu-item-icon-default { + color: var(--nord-subtext0) !important; + order: -1 !important; + position: relative !important; + float: none !important; + margin-right: 8px !important; + margin-left: 0 !important; + left: auto !important; + top: auto !important; + width: 16px !important; + text-align: center !important; + display: inline-flex !important; + align-items: center !important; + justify-content: center !important; + height: 20px !important; + line-height: 20px !important; + vertical-align: middle !important; + flex: 0 0 16px !important; + align-self: center !important; +} + +.x-menu-item-arrow, +.x-menu-item-arrow-default { + order: 2 !important; + margin-left: auto !important; +} + +.x-menu-item-default.x-menu-item-separator { + background-color: var(--nord-surface0) !important; + border: none !important; + height: 1px !important; + margin: 6px 4px !important; +} + +.x-menu-item-default.x-menu-item-focus, +.x-menu-item-default.x-menu-item-active, +.x-menu-item:hover { + background-color: var(--nord-surface0) !important; + color: var(--nord-text) !important; + border-radius: var(--pm-radius-md) !important; +} + +.x-menu-item-active .x-menu-item-text-default, +.x-menu-item-focus .x-menu-item-text-default { + color: var(--nord-text) !important; +} + +.x-menu-item-active .x-menu-item-icon-default, +.x-menu-item-focus .x-menu-item-icon-default { + color: var(--nord-cyan) !important; +} + +/* ===================================================== + PROGRESS BARS + ===================================================== */ + +/* Fix: Widget containers need overflow visible to not clip progress bars */ +.x-container[id^="pmxInfoWidget"], +.x-container.x-box-layout-ct { + overflow: visible !important; +} + +.x-progress, +.x-progress-default { + background-color: var(--nord-surface0) !important; + border-radius: 5px !important; +} + +.x-progress-default .x-progress-bar-default { + background-color: var(--nord-purple) !important; + border-radius: 5px !important; + transition: width 0.4s ease !important; +} + +.x-progress-default .x-progress-text { + color: var(--nord-text) !important; +} + +/* Text overlaid on the progress bar fill — use on-accent for contrast */ +.x-progress-bar .x-progress-text { + color: var(--nord-on-accent) !important; +} + +.x-progress.warning .x-progress-bar { + background-color: var(--nord-yellow) !important; +} + +.x-progress.critical .x-progress-bar { + background-color: var(--nord-red) !important; +} + +/* ===================================================== + TABS — Dracula underline style + Flat tabs with Purple underline on active tab + ===================================================== */ +.x-tab-bar, +.x-tab-bar-default { + background-color: var(--nord-base) !important; + border-radius: 0 !important; + border-bottom: 1px solid var(--nord-surface1) !important; + padding-bottom: 0 !important; +} + +/* Overflow visible for the underline indicator */ +.x-tab-bar .x-box-inner, +.x-tab-bar .x-box-target, +.x-tab-bar-body, +.x-tab-bar-body-default { + overflow: visible !important; +} + +/* Base tab */ +.x-tab, +.x-tab-default, +.x-tab-default-top { + background-color: transparent !important; + border: none !important; + border-radius: var(--pm-radius-md) var(--pm-radius-md) 0 0 !important; + padding: 8px 16px 8px !important; + overflow: visible !important; + margin-bottom: 0 !important; + transition: color 0.15s ease !important; + outline: none !important; + box-shadow: none !important; +} + +/* Remove ::after from inactive tabs */ +.x-tab::after { + display: none !important; +} + +.x-tab-inner-default { + color: var(--nord-subtext0) !important; + font-size: 13px !important; +} + +.x-tab-default.x-tab-over { + background-color: transparent !important; +} + +.x-tab-default.x-tab-over .x-tab-inner-default { + color: var(--nord-text) !important; +} + +/* Active tab */ +.x-tab-default.x-tab.x-tab-active { + background-color: transparent !important; + border: none !important; + overflow: visible !important; + margin-bottom: 0 !important; + outline: none !important; + box-shadow: none !important; +} + +/* Purple underline indicator on active tab */ +.x-tab-default.x-tab.x-tab-active::after { + content: '' !important; + display: block !important; + position: absolute !important; + bottom: 0 !important; + left: 0 !important; + right: 0 !important; + height: 2px !important; + background: var(--nord-purple) !important; + z-index: 10 !important; + border-radius: 2px 2px 0 0 !important; + pointer-events: none !important; +} + +.x-tab-active .x-tab-inner-default { + color: var(--nord-text) !important; + font-weight: 600 !important; +} + +.x-tab-default.x-tab.x-tab-disabled { + background-color: transparent !important; + border: none !important; + color: var(--nord-overlay0) !important; + margin-bottom: 0 !important; +} + +/* Focus states — no outline */ +.x-keyboard-mode .x-tab-default.x-tab-focus, +.x-keyboard-mode .x-tab-default.x-tab-focus.x-tab-active { + background-color: transparent !important; + border: none !important; + outline: none !important; + box-shadow: none !important; + margin-bottom: 0 !important; +} + +.x-keyboard-mode .x-tab-default.x-tab-focus.x-tab-active::after { + content: '' !important; + display: block !important; + position: absolute !important; + bottom: 0 !important; + left: 0 !important; + right: 0 !important; + height: 2px !important; + background: var(--nord-purple) !important; + z-index: 10 !important; + pointer-events: none !important; +} + +/* Kill ALL tab interaction outlines/shadows */ +.x-tab:focus, +.x-tab *:focus, +.x-tab-focus, +.x-tab-active.x-tab-focus, +.x-tab-inner-focus, +.x-tab-button-focus, +.x-tab-pressed, +.x-tab-active.x-tab-pressed, +.x-tab-over, +.x-tab:active, +.x-tab *:active { + outline: none !important; + box-shadow: none !important; +} + +.x-tabpanel-child { + border-radius: 0 0 var(--pm-radius-lg) var(--pm-radius-lg) !important; +} + +/* Tab hover/active corners */ +.x-tab-default.x-tab-over, +.x-tab-default.x-tab.x-tab-active { + border-radius: var(--pm-radius-md) var(--pm-radius-md) 0 0 !important; +} + +/* ===================================================== + TOOLTIPS + ===================================================== */ +.x-tip, +.x-tip-default { + background-color: var(--nord-mantle) !important; + border: 1px solid var(--nord-surface1) !important; + border-radius: var(--pm-radius-md) !important; + box-shadow: 0 4px 12px rgba(30, 31, 41, 0.5); +} + +.x-tip-body-default { + color: var(--nord-text) !important; +} + +.x-tip-form-invalid { + background-color: var(--nord-mantle) !important; + border-color: var(--nord-red) !important; +} + +.x-tip-body-form-invalid { + color: var(--nord-red) !important; +} + +/* ===================================================== + TREE NAVIGATION (Sidebar) + ===================================================== */ +.x-treelist-item { + background-color: var(--nord-base) !important; + border-radius: var(--pm-radius-md) !important; +} + +/* Pseudo-element approach for hover/selected highlighting */ +.x-treelist-row { + border-radius: var(--pm-radius-md) !important; + background-color: transparent !important; + position: relative !important; + z-index: 0 !important; +} + +.x-treelist-row::before { + content: ""; + position: absolute; + top: 1px; + bottom: 1px; + left: 0; + right: 4px; + border-radius: var(--pm-radius-md); + background-color: transparent; + z-index: -1; + pointer-events: none; + transition: background-color 0.15s ease; +} + +/* Fix toolbox tree item text overlapping icons */ +.x-treelist-item-text { + margin-left: 28px !important; +} + +/* Toolbox tree items — bright text */ +.x-treelist-item-text, +.x-treelist-item-icon, +.x-treelist.x-treelist-pve-nav .x-treelist-item-text, +.x-treelist.x-treelist-pve-nav .x-treelist-item-icon { + color: var(--nord-subtext1) !important; +} + +/* Hover state — apply to pseudo-element */ +.x-treelist-row-over { + background-color: transparent !important; +} + +.x-treelist-row-over::before { + background-color: var(--nord-hover-overlay) !important; +} + +.x-treelist-row-over .x-treelist-item-icon, +.x-treelist-row-over .x-treelist-item-text { + background-color: transparent !important; + color: var(--nord-text) !important; +} + +/* Selected/active item — Purple highlight */ +.x-treelist-item-selected > .x-treelist-row { + background-color: transparent !important; +} + +.x-treelist-item-selected > .x-treelist-row::before, +.x-treelist-item-selected > .x-treelist-row:hover::before { + background-color: var(--nord-purple) !important; +} + +.x-treelist-item-selected .x-treelist-item-text, +.x-treelist-item-selected .x-treelist-item-icon, +.x-treelist.x-treelist-pve-nav .x-treelist-item-selected .x-treelist-item-text, +.x-treelist.x-treelist-pve-nav .x-treelist-item-selected .x-treelist-item-icon { + color: var(--nord-on-accent) !important; +} + +.x-treelist-pve-nav { + background-color: var(--nord-base) !important; + border-color: var(--nord-surface1) !important; +} + +/* Tree navigation radius overrides */ +.x-treelist-item, +.x-treelist-item-tool { + border-radius: var(--pm-radius-sm) !important; +} + +.x-treelist-row, +.x-treelist-row:hover, +.x-treelist-row-over, +.x-treelist-item-selected > .x-treelist-row, +.x-treelist-item-selected > .x-treelist-row:hover, +.x-treelist-item-expanded > .x-treelist-row, +.x-treelist-item-expanded > .x-treelist-row-over, +.x-treelist-item-expandable > .x-treelist-row, +.x-treelist-item-expandable > .x-treelist-row-over { + border-radius: var(--pm-radius-sm) !important; +} + +.x-treelist-row::before { + border-radius: var(--pm-radius-sm) !important; +} + +.x-treelist-item-wrap, +.x-treelist-item-text, +.x-treelist-row, +.x-treelist-container, +.x-treelist-root-container, +.x-treelist, +.x-treelist-pve-nav { + border-radius: var(--pm-radius-sm) !important; +} + +/* Cursor pointer for interactive tree/grid items */ +.x-grid-cell, +.x-grid-cell-inner, +.x-tree-elbow-img, +.x-tree-icon, +.x-treelist-item, +.x-treelist-row, +.x-treelist-item-wrap, +.x-treelist-item-text, +.x-treelist-item-icon { + cursor: pointer !important; +} + +/* ===================================================== + WINDOWS / MODALS + ===================================================== */ +.x-window, +.x-window-default { + background-color: var(--nord-crust) !important; + border: 1px solid var(--nord-surface1) !important; + border-radius: var(--pm-radius-lg) !important; + box-shadow: 0 8px 24px rgba(30, 31, 41, 0.6) !important; + overflow: hidden !important; +} + +.x-window .x-window-header, +.x-window-header-default { + background-color: var(--nord-mantle) !important; + border-color: transparent !important; + border-radius: var(--pm-radius-lg) var(--pm-radius-lg) 0 0 !important; +} + +.x-window-header-default .x-mask { + background-color: rgba(30, 31, 41, 0.7); +} + +.x-window .x-window-body, +.x-window-body-default { + background-color: var(--nord-base) !important; + border-color: var(--nord-surface1) !important; + color: var(--nord-text) !important; + border-radius: 0 0 var(--pm-radius-lg) var(--pm-radius-lg) !important; +} + +.x-window-ghost { + background-color: var(--nord-base) !important; +} + +.x-window-header-default .x-tool-img { + background-color: transparent; +} + +.x-message-box .x-window-body { + background-color: var(--nord-mantle) !important; +} + +/* Respect ExtJS inline display:none on hidden dialog buttons */ +.x-message-box .x-btn.x-btn-default-small[style*="display: none"], +.x-message-box .x-btn.x-btn-default-small[style*="display:none"], +.x-window .x-toolbar-footer .x-btn[style*="display: none"], +.x-window .x-toolbar-footer .x-btn[style*="display:none"] { + display: none !important; +} + +/* Login dialog — clean inner panel borders */ +.x-window:has(#pveloginrealm) .x-panel-body { + border: none !important; + background: transparent !important; + width: auto !important; +} + +/* ===================================================== + CONSOLE / TERMINAL + ===================================================== */ +div.monitor { + border-color: var(--nord-surface1); +} + +.install-mask { + background-color: var(--nord-crust); + color: var(--nord-subtext0); +} + +.x-window.install-mask { + box-shadow: rgba(30, 31, 41, 0.5) 0 4px 20px !important; +} + +/* ===================================================== + LEGEND / CHARTS + ===================================================== */ +.x-legend-container { + background-color: var(--nord-base) !important; +} + +.x-legend-horizontal .x-legend-item { + background-color: var(--nord-mantle) !important; + color: var(--nord-text) !important; + border: 1px solid var(--nord-surface0) !important; +} + +/* Chart/RRD panel backgrounds */ +div[id*="rrdchart"], +.pve-rrddatastore, +.pmx-panel-rrd { + background-color: var(--nord-base) !important; +} + +.proxmox-rrd-panel canvas, +.proxmox-widget-toolkit canvas, +canvas.x-surface, +.x-surface canvas { + background-color: transparent !important; + opacity: 1 !important; +} + +.proxmox-rrd-panel, +.proxmox-rrd-chart { + background-color: var(--nord-base) !important; +} + +/* Chart text/labels */ +.x-surface text, +svg text { + fill: var(--nord-text) !important; +} + +/* ===================================================== + PROXMOX-SPECIFIC OVERRIDES + ===================================================== */ + +/* Logo inversion */ +img[id^="proxmoxlogo-"][id$="-img"], +img[id^="proxmoxLogoSvg-"][id$="-img"] { + filter: none; +} + +/* Invalid/warning/disabled rows */ +.proxmox-invalid-row { + background-color: rgba(255, 85, 85, 0.15) !important; +} + +.proxmox-warning-row { + background-color: rgba(255, 184, 108, 0.15) !important; +} + +.proxmox-disabled-row td { + color: var(--nord-overlay0) !important; +} + +/* Hints */ +.pmx-hint { + background-color: rgba(255, 184, 108, 0.15) !important; + white-space: nowrap !important; +} + +.pmx-hint a { + color: var(--nord-cyan) !important; +} + +/* Status text colors — Information → Cyan */ +.info-blue { + color: var(--nord-cyan) !important; +} + +.critical { + color: var(--nord-red) !important; +} + +/* Links */ +a { + color: var(--nord-cyan) !important; +} + +/* Markdown content */ +.pmx-md code { + background-color: var(--nord-mantle) !important; + color: var(--nord-pink) !important; + border-radius: var(--pm-radius-sm) !important; +} + +.pmx-md pre code { + border-color: var(--nord-surface1) !important; + background-color: var(--nord-crust) !important; +} + +.pmx-md a { + color: var(--nord-cyan) !important; +} + +.pmx-md table { + border-color: var(--nord-surface1) !important; +} + +.pmx-md th { + background-color: var(--nord-mantle) !important; + border-color: var(--nord-surface1) !important; +} + +.pmx-md td { + border-color: var(--nord-surface1) !important; +} + +/* APT repos */ +.proxmox-apt-repos .x-grid-group-hd { + background-color: var(--nord-base) !important; + border: none !important; +} + +.proxmox-apt-repos .x-grid-group-title { + color: var(--nord-text) !important; +} + +/* Tags */ +.pve-edit-tag { + border-radius: var(--pm-radius-md) !important; +} + +.pve-edit-tag.editable span { + background-color: var(--nord-mantle) !important; + color: var(--nord-text) !important; + border-color: var(--nord-surface1) !important; +} + +.x-tree-node-text .proxmox-tag-dark, +.x-tree-node-text .proxmox-tag-light, +.x-grid-cell-inner .proxmox-tag-dark, +.x-grid-cell-inner .proxmox-tag-light, +span.proxmox-tag-dark, +span.proxmox-tag-light { + border-radius: var(--pm-radius-md) !important; +} + +/* Checkmark button in tag edit — match toolbar button size */ +.x-btn.x-btn-default-small:has(.fa-check) { + min-height: 24px !important; + height: 24px !important; + padding: 3px 8px !important; + border-radius: var(--pm-radius-sm) !important; + background-color: var(--nord-purple) !important; + border: none !important; +} + +.x-btn.x-btn-default-small:has(.fa-check).x-btn-disabled { + background-color: transparent !important; + border: 1px solid var(--nord-surface1) !important; + opacity: 0.5 !important; +} + +.x-btn.x-btn-default-small:has(.fa-check) .fa-check { + color: var(--nord-on-accent) !important; +} + +.x-btn.x-btn-default-small:has(.fa-check).x-btn-disabled .fa-check { + color: var(--nord-overlay1) !important; +} + +.x-btn.x-btn-default-small:has(.fa-check):not(.x-btn-disabled):hover { + background-color: #caa9fa !important; +} + +.x-btn.x-btn-default-small:has(.fa-check) .x-btn-inner { + display: none !important; +} + +/* Date picker */ +.x-datepicker, +.x-datepicker-column-header, +.x-monthpicker { + background-color: var(--nord-base) !important; + color: var(--nord-text) !important; + border-color: transparent !important; +} + +.x-datepicker-header, +.x-datepicker-footer, +.x-monthpicker-buttons { + background-color: var(--nord-mantle) !important; +} + +.x-datepicker-date, +.x-monthpicker-item-inner { + color: var(--nord-text) !important; +} + +.x-datepicker-selected div.x-datepicker-date, +.x-monthpicker-item a.x-monthpicker-selected, +a.x-monthpicker-item-inner:hover, +div.x-datepicker-date:hover { + background-color: var(--nord-hover-overlay) !important; + color: var(--nord-text) !important; +} + +.x-datepicker-today .x-datepicker-date { + border-color: var(--nord-purple) !important; +} + +.x-datepicker-disabled .x-datepicker-date { + color: var(--nord-overlay0) !important; +} + +.x-datepicker-prev-day .x-datepicker-date, +.x-datepicker-next-day .x-datepicker-date { + color: var(--nord-overlay0) !important; +} + +/* Usage bars */ +.usage-wrapper, +.usage { + border-radius: 2px !important; +} + +.usage { + background-color: var(--nord-overlay2) !important; +} + +/* ===================================================== + SCROLLBARS + ===================================================== */ +::-webkit-scrollbar { + width: 8px; + height: 8px; +} + +::-webkit-scrollbar-track { + background: var(--nord-base); + border-radius: var(--pm-radius-sm); +} + +::-webkit-scrollbar-thumb { + background: var(--nord-surface2); + border-radius: var(--pm-radius-sm); + border: 1px solid transparent; + background-clip: padding-box; + transition: background 0.15s ease; +} + +::-webkit-scrollbar-thumb:hover { + background: var(--nord-overlay0); +} + +::-webkit-scrollbar-corner { + background: var(--nord-base); +} + +/* Firefox scrollbar */ +* { + scrollbar-width: thin; + scrollbar-color: var(--nord-surface2) var(--nord-base); +} + +/* ===================================================== + SELECTION HIGHLIGHT + ===================================================== */ +::selection { + background-color: rgba(98, 114, 164, 0.3); + color: var(--nord-text); +} + +/* ===================================================== + TRANSITIONS (smooth interactions) + ===================================================== */ + +/* Grid row transitions */ +.x-grid-item { + transition: background-color 0.15s ease !important; +} + +/* Tree pseudo-element transitions */ +.x-treelist-row::before { + transition: background-color 0.15s ease !important; +} + +/* Menu item transitions */ +.x-menu-item-default > .x-menu-item-link { + transition: background-color 0.12s ease !important; +} + +/* Boundlist item transitions */ +.x-boundlist-item { + transition: background-color 0.12s ease !important; +} + +/* Tab transitions */ +.x-tab { + transition: color 0.15s ease !important; +} + +/* Splitter transition */ +.x-splitter { + transition: background-color 0.15s ease !important; +} + +/* Tooltip transition */ +.x-tip { + transition: opacity 0.15s ease !important; +} + +/* Progress bar width transition */ +.x-progress-bar { + transition: width 0.4s ease !important; +} + +/* Scrollbar thumb transition */ +::-webkit-scrollbar-thumb { + transition: background 0.15s ease !important; +} + +/* Window close tool transition */ +.x-tool-img { + transition: filter 0.15s ease !important; +} +/* ===================================================== + TOOL ICONS - FontAwesome Replacements + (Ported from UniFi v5.86) + Replace sprite-based ExtJS tool icons with crisp + FontAwesome icons for better consistency and clarity + ===================================================== */ + +/* Base styling for all tool icons - remove sprite backgrounds */ +.x-tool-tool-el.x-tool-minus, +.x-tool-img.x-tool-minus, +.x-tool-tool-el.x-tool-collapse-right, +.x-tool-img.x-tool-collapse-right, +.x-tool-tool-el.x-tool-collapse-left, +.x-tool-img.x-tool-collapse-left, +.x-tool-tool-el.x-tool-expand-right, +.x-tool-img.x-tool-expand-right, +.x-tool-tool-el.x-tool-expand-left, +.x-tool-img.x-tool-expand-left, +.x-tool-tool-el.x-tool-maximize, +.x-tool-img.x-tool-maximize, +.x-tool-tool-el.x-tool-restore, +.x-tool-img.x-tool-restore, +.x-tool-tool-el.x-tool-gear, +.x-tool-img.x-tool-gear, +.x-tool-tool-el.x-tool-refresh, +.x-tool-img.x-tool-refresh, +.x-tool-tool-el.x-tool-close, +.x-tool-img.x-tool-close { + background-image: none !important; + font-family: "FontAwesome" !important; + font-size: 14px !important; + line-height: 16px !important; + text-align: center !important; + color: var(--pm-text-dim) !important; + transition: color 0.15s ease !important; + filter: none !important; + width: 16px !important; + height: 16px !important; + display: flex !important; + align-items: center !important; + justify-content: center !important; +} + +/* Close button - slightly larger */ +.x-tool-tool-el.x-tool-close, +.x-tool-img.x-tool-close { + font-size: 20px !important; +} + +/* Individual glyph assignments */ +.x-tool-tool-el.x-tool-minus::before, +.x-tool-img.x-tool-minus::before { + content: "\f010" !important; /* fa-search-minus (zoom out) */ +} + +.x-tool-tool-el.x-tool-collapse-right::before, +.x-tool-img.x-tool-collapse-right::before { + content: "\f054" !important; /* fa-chevron-right */ +} + +.x-tool-tool-el.x-tool-expand-left::before, +.x-tool-img.x-tool-expand-left::before { + content: "\f053" !important; /* fa-chevron-left */ +} + +.x-tool-tool-el.x-tool-collapse-left::before, +.x-tool-img.x-tool-collapse-left::before { + content: "\f053" !important; /* fa-chevron-left */ +} + +.x-tool-tool-el.x-tool-expand-right::before, +.x-tool-img.x-tool-expand-right::before { + content: "\f054" !important; /* fa-chevron-right */ +} + +.x-tool-tool-el.x-tool-maximize::before, +.x-tool-img.x-tool-maximize::before { + content: "\f065" !important; /* fa-expand */ +} + +.x-tool-tool-el.x-tool-restore::before, +.x-tool-img.x-tool-restore::before { + content: "\f066" !important; /* fa-compress */ +} + +.x-tool-tool-el.x-tool-gear::before, +.x-tool-img.x-tool-gear::before { + content: "\f013" !important; /* fa-cog */ +} + +.x-tool-tool-el.x-tool-refresh::before, +.x-tool-img.x-tool-refresh::before { + content: "\f021" !important; /* fa-refresh */ +} + +.x-tool-tool-el.x-tool-close::before, +.x-tool-img.x-tool-close::before { + content: "\f00d" !important; /* fa-times */ +} + +/* Hover state - all tool icons */ +.x-tool:hover .x-tool-tool-el.x-tool-minus, +.x-tool:hover .x-tool-img.x-tool-minus, +.x-tool:hover .x-tool-tool-el.x-tool-collapse-right, +.x-tool:hover .x-tool-img.x-tool-collapse-right, +.x-tool:hover .x-tool-tool-el.x-tool-collapse-left, +.x-tool:hover .x-tool-img.x-tool-collapse-left, +.x-tool:hover .x-tool-tool-el.x-tool-expand-right, +.x-tool:hover .x-tool-img.x-tool-expand-right, +.x-tool:hover .x-tool-tool-el.x-tool-expand-left, +.x-tool:hover .x-tool-img.x-tool-expand-left, +.x-tool:hover .x-tool-tool-el.x-tool-maximize, +.x-tool:hover .x-tool-img.x-tool-maximize, +.x-tool:hover .x-tool-tool-el.x-tool-restore, +.x-tool:hover .x-tool-img.x-tool-restore, +.x-tool:hover .x-tool-tool-el.x-tool-gear, +.x-tool:hover .x-tool-img.x-tool-gear, +.x-tool:hover .x-tool-tool-el.x-tool-refresh, +.x-tool:hover .x-tool-img.x-tool-refresh, +.x-tool:hover .x-tool-tool-el.x-tool-close, +.x-tool:hover .x-tool-img.x-tool-close { + color: var(--pm-text) !important; +} + +/* Disabled state */ +.x-tool-disabled .x-tool-tool-el, +.x-tool-disabled .x-tool-img { + opacity: 0.4 !important; + cursor: default !important; +} + +/* Inline FontAwesome tools (PVE-injected) */ +.x-tool-tool-el[style*="font-family:FontAwesome"], +.x-tool-tool-el[style*="font-family: FontAwesome"] { + color: var(--pm-text-dim) !important; + font-size: 14px !important; + line-height: 16px !important; + display: flex !important; + align-items: center !important; + justify-content: center !important; + width: 16px !important; + height: 16px !important; + transition: color 0.15s ease !important; + background-image: none !important; + background-color: transparent !important; +} + +.x-tool:not(.x-tool-disabled) .x-tool-tool-el[style*="font-family:FontAwesome"], +.x-tool:not(.x-tool-disabled) .x-tool-tool-el[style*="font-family: FontAwesome"] { + cursor: pointer !important; +} + +.x-tool.x-tool-disabled .x-tool-tool-el[style*="font-family:FontAwesome"], +.x-tool.x-tool-disabled .x-tool-tool-el[style*="font-family: FontAwesome"] { + cursor: default !important; + opacity: 0.4 !important; +} + +.x-tool .x-mask { + background-color: transparent !important; + backdrop-filter: none !important; + pointer-events: none !important; +} + +.x-tool:not(.x-tool-disabled):hover .x-tool-tool-el[style*="font-family:FontAwesome"], +.x-tool:not(.x-tool-disabled):hover .x-tool-tool-el[style*="font-family: FontAwesome"] { + color: var(--pm-text) !important; +} diff --git a/themes/theme-solarized-dark.css b/themes/theme-solarized-dark.css new file mode 100644 index 0000000..8383ed0 --- /dev/null +++ b/themes/theme-solarized-dark.css @@ -0,0 +1,2340 @@ +/*!Solarized Dark*/ + +/* ===================================================== + CSS VARIABLES + ===================================================== */ +:root { + /* Theme: Solarized Dark */ + --pm-accent: #268bd2; + --pm-bg-base: #002b36; + --pm-bg-surface: #073642; + --pm-bg-elevated: #586e75; + --pm-text: #93a1a1; + --pm-text-dim: #839496; + --pm-success: #859900; + --pm-warning: #b58900; + --pm-error: #dc322f; + --pm-border: #586e75; + --pm-radius-sm: 4px; + --pm-radius-md: 6px; + --pm-radius-lg: 8px; + + /* Proxmox Widget Toolkit Mappings */ + --pwt-panel-background: var(--pm-bg-base); + --pwt-text-color: var(--pm-text); + --pwt-gauge-default: var(--pm-accent); + --pwt-gauge-back: var(--pm-bg-elevated); + --pwt-gauge-warn: var(--pm-warning); + --pwt-gauge-crit: var(--pm-error); + --pwt-chart-primary: var(--pm-accent); + --pwt-chart-grid-stroke: var(--pm-bg-elevated); + + /* Solarized theme internal variables (based on Dracula template structure) */ + --sol-text: var(--pm-text); + --sol-subtext0: var(--pm-text-dim); + --sol-subtext1: var(--pm-text-dim); + --sol-overlay0: var(--pm-border); + --sol-overlay1: var(--pm-text-dim); + --sol-overlay2: var(--pm-text-dim); + --sol-surface0: var(--pm-bg-surface); + --sol-surface1: var(--pm-bg-elevated); + --sol-surface2: var(--pm-bg-elevated); + --sol-base: var(--pm-bg-base); + --sol-mantle: #00212b; + --sol-crust: #00212b; + + --sol-on-accent: #002b36; + --sol-hover-overlay: rgba(128, 128, 128, 0.12); + --sol-select-overlay: rgba(128, 128, 128, 0.25); + --sol-accent-muted: rgba(128, 128, 128, 0.4); + --sol-accent-subtle: rgba(128, 128, 128, 0.15); + + --sol-cyan: var(--pm-accent); + --sol-green: var(--pm-success); + --sol-orange: var(--pm-warning); + --sol-pink: var(--pm-accent); + --sol-purple: var(--pm-accent); + --sol-red: var(--pm-error); + --sol-yellow: var(--pm-warning); + + color-scheme: dark; +} + +/* ===================================================== + GLOBAL BORDER-RADIUS ARCHITECTURE + (Ported from UniFi theme — reset everything, selectively re-apply) + ===================================================== */ +.x-border-box, +.x-border-box * { + border-radius: var(--pm-radius-lg); +} + +/* Remove rounded corners from grids/tables/lists */ +.x-grid, +.x-grid *, +.x-grid-header-ct, +.x-grid-header-ct *, +.x-grid-view, +.x-grid-view *, +.x-column-header, +.x-column-header *, +.x-grid-item, +.x-grid-cell, +.x-grid-cell-inner, +.x-grid-row, +table, +table *, +tr, +td, +th, +.x-legend, +.x-legend *, +.x-legend-container, +.x-legend-container *, +.x-legend-item, +.x-legend-horizontal .x-legend-item, +.x-legend-vertical .x-legend-item, +.x-legend-horizontal .x-legend-item:first-child, +.x-legend-horizontal .x-legend-item:last-child, +.x-legend-vertical .x-legend-item:first-child, +.x-legend-vertical .x-legend-item:last-child, +.x-tool, +.x-tool-tool-el, +.x-tool-default, +.x-tool-img { + border-radius: 0 !important; +} + +/* Form elements - exclude from global radius */ +.x-form-item, +.x-form-item-default, +.x-form-item-body, +.x-form-item-body-default, +.x-form-text-field-body, +.x-form-text-field-body-default, +.x-form-fieldcontainer, +.x-field, +.x-field-default, +.x-form-type-text { + border-radius: 0 !important; +} + +/* Reset layout containers that clip elements with overflow:hidden + radius */ +.x-box-layout-ct, +.x-panel-bodyWrap, +.x-panel-bodyWrap-default, +.x-autocontainer-innerCt, +.x-autocontainer-outerCt, +.x-panel.x-tabpanel-child, +.x-panel.x-box-item, +.x-box-inner, +.x-box-target, +.x-container, +.x-container-default, +.x-window .x-panel-body, +.x-window .x-window-body, +.x-window .x-window-bodyWrap { + border-radius: 0 !important; +} + +/* Reset everything inside windows to 0 — then re-apply specific radii */ +.x-window *, +.x-window .x-autocontainer-innerCt, +.x-window .x-autocontainer-outerCt, +.x-window .x-form-layout-wrap, +.x-window .x-form-layout-auto-label, +.x-window .x-form-layout-colgroup, +.x-window .x-form-layout-column, +.x-window .x-field, +.x-window .x-form-item, +.x-window .x-form-item-body { + border-radius: 0 !important; +} + +/* Chart canvas — no radius on data area */ +.x-chart-grid, +.x-chart-axis, +canvas.x-surface, +.x-chart canvas, +canvas.x-surface-canvas, +.x-surface-canvas, +.x-draw-component canvas, +.proxmox-rrd-chart canvas, +svg.x-surface, +.x-draw-container, +.x-surface { + border-radius: 0 !important; +} + +/* Legend color marker (dot) — keep circular */ +.x-legend-item-marker { + border-radius: 50% !important; +} + +/* ===================================================== + RE-APPLY BORDER RADII (selective) + ===================================================== */ + +/* Windows */ +.x-window, +.x-window-default { + border-radius: var(--pm-radius-lg) !important; +} + +.x-window-header, +.x-window-header-default { + border-radius: var(--pm-radius-lg) var(--pm-radius-lg) 0 0 !important; +} + +.x-window .x-window-body, +.x-window-body-default { + border-radius: 0 !important; +} + +/* Buttons inside windows */ +.x-window .x-btn { + border-radius: var(--pm-radius-md) !important; +} + +/* Checkboxes inside windows */ +.x-window .x-form-checkbox { + border-radius: 3px !important; +} + +/* Form inputs inside windows */ +.x-window .x-form-trigger-wrap, +.x-window .x-form-trigger-wrap-default { + border-radius: var(--pm-radius-sm) !important; +} + +.x-window .x-form-text-wrap, +.x-window .x-form-text { + border-radius: var(--pm-radius-sm) 0 0 var(--pm-radius-sm) !important; +} + +.x-window .x-form-arrow-trigger { + border-radius: 0 var(--pm-radius-sm) var(--pm-radius-sm) 0 !important; +} + +/* Form trigger/text wrap — reset and re-apply */ +.x-form-trigger-wrap, +.x-form-trigger-wrap *, +.x-form-text-wrap, +.x-form-text-wrap *, +.x-form-text, +.x-form-trigger { + border-radius: 0 !important; +} + +.x-form-trigger-wrap, +.x-form-trigger-wrap-default { + border-radius: var(--pm-radius-sm) !important; + overflow: hidden !important; +} + +.x-form-text-wrap, +.x-form-text-wrap-default { + border-radius: var(--pm-radius-sm) 0 0 var(--pm-radius-sm) !important; +} + +.x-form-text, +.x-form-text-default { + border-radius: var(--pm-radius-sm) 0 0 var(--pm-radius-sm) !important; +} + +.x-form-trigger, +.x-form-trigger-default, +.x-form-arrow-trigger, +.x-form-arrow-trigger-default { + border-radius: 0 var(--pm-radius-sm) var(--pm-radius-sm) 0 !important; +} + +/* Dialog form content padding — vertical only (horizontal causes ExtJS overflow) */ +.x-window .x-tabpanel-child .x-autocontainer-innerCt { + padding: 12px 0 !important; +} + +/* Allow column panel bodies to show overflowed form content */ +.x-window .x-panel-body:not(.x-scroller) { + overflow: visible !important; +} + +/* Side padding on column panel bodies inside windows */ +.x-window .x-panel.x-box-item .x-panel-body { + padding: 0 4px !important; +} + +/* Constrain autocontainer width inside windows */ +.x-window .x-autocontainer-outerCt { + max-width: 100% !important; +} + +/* Fix window header/body width consistency */ +.x-window > .x-window-header, +.x-window > .x-window-body, +.x-window > .x-window-bodyWrap, +.x-window-bodyWrap > .x-window-body { + width: 100% !important; +} + +.x-window-header > .x-box-inner, +.x-window-header > .x-box-inner > .x-box-target { + width: 100% !important; +} + +.x-window-header-title { + width: auto !important; + flex: 1 !important; + max-width: calc(100% - 30px) !important; +} + +/* Boundlists */ +.x-boundlist { + border-radius: var(--pm-radius-md) !important; + overflow: hidden !important; +} + +/* ===================================================== + BASE / BODY + ===================================================== */ +.x-body, +.x-viewport > .x-body, +body.x-border-layout-ct, +div.x-border-layout-ct { + background-color: var(--sol-base) !important; + color: var(--sol-text) !important; +} + +/* ===================================================== + MASKS & OVERLAYS + ===================================================== */ +.x-mask { + background-color: rgba(30, 31, 41, 0.6) !important; + backdrop-filter: blur(4px); +} + +.x-mask-msg { + background-color: var(--sol-mantle) !important; + border: 1px solid var(--sol-surface1) !important; + border-radius: var(--pm-radius-lg) !important; +} + +.x-mask-msg-text { + color: var(--sol-subtext0) !important; + filter: none !important; +} + +.x-css-shadow { + box-shadow: 0 8px 24px rgba(30, 31, 41, 0.6) !important; +} + +/* Loading indicators */ +.x-grid-row-loading, +.x-treelist-item-loading .x-treelist-item-icon, +.x-grid-tree-loading .x-tree-icon { + filter: invert(90%); +} + +/* ===================================================== + ICONS — Proxmox default colors for dark mode + ===================================================== */ + +/* General icon colors — neutral gray for dark backgrounds */ +.x-tree-icon-custom, +.x-grid-icon-custom, +.fa-tags::before, +.fa-file-o::before, +.fa-building::before, +.x-action-col-icon::before, +.fa-shield::before, +.fa-file-text-o::before, +.fa-clock-o::before, +.x-tab-icon-el-default, +.pve-icon-verify-lettering::after, +.x-tree-icon-leaf:not(.x-tree-icon-custom)::before, +.x-tree-icon-parent:not(.x-tree-icon-custom)::before, +.x-tree-icon-parent-expanded:not(.x-tree-icon-custom)::before, +.x-grid-filters-filtered-column .x-column-header-text::after { + color: var(--sol-overlay2) !important; +} + +/* Folder icons — invert for dark mode */ +.x-tree-icon-parent:not(.x-tree-icon-custom)::before, +.x-tree-icon-parent-expanded:not(.x-tree-icon-custom)::before { + filter: invert(90%); +} + +/* Various image-based icons — invert for visibility */ +.fa-ceph::before, +.fa-sdn::before, +.fa-network-wired::before, +.pve-itype-treelist-item-icon-cdrom, +.fa-chevron-right::before, +.x-grid-row-console, +.x-box-scroller-toolbar-default.x-box-scroller, +.x-tree-elbow-img, +.pve-itype-icon-qemu, +.x-tree-node-computer, +.x-grid-tree-node-expanded .x-tree-node-computer, +.pbs-icon-tape, +.pbs-icon-tape-drive, +.x-tree-icon-leaf:not(.x-tree-icon-custom), +.x-tree-icon-parent:not(.x-tree-icon-custom), +.x-tree-icon-parent-expanded:not(.x-tree-icon-custom) { + filter: invert(90%); +} + +/* Hardware icons */ +.pve-itype-icon-cpu, +.pve-itype-icon-cdrom, +.pve-itype-icon-memory, +.pve-itype-icon-pci, +.pve-itype-icon-serial, +.pve-itype-icon-die, +.pmx-itype-icon-processor, +.pmx-itype-icon-memory, +.pve-itype-icon-storage, +.x-tree-node-harddisk, +.x-grid-tree-node-expanded .x-tree-node-harddisk { + filter: invert(100%); +} + +/* Hardware icons — counter-invert for non-SVG icon cells */ +td.pve-itype-icon-storage .x-grid-cell-inner, +td.x-tree-node-harddisk .x-grid-cell-inner { + filter: invert(100%) !important; +} + +/* Hardware icons — hide inverted borders for non-SVG icon cells */ +td.pve-itype-icon-storage, +td.x-tree-node-harddisk { + border-color: transparent !important; +} + +/* Hardware grid icons — mask-image renders SVG icons in theme text color + Replaces filter:invert approach for pve-itype-icon-* and pmx-itype-icon-* grid cells */ +td.pve-itype-icon-cpu, +td.pve-itype-icon-cdrom, +td.pve-itype-icon-memory, +td.pve-itype-icon-pci, +td.pve-itype-icon-serial, +td.pve-itype-icon-die, +td.pmx-itype-icon-processor, +td.pmx-itype-icon-memory { + filter: none !important; + background-image: none !important; + padding-left: 0 !important; + border-color: transparent !important; +} + +td.pve-itype-icon-cpu .x-grid-cell-inner, +td.pve-itype-icon-cdrom .x-grid-cell-inner, +td.pve-itype-icon-memory .x-grid-cell-inner, +td.pve-itype-icon-pci .x-grid-cell-inner, +td.pve-itype-icon-serial .x-grid-cell-inner, +td.pve-itype-icon-die .x-grid-cell-inner, +td.pmx-itype-icon-processor .x-grid-cell-inner, +td.pmx-itype-icon-memory .x-grid-cell-inner { + padding-left: 3px !important; +} + +td.pve-itype-icon-cpu .x-grid-cell-inner::before, +td.pve-itype-icon-cdrom .x-grid-cell-inner::before, +td.pve-itype-icon-memory .x-grid-cell-inner::before, +td.pve-itype-icon-pci .x-grid-cell-inner::before, +td.pve-itype-icon-serial .x-grid-cell-inner::before, +td.pve-itype-icon-die .x-grid-cell-inner::before, +td.pmx-itype-icon-processor .x-grid-cell-inner::before, +td.pmx-itype-icon-memory .x-grid-cell-inner::before { + content: '' !important; + display: inline-block !important; + width: 18px !important; + height: 14px !important; + vertical-align: middle !important; + margin-right: 10px !important; + background-color: currentColor !important; + -webkit-mask-size: contain !important; + mask-size: contain !important; + -webkit-mask-repeat: no-repeat !important; + mask-repeat: no-repeat !important; + -webkit-mask-position: center !important; + mask-position: center !important; +} + +td.pve-itype-icon-cpu .x-grid-cell-inner::before { + -webkit-mask-image: url('/pve2/images/icon-cpu.svg') !important; + mask-image: url('/pve2/images/icon-cpu.svg') !important; +} + +td.pve-itype-icon-memory .x-grid-cell-inner::before { + -webkit-mask-image: url('/pve2/images/icon-memory.svg') !important; + mask-image: url('/pve2/images/icon-memory.svg') !important; +} + +td.pve-itype-icon-cdrom .x-grid-cell-inner::before { + -webkit-mask-image: url('/pve2/images/icon-cd-drive.svg') !important; + mask-image: url('/pve2/images/icon-cd-drive.svg') !important; +} + +td.pve-itype-icon-pci .x-grid-cell-inner::before { + -webkit-mask-image: url('/pve2/images/icon-pci.svg') !important; + mask-image: url('/pve2/images/icon-pci.svg') !important; +} + +td.pve-itype-icon-serial .x-grid-cell-inner::before { + -webkit-mask-image: url('/pve2/images/icon-serial.svg') !important; + mask-image: url('/pve2/images/icon-serial.svg') !important; +} + +td.pve-itype-icon-die .x-grid-cell-inner::before { + -webkit-mask-image: url('/pve2/images/icon-die.svg') !important; + mask-image: url('/pve2/images/icon-die.svg') !important; +} + +td.pmx-itype-icon-processor .x-grid-cell-inner::before { + -webkit-mask-image: url('../images/icon-cpu.svg') !important; + mask-image: url('../images/icon-cpu.svg') !important; +} + +td.pmx-itype-icon-memory .x-grid-cell-inner::before { + -webkit-mask-image: url('../images/icon-ram.svg') !important; + mask-image: url('../images/icon-ram.svg') !important; +} + + +/* Icon overlays — default */ +.x-tree-icon-custom::after, +.x-grid-icon-custom::after { + color: var(--sol-overlay2) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* RUNNING VMs/CTs — Dracula Green */ +.x-tree-icon-custom.running::after, +.x-grid-icon-custom.running::after, +.x-treelist-item-icon.running::after { + color: var(--sol-green) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* ONLINE state — Green */ +.x-tree-icon-custom.online::after, +.x-grid-icon-custom.online::after { + color: var(--sol-green) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* Stopped/offline — Overlay1 (muted gray) */ +.x-tree-icon-custom.stopped, +.x-tree-icon-custom.offline, +.x-grid-icon-custom.stopped, +.x-grid-icon-custom.offline { + color: var(--sol-overlay1) !important; +} + +/* Unknown state — Overlay1 */ +.x-tree-icon-custom.unknown::after, +.x-grid-icon-custom.unknown::after { + color: var(--sol-overlay1) !important; +} + +/* ERROR states — Dracula Red */ +.x-tree-icon-custom.error::after, +.x-tree-icon-custom.offline::after, +.x-tree-icon-custom.ha-error::after, +.x-grid-icon-custom.error::after, +.x-grid-icon-custom.offline::after, +.x-grid-icon-custom.ha-error::after { + color: var(--sol-red) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* PAUSED/SUSPENDED — Dracula Orange */ +.x-tree-icon-custom.paused::after, +.x-tree-icon-custom.suspended::after, +.x-tree-icon-custom.lock-suspending::after, +.x-grid-icon-custom.paused::after, +.x-grid-icon-custom.suspended::after, +.x-grid-icon-custom.lock-suspending::after { + color: var(--sol-orange) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* PENDING/WARNING states — Dracula Yellow */ +.x-tree-icon-custom.pending::after, +.x-tree-icon-custom.io-error::after, +.x-tree-icon-custom.internal-error::after, +.x-tree-icon-custom.guest-panicked::after, +.x-grid-icon-custom.pending::after, +.x-grid-icon-custom.io-error::after, +.x-grid-icon-custom.internal-error::after, +.x-grid-icon-custom.guest-panicked::after { + color: var(--sol-yellow) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* HA MAINTENANCE — Dracula Cyan */ +.x-tree-icon-custom.ha-maintenance::after, +.x-grid-icon-custom.ha-maintenance::after { + color: var(--sol-cyan) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* Locked icons */ +.x-tree-icon-custom.locked::after, +.x-tree-icon-custom.lock-backup::after, +.x-tree-icon-custom.lock-migrate::after, +.x-tree-icon-custom.lock-suspended::after, +.x-grid-icon-custom.locked::after, +.x-grid-icon-custom.lock-backup::after, +.x-grid-icon-custom.lock-migrate::after, +.x-grid-icon-custom.lock-suspended::after { + color: var(--sol-overlay2) !important; +} + +/* LXC/QEMU type indicators */ +.x-tree-icon-custom.lxc::after, +.x-tree-icon-custom.qemu::after, +.x-grid-icon-custom.lxc::after, +.x-grid-icon-custom.qemu::after { + background-color: transparent; + color: var(--sol-overlay1) !important; +} + +.x-treelist-item-icon.lxc::after, +.x-treelist-item-icon.qemu::after { + background-color: transparent; + color: var(--sol-overlay1) !important; +} + +/* Tree expander arrows */ +.x-tree-arrows .x-tree-expander { + filter: brightness(200%); +} + +/* Cancel sprite-inversion on custom controls (checkboxes/radios handled via CSS) */ +.x-form-checkbox-default, +.x-form-radio-default, +.x-column-header-checkbox .x-column-header-checkbox::after, +.x-grid-checkcolumn::after, +.x-menu-item-checked .x-menu-item-icon-default.x-menu-item-checkbox, +.x-menu-item-unchecked .x-menu-item-icon-default.x-menu-item-checkbox { + filter: none !important; +} + +/* ===================================================== + PANELS & HEADERS + ===================================================== */ +.x-panel, +.x-panel-default { + border-radius: var(--pm-radius-lg) !important; + padding: 0 !important; +} + +/* Column panels — native stacked layout (Issue #23 fix) */ +.x-panel.x-column { + padding: 5px !important; + margin: 0 !important; + max-width: none !important; + box-sizing: border-box !important; +} + +/* Column panel card styling — borders for summary + chart panels */ +.x-panel.x-panel-default.x-column { + border: 1px solid var(--sol-surface1) !important; + border-radius: var(--pm-radius-lg) !important; + overflow: hidden !important; +} + +/* Guest status + Notes panel borders */ +[id^="pveGuestStatusView-"].x-panel, +[id^="pveLxcStatusView-"].x-panel, +[id^="pveQemuStatusView-"].x-panel, +[id^="pmxNotesView-"].x-panel { + border: 1px solid var(--sol-surface1) !important; + border-radius: var(--pm-radius-lg) !important; +} + +.x-panel-body, +.x-panel-body-default { + background-color: var(--sol-base) !important; + color: var(--sol-text) !important; + border: none !important; +} + +/* Panel headers — bottom border only */ +.x-panel-header, +.x-panel-header-default { + background-color: var(--sol-mantle) !important; + border: none !important; + border-bottom: 1px solid var(--sol-surface1) !important; + border-radius: var(--pm-radius-lg) var(--pm-radius-lg) 0 0 !important; + margin: 0 !important; + padding: 8px 12px !important; + width: 100% !important; + box-sizing: border-box !important; + overflow: visible !important; +} + +/* Title text — prevent border-radius clipping */ +.x-title-text, +.x-title-text-default { + overflow: visible !important; +} + +.x-panel-bodyWrap, +.x-panel-bodyWrap-default { + margin: 0 !important; + padding: 0 !important; + overflow: visible !important; +} + +/* Remove borders from nested panels */ +.x-panel-body > .x-box-layout-ct, +.x-panel-body > .x-container, +.x-panel-body > .x-box-inner, +[id*="pmxGauge"] { + border: none !important; +} + +.x-panel-header-title-default, +.x-window-header-title-default { + color: var(--sol-text) !important; +} + +.x-panel-header-default .x-tool-tool-el { + background-color: transparent; +} + +.x-tool-img { + filter: brightness(175%); +} + +.x-tool-over .x-tool-img { + filter: brightness(200%); +} + +/* Resource tree — panel body border */ +div[id^="pveResourceTree-"][id$="-body"] { + border-color: var(--sol-base) !important; +} + +/* Resource tree — remove row separators */ +[id^="pveResourceTree-"].x-tree-panel td.x-grid-cell, +[id^="pveResourceTree-"].x-tree-panel .x-grid-td, +[id^="pveResourceTree-"].x-tree-panel .x-grid-cell { + border-bottom: none !important; +} + +/* Resource tree — row spacing */ +div[id^="pveResourceTree"] .x-grid-cell { + padding-top: 3px !important; + padding-bottom: 3px !important; +} + +/* Summary/stats panel radius overrides */ +.pveStatusPanel, +.x-panel-default-framed, +.x-panel-body-default-framed { + border-radius: 12px !important; +} + +.x-panel-header-default-framed { + border-radius: 12px 12px 0 0 !important; +} + +/* Column widget panel radius */ +.x-panel.x-column > .x-panel-bodyWrap > .x-panel-body.x-panel-body-default { + border-radius: var(--pm-radius-lg) !important; +} + +/* ===================================================== + SPLITTERS / SEPARATORS + ===================================================== */ +.x-splitter-vertical { + background-color: transparent !important; + border-left: 1px solid var(--sol-surface1) !important; + border-right: none !important; + width: 1px !important; +} + +.x-splitter-horizontal { + background-color: var(--sol-crust) !important; + border-top: 1px solid var(--sol-surface1) !important; +} + +.x-splitter { + background-color: var(--sol-crust) !important; +} + +.x-keyboard-mode .x-splitter-focus::after { + border-color: var(--sol-purple) !important; +} + +.x-layout-split-bottom { + opacity: 0.7; +} + +/* Toolbox tree (pve-nav) right border — full height */ +.pve-toolbar-bg { + border-right: 1px solid var(--sol-surface1) !important; + z-index: 3 !important; +} + +.x-treelist.x-treelist-pve-nav { + border-right: none !important; +} + +/* ===================================================== + TOOLBARS + ===================================================== */ +.x-toolbar, +.x-toolbar-default { + background-color: var(--sol-base) !important; + border-color: var(--sol-surface1) !important; +} + +.x-toolbar-default.x-docked-top { + border: none !important; + border-bottom: 1px solid var(--sol-surface1) !important; +} + +.x-toolbar-default .x-toolbar-separator { + border-color: var(--sol-surface1); +} + +.x-toolbar-text-default { + color: var(--sol-subtext0); +} + +/* ===================================================== + PRIMARY BUTTONS — Dracula Purple + ===================================================== */ +.x-btn-default-small { + background-color: var(--sol-purple) !important; + border: 1px solid rgba(189, 147, 249, 0.4) !important; + border-radius: var(--pm-radius-md) !important; + transition: background-color 0.15s ease, box-shadow 0.15s ease !important; +} + +.x-btn-default-small .x-btn-inner { + color: var(--sol-on-accent) !important; + font-weight: 600 !important; +} + +.x-btn-default-small .x-btn-icon-el { + color: var(--sol-on-accent) !important; +} + +.x-btn-default-small.x-btn-over, +.x-keyboard-mode .x-btn-default-small.x-btn-focus { + background-color: #caa9fa !important; + box-shadow: 0 0 0 3px var(--sol-accent-subtle) !important; +} + +.x-btn-default-small.x-btn.x-btn-disabled { + background-color: var(--sol-purple) !important; + opacity: 0.4; +} + +.x-btn-default-small.x-btn.x-btn-pressed { + background-color: #a986f0 !important; +} + +/* Button height consistency — 28px with vertical centering */ +/* Exclude tag edit buttons (display:none when hidden, :has(.fa-check) for checkmark) */ +.x-btn.x-btn-default-small:not(.x-btn-default-toolbar-small):not([style*="display: none"]):not([style*="display:none"]):not(:has(.fa-check)) { + height: 28px !important; + min-height: 28px !important; + display: flex !important; + align-items: center !important; + padding: 3px 8px !important; +} + +/* Fix button inner element centering for proper icon alignment (issue #17) */ +.x-btn.x-btn-default-small:not(.x-btn-default-toolbar-small):not([style*="display: none"]):not([style*="display:none"]):not(:has(.fa-check)) .x-btn-wrap { + display: flex !important; + align-items: center !important; +} + +.x-btn.x-btn-default-small:not(.x-btn-default-toolbar-small):not([style*="display: none"]):not([style*="display:none"]):not(:has(.fa-check)) .x-btn-inner { + display: flex !important; + align-items: center !important; +} + +/* Fix dropdown arrows on split/arrow buttons */ +.x-btn-wrap.x-btn-arrow-right::after, +.x-btn-wrap.x-btn-split-right::after { + height: 16px !important; + min-height: 16px !important; + width: 20px !important; + display: flex !important; + align-items: center !important; +} + +/* Fix icon-only buttons — hide   inner element when button has no text */ +.x-btn-no-text .x-btn-inner, +.x-btn-button.x-btn-no-text .x-btn-inner, +.x-btn-button-default-toolbar-small.x-btn-no-text .x-btn-inner-default-toolbar-small, +.x-btn-button-default-small.x-btn-no-text .x-btn-inner-default-small, +.x-btn-button-default-small.x-btn-no-text > .x-btn-inner-default-small { + display: none !important; +} + +/* Specific fix for fa-desktop icon (Create VM) — visually bottom-heavy */ +.x-btn-icon-el.fa-desktop { + transform: translateY(1.1px) !important; +} + +/* ===================================================== + SECONDARY / TOOLBAR BUTTONS + ===================================================== */ +.x-btn-default-toolbar-small { + background-color: var(--sol-surface0) !important; + border: 1px solid var(--sol-surface1) !important; + border-radius: var(--pm-radius-md) !important; + transition: background-color 0.15s ease, border-color 0.15s ease !important; +} + +.x-btn-default-toolbar-small .x-btn-inner-default-toolbar-small, +.x-btn-default-toolbar-small .x-btn-icon-el-default-toolbar-small { + color: var(--sol-text) !important; +} + +.x-btn-default-toolbar-small .x-btn-wrap-default-toolbar-small.x-btn-arrow-right::after, +.x-btn-default-toolbar-small .x-btn-wrap-default-toolbar-small.x-btn-split-right::after { + filter: brightness(150%); +} + +.x-btn-default-toolbar-small.x-btn-over, +.x-keyboard-mode .x-btn-default-toolbar-small.x-btn-focus { + background-color: var(--sol-surface1) !important; + border-color: var(--sol-surface2) !important; +} + +.x-btn-default-toolbar-small.x-btn.x-btn-disabled { + background-color: var(--sol-surface0) !important; + opacity: 0.4; +} + +.x-btn-default-toolbar-small.x-btn.x-btn-menu-active, +.x-btn-default-toolbar-small.x-btn.x-btn-pressed { + background-color: var(--sol-purple) !important; + border-color: var(--sol-purple) !important; + padding: 4px 8px !important; /* Fix #30: prevent width change on dropdown */ +} + +.x-btn-default-toolbar-small.x-btn.x-btn-pressed .x-btn-inner-default-toolbar-small, +.x-btn-default-toolbar-small.x-btn.x-btn-pressed .x-btn-icon-el-default-toolbar-small, +.x-btn-default-toolbar-small.x-btn.x-btn-pressed .x-btn-inner-default-small, +.x-btn-default-toolbar-small.x-btn.x-btn-pressed .x-btn-icon-el-default-small { + color: var(--sol-on-accent) !important; +} + +/* Segmented buttons */ +.x-segmented-button { + border-radius: var(--pm-radius-md) !important; +} + +.x-segmented-button .x-btn, +.x-segmented-button .x-btn-default-small, +.x-segmented-button .x-btn-inner, +.x-segmented-button .x-btn-wrap { + border-radius: var(--pm-radius-md) !important; +} + +/* Inline buttons (Documentation, Help) */ +.proxmox-inline-button { + height: 28px !important; + min-height: 28px !important; + display: flex !important; + align-items: center !important; + padding: 3px 8px !important; + background-color: var(--sol-surface0) !important; + border: 1px solid var(--sol-surface1) !important; + border-radius: var(--pm-radius-md) !important; + color: var(--sol-text) !important; + transition: background-color 0.15s ease !important; +} + +.proxmox-inline-button:hover, +.proxmox-inline-button.x-btn-over { + background-color: var(--sol-surface1) !important; + border-color: var(--sol-overlay0) !important; +} + +.proxmox-inline-button:active, +.proxmox-inline-button.x-btn-pressed { + background-color: var(--sol-surface2) !important; +} + +.proxmox-inline-button .x-btn-inner, +.proxmox-inline-button .x-btn-icon-el { + color: var(--sol-text) !important; +} + +/* Pressed/active inline buttons — use on-accent text */ +.proxmox-inline-button.x-btn-pressed .x-btn-inner, +.proxmox-inline-button.x-btn-pressed .x-btn-icon-el, +.proxmox-inline-button.x-btn-menu-active .x-btn-inner, +.proxmox-inline-button.x-btn-menu-active .x-btn-icon-el { + color: var(--sol-on-accent) !important; +} + +/* ===================================================== + FORM ELEMENTS + ===================================================== */ +.x-form-trigger-default { + background-color: var(--sol-surface0) !important; +} + +.x-form-text-default { + background-color: var(--sol-surface0) !important; + color: var(--sol-text) !important; + border-radius: var(--pm-radius-sm) !important; +} + +.x-form-trigger-wrap, +.x-form-trigger-wrap-default { + border-color: var(--sol-surface1) !important; + background-color: var(--sol-surface0) !important; + border-radius: var(--pm-radius-sm) !important; + transition: border-color 0.15s ease !important; +} + +.x-form-trigger-wrap-default.x-form-trigger-wrap-focus { + border-color: var(--sol-purple) !important; + box-shadow: 0 0 0 3px var(--sol-accent-subtle) !important; +} + +.x-form-item-label-default, +.x-form-cb-label-default { + color: var(--sol-text) !important; +} + +.x-form-display-field-default { + color: var(--sol-subtext0) !important; + border-radius: var(--pm-radius-md) !important; +} + +.x-form-spinner-default { + background-color: var(--sol-surface0) !important; +} + +.x-fieldset, +.x-fieldset-default { + border-color: var(--sol-surface1) !important; + border-radius: var(--pm-radius-lg) !important; +} + +.x-fieldset-header-default > .x-fieldset-header-text { + color: var(--sol-text) !important; +} + +/* ===================================================== + CHECKBOXES & RADIOS — Dracula styled + ===================================================== */ + +/* Base: remove sprite, styled as custom control */ +.x-form-checkbox, .x-form-checkbox-default, +.x-form-radio, .x-form-radio-default { + background-image: none !important; + background-color: var(--sol-surface0) !important; + border: 1.5px solid var(--sol-overlay0) !important; + width: 16px !important; + height: 16px !important; + display: inline-block !important; + box-sizing: border-box !important; + cursor: pointer !important; + transition: border-color 0.12s ease, background-color 0.12s ease !important; +} + +/* Checkbox: rounded square */ +.x-form-checkbox, .x-form-checkbox-default { + border-radius: 3px !important; +} + +/* Radio: circle + ::after inner dot */ +.x-form-radio, .x-form-radio-default { + border-radius: 50% !important; + position: relative !important; + transform: translateZ(0) !important; + box-shadow: inset 0 0 0 0 transparent !important; +} + +.x-form-radio::after { + content: '' !important; + position: absolute !important; + top: 50% !important; + left: 50% !important; + width: 7px !important; + height: 7px !important; + border-radius: 50% !important; + background: transparent !important; + transform: translate(-50%, -50%) scale(0) !important; + transition: transform 0.15s ease, background 0.15s ease !important; + pointer-events: none !important; +} + +/* Hover */ +.x-form-checkbox:hover, .x-form-checkbox-default:hover, +.x-form-cb-wrap:hover .x-form-checkbox { + border-color: var(--sol-purple) !important; +} + +.x-form-radio:hover, .x-form-radio-default:hover, +.x-form-cb-wrap:hover .x-form-radio { + border-color: var(--sol-purple) !important; +} + +/* CHECKED checkbox — Purple fill + dark SVG checkmark */ +.x-form-cb-checked .x-form-checkbox, +.x-form-cb-checked .x-form-checkbox-default { + background-color: var(--sol-purple) !important; + border-color: var(--sol-purple) !important; + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 8'%3E%3Cpath d='M1 4l3 3 5-6' fill='none' stroke='%23002b36' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") !important; + background-repeat: no-repeat !important; + background-position: center !important; + background-size: 9px 7px !important; +} + +/* SELECTED radio — Purple dot */ +.x-form-cb-checked .x-form-radio, +.x-form-cb-checked .x-form-radio-default { + border-color: var(--sol-purple) !important; + background-color: var(--sol-base) !important; +} + +.x-form-cb-checked .x-form-radio::after { + background: var(--sol-purple) !important; + transform: translate(-50%, -50%) scale(1) !important; +} + +/* ===================================================== + BOUNDLIST / DROPDOWNS + ===================================================== */ +.x-boundlist { + background-color: var(--sol-mantle) !important; + border: 1px solid var(--sol-surface1) !important; + border-radius: var(--pm-radius-md) !important; + box-shadow: 0 8px 24px rgba(30, 31, 41, 0.7) !important; + padding: 2px !important; + overflow: hidden !important; +} + +.x-boundlist-item { + background-color: transparent !important; + color: var(--sol-text) !important; + border-radius: var(--pm-radius-sm) !important; + padding: 2px 6px !important; + line-height: normal !important; + border: none !important; + cursor: pointer !important; + outline: none !important; + box-shadow: none !important; +} + +.x-boundlist-selected { + background-color: var(--sol-select-overlay) !important; + color: var(--sol-text) !important; +} + +.x-boundlist-item-over { + background-color: var(--sol-hover-overlay) !important; +} + +/* ===================================================== + GRIDS / TABLES + ===================================================== */ +.x-grid, +.x-grid-view { + border-radius: 0 !important; +} + +.x-column-header { + border-color: var(--sol-surface1) !important; + background-color: transparent !important; +} + +.x-column-header-inner, +.x-column-header-text { + color: var(--sol-text) !important; + font-weight: 600 !important; +} + +.x-column-header-trigger { + border-color: var(--sol-surface1) !important; +} + +.x-grid-item, +.x-column-header-default, +.x-grid-cell-row-numberer { + color: var(--sol-text) !important; + background-color: var(--sol-base) !important; +} + +.x-grid-cell-special { + border-color: var(--sol-surface1) !important; +} + +.x-grid-group-hd { + background-color: var(--sol-base) !important; + border-color: var(--sol-surface1) !important; +} + +.x-grid-group-title { + color: var(--sol-text) !important; +} + +.x-grid-header-ct { + background-color: var(--sol-mantle) !important; + border: 1px solid var(--sol-surface0) !important; + border-radius: var(--pm-radius-lg) var(--pm-radius-lg) 0 0 !important; +} + +.x-grid-item-alt { + background-color: var(--sol-crust) !important; +} + +.x-grid-with-row-lines .x-grid-item { + border-color: var(--sol-surface0) !important; +} + +.x-grid-cell { + border-bottom: 1px solid rgba(68, 71, 90, 0.4) !important; +} + +.x-grid-item-over, +.x-grid-with-row-lines .x-grid-item.x-grid-item-over { + background-color: var(--sol-hover-overlay) !important; +} + +.x-grid-item-selected, +.x-grid-with-row-lines .x-grid-item.x-grid-item-selected { + background-color: var(--sol-select-overlay) !important; +} + +.x-column-header-over, +.x-column-header-open { + background-color: var(--sol-hover-overlay) !important; +} + +.x-column-header-sort-ASC, +.x-column-header-sort-DESC { + background-color: var(--sol-hover-overlay) !important; +} + +.x-grid-row-summary .x-grid-cell, +.x-grid-row-summary .x-grid-rowwrap, +.x-grid-row-summary .x-grid-cell-rowbody { + background-color: var(--sol-base) !important; + border-color: var(--sol-surface1); +} + +.x-grid-with-col-lines .x-grid-cell, +.x-grid-with-col-lines .x-grid-item-over .x-grid-cell, +.x-grid-with-col-lines .x-grid-item-selected .x-grid-cell { + border-color: var(--sol-surface1) !important; +} + +.x-dd-drag-proxy { + background-color: var(--sol-mantle); + border-color: var(--sol-surface1); + color: var(--sol-text); +} + +.x-keyboard-mode .x-grid-item-focused { + background-color: var(--sol-hover-overlay) !important; + color: var(--sol-text) !important; +} + +/* Remove blue outline from focused/selected items in resource tree */ +.x-keyboard-mode .x-grid-item-focused .x-grid-cell-inner::before, +.x-keyboard-mode .x-grid-item-selected .x-grid-cell-inner::before, +.x-grid-item-selected .x-grid-cell-inner::before, +.x-grid-item-focused .x-grid-cell-inner::before, +[id^="pveResourceTree"] .x-grid-item-selected .x-grid-cell-inner::before, +[id^="pveResourceTree"] .x-grid-item-focused .x-grid-cell-inner::before { + content: none !important; + display: none !important; + border: none !important; +} + +.x-grid-empty { + background-color: var(--sol-base) !important; + color: var(--sol-subtext0) !important; +} + +/* Grid info (pve-info-grid) and RRD view */ +.pve-info-grid { + border-radius: 12px !important; +} + +.pve-rrdview, +.rrdview { + border-radius: 12px !important; +} + +.pve-summary-status, +.x-container .pve-status { + border-radius: var(--pm-radius-lg) !important; +} + +[id^="pveGuestStatusView-"][id$="-body"], +[id^="pmxNotesView-"] .x-panel-body { + border-radius: var(--pm-radius-lg) !important; +} + +.x-panel-default[id*="notes"], +.pve-notes-view { + border-radius: var(--pm-radius-lg) !important; +} + +/* Floating grid pickers (storage/ISO selectors) */ +.x-layer.x-grid .x-grid-view, +.x-panel.x-layer.x-grid .x-grid-view, +.x-panel.x-layer.x-grid, +.x-layer.x-panel.x-grid { + border-radius: var(--pm-radius-sm) !important; +} + +.x-layer.x-grid .x-grid-item-over, +.x-layer.x-grid .x-grid-item-selected, +.x-panel.x-layer.x-grid .x-grid-item-over, +.x-panel.x-layer.x-grid .x-grid-item-selected { + border-radius: var(--pm-radius-sm) !important; + outline: none !important; + box-shadow: none !important; +} + +.x-layer.x-grid .x-grid-item-over td, +.x-layer.x-grid .x-grid-item-selected td, +.x-layer.x-grid .x-grid-item-over .x-grid-cell, +.x-layer.x-grid .x-grid-item-selected .x-grid-cell, +.x-panel.x-layer.x-grid .x-grid-item-over td, +.x-panel.x-layer.x-grid .x-grid-item-selected td, +.x-panel.x-layer.x-grid .x-grid-item-over .x-grid-cell, +.x-panel.x-layer.x-grid .x-grid-item-selected .x-grid-cell { + border-radius: 0 !important; +} + +.x-layer.x-grid .x-grid-item-over td:first-child, +.x-layer.x-grid .x-grid-item-selected td:first-child, +.x-panel.x-layer.x-grid .x-grid-item-over td:first-child, +.x-panel.x-layer.x-grid .x-grid-item-selected td:first-child { + border-radius: var(--pm-radius-sm) 0 0 var(--pm-radius-sm) !important; +} + +.x-layer.x-grid .x-grid-item-over td:last-child, +.x-layer.x-grid .x-grid-item-selected td:last-child, +.x-panel.x-layer.x-grid .x-grid-item-over td:last-child, +.x-panel.x-layer.x-grid .x-grid-item-selected td:last-child { + border-radius: 0 var(--pm-radius-sm) var(--pm-radius-sm) 0 !important; +} + +/* ===================================================== + MENUS + ===================================================== */ +.x-menu, +.x-menu-default { + background-color: var(--sol-crust) !important; + border: 1px solid var(--sol-surface0) !important; + border-radius: var(--pm-radius-lg) !important; + box-shadow: 0 8px 24px rgba(30, 31, 41, 0.8) !important; + padding: 4px !important; + overflow: hidden !important; +} + +.x-menu-body-default { + background-color: transparent !important; + padding: 4px !important; +} + +.x-menu-header { + background-color: transparent !important; + color: var(--sol-text) !important; +} + +/* Menu icon separator — hide */ +.x-menu-icon-separator-default { + display: none !important; +} + +/* Menu item layout (flexbox reordering) */ +.x-menu-item-default > .x-menu-item-link { + display: flex !important; + align-items: center !important; + flex-direction: row !important; + gap: 4px !important; + justify-content: flex-start !important; + flex-wrap: nowrap !important; + border-radius: var(--pm-radius-md) !important; + padding: 4px 8px !important; + line-height: 20px !important; + border: none !important; + cursor: pointer !important; + outline: none !important; + box-shadow: none !important; + white-space: nowrap !important; + text-decoration: none !important; +} + +.x-menu-item-text-default { + color: var(--sol-text) !important; + font-size: 13px !important; + order: 1 !important; + margin-left: 0 !important; + text-align: left !important; + line-height: 20px !important; + display: inline-flex !important; + align-items: center !important; + flex: 1 1 auto !important; + width: auto !important; + white-space: nowrap !important; +} + +.x-menu-item-icon-default { + color: var(--sol-subtext0) !important; + order: -1 !important; + position: relative !important; + float: none !important; + margin-right: 8px !important; + margin-left: 0 !important; + left: auto !important; + top: auto !important; + width: 16px !important; + text-align: center !important; + display: inline-flex !important; + align-items: center !important; + justify-content: center !important; + height: 20px !important; + line-height: 20px !important; + vertical-align: middle !important; + flex: 0 0 16px !important; + align-self: center !important; +} + +.x-menu-item-arrow, +.x-menu-item-arrow-default { + order: 2 !important; + margin-left: auto !important; +} + +.x-menu-item-default.x-menu-item-separator { + background-color: var(--sol-surface0) !important; + border: none !important; + height: 1px !important; + margin: 6px 4px !important; +} + +.x-menu-item-default.x-menu-item-focus, +.x-menu-item-default.x-menu-item-active, +.x-menu-item:hover { + background-color: var(--sol-surface0) !important; + color: var(--sol-text) !important; + border-radius: var(--pm-radius-md) !important; +} + +.x-menu-item-active .x-menu-item-text-default, +.x-menu-item-focus .x-menu-item-text-default { + color: var(--sol-text) !important; +} + +.x-menu-item-active .x-menu-item-icon-default, +.x-menu-item-focus .x-menu-item-icon-default { + color: var(--sol-cyan) !important; +} + +/* ===================================================== + PROGRESS BARS + ===================================================== */ + +/* Fix: Widget containers need overflow visible to not clip progress bars */ +.x-container[id^="pmxInfoWidget"], +.x-container.x-box-layout-ct { + overflow: visible !important; +} + +.x-progress, +.x-progress-default { + background-color: var(--sol-surface0) !important; + border-radius: 5px !important; +} + +.x-progress-default .x-progress-bar-default { + background-color: var(--sol-purple) !important; + border-radius: 5px !important; + transition: width 0.4s ease !important; +} + +.x-progress-default .x-progress-text { + color: var(--sol-text) !important; +} + +/* Text overlaid on the progress bar fill — use on-accent for contrast */ +.x-progress-bar .x-progress-text { + color: var(--sol-on-accent) !important; +} + +.x-progress.warning .x-progress-bar { + background-color: var(--sol-yellow) !important; +} + +.x-progress.critical .x-progress-bar { + background-color: var(--sol-red) !important; +} + +/* ===================================================== + TABS — Dracula underline style + Flat tabs with Purple underline on active tab + ===================================================== */ +.x-tab-bar, +.x-tab-bar-default { + background-color: var(--sol-base) !important; + border-radius: 0 !important; + border-bottom: 1px solid var(--sol-surface1) !important; + padding-bottom: 0 !important; +} + +/* Overflow visible for the underline indicator */ +.x-tab-bar .x-box-inner, +.x-tab-bar .x-box-target, +.x-tab-bar-body, +.x-tab-bar-body-default { + overflow: visible !important; +} + +/* Base tab */ +.x-tab, +.x-tab-default, +.x-tab-default-top { + background-color: transparent !important; + border: none !important; + border-radius: var(--pm-radius-md) var(--pm-radius-md) 0 0 !important; + padding: 8px 16px 8px !important; + overflow: visible !important; + margin-bottom: 0 !important; + transition: color 0.15s ease !important; + outline: none !important; + box-shadow: none !important; +} + +/* Remove ::after from inactive tabs */ +.x-tab::after { + display: none !important; +} + +.x-tab-inner-default { + color: var(--sol-subtext0) !important; + font-size: 13px !important; +} + +.x-tab-default.x-tab-over { + background-color: transparent !important; +} + +.x-tab-default.x-tab-over .x-tab-inner-default { + color: var(--sol-text) !important; +} + +/* Active tab */ +.x-tab-default.x-tab.x-tab-active { + background-color: transparent !important; + border: none !important; + overflow: visible !important; + margin-bottom: 0 !important; + outline: none !important; + box-shadow: none !important; +} + +/* Purple underline indicator on active tab */ +.x-tab-default.x-tab.x-tab-active::after { + content: '' !important; + display: block !important; + position: absolute !important; + bottom: 0 !important; + left: 0 !important; + right: 0 !important; + height: 2px !important; + background: var(--sol-purple) !important; + z-index: 10 !important; + border-radius: 2px 2px 0 0 !important; + pointer-events: none !important; +} + +.x-tab-active .x-tab-inner-default { + color: var(--sol-text) !important; + font-weight: 600 !important; +} + +.x-tab-default.x-tab.x-tab-disabled { + background-color: transparent !important; + border: none !important; + color: var(--sol-overlay0) !important; + margin-bottom: 0 !important; +} + +/* Focus states — no outline */ +.x-keyboard-mode .x-tab-default.x-tab-focus, +.x-keyboard-mode .x-tab-default.x-tab-focus.x-tab-active { + background-color: transparent !important; + border: none !important; + outline: none !important; + box-shadow: none !important; + margin-bottom: 0 !important; +} + +.x-keyboard-mode .x-tab-default.x-tab-focus.x-tab-active::after { + content: '' !important; + display: block !important; + position: absolute !important; + bottom: 0 !important; + left: 0 !important; + right: 0 !important; + height: 2px !important; + background: var(--sol-purple) !important; + z-index: 10 !important; + pointer-events: none !important; +} + +/* Kill ALL tab interaction outlines/shadows */ +.x-tab:focus, +.x-tab *:focus, +.x-tab-focus, +.x-tab-active.x-tab-focus, +.x-tab-inner-focus, +.x-tab-button-focus, +.x-tab-pressed, +.x-tab-active.x-tab-pressed, +.x-tab-over, +.x-tab:active, +.x-tab *:active { + outline: none !important; + box-shadow: none !important; +} + +.x-tabpanel-child { + border-radius: 0 0 var(--pm-radius-lg) var(--pm-radius-lg) !important; +} + +/* Tab hover/active corners */ +.x-tab-default.x-tab-over, +.x-tab-default.x-tab.x-tab-active { + border-radius: var(--pm-radius-md) var(--pm-radius-md) 0 0 !important; +} + +/* ===================================================== + TOOLTIPS + ===================================================== */ +.x-tip, +.x-tip-default { + background-color: var(--sol-mantle) !important; + border: 1px solid var(--sol-surface1) !important; + border-radius: var(--pm-radius-md) !important; + box-shadow: 0 4px 12px rgba(30, 31, 41, 0.5); +} + +.x-tip-body-default { + color: var(--sol-text) !important; +} + +.x-tip-form-invalid { + background-color: var(--sol-mantle) !important; + border-color: var(--sol-red) !important; +} + +.x-tip-body-form-invalid { + color: var(--sol-red) !important; +} + +/* ===================================================== + TREE NAVIGATION (Sidebar) + ===================================================== */ +.x-treelist-item { + background-color: var(--sol-base) !important; + border-radius: var(--pm-radius-md) !important; +} + +/* Pseudo-element approach for hover/selected highlighting */ +.x-treelist-row { + border-radius: var(--pm-radius-md) !important; + background-color: transparent !important; + position: relative !important; + z-index: 0 !important; +} + +.x-treelist-row::before { + content: ""; + position: absolute; + top: 1px; + bottom: 1px; + left: 0; + right: 4px; + border-radius: var(--pm-radius-md); + background-color: transparent; + z-index: -1; + pointer-events: none; + transition: background-color 0.15s ease; +} + +/* Fix toolbox tree item text overlapping icons */ +.x-treelist-item-text { + margin-left: 28px !important; +} + +/* Toolbox tree items — bright text */ +.x-treelist-item-text, +.x-treelist-item-icon, +.x-treelist.x-treelist-pve-nav .x-treelist-item-text, +.x-treelist.x-treelist-pve-nav .x-treelist-item-icon { + color: var(--sol-subtext1) !important; +} + +/* Hover state — apply to pseudo-element */ +.x-treelist-row-over { + background-color: transparent !important; +} + +.x-treelist-row-over::before { + background-color: var(--sol-hover-overlay) !important; +} + +.x-treelist-row-over .x-treelist-item-icon, +.x-treelist-row-over .x-treelist-item-text { + background-color: transparent !important; + color: var(--sol-text) !important; +} + +/* Selected/active item — Purple highlight */ +.x-treelist-item-selected > .x-treelist-row { + background-color: transparent !important; +} + +.x-treelist-item-selected > .x-treelist-row::before, +.x-treelist-item-selected > .x-treelist-row:hover::before { + background-color: var(--sol-purple) !important; +} + +.x-treelist-item-selected .x-treelist-item-text, +.x-treelist-item-selected .x-treelist-item-icon, +.x-treelist.x-treelist-pve-nav .x-treelist-item-selected .x-treelist-item-text, +.x-treelist.x-treelist-pve-nav .x-treelist-item-selected .x-treelist-item-icon { + color: var(--sol-on-accent) !important; +} + +.x-treelist-pve-nav { + background-color: var(--sol-base) !important; + border-color: var(--sol-surface1) !important; +} + +/* Tree navigation radius overrides */ +.x-treelist-item, +.x-treelist-item-tool { + border-radius: var(--pm-radius-sm) !important; +} + +.x-treelist-row, +.x-treelist-row:hover, +.x-treelist-row-over, +.x-treelist-item-selected > .x-treelist-row, +.x-treelist-item-selected > .x-treelist-row:hover, +.x-treelist-item-expanded > .x-treelist-row, +.x-treelist-item-expanded > .x-treelist-row-over, +.x-treelist-item-expandable > .x-treelist-row, +.x-treelist-item-expandable > .x-treelist-row-over { + border-radius: var(--pm-radius-sm) !important; +} + +.x-treelist-row::before { + border-radius: var(--pm-radius-sm) !important; +} + +.x-treelist-item-wrap, +.x-treelist-item-text, +.x-treelist-row, +.x-treelist-container, +.x-treelist-root-container, +.x-treelist, +.x-treelist-pve-nav { + border-radius: var(--pm-radius-sm) !important; +} + +/* Cursor pointer for interactive tree/grid items */ +.x-grid-cell, +.x-grid-cell-inner, +.x-tree-elbow-img, +.x-tree-icon, +.x-treelist-item, +.x-treelist-row, +.x-treelist-item-wrap, +.x-treelist-item-text, +.x-treelist-item-icon { + cursor: pointer !important; +} + +/* ===================================================== + WINDOWS / MODALS + ===================================================== */ +.x-window, +.x-window-default { + background-color: var(--sol-crust) !important; + border: 1px solid var(--sol-surface1) !important; + border-radius: var(--pm-radius-lg) !important; + box-shadow: 0 8px 24px rgba(30, 31, 41, 0.6) !important; + overflow: hidden !important; +} + +.x-window .x-window-header, +.x-window-header-default { + background-color: var(--sol-mantle) !important; + border-color: transparent !important; + border-radius: var(--pm-radius-lg) var(--pm-radius-lg) 0 0 !important; +} + +.x-window-header-default .x-mask { + background-color: rgba(30, 31, 41, 0.7); +} + +.x-window .x-window-body, +.x-window-body-default { + background-color: var(--sol-base) !important; + border-color: var(--sol-surface1) !important; + color: var(--sol-text) !important; + border-radius: 0 0 var(--pm-radius-lg) var(--pm-radius-lg) !important; +} + +.x-window-ghost { + background-color: var(--sol-base) !important; +} + +.x-window-header-default .x-tool-img { + background-color: transparent; +} + +.x-message-box .x-window-body { + background-color: var(--sol-mantle) !important; +} + +/* Respect ExtJS inline display:none on hidden dialog buttons */ +.x-message-box .x-btn.x-btn-default-small[style*="display: none"], +.x-message-box .x-btn.x-btn-default-small[style*="display:none"], +.x-window .x-toolbar-footer .x-btn[style*="display: none"], +.x-window .x-toolbar-footer .x-btn[style*="display:none"] { + display: none !important; +} + +/* Login dialog — clean inner panel borders */ +.x-window:has(#pveloginrealm) .x-panel-body { + border: none !important; + background: transparent !important; + width: auto !important; +} + +/* ===================================================== + CONSOLE / TERMINAL + ===================================================== */ +div.monitor { + border-color: var(--sol-surface1); +} + +.install-mask { + background-color: var(--sol-crust); + color: var(--sol-subtext0); +} + +.x-window.install-mask { + box-shadow: rgba(30, 31, 41, 0.5) 0 4px 20px !important; +} + +/* ===================================================== + LEGEND / CHARTS + ===================================================== */ +.x-legend-container { + background-color: var(--sol-base) !important; +} + +.x-legend-horizontal .x-legend-item { + background-color: var(--sol-mantle) !important; + color: var(--sol-text) !important; + border: 1px solid var(--sol-surface0) !important; +} + +/* Chart/RRD panel backgrounds */ +div[id*="rrdchart"], +.pve-rrddatastore, +.pmx-panel-rrd { + background-color: var(--sol-base) !important; +} + +.proxmox-rrd-panel canvas, +.proxmox-widget-toolkit canvas, +canvas.x-surface, +.x-surface canvas { + background-color: transparent !important; + opacity: 1 !important; +} + +.proxmox-rrd-panel, +.proxmox-rrd-chart { + background-color: var(--sol-base) !important; +} + +/* Chart text/labels */ +.x-surface text, +svg text { + fill: var(--sol-text) !important; +} + +/* ===================================================== + PROXMOX-SPECIFIC OVERRIDES + ===================================================== */ + +/* Logo inversion */ +img[id^="proxmoxlogo-"][id$="-img"], +img[id^="proxmoxLogoSvg-"][id$="-img"] { + filter: invert(1) hue-rotate(180deg); +} + +/* Invalid/warning/disabled rows */ +.proxmox-invalid-row { + background-color: rgba(255, 85, 85, 0.15) !important; +} + +.proxmox-warning-row { + background-color: rgba(255, 184, 108, 0.15) !important; +} + +.proxmox-disabled-row td { + color: var(--sol-overlay0) !important; +} + +/* Hints */ +.pmx-hint { + background-color: rgba(255, 184, 108, 0.15) !important; + white-space: nowrap !important; +} + +.pmx-hint a { + color: var(--sol-cyan) !important; +} + +/* Status text colors — Information → Cyan */ +.info-blue { + color: var(--sol-cyan) !important; +} + +.critical { + color: var(--sol-red) !important; +} + +/* Links */ +a { + color: var(--sol-cyan) !important; +} + +/* Markdown content */ +.pmx-md code { + background-color: var(--sol-mantle) !important; + color: var(--sol-pink) !important; + border-radius: var(--pm-radius-sm) !important; +} + +.pmx-md pre code { + border-color: var(--sol-surface1) !important; + background-color: var(--sol-crust) !important; +} + +.pmx-md a { + color: var(--sol-cyan) !important; +} + +.pmx-md table { + border-color: var(--sol-surface1) !important; +} + +.pmx-md th { + background-color: var(--sol-mantle) !important; + border-color: var(--sol-surface1) !important; +} + +.pmx-md td { + border-color: var(--sol-surface1) !important; +} + +/* APT repos */ +.proxmox-apt-repos .x-grid-group-hd { + background-color: var(--sol-base) !important; + border: none !important; +} + +.proxmox-apt-repos .x-grid-group-title { + color: var(--sol-text) !important; +} + +/* Tags */ +.pve-edit-tag { + border-radius: var(--pm-radius-md) !important; +} + +.pve-edit-tag.editable span { + background-color: var(--sol-mantle) !important; + color: var(--sol-text) !important; + border-color: var(--sol-surface1) !important; +} + +.x-tree-node-text .proxmox-tag-dark, +.x-tree-node-text .proxmox-tag-light, +.x-grid-cell-inner .proxmox-tag-dark, +.x-grid-cell-inner .proxmox-tag-light, +span.proxmox-tag-dark, +span.proxmox-tag-light { + border-radius: var(--pm-radius-md) !important; +} + +/* Checkmark button in tag edit — match toolbar button size */ +.x-btn.x-btn-default-small:has(.fa-check) { + min-height: 24px !important; + height: 24px !important; + padding: 3px 8px !important; + border-radius: var(--pm-radius-sm) !important; + background-color: var(--sol-purple) !important; + border: none !important; +} + +.x-btn.x-btn-default-small:has(.fa-check).x-btn-disabled { + background-color: transparent !important; + border: 1px solid var(--sol-surface1) !important; + opacity: 0.5 !important; +} + +.x-btn.x-btn-default-small:has(.fa-check) .fa-check { + color: var(--sol-on-accent) !important; +} + +.x-btn.x-btn-default-small:has(.fa-check).x-btn-disabled .fa-check { + color: var(--sol-overlay1) !important; +} + +.x-btn.x-btn-default-small:has(.fa-check):not(.x-btn-disabled):hover { + background-color: #caa9fa !important; +} + +.x-btn.x-btn-default-small:has(.fa-check) .x-btn-inner { + display: none !important; +} + +/* Date picker */ +.x-datepicker, +.x-datepicker-column-header, +.x-monthpicker { + background-color: var(--sol-base) !important; + color: var(--sol-text) !important; + border-color: transparent !important; +} + +.x-datepicker-header, +.x-datepicker-footer, +.x-monthpicker-buttons { + background-color: var(--sol-mantle) !important; +} + +.x-datepicker-date, +.x-monthpicker-item-inner { + color: var(--sol-text) !important; +} + +.x-datepicker-selected div.x-datepicker-date, +.x-monthpicker-item a.x-monthpicker-selected, +a.x-monthpicker-item-inner:hover, +div.x-datepicker-date:hover { + background-color: var(--sol-hover-overlay) !important; + color: var(--sol-text) !important; +} + +.x-datepicker-today .x-datepicker-date { + border-color: var(--sol-purple) !important; +} + +.x-datepicker-disabled .x-datepicker-date { + color: var(--sol-overlay0) !important; +} + +.x-datepicker-prev-day .x-datepicker-date, +.x-datepicker-next-day .x-datepicker-date { + color: var(--sol-overlay0) !important; +} + +/* Usage bars */ +.usage-wrapper, +.usage { + border-radius: 2px !important; +} + +.usage { + background-color: var(--sol-overlay2) !important; +} + +/* ===================================================== + SCROLLBARS + ===================================================== */ +::-webkit-scrollbar { + width: 8px; + height: 8px; +} + +::-webkit-scrollbar-track { + background: var(--sol-base); + border-radius: var(--pm-radius-sm); +} + +::-webkit-scrollbar-thumb { + background: var(--sol-surface2); + border-radius: var(--pm-radius-sm); + border: 1px solid transparent; + background-clip: padding-box; + transition: background 0.15s ease; +} + +::-webkit-scrollbar-thumb:hover { + background: var(--sol-overlay0); +} + +::-webkit-scrollbar-corner { + background: var(--sol-base); +} + +/* Firefox scrollbar */ +* { + scrollbar-width: thin; + scrollbar-color: var(--sol-surface2) var(--sol-base); +} + +/* ===================================================== + SELECTION HIGHLIGHT + ===================================================== */ +::selection { + background-color: rgba(98, 114, 164, 0.3); + color: var(--sol-text); +} + +/* ===================================================== + TRANSITIONS (smooth interactions) + ===================================================== */ + +/* Grid row transitions */ +.x-grid-item { + transition: background-color 0.15s ease !important; +} + +/* Tree pseudo-element transitions */ +.x-treelist-row::before { + transition: background-color 0.15s ease !important; +} + +/* Menu item transitions */ +.x-menu-item-default > .x-menu-item-link { + transition: background-color 0.12s ease !important; +} + +/* Boundlist item transitions */ +.x-boundlist-item { + transition: background-color 0.12s ease !important; +} + +/* Tab transitions */ +.x-tab { + transition: color 0.15s ease !important; +} + +/* Splitter transition */ +.x-splitter { + transition: background-color 0.15s ease !important; +} + +/* Tooltip transition */ +.x-tip { + transition: opacity 0.15s ease !important; +} + +/* Progress bar width transition */ +.x-progress-bar { + transition: width 0.4s ease !important; +} + +/* Scrollbar thumb transition */ +::-webkit-scrollbar-thumb { + transition: background 0.15s ease !important; +} + +/* Window close tool transition */ +.x-tool-img { + transition: filter 0.15s ease !important; +} +/* ===================================================== + TOOL ICONS - FontAwesome Replacements + (Ported from UniFi v5.86) + Replace sprite-based ExtJS tool icons with crisp + FontAwesome icons for better consistency and clarity + ===================================================== */ + +/* Base styling for all tool icons - remove sprite backgrounds */ +.x-tool-tool-el.x-tool-minus, +.x-tool-img.x-tool-minus, +.x-tool-tool-el.x-tool-collapse-right, +.x-tool-img.x-tool-collapse-right, +.x-tool-tool-el.x-tool-collapse-left, +.x-tool-img.x-tool-collapse-left, +.x-tool-tool-el.x-tool-expand-right, +.x-tool-img.x-tool-expand-right, +.x-tool-tool-el.x-tool-expand-left, +.x-tool-img.x-tool-expand-left, +.x-tool-tool-el.x-tool-maximize, +.x-tool-img.x-tool-maximize, +.x-tool-tool-el.x-tool-restore, +.x-tool-img.x-tool-restore, +.x-tool-tool-el.x-tool-gear, +.x-tool-img.x-tool-gear, +.x-tool-tool-el.x-tool-refresh, +.x-tool-img.x-tool-refresh, +.x-tool-tool-el.x-tool-close, +.x-tool-img.x-tool-close { + background-image: none !important; + font-family: "FontAwesome" !important; + font-size: 14px !important; + line-height: 16px !important; + text-align: center !important; + color: var(--pm-text-dim) !important; + transition: color 0.15s ease !important; + filter: none !important; + width: 16px !important; + height: 16px !important; + display: flex !important; + align-items: center !important; + justify-content: center !important; +} + +/* Close button - slightly larger */ +.x-tool-tool-el.x-tool-close, +.x-tool-img.x-tool-close { + font-size: 20px !important; +} + +/* Individual glyph assignments */ +.x-tool-tool-el.x-tool-minus::before, +.x-tool-img.x-tool-minus::before { + content: "\f010" !important; /* fa-search-minus (zoom out) */ +} + +.x-tool-tool-el.x-tool-collapse-right::before, +.x-tool-img.x-tool-collapse-right::before { + content: "\f054" !important; /* fa-chevron-right */ +} + +.x-tool-tool-el.x-tool-expand-left::before, +.x-tool-img.x-tool-expand-left::before { + content: "\f053" !important; /* fa-chevron-left */ +} + +.x-tool-tool-el.x-tool-collapse-left::before, +.x-tool-img.x-tool-collapse-left::before { + content: "\f053" !important; /* fa-chevron-left */ +} + +.x-tool-tool-el.x-tool-expand-right::before, +.x-tool-img.x-tool-expand-right::before { + content: "\f054" !important; /* fa-chevron-right */ +} + +.x-tool-tool-el.x-tool-maximize::before, +.x-tool-img.x-tool-maximize::before { + content: "\f065" !important; /* fa-expand */ +} + +.x-tool-tool-el.x-tool-restore::before, +.x-tool-img.x-tool-restore::before { + content: "\f066" !important; /* fa-compress */ +} + +.x-tool-tool-el.x-tool-gear::before, +.x-tool-img.x-tool-gear::before { + content: "\f013" !important; /* fa-cog */ +} + +.x-tool-tool-el.x-tool-refresh::before, +.x-tool-img.x-tool-refresh::before { + content: "\f021" !important; /* fa-refresh */ +} + +.x-tool-tool-el.x-tool-close::before, +.x-tool-img.x-tool-close::before { + content: "\f00d" !important; /* fa-times */ +} + +/* Hover state - all tool icons */ +.x-tool:hover .x-tool-tool-el.x-tool-minus, +.x-tool:hover .x-tool-img.x-tool-minus, +.x-tool:hover .x-tool-tool-el.x-tool-collapse-right, +.x-tool:hover .x-tool-img.x-tool-collapse-right, +.x-tool:hover .x-tool-tool-el.x-tool-collapse-left, +.x-tool:hover .x-tool-img.x-tool-collapse-left, +.x-tool:hover .x-tool-tool-el.x-tool-expand-right, +.x-tool:hover .x-tool-img.x-tool-expand-right, +.x-tool:hover .x-tool-tool-el.x-tool-expand-left, +.x-tool:hover .x-tool-img.x-tool-expand-left, +.x-tool:hover .x-tool-tool-el.x-tool-maximize, +.x-tool:hover .x-tool-img.x-tool-maximize, +.x-tool:hover .x-tool-tool-el.x-tool-restore, +.x-tool:hover .x-tool-img.x-tool-restore, +.x-tool:hover .x-tool-tool-el.x-tool-gear, +.x-tool:hover .x-tool-img.x-tool-gear, +.x-tool:hover .x-tool-tool-el.x-tool-refresh, +.x-tool:hover .x-tool-img.x-tool-refresh, +.x-tool:hover .x-tool-tool-el.x-tool-close, +.x-tool:hover .x-tool-img.x-tool-close { + color: var(--pm-text) !important; +} + +/* Disabled state */ +.x-tool-disabled .x-tool-tool-el, +.x-tool-disabled .x-tool-img { + opacity: 0.4 !important; + cursor: default !important; +} + +/* Inline FontAwesome tools (PVE-injected) */ +.x-tool-tool-el[style*="font-family:FontAwesome"], +.x-tool-tool-el[style*="font-family: FontAwesome"] { + color: var(--pm-text-dim) !important; + font-size: 14px !important; + line-height: 16px !important; + display: flex !important; + align-items: center !important; + justify-content: center !important; + width: 16px !important; + height: 16px !important; + transition: color 0.15s ease !important; + background-image: none !important; + background-color: transparent !important; +} + +.x-tool:not(.x-tool-disabled) .x-tool-tool-el[style*="font-family:FontAwesome"], +.x-tool:not(.x-tool-disabled) .x-tool-tool-el[style*="font-family: FontAwesome"] { + cursor: pointer !important; +} + +.x-tool.x-tool-disabled .x-tool-tool-el[style*="font-family:FontAwesome"], +.x-tool.x-tool-disabled .x-tool-tool-el[style*="font-family: FontAwesome"] { + cursor: default !important; + opacity: 0.4 !important; +} + +.x-tool .x-mask { + background-color: transparent !important; + backdrop-filter: none !important; + pointer-events: none !important; +} + +.x-tool:not(.x-tool-disabled):hover .x-tool-tool-el[style*="font-family:FontAwesome"], +.x-tool:not(.x-tool-disabled):hover .x-tool-tool-el[style*="font-family: FontAwesome"] { + color: var(--pm-text) !important; +} diff --git a/themes/theme-solarized-light.css b/themes/theme-solarized-light.css new file mode 100644 index 0000000..4e5e0c2 --- /dev/null +++ b/themes/theme-solarized-light.css @@ -0,0 +1,2237 @@ +/*!Solarized Light*/ + +/* ===================================================== + CSS VARIABLES + ===================================================== */ +:root { + /* Theme: Solarized Light */ + --pm-accent: #268bd2; + --pm-bg-base: #fdf6e3; + --pm-bg-surface: #eee8d5; + --pm-bg-elevated: #93a1a1; + --pm-text: #002b36; + --pm-text-dim: #073642; + --pm-success: #859900; + --pm-warning: #b58900; + --pm-error: #dc322f; + --pm-border: #93a1a1; + --pm-radius-sm: 4px; + --pm-radius-md: 6px; + --pm-radius-lg: 8px; + + /* Proxmox Widget Toolkit Mappings */ + --pwt-panel-background: var(--pm-bg-base); + --pwt-text-color: var(--pm-text); + --pwt-gauge-default: var(--pm-accent); + --pwt-gauge-back: var(--pm-bg-elevated); + --pwt-gauge-warn: var(--pm-warning); + --pwt-gauge-crit: var(--pm-error); + --pwt-chart-primary: var(--pm-accent); + --pwt-chart-grid-stroke: var(--pm-bg-elevated); + + /* Solarized theme internal variables (based on Dracula template structure) */ + --sol-text: var(--pm-text); + --sol-subtext0: var(--pm-text-dim); + --sol-subtext1: var(--pm-text-dim); + --sol-overlay0: var(--pm-border); + --sol-overlay1: var(--pm-text-dim); + --sol-overlay2: var(--pm-text-dim); + --sol-surface0: var(--pm-bg-surface); + --sol-surface1: var(--pm-bg-elevated); + --sol-surface2: var(--pm-bg-elevated); + --sol-base: var(--pm-bg-base); + --sol-mantle: #eee8d5; + --sol-crust: #eee8d5; + + --sol-on-accent: #fdf6e3; + --sol-hover-overlay: rgba(128, 128, 128, 0.12); + --sol-select-overlay: rgba(128, 128, 128, 0.25); + --sol-accent-muted: rgba(128, 128, 128, 0.4); + --sol-accent-subtle: rgba(128, 128, 128, 0.15); + + --sol-cyan: var(--pm-accent); + --sol-green: var(--pm-success); + --sol-orange: var(--pm-warning); + --sol-pink: var(--pm-accent); + --sol-purple: var(--pm-accent); + --sol-red: var(--pm-error); + --sol-yellow: var(--pm-warning); + + color-scheme: light; +} + +/* ===================================================== + GLOBAL BORDER-RADIUS ARCHITECTURE + (Ported from UniFi theme — reset everything, selectively re-apply) + ===================================================== */ +.x-border-box, +.x-border-box * { + border-radius: var(--pm-radius-lg); +} + +/* Remove rounded corners from grids/tables/lists */ +.x-grid, +.x-grid *, +.x-grid-header-ct, +.x-grid-header-ct *, +.x-grid-view, +.x-grid-view *, +.x-column-header, +.x-column-header *, +.x-grid-item, +.x-grid-cell, +.x-grid-cell-inner, +.x-grid-row, +table, +table *, +tr, +td, +th, +.x-legend, +.x-legend *, +.x-legend-container, +.x-legend-container *, +.x-legend-item, +.x-legend-horizontal .x-legend-item, +.x-legend-vertical .x-legend-item, +.x-legend-horizontal .x-legend-item:first-child, +.x-legend-horizontal .x-legend-item:last-child, +.x-legend-vertical .x-legend-item:first-child, +.x-legend-vertical .x-legend-item:last-child, +.x-tool, +.x-tool-tool-el, +.x-tool-default, +.x-tool-img { + border-radius: 0 !important; +} + +/* Form elements - exclude from global radius */ +.x-form-item, +.x-form-item-default, +.x-form-item-body, +.x-form-item-body-default, +.x-form-text-field-body, +.x-form-text-field-body-default, +.x-form-fieldcontainer, +.x-field, +.x-field-default, +.x-form-type-text { + border-radius: 0 !important; +} + +/* Reset layout containers that clip elements with overflow:hidden + radius */ +.x-box-layout-ct, +.x-panel-bodyWrap, +.x-panel-bodyWrap-default, +.x-autocontainer-innerCt, +.x-autocontainer-outerCt, +.x-panel.x-tabpanel-child, +.x-panel.x-box-item, +.x-box-inner, +.x-box-target, +.x-container, +.x-container-default, +.x-window .x-panel-body, +.x-window .x-window-body, +.x-window .x-window-bodyWrap { + border-radius: 0 !important; +} + +/* Reset everything inside windows to 0 — then re-apply specific radii */ +.x-window *, +.x-window .x-autocontainer-innerCt, +.x-window .x-autocontainer-outerCt, +.x-window .x-form-layout-wrap, +.x-window .x-form-layout-auto-label, +.x-window .x-form-layout-colgroup, +.x-window .x-form-layout-column, +.x-window .x-field, +.x-window .x-form-item, +.x-window .x-form-item-body { + border-radius: 0 !important; +} + +/* Chart canvas — no radius on data area */ +.x-chart-grid, +.x-chart-axis, +canvas.x-surface, +.x-chart canvas, +canvas.x-surface-canvas, +.x-surface-canvas, +.x-draw-component canvas, +.proxmox-rrd-chart canvas, +svg.x-surface, +.x-draw-container, +.x-surface { + border-radius: 0 !important; +} + +/* Legend color marker (dot) — keep circular */ +.x-legend-item-marker { + border-radius: 50% !important; +} + +/* ===================================================== + RE-APPLY BORDER RADII (selective) + ===================================================== */ + +/* Windows */ +.x-window, +.x-window-default { + border-radius: var(--pm-radius-lg) !important; +} + +.x-window-header, +.x-window-header-default { + border-radius: var(--pm-radius-lg) var(--pm-radius-lg) 0 0 !important; +} + +.x-window .x-window-body, +.x-window-body-default { + border-radius: 0 !important; +} + +/* Buttons inside windows */ +.x-window .x-btn { + border-radius: var(--pm-radius-md) !important; +} + +/* Checkboxes inside windows */ +.x-window .x-form-checkbox { + border-radius: 3px !important; +} + +/* Form inputs inside windows */ +.x-window .x-form-trigger-wrap, +.x-window .x-form-trigger-wrap-default { + border-radius: var(--pm-radius-sm) !important; +} + +.x-window .x-form-text-wrap, +.x-window .x-form-text { + border-radius: var(--pm-radius-sm) 0 0 var(--pm-radius-sm) !important; +} + +.x-window .x-form-arrow-trigger { + border-radius: 0 var(--pm-radius-sm) var(--pm-radius-sm) 0 !important; +} + +/* Form trigger/text wrap — reset and re-apply */ +.x-form-trigger-wrap, +.x-form-trigger-wrap *, +.x-form-text-wrap, +.x-form-text-wrap *, +.x-form-text, +.x-form-trigger { + border-radius: 0 !important; +} + +.x-form-trigger-wrap, +.x-form-trigger-wrap-default { + border-radius: var(--pm-radius-sm) !important; + overflow: hidden !important; +} + +.x-form-text-wrap, +.x-form-text-wrap-default { + border-radius: var(--pm-radius-sm) 0 0 var(--pm-radius-sm) !important; +} + +.x-form-text, +.x-form-text-default { + border-radius: var(--pm-radius-sm) 0 0 var(--pm-radius-sm) !important; +} + +.x-form-trigger, +.x-form-trigger-default, +.x-form-arrow-trigger, +.x-form-arrow-trigger-default { + border-radius: 0 var(--pm-radius-sm) var(--pm-radius-sm) 0 !important; +} + +/* Dialog form content padding — vertical only (horizontal causes ExtJS overflow) */ +.x-window .x-tabpanel-child .x-autocontainer-innerCt { + padding: 12px 0 !important; +} + +/* Allow column panel bodies to show overflowed form content */ +.x-window .x-panel-body:not(.x-scroller) { + overflow: visible !important; +} + +/* Side padding on column panel bodies inside windows */ +.x-window .x-panel.x-box-item .x-panel-body { + padding: 0 4px !important; +} + +/* Constrain autocontainer width inside windows */ +.x-window .x-autocontainer-outerCt { + max-width: 100% !important; +} + +/* Fix window header/body width consistency */ +.x-window > .x-window-header, +.x-window > .x-window-body, +.x-window > .x-window-bodyWrap, +.x-window-bodyWrap > .x-window-body { + width: 100% !important; +} + +.x-window-header > .x-box-inner, +.x-window-header > .x-box-inner > .x-box-target { + width: 100% !important; +} + +.x-window-header-title { + width: auto !important; + flex: 1 !important; + max-width: calc(100% - 30px) !important; +} + +/* Boundlists */ +.x-boundlist { + border-radius: var(--pm-radius-md) !important; + overflow: hidden !important; +} + +/* ===================================================== + BASE / BODY + ===================================================== */ +.x-body, +.x-viewport > .x-body, +body.x-border-layout-ct, +div.x-border-layout-ct { + background-color: var(--sol-base) !important; + color: var(--sol-text) !important; +} + +/* ===================================================== + MASKS & OVERLAYS + ===================================================== */ +.x-mask { + background-color: rgba(30, 31, 41, 0.6) !important; + backdrop-filter: blur(4px); +} + +.x-mask-msg { + background-color: var(--sol-mantle) !important; + border: 1px solid var(--sol-surface1) !important; + border-radius: var(--pm-radius-lg) !important; +} + +.x-mask-msg-text { + color: var(--sol-subtext0) !important; + filter: none !important; +} + +.x-css-shadow { + box-shadow: 0 8px 24px rgba(30, 31, 41, 0.6) !important; +} + +/* Loading indicators */ +.x-grid-row-loading, +.x-treelist-item-loading .x-treelist-item-icon, +.x-grid-tree-loading .x-tree-icon { + filter: none; +} + +/* ===================================================== + ICONS — Proxmox default colors for dark mode + ===================================================== */ + +/* General icon colors — neutral gray for dark backgrounds */ +.x-tree-icon-custom, +.x-grid-icon-custom, +.fa-tags::before, +.fa-file-o::before, +.fa-building::before, +.x-action-col-icon::before, +.fa-shield::before, +.fa-file-text-o::before, +.fa-clock-o::before, +.x-tab-icon-el-default, +.pve-icon-verify-lettering::after, +.x-tree-icon-leaf:not(.x-tree-icon-custom)::before, +.x-tree-icon-parent:not(.x-tree-icon-custom)::before, +.x-tree-icon-parent-expanded:not(.x-tree-icon-custom)::before, +.x-grid-filters-filtered-column .x-column-header-text::after { + color: var(--sol-overlay2) !important; +} + +/* Folder icons — invert for dark mode */ +.x-tree-icon-parent:not(.x-tree-icon-custom)::before, +.x-tree-icon-parent-expanded:not(.x-tree-icon-custom)::before { + filter: none; +} + +/* Various image-based icons — invert for visibility */ +.fa-ceph::before, +.fa-sdn::before, +.fa-network-wired::before, +.pve-itype-treelist-item-icon-cdrom, +.fa-chevron-right::before, +.x-grid-row-console, +.x-box-scroller-toolbar-default.x-box-scroller, +.x-tree-elbow-img, +.pve-itype-icon-qemu, +.x-tree-node-computer, +.x-grid-tree-node-expanded .x-tree-node-computer, +.pbs-icon-tape, +.pbs-icon-tape-drive, +.x-tree-icon-leaf:not(.x-tree-icon-custom), +.x-tree-icon-parent:not(.x-tree-icon-custom), +.x-tree-icon-parent-expanded:not(.x-tree-icon-custom) { + filter: none; +} + +/* Hardware icons */ +.pve-itype-icon-cpu, +.pve-itype-icon-cdrom, +.pve-itype-icon-memory, +.pve-itype-icon-pci, +.pve-itype-icon-serial, +.pve-itype-icon-die, +.pmx-itype-icon-processor, +.pmx-itype-icon-memory, +.pve-itype-icon-storage, +.x-tree-node-harddisk, +.x-grid-tree-node-expanded .x-tree-node-harddisk { + filter: none; +} + +/* Icon overlays — default */ +.x-tree-icon-custom::after, +.x-grid-icon-custom::after { + color: var(--sol-overlay2) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* RUNNING VMs/CTs — Dracula Green */ +.x-tree-icon-custom.running::after, +.x-grid-icon-custom.running::after, +.x-treelist-item-icon.running::after { + color: var(--sol-green) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* ONLINE state — Green */ +.x-tree-icon-custom.online::after, +.x-grid-icon-custom.online::after { + color: var(--sol-green) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* Stopped/offline — Overlay1 (muted gray) */ +.x-tree-icon-custom.stopped, +.x-tree-icon-custom.offline, +.x-grid-icon-custom.stopped, +.x-grid-icon-custom.offline { + color: var(--sol-overlay1) !important; +} + +/* Unknown state — Overlay1 */ +.x-tree-icon-custom.unknown::after, +.x-grid-icon-custom.unknown::after { + color: var(--sol-overlay1) !important; +} + +/* ERROR states — Dracula Red */ +.x-tree-icon-custom.error::after, +.x-tree-icon-custom.offline::after, +.x-tree-icon-custom.ha-error::after, +.x-grid-icon-custom.error::after, +.x-grid-icon-custom.offline::after, +.x-grid-icon-custom.ha-error::after { + color: var(--sol-red) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* PAUSED/SUSPENDED — Dracula Orange */ +.x-tree-icon-custom.paused::after, +.x-tree-icon-custom.suspended::after, +.x-tree-icon-custom.lock-suspending::after, +.x-grid-icon-custom.paused::after, +.x-grid-icon-custom.suspended::after, +.x-grid-icon-custom.lock-suspending::after { + color: var(--sol-orange) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* PENDING/WARNING states — Dracula Yellow */ +.x-tree-icon-custom.pending::after, +.x-tree-icon-custom.io-error::after, +.x-tree-icon-custom.internal-error::after, +.x-tree-icon-custom.guest-panicked::after, +.x-grid-icon-custom.pending::after, +.x-grid-icon-custom.io-error::after, +.x-grid-icon-custom.internal-error::after, +.x-grid-icon-custom.guest-panicked::after { + color: var(--sol-yellow) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* HA MAINTENANCE — Dracula Cyan */ +.x-tree-icon-custom.ha-maintenance::after, +.x-grid-icon-custom.ha-maintenance::after { + color: var(--sol-cyan) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* Locked icons */ +.x-tree-icon-custom.locked::after, +.x-tree-icon-custom.lock-backup::after, +.x-tree-icon-custom.lock-migrate::after, +.x-tree-icon-custom.lock-suspended::after, +.x-grid-icon-custom.locked::after, +.x-grid-icon-custom.lock-backup::after, +.x-grid-icon-custom.lock-migrate::after, +.x-grid-icon-custom.lock-suspended::after { + color: var(--sol-overlay2) !important; +} + +/* LXC/QEMU type indicators */ +.x-tree-icon-custom.lxc::after, +.x-tree-icon-custom.qemu::after, +.x-grid-icon-custom.lxc::after, +.x-grid-icon-custom.qemu::after { + background-color: transparent; + color: var(--sol-overlay1) !important; +} + +.x-treelist-item-icon.lxc::after, +.x-treelist-item-icon.qemu::after { + background-color: transparent; + color: var(--sol-overlay1) !important; +} + +/* Tree expander arrows */ +.x-tree-arrows .x-tree-expander { + filter: none; +} + +/* Cancel sprite-inversion on custom controls (checkboxes/radios handled via CSS) */ +.x-form-checkbox-default, +.x-form-radio-default, +.x-column-header-checkbox .x-column-header-checkbox::after, +.x-grid-checkcolumn::after, +.x-menu-item-checked .x-menu-item-icon-default.x-menu-item-checkbox, +.x-menu-item-unchecked .x-menu-item-icon-default.x-menu-item-checkbox { + filter: none !important; +} + +/* ===================================================== + PANELS & HEADERS + ===================================================== */ +.x-panel, +.x-panel-default { + border-radius: var(--pm-radius-lg) !important; + padding: 0 !important; +} + +/* Column panels — gaps + max-width prevents scrollbar-induced sub-pixel overflow */ +.x-panel.x-column { + padding: 5px !important; + margin: 0 !important; + max-width: none !important; + box-sizing: border-box !important; +} + +/* Column panel card styling — borders for summary + chart panels */ +.x-panel.x-panel-default.x-column { + border: 1px solid var(--sol-surface1) !important; + border-radius: var(--pm-radius-lg) !important; + overflow: hidden !important; +} + +/* Guest status + Notes panel borders */ +[id^="pveGuestStatusView-"].x-panel, +[id^="pveLxcStatusView-"].x-panel, +[id^="pveQemuStatusView-"].x-panel, +[id^="pmxNotesView-"].x-panel { + border: 1px solid var(--sol-surface1) !important; + border-radius: var(--pm-radius-lg) !important; +} + +.x-panel-body, +.x-panel-body-default { + background-color: var(--sol-base) !important; + color: var(--sol-text) !important; + border: none !important; +} + +/* Panel headers — bottom border only */ +.x-panel-header, +.x-panel-header-default { + background-color: var(--sol-mantle) !important; + border: none !important; + border-bottom: 1px solid var(--sol-surface1) !important; + border-radius: var(--pm-radius-lg) var(--pm-radius-lg) 0 0 !important; + margin: 0 !important; + padding: 8px 12px !important; + width: 100% !important; + box-sizing: border-box !important; + overflow: visible !important; +} + +/* Title text — prevent border-radius clipping */ +.x-title-text, +.x-title-text-default { + overflow: visible !important; +} + +.x-panel-bodyWrap, +.x-panel-bodyWrap-default { + margin: 0 !important; + padding: 0 !important; + overflow: visible !important; +} + +/* Remove borders from nested panels */ +.x-panel-body > .x-box-layout-ct, +.x-panel-body > .x-container, +.x-panel-body > .x-box-inner, +[id*="pmxGauge"] { + border: none !important; +} + +.x-panel-header-title-default, +.x-window-header-title-default { + color: var(--sol-text) !important; +} + +.x-panel-header-default .x-tool-tool-el { + background-color: transparent; +} + +.x-tool-img { + filter: none; +} + +.x-tool-over .x-tool-img { + filter: none; +} + +/* Resource tree — panel body border */ +div[id^="pveResourceTree-"][id$="-body"] { + border-color: var(--sol-base) !important; +} + +/* Resource tree — remove row separators */ +[id^="pveResourceTree-"].x-tree-panel td.x-grid-cell, +[id^="pveResourceTree-"].x-tree-panel .x-grid-td, +[id^="pveResourceTree-"].x-tree-panel .x-grid-cell { + border-bottom: none !important; +} + +/* Resource tree — row spacing */ +div[id^="pveResourceTree"] .x-grid-cell { + padding-top: 3px !important; + padding-bottom: 3px !important; +} + +/* Summary/stats panel radius overrides */ +.pveStatusPanel, +.x-panel-default-framed, +.x-panel-body-default-framed { + border-radius: 12px !important; +} + +.x-panel-header-default-framed { + border-radius: 12px 12px 0 0 !important; +} + +/* Column widget panel radius */ +.x-panel.x-column > .x-panel-bodyWrap > .x-panel-body.x-panel-body-default { + border-radius: var(--pm-radius-lg) !important; +} + +/* ===================================================== + SPLITTERS / SEPARATORS + ===================================================== */ +.x-splitter-vertical { + background-color: transparent !important; + border-left: 1px solid var(--sol-surface1) !important; + border-right: none !important; + width: 1px !important; +} + +.x-splitter-horizontal { + background-color: var(--sol-crust) !important; + border-top: 1px solid var(--sol-surface1) !important; +} + +.x-splitter { + background-color: var(--sol-crust) !important; +} + +.x-keyboard-mode .x-splitter-focus::after { + border-color: var(--sol-purple) !important; +} + +.x-layout-split-bottom { + opacity: 0.7; +} + +/* Toolbox tree (pve-nav) right border — full height */ +.pve-toolbar-bg { + border-right: 1px solid var(--sol-surface1) !important; + z-index: 3 !important; +} + +.x-treelist.x-treelist-pve-nav { + border-right: none !important; +} + +/* ===================================================== + TOOLBARS + ===================================================== */ +.x-toolbar, +.x-toolbar-default { + background-color: var(--sol-base) !important; + border-color: var(--sol-surface1) !important; +} + +.x-toolbar-default.x-docked-top { + border: none !important; + border-bottom: 1px solid var(--sol-surface1) !important; +} + +.x-toolbar-default .x-toolbar-separator { + border-color: var(--sol-surface1); +} + +.x-toolbar-text-default { + color: var(--sol-subtext0); +} + +/* ===================================================== + PRIMARY BUTTONS — Dracula Purple + ===================================================== */ +.x-btn-default-small { + background-color: var(--sol-purple) !important; + border: 1px solid rgba(189, 147, 249, 0.4) !important; + border-radius: var(--pm-radius-md) !important; + transition: background-color 0.15s ease, box-shadow 0.15s ease !important; +} + +.x-btn-default-small .x-btn-inner { + color: var(--sol-on-accent) !important; + font-weight: 600 !important; +} + +.x-btn-default-small .x-btn-icon-el { + color: var(--sol-on-accent) !important; +} + +.x-btn-default-small.x-btn-over, +.x-keyboard-mode .x-btn-default-small.x-btn-focus { + background-color: #caa9fa !important; + box-shadow: 0 0 0 3px var(--sol-accent-subtle) !important; +} + +.x-btn-default-small.x-btn.x-btn-disabled { + background-color: var(--sol-purple) !important; + opacity: 0.4; +} + +.x-btn-default-small.x-btn.x-btn-pressed { + background-color: #a986f0 !important; +} + +/* Button height consistency — 28px with vertical centering */ +/* Exclude tag edit buttons (display:none when hidden, :has(.fa-check) for checkmark) */ +.x-btn.x-btn-default-small:not(.x-btn-default-toolbar-small):not([style*="display: none"]):not([style*="display:none"]):not(:has(.fa-check)) { + height: 28px !important; + min-height: 28px !important; + display: flex !important; + align-items: center !important; + padding: 3px 8px !important; +} + +/* Fix button inner element centering for proper icon alignment (issue #17) */ +.x-btn.x-btn-default-small:not(.x-btn-default-toolbar-small):not([style*="display: none"]):not([style*="display:none"]):not(:has(.fa-check)) .x-btn-wrap { + display: flex !important; + align-items: center !important; +} + +.x-btn.x-btn-default-small:not(.x-btn-default-toolbar-small):not([style*="display: none"]):not([style*="display:none"]):not(:has(.fa-check)) .x-btn-inner { + display: flex !important; + align-items: center !important; +} + +/* Fix dropdown arrows on split/arrow buttons */ +.x-btn-wrap.x-btn-arrow-right::after, +.x-btn-wrap.x-btn-split-right::after { + height: 16px !important; + min-height: 16px !important; + width: 20px !important; + display: flex !important; + align-items: center !important; +} + +/* Fix icon-only buttons — hide   inner element when button has no text */ +.x-btn-no-text .x-btn-inner, +.x-btn-button.x-btn-no-text .x-btn-inner, +.x-btn-button-default-toolbar-small.x-btn-no-text .x-btn-inner-default-toolbar-small, +.x-btn-button-default-small.x-btn-no-text .x-btn-inner-default-small, +.x-btn-button-default-small.x-btn-no-text > .x-btn-inner-default-small { + display: none !important; +} + +/* Specific fix for fa-desktop icon (Create VM) — visually bottom-heavy */ +.x-btn-icon-el.fa-desktop { + transform: translateY(1.1px) !important; +} + +/* ===================================================== + SECONDARY / TOOLBAR BUTTONS + ===================================================== */ +.x-btn-default-toolbar-small { + background-color: var(--sol-surface0) !important; + border: 1px solid var(--sol-surface1) !important; + border-radius: var(--pm-radius-md) !important; + transition: background-color 0.15s ease, border-color 0.15s ease !important; +} + +.x-btn-default-toolbar-small .x-btn-inner-default-toolbar-small, +.x-btn-default-toolbar-small .x-btn-icon-el-default-toolbar-small { + color: var(--sol-text) !important; +} + +.x-btn-default-toolbar-small .x-btn-wrap-default-toolbar-small.x-btn-arrow-right::after, +.x-btn-default-toolbar-small .x-btn-wrap-default-toolbar-small.x-btn-split-right::after { + filter: none; +} + +.x-btn-default-toolbar-small.x-btn-over, +.x-keyboard-mode .x-btn-default-toolbar-small.x-btn-focus { + background-color: var(--sol-surface1) !important; + border-color: var(--sol-surface2) !important; +} + +.x-btn-default-toolbar-small.x-btn.x-btn-disabled { + background-color: var(--sol-surface0) !important; + opacity: 0.4; +} + +.x-btn-default-toolbar-small.x-btn.x-btn-menu-active, +.x-btn-default-toolbar-small.x-btn.x-btn-pressed { + background-color: var(--sol-purple) !important; + border-color: var(--sol-purple) !important; + padding: 4px 8px !important; /* Fix #30: prevent width change on dropdown */ +} + +.x-btn-default-toolbar-small.x-btn.x-btn-pressed .x-btn-inner-default-toolbar-small, +.x-btn-default-toolbar-small.x-btn.x-btn-pressed .x-btn-icon-el-default-toolbar-small, +.x-btn-default-toolbar-small.x-btn.x-btn-pressed .x-btn-inner-default-small, +.x-btn-default-toolbar-small.x-btn.x-btn-pressed .x-btn-icon-el-default-small { + color: var(--sol-on-accent) !important; +} + +/* Segmented buttons */ +.x-segmented-button { + border-radius: var(--pm-radius-md) !important; +} + +.x-segmented-button .x-btn, +.x-segmented-button .x-btn-default-small, +.x-segmented-button .x-btn-inner, +.x-segmented-button .x-btn-wrap { + border-radius: var(--pm-radius-md) !important; +} + +/* Inline buttons (Documentation, Help) */ +.proxmox-inline-button { + height: 28px !important; + min-height: 28px !important; + display: flex !important; + align-items: center !important; + padding: 3px 8px !important; + background-color: var(--sol-surface0) !important; + border: 1px solid var(--sol-surface1) !important; + border-radius: var(--pm-radius-md) !important; + color: var(--sol-text) !important; + transition: background-color 0.15s ease !important; +} + +.proxmox-inline-button:hover, +.proxmox-inline-button.x-btn-over { + background-color: var(--sol-surface1) !important; + border-color: var(--sol-overlay0) !important; +} + +.proxmox-inline-button:active, +.proxmox-inline-button.x-btn-pressed { + background-color: var(--sol-surface2) !important; +} + +.proxmox-inline-button .x-btn-inner, +.proxmox-inline-button .x-btn-icon-el { + color: var(--sol-text) !important; +} + +/* Pressed/active inline buttons — use on-accent text */ +.proxmox-inline-button.x-btn-pressed .x-btn-inner, +.proxmox-inline-button.x-btn-pressed .x-btn-icon-el, +.proxmox-inline-button.x-btn-menu-active .x-btn-inner, +.proxmox-inline-button.x-btn-menu-active .x-btn-icon-el { + color: var(--sol-on-accent) !important; +} + +/* ===================================================== + FORM ELEMENTS + ===================================================== */ +.x-form-trigger-default { + background-color: var(--sol-surface0) !important; +} + +.x-form-text-default { + background-color: var(--sol-surface0) !important; + color: var(--sol-text) !important; + border-radius: var(--pm-radius-sm) !important; +} + +.x-form-trigger-wrap, +.x-form-trigger-wrap-default { + border-color: var(--sol-surface1) !important; + background-color: var(--sol-surface0) !important; + border-radius: var(--pm-radius-sm) !important; + transition: border-color 0.15s ease !important; +} + +.x-form-trigger-wrap-default.x-form-trigger-wrap-focus { + border-color: var(--sol-purple) !important; + box-shadow: 0 0 0 3px var(--sol-accent-subtle) !important; +} + +.x-form-item-label-default, +.x-form-cb-label-default { + color: var(--sol-text) !important; +} + +.x-form-display-field-default { + color: var(--sol-subtext0) !important; + border-radius: var(--pm-radius-md) !important; +} + +.x-form-spinner-default { + background-color: var(--sol-surface0) !important; +} + +.x-fieldset, +.x-fieldset-default { + border-color: var(--sol-surface1) !important; + border-radius: var(--pm-radius-lg) !important; +} + +.x-fieldset-header-default > .x-fieldset-header-text { + color: var(--sol-text) !important; +} + +/* ===================================================== + CHECKBOXES & RADIOS — Dracula styled + ===================================================== */ + +/* Base: remove sprite, styled as custom control */ +.x-form-checkbox, .x-form-checkbox-default, +.x-form-radio, .x-form-radio-default { + background-image: none !important; + background-color: var(--sol-surface0) !important; + border: 1.5px solid var(--sol-overlay0) !important; + width: 16px !important; + height: 16px !important; + display: inline-block !important; + box-sizing: border-box !important; + cursor: pointer !important; + transition: border-color 0.12s ease, background-color 0.12s ease !important; +} + +/* Checkbox: rounded square */ +.x-form-checkbox, .x-form-checkbox-default { + border-radius: 3px !important; +} + +/* Radio: circle + ::after inner dot */ +.x-form-radio, .x-form-radio-default { + border-radius: 50% !important; + position: relative !important; + transform: translateZ(0) !important; + box-shadow: inset 0 0 0 0 transparent !important; +} + +.x-form-radio::after { + content: '' !important; + position: absolute !important; + top: 50% !important; + left: 50% !important; + width: 7px !important; + height: 7px !important; + border-radius: 50% !important; + background: transparent !important; + transform: translate(-50%, -50%) scale(0) !important; + transition: transform 0.15s ease, background 0.15s ease !important; + pointer-events: none !important; +} + +/* Hover */ +.x-form-checkbox:hover, .x-form-checkbox-default:hover, +.x-form-cb-wrap:hover .x-form-checkbox { + border-color: var(--sol-purple) !important; +} + +.x-form-radio:hover, .x-form-radio-default:hover, +.x-form-cb-wrap:hover .x-form-radio { + border-color: var(--sol-purple) !important; +} + +/* CHECKED checkbox — Purple fill + dark SVG checkmark */ +.x-form-cb-checked .x-form-checkbox, +.x-form-cb-checked .x-form-checkbox-default { + background-color: var(--sol-purple) !important; + border-color: var(--sol-purple) !important; + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 8'%3E%3Cpath d='M1 4l3 3 5-6' fill='none' stroke='%23fdf6e3' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") !important; + background-repeat: no-repeat !important; + background-position: center !important; + background-size: 9px 7px !important; +} + +/* SELECTED radio — Purple dot */ +.x-form-cb-checked .x-form-radio, +.x-form-cb-checked .x-form-radio-default { + border-color: var(--sol-purple) !important; + background-color: var(--sol-base) !important; +} + +.x-form-cb-checked .x-form-radio::after { + background: var(--sol-purple) !important; + transform: translate(-50%, -50%) scale(1) !important; +} + +/* ===================================================== + BOUNDLIST / DROPDOWNS + ===================================================== */ +.x-boundlist { + background-color: var(--sol-mantle) !important; + border: 1px solid var(--sol-surface1) !important; + border-radius: var(--pm-radius-md) !important; + box-shadow: 0 8px 24px rgba(30, 31, 41, 0.7) !important; + padding: 2px !important; + overflow: hidden !important; +} + +.x-boundlist-item { + background-color: transparent !important; + color: var(--sol-text) !important; + border-radius: var(--pm-radius-sm) !important; + padding: 2px 6px !important; + line-height: normal !important; + border: none !important; + cursor: pointer !important; + outline: none !important; + box-shadow: none !important; +} + +.x-boundlist-selected { + background-color: var(--sol-select-overlay) !important; + color: var(--sol-text) !important; +} + +.x-boundlist-item-over { + background-color: var(--sol-hover-overlay) !important; +} + +/* ===================================================== + GRIDS / TABLES + ===================================================== */ +.x-grid, +.x-grid-view { + border-radius: 0 !important; +} + +.x-column-header { + border-color: var(--sol-surface1) !important; + background-color: transparent !important; +} + +.x-column-header-inner, +.x-column-header-text { + color: var(--sol-text) !important; + font-weight: 600 !important; +} + +.x-column-header-trigger { + border-color: var(--sol-surface1) !important; +} + +.x-grid-item, +.x-column-header-default, +.x-grid-cell-row-numberer { + color: var(--sol-text) !important; + background-color: var(--sol-base) !important; +} + +.x-grid-cell-special { + border-color: var(--sol-surface1) !important; +} + +.x-grid-group-hd { + background-color: var(--sol-base) !important; + border-color: var(--sol-surface1) !important; +} + +.x-grid-group-title { + color: var(--sol-text) !important; +} + +.x-grid-header-ct { + background-color: var(--sol-mantle) !important; + border: 1px solid var(--sol-surface0) !important; + border-radius: var(--pm-radius-lg) var(--pm-radius-lg) 0 0 !important; +} + +.x-grid-item-alt { + background-color: var(--sol-crust) !important; +} + +.x-grid-with-row-lines .x-grid-item { + border-color: var(--sol-surface0) !important; +} + +.x-grid-cell { + border-bottom: 1px solid rgba(68, 71, 90, 0.4) !important; +} + +.x-grid-item-over, +.x-grid-with-row-lines .x-grid-item.x-grid-item-over { + background-color: var(--sol-hover-overlay) !important; +} + +.x-grid-item-selected, +.x-grid-with-row-lines .x-grid-item.x-grid-item-selected { + background-color: var(--sol-select-overlay) !important; +} + +.x-column-header-over, +.x-column-header-open { + background-color: var(--sol-hover-overlay) !important; +} + +.x-column-header-sort-ASC, +.x-column-header-sort-DESC { + background-color: var(--sol-hover-overlay) !important; +} + +.x-grid-row-summary .x-grid-cell, +.x-grid-row-summary .x-grid-rowwrap, +.x-grid-row-summary .x-grid-cell-rowbody { + background-color: var(--sol-base) !important; + border-color: var(--sol-surface1); +} + +.x-grid-with-col-lines .x-grid-cell, +.x-grid-with-col-lines .x-grid-item-over .x-grid-cell, +.x-grid-with-col-lines .x-grid-item-selected .x-grid-cell { + border-color: var(--sol-surface1) !important; +} + +.x-dd-drag-proxy { + background-color: var(--sol-mantle); + border-color: var(--sol-surface1); + color: var(--sol-text); +} + +.x-keyboard-mode .x-grid-item-focused { + background-color: var(--sol-hover-overlay) !important; + color: var(--sol-text) !important; +} + +/* Remove blue outline from focused/selected items in resource tree */ +.x-keyboard-mode .x-grid-item-focused .x-grid-cell-inner::before, +.x-keyboard-mode .x-grid-item-selected .x-grid-cell-inner::before, +.x-grid-item-selected .x-grid-cell-inner::before, +.x-grid-item-focused .x-grid-cell-inner::before, +[id^="pveResourceTree"] .x-grid-item-selected .x-grid-cell-inner::before, +[id^="pveResourceTree"] .x-grid-item-focused .x-grid-cell-inner::before { + content: none !important; + display: none !important; + border: none !important; +} + +.x-grid-empty { + background-color: var(--sol-base) !important; + color: var(--sol-subtext0) !important; +} + +/* Grid info (pve-info-grid) and RRD view */ +.pve-info-grid { + border-radius: 12px !important; +} + +.pve-rrdview, +.rrdview { + border-radius: 12px !important; +} + +.pve-summary-status, +.x-container .pve-status { + border-radius: var(--pm-radius-lg) !important; +} + +[id^="pveGuestStatusView-"][id$="-body"], +[id^="pmxNotesView-"] .x-panel-body { + border-radius: var(--pm-radius-lg) !important; +} + +.x-panel-default[id*="notes"], +.pve-notes-view { + border-radius: var(--pm-radius-lg) !important; +} + +/* Floating grid pickers (storage/ISO selectors) */ +.x-layer.x-grid .x-grid-view, +.x-panel.x-layer.x-grid .x-grid-view, +.x-panel.x-layer.x-grid, +.x-layer.x-panel.x-grid { + border-radius: var(--pm-radius-sm) !important; +} + +.x-layer.x-grid .x-grid-item-over, +.x-layer.x-grid .x-grid-item-selected, +.x-panel.x-layer.x-grid .x-grid-item-over, +.x-panel.x-layer.x-grid .x-grid-item-selected { + border-radius: var(--pm-radius-sm) !important; + outline: none !important; + box-shadow: none !important; +} + +.x-layer.x-grid .x-grid-item-over td, +.x-layer.x-grid .x-grid-item-selected td, +.x-layer.x-grid .x-grid-item-over .x-grid-cell, +.x-layer.x-grid .x-grid-item-selected .x-grid-cell, +.x-panel.x-layer.x-grid .x-grid-item-over td, +.x-panel.x-layer.x-grid .x-grid-item-selected td, +.x-panel.x-layer.x-grid .x-grid-item-over .x-grid-cell, +.x-panel.x-layer.x-grid .x-grid-item-selected .x-grid-cell { + border-radius: 0 !important; +} + +.x-layer.x-grid .x-grid-item-over td:first-child, +.x-layer.x-grid .x-grid-item-selected td:first-child, +.x-panel.x-layer.x-grid .x-grid-item-over td:first-child, +.x-panel.x-layer.x-grid .x-grid-item-selected td:first-child { + border-radius: var(--pm-radius-sm) 0 0 var(--pm-radius-sm) !important; +} + +.x-layer.x-grid .x-grid-item-over td:last-child, +.x-layer.x-grid .x-grid-item-selected td:last-child, +.x-panel.x-layer.x-grid .x-grid-item-over td:last-child, +.x-panel.x-layer.x-grid .x-grid-item-selected td:last-child { + border-radius: 0 var(--pm-radius-sm) var(--pm-radius-sm) 0 !important; +} + +/* ===================================================== + MENUS + ===================================================== */ +.x-menu, +.x-menu-default { + background-color: var(--sol-crust) !important; + border: 1px solid var(--sol-surface0) !important; + border-radius: var(--pm-radius-lg) !important; + box-shadow: 0 8px 24px rgba(30, 31, 41, 0.8) !important; + padding: 4px !important; + overflow: hidden !important; +} + +.x-menu-body-default { + background-color: transparent !important; + padding: 4px !important; +} + +.x-menu-header { + background-color: transparent !important; + color: var(--sol-text) !important; +} + +/* Menu icon separator — hide */ +.x-menu-icon-separator-default { + display: none !important; +} + +/* Menu item layout (flexbox reordering) */ +.x-menu-item-default > .x-menu-item-link { + display: flex !important; + align-items: center !important; + flex-direction: row !important; + gap: 4px !important; + justify-content: flex-start !important; + flex-wrap: nowrap !important; + border-radius: var(--pm-radius-md) !important; + padding: 4px 8px !important; + line-height: 20px !important; + border: none !important; + cursor: pointer !important; + outline: none !important; + box-shadow: none !important; + white-space: nowrap !important; + text-decoration: none !important; +} + +.x-menu-item-text-default { + color: var(--sol-text) !important; + font-size: 13px !important; + order: 1 !important; + margin-left: 0 !important; + text-align: left !important; + line-height: 20px !important; + display: inline-flex !important; + align-items: center !important; + flex: 1 1 auto !important; + width: auto !important; + white-space: nowrap !important; +} + +.x-menu-item-icon-default { + color: var(--sol-subtext0) !important; + order: -1 !important; + position: relative !important; + float: none !important; + margin-right: 8px !important; + margin-left: 0 !important; + left: auto !important; + top: auto !important; + width: 16px !important; + text-align: center !important; + display: inline-flex !important; + align-items: center !important; + justify-content: center !important; + height: 20px !important; + line-height: 20px !important; + vertical-align: middle !important; + flex: 0 0 16px !important; + align-self: center !important; +} + +.x-menu-item-arrow, +.x-menu-item-arrow-default { + order: 2 !important; + margin-left: auto !important; +} + +.x-menu-item-default.x-menu-item-separator { + background-color: var(--sol-surface0) !important; + border: none !important; + height: 1px !important; + margin: 6px 4px !important; +} + +.x-menu-item-default.x-menu-item-focus, +.x-menu-item-default.x-menu-item-active, +.x-menu-item:hover { + background-color: var(--sol-surface0) !important; + color: var(--sol-text) !important; + border-radius: var(--pm-radius-md) !important; +} + +.x-menu-item-active .x-menu-item-text-default, +.x-menu-item-focus .x-menu-item-text-default { + color: var(--sol-text) !important; +} + +.x-menu-item-active .x-menu-item-icon-default, +.x-menu-item-focus .x-menu-item-icon-default { + color: var(--sol-cyan) !important; +} + +/* ===================================================== + PROGRESS BARS + ===================================================== */ + +/* Fix: Widget containers need overflow visible to not clip progress bars */ +.x-container[id^="pmxInfoWidget"], +.x-container.x-box-layout-ct { + overflow: visible !important; +} + +.x-progress, +.x-progress-default { + background-color: var(--sol-surface0) !important; + border-radius: 5px !important; +} + +.x-progress-default .x-progress-bar-default { + background-color: var(--sol-purple) !important; + border-radius: 5px !important; + transition: width 0.4s ease !important; +} + +.x-progress-default .x-progress-text { + color: var(--sol-text) !important; +} + +/* Text overlaid on the progress bar fill — use on-accent for contrast */ +.x-progress-bar .x-progress-text { + color: var(--sol-on-accent) !important; +} + +.x-progress.warning .x-progress-bar { + background-color: var(--sol-yellow) !important; +} + +.x-progress.critical .x-progress-bar { + background-color: var(--sol-red) !important; +} + +/* ===================================================== + TABS — Dracula underline style + Flat tabs with Purple underline on active tab + ===================================================== */ +.x-tab-bar, +.x-tab-bar-default { + background-color: var(--sol-base) !important; + border-radius: 0 !important; + border-bottom: 1px solid var(--sol-surface1) !important; + padding-bottom: 0 !important; +} + +/* Overflow visible for the underline indicator */ +.x-tab-bar .x-box-inner, +.x-tab-bar .x-box-target, +.x-tab-bar-body, +.x-tab-bar-body-default { + overflow: visible !important; +} + +/* Base tab */ +.x-tab, +.x-tab-default, +.x-tab-default-top { + background-color: transparent !important; + border: none !important; + border-radius: var(--pm-radius-md) var(--pm-radius-md) 0 0 !important; + padding: 8px 16px 8px !important; + overflow: visible !important; + margin-bottom: 0 !important; + transition: color 0.15s ease !important; + outline: none !important; + box-shadow: none !important; +} + +/* Remove ::after from inactive tabs */ +.x-tab::after { + display: none !important; +} + +.x-tab-inner-default { + color: var(--sol-subtext0) !important; + font-size: 13px !important; +} + +.x-tab-default.x-tab-over { + background-color: transparent !important; +} + +.x-tab-default.x-tab-over .x-tab-inner-default { + color: var(--sol-text) !important; +} + +/* Active tab */ +.x-tab-default.x-tab.x-tab-active { + background-color: transparent !important; + border: none !important; + overflow: visible !important; + margin-bottom: 0 !important; + outline: none !important; + box-shadow: none !important; +} + +/* Purple underline indicator on active tab */ +.x-tab-default.x-tab.x-tab-active::after { + content: '' !important; + display: block !important; + position: absolute !important; + bottom: 0 !important; + left: 0 !important; + right: 0 !important; + height: 2px !important; + background: var(--sol-purple) !important; + z-index: 10 !important; + border-radius: 2px 2px 0 0 !important; + pointer-events: none !important; +} + +.x-tab-active .x-tab-inner-default { + color: var(--sol-text) !important; + font-weight: 600 !important; +} + +.x-tab-default.x-tab.x-tab-disabled { + background-color: transparent !important; + border: none !important; + color: var(--sol-overlay0) !important; + margin-bottom: 0 !important; +} + +/* Focus states — no outline */ +.x-keyboard-mode .x-tab-default.x-tab-focus, +.x-keyboard-mode .x-tab-default.x-tab-focus.x-tab-active { + background-color: transparent !important; + border: none !important; + outline: none !important; + box-shadow: none !important; + margin-bottom: 0 !important; +} + +.x-keyboard-mode .x-tab-default.x-tab-focus.x-tab-active::after { + content: '' !important; + display: block !important; + position: absolute !important; + bottom: 0 !important; + left: 0 !important; + right: 0 !important; + height: 2px !important; + background: var(--sol-purple) !important; + z-index: 10 !important; + pointer-events: none !important; +} + +/* Kill ALL tab interaction outlines/shadows */ +.x-tab:focus, +.x-tab *:focus, +.x-tab-focus, +.x-tab-active.x-tab-focus, +.x-tab-inner-focus, +.x-tab-button-focus, +.x-tab-pressed, +.x-tab-active.x-tab-pressed, +.x-tab-over, +.x-tab:active, +.x-tab *:active { + outline: none !important; + box-shadow: none !important; +} + +.x-tabpanel-child { + border-radius: 0 0 var(--pm-radius-lg) var(--pm-radius-lg) !important; +} + +/* Tab hover/active corners */ +.x-tab-default.x-tab-over, +.x-tab-default.x-tab.x-tab-active { + border-radius: var(--pm-radius-md) var(--pm-radius-md) 0 0 !important; +} + +/* ===================================================== + TOOLTIPS + ===================================================== */ +.x-tip, +.x-tip-default { + background-color: var(--sol-mantle) !important; + border: 1px solid var(--sol-surface1) !important; + border-radius: var(--pm-radius-md) !important; + box-shadow: 0 4px 12px rgba(30, 31, 41, 0.5); +} + +.x-tip-body-default { + color: var(--sol-text) !important; +} + +.x-tip-form-invalid { + background-color: var(--sol-mantle) !important; + border-color: var(--sol-red) !important; +} + +.x-tip-body-form-invalid { + color: var(--sol-red) !important; +} + +/* ===================================================== + TREE NAVIGATION (Sidebar) + ===================================================== */ +.x-treelist-item { + background-color: var(--sol-base) !important; + border-radius: var(--pm-radius-md) !important; +} + +/* Pseudo-element approach for hover/selected highlighting */ +.x-treelist-row { + border-radius: var(--pm-radius-md) !important; + background-color: transparent !important; + position: relative !important; + z-index: 0 !important; +} + +.x-treelist-row::before { + content: ""; + position: absolute; + top: 1px; + bottom: 1px; + left: 0; + right: 4px; + border-radius: var(--pm-radius-md); + background-color: transparent; + z-index: -1; + pointer-events: none; + transition: background-color 0.15s ease; +} + +/* Fix toolbox tree item text overlapping icons */ +.x-treelist-item-text { + margin-left: 28px !important; +} + +/* Toolbox tree items — bright text */ +.x-treelist-item-text, +.x-treelist-item-icon, +.x-treelist.x-treelist-pve-nav .x-treelist-item-text, +.x-treelist.x-treelist-pve-nav .x-treelist-item-icon { + color: var(--sol-subtext1) !important; +} + +/* Hover state — apply to pseudo-element */ +.x-treelist-row-over { + background-color: transparent !important; +} + +.x-treelist-row-over::before { + background-color: var(--sol-hover-overlay) !important; +} + +.x-treelist-row-over .x-treelist-item-icon, +.x-treelist-row-over .x-treelist-item-text { + background-color: transparent !important; + color: var(--sol-text) !important; +} + +/* Selected/active item — Purple highlight */ +.x-treelist-item-selected > .x-treelist-row { + background-color: transparent !important; +} + +.x-treelist-item-selected > .x-treelist-row::before, +.x-treelist-item-selected > .x-treelist-row:hover::before { + background-color: var(--sol-purple) !important; +} + +.x-treelist-item-selected .x-treelist-item-text, +.x-treelist-item-selected .x-treelist-item-icon, +.x-treelist.x-treelist-pve-nav .x-treelist-item-selected .x-treelist-item-text, +.x-treelist.x-treelist-pve-nav .x-treelist-item-selected .x-treelist-item-icon { + color: var(--sol-on-accent) !important; +} + +.x-treelist-pve-nav { + background-color: var(--sol-base) !important; + border-color: var(--sol-surface1) !important; +} + +/* Tree navigation radius overrides */ +.x-treelist-item, +.x-treelist-item-tool { + border-radius: var(--pm-radius-sm) !important; +} + +.x-treelist-row, +.x-treelist-row:hover, +.x-treelist-row-over, +.x-treelist-item-selected > .x-treelist-row, +.x-treelist-item-selected > .x-treelist-row:hover, +.x-treelist-item-expanded > .x-treelist-row, +.x-treelist-item-expanded > .x-treelist-row-over, +.x-treelist-item-expandable > .x-treelist-row, +.x-treelist-item-expandable > .x-treelist-row-over { + border-radius: var(--pm-radius-sm) !important; +} + +.x-treelist-row::before { + border-radius: var(--pm-radius-sm) !important; +} + +.x-treelist-item-wrap, +.x-treelist-item-text, +.x-treelist-row, +.x-treelist-container, +.x-treelist-root-container, +.x-treelist, +.x-treelist-pve-nav { + border-radius: var(--pm-radius-sm) !important; +} + +/* Cursor pointer for interactive tree/grid items */ +.x-grid-cell, +.x-grid-cell-inner, +.x-tree-elbow-img, +.x-tree-icon, +.x-treelist-item, +.x-treelist-row, +.x-treelist-item-wrap, +.x-treelist-item-text, +.x-treelist-item-icon { + cursor: pointer !important; +} + +/* ===================================================== + WINDOWS / MODALS + ===================================================== */ +.x-window, +.x-window-default { + background-color: var(--sol-crust) !important; + border: 1px solid var(--sol-surface1) !important; + border-radius: var(--pm-radius-lg) !important; + box-shadow: 0 8px 24px rgba(30, 31, 41, 0.6) !important; + overflow: hidden !important; +} + +.x-window .x-window-header, +.x-window-header-default { + background-color: var(--sol-mantle) !important; + border-color: transparent !important; + border-radius: var(--pm-radius-lg) var(--pm-radius-lg) 0 0 !important; +} + +.x-window-header-default .x-mask { + background-color: rgba(30, 31, 41, 0.7); +} + +.x-window .x-window-body, +.x-window-body-default { + background-color: var(--sol-base) !important; + border-color: var(--sol-surface1) !important; + color: var(--sol-text) !important; + border-radius: 0 0 var(--pm-radius-lg) var(--pm-radius-lg) !important; +} + +.x-window-ghost { + background-color: var(--sol-base) !important; +} + +.x-window-header-default .x-tool-img { + background-color: transparent; +} + +.x-message-box .x-window-body { + background-color: var(--sol-mantle) !important; +} + +/* Respect ExtJS inline display:none on hidden dialog buttons */ +.x-message-box .x-btn.x-btn-default-small[style*="display: none"], +.x-message-box .x-btn.x-btn-default-small[style*="display:none"], +.x-window .x-toolbar-footer .x-btn[style*="display: none"], +.x-window .x-toolbar-footer .x-btn[style*="display:none"] { + display: none !important; +} + +/* Login dialog — clean inner panel borders */ +.x-window:has(#pveloginrealm) .x-panel-body { + border: none !important; + background: transparent !important; + width: auto !important; +} + +/* ===================================================== + CONSOLE / TERMINAL + ===================================================== */ +div.monitor { + border-color: var(--sol-surface1); +} + +.install-mask { + background-color: var(--sol-crust); + color: var(--sol-subtext0); +} + +.x-window.install-mask { + box-shadow: rgba(30, 31, 41, 0.5) 0 4px 20px !important; +} + +/* ===================================================== + LEGEND / CHARTS + ===================================================== */ +.x-legend-container { + background-color: var(--sol-base) !important; +} + +.x-legend-horizontal .x-legend-item { + background-color: var(--sol-mantle) !important; + color: var(--sol-text) !important; + border: 1px solid var(--sol-surface0) !important; +} + +/* Chart/RRD panel backgrounds */ +div[id*="rrdchart"], +.pve-rrddatastore, +.pmx-panel-rrd { + background-color: var(--sol-base) !important; +} + +.proxmox-rrd-panel canvas, +.proxmox-widget-toolkit canvas, +canvas.x-surface, +.x-surface canvas { + background-color: transparent !important; + opacity: 1 !important; +} + +.proxmox-rrd-panel, +.proxmox-rrd-chart { + background-color: var(--sol-base) !important; +} + +/* Chart text/labels */ +.x-surface text, +svg text { + fill: var(--sol-text) !important; +} + +/* ===================================================== + PROXMOX-SPECIFIC OVERRIDES + ===================================================== */ + +/* Logo inversion */ +img[id^="proxmoxlogo-"][id$="-img"], +img[id^="proxmoxLogoSvg-"][id$="-img"] { + filter: none; +} + +/* Invalid/warning/disabled rows */ +.proxmox-invalid-row { + background-color: rgba(255, 85, 85, 0.15) !important; +} + +.proxmox-warning-row { + background-color: rgba(255, 184, 108, 0.15) !important; +} + +.proxmox-disabled-row td { + color: var(--sol-overlay0) !important; +} + +/* Hints */ +.pmx-hint { + background-color: rgba(255, 184, 108, 0.15) !important; + white-space: nowrap !important; +} + +.pmx-hint a { + color: var(--sol-cyan) !important; +} + +/* Status text colors — Information → Cyan */ +.info-blue { + color: var(--sol-cyan) !important; +} + +.critical { + color: var(--sol-red) !important; +} + +/* Links */ +a { + color: var(--sol-cyan) !important; +} + +/* Markdown content */ +.pmx-md code { + background-color: var(--sol-mantle) !important; + color: var(--sol-pink) !important; + border-radius: var(--pm-radius-sm) !important; +} + +.pmx-md pre code { + border-color: var(--sol-surface1) !important; + background-color: var(--sol-crust) !important; +} + +.pmx-md a { + color: var(--sol-cyan) !important; +} + +.pmx-md table { + border-color: var(--sol-surface1) !important; +} + +.pmx-md th { + background-color: var(--sol-mantle) !important; + border-color: var(--sol-surface1) !important; +} + +.pmx-md td { + border-color: var(--sol-surface1) !important; +} + +/* APT repos */ +.proxmox-apt-repos .x-grid-group-hd { + background-color: var(--sol-base) !important; + border: none !important; +} + +.proxmox-apt-repos .x-grid-group-title { + color: var(--sol-text) !important; +} + +/* Tags */ +.pve-edit-tag { + border-radius: var(--pm-radius-md) !important; +} + +.pve-edit-tag.editable span { + background-color: var(--sol-mantle) !important; + color: var(--sol-text) !important; + border-color: var(--sol-surface1) !important; +} + +.x-tree-node-text .proxmox-tag-dark, +.x-tree-node-text .proxmox-tag-light, +.x-grid-cell-inner .proxmox-tag-dark, +.x-grid-cell-inner .proxmox-tag-light, +span.proxmox-tag-dark, +span.proxmox-tag-light { + border-radius: var(--pm-radius-md) !important; +} + +/* Checkmark button in tag edit — match toolbar button size */ +.x-btn.x-btn-default-small:has(.fa-check) { + min-height: 24px !important; + height: 24px !important; + padding: 3px 8px !important; + border-radius: var(--pm-radius-sm) !important; + background-color: var(--sol-purple) !important; + border: none !important; +} + +.x-btn.x-btn-default-small:has(.fa-check).x-btn-disabled { + background-color: transparent !important; + border: 1px solid var(--sol-surface1) !important; + opacity: 0.5 !important; +} + +.x-btn.x-btn-default-small:has(.fa-check) .fa-check { + color: var(--sol-on-accent) !important; +} + +.x-btn.x-btn-default-small:has(.fa-check).x-btn-disabled .fa-check { + color: var(--sol-overlay1) !important; +} + +.x-btn.x-btn-default-small:has(.fa-check):not(.x-btn-disabled):hover { + background-color: #caa9fa !important; +} + +.x-btn.x-btn-default-small:has(.fa-check) .x-btn-inner { + display: none !important; +} + +/* Date picker */ +.x-datepicker, +.x-datepicker-column-header, +.x-monthpicker { + background-color: var(--sol-base) !important; + color: var(--sol-text) !important; + border-color: transparent !important; +} + +.x-datepicker-header, +.x-datepicker-footer, +.x-monthpicker-buttons { + background-color: var(--sol-mantle) !important; +} + +.x-datepicker-date, +.x-monthpicker-item-inner { + color: var(--sol-text) !important; +} + +.x-datepicker-selected div.x-datepicker-date, +.x-monthpicker-item a.x-monthpicker-selected, +a.x-monthpicker-item-inner:hover, +div.x-datepicker-date:hover { + background-color: var(--sol-hover-overlay) !important; + color: var(--sol-text) !important; +} + +.x-datepicker-today .x-datepicker-date { + border-color: var(--sol-purple) !important; +} + +.x-datepicker-disabled .x-datepicker-date { + color: var(--sol-overlay0) !important; +} + +.x-datepicker-prev-day .x-datepicker-date, +.x-datepicker-next-day .x-datepicker-date { + color: var(--sol-overlay0) !important; +} + +/* Usage bars */ +.usage-wrapper, +.usage { + border-radius: 2px !important; +} + +.usage { + background-color: var(--sol-overlay2) !important; +} + +/* ===================================================== + SCROLLBARS + ===================================================== */ +::-webkit-scrollbar { + width: 8px; + height: 8px; +} + +::-webkit-scrollbar-track { + background: var(--sol-base); + border-radius: var(--pm-radius-sm); +} + +::-webkit-scrollbar-thumb { + background: var(--sol-surface2); + border-radius: var(--pm-radius-sm); + border: 1px solid transparent; + background-clip: padding-box; + transition: background 0.15s ease; +} + +::-webkit-scrollbar-thumb:hover { + background: var(--sol-overlay0); +} + +::-webkit-scrollbar-corner { + background: var(--sol-base); +} + +/* Firefox scrollbar */ +* { + scrollbar-width: thin; + scrollbar-color: var(--sol-surface2) var(--sol-base); +} + +/* ===================================================== + SELECTION HIGHLIGHT + ===================================================== */ +::selection { + background-color: rgba(98, 114, 164, 0.3); + color: var(--sol-text); +} + +/* ===================================================== + TRANSITIONS (smooth interactions) + ===================================================== */ + +/* Grid row transitions */ +.x-grid-item { + transition: background-color 0.15s ease !important; +} + +/* Tree pseudo-element transitions */ +.x-treelist-row::before { + transition: background-color 0.15s ease !important; +} + +/* Menu item transitions */ +.x-menu-item-default > .x-menu-item-link { + transition: background-color 0.12s ease !important; +} + +/* Boundlist item transitions */ +.x-boundlist-item { + transition: background-color 0.12s ease !important; +} + +/* Tab transitions */ +.x-tab { + transition: color 0.15s ease !important; +} + +/* Splitter transition */ +.x-splitter { + transition: background-color 0.15s ease !important; +} + +/* Tooltip transition */ +.x-tip { + transition: opacity 0.15s ease !important; +} + +/* Progress bar width transition */ +.x-progress-bar { + transition: width 0.4s ease !important; +} + +/* Scrollbar thumb transition */ +::-webkit-scrollbar-thumb { + transition: background 0.15s ease !important; +} + +/* Window close tool transition */ +.x-tool-img { + transition: filter 0.15s ease !important; +} +/* ===================================================== + TOOL ICONS - FontAwesome Replacements + (Ported from UniFi v5.86) + Replace sprite-based ExtJS tool icons with crisp + FontAwesome icons for better consistency and clarity + ===================================================== */ + +/* Base styling for all tool icons - remove sprite backgrounds */ +.x-tool-tool-el.x-tool-minus, +.x-tool-img.x-tool-minus, +.x-tool-tool-el.x-tool-collapse-right, +.x-tool-img.x-tool-collapse-right, +.x-tool-tool-el.x-tool-collapse-left, +.x-tool-img.x-tool-collapse-left, +.x-tool-tool-el.x-tool-expand-right, +.x-tool-img.x-tool-expand-right, +.x-tool-tool-el.x-tool-expand-left, +.x-tool-img.x-tool-expand-left, +.x-tool-tool-el.x-tool-maximize, +.x-tool-img.x-tool-maximize, +.x-tool-tool-el.x-tool-restore, +.x-tool-img.x-tool-restore, +.x-tool-tool-el.x-tool-gear, +.x-tool-img.x-tool-gear, +.x-tool-tool-el.x-tool-refresh, +.x-tool-img.x-tool-refresh, +.x-tool-tool-el.x-tool-close, +.x-tool-img.x-tool-close { + background-image: none !important; + font-family: "FontAwesome" !important; + font-size: 14px !important; + line-height: 16px !important; + text-align: center !important; + color: var(--pm-text-dim) !important; + transition: color 0.15s ease !important; + filter: none !important; + width: 16px !important; + height: 16px !important; + display: flex !important; + align-items: center !important; + justify-content: center !important; +} + +/* Close button - slightly larger */ +.x-tool-tool-el.x-tool-close, +.x-tool-img.x-tool-close { + font-size: 20px !important; +} + +/* Individual glyph assignments */ +.x-tool-tool-el.x-tool-minus::before, +.x-tool-img.x-tool-minus::before { + content: "\f010" !important; /* fa-search-minus (zoom out) */ +} + +.x-tool-tool-el.x-tool-collapse-right::before, +.x-tool-img.x-tool-collapse-right::before { + content: "\f054" !important; /* fa-chevron-right */ +} + +.x-tool-tool-el.x-tool-expand-left::before, +.x-tool-img.x-tool-expand-left::before { + content: "\f053" !important; /* fa-chevron-left */ +} + +.x-tool-tool-el.x-tool-collapse-left::before, +.x-tool-img.x-tool-collapse-left::before { + content: "\f053" !important; /* fa-chevron-left */ +} + +.x-tool-tool-el.x-tool-expand-right::before, +.x-tool-img.x-tool-expand-right::before { + content: "\f054" !important; /* fa-chevron-right */ +} + +.x-tool-tool-el.x-tool-maximize::before, +.x-tool-img.x-tool-maximize::before { + content: "\f065" !important; /* fa-expand */ +} + +.x-tool-tool-el.x-tool-restore::before, +.x-tool-img.x-tool-restore::before { + content: "\f066" !important; /* fa-compress */ +} + +.x-tool-tool-el.x-tool-gear::before, +.x-tool-img.x-tool-gear::before { + content: "\f013" !important; /* fa-cog */ +} + +.x-tool-tool-el.x-tool-refresh::before, +.x-tool-img.x-tool-refresh::before { + content: "\f021" !important; /* fa-refresh */ +} + +.x-tool-tool-el.x-tool-close::before, +.x-tool-img.x-tool-close::before { + content: "\f00d" !important; /* fa-times */ +} + +/* Hover state - all tool icons */ +.x-tool:hover .x-tool-tool-el.x-tool-minus, +.x-tool:hover .x-tool-img.x-tool-minus, +.x-tool:hover .x-tool-tool-el.x-tool-collapse-right, +.x-tool:hover .x-tool-img.x-tool-collapse-right, +.x-tool:hover .x-tool-tool-el.x-tool-collapse-left, +.x-tool:hover .x-tool-img.x-tool-collapse-left, +.x-tool:hover .x-tool-tool-el.x-tool-expand-right, +.x-tool:hover .x-tool-img.x-tool-expand-right, +.x-tool:hover .x-tool-tool-el.x-tool-expand-left, +.x-tool:hover .x-tool-img.x-tool-expand-left, +.x-tool:hover .x-tool-tool-el.x-tool-maximize, +.x-tool:hover .x-tool-img.x-tool-maximize, +.x-tool:hover .x-tool-tool-el.x-tool-restore, +.x-tool:hover .x-tool-img.x-tool-restore, +.x-tool:hover .x-tool-tool-el.x-tool-gear, +.x-tool:hover .x-tool-img.x-tool-gear, +.x-tool:hover .x-tool-tool-el.x-tool-refresh, +.x-tool:hover .x-tool-img.x-tool-refresh, +.x-tool:hover .x-tool-tool-el.x-tool-close, +.x-tool:hover .x-tool-img.x-tool-close { + color: var(--pm-text) !important; +} + +/* Disabled state */ +.x-tool-disabled .x-tool-tool-el, +.x-tool-disabled .x-tool-img { + opacity: 0.4 !important; + cursor: default !important; +} + +/* Inline FontAwesome tools (PVE-injected) */ +.x-tool-tool-el[style*="font-family:FontAwesome"], +.x-tool-tool-el[style*="font-family: FontAwesome"] { + color: var(--pm-text-dim) !important; + font-size: 14px !important; + line-height: 16px !important; + display: flex !important; + align-items: center !important; + justify-content: center !important; + width: 16px !important; + height: 16px !important; + transition: color 0.15s ease !important; + background-image: none !important; + background-color: transparent !important; +} + +.x-tool:not(.x-tool-disabled) .x-tool-tool-el[style*="font-family:FontAwesome"], +.x-tool:not(.x-tool-disabled) .x-tool-tool-el[style*="font-family: FontAwesome"] { + cursor: pointer !important; +} + +.x-tool.x-tool-disabled .x-tool-tool-el[style*="font-family:FontAwesome"], +.x-tool.x-tool-disabled .x-tool-tool-el[style*="font-family: FontAwesome"] { + cursor: default !important; + opacity: 0.4 !important; +} + +.x-tool .x-mask { + background-color: transparent !important; + backdrop-filter: none !important; + pointer-events: none !important; +} + +.x-tool:not(.x-tool-disabled):hover .x-tool-tool-el[style*="font-family:FontAwesome"], +.x-tool:not(.x-tool-disabled):hover .x-tool-tool-el[style*="font-family: FontAwesome"] { + color: var(--pm-text) !important; +} diff --git a/themes/theme-theraiwy-dark.css b/themes/theme-theraiwy-dark.css new file mode 100644 index 0000000..662ee2e --- /dev/null +++ b/themes/theme-theraiwy-dark.css @@ -0,0 +1,2444 @@ +/*!TheRaiwy Dark*/ +/* + * ProxMorph Theme: TheRaiwy Dark + * Cyber aesthetic theme for Proxmox — dark, red-accented, grid-inspired + * Version: 1.0.0 + * + * Based on ProxMorph v2.2.23 GitHub Dark theme framework. + * Replaces Primer colors with TheRaiwy's cyber dark palette: + * #080808 body / #0d0d0d surface / #dc2626 accent + * + * TheRaiwy Cyber Dark Mode Color Palette: + * + * CANVAS (Backgrounds): + * - canvas-default: #080808 - Main page background (deep black) + * - canvas-muted: #0d0d0d - Muted/card backgrounds + * - canvas-inset: #050505 - Header, inset areas + * - canvas-subtle: #111111 - Subtle backgrounds + * + * FOREGROUND (Text): + * - fg-default: #f0ede8 - Primary text (warm white) + * - fg-muted: #b0ada8 - Secondary/muted text + * - fg-subtle: #6b6966 - Tertiary text + * - fg-onEmphasis: #ffffff - Text on colored backgrounds + * + * BORDERS: + * - border-default: #2e2e31 - Default borders + * - border-muted: rgba(46, 46, 49, 0.7) - Muted borders + * - border-subtle: rgba(240, 237, 232, 0.1) - Subtle borders + * + * ACCENT (Red): + * - accent-fg: #dc2626 - Links, accent text + * - accent-emphasis: #c62222 - Active states + * + * SUCCESS (Green): + * - success-fg: #22c55e - Success text + * - success-emphasis: #16a34a - Primary buttons + * + * BORDER RADII (UniFi-aligned): + * - radius-sm: 4px - Form inputs, checkboxes + * - radius-md: 6px - Buttons + * - radius-lg: 8px - Windows, panels, cards + */ + +/* ===================================================== + CSS VARIABLES + ===================================================== */ +:root { + /* TheRaiwy Cyber Dark Mode Tokens */ + + /* CANVAS (Backgrounds) */ + --trw-canvas-default: #080808; + --trw-canvas-muted: #0d0d0d; + --trw-canvas-inset: #050505; + --trw-canvas-subtle: #111111; + + /* FOREGROUND (Text) */ + --trw-fg-default: #f0ede8; + --trw-fg-muted: #b0ada8; + --trw-fg-subtle: #6b6966; + --trw-fg-on-emphasis: #ffffff; + + /* BORDERS */ + --trw-border-default: #2e2e31; + --trw-border-muted: rgba(46, 46, 49, 0.7); + --trw-border-subtle: rgba(240, 237, 232, 0.1); + + /* ACCENT (Red) */ + --trw-accent-fg: #dc2626; + --trw-accent-emphasis: #c62222; + --trw-accent-muted: rgba(220, 38, 38, 0.4); + --trw-accent-subtle: rgba(220, 38, 38, 0.15); + + /* SUCCESS (Green) */ + --trw-success-fg: #22c55e; + --trw-success-emphasis: #16a34a; + --trw-success-hover: #1fb954; + --trw-success-active: #22c55e; + + /* DANGER (Red) */ + --trw-danger-fg: #dc2626; + --trw-danger-emphasis: #b91c1c; + + /* ATTENTION (Yellow) */ + --trw-attention-fg: #cc9903; + --trw-attention-emphasis: #a37a02; + + /* Select menu active - red-tinted */ + --trw-selectmenu-active: #2a0808; + + /* Border Radii - UniFi aligned */ + --trw-radius-sm: 4px; + --trw-radius-md: 6px; + --trw-radius-lg: 8px; + + /* Hover overlay */ + --trw-hover-overlay: rgba(240, 237, 232, 0.1); + + /* Map to Proxmox widget toolkit vars */ + --pwt-panel-background: var(--trw-canvas-default); + --pwt-text-color: var(--trw-fg-default); + --pwt-gauge-default: var(--trw-accent-emphasis); + --pwt-gauge-back: #1a1a1c; + --pwt-gauge-warn: var(--trw-attention-fg); + --pwt-gauge-crit: var(--trw-danger-emphasis); + --pwt-chart-primary: var(--trw-accent-emphasis); + --pwt-chart-grid-stroke: var(--trw-border-default); + + color-scheme: dark; +} + +/* ===================================================== + BASE / BODY + ===================================================== */ +.x-body, +.x-viewport>.x-body, +body.x-border-layout-ct, +div.x-border-layout-ct { + background-color: var(--trw-canvas-default) !important; + color: var(--trw-fg-default) !important; +} + +/* ===================================================== + LAYOUT CONTAINER RESET (Prevent ExtJS clipping) + v2.1.5: Ported from UniFi theme for consistent border handling + ===================================================== */ + +/* Tool icons - no rounded corners */ +.x-tool, +.x-tool-tool-el, +.x-tool-default, +.x-tool-img { + border-radius: 0 !important; +} + +/* Form elements - exclude from global radius, apply 6px (GitHub style) */ +.x-form-item, +.x-form-item-default, +.x-form-item-body, +.x-form-item-body-default, +.x-form-text-field-body, +.x-form-text-field-body-default, +.x-form-fieldcontainer, +.x-field, +.x-field-default, +.x-form-type-text { + border-radius: 0 !important; +} + +/* Reset layout containers that clip elements with overflow:hidden + radius */ +.x-box-layout-ct, +.x-panel-bodyWrap, +.x-panel-bodyWrap-default, +.x-autocontainer-innerCt, +.x-autocontainer-outerCt, +.x-panel.x-tabpanel-child, +.x-panel.x-box-item, +.x-box-inner, +.x-box-target, +.x-container, +.x-container-default, +.x-window .x-panel-body, +.x-window .x-window-body, +.x-window .x-window-bodyWrap { + border-radius: 0 !important; +} + +/* Reset everything inside windows to 0 - then re-apply specific radii */ +.x-window *, +.x-window .x-autocontainer-innerCt, +.x-window .x-autocontainer-outerCt, +.x-window .x-form-layout-wrap, +.x-window .x-form-layout-auto-label, +.x-window .x-form-layout-colgroup, +.x-window .x-form-layout-column, +.x-window .x-field, +.x-window .x-form-item, +.x-window .x-form-item-body { + border-radius: 0 !important; +} + +/* v2.2.0: Dialog form content padding - vertical only (horizontal causes ExtJS layout overflow). + Root cause: ExtJS uses offsetWidth for layout → CSS horizontal padding shifts form items + rightward but doesn't narrow their computed width, causing trigger wraps to overflow 16px past + the column boundary where the adjacent column's opaque background covers them. */ +.x-window .x-tabpanel-child .x-autocontainer-innerCt { + padding: 12px 0 !important; +} + +/* v2.2.17: Allow column panel bodies to show overflowed form content (e.g. trigger wraps). + overflow:visible prevents the panel's own clipping from hiding elements that extend + slightly past the panel boundary during ExtJS layout calculation. */ +.x-window .x-panel-body:not(.x-scroller) { + overflow: visible !important; +} + +/* v2.2.17: 4px side padding on column panel bodies for visual breathing room. + ExtJS reads getPaddingInfo() on panel-body when sizing child form items, so this + correctly reduces item widths by 8px total without causing any overflow. */ +.x-window .x-panel.x-box-item .x-panel-body { + padding: 0 4px !important; +} + +/* Re-apply button styling inside windows (6px) */ +.x-window .x-btn { + border-radius: var(--trw-radius-md) !important; +} + +/* Re-apply checkbox styling inside windows */ +.x-window .x-form-checkbox { + border-radius: var(--trw-radius-sm) !important; +} + +/* Re-apply form inputs inside windows (4px with split corners - UniFi style) */ +.x-window .x-form-trigger-wrap, +.x-window .x-form-trigger-wrap-default { + border-radius: var(--trw-radius-sm) !important; +} + +.x-window .x-form-text-wrap, +.x-window .x-form-text { + border-radius: var(--trw-radius-sm) 0 0 var(--trw-radius-sm) !important; +} + +.x-window .x-form-arrow-trigger { + border-radius: 0 var(--trw-radius-sm) var(--trw-radius-sm) 0 !important; +} + +/* Form trigger/text wrap - reset and re-apply */ +.x-form-trigger-wrap, +.x-form-trigger-wrap *, +.x-form-text-wrap, +.x-form-text-wrap *, +.x-form-text, +.x-form-trigger { + border-radius: 0 !important; +} + +.x-form-trigger-wrap, +.x-form-trigger-wrap-default { + border-radius: var(--trw-radius-sm) !important; + overflow: hidden !important; +} + +.x-form-text-wrap, +.x-form-text-wrap-default { + border-radius: var(--trw-radius-sm) 0 0 var(--trw-radius-sm) !important; +} + +.x-form-text, +.x-form-text-default { + border-radius: var(--trw-radius-sm) 0 0 var(--trw-radius-sm) !important; +} + +.x-form-trigger, +.x-form-trigger-default, +.x-form-arrow-trigger, +.x-form-arrow-trigger-default { + border-radius: 0 var(--trw-radius-sm) var(--trw-radius-sm) 0 !important; +} + +/* Legend items - no rounded corners */ +.x-legend-container, +.x-legend-horizontal .x-legend-item, +.x-legend-item { + border-radius: 0 !important; +} + +/* Legend color marker (dot) - keep circular */ +.x-legend-item-marker { + border-radius: 50% !important; +} + +/* Boundlist - prevent clipping (applied to parent) */ +.x-boundlist { + border-radius: var(--trw-radius-lg) !important; + overflow: hidden !important; +} + +/* Chart canvas - no rounded corners on data area */ +.x-chart-grid, +.x-chart-axis, +canvas.x-surface, +.x-chart canvas { + border-radius: 0 !important; +} + +/* Constrain autocontainer width inside windows */ +.x-window .x-autocontainer-outerCt { + max-width: 100% !important; +} + +/* Fix window header/body width consistency */ +.x-window > .x-window-header, +.x-window > .x-window-body, +.x-window > .x-window-bodyWrap, +.x-window-bodyWrap > .x-window-body { + width: 100% !important; +} + +.x-window-header > .x-box-inner, +.x-window-header > .x-box-inner > .x-box-target { + width: 100% !important; +} + +.x-window-header-title { + width: auto !important; + flex: 1 !important; + max-width: calc(100% - 30px) !important; +} + +/* ===================================================== + MASKS & OVERLAYS + ===================================================== */ +.x-mask { + background-color: rgba(1, 4, 9, 0.5) !important; +} + +.x-tool .x-mask { + backdrop-filter: blur(4px); + background-color: var(--trw-canvas-muted); + opacity: 0.6; +} + +.x-css-shadow { + box-shadow: 0 8px 24px rgba(1, 4, 9, 0.5) !important; +} + +/* ===================================================== + ICONS - Using Proxmox default colors for dark mode + v2.1.1: Restored PVE base color scheme + ===================================================== */ + +/* General icon colors - visible gray for dark backgrounds */ +.x-tree-icon-custom, +.x-grid-icon-custom, +.fa-tags::before, +.fa-file-o::before, +.fa-building::before, +.x-action-col-icon::before, +.fa-shield::before, +.fa-file-text-o::before, +.fa-clock-o::before, +.x-tab-icon-el-default, +.pve-icon-verify-lettering::after, +.x-tree-icon-leaf:not(.x-tree-icon-custom)::before, +.x-tree-icon-parent:not(.x-tree-icon-custom)::before, +.x-tree-icon-parent-expanded:not(.x-tree-icon-custom)::before, +.x-grid-filters-filtered-column .x-column-header-text::after { + color: #aaaaaa !important; +} + +/* Folder icons - invert for dark mode */ +.x-tree-icon-parent:not(.x-tree-icon-custom)::before, +.x-tree-icon-parent-expanded:not(.x-tree-icon-custom)::before { + filter: invert(90%); +} + +/* Various image-based icons - invert for visibility */ +.fa-ceph::before, +.fa-sdn::before, +.fa-network-wired::before, +.pve-itype-treelist-item-icon-cdrom, +.fa-chevron-right::before, +.x-grid-row-console, +.x-box-scroller-toolbar-default.x-box-scroller, +.x-tree-elbow-img, +.pve-itype-icon-qemu, +.x-tree-node-computer, +.x-grid-tree-node-expanded .x-tree-node-computer, +.pbs-icon-tape, +.pbs-icon-tape-drive, +.x-tree-icon-leaf:not(.x-tree-icon-custom), +.x-tree-icon-parent:not(.x-tree-icon-custom), +.x-tree-icon-parent-expanded:not(.x-tree-icon-custom) { + filter: invert(90%); +} + +/* Hardware icons */ +.pve-itype-icon-cpu, +.pve-itype-icon-cdrom, +.pve-itype-icon-memory, +.pve-itype-icon-pci, +.pve-itype-icon-serial, +.pve-itype-icon-die, +.pmx-itype-icon-processor, +.pmx-itype-icon-memory, +.pve-itype-icon-storage, +.x-tree-node-harddisk, +.x-grid-tree-node-expanded .x-tree-node-harddisk { + filter: invert(100%); +} + +/* Hardware icons — counter-invert for non-SVG icon cells */ +td.pve-itype-icon-storage .x-grid-cell-inner, +td.x-tree-node-harddisk .x-grid-cell-inner { + filter: invert(100%) !important; +} + +/* Hardware icons — hide inverted borders for non-SVG icon cells */ +td.pve-itype-icon-storage, +td.x-tree-node-harddisk { + border-color: transparent !important; +} + +/* Hardware grid icons — mask-image renders SVG icons in theme text color + Replaces filter:invert approach for pve-itype-icon-* and pmx-itype-icon-* grid cells */ +td.pve-itype-icon-cpu, +td.pve-itype-icon-cdrom, +td.pve-itype-icon-memory, +td.pve-itype-icon-pci, +td.pve-itype-icon-serial, +td.pve-itype-icon-die, +td.pmx-itype-icon-processor, +td.pmx-itype-icon-memory { + filter: none !important; + background-image: none !important; + padding-left: 0 !important; + border-color: transparent !important; +} + +td.pve-itype-icon-cpu .x-grid-cell-inner, +td.pve-itype-icon-cdrom .x-grid-cell-inner, +td.pve-itype-icon-memory .x-grid-cell-inner, +td.pve-itype-icon-pci .x-grid-cell-inner, +td.pve-itype-icon-serial .x-grid-cell-inner, +td.pve-itype-icon-die .x-grid-cell-inner, +td.pmx-itype-icon-processor .x-grid-cell-inner, +td.pmx-itype-icon-memory .x-grid-cell-inner { + padding-left: 3px !important; +} + +td.pve-itype-icon-cpu .x-grid-cell-inner::before, +td.pve-itype-icon-cdrom .x-grid-cell-inner::before, +td.pve-itype-icon-memory .x-grid-cell-inner::before, +td.pve-itype-icon-pci .x-grid-cell-inner::before, +td.pve-itype-icon-serial .x-grid-cell-inner::before, +td.pve-itype-icon-die .x-grid-cell-inner::before, +td.pmx-itype-icon-processor .x-grid-cell-inner::before, +td.pmx-itype-icon-memory .x-grid-cell-inner::before { + content: '' !important; + display: inline-block !important; + width: 18px !important; + height: 14px !important; + vertical-align: middle !important; + margin-right: 10px !important; + background-color: currentColor !important; + -webkit-mask-size: contain !important; + mask-size: contain !important; + -webkit-mask-repeat: no-repeat !important; + mask-repeat: no-repeat !important; + -webkit-mask-position: center !important; + mask-position: center !important; +} + +td.pve-itype-icon-cpu .x-grid-cell-inner::before { + -webkit-mask-image: url('/pve2/images/icon-cpu.svg') !important; + mask-image: url('/pve2/images/icon-cpu.svg') !important; +} + +td.pve-itype-icon-memory .x-grid-cell-inner::before { + -webkit-mask-image: url('/pve2/images/icon-memory.svg') !important; + mask-image: url('/pve2/images/icon-memory.svg') !important; +} + +td.pve-itype-icon-cdrom .x-grid-cell-inner::before { + -webkit-mask-image: url('/pve2/images/icon-cd-drive.svg') !important; + mask-image: url('/pve2/images/icon-cd-drive.svg') !important; +} + +td.pve-itype-icon-pci .x-grid-cell-inner::before { + -webkit-mask-image: url('/pve2/images/icon-pci.svg') !important; + mask-image: url('/pve2/images/icon-pci.svg') !important; +} + +td.pve-itype-icon-serial .x-grid-cell-inner::before { + -webkit-mask-image: url('/pve2/images/icon-serial.svg') !important; + mask-image: url('/pve2/images/icon-serial.svg') !important; +} + +td.pve-itype-icon-die .x-grid-cell-inner::before { + -webkit-mask-image: url('/pve2/images/icon-die.svg') !important; + mask-image: url('/pve2/images/icon-die.svg') !important; +} + +td.pmx-itype-icon-processor .x-grid-cell-inner::before { + -webkit-mask-image: url('../images/icon-cpu.svg') !important; + mask-image: url('../images/icon-cpu.svg') !important; +} + +td.pmx-itype-icon-memory .x-grid-cell-inner::before { + -webkit-mask-image: url('../images/icon-ram.svg') !important; + mask-image: url('../images/icon-ram.svg') !important; +} + + +/* Icon overlays - default styling */ +.x-tree-icon-custom::after, +.x-grid-icon-custom::after { + color: #aaaaaa !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* RUNNING VMs/CTs - Green status indicator (PVE default) */ +.x-tree-icon-custom.running::after, +.x-grid-icon-custom.running::after, +.x-treelist-item-icon.running::after { + color: rgb(33, 191, 75) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* ONLINE state - Green */ +.x-tree-icon-custom.online::after, +.x-grid-icon-custom.online::after { + color: rgb(33, 191, 75) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* Stopped/offline - Muted gray */ +.x-tree-icon-custom.stopped, +.x-tree-icon-custom.offline, +.x-grid-icon-custom.stopped, +.x-grid-icon-custom.offline { + color: #888888 !important; +} + +/* Unknown state - Gray */ +.x-tree-icon-custom.unknown::after, +.x-grid-icon-custom.unknown::after { + color: #888888 !important; +} + +/* ERROR states - Red (PVE default) */ +.x-tree-icon-custom.error::after, +.x-tree-icon-custom.offline::after, +.x-tree-icon-custom.ha-error::after, +.x-grid-icon-custom.error::after, +.x-grid-icon-custom.offline::after, +.x-grid-icon-custom.ha-error::after { + color: rgb(204, 24, 0) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* PAUSED/SUSPENDED - Amber (PVE default) */ +.x-tree-icon-custom.paused::after, +.x-tree-icon-custom.suspended::after, +.x-tree-icon-custom.lock-suspending::after, +.x-grid-icon-custom.paused::after, +.x-grid-icon-custom.suspended::after, +.x-grid-icon-custom.lock-suspending::after { + color: rgb(204, 142, 0) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* PENDING/WARNING states - Yellow (PVE default) */ +.x-tree-icon-custom.pending::after, +.x-tree-icon-custom.io-error::after, +.x-tree-icon-custom.internal-error::after, +.x-tree-icon-custom.guest-panicked::after, +.x-grid-icon-custom.pending::after, +.x-grid-icon-custom.io-error::after, +.x-grid-icon-custom.internal-error::after, +.x-grid-icon-custom.guest-panicked::after { + color: rgb(255, 204, 0) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* HA MAINTENANCE - Blue (PVE default) */ +.x-tree-icon-custom.ha-maintenance::after, +.x-grid-icon-custom.ha-maintenance::after { + color: rgb(56, 146, 212) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* Locked icons */ +.x-tree-icon-custom.locked::after, +.x-tree-icon-custom.lock-backup::after, +.x-tree-icon-custom.lock-migrate::after, +.x-tree-icon-custom.lock-suspended::after, +.x-grid-icon-custom.locked::after, +.x-grid-icon-custom.lock-backup::after, +.x-grid-icon-custom.lock-migrate::after, +.x-grid-icon-custom.lock-suspended::after { + color: #aaaaaa !important; +} + +/* LXC/QEMU type indicators */ +.x-tree-icon-custom.lxc::after, +.x-tree-icon-custom.qemu::after, +.x-grid-icon-custom.lxc::after, +.x-grid-icon-custom.qemu::after { + background-color: transparent; + color: #888888 !important; +} + +.x-treelist-item-icon.lxc::after, +.x-treelist-item-icon.qemu::after { + background-color: transparent; + color: #888888 !important; +} + +/* Tree expander arrows */ +.x-tree-arrows .x-tree-expander { + filter: brightness(200%); +} + +/* v2.2.18: cancel old sprite-inversion; custom CSS controls handle appearance now */ +.x-form-checkbox-default, +.x-form-radio-default, +.x-column-header-checkbox .x-column-header-checkbox::after, +.x-grid-checkcolumn::after, +.x-menu-item-checked .x-menu-item-icon-default.x-menu-item-checkbox, +.x-menu-item-unchecked .x-menu-item-icon-default.x-menu-item-checkbox { + filter: none !important; +} + +/* ===================================================== + PANELS - UniFi base radius (8px) + ===================================================== */ +.x-panel, +.x-panel-default { + border-radius: var(--trw-radius-lg) !important; + padding: 0 !important; +} + +/* Column panels — native stacked layout (Issue #23 fix) */ +.x-panel.x-column { + padding: 5px !important; + margin: 0 !important; + max-width: none !important; + box-sizing: border-box !important; +} + +/* Column panel card styling — borders for summary + chart panels */ +.x-panel.x-panel-default.x-column { + border: 1px solid var(--trw-border-default) !important; + border-radius: var(--trw-radius-lg) !important; + overflow: hidden !important; +} + +/* v2.2.1: Guest status panel and Notes panel borders */ +[id^="pveGuestStatusView-"].x-panel, +[id^="pveLxcStatusView-"].x-panel, +[id^="pveQemuStatusView-"].x-panel, +[id^="pmxNotesView-"].x-panel { + border: 1px solid var(--trw-border-default) !important; + border-radius: var(--trw-radius-lg) !important; +} + +.x-panel-body, +.x-panel-body-default { + background-color: var(--trw-canvas-default) !important; + color: var(--trw-fg-default) !important; + border: none !important; +} + +/* Panel headers - only bottom border, flush with edges */ +.x-panel-header, +.x-panel-header-default { + background-color: var(--trw-canvas-muted) !important; + border: none !important; + border-bottom: 1px solid var(--trw-border-default) !important; + border-radius: var(--trw-radius-lg) var(--trw-radius-lg) 0 0 !important; + margin: 0 !important; + padding: 8px 12px !important; + width: 100% !important; + box-sizing: border-box !important; + overflow: visible !important; +} + +/* Title text — prevent border-radius clipping */ +.x-title-text, +.x-title-text-default { + overflow: visible !important; +} + +.x-panel-bodyWrap, +.x-panel-bodyWrap-default { + margin: 0 !important; + padding: 0 !important; +} + +/* Remove borders from nested panels (like gauge widgets inside Resources) */ +.x-panel-body>.x-box-layout-ct, +.x-panel-body>.x-container, +.x-panel-body>.x-box-inner, +[id*="pmxGauge"] { + border: none !important; +} + +.x-panel-header-title-default, +.x-window-header-title-default { + color: var(--trw-fg-default) !important; +} + +.x-panel-header-default .x-tool-tool-el { + background-color: transparent; +} + +.x-tool-img { + filter: brightness(175%); +} + +.x-tool-over .x-tool-img { + filter: brightness(200%); +} + +div[id^="pveResourceTree-"][id$="-body"] { + border-color: var(--trw-canvas-default) !important; +} + +/* Resource tree: remove row separators/borders */ +[id^="pveResourceTree-"].x-tree-panel td.x-grid-cell, +[id^="pveResourceTree-"].x-tree-panel .x-grid-td, +[id^="pveResourceTree-"].x-tree-panel .x-grid-cell { + border-bottom: none !important; +} + +/* Resource tree: slightly increased row spacing */ +div[id^="pveResourceTree"] .x-grid-cell { + padding-top: 3px !important; + padding-bottom: 3px !important; +} + +.x-panel-bodyWrap { + overflow: visible !important; +} + +/* ===================================================== + SPLITTERS / SEPARATORS + v2.1.1: Fixed double border issue + ===================================================== */ +.x-splitter-vertical { + background-color: transparent !important; + border-left: 1px solid var(--trw-border-default) !important; + border-right: none !important; + width: 1px !important; +} + +.x-splitter-horizontal { + background-color: var(--trw-canvas-inset) !important; + border-top: 1px solid var(--trw-border-default) !important; +} + +/* Toolbox tree (pve-nav) right border - full height */ +/* Fix: border must be on .pve-toolbar-bg (the full-height docked toolbar), + not on .x-treelist which only stretches to cover its items. + z-index: 3 needed because content toolbar (z-index: 2, same as nav) renders + on top (later in DOM), covering the nav right border. */ +.pve-toolbar-bg { + border-right: 1px solid var(--trw-border-default) !important; + z-index: 3 !important; +} + +.x-treelist.x-treelist-pve-nav { + border-right: none !important; +} + +/* ===================================================== + TOOLBARS + ===================================================== */ +.x-toolbar, +.x-toolbar-default { + background-color: var(--trw-canvas-default) !important; + border-color: var(--trw-border-default) !important; +} + +.x-toolbar-default.x-docked-top { + border: none !important; + border-bottom: 1px solid var(--trw-border-default) !important; +} + +.x-toolbar-default .x-toolbar-separator { + border-color: var(--trw-border-default); +} + +.x-toolbar-text-default { + color: var(--trw-fg-muted); +} + +/* ===================================================== + PRIMARY BUTTONS - GitHub Green (6px radius) + ===================================================== */ +.x-btn-default-small { + background-color: var(--trw-success-emphasis) !important; + border: 1px solid rgba(255, 255, 255, 0.15) !important; + border-radius: var(--trw-radius-md) !important; +} + +.x-btn-default-small .x-btn-inner { + color: var(--trw-fg-on-emphasis) !important; +} + +.x-btn-default-small.x-btn-over, +.x-keyboard-mode .x-btn-default-small.x-btn-focus { + background-color: var(--trw-success-hover) !important; +} + +.x-btn-default-small.x-btn.x-btn-disabled { + background-color: var(--trw-success-emphasis) !important; + opacity: 0.5; +} + +.x-btn-default-small.x-btn.x-btn-pressed { + background-color: var(--trw-success-active) !important; +} + +/* ===================================================== + SECONDARY/TOOLBAR BUTTONS (4px radius) + ===================================================== */ +.x-btn-default-toolbar-small { + background-color: var(--trw-canvas-subtle) !important; + border: 1px solid var(--trw-border-default) !important; + border-radius: var(--trw-radius-md) !important; +} + +.x-btn-default-toolbar-small .x-btn-inner-default-toolbar-small, +.x-btn-default-toolbar-small .x-btn-icon-el-default-toolbar-small { + color: var(--trw-fg-default) !important; +} + +.x-btn-default-toolbar-small .x-btn-wrap-default-toolbar-small.x-btn-arrow-right::after, +.x-btn-default-toolbar-small .x-btn-wrap-default-toolbar-small.x-btn-split-right::after { + filter: brightness(150%); +} + +.x-btn-default-toolbar-small.x-btn-over, +.x-keyboard-mode .x-btn-default-toolbar-small.x-btn-focus { + background-color: var(--trw-canvas-subtle) !important; + border-color: var(--trw-border-default) !important; +} + +.x-btn-default-toolbar-small.x-btn.x-btn-disabled { + background-color: var(--trw-canvas-subtle) !important; + opacity: 0.5; +} + +.x-btn-default-toolbar-small.x-btn.x-btn-menu-active, +.x-btn-default-toolbar-small.x-btn.x-btn-pressed { + background-color: var(--trw-accent-emphasis) !important; + border-color: var(--trw-accent-emphasis) !important; + padding: 4px 8px !important; /* Fix #30: prevent width change on dropdown */ +} + +.x-btn-default-toolbar-small.x-btn.x-btn-pressed .x-btn-inner-default-toolbar-small, +.x-btn-default-toolbar-small.x-btn.x-btn-pressed .x-btn-icon-el-default-toolbar-small { + color: var(--trw-fg-on-emphasis) !important; +} + +/* ===================================================== + FORM ELEMENTS (4px radius) + ===================================================== */ +.x-form-trigger-default { + background-color: var(--trw-canvas-muted) !important; +} + +.x-form-text-default { + background-color: var(--trw-canvas-muted) !important; + color: var(--trw-fg-default) !important; + border-radius: var(--trw-radius-sm) !important; +} + +.x-form-trigger-wrap, +.x-form-trigger-wrap-default { + border-color: var(--trw-border-default) !important; + background-color: var(--trw-canvas-muted) !important; + border-radius: var(--trw-radius-sm) !important; +} + +.x-form-trigger-wrap-default.x-form-trigger-wrap-focus { + border-color: var(--trw-accent-emphasis) !important; + box-shadow: 0 0 0 3px var(--trw-accent-subtle) !important; +} + +.x-form-item-label-default, +.x-form-cb-label-default { + color: var(--trw-fg-default) !important; +} + +.x-form-display-field-default { + color: var(--trw-fg-muted) !important; +} + +.x-form-spinner-default { + background-color: var(--trw-canvas-muted) !important; +} + +.x-fieldset, +.x-fieldset-default { + border-color: var(--trw-border-default) !important; + border-radius: var(--trw-radius-lg) !important; +} + +.x-fieldset-header-default>.x-fieldset-header-text { + color: var(--trw-fg-default) !important; +} + +/* ===================================================== + BOUNDLIST / DROPDOWNS (4px radius) + ===================================================== */ +.x-boundlist { + background-color: var(--trw-canvas-muted) !important; + border: 1px solid var(--trw-border-default) !important; + border-radius: var(--trw-radius-lg) !important; + box-shadow: 0 8px 24px rgba(1, 4, 9, 0.5); + overflow: hidden !important; +} + +.x-boundlist-item { + background-color: transparent !important; + color: var(--trw-fg-default) !important; +} + +.x-boundlist-selected { + background-color: var(--trw-accent-subtle) !important; +} + +.x-boundlist-item-over { + background-color: var(--trw-hover-overlay) !important; +} + +/* ===================================================== + GRIDS / TABLES (square corners) + ===================================================== */ +.x-grid, +.x-grid-view { + border-radius: 0 !important; +} + +.x-column-header { + border-color: var(--trw-border-default) !important; + background-color: transparent !important; +} + +.x-column-header-inner, +.x-column-header-text { + color: var(--trw-fg-default) !important; + font-weight: 600 !important; +} + +.x-column-header-trigger { + border-color: var(--trw-border-muted) !important; +} + +.x-grid-item, +.x-column-header-default, +.x-grid-cell-row-numberer { + color: var(--trw-fg-default) !important; + background-color: var(--trw-canvas-default) !important; +} + +.x-grid-cell-special { + border-color: var(--trw-border-default) !important; +} + +.x-grid-group-hd { + background-color: var(--trw-canvas-default) !important; + border-color: var(--trw-border-default) !important; +} + +.x-grid-group-title { + color: var(--trw-fg-default) !important; +} + +.x-grid-header-ct { + background-color: var(--trw-canvas-muted) !important; + border: 1px solid var(--trw-border-muted) !important; + border-radius: var(--trw-radius-lg) var(--trw-radius-lg) 0 0 !important; +} + +.x-grid-item-alt { + background-color: #0c0c0c !important; +} + +.x-grid-with-row-lines .x-grid-item { + border-color: var(--trw-border-muted) !important; +} + +.x-grid-cell { + border-bottom: 1px solid var(--trw-border-subtle) !important; +} + +.x-grid-item-over, +.x-grid-with-row-lines .x-grid-item.x-grid-item-over { + background-color: var(--trw-hover-overlay) !important; +} + +.x-grid-item-selected, +.x-grid-with-row-lines .x-grid-item.x-grid-item-selected { + background-color: var(--trw-accent-subtle) !important; +} + +.x-column-header-over, +.x-column-header-open { + background-color: var(--trw-hover-overlay) !important; +} + +.x-column-header-sort-ASC, +.x-column-header-sort-DESC { + background-color: #1c0808 !important; +} + +.x-grid-row-summary .x-grid-cell, +.x-grid-row-summary .x-grid-rowwrap, +.x-grid-row-summary .x-grid-cell-rowbody { + background-color: var(--trw-canvas-default) !important; + border-color: var(--trw-border-default); +} + +.x-grid-with-col-lines .x-grid-cell, +.x-grid-with-col-lines .x-grid-item-over .x-grid-cell, +.x-grid-with-col-lines .x-grid-item-selected .x-grid-cell { + border-color: var(--trw-border-default) !important; +} + +.x-dd-drag-proxy { + background-color: var(--trw-canvas-muted); + border-color: var(--trw-border-default); + color: var(--trw-fg-default); +} + +.x-keyboard-mode .x-grid-item-focused { + background-color: var(--trw-hover-overlay) !important; + color: var(--trw-fg-on-emphasis) !important; +} + +/* v2.2.1: Remove blue outline from selected/focused items in resource tree */ +.x-keyboard-mode .x-grid-item-focused .x-grid-cell-inner::before, +.x-keyboard-mode .x-grid-item-selected .x-grid-cell-inner::before, +.x-grid-item-selected .x-grid-cell-inner::before, +.x-grid-item-focused .x-grid-cell-inner::before, +[id^="pveResourceTree"] .x-grid-item-selected .x-grid-cell-inner::before, +[id^="pveResourceTree"] .x-grid-item-focused .x-grid-cell-inner::before { + content: none !important; + display: none !important; + border: none !important; +} + +.x-grid-empty { + background-color: var(--trw-canvas-default) !important; + color: var(--trw-fg-muted) !important; +} + +/* ===================================================== +/* ===================================================== + MENUS (variable radius) + ===================================================== */ +.x-menu, +.x-menu-default { + border: 1px solid var(--trw-border-default) !important; + border-radius: var(--trw-radius-lg) !important; + box-shadow: 0 8px 24px rgba(1, 4, 9, 0.5) !important; + overflow: hidden !important; +} + +.x-menu-body-default { + background-color: var(--trw-canvas-muted) !important; +} + +.x-menu-header { + background-color: var(--trw-accent-emphasis) !important; +} + +/* Menu Layout Fix (Flexbox reordering) */ +.x-menu-item-default > .x-menu-item-link { + display: flex !important; + align-items: center !important; + flex-direction: row !important; + padding: 6px 8px !important; + line-height: 20px !important; + text-decoration: none !important; +} + +.x-menu-item-text-default { + color: var(--trw-fg-default) !important; + font-size: 14px !important; + margin-left: 0 !important; +} + +.x-menu-item-icon-default { + color: var(--trw-fg-muted) !important; + order: -1 !important; /* Move icon to start */ + position: relative !important; + float: none !important; + margin-right: 8px !important; + margin-left: 0 !important; + left: auto !important; + top: auto !important; + width: 16px !important; + text-align: center !important; +} + +/* Remove the gutter/separator line */ +.x-menu-icon-separator-default { + display: none !important; +} + +.x-menu-item-default.x-menu-item-separator { + background-color: var(--trw-canvas-muted); + border-color: var(--trw-border-default); + margin: 4px 0 !important; +} + +.x-menu-item-default.x-menu-item-focus, +.x-menu-item-default.x-menu-item-active { + background-color: var(--trw-accent-emphasis) !important; + color: var(--trw-fg-on-emphasis) !important; +} + +.x-menu-item-active .x-menu-item-text-default, +.x-menu-item-focus .x-menu-item-text-default, +.x-menu-item-active .x-menu-item-icon-default, +.x-menu-item-focus .x-menu-item-icon-default { + color: var(--trw-fg-on-emphasis) !important; +} + +/* ===================================================== + PROGRESS BARS (5px radius) + ===================================================== */ +.x-progress, +.x-progress-default { + background-color: var(--trw-canvas-subtle) !important; + border-radius: var(--trw-radius-md) !important; +} + +.x-progress-default .x-progress-bar-default { + background-color: var(--trw-accent-emphasis) !important; + border-radius: var(--trw-radius-md) !important; +} + +.x-progress-default .x-progress-text { + color: var(--trw-fg-default) !important; +} + +.x-progress.warning .x-progress-bar { + background-color: var(--pwt-gauge-warn) !important; +} + +.x-progress.critical .x-progress-bar { + background-color: var(--pwt-gauge-crit) !important; +} + +/* ===================================================== + SPLITTERS + ===================================================== */ +.x-splitter { + background-color: var(--trw-canvas-inset) !important; +} + +.x-splitter-horizontal { + background-color: var(--trw-canvas-inset) !important; + border-top: 1px solid var(--trw-border-default) !important; +} + +.x-keyboard-mode .x-splitter-focus::after { + border-color: var(--trw-accent-emphasis) !important; +} + +.x-layout-split-bottom { + opacity: 0.7; +} + +/* ===================================================== + TABS — GitHub UnderlineNav style (v2.2.21) + Flat tabs, coral ::after underline on active tab. + Uses ::after (not border-bottom — ExtJS overrides it). + ===================================================== */ +.x-tab-bar, +.x-tab-bar-default { + background-color: var(--trw-canvas-default) !important; + border-radius: 0 !important; + border-bottom: 1px solid var(--trw-border-default) !important; + padding-bottom: 0 !important; +} + +/* v2.2.23: overflow visible on ALL containers within tab bar to prevent clipping */ +.x-tab-bar .x-box-inner, +.x-tab-bar .x-box-target, +.x-tab-bar-body, +.x-tab-bar-body-default { + overflow: visible !important; +} + +/* Base tab — no margin-bottom hack, position relative, no outlines */ +.x-tab, +.x-tab-default, +.x-tab-default-top { + background-color: transparent !important; + border: none !important; + border-radius: 0 !important; + padding: 8px 16px 8px !important; + overflow: visible !important; + margin-bottom: 0 !important; + transition: color .12s ease !important; + outline: none !important; + box-shadow: none !important; +} + +/* Remove ::after from inactive tabs */ +.x-tab::after { + display: none !important; +} + +.x-tab-inner-default { + color: var(--trw-fg-muted) !important; + font-size: 13px !important; +} + +.x-tab-default.x-tab-over { + background-color: transparent !important; +} +.x-tab-default.x-tab-over .x-tab-inner-default { + color: var(--trw-fg-default) !important; +} + +/* Active tab */ +.x-tab-default.x-tab.x-tab-active { + background-color: transparent !important; + border: none !important; + overflow: visible !important; + margin-bottom: 0 !important; + outline: none !important; + box-shadow: none !important; +} + +/* v2.2.23: coral underline INSIDE the tab at bottom:0 — immune to parent clipping */ +.x-tab-default.x-tab.x-tab-active::after { + content: '' !important; + display: block !important; + position: absolute !important; + bottom: 0 !important; + left: 0 !important; + right: 0 !important; + height: 2px !important; + background: var(--trw-accent-fg) !important; + z-index: 10 !important; + border-radius: 0 !important; + pointer-events: none !important; +} + +.x-tab-active .x-tab-inner-default { + color: var(--trw-fg-default) !important; + font-weight: 600 !important; +} + +.x-tab-default.x-tab.x-tab-disabled { + background-color: transparent !important; + border: none !important; + color: var(--trw-fg-subtle) !important; + margin-bottom: 0 !important; +} + +/* Keyboard mode focus: keep the same indicator, no outline */ +.x-keyboard-mode .x-tab-default.x-tab-focus, +.x-keyboard-mode .x-tab-default.x-tab-focus.x-tab-active { + background-color: transparent !important; + border: none !important; + outline: none !important; + box-shadow: none !important; + margin-bottom: 0 !important; +} +.x-keyboard-mode .x-tab-default.x-tab-focus.x-tab-active::after { + content: '' !important; + display: block !important; + position: absolute !important; + bottom: 0 !important; + left: 0 !important; + right: 0 !important; + height: 2px !important; + background: var(--trw-accent-fg) !important; + z-index: 10 !important; + pointer-events: none !important; +} + +/* Kill ALL interaction outlines/shadows — every possible state */ +.x-tab:focus, +.x-tab *:focus, +.x-tab-focus, +.x-tab-active.x-tab-focus, +.x-tab-inner-focus, +.x-tab-button-focus, +.x-tab-pressed, +.x-tab-active.x-tab-pressed, +.x-tab-over, +.x-tab:active, +.x-tab *:active { + outline: none !important; + box-shadow: none !important; +} + +.x-tabpanel-child { + border-radius: 0 0 var(--trw-radius-lg) var(--trw-radius-lg) !important; +} + +/* ===================================================== + TOOLTIPS (6px radius) + ===================================================== */ +.x-tip, +.x-tip-default { + background-color: var(--trw-canvas-muted) !important; + border: 1px solid var(--trw-border-default) !important; + border-radius: var(--trw-radius-md) !important; + box-shadow: 0 4px 12px rgba(1, 4, 9, 0.4); +} + +.x-tip-body-default { + color: var(--trw-fg-default) !important; +} + +.x-tip-form-invalid { + background-color: var(--trw-canvas-muted) !important; + border-color: var(--trw-danger-emphasis) !important; +} + +.x-tip-body-form-invalid { + color: var(--trw-danger-fg) !important; +} + +/* ===================================================== + TREE NAVIGATION (4px radius) + ===================================================== */ +.x-treelist-item { + background-color: var(--trw-canvas-default) !important; + border-radius: var(--trw-radius-md) !important; +} + +/* v2.2.4: Pseudo-element approach for balanced hover/selected highlighting */ +.x-treelist-row { + border-radius: var(--trw-radius-md) !important; + background-color: transparent !important; + position: relative !important; + z-index: 0 !important; +} + +.x-treelist-row::before { + content: ""; + position: absolute; + top: 1px; + bottom: 1px; + left: 0; + right: 4px; + border-radius: var(--trw-radius-md); + background-color: transparent; + z-index: -1; + pointer-events: none; +} + +/* v2.1.4: Fix toolbox tree item text overlapping icons (icon is 24px absolute positioned) */ +.x-treelist-item-text { + margin-left: 28px !important; +} + +/* Toolbox tree items - increased visibility */ +.x-treelist-item-text, +.x-treelist-item-icon, +.x-treelist.x-treelist-pve-nav .x-treelist-item-text, +.x-treelist.x-treelist-pve-nav .x-treelist-item-icon { + color: var(--trw-fg-default) !important; +} + +/* Hover state - apply to pseudo-element */ +.x-treelist-row-over { + background-color: transparent !important; +} + +.x-treelist-row-over::before { + background-color: var(--trw-hover-overlay) !important; +} + +.x-treelist-row-over .x-treelist-item-icon, +.x-treelist-row-over .x-treelist-item-text { + background-color: transparent !important; + color: var(--trw-fg-default) !important; +} + +/* Toolbox tree - selected/active item uses GitHub green (pseudo-element) */ +.x-treelist-item-selected>.x-treelist-row { + background-color: transparent !important; +} + +.x-treelist-item-selected>.x-treelist-row::before, +.x-treelist-item-selected>.x-treelist-row:hover::before { + background-color: var(--trw-success-emphasis) !important; +} + +.x-treelist-item-selected .x-treelist-item-text, +.x-treelist-item-selected .x-treelist-item-icon { + color: var(--trw-fg-on-emphasis) !important; +} + +.x-treelist-pve-nav { + background-color: var(--trw-canvas-default) !important; + border-color: var(--trw-border-default) !important; +} + +/* ===================================================== + WINDOWS / MODALS (variable radius) + ===================================================== */ +.x-window, +.x-window-default { + background-color: var(--trw-canvas-inset) !important; + border: 1px solid var(--trw-border-default) !important; + border-radius: var(--trw-radius-lg) !important; + box-shadow: 0 8px 24px rgba(1, 4, 9, 0.5) !important; + overflow: hidden !important; +} + +.x-window .x-window-header, +.x-window-header-default { + background-color: var(--trw-canvas-muted) !important; + border-color: transparent !important; + border-radius: var(--trw-radius-lg) var(--trw-radius-lg) 0 0 !important; +} + +.x-window-header-default .x-mask { + background-color: rgba(1, 4, 9, 0.7); +} + +.x-window .x-window-body, +.x-window-body-default { + background-color: var(--trw-canvas-default) !important; + border-color: var(--trw-border-default) !important; + color: var(--trw-fg-default) !important; + border-radius: 0 0 var(--trw-radius-lg) var(--trw-radius-lg) !important; +} + +.x-window-ghost { + background-color: var(--trw-canvas-default) !important; +} + +.x-window-header-default .x-tool-img { + background-color: transparent; +} + +.x-message-box .x-window-body { + background-color: var(--trw-canvas-muted) !important; +} + +/* ===================================================== + LEGEND / CHARTS + ===================================================== */ +.x-legend-container { + background-color: var(--trw-canvas-default) !important; +} + +.x-legend-horizontal .x-legend-item { + background-color: var(--trw-canvas-muted) !important; + color: var(--trw-fg-default) !important; + border: 1px solid var(--trw-border-muted) !important; +} + +/* ===================================================== + PROXMOX-SPECIFIC + ===================================================== */ +img[id^="proxmoxlogo-"][id$="-img"], +img[id^="proxmoxLogoSvg-"][id$="-img"] { + filter: invert(1) hue-rotate(180deg); +} + +.proxmox-invalid-row { + background-color: #521414 !important; +} + +.proxmox-warning-row { + background-color: #640 !important; +} + +.proxmox-disabled-row td { + color: var(--trw-fg-subtle) !important; +} + +.pmx-hint { + background-color: #640 !important; +} + +.pmx-hint a { + color: var(--trw-accent-fg) !important; +} + +.info-blue { + color: var(--trw-accent-fg) !important; +} + +.critical { + color: var(--trw-danger-fg) !important; +} + +/* Inline buttons (Documentation, Help) - GitHub Primer dark secondary button style */ +.proxmox-inline-button { + height: 28px !important; + min-height: 28px !important; + display: flex !important; + align-items: center !important; + padding: 3px 8px !important; + background-color: var(--trw-canvas-subtle) !important; + border: 1px solid var(--trw-border-default) !important; + border-radius: var(--trw-radius-md) !important; + color: var(--trw-fg-default) !important; + transition: background 0.08s cubic-bezier(0.33, 1, 0.68, 1) !important; +} + +.proxmox-inline-button:hover, +.proxmox-inline-button.x-btn-over { + background-color: var(--trw-canvas-muted) !important; + border-color: var(--trw-fg-muted) !important; +} + +.proxmox-inline-button:active, +.proxmox-inline-button.x-btn-pressed { + background-color: var(--trw-canvas-muted) !important; +} + +.proxmox-inline-button .x-btn-inner, +.proxmox-inline-button .x-btn-icon-el { + color: var(--trw-fg-default) !important; +} + +/* Loading states */ +.x-grid-row-loading, +.x-treelist-item-loading .x-treelist-item-icon, +.x-mask-msg-text, +.x-grid-tree-loading .x-tree-icon { + filter: invert(90%); +} + +.x-mask-msg { + background-color: var(--trw-canvas-muted) !important; + border: 1px solid var(--trw-border-default) !important; +} + +/* Markdown */ +.pmx-md code { + background-color: var(--trw-canvas-muted) !important; +} + +.pmx-md pre code { + border-color: var(--trw-border-default) !important; +} + +.pmx-md a { + color: var(--trw-accent-fg) !important; +} + +/* Tags */ +.pve-edit-tag.editable span { + background-color: var(--trw-canvas-muted) !important; + color: var(--trw-fg-default) !important; + border-color: var(--trw-border-default) !important; +} + +/* Datepicker */ +.x-datepicker, +.x-datepicker-column-header, +.x-monthpicker { + background-color: var(--trw-canvas-default) !important; + color: var(--trw-fg-default) !important; + border-color: transparent !important; +} + +.x-datepicker-header, +.x-datepicker-footer, +.x-monthpicker-buttons { + background-color: var(--trw-canvas-inset) !important; +} + +.x-datepicker-date, +.x-monthpicker-item-inner { + color: var(--trw-fg-default) !important; +} + +.x-datepicker-selected div.x-datepicker-date, +.x-monthpicker-item a.x-monthpicker-selected, +a.x-monthpicker-item-inner:hover, +div.x-datepicker-date:hover { + background-color: var(--trw-hover-overlay) !important; + color: var(--trw-fg-on-emphasis) !important; +} + +/* ===================================================== + SCROLLBARS - Cyber red-accented styling + ===================================================== */ +::-webkit-scrollbar { + width: 6px; + height: 6px; +} + +::-webkit-scrollbar-track { + background: var(--trw-canvas-default); +} + +::-webkit-scrollbar-thumb { + background: rgba(220, 38, 38, 0.25); + border-radius: 3px; + transition: background .3s; +} + +::-webkit-scrollbar-thumb:hover { + background: rgba(220, 38, 38, 0.5); +} + +::-webkit-scrollbar-corner { + background: var(--trw-canvas-default); +} + +/* Firefox scrollbar styling */ +* { + scrollbar-width: thin; + scrollbar-color: rgba(220, 38, 38, 0.25) var(--trw-canvas-default); +} + +/* ===================================================== + USAGE BARS (Vertical progress indicators) + v2.1.2: Using Proxmox dark theme default #e6e6e6 + ===================================================== */ +.usage { + background-color: #e6e6e6 !important; +} + +/* ===================================================== + DROPDOWNS - GitHub profile menu styling (dark) + ===================================================== */ +.x-menu, +.x-menu-default { + background-color: var(--trw-canvas-inset) !important; /* #050505 */ + border: 1px solid var(--trw-border-muted) !important; + border-radius: 6px !important; + box-shadow: 0 8px 24px rgba(1, 4, 9, 0.8) !important; + padding: 4px !important; +} + +.x-menu-body-default { + background-color: transparent !important; + padding: 4px !important; +} + +.x-menu-header { + background-color: transparent !important; + color: var(--trw-fg-default) !important; +} + +.x-menu-item-default > .x-menu-item-link { + display: flex !important; + align-items: center !important; + flex-direction: row !important; + gap: 8px !important; + justify-content: flex-start !important; + flex-wrap: nowrap !important; + min-height: 28px !important; + border-radius: 6px !important; + padding: 6px 8px !important; + line-height: 20px !important; + border: none !important; + cursor: pointer !important; + outline: none !important; + box-shadow: none !important; + white-space: nowrap !important; +} + +.x-menu-item-text-default { + color: var(--trw-fg-default) !important; + font-size: 13px !important; +} + +.x-menu-item-icon-default { + color: var(--trw-fg-muted) !important; + order: -1 !important; + margin-left: 0 !important; + margin-right: 8px !important; + position: relative !important; + left: 0 !important; + right: auto !important; + text-align: left !important; + display: inline-flex !important; + align-items: center !important; + justify-content: center !important; + height: 20px !important; + line-height: 20px !important; + vertical-align: middle !important; + top: 1px !important; + flex: 0 0 16px !important; + width: 16px !important; + align-self: center !important; + float: none !important; +} + +.x-menu-item-text-default { + order: 1 !important; + margin-left: 0 !important; + text-align: left !important; + line-height: 20px !important; + display: inline-flex !important; + align-items: center !important; + flex: 1 1 auto !important; + width: auto !important; + white-space: nowrap !important; +} + +.x-menu-item-default > .x-menu-item-link > .x-menu-item-icon-default, +.x-menu-item-default > .x-menu-item-link > .x-menu-item-text-default { + width: auto !important; + max-width: none !important; +} + +.x-menu-item-arrow, +.x-menu-item-arrow-default { + order: 2 !important; + margin-left: auto !important; +} + +.x-menu-item-default.x-menu-item-separator { + background-color: var(--trw-border-default) !important; + border: none !important; + height: 1px !important; + margin: 6px 4px !important; +} + +.x-menu-item-default.x-menu-item-focus, +.x-menu-item-default.x-menu-item-active, +.x-menu-item:hover { + background-color: var(--trw-canvas-muted) !important; + color: var(--trw-fg-default) !important; + border-radius: 6px !important; +} + +.x-menu-item-active .x-menu-item-text-default, +.x-menu-item-focus .x-menu-item-text-default { + color: var(--trw-fg-default) !important; +} + +/* Combo dropdowns (selects, boundlists) */ +.x-boundlist { + background-color: var(--trw-canvas-inset) !important; + border: 1px solid var(--trw-border-muted) !important; + border-radius: 6px !important; + box-shadow: 0 8px 24px rgba(1, 4, 9, 0.8) !important; + padding: 2px !important; + overflow: hidden !important; +} + +.x-boundlist-item { + border-radius: 6px !important; + padding: 2px 6px !important; + line-height: normal !important; + border: none !important; + cursor: pointer !important; + outline: none !important; + box-shadow: none !important; +} + +.x-boundlist-item-over { + background-color: var(--trw-canvas-muted) !important; +} + +.x-boundlist-selected { + background-color: var(--trw-selectmenu-active) !important; /* #2a0808 */ + color: var(--trw-fg-on-emphasis) !important; +} + +/* Floating grid pickers (storage/ISO selectors) */ +.x-layer.x-grid .x-grid-view, +.x-panel.x-layer.x-grid .x-grid-view, +.x-panel.x-layer.x-grid, +.x-layer.x-panel.x-grid { + border-radius: 6px !important; +} + +.x-layer.x-grid .x-grid-item-over, +.x-layer.x-grid .x-grid-item-selected, +.x-panel.x-layer.x-grid .x-grid-item-over, +.x-panel.x-layer.x-grid .x-grid-item-selected { + border-radius: 6px !important; + outline: none !important; + box-shadow: none !important; +} + +.x-layer.x-grid .x-grid-item-over td:first-child, +.x-layer.x-grid .x-grid-item-selected td:first-child, +.x-panel.x-layer.x-grid .x-grid-item-over td:first-child, +.x-panel.x-layer.x-grid .x-grid-item-selected td:first-child { + border-radius: 6px 0 0 6px !important; +} + +.x-layer.x-grid .x-grid-item-over td:last-child, +.x-layer.x-grid .x-grid-item-selected td:last-child, +.x-panel.x-layer.x-grid .x-grid-item-over td:last-child, +.x-panel.x-layer.x-grid .x-grid-item-selected td:last-child { + border-radius: 0 6px 6px 0 !important; +} + +/* ===================================================== + UNIFI BORDER-RADIUS PARITY (ported from theme-unifi.css) + ===================================================== */ +.x-border-box, +.x-border-box * { + border-radius: var(--trw-radius-lg); +} + +/* Remove rounded corners from grids/tables/lists (Tasks, logs) */ +.x-grid, +.x-grid *, +.x-grid-header-ct, +.x-grid-header-ct *, +.x-grid-view, +.x-grid-view *, +.x-column-header, +.x-column-header *, +.x-grid-item, +.x-grid-cell, +.x-grid-cell-inner, +.x-grid-row, +table, +table *, +tr, +td, +th, +.x-legend, +.x-legend *, +.x-legend-container, +.x-legend-container *, +.x-legend-item, +.x-legend-horizontal .x-legend-item, +.x-legend-vertical .x-legend-item, +.x-legend-horizontal .x-legend-item:first-child, +.x-legend-horizontal .x-legend-item:last-child, +.x-legend-vertical .x-legend-item:first-child, +.x-legend-vertical .x-legend-item:last-child, +.x-tool, +.x-tool-tool-el, +.x-tool-default, +.x-tool-img { + border-radius: 0 !important; +} + +/* Form elements - exclude from global radius */ +.x-form-item, +.x-form-item-default, +.x-form-item-body, +.x-form-item-body-default, +.x-form-text-field-body, +.x-form-text-field-body-default, +.x-form-fieldcontainer, +.x-field, +.x-field-default, +.x-form-type-text { + border-radius: 0 !important; +} + +/* Reset layout containers that clip form elements */ +.x-box-layout-ct, +.x-panel-bodyWrap, +.x-panel-bodyWrap-default, +.x-autocontainer-innerCt, +.x-autocontainer-outerCt, +.x-panel.x-tabpanel-child, +.x-panel.x-box-item, +.x-box-inner, +.x-box-target, +.x-container, +.x-container-default, +.x-window .x-panel-body, +.x-window .x-window-body, +.x-window .x-window-bodyWrap { + border-radius: 0 !important; +} + +/* Reset everything inside windows to 0 - then re-apply specific radii */ +.x-window *, +.x-window .x-autocontainer-innerCt, +.x-window .x-autocontainer-outerCt, +.x-window .x-form-layout-wrap, +.x-window .x-form-layout-auto-label, +.x-window .x-form-layout-colgroup, +.x-window .x-form-layout-column, +.x-window .x-field, +.x-window .x-form-item, +.x-window .x-form-item-body { + border-radius: 0 !important; +} + +.x-window, +.x-window-default { + border-radius: 8px !important; +} + +.x-window-header, +.x-window-header-default { + border-radius: 8px 8px 0 0 !important; +} + +.x-window .x-window-body, +.x-window-body-default { + border-radius: 0 !important; +} + +.x-window .x-btn { + border-radius: 6px !important; +} + +.x-window .x-form-checkbox { + border-radius: 4px !important; +} + +.x-window .x-form-trigger-wrap, +.x-window .x-form-trigger-wrap-default { + border-radius: 4px !important; +} + +.x-window .x-form-text-wrap, +.x-window .x-form-text { + border-radius: 4px 0 0 4px !important; +} + +.x-window .x-form-arrow-trigger { + border-radius: 0 4px 4px 0 !important; +} + +.x-form-trigger-wrap, +.x-form-trigger-wrap *, +.x-form-text-wrap, +.x-form-text-wrap *, +.x-form-text, +.x-form-trigger { + border-radius: 0 !important; +} + +.x-form-trigger-wrap, +.x-form-trigger-wrap-default { + border-radius: 4px !important; +} + +.x-form-text-wrap, +.x-form-text-wrap-default { + border-radius: 4px 0 0 4px !important; +} + +.x-form-text, +.x-form-text-default { + border-radius: 4px 0 0 4px !important; +} + +.x-form-trigger, +.x-form-trigger-default, +.x-form-arrow-trigger, +.x-form-arrow-trigger-default { + border-radius: 0 4px 4px 0 !important; +} + +.x-legend-item-marker { + border-radius: 50% !important; +} + +/* ===================================================== + CHECKBOXES & RADIOS — GitHub Primer (v2.2.18) + ===================================================== */ + +/* Base: remove sprite, styled as clean custom control */ +.x-form-checkbox, .x-form-checkbox-default, +.x-form-radio, .x-form-radio-default { + background-image: none !important; + background-color: var(--trw-canvas-subtle) !important; + border: 1.5px solid var(--trw-fg-subtle) !important; + width: 16px !important; + height: 16px !important; + display: inline-block !important; + box-sizing: border-box !important; + cursor: pointer !important; + transition: border-color .12s ease, background-color .12s ease !important; +} + +/* Checkbox: rounded square */ +.x-form-checkbox, .x-form-checkbox-default { + border-radius: 3px !important; +} + +/* Radio: circle + ::after inner dot */ +.x-form-radio, .x-form-radio-default { + border-radius: 50% !important; + position: relative !important; + transform: translateZ(0) !important; + box-shadow: inset 0 0 0 0 transparent !important; +} + +.x-form-radio::after { + content: '' !important; + position: absolute !important; + top: 50% !important; + left: 50% !important; + width: 7px !important; + height: 7px !important; + border-radius: 50% !important; + background: transparent !important; + transform: translate(-50%, -50%) scale(0) !important; + transition: transform .15s ease, background .15s ease !important; + pointer-events: none !important; +} + +/* Hover */ +.x-form-checkbox:hover, .x-form-checkbox-default:hover, +.x-form-cb-wrap:hover .x-form-checkbox { + border-color: var(--trw-accent-fg) !important; +} + +.x-form-radio:hover, .x-form-radio-default:hover, +.x-form-cb-wrap:hover .x-form-radio { + border-color: var(--trw-accent-fg) !important; +} + +/* CHECKED checkbox — .x-form-cb-checked lives on the .x-form-item ancestor */ +.x-form-cb-checked .x-form-checkbox, +.x-form-cb-checked .x-form-checkbox-default { + background-color: var(--trw-accent-emphasis) !important; + border-color: var(--trw-accent-emphasis) !important; + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 8'%3E%3Cpath d='M1 4l3 3 5-6' fill='none' stroke='%23fff' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") !important; + background-repeat: no-repeat !important; + background-position: center !important; + background-size: 9px 7px !important; +} + +/* SELECTED radio */ +.x-form-cb-checked .x-form-radio, +.x-form-cb-checked .x-form-radio-default { + border-color: var(--trw-accent-emphasis) !important; + background-color: var(--trw-canvas-muted) !important; +} + +.x-form-cb-checked .x-form-radio::after { + background: var(--trw-accent-emphasis) !important; + transform: translate(-50%, -50%) scale(1) !important; +} + +/* Buttons */ +.x-btn-default-small { + border-radius: 6px !important; +} + +.x-btn-default-toolbar-small { + border-radius: 4px !important; +} + +.x-btn.x-btn-default-small:has(.fa-check) { + border-radius: 4px !important; +} + +/* Boundlist dropdowns */ +.x-boundlist { + border-radius: 4px !important; +} + +.x-boundlist-item { + border-radius: 4px !important; +} + +.x-boundlist-list-ct { + border-radius: 4px !important; +} + +.x-boundlist-item-over, +.x-boundlist-selected { + border-radius: 4px !important; +} + +/* Menus */ +.x-menu, +.x-menu-default { + border-radius: 8px !important; +} + +.x-menu-item-default.x-menu-item-focus, +.x-menu-item-default.x-menu-item-active, +.x-menu-item:hover { + border-radius: 6px !important; +} + +/* Tooltips */ +.x-tip-default { + border-radius: 6px !important; +} + +/* Tree list items */ +.x-treelist-item, +.x-treelist-item-tool { + border-radius: 4px !important; +} + +.x-treelist-row, +.x-treelist-row:hover, +.x-treelist-row-over, +.x-treelist-item-selected>.x-treelist-row, +.x-treelist-item-selected>.x-treelist-row:hover, +.x-treelist-item-expanded>.x-treelist-row, +.x-treelist-item-expanded>.x-treelist-row-over, +.x-treelist-item-expandable>.x-treelist-row, +.x-treelist-item-expandable>.x-treelist-row-over { + border-radius: 4px !important; +} + +.x-treelist-row::before { + border-radius: 4px !important; +} + +.x-treelist-item-wrap, +.x-treelist-item-text, +.x-treelist-row, +.x-treelist-container, +.x-treelist-root-container, +.x-treelist, +.x-treelist-pve-nav { + border-radius: 4px !important; +} + +/* Window message mask */ +.x-mask-msg { + border-radius: 8px !important; +} + +/* Tags */ +.pve-edit-tag { + border-radius: 6px !important; +} + +.x-tree-node-text .proxmox-tag-dark, +.x-tree-node-text .proxmox-tag-light, +.x-grid-cell-inner .proxmox-tag-dark, +.x-grid-cell-inner .proxmox-tag-light, +span.proxmox-tag-dark, +span.proxmox-tag-light { + border-radius: 6px !important; +} + +/* Usage bars */ +.usage-wrapper, +.usage { + border-radius: 2px !important; +} + +/* Progress bars */ +.x-progress, +.x-progress-default { + border-radius: 5px !important; +} + +.x-progress-bar, +.x-progress-bar-default, +.x-progress-default .x-progress-bar-default { + border-radius: 5px !important; +} + +/* Scrollbar thumb */ +::-webkit-scrollbar-thumb { + border-radius: 4px !important; +} + +/* Summary/stats panels */ +.pveStatusPanel, +.x-panel-default-framed, +.x-panel-body-default-framed { + border-radius: 12px !important; +} + +[id^="pveGuestStatusView-"][id$="-body"], +[id^="pmxNotesView-"] .x-panel-body { + border-radius: 8px !important; +} + +.x-panel-header-default-framed { + border-radius: 12px 12px 0 0 !important; +} + +.pve-info-grid { + border-radius: 12px !important; +} + +.x-form-display-field-default { + border-radius: 6px !important; +} + +.pve-rrdview, +.rrdview { + border-radius: 12px !important; +} + +.pve-summary-status, +.x-container .pve-status { + border-radius: 8px !important; +} + +.x-panel-default[id*="notes"], +.pve-notes-view { + border-radius: 8px !important; +} + +.x-fieldset { + border-radius: 8px !important; +} + +/* Tab hover/active corners */ +.x-tab-default.x-tab-over, +.x-tab-default.x-tab.x-tab-active { + border-radius: 6px 6px 0 0 !important; +} + +/* Segmented buttons */ +.x-segmented-button { + border-radius: 6px !important; +} + +.x-segmented-button .x-btn, +.x-segmented-button .x-btn-default-small, +.x-segmented-button .x-btn-inner, +.x-segmented-button .x-btn-wrap { + border-radius: 6px !important; +} + +/* Summary page widget panels */ +.x-panel.x-column>.x-panel-bodyWrap>.x-panel-body.x-panel-body-default { + border-radius: 8px !important; +} + +/* Floating grid pickers (storage/ISO selectors) */ +.x-layer.x-grid .x-grid-view, +.x-panel.x-layer.x-grid .x-grid-view { + border-radius: 4px !important; +} + +.x-panel.x-layer.x-grid, +.x-layer.x-panel.x-grid { + border-radius: 4px !important; +} + +.x-layer.x-grid .x-grid-item-over, +.x-layer.x-grid .x-grid-item-selected, +.x-panel.x-layer.x-grid .x-grid-item-over, +.x-panel.x-layer.x-grid .x-grid-item-selected { + border-radius: 4px !important; +} + +.x-layer.x-grid .x-grid-item-over td, +.x-layer.x-grid .x-grid-item-selected td, +.x-layer.x-grid .x-grid-item-over .x-grid-cell, +.x-layer.x-grid .x-grid-item-selected .x-grid-cell, +.x-panel.x-layer.x-grid .x-grid-item-over td, +.x-panel.x-layer.x-grid .x-grid-item-selected td, +.x-panel.x-layer.x-grid .x-grid-item-over .x-grid-cell, +.x-panel.x-layer.x-grid .x-grid-item-selected .x-grid-cell { + border-radius: 0 !important; +} + +.x-layer.x-grid .x-grid-item-over td:first-child, +.x-layer.x-grid .x-grid-item-selected td:first-child, +.x-panel.x-layer.x-grid .x-grid-item-over td:first-child, +.x-panel.x-layer.x-grid .x-grid-item-selected td:first-child { + border-radius: 4px 0 0 4px !important; +} + +.x-layer.x-grid .x-grid-item-over td:last-child, +.x-layer.x-grid .x-grid-item-selected td:last-child, +.x-panel.x-layer.x-grid .x-grid-item-over td:last-child, +.x-panel.x-layer.x-grid .x-grid-item-selected td:last-child { + border-radius: 0 4px 4px 0 !important; +} + +/* Charts - remove border-radius from data area only */ +canvas.x-surface-canvas, +.x-surface-canvas, +.x-draw-component canvas, +.proxmox-rrd-chart canvas { + border-radius: 0 !important; +} + +svg.x-surface { + border-radius: 0 !important; +} + +.x-draw-container, +.x-surface { + border-radius: 0 !important; +} +/* ===================================================== + TOOL ICONS - FontAwesome Replacements + (Ported from UniFi v5.86) + Replace sprite-based ExtJS tool icons with crisp + FontAwesome icons for better consistency and clarity + ===================================================== */ + +/* Base styling for all tool icons - remove sprite backgrounds */ +.x-tool-tool-el.x-tool-minus, +.x-tool-img.x-tool-minus, +.x-tool-tool-el.x-tool-collapse-right, +.x-tool-img.x-tool-collapse-right, +.x-tool-tool-el.x-tool-collapse-left, +.x-tool-img.x-tool-collapse-left, +.x-tool-tool-el.x-tool-expand-right, +.x-tool-img.x-tool-expand-right, +.x-tool-tool-el.x-tool-expand-left, +.x-tool-img.x-tool-expand-left, +.x-tool-tool-el.x-tool-maximize, +.x-tool-img.x-tool-maximize, +.x-tool-tool-el.x-tool-restore, +.x-tool-img.x-tool-restore, +.x-tool-tool-el.x-tool-gear, +.x-tool-img.x-tool-gear, +.x-tool-tool-el.x-tool-refresh, +.x-tool-img.x-tool-refresh, +.x-tool-tool-el.x-tool-close, +.x-tool-img.x-tool-close { + background-image: none !important; + font-family: "FontAwesome" !important; + font-size: 14px !important; + line-height: 16px !important; + text-align: center !important; + color: var(--pm-text-dim) !important; + transition: color 0.15s ease !important; + filter: none !important; + width: 16px !important; + height: 16px !important; + display: flex !important; + align-items: center !important; + justify-content: center !important; +} + +/* Close button - slightly larger */ +.x-tool-tool-el.x-tool-close, +.x-tool-img.x-tool-close { + font-size: 20px !important; +} + +/* Individual glyph assignments */ +.x-tool-tool-el.x-tool-minus::before, +.x-tool-img.x-tool-minus::before { + content: "\f010" !important; /* fa-search-minus (zoom out) */ +} + +.x-tool-tool-el.x-tool-collapse-right::before, +.x-tool-img.x-tool-collapse-right::before { + content: "\f054" !important; /* fa-chevron-right */ +} + +.x-tool-tool-el.x-tool-expand-left::before, +.x-tool-img.x-tool-expand-left::before { + content: "\f053" !important; /* fa-chevron-left */ +} + +.x-tool-tool-el.x-tool-collapse-left::before, +.x-tool-img.x-tool-collapse-left::before { + content: "\f053" !important; /* fa-chevron-left */ +} + +.x-tool-tool-el.x-tool-expand-right::before, +.x-tool-img.x-tool-expand-right::before { + content: "\f054" !important; /* fa-chevron-right */ +} + +.x-tool-tool-el.x-tool-maximize::before, +.x-tool-img.x-tool-maximize::before { + content: "\f065" !important; /* fa-expand */ +} + +.x-tool-tool-el.x-tool-restore::before, +.x-tool-img.x-tool-restore::before { + content: "\f066" !important; /* fa-compress */ +} + +.x-tool-tool-el.x-tool-gear::before, +.x-tool-img.x-tool-gear::before { + content: "\f013" !important; /* fa-cog */ +} + +.x-tool-tool-el.x-tool-refresh::before, +.x-tool-img.x-tool-refresh::before { + content: "\f021" !important; /* fa-refresh */ +} + +.x-tool-tool-el.x-tool-close::before, +.x-tool-img.x-tool-close::before { + content: "\f00d" !important; /* fa-times */ +} + +/* Hover state - all tool icons */ +.x-tool:hover .x-tool-tool-el.x-tool-minus, +.x-tool:hover .x-tool-img.x-tool-minus, +.x-tool:hover .x-tool-tool-el.x-tool-collapse-right, +.x-tool:hover .x-tool-img.x-tool-collapse-right, +.x-tool:hover .x-tool-tool-el.x-tool-collapse-left, +.x-tool:hover .x-tool-img.x-tool-collapse-left, +.x-tool:hover .x-tool-tool-el.x-tool-expand-right, +.x-tool:hover .x-tool-img.x-tool-expand-right, +.x-tool:hover .x-tool-tool-el.x-tool-expand-left, +.x-tool:hover .x-tool-img.x-tool-expand-left, +.x-tool:hover .x-tool-tool-el.x-tool-maximize, +.x-tool:hover .x-tool-img.x-tool-maximize, +.x-tool:hover .x-tool-tool-el.x-tool-restore, +.x-tool:hover .x-tool-img.x-tool-restore, +.x-tool:hover .x-tool-tool-el.x-tool-gear, +.x-tool:hover .x-tool-img.x-tool-gear, +.x-tool:hover .x-tool-tool-el.x-tool-refresh, +.x-tool:hover .x-tool-img.x-tool-refresh, +.x-tool:hover .x-tool-tool-el.x-tool-close, +.x-tool:hover .x-tool-img.x-tool-close { + color: var(--pm-text) !important; +} + +/* Disabled state */ +.x-tool-disabled .x-tool-tool-el, +.x-tool-disabled .x-tool-img { + opacity: 0.4 !important; + cursor: default !important; +} + +/* Inline FontAwesome tools (PVE-injected) */ +.x-tool-tool-el[style*="font-family:FontAwesome"], +.x-tool-tool-el[style*="font-family: FontAwesome"] { + color: var(--pm-text-dim) !important; + font-size: 14px !important; + line-height: 16px !important; + display: flex !important; + align-items: center !important; + justify-content: center !important; + width: 16px !important; + height: 16px !important; + transition: color 0.15s ease !important; + background-image: none !important; + background-color: transparent !important; +} + +.x-tool:not(.x-tool-disabled) .x-tool-tool-el[style*="font-family:FontAwesome"], +.x-tool:not(.x-tool-disabled) .x-tool-tool-el[style*="font-family: FontAwesome"] { + cursor: pointer !important; +} + +.x-tool.x-tool-disabled .x-tool-tool-el[style*="font-family:FontAwesome"], +.x-tool.x-tool-disabled .x-tool-tool-el[style*="font-family: FontAwesome"] { + cursor: default !important; + opacity: 0.4 !important; +} + +.x-tool .x-mask { + background-color: transparent !important; + backdrop-filter: none !important; + pointer-events: none !important; +} + +.x-tool:not(.x-tool-disabled):hover .x-tool-tool-el[style*="font-family:FontAwesome"], +.x-tool:not(.x-tool-disabled):hover .x-tool-tool-el[style*="font-family: FontAwesome"] { + color: var(--pm-text) !important; +} diff --git a/themes/theme-tokyo-night.css b/themes/theme-tokyo-night.css new file mode 100644 index 0000000..4551a80 --- /dev/null +++ b/themes/theme-tokyo-night.css @@ -0,0 +1,2340 @@ +/*!Tokyo Night*/ + +/* ===================================================== + CSS VARIABLES + ===================================================== */ +:root { + /* Theme: Tokyo Night */ + --pm-accent: #7aa2f7; + --pm-bg-base: #1a1b26; + --pm-bg-surface: #1f2335; + --pm-bg-elevated: #24283b; + --pm-text: #c0caf5; + --pm-text-dim: #a9b1d6; + --pm-success: #9ece6a; + --pm-warning: #e0af68; + --pm-error: #f7768e; + --pm-border: #24283b; + --pm-radius-sm: 4px; + --pm-radius-md: 6px; + --pm-radius-lg: 8px; + + /* Proxmox Widget Toolkit Mappings */ + --pwt-panel-background: var(--pm-bg-base); + --pwt-text-color: var(--pm-text); + --pwt-gauge-default: var(--pm-accent); + --pwt-gauge-back: var(--pm-bg-elevated); + --pwt-gauge-warn: var(--pm-warning); + --pwt-gauge-crit: var(--pm-error); + --pwt-chart-primary: var(--pm-accent); + --pwt-chart-grid-stroke: var(--pm-bg-elevated); + + /* Tokyo Night theme internal variables (based on Dracula template structure) */ + --tn-text: var(--pm-text); + --tn-subtext0: var(--pm-text-dim); + --tn-subtext1: var(--pm-text-dim); + --tn-overlay0: var(--pm-border); + --tn-overlay1: var(--pm-text-dim); + --tn-overlay2: var(--pm-text-dim); + --tn-surface0: var(--pm-bg-surface); + --tn-surface1: var(--pm-bg-elevated); + --tn-surface2: var(--pm-bg-elevated); + --tn-base: var(--pm-bg-base); + --tn-mantle: #16161e; + --tn-crust: #16161e; + + --tn-on-accent: #1a1b26; + --tn-hover-overlay: rgba(128, 128, 128, 0.12); + --tn-select-overlay: rgba(128, 128, 128, 0.25); + --tn-accent-muted: rgba(128, 128, 128, 0.4); + --tn-accent-subtle: rgba(128, 128, 128, 0.15); + + --tn-cyan: var(--pm-accent); + --tn-green: var(--pm-success); + --tn-orange: var(--pm-warning); + --tn-pink: var(--pm-accent); + --tn-purple: var(--pm-accent); + --tn-red: var(--pm-error); + --tn-yellow: var(--pm-warning); + + color-scheme: dark; +} + +/* ===================================================== + GLOBAL BORDER-RADIUS ARCHITECTURE + (Ported from UniFi theme — reset everything, selectively re-apply) + ===================================================== */ +.x-border-box, +.x-border-box * { + border-radius: var(--pm-radius-lg); +} + +/* Remove rounded corners from grids/tables/lists */ +.x-grid, +.x-grid *, +.x-grid-header-ct, +.x-grid-header-ct *, +.x-grid-view, +.x-grid-view *, +.x-column-header, +.x-column-header *, +.x-grid-item, +.x-grid-cell, +.x-grid-cell-inner, +.x-grid-row, +table, +table *, +tr, +td, +th, +.x-legend, +.x-legend *, +.x-legend-container, +.x-legend-container *, +.x-legend-item, +.x-legend-horizontal .x-legend-item, +.x-legend-vertical .x-legend-item, +.x-legend-horizontal .x-legend-item:first-child, +.x-legend-horizontal .x-legend-item:last-child, +.x-legend-vertical .x-legend-item:first-child, +.x-legend-vertical .x-legend-item:last-child, +.x-tool, +.x-tool-tool-el, +.x-tool-default, +.x-tool-img { + border-radius: 0 !important; +} + +/* Form elements - exclude from global radius */ +.x-form-item, +.x-form-item-default, +.x-form-item-body, +.x-form-item-body-default, +.x-form-text-field-body, +.x-form-text-field-body-default, +.x-form-fieldcontainer, +.x-field, +.x-field-default, +.x-form-type-text { + border-radius: 0 !important; +} + +/* Reset layout containers that clip elements with overflow:hidden + radius */ +.x-box-layout-ct, +.x-panel-bodyWrap, +.x-panel-bodyWrap-default, +.x-autocontainer-innerCt, +.x-autocontainer-outerCt, +.x-panel.x-tabpanel-child, +.x-panel.x-box-item, +.x-box-inner, +.x-box-target, +.x-container, +.x-container-default, +.x-window .x-panel-body, +.x-window .x-window-body, +.x-window .x-window-bodyWrap { + border-radius: 0 !important; +} + +/* Reset everything inside windows to 0 — then re-apply specific radii */ +.x-window *, +.x-window .x-autocontainer-innerCt, +.x-window .x-autocontainer-outerCt, +.x-window .x-form-layout-wrap, +.x-window .x-form-layout-auto-label, +.x-window .x-form-layout-colgroup, +.x-window .x-form-layout-column, +.x-window .x-field, +.x-window .x-form-item, +.x-window .x-form-item-body { + border-radius: 0 !important; +} + +/* Chart canvas — no radius on data area */ +.x-chart-grid, +.x-chart-axis, +canvas.x-surface, +.x-chart canvas, +canvas.x-surface-canvas, +.x-surface-canvas, +.x-draw-component canvas, +.proxmox-rrd-chart canvas, +svg.x-surface, +.x-draw-container, +.x-surface { + border-radius: 0 !important; +} + +/* Legend color marker (dot) — keep circular */ +.x-legend-item-marker { + border-radius: 50% !important; +} + +/* ===================================================== + RE-APPLY BORDER RADII (selective) + ===================================================== */ + +/* Windows */ +.x-window, +.x-window-default { + border-radius: var(--pm-radius-lg) !important; +} + +.x-window-header, +.x-window-header-default { + border-radius: var(--pm-radius-lg) var(--pm-radius-lg) 0 0 !important; +} + +.x-window .x-window-body, +.x-window-body-default { + border-radius: 0 !important; +} + +/* Buttons inside windows */ +.x-window .x-btn { + border-radius: var(--pm-radius-md) !important; +} + +/* Checkboxes inside windows */ +.x-window .x-form-checkbox { + border-radius: 3px !important; +} + +/* Form inputs inside windows */ +.x-window .x-form-trigger-wrap, +.x-window .x-form-trigger-wrap-default { + border-radius: var(--pm-radius-sm) !important; +} + +.x-window .x-form-text-wrap, +.x-window .x-form-text { + border-radius: var(--pm-radius-sm) 0 0 var(--pm-radius-sm) !important; +} + +.x-window .x-form-arrow-trigger { + border-radius: 0 var(--pm-radius-sm) var(--pm-radius-sm) 0 !important; +} + +/* Form trigger/text wrap — reset and re-apply */ +.x-form-trigger-wrap, +.x-form-trigger-wrap *, +.x-form-text-wrap, +.x-form-text-wrap *, +.x-form-text, +.x-form-trigger { + border-radius: 0 !important; +} + +.x-form-trigger-wrap, +.x-form-trigger-wrap-default { + border-radius: var(--pm-radius-sm) !important; + overflow: hidden !important; +} + +.x-form-text-wrap, +.x-form-text-wrap-default { + border-radius: var(--pm-radius-sm) 0 0 var(--pm-radius-sm) !important; +} + +.x-form-text, +.x-form-text-default { + border-radius: var(--pm-radius-sm) 0 0 var(--pm-radius-sm) !important; +} + +.x-form-trigger, +.x-form-trigger-default, +.x-form-arrow-trigger, +.x-form-arrow-trigger-default { + border-radius: 0 var(--pm-radius-sm) var(--pm-radius-sm) 0 !important; +} + +/* Dialog form content padding — vertical only (horizontal causes ExtJS overflow) */ +.x-window .x-tabpanel-child .x-autocontainer-innerCt { + padding: 12px 0 !important; +} + +/* Allow column panel bodies to show overflowed form content */ +.x-window .x-panel-body:not(.x-scroller) { + overflow: visible !important; +} + +/* Side padding on column panel bodies inside windows */ +.x-window .x-panel.x-box-item .x-panel-body { + padding: 0 4px !important; +} + +/* Constrain autocontainer width inside windows */ +.x-window .x-autocontainer-outerCt { + max-width: 100% !important; +} + +/* Fix window header/body width consistency */ +.x-window > .x-window-header, +.x-window > .x-window-body, +.x-window > .x-window-bodyWrap, +.x-window-bodyWrap > .x-window-body { + width: 100% !important; +} + +.x-window-header > .x-box-inner, +.x-window-header > .x-box-inner > .x-box-target { + width: 100% !important; +} + +.x-window-header-title { + width: auto !important; + flex: 1 !important; + max-width: calc(100% - 30px) !important; +} + +/* Boundlists */ +.x-boundlist { + border-radius: var(--pm-radius-md) !important; + overflow: hidden !important; +} + +/* ===================================================== + BASE / BODY + ===================================================== */ +.x-body, +.x-viewport > .x-body, +body.x-border-layout-ct, +div.x-border-layout-ct { + background-color: var(--tn-base) !important; + color: var(--tn-text) !important; +} + +/* ===================================================== + MASKS & OVERLAYS + ===================================================== */ +.x-mask { + background-color: rgba(30, 31, 41, 0.6) !important; + backdrop-filter: blur(4px); +} + +.x-mask-msg { + background-color: var(--tn-mantle) !important; + border: 1px solid var(--tn-surface1) !important; + border-radius: var(--pm-radius-lg) !important; +} + +.x-mask-msg-text { + color: var(--tn-subtext0) !important; + filter: none !important; +} + +.x-css-shadow { + box-shadow: 0 8px 24px rgba(30, 31, 41, 0.6) !important; +} + +/* Loading indicators */ +.x-grid-row-loading, +.x-treelist-item-loading .x-treelist-item-icon, +.x-grid-tree-loading .x-tree-icon { + filter: invert(90%); +} + +/* ===================================================== + ICONS — Proxmox default colors for dark mode + ===================================================== */ + +/* General icon colors — neutral gray for dark backgrounds */ +.x-tree-icon-custom, +.x-grid-icon-custom, +.fa-tags::before, +.fa-file-o::before, +.fa-building::before, +.x-action-col-icon::before, +.fa-shield::before, +.fa-file-text-o::before, +.fa-clock-o::before, +.x-tab-icon-el-default, +.pve-icon-verify-lettering::after, +.x-tree-icon-leaf:not(.x-tree-icon-custom)::before, +.x-tree-icon-parent:not(.x-tree-icon-custom)::before, +.x-tree-icon-parent-expanded:not(.x-tree-icon-custom)::before, +.x-grid-filters-filtered-column .x-column-header-text::after { + color: var(--tn-overlay2) !important; +} + +/* Folder icons — invert for dark mode */ +.x-tree-icon-parent:not(.x-tree-icon-custom)::before, +.x-tree-icon-parent-expanded:not(.x-tree-icon-custom)::before { + filter: invert(90%); +} + +/* Various image-based icons — invert for visibility */ +.fa-ceph::before, +.fa-sdn::before, +.fa-network-wired::before, +.pve-itype-treelist-item-icon-cdrom, +.fa-chevron-right::before, +.x-grid-row-console, +.x-box-scroller-toolbar-default.x-box-scroller, +.x-tree-elbow-img, +.pve-itype-icon-qemu, +.x-tree-node-computer, +.x-grid-tree-node-expanded .x-tree-node-computer, +.pbs-icon-tape, +.pbs-icon-tape-drive, +.x-tree-icon-leaf:not(.x-tree-icon-custom), +.x-tree-icon-parent:not(.x-tree-icon-custom), +.x-tree-icon-parent-expanded:not(.x-tree-icon-custom) { + filter: invert(90%); +} + +/* Hardware icons */ +.pve-itype-icon-cpu, +.pve-itype-icon-cdrom, +.pve-itype-icon-memory, +.pve-itype-icon-pci, +.pve-itype-icon-serial, +.pve-itype-icon-die, +.pmx-itype-icon-processor, +.pmx-itype-icon-memory, +.pve-itype-icon-storage, +.x-tree-node-harddisk, +.x-grid-tree-node-expanded .x-tree-node-harddisk { + filter: invert(100%); +} + +/* Hardware icons — counter-invert for non-SVG icon cells */ +td.pve-itype-icon-storage .x-grid-cell-inner, +td.x-tree-node-harddisk .x-grid-cell-inner { + filter: invert(100%) !important; +} + +/* Hardware icons — hide inverted borders for non-SVG icon cells */ +td.pve-itype-icon-storage, +td.x-tree-node-harddisk { + border-color: transparent !important; +} + +/* Hardware grid icons — mask-image renders SVG icons in theme text color + Replaces filter:invert approach for pve-itype-icon-* and pmx-itype-icon-* grid cells */ +td.pve-itype-icon-cpu, +td.pve-itype-icon-cdrom, +td.pve-itype-icon-memory, +td.pve-itype-icon-pci, +td.pve-itype-icon-serial, +td.pve-itype-icon-die, +td.pmx-itype-icon-processor, +td.pmx-itype-icon-memory { + filter: none !important; + background-image: none !important; + padding-left: 0 !important; + border-color: transparent !important; +} + +td.pve-itype-icon-cpu .x-grid-cell-inner, +td.pve-itype-icon-cdrom .x-grid-cell-inner, +td.pve-itype-icon-memory .x-grid-cell-inner, +td.pve-itype-icon-pci .x-grid-cell-inner, +td.pve-itype-icon-serial .x-grid-cell-inner, +td.pve-itype-icon-die .x-grid-cell-inner, +td.pmx-itype-icon-processor .x-grid-cell-inner, +td.pmx-itype-icon-memory .x-grid-cell-inner { + padding-left: 3px !important; +} + +td.pve-itype-icon-cpu .x-grid-cell-inner::before, +td.pve-itype-icon-cdrom .x-grid-cell-inner::before, +td.pve-itype-icon-memory .x-grid-cell-inner::before, +td.pve-itype-icon-pci .x-grid-cell-inner::before, +td.pve-itype-icon-serial .x-grid-cell-inner::before, +td.pve-itype-icon-die .x-grid-cell-inner::before, +td.pmx-itype-icon-processor .x-grid-cell-inner::before, +td.pmx-itype-icon-memory .x-grid-cell-inner::before { + content: '' !important; + display: inline-block !important; + width: 18px !important; + height: 14px !important; + vertical-align: middle !important; + margin-right: 10px !important; + background-color: currentColor !important; + -webkit-mask-size: contain !important; + mask-size: contain !important; + -webkit-mask-repeat: no-repeat !important; + mask-repeat: no-repeat !important; + -webkit-mask-position: center !important; + mask-position: center !important; +} + +td.pve-itype-icon-cpu .x-grid-cell-inner::before { + -webkit-mask-image: url('/pve2/images/icon-cpu.svg') !important; + mask-image: url('/pve2/images/icon-cpu.svg') !important; +} + +td.pve-itype-icon-memory .x-grid-cell-inner::before { + -webkit-mask-image: url('/pve2/images/icon-memory.svg') !important; + mask-image: url('/pve2/images/icon-memory.svg') !important; +} + +td.pve-itype-icon-cdrom .x-grid-cell-inner::before { + -webkit-mask-image: url('/pve2/images/icon-cd-drive.svg') !important; + mask-image: url('/pve2/images/icon-cd-drive.svg') !important; +} + +td.pve-itype-icon-pci .x-grid-cell-inner::before { + -webkit-mask-image: url('/pve2/images/icon-pci.svg') !important; + mask-image: url('/pve2/images/icon-pci.svg') !important; +} + +td.pve-itype-icon-serial .x-grid-cell-inner::before { + -webkit-mask-image: url('/pve2/images/icon-serial.svg') !important; + mask-image: url('/pve2/images/icon-serial.svg') !important; +} + +td.pve-itype-icon-die .x-grid-cell-inner::before { + -webkit-mask-image: url('/pve2/images/icon-die.svg') !important; + mask-image: url('/pve2/images/icon-die.svg') !important; +} + +td.pmx-itype-icon-processor .x-grid-cell-inner::before { + -webkit-mask-image: url('../images/icon-cpu.svg') !important; + mask-image: url('../images/icon-cpu.svg') !important; +} + +td.pmx-itype-icon-memory .x-grid-cell-inner::before { + -webkit-mask-image: url('../images/icon-ram.svg') !important; + mask-image: url('../images/icon-ram.svg') !important; +} + + +/* Icon overlays — default */ +.x-tree-icon-custom::after, +.x-grid-icon-custom::after { + color: var(--tn-overlay2) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* RUNNING VMs/CTs — Dracula Green */ +.x-tree-icon-custom.running::after, +.x-grid-icon-custom.running::after, +.x-treelist-item-icon.running::after { + color: var(--tn-green) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* ONLINE state — Green */ +.x-tree-icon-custom.online::after, +.x-grid-icon-custom.online::after { + color: var(--tn-green) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* Stopped/offline — Overlay1 (muted gray) */ +.x-tree-icon-custom.stopped, +.x-tree-icon-custom.offline, +.x-grid-icon-custom.stopped, +.x-grid-icon-custom.offline { + color: var(--tn-overlay1) !important; +} + +/* Unknown state — Overlay1 */ +.x-tree-icon-custom.unknown::after, +.x-grid-icon-custom.unknown::after { + color: var(--tn-overlay1) !important; +} + +/* ERROR states — Dracula Red */ +.x-tree-icon-custom.error::after, +.x-tree-icon-custom.offline::after, +.x-tree-icon-custom.ha-error::after, +.x-grid-icon-custom.error::after, +.x-grid-icon-custom.offline::after, +.x-grid-icon-custom.ha-error::after { + color: var(--tn-red) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* PAUSED/SUSPENDED — Dracula Orange */ +.x-tree-icon-custom.paused::after, +.x-tree-icon-custom.suspended::after, +.x-tree-icon-custom.lock-suspending::after, +.x-grid-icon-custom.paused::after, +.x-grid-icon-custom.suspended::after, +.x-grid-icon-custom.lock-suspending::after { + color: var(--tn-orange) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* PENDING/WARNING states — Dracula Yellow */ +.x-tree-icon-custom.pending::after, +.x-tree-icon-custom.io-error::after, +.x-tree-icon-custom.internal-error::after, +.x-tree-icon-custom.guest-panicked::after, +.x-grid-icon-custom.pending::after, +.x-grid-icon-custom.io-error::after, +.x-grid-icon-custom.internal-error::after, +.x-grid-icon-custom.guest-panicked::after { + color: var(--tn-yellow) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* HA MAINTENANCE — Dracula Cyan */ +.x-tree-icon-custom.ha-maintenance::after, +.x-grid-icon-custom.ha-maintenance::after { + color: var(--tn-cyan) !important; + text-shadow: -1px 0 1px rgba(0, 0, 0, 0.5); +} + +/* Locked icons */ +.x-tree-icon-custom.locked::after, +.x-tree-icon-custom.lock-backup::after, +.x-tree-icon-custom.lock-migrate::after, +.x-tree-icon-custom.lock-suspended::after, +.x-grid-icon-custom.locked::after, +.x-grid-icon-custom.lock-backup::after, +.x-grid-icon-custom.lock-migrate::after, +.x-grid-icon-custom.lock-suspended::after { + color: var(--tn-overlay2) !important; +} + +/* LXC/QEMU type indicators */ +.x-tree-icon-custom.lxc::after, +.x-tree-icon-custom.qemu::after, +.x-grid-icon-custom.lxc::after, +.x-grid-icon-custom.qemu::after { + background-color: transparent; + color: var(--tn-overlay1) !important; +} + +.x-treelist-item-icon.lxc::after, +.x-treelist-item-icon.qemu::after { + background-color: transparent; + color: var(--tn-overlay1) !important; +} + +/* Tree expander arrows */ +.x-tree-arrows .x-tree-expander { + filter: brightness(200%); +} + +/* Cancel sprite-inversion on custom controls (checkboxes/radios handled via CSS) */ +.x-form-checkbox-default, +.x-form-radio-default, +.x-column-header-checkbox .x-column-header-checkbox::after, +.x-grid-checkcolumn::after, +.x-menu-item-checked .x-menu-item-icon-default.x-menu-item-checkbox, +.x-menu-item-unchecked .x-menu-item-icon-default.x-menu-item-checkbox { + filter: none !important; +} + +/* ===================================================== + PANELS & HEADERS + ===================================================== */ +.x-panel, +.x-panel-default { + border-radius: var(--pm-radius-lg) !important; + padding: 0 !important; +} + +/* Column panels — native stacked layout (Issue #23 fix) */ +.x-panel.x-column { + padding: 5px !important; + margin: 0 !important; + max-width: none !important; + box-sizing: border-box !important; +} + +/* Column panel card styling — borders for summary + chart panels */ +.x-panel.x-panel-default.x-column { + border: 1px solid var(--tn-surface1) !important; + border-radius: var(--pm-radius-lg) !important; + overflow: hidden !important; +} + +/* Guest status + Notes panel borders */ +[id^="pveGuestStatusView-"].x-panel, +[id^="pveLxcStatusView-"].x-panel, +[id^="pveQemuStatusView-"].x-panel, +[id^="pmxNotesView-"].x-panel { + border: 1px solid var(--tn-surface1) !important; + border-radius: var(--pm-radius-lg) !important; +} + +.x-panel-body, +.x-panel-body-default { + background-color: var(--tn-base) !important; + color: var(--tn-text) !important; + border: none !important; +} + +/* Panel headers — bottom border only */ +.x-panel-header, +.x-panel-header-default { + background-color: var(--tn-mantle) !important; + border: none !important; + border-bottom: 1px solid var(--tn-surface1) !important; + border-radius: var(--pm-radius-lg) var(--pm-radius-lg) 0 0 !important; + margin: 0 !important; + padding: 8px 12px !important; + width: 100% !important; + box-sizing: border-box !important; + overflow: visible !important; +} + +/* Title text — prevent border-radius clipping */ +.x-title-text, +.x-title-text-default { + overflow: visible !important; +} + +.x-panel-bodyWrap, +.x-panel-bodyWrap-default { + margin: 0 !important; + padding: 0 !important; + overflow: visible !important; +} + +/* Remove borders from nested panels */ +.x-panel-body > .x-box-layout-ct, +.x-panel-body > .x-container, +.x-panel-body > .x-box-inner, +[id*="pmxGauge"] { + border: none !important; +} + +.x-panel-header-title-default, +.x-window-header-title-default { + color: var(--tn-text) !important; +} + +.x-panel-header-default .x-tool-tool-el { + background-color: transparent; +} + +.x-tool-img { + filter: brightness(175%); +} + +.x-tool-over .x-tool-img { + filter: brightness(200%); +} + +/* Resource tree — panel body border */ +div[id^="pveResourceTree-"][id$="-body"] { + border-color: var(--tn-base) !important; +} + +/* Resource tree — remove row separators */ +[id^="pveResourceTree-"].x-tree-panel td.x-grid-cell, +[id^="pveResourceTree-"].x-tree-panel .x-grid-td, +[id^="pveResourceTree-"].x-tree-panel .x-grid-cell { + border-bottom: none !important; +} + +/* Resource tree — row spacing */ +div[id^="pveResourceTree"] .x-grid-cell { + padding-top: 3px !important; + padding-bottom: 3px !important; +} + +/* Summary/stats panel radius overrides */ +.pveStatusPanel, +.x-panel-default-framed, +.x-panel-body-default-framed { + border-radius: 12px !important; +} + +.x-panel-header-default-framed { + border-radius: 12px 12px 0 0 !important; +} + +/* Column widget panel radius */ +.x-panel.x-column > .x-panel-bodyWrap > .x-panel-body.x-panel-body-default { + border-radius: var(--pm-radius-lg) !important; +} + +/* ===================================================== + SPLITTERS / SEPARATORS + ===================================================== */ +.x-splitter-vertical { + background-color: transparent !important; + border-left: 1px solid var(--tn-surface1) !important; + border-right: none !important; + width: 1px !important; +} + +.x-splitter-horizontal { + background-color: var(--tn-crust) !important; + border-top: 1px solid var(--tn-surface1) !important; +} + +.x-splitter { + background-color: var(--tn-crust) !important; +} + +.x-keyboard-mode .x-splitter-focus::after { + border-color: var(--tn-purple) !important; +} + +.x-layout-split-bottom { + opacity: 0.7; +} + +/* Toolbox tree (pve-nav) right border — full height */ +.pve-toolbar-bg { + border-right: 1px solid var(--tn-surface1) !important; + z-index: 3 !important; +} + +.x-treelist.x-treelist-pve-nav { + border-right: none !important; +} + +/* ===================================================== + TOOLBARS + ===================================================== */ +.x-toolbar, +.x-toolbar-default { + background-color: var(--tn-base) !important; + border-color: var(--tn-surface1) !important; +} + +.x-toolbar-default.x-docked-top { + border: none !important; + border-bottom: 1px solid var(--tn-surface1) !important; +} + +.x-toolbar-default .x-toolbar-separator { + border-color: var(--tn-surface1); +} + +.x-toolbar-text-default { + color: var(--tn-subtext0); +} + +/* ===================================================== + PRIMARY BUTTONS — Dracula Purple + ===================================================== */ +.x-btn-default-small { + background-color: var(--tn-purple) !important; + border: 1px solid rgba(189, 147, 249, 0.4) !important; + border-radius: var(--pm-radius-md) !important; + transition: background-color 0.15s ease, box-shadow 0.15s ease !important; +} + +.x-btn-default-small .x-btn-inner { + color: var(--tn-on-accent) !important; + font-weight: 600 !important; +} + +.x-btn-default-small .x-btn-icon-el { + color: var(--tn-on-accent) !important; +} + +.x-btn-default-small.x-btn-over, +.x-keyboard-mode .x-btn-default-small.x-btn-focus { + background-color: #caa9fa !important; + box-shadow: 0 0 0 3px var(--tn-accent-subtle) !important; +} + +.x-btn-default-small.x-btn.x-btn-disabled { + background-color: var(--tn-purple) !important; + opacity: 0.4; +} + +.x-btn-default-small.x-btn.x-btn-pressed { + background-color: #a986f0 !important; +} + +/* Button height consistency — 28px with vertical centering */ +/* Exclude tag edit buttons (display:none when hidden, :has(.fa-check) for checkmark) */ +.x-btn.x-btn-default-small:not(.x-btn-default-toolbar-small):not([style*="display: none"]):not([style*="display:none"]):not(:has(.fa-check)) { + height: 28px !important; + min-height: 28px !important; + display: flex !important; + align-items: center !important; + padding: 3px 8px !important; +} + +/* Fix button inner element centering for proper icon alignment (issue #17) */ +.x-btn.x-btn-default-small:not(.x-btn-default-toolbar-small):not([style*="display: none"]):not([style*="display:none"]):not(:has(.fa-check)) .x-btn-wrap { + display: flex !important; + align-items: center !important; +} + +.x-btn.x-btn-default-small:not(.x-btn-default-toolbar-small):not([style*="display: none"]):not([style*="display:none"]):not(:has(.fa-check)) .x-btn-inner { + display: flex !important; + align-items: center !important; +} + +/* Fix dropdown arrows on split/arrow buttons */ +.x-btn-wrap.x-btn-arrow-right::after, +.x-btn-wrap.x-btn-split-right::after { + height: 16px !important; + min-height: 16px !important; + width: 20px !important; + display: flex !important; + align-items: center !important; +} + +/* Fix icon-only buttons — hide   inner element when button has no text */ +.x-btn-no-text .x-btn-inner, +.x-btn-button.x-btn-no-text .x-btn-inner, +.x-btn-button-default-toolbar-small.x-btn-no-text .x-btn-inner-default-toolbar-small, +.x-btn-button-default-small.x-btn-no-text .x-btn-inner-default-small, +.x-btn-button-default-small.x-btn-no-text > .x-btn-inner-default-small { + display: none !important; +} + +/* Specific fix for fa-desktop icon (Create VM) — visually bottom-heavy */ +.x-btn-icon-el.fa-desktop { + transform: translateY(1.1px) !important; +} + +/* ===================================================== + SECONDARY / TOOLBAR BUTTONS + ===================================================== */ +.x-btn-default-toolbar-small { + background-color: var(--tn-surface0) !important; + border: 1px solid var(--tn-surface1) !important; + border-radius: var(--pm-radius-md) !important; + transition: background-color 0.15s ease, border-color 0.15s ease !important; +} + +.x-btn-default-toolbar-small .x-btn-inner-default-toolbar-small, +.x-btn-default-toolbar-small .x-btn-icon-el-default-toolbar-small { + color: var(--tn-text) !important; +} + +.x-btn-default-toolbar-small .x-btn-wrap-default-toolbar-small.x-btn-arrow-right::after, +.x-btn-default-toolbar-small .x-btn-wrap-default-toolbar-small.x-btn-split-right::after { + filter: brightness(150%); +} + +.x-btn-default-toolbar-small.x-btn-over, +.x-keyboard-mode .x-btn-default-toolbar-small.x-btn-focus { + background-color: var(--tn-surface1) !important; + border-color: var(--tn-surface2) !important; +} + +.x-btn-default-toolbar-small.x-btn.x-btn-disabled { + background-color: var(--tn-surface0) !important; + opacity: 0.4; +} + +.x-btn-default-toolbar-small.x-btn.x-btn-menu-active, +.x-btn-default-toolbar-small.x-btn.x-btn-pressed { + background-color: var(--tn-purple) !important; + border-color: var(--tn-purple) !important; + padding: 4px 8px !important; /* Fix #30: prevent width change on dropdown */ +} + +.x-btn-default-toolbar-small.x-btn.x-btn-pressed .x-btn-inner-default-toolbar-small, +.x-btn-default-toolbar-small.x-btn.x-btn-pressed .x-btn-icon-el-default-toolbar-small, +.x-btn-default-toolbar-small.x-btn.x-btn-pressed .x-btn-inner-default-small, +.x-btn-default-toolbar-small.x-btn.x-btn-pressed .x-btn-icon-el-default-small { + color: var(--tn-on-accent) !important; +} + +/* Segmented buttons */ +.x-segmented-button { + border-radius: var(--pm-radius-md) !important; +} + +.x-segmented-button .x-btn, +.x-segmented-button .x-btn-default-small, +.x-segmented-button .x-btn-inner, +.x-segmented-button .x-btn-wrap { + border-radius: var(--pm-radius-md) !important; +} + +/* Inline buttons (Documentation, Help) */ +.proxmox-inline-button { + height: 28px !important; + min-height: 28px !important; + display: flex !important; + align-items: center !important; + padding: 3px 8px !important; + background-color: var(--tn-surface0) !important; + border: 1px solid var(--tn-surface1) !important; + border-radius: var(--pm-radius-md) !important; + color: var(--tn-text) !important; + transition: background-color 0.15s ease !important; +} + +.proxmox-inline-button:hover, +.proxmox-inline-button.x-btn-over { + background-color: var(--tn-surface1) !important; + border-color: var(--tn-overlay0) !important; +} + +.proxmox-inline-button:active, +.proxmox-inline-button.x-btn-pressed { + background-color: var(--tn-surface2) !important; +} + +.proxmox-inline-button .x-btn-inner, +.proxmox-inline-button .x-btn-icon-el { + color: var(--tn-text) !important; +} + +/* Pressed/active inline buttons — use on-accent text */ +.proxmox-inline-button.x-btn-pressed .x-btn-inner, +.proxmox-inline-button.x-btn-pressed .x-btn-icon-el, +.proxmox-inline-button.x-btn-menu-active .x-btn-inner, +.proxmox-inline-button.x-btn-menu-active .x-btn-icon-el { + color: var(--tn-on-accent) !important; +} + +/* ===================================================== + FORM ELEMENTS + ===================================================== */ +.x-form-trigger-default { + background-color: var(--tn-surface0) !important; +} + +.x-form-text-default { + background-color: var(--tn-surface0) !important; + color: var(--tn-text) !important; + border-radius: var(--pm-radius-sm) !important; +} + +.x-form-trigger-wrap, +.x-form-trigger-wrap-default { + border-color: var(--tn-surface1) !important; + background-color: var(--tn-surface0) !important; + border-radius: var(--pm-radius-sm) !important; + transition: border-color 0.15s ease !important; +} + +.x-form-trigger-wrap-default.x-form-trigger-wrap-focus { + border-color: var(--tn-purple) !important; + box-shadow: 0 0 0 3px var(--tn-accent-subtle) !important; +} + +.x-form-item-label-default, +.x-form-cb-label-default { + color: var(--tn-text) !important; +} + +.x-form-display-field-default { + color: var(--tn-subtext0) !important; + border-radius: var(--pm-radius-md) !important; +} + +.x-form-spinner-default { + background-color: var(--tn-surface0) !important; +} + +.x-fieldset, +.x-fieldset-default { + border-color: var(--tn-surface1) !important; + border-radius: var(--pm-radius-lg) !important; +} + +.x-fieldset-header-default > .x-fieldset-header-text { + color: var(--tn-text) !important; +} + +/* ===================================================== + CHECKBOXES & RADIOS — Dracula styled + ===================================================== */ + +/* Base: remove sprite, styled as custom control */ +.x-form-checkbox, .x-form-checkbox-default, +.x-form-radio, .x-form-radio-default { + background-image: none !important; + background-color: var(--tn-surface0) !important; + border: 1.5px solid var(--tn-overlay0) !important; + width: 16px !important; + height: 16px !important; + display: inline-block !important; + box-sizing: border-box !important; + cursor: pointer !important; + transition: border-color 0.12s ease, background-color 0.12s ease !important; +} + +/* Checkbox: rounded square */ +.x-form-checkbox, .x-form-checkbox-default { + border-radius: 3px !important; +} + +/* Radio: circle + ::after inner dot */ +.x-form-radio, .x-form-radio-default { + border-radius: 50% !important; + position: relative !important; + transform: translateZ(0) !important; + box-shadow: inset 0 0 0 0 transparent !important; +} + +.x-form-radio::after { + content: '' !important; + position: absolute !important; + top: 50% !important; + left: 50% !important; + width: 7px !important; + height: 7px !important; + border-radius: 50% !important; + background: transparent !important; + transform: translate(-50%, -50%) scale(0) !important; + transition: transform 0.15s ease, background 0.15s ease !important; + pointer-events: none !important; +} + +/* Hover */ +.x-form-checkbox:hover, .x-form-checkbox-default:hover, +.x-form-cb-wrap:hover .x-form-checkbox { + border-color: var(--tn-purple) !important; +} + +.x-form-radio:hover, .x-form-radio-default:hover, +.x-form-cb-wrap:hover .x-form-radio { + border-color: var(--tn-purple) !important; +} + +/* CHECKED checkbox — Purple fill + dark SVG checkmark */ +.x-form-cb-checked .x-form-checkbox, +.x-form-cb-checked .x-form-checkbox-default { + background-color: var(--tn-purple) !important; + border-color: var(--tn-purple) !important; + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 8'%3E%3Cpath d='M1 4l3 3 5-6' fill='none' stroke='%231a1b26' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") !important; + background-repeat: no-repeat !important; + background-position: center !important; + background-size: 9px 7px !important; +} + +/* SELECTED radio — Purple dot */ +.x-form-cb-checked .x-form-radio, +.x-form-cb-checked .x-form-radio-default { + border-color: var(--tn-purple) !important; + background-color: var(--tn-base) !important; +} + +.x-form-cb-checked .x-form-radio::after { + background: var(--tn-purple) !important; + transform: translate(-50%, -50%) scale(1) !important; +} + +/* ===================================================== + BOUNDLIST / DROPDOWNS + ===================================================== */ +.x-boundlist { + background-color: var(--tn-mantle) !important; + border: 1px solid var(--tn-surface1) !important; + border-radius: var(--pm-radius-md) !important; + box-shadow: 0 8px 24px rgba(30, 31, 41, 0.7) !important; + padding: 2px !important; + overflow: hidden !important; +} + +.x-boundlist-item { + background-color: transparent !important; + color: var(--tn-text) !important; + border-radius: var(--pm-radius-sm) !important; + padding: 2px 6px !important; + line-height: normal !important; + border: none !important; + cursor: pointer !important; + outline: none !important; + box-shadow: none !important; +} + +.x-boundlist-selected { + background-color: var(--tn-select-overlay) !important; + color: var(--tn-text) !important; +} + +.x-boundlist-item-over { + background-color: var(--tn-hover-overlay) !important; +} + +/* ===================================================== + GRIDS / TABLES + ===================================================== */ +.x-grid, +.x-grid-view { + border-radius: 0 !important; +} + +.x-column-header { + border-color: var(--tn-surface1) !important; + background-color: transparent !important; +} + +.x-column-header-inner, +.x-column-header-text { + color: var(--tn-text) !important; + font-weight: 600 !important; +} + +.x-column-header-trigger { + border-color: var(--tn-surface1) !important; +} + +.x-grid-item, +.x-column-header-default, +.x-grid-cell-row-numberer { + color: var(--tn-text) !important; + background-color: var(--tn-base) !important; +} + +.x-grid-cell-special { + border-color: var(--tn-surface1) !important; +} + +.x-grid-group-hd { + background-color: var(--tn-base) !important; + border-color: var(--tn-surface1) !important; +} + +.x-grid-group-title { + color: var(--tn-text) !important; +} + +.x-grid-header-ct { + background-color: var(--tn-mantle) !important; + border: 1px solid var(--tn-surface0) !important; + border-radius: var(--pm-radius-lg) var(--pm-radius-lg) 0 0 !important; +} + +.x-grid-item-alt { + background-color: var(--tn-crust) !important; +} + +.x-grid-with-row-lines .x-grid-item { + border-color: var(--tn-surface0) !important; +} + +.x-grid-cell { + border-bottom: 1px solid rgba(68, 71, 90, 0.4) !important; +} + +.x-grid-item-over, +.x-grid-with-row-lines .x-grid-item.x-grid-item-over { + background-color: var(--tn-hover-overlay) !important; +} + +.x-grid-item-selected, +.x-grid-with-row-lines .x-grid-item.x-grid-item-selected { + background-color: var(--tn-select-overlay) !important; +} + +.x-column-header-over, +.x-column-header-open { + background-color: var(--tn-hover-overlay) !important; +} + +.x-column-header-sort-ASC, +.x-column-header-sort-DESC { + background-color: var(--tn-hover-overlay) !important; +} + +.x-grid-row-summary .x-grid-cell, +.x-grid-row-summary .x-grid-rowwrap, +.x-grid-row-summary .x-grid-cell-rowbody { + background-color: var(--tn-base) !important; + border-color: var(--tn-surface1); +} + +.x-grid-with-col-lines .x-grid-cell, +.x-grid-with-col-lines .x-grid-item-over .x-grid-cell, +.x-grid-with-col-lines .x-grid-item-selected .x-grid-cell { + border-color: var(--tn-surface1) !important; +} + +.x-dd-drag-proxy { + background-color: var(--tn-mantle); + border-color: var(--tn-surface1); + color: var(--tn-text); +} + +.x-keyboard-mode .x-grid-item-focused { + background-color: var(--tn-hover-overlay) !important; + color: var(--tn-text) !important; +} + +/* Remove blue outline from focused/selected items in resource tree */ +.x-keyboard-mode .x-grid-item-focused .x-grid-cell-inner::before, +.x-keyboard-mode .x-grid-item-selected .x-grid-cell-inner::before, +.x-grid-item-selected .x-grid-cell-inner::before, +.x-grid-item-focused .x-grid-cell-inner::before, +[id^="pveResourceTree"] .x-grid-item-selected .x-grid-cell-inner::before, +[id^="pveResourceTree"] .x-grid-item-focused .x-grid-cell-inner::before { + content: none !important; + display: none !important; + border: none !important; +} + +.x-grid-empty { + background-color: var(--tn-base) !important; + color: var(--tn-subtext0) !important; +} + +/* Grid info (pve-info-grid) and RRD view */ +.pve-info-grid { + border-radius: 12px !important; +} + +.pve-rrdview, +.rrdview { + border-radius: 12px !important; +} + +.pve-summary-status, +.x-container .pve-status { + border-radius: var(--pm-radius-lg) !important; +} + +[id^="pveGuestStatusView-"][id$="-body"], +[id^="pmxNotesView-"] .x-panel-body { + border-radius: var(--pm-radius-lg) !important; +} + +.x-panel-default[id*="notes"], +.pve-notes-view { + border-radius: var(--pm-radius-lg) !important; +} + +/* Floating grid pickers (storage/ISO selectors) */ +.x-layer.x-grid .x-grid-view, +.x-panel.x-layer.x-grid .x-grid-view, +.x-panel.x-layer.x-grid, +.x-layer.x-panel.x-grid { + border-radius: var(--pm-radius-sm) !important; +} + +.x-layer.x-grid .x-grid-item-over, +.x-layer.x-grid .x-grid-item-selected, +.x-panel.x-layer.x-grid .x-grid-item-over, +.x-panel.x-layer.x-grid .x-grid-item-selected { + border-radius: var(--pm-radius-sm) !important; + outline: none !important; + box-shadow: none !important; +} + +.x-layer.x-grid .x-grid-item-over td, +.x-layer.x-grid .x-grid-item-selected td, +.x-layer.x-grid .x-grid-item-over .x-grid-cell, +.x-layer.x-grid .x-grid-item-selected .x-grid-cell, +.x-panel.x-layer.x-grid .x-grid-item-over td, +.x-panel.x-layer.x-grid .x-grid-item-selected td, +.x-panel.x-layer.x-grid .x-grid-item-over .x-grid-cell, +.x-panel.x-layer.x-grid .x-grid-item-selected .x-grid-cell { + border-radius: 0 !important; +} + +.x-layer.x-grid .x-grid-item-over td:first-child, +.x-layer.x-grid .x-grid-item-selected td:first-child, +.x-panel.x-layer.x-grid .x-grid-item-over td:first-child, +.x-panel.x-layer.x-grid .x-grid-item-selected td:first-child { + border-radius: var(--pm-radius-sm) 0 0 var(--pm-radius-sm) !important; +} + +.x-layer.x-grid .x-grid-item-over td:last-child, +.x-layer.x-grid .x-grid-item-selected td:last-child, +.x-panel.x-layer.x-grid .x-grid-item-over td:last-child, +.x-panel.x-layer.x-grid .x-grid-item-selected td:last-child { + border-radius: 0 var(--pm-radius-sm) var(--pm-radius-sm) 0 !important; +} + +/* ===================================================== + MENUS + ===================================================== */ +.x-menu, +.x-menu-default { + background-color: var(--tn-crust) !important; + border: 1px solid var(--tn-surface0) !important; + border-radius: var(--pm-radius-lg) !important; + box-shadow: 0 8px 24px rgba(30, 31, 41, 0.8) !important; + padding: 4px !important; + overflow: hidden !important; +} + +.x-menu-body-default { + background-color: transparent !important; + padding: 4px !important; +} + +.x-menu-header { + background-color: transparent !important; + color: var(--tn-text) !important; +} + +/* Menu icon separator — hide */ +.x-menu-icon-separator-default { + display: none !important; +} + +/* Menu item layout (flexbox reordering) */ +.x-menu-item-default > .x-menu-item-link { + display: flex !important; + align-items: center !important; + flex-direction: row !important; + gap: 4px !important; + justify-content: flex-start !important; + flex-wrap: nowrap !important; + border-radius: var(--pm-radius-md) !important; + padding: 4px 8px !important; + line-height: 20px !important; + border: none !important; + cursor: pointer !important; + outline: none !important; + box-shadow: none !important; + white-space: nowrap !important; + text-decoration: none !important; +} + +.x-menu-item-text-default { + color: var(--tn-text) !important; + font-size: 13px !important; + order: 1 !important; + margin-left: 0 !important; + text-align: left !important; + line-height: 20px !important; + display: inline-flex !important; + align-items: center !important; + flex: 1 1 auto !important; + width: auto !important; + white-space: nowrap !important; +} + +.x-menu-item-icon-default { + color: var(--tn-subtext0) !important; + order: -1 !important; + position: relative !important; + float: none !important; + margin-right: 8px !important; + margin-left: 0 !important; + left: auto !important; + top: auto !important; + width: 16px !important; + text-align: center !important; + display: inline-flex !important; + align-items: center !important; + justify-content: center !important; + height: 20px !important; + line-height: 20px !important; + vertical-align: middle !important; + flex: 0 0 16px !important; + align-self: center !important; +} + +.x-menu-item-arrow, +.x-menu-item-arrow-default { + order: 2 !important; + margin-left: auto !important; +} + +.x-menu-item-default.x-menu-item-separator { + background-color: var(--tn-surface0) !important; + border: none !important; + height: 1px !important; + margin: 6px 4px !important; +} + +.x-menu-item-default.x-menu-item-focus, +.x-menu-item-default.x-menu-item-active, +.x-menu-item:hover { + background-color: var(--tn-surface0) !important; + color: var(--tn-text) !important; + border-radius: var(--pm-radius-md) !important; +} + +.x-menu-item-active .x-menu-item-text-default, +.x-menu-item-focus .x-menu-item-text-default { + color: var(--tn-text) !important; +} + +.x-menu-item-active .x-menu-item-icon-default, +.x-menu-item-focus .x-menu-item-icon-default { + color: var(--tn-cyan) !important; +} + +/* ===================================================== + PROGRESS BARS + ===================================================== */ + +/* Fix: Widget containers need overflow visible to not clip progress bars */ +.x-container[id^="pmxInfoWidget"], +.x-container.x-box-layout-ct { + overflow: visible !important; +} + +.x-progress, +.x-progress-default { + background-color: var(--tn-surface0) !important; + border-radius: 5px !important; +} + +.x-progress-default .x-progress-bar-default { + background-color: var(--tn-purple) !important; + border-radius: 5px !important; + transition: width 0.4s ease !important; +} + +.x-progress-default .x-progress-text { + color: var(--tn-text) !important; +} + +/* Text overlaid on the progress bar fill — use on-accent for contrast */ +.x-progress-bar .x-progress-text { + color: var(--tn-on-accent) !important; +} + +.x-progress.warning .x-progress-bar { + background-color: var(--tn-yellow) !important; +} + +.x-progress.critical .x-progress-bar { + background-color: var(--tn-red) !important; +} + +/* ===================================================== + TABS — Dracula underline style + Flat tabs with Purple underline on active tab + ===================================================== */ +.x-tab-bar, +.x-tab-bar-default { + background-color: var(--tn-base) !important; + border-radius: 0 !important; + border-bottom: 1px solid var(--tn-surface1) !important; + padding-bottom: 0 !important; +} + +/* Overflow visible for the underline indicator */ +.x-tab-bar .x-box-inner, +.x-tab-bar .x-box-target, +.x-tab-bar-body, +.x-tab-bar-body-default { + overflow: visible !important; +} + +/* Base tab */ +.x-tab, +.x-tab-default, +.x-tab-default-top { + background-color: transparent !important; + border: none !important; + border-radius: var(--pm-radius-md) var(--pm-radius-md) 0 0 !important; + padding: 8px 16px 8px !important; + overflow: visible !important; + margin-bottom: 0 !important; + transition: color 0.15s ease !important; + outline: none !important; + box-shadow: none !important; +} + +/* Remove ::after from inactive tabs */ +.x-tab::after { + display: none !important; +} + +.x-tab-inner-default { + color: var(--tn-subtext0) !important; + font-size: 13px !important; +} + +.x-tab-default.x-tab-over { + background-color: transparent !important; +} + +.x-tab-default.x-tab-over .x-tab-inner-default { + color: var(--tn-text) !important; +} + +/* Active tab */ +.x-tab-default.x-tab.x-tab-active { + background-color: transparent !important; + border: none !important; + overflow: visible !important; + margin-bottom: 0 !important; + outline: none !important; + box-shadow: none !important; +} + +/* Purple underline indicator on active tab */ +.x-tab-default.x-tab.x-tab-active::after { + content: '' !important; + display: block !important; + position: absolute !important; + bottom: 0 !important; + left: 0 !important; + right: 0 !important; + height: 2px !important; + background: var(--tn-purple) !important; + z-index: 10 !important; + border-radius: 2px 2px 0 0 !important; + pointer-events: none !important; +} + +.x-tab-active .x-tab-inner-default { + color: var(--tn-text) !important; + font-weight: 600 !important; +} + +.x-tab-default.x-tab.x-tab-disabled { + background-color: transparent !important; + border: none !important; + color: var(--tn-overlay0) !important; + margin-bottom: 0 !important; +} + +/* Focus states — no outline */ +.x-keyboard-mode .x-tab-default.x-tab-focus, +.x-keyboard-mode .x-tab-default.x-tab-focus.x-tab-active { + background-color: transparent !important; + border: none !important; + outline: none !important; + box-shadow: none !important; + margin-bottom: 0 !important; +} + +.x-keyboard-mode .x-tab-default.x-tab-focus.x-tab-active::after { + content: '' !important; + display: block !important; + position: absolute !important; + bottom: 0 !important; + left: 0 !important; + right: 0 !important; + height: 2px !important; + background: var(--tn-purple) !important; + z-index: 10 !important; + pointer-events: none !important; +} + +/* Kill ALL tab interaction outlines/shadows */ +.x-tab:focus, +.x-tab *:focus, +.x-tab-focus, +.x-tab-active.x-tab-focus, +.x-tab-inner-focus, +.x-tab-button-focus, +.x-tab-pressed, +.x-tab-active.x-tab-pressed, +.x-tab-over, +.x-tab:active, +.x-tab *:active { + outline: none !important; + box-shadow: none !important; +} + +.x-tabpanel-child { + border-radius: 0 0 var(--pm-radius-lg) var(--pm-radius-lg) !important; +} + +/* Tab hover/active corners */ +.x-tab-default.x-tab-over, +.x-tab-default.x-tab.x-tab-active { + border-radius: var(--pm-radius-md) var(--pm-radius-md) 0 0 !important; +} + +/* ===================================================== + TOOLTIPS + ===================================================== */ +.x-tip, +.x-tip-default { + background-color: var(--tn-mantle) !important; + border: 1px solid var(--tn-surface1) !important; + border-radius: var(--pm-radius-md) !important; + box-shadow: 0 4px 12px rgba(30, 31, 41, 0.5); +} + +.x-tip-body-default { + color: var(--tn-text) !important; +} + +.x-tip-form-invalid { + background-color: var(--tn-mantle) !important; + border-color: var(--tn-red) !important; +} + +.x-tip-body-form-invalid { + color: var(--tn-red) !important; +} + +/* ===================================================== + TREE NAVIGATION (Sidebar) + ===================================================== */ +.x-treelist-item { + background-color: var(--tn-base) !important; + border-radius: var(--pm-radius-md) !important; +} + +/* Pseudo-element approach for hover/selected highlighting */ +.x-treelist-row { + border-radius: var(--pm-radius-md) !important; + background-color: transparent !important; + position: relative !important; + z-index: 0 !important; +} + +.x-treelist-row::before { + content: ""; + position: absolute; + top: 1px; + bottom: 1px; + left: 0; + right: 4px; + border-radius: var(--pm-radius-md); + background-color: transparent; + z-index: -1; + pointer-events: none; + transition: background-color 0.15s ease; +} + +/* Fix toolbox tree item text overlapping icons */ +.x-treelist-item-text { + margin-left: 28px !important; +} + +/* Toolbox tree items — bright text */ +.x-treelist-item-text, +.x-treelist-item-icon, +.x-treelist.x-treelist-pve-nav .x-treelist-item-text, +.x-treelist.x-treelist-pve-nav .x-treelist-item-icon { + color: var(--tn-subtext1) !important; +} + +/* Hover state — apply to pseudo-element */ +.x-treelist-row-over { + background-color: transparent !important; +} + +.x-treelist-row-over::before { + background-color: var(--tn-hover-overlay) !important; +} + +.x-treelist-row-over .x-treelist-item-icon, +.x-treelist-row-over .x-treelist-item-text { + background-color: transparent !important; + color: var(--tn-text) !important; +} + +/* Selected/active item — Purple highlight */ +.x-treelist-item-selected > .x-treelist-row { + background-color: transparent !important; +} + +.x-treelist-item-selected > .x-treelist-row::before, +.x-treelist-item-selected > .x-treelist-row:hover::before { + background-color: var(--tn-purple) !important; +} + +.x-treelist-item-selected .x-treelist-item-text, +.x-treelist-item-selected .x-treelist-item-icon, +.x-treelist.x-treelist-pve-nav .x-treelist-item-selected .x-treelist-item-text, +.x-treelist.x-treelist-pve-nav .x-treelist-item-selected .x-treelist-item-icon { + color: var(--tn-on-accent) !important; +} + +.x-treelist-pve-nav { + background-color: var(--tn-base) !important; + border-color: var(--tn-surface1) !important; +} + +/* Tree navigation radius overrides */ +.x-treelist-item, +.x-treelist-item-tool { + border-radius: var(--pm-radius-sm) !important; +} + +.x-treelist-row, +.x-treelist-row:hover, +.x-treelist-row-over, +.x-treelist-item-selected > .x-treelist-row, +.x-treelist-item-selected > .x-treelist-row:hover, +.x-treelist-item-expanded > .x-treelist-row, +.x-treelist-item-expanded > .x-treelist-row-over, +.x-treelist-item-expandable > .x-treelist-row, +.x-treelist-item-expandable > .x-treelist-row-over { + border-radius: var(--pm-radius-sm) !important; +} + +.x-treelist-row::before { + border-radius: var(--pm-radius-sm) !important; +} + +.x-treelist-item-wrap, +.x-treelist-item-text, +.x-treelist-row, +.x-treelist-container, +.x-treelist-root-container, +.x-treelist, +.x-treelist-pve-nav { + border-radius: var(--pm-radius-sm) !important; +} + +/* Cursor pointer for interactive tree/grid items */ +.x-grid-cell, +.x-grid-cell-inner, +.x-tree-elbow-img, +.x-tree-icon, +.x-treelist-item, +.x-treelist-row, +.x-treelist-item-wrap, +.x-treelist-item-text, +.x-treelist-item-icon { + cursor: pointer !important; +} + +/* ===================================================== + WINDOWS / MODALS + ===================================================== */ +.x-window, +.x-window-default { + background-color: var(--tn-crust) !important; + border: 1px solid var(--tn-surface1) !important; + border-radius: var(--pm-radius-lg) !important; + box-shadow: 0 8px 24px rgba(30, 31, 41, 0.6) !important; + overflow: hidden !important; +} + +.x-window .x-window-header, +.x-window-header-default { + background-color: var(--tn-mantle) !important; + border-color: transparent !important; + border-radius: var(--pm-radius-lg) var(--pm-radius-lg) 0 0 !important; +} + +.x-window-header-default .x-mask { + background-color: rgba(30, 31, 41, 0.7); +} + +.x-window .x-window-body, +.x-window-body-default { + background-color: var(--tn-base) !important; + border-color: var(--tn-surface1) !important; + color: var(--tn-text) !important; + border-radius: 0 0 var(--pm-radius-lg) var(--pm-radius-lg) !important; +} + +.x-window-ghost { + background-color: var(--tn-base) !important; +} + +.x-window-header-default .x-tool-img { + background-color: transparent; +} + +.x-message-box .x-window-body { + background-color: var(--tn-mantle) !important; +} + +/* Respect ExtJS inline display:none on hidden dialog buttons */ +.x-message-box .x-btn.x-btn-default-small[style*="display: none"], +.x-message-box .x-btn.x-btn-default-small[style*="display:none"], +.x-window .x-toolbar-footer .x-btn[style*="display: none"], +.x-window .x-toolbar-footer .x-btn[style*="display:none"] { + display: none !important; +} + +/* Login dialog — clean inner panel borders */ +.x-window:has(#pveloginrealm) .x-panel-body { + border: none !important; + background: transparent !important; + width: auto !important; +} + +/* ===================================================== + CONSOLE / TERMINAL + ===================================================== */ +div.monitor { + border-color: var(--tn-surface1); +} + +.install-mask { + background-color: var(--tn-crust); + color: var(--tn-subtext0); +} + +.x-window.install-mask { + box-shadow: rgba(30, 31, 41, 0.5) 0 4px 20px !important; +} + +/* ===================================================== + LEGEND / CHARTS + ===================================================== */ +.x-legend-container { + background-color: var(--tn-base) !important; +} + +.x-legend-horizontal .x-legend-item { + background-color: var(--tn-mantle) !important; + color: var(--tn-text) !important; + border: 1px solid var(--tn-surface0) !important; +} + +/* Chart/RRD panel backgrounds */ +div[id*="rrdchart"], +.pve-rrddatastore, +.pmx-panel-rrd { + background-color: var(--tn-base) !important; +} + +.proxmox-rrd-panel canvas, +.proxmox-widget-toolkit canvas, +canvas.x-surface, +.x-surface canvas { + background-color: transparent !important; + opacity: 1 !important; +} + +.proxmox-rrd-panel, +.proxmox-rrd-chart { + background-color: var(--tn-base) !important; +} + +/* Chart text/labels */ +.x-surface text, +svg text { + fill: var(--tn-text) !important; +} + +/* ===================================================== + PROXMOX-SPECIFIC OVERRIDES + ===================================================== */ + +/* Logo inversion */ +img[id^="proxmoxlogo-"][id$="-img"], +img[id^="proxmoxLogoSvg-"][id$="-img"] { + filter: invert(1) hue-rotate(180deg); +} + +/* Invalid/warning/disabled rows */ +.proxmox-invalid-row { + background-color: rgba(255, 85, 85, 0.15) !important; +} + +.proxmox-warning-row { + background-color: rgba(255, 184, 108, 0.15) !important; +} + +.proxmox-disabled-row td { + color: var(--tn-overlay0) !important; +} + +/* Hints */ +.pmx-hint { + background-color: rgba(255, 184, 108, 0.15) !important; + white-space: nowrap !important; +} + +.pmx-hint a { + color: var(--tn-cyan) !important; +} + +/* Status text colors — Information → Cyan */ +.info-blue { + color: var(--tn-cyan) !important; +} + +.critical { + color: var(--tn-red) !important; +} + +/* Links */ +a { + color: var(--tn-cyan) !important; +} + +/* Markdown content */ +.pmx-md code { + background-color: var(--tn-mantle) !important; + color: var(--tn-pink) !important; + border-radius: var(--pm-radius-sm) !important; +} + +.pmx-md pre code { + border-color: var(--tn-surface1) !important; + background-color: var(--tn-crust) !important; +} + +.pmx-md a { + color: var(--tn-cyan) !important; +} + +.pmx-md table { + border-color: var(--tn-surface1) !important; +} + +.pmx-md th { + background-color: var(--tn-mantle) !important; + border-color: var(--tn-surface1) !important; +} + +.pmx-md td { + border-color: var(--tn-surface1) !important; +} + +/* APT repos */ +.proxmox-apt-repos .x-grid-group-hd { + background-color: var(--tn-base) !important; + border: none !important; +} + +.proxmox-apt-repos .x-grid-group-title { + color: var(--tn-text) !important; +} + +/* Tags */ +.pve-edit-tag { + border-radius: var(--pm-radius-md) !important; +} + +.pve-edit-tag.editable span { + background-color: var(--tn-mantle) !important; + color: var(--tn-text) !important; + border-color: var(--tn-surface1) !important; +} + +.x-tree-node-text .proxmox-tag-dark, +.x-tree-node-text .proxmox-tag-light, +.x-grid-cell-inner .proxmox-tag-dark, +.x-grid-cell-inner .proxmox-tag-light, +span.proxmox-tag-dark, +span.proxmox-tag-light { + border-radius: var(--pm-radius-md) !important; +} + +/* Checkmark button in tag edit — match toolbar button size */ +.x-btn.x-btn-default-small:has(.fa-check) { + min-height: 24px !important; + height: 24px !important; + padding: 3px 8px !important; + border-radius: var(--pm-radius-sm) !important; + background-color: var(--tn-purple) !important; + border: none !important; +} + +.x-btn.x-btn-default-small:has(.fa-check).x-btn-disabled { + background-color: transparent !important; + border: 1px solid var(--tn-surface1) !important; + opacity: 0.5 !important; +} + +.x-btn.x-btn-default-small:has(.fa-check) .fa-check { + color: var(--tn-on-accent) !important; +} + +.x-btn.x-btn-default-small:has(.fa-check).x-btn-disabled .fa-check { + color: var(--tn-overlay1) !important; +} + +.x-btn.x-btn-default-small:has(.fa-check):not(.x-btn-disabled):hover { + background-color: #caa9fa !important; +} + +.x-btn.x-btn-default-small:has(.fa-check) .x-btn-inner { + display: none !important; +} + +/* Date picker */ +.x-datepicker, +.x-datepicker-column-header, +.x-monthpicker { + background-color: var(--tn-base) !important; + color: var(--tn-text) !important; + border-color: transparent !important; +} + +.x-datepicker-header, +.x-datepicker-footer, +.x-monthpicker-buttons { + background-color: var(--tn-mantle) !important; +} + +.x-datepicker-date, +.x-monthpicker-item-inner { + color: var(--tn-text) !important; +} + +.x-datepicker-selected div.x-datepicker-date, +.x-monthpicker-item a.x-monthpicker-selected, +a.x-monthpicker-item-inner:hover, +div.x-datepicker-date:hover { + background-color: var(--tn-hover-overlay) !important; + color: var(--tn-text) !important; +} + +.x-datepicker-today .x-datepicker-date { + border-color: var(--tn-purple) !important; +} + +.x-datepicker-disabled .x-datepicker-date { + color: var(--tn-overlay0) !important; +} + +.x-datepicker-prev-day .x-datepicker-date, +.x-datepicker-next-day .x-datepicker-date { + color: var(--tn-overlay0) !important; +} + +/* Usage bars */ +.usage-wrapper, +.usage { + border-radius: 2px !important; +} + +.usage { + background-color: var(--tn-overlay2) !important; +} + +/* ===================================================== + SCROLLBARS + ===================================================== */ +::-webkit-scrollbar { + width: 8px; + height: 8px; +} + +::-webkit-scrollbar-track { + background: var(--tn-base); + border-radius: var(--pm-radius-sm); +} + +::-webkit-scrollbar-thumb { + background: var(--tn-surface2); + border-radius: var(--pm-radius-sm); + border: 1px solid transparent; + background-clip: padding-box; + transition: background 0.15s ease; +} + +::-webkit-scrollbar-thumb:hover { + background: var(--tn-overlay0); +} + +::-webkit-scrollbar-corner { + background: var(--tn-base); +} + +/* Firefox scrollbar */ +* { + scrollbar-width: thin; + scrollbar-color: var(--tn-surface2) var(--tn-base); +} + +/* ===================================================== + SELECTION HIGHLIGHT + ===================================================== */ +::selection { + background-color: rgba(98, 114, 164, 0.3); + color: var(--tn-text); +} + +/* ===================================================== + TRANSITIONS (smooth interactions) + ===================================================== */ + +/* Grid row transitions */ +.x-grid-item { + transition: background-color 0.15s ease !important; +} + +/* Tree pseudo-element transitions */ +.x-treelist-row::before { + transition: background-color 0.15s ease !important; +} + +/* Menu item transitions */ +.x-menu-item-default > .x-menu-item-link { + transition: background-color 0.12s ease !important; +} + +/* Boundlist item transitions */ +.x-boundlist-item { + transition: background-color 0.12s ease !important; +} + +/* Tab transitions */ +.x-tab { + transition: color 0.15s ease !important; +} + +/* Splitter transition */ +.x-splitter { + transition: background-color 0.15s ease !important; +} + +/* Tooltip transition */ +.x-tip { + transition: opacity 0.15s ease !important; +} + +/* Progress bar width transition */ +.x-progress-bar { + transition: width 0.4s ease !important; +} + +/* Scrollbar thumb transition */ +::-webkit-scrollbar-thumb { + transition: background 0.15s ease !important; +} + +/* Window close tool transition */ +.x-tool-img { + transition: filter 0.15s ease !important; +} +/* ===================================================== + TOOL ICONS - FontAwesome Replacements + (Ported from UniFi v5.86) + Replace sprite-based ExtJS tool icons with crisp + FontAwesome icons for better consistency and clarity + ===================================================== */ + +/* Base styling for all tool icons - remove sprite backgrounds */ +.x-tool-tool-el.x-tool-minus, +.x-tool-img.x-tool-minus, +.x-tool-tool-el.x-tool-collapse-right, +.x-tool-img.x-tool-collapse-right, +.x-tool-tool-el.x-tool-collapse-left, +.x-tool-img.x-tool-collapse-left, +.x-tool-tool-el.x-tool-expand-right, +.x-tool-img.x-tool-expand-right, +.x-tool-tool-el.x-tool-expand-left, +.x-tool-img.x-tool-expand-left, +.x-tool-tool-el.x-tool-maximize, +.x-tool-img.x-tool-maximize, +.x-tool-tool-el.x-tool-restore, +.x-tool-img.x-tool-restore, +.x-tool-tool-el.x-tool-gear, +.x-tool-img.x-tool-gear, +.x-tool-tool-el.x-tool-refresh, +.x-tool-img.x-tool-refresh, +.x-tool-tool-el.x-tool-close, +.x-tool-img.x-tool-close { + background-image: none !important; + font-family: "FontAwesome" !important; + font-size: 14px !important; + line-height: 16px !important; + text-align: center !important; + color: var(--pm-text-dim) !important; + transition: color 0.15s ease !important; + filter: none !important; + width: 16px !important; + height: 16px !important; + display: flex !important; + align-items: center !important; + justify-content: center !important; +} + +/* Close button - slightly larger */ +.x-tool-tool-el.x-tool-close, +.x-tool-img.x-tool-close { + font-size: 20px !important; +} + +/* Individual glyph assignments */ +.x-tool-tool-el.x-tool-minus::before, +.x-tool-img.x-tool-minus::before { + content: "\f010" !important; /* fa-search-minus (zoom out) */ +} + +.x-tool-tool-el.x-tool-collapse-right::before, +.x-tool-img.x-tool-collapse-right::before { + content: "\f054" !important; /* fa-chevron-right */ +} + +.x-tool-tool-el.x-tool-expand-left::before, +.x-tool-img.x-tool-expand-left::before { + content: "\f053" !important; /* fa-chevron-left */ +} + +.x-tool-tool-el.x-tool-collapse-left::before, +.x-tool-img.x-tool-collapse-left::before { + content: "\f053" !important; /* fa-chevron-left */ +} + +.x-tool-tool-el.x-tool-expand-right::before, +.x-tool-img.x-tool-expand-right::before { + content: "\f054" !important; /* fa-chevron-right */ +} + +.x-tool-tool-el.x-tool-maximize::before, +.x-tool-img.x-tool-maximize::before { + content: "\f065" !important; /* fa-expand */ +} + +.x-tool-tool-el.x-tool-restore::before, +.x-tool-img.x-tool-restore::before { + content: "\f066" !important; /* fa-compress */ +} + +.x-tool-tool-el.x-tool-gear::before, +.x-tool-img.x-tool-gear::before { + content: "\f013" !important; /* fa-cog */ +} + +.x-tool-tool-el.x-tool-refresh::before, +.x-tool-img.x-tool-refresh::before { + content: "\f021" !important; /* fa-refresh */ +} + +.x-tool-tool-el.x-tool-close::before, +.x-tool-img.x-tool-close::before { + content: "\f00d" !important; /* fa-times */ +} + +/* Hover state - all tool icons */ +.x-tool:hover .x-tool-tool-el.x-tool-minus, +.x-tool:hover .x-tool-img.x-tool-minus, +.x-tool:hover .x-tool-tool-el.x-tool-collapse-right, +.x-tool:hover .x-tool-img.x-tool-collapse-right, +.x-tool:hover .x-tool-tool-el.x-tool-collapse-left, +.x-tool:hover .x-tool-img.x-tool-collapse-left, +.x-tool:hover .x-tool-tool-el.x-tool-expand-right, +.x-tool:hover .x-tool-img.x-tool-expand-right, +.x-tool:hover .x-tool-tool-el.x-tool-expand-left, +.x-tool:hover .x-tool-img.x-tool-expand-left, +.x-tool:hover .x-tool-tool-el.x-tool-maximize, +.x-tool:hover .x-tool-img.x-tool-maximize, +.x-tool:hover .x-tool-tool-el.x-tool-restore, +.x-tool:hover .x-tool-img.x-tool-restore, +.x-tool:hover .x-tool-tool-el.x-tool-gear, +.x-tool:hover .x-tool-img.x-tool-gear, +.x-tool:hover .x-tool-tool-el.x-tool-refresh, +.x-tool:hover .x-tool-img.x-tool-refresh, +.x-tool:hover .x-tool-tool-el.x-tool-close, +.x-tool:hover .x-tool-img.x-tool-close { + color: var(--pm-text) !important; +} + +/* Disabled state */ +.x-tool-disabled .x-tool-tool-el, +.x-tool-disabled .x-tool-img { + opacity: 0.4 !important; + cursor: default !important; +} + +/* Inline FontAwesome tools (PVE-injected) */ +.x-tool-tool-el[style*="font-family:FontAwesome"], +.x-tool-tool-el[style*="font-family: FontAwesome"] { + color: var(--pm-text-dim) !important; + font-size: 14px !important; + line-height: 16px !important; + display: flex !important; + align-items: center !important; + justify-content: center !important; + width: 16px !important; + height: 16px !important; + transition: color 0.15s ease !important; + background-image: none !important; + background-color: transparent !important; +} + +.x-tool:not(.x-tool-disabled) .x-tool-tool-el[style*="font-family:FontAwesome"], +.x-tool:not(.x-tool-disabled) .x-tool-tool-el[style*="font-family: FontAwesome"] { + cursor: pointer !important; +} + +.x-tool.x-tool-disabled .x-tool-tool-el[style*="font-family:FontAwesome"], +.x-tool.x-tool-disabled .x-tool-tool-el[style*="font-family: FontAwesome"] { + cursor: default !important; + opacity: 0.4 !important; +} + +.x-tool .x-mask { + background-color: transparent !important; + backdrop-filter: none !important; + pointer-events: none !important; +} + +.x-tool:not(.x-tool-disabled):hover .x-tool-tool-el[style*="font-family:FontAwesome"], +.x-tool:not(.x-tool-disabled):hover .x-tool-tool-el[style*="font-family: FontAwesome"] { + color: var(--pm-text) !important; +} diff --git a/themes/theme-unifi-light.css b/themes/theme-unifi-light.css new file mode 100644 index 0000000..d8e3611 --- /dev/null +++ b/themes/theme-unifi-light.css @@ -0,0 +1,3913 @@ +/*!UniFi Light*/ +/* + * ProxMorph Theme: UniFi Light + * Light variant of the UniFi Network Application theme + * Version: 5.94 + * Author: OiCkilL / N.E.S.T. / Dr. Dranglog + * + * UniFi Color Palette (extracted from live instance): + * + * BACKGROUNDS: + * - Base/Body: #FFFFFF (rgb 255,255,255) - main light background + * - Header: #F6F6F8 (rgb 246,246,248) - top navigation bar + * - Hover solid: #ECEDF0 (rgb 236,237,240) - button hover + * - Hover subtle: rgba(0, 0, 0, 0.03) - row hover + * - Hover medium: rgba(0, 0, 0, 0.05) - tertiary hover + * - Hover strong: rgba(0, 0, 0, 0.08) - input hover + * + * TEXT COLORS: + * - Primary: #1A1C21 (rgb 26,28,33) - main text + * - Secondary: #585C66 (rgb 88,92,102) - labels + * - Bright: #111217 (rgb 17,18,23) - headings/emphasis + * - Muted: rgba(0, 0, 0, 0.65) - sidebar text + * - Tertiary: #A0A3AB (rgb 160,163,171) - disabled/hints + * + * ACCENT COLORS: + * - Primary Blue: #006EFF - links, active states + * - Blue Hover: #4797FF (rgb 71,151,255) + * - Success: #37BE5F (rgb 55,190,95) + * - Warning: #f5a623 + * - Danger: #f03a3e + * + * CSS VARIABLES (official Ubiquiti): + * - --ubnt-color-DN60: #151725 (darkest neutral) + * - --ubnt-color-DN50: #242635 (card background) + * - --ubnt-color-primary: #006fff + */ + +/* ===================================================== + CSS VARIABLES + ===================================================== */ +:root { + /* UniFi design tokens (only the ones actually used) */ + --ubnt-color-primary: #006fff; + --ubnt-color-danger: #f03a3e; + --ubnt-color-warning: #f5a623; + --ubnt-color-success: #39cc64; + + /* ProxMorph semantic variables */ + --pm-accent: #006EFF; + --pm-accent-hover: #4797FF; + --pm-accent-active: #0058cc; + + --pm-success: #37BE5F; + --pm-warning: var(--ubnt-color-warning); + --pm-error: var(--ubnt-color-danger); + + /* Base palette tuned to Proxmox UI (keeps existing theme look) */ + --pm-bg-base: #FFFFFF; + --pm-bg-surface: #F6F6F8; + --pm-bg-elevated: #ECEDF0; + + --pm-border: #DDDDE0; + --pm-border-strong: #C8C9CC; + + --pm-text: #1A1C21; + --pm-text-dim: #585C66; + --pm-text-muted: #585C66; + --pm-text-disabled: #A0A3AB; + --pm-text-bright: #111217; + + --pm-hover-subtle: rgba(0, 0, 0, 0.03); + --pm-hover-medium: rgba(0, 0, 0, 0.05); + --pm-hover-strong: rgba(0, 0, 0, 0.08); + + --pm-radius-sm: 4px; + --pm-radius-md: 6px; + --pm-radius-lg: 8px; + --pm-radius-xl: 12px; + + --pm-focus-ring-color: rgba(0, 111, 255, 0.20); + + /* Proxmox widget toolkit variables */ + --pwt-panel-background: var(--pm-bg-base); + --pwt-text-color: var(--pm-text-dim); + --pwt-gauge-default: var(--pm-accent-hover); + --pwt-gauge-back: var(--pm-bg-elevated); + --pwt-gauge-warn: var(--pm-warning); + --pwt-gauge-crit: var(--pm-error); + --pwt-chart-primary: var(--pm-success); + --pwt-chart-grid-stroke: var(--pm-border); + + color-scheme: light; +} + +/* ===================================================== + GLOBAL BORDER-BOX ROUNDED CORNERS (UniFi style) + ===================================================== */ +.x-border-box, +.x-border-box * { + border-radius: var(--pm-radius-lg); +} + +/* Remove rounded corners from grids/tables/lists (Tasks, logs) */ +.x-grid, +.x-grid *, +.x-grid-header-ct, +.x-grid-header-ct *, +.x-grid-view, +.x-grid-view *, +.x-column-header, +.x-column-header *, +.x-grid-item, +.x-grid-cell, +.x-grid-cell-inner, +.x-grid-row, +table, +table *, +tr, +td, +th, +/* Legend elements - no rounded corners */ +.x-legend, +.x-legend *, +.x-legend-container, +.x-legend-container *, +.x-legend-item, +.x-legend-horizontal .x-legend-item, +.x-legend-vertical .x-legend-item, +.x-legend-horizontal .x-legend-item:first-child, +.x-legend-horizontal .x-legend-item:last-child, +.x-legend-vertical .x-legend-item:first-child, +.x-legend-vertical .x-legend-item:last-child, +/* Tool icons - no rounded corners */ +.x-tool, +.x-tool-tool-el, +.x-tool-default, +.x-tool-img { + border-radius: 0 !important; +} + +/* Form elements - exclude from global 8px, apply 4px (UniFi style) */ +/* Reset ALL form-related parent containers to prevent 8px inheritance */ +.x-form-item, +.x-form-item-default, +.x-form-item-body, +.x-form-item-body-default, +.x-form-text-field-body, +.x-form-text-field-body-default, +.x-form-fieldcontainer, +.x-field, +.x-field-default, +.x-form-type-text { + border-radius: 0 !important; +} + +/* Reset layout containers that clip form elements with overflow:hidden + 8px radius */ +.x-box-layout-ct, +.x-panel-bodyWrap, +.x-panel-bodyWrap-default, +.x-autocontainer-innerCt, +.x-autocontainer-outerCt, +.x-panel.x-tabpanel-child, +.x-panel.x-box-item, +.x-box-inner, +.x-box-target, +.x-container, +.x-container-default, +/* Window/dialog inner bodies - prevent 8px clipping on form elements */ +.x-window .x-panel-body, +.x-window .x-window-body, +.x-window .x-window-bodyWrap { + border-radius: 0 !important; +} + +/* Restore right border for grids inside windows (fixed v5.4 over-reach) */ +.x-window .x-panel-body.x-grid-body { + border-right: 1px solid #DDDDE0 !important; +} + +/* ===================================================== + v5.73: WINDOW/MODAL BORDER-RADIUS CONSISTENCY + Reset all children to 0, then re-apply specific radii + to ensure consistent 8px corners on login/modals + ===================================================== */ + +/* 1. Reset everything inside windows to 0 - overrides global x-border-box rule */ +.x-window *, +.x-window .x-autocontainer-innerCt, +.x-window .x-autocontainer-outerCt, +.x-window .x-form-layout-wrap, +.x-window .x-form-layout-auto-label, +.x-window .x-form-layout-colgroup, +.x-window .x-form-layout-column, +.x-window .x-field, +.x-window .x-form-item, +.x-window .x-form-item-body { + border-radius: 0 !important; +} + +/* 2. Window container - consistent 8px with overflow hidden */ +.x-window { + border-radius: 8px !important; + overflow: hidden !important; + min-width: 295px !important; + /* v5.85: Match Proxmox default to prevent scrollbars */ +} + +/* v5.86: Fix dialog header/body not matching dialog width when min-width is applied + Root cause: ExtJS sets inline width on header/body that's smaller than min-width forces. + Solution: Force header/body to use 100% width so they inherit parent's computed width. */ +.x-window > .x-window-header, +.x-window > .x-window-body, +.x-window > .x-window-bodyWrap, +.x-window-bodyWrap > .x-window-body { + width: 100% !important; +} + +/* Ensure box containers inside header use full width */ +.x-window-header > .x-box-inner, +.x-window-header > .x-box-inner > .x-box-target { + width: 100% !important; +} + +/* Header title should expand appropriately */ +.x-window-header-title { + width: auto !important; + flex: 1 !important; + max-width: calc(100% - 30px) !important; +} + +/* 3. Window header - top corners only */ +.x-window-header, +.x-window-header-default { + border-radius: 8px 8px 0 0 !important; +} + +/* 4. Re-apply button styling inside windows (6px) */ +.x-window .x-btn { + border-radius: 6px !important; +} + +/* 5. Re-apply checkbox styling inside windows (4px) */ +.x-window .x-form-checkbox { + border-radius: 4px !important; +} + +/* 6. Re-apply form inputs inside windows (4px with split corners) */ +.x-window .x-form-trigger-wrap, +.x-window .x-form-trigger-wrap-default { + border-radius: 4px !important; +} + +.x-window .x-form-text-wrap, +.x-window .x-form-text { + border-radius: 4px 0 0 4px !important; +} + +.x-window .x-form-arrow-trigger { + border-radius: 0 4px 4px 0 !important; +} + +.x-form-trigger-wrap, +.x-form-trigger-wrap *, +.x-form-text-wrap, +.x-form-text-wrap *, +.x-form-text, +.x-form-trigger { + border-radius: 0 !important; +} + +/* Form element containers - 4px radius (UniFi consistent) */ +.x-form-trigger-wrap, +.x-form-trigger-wrap-default { + border-radius: 4px !important; + overflow: hidden !important; +} + +/* Constrain autocontainer width (Moved from L3450) */ +.x-window .x-autocontainer-outerCt { + max-width: 100% !important; +} + +/* Form text wrap - left side rounded */ +.x-form-text-wrap, +.x-form-text-wrap-default { + border-radius: 4px 0 0 4px !important; +} + +/* Form input text - left side rounded */ +.x-form-text, +.x-form-text-default { + border-radius: 4px 0 0 4px !important; +} + +/* Form trigger button - right side rounded */ +.x-form-trigger, +.x-form-trigger-default, +.x-form-arrow-trigger, +.x-form-arrow-trigger-default { + border-radius: 0 4px 4px 0 !important; +} + +/* Cursor styles for combobox/dropdown elements (pointer indicates clickable) */ +.x-form-trigger-wrap, +.x-form-text-wrap, +.x-form-field[role="combobox"], +input.x-form-text[readonly], +.x-form-trigger, +.x-form-arrow-trigger { + cursor: pointer !important; +} + +/* Cursor for dropdown list items */ +.x-boundlist-item, +.x-boundlist-item-over, +.x-boundlist-selected { + cursor: pointer !important; +} + +/* ===================================================== + BASE / BODY - Authentic UniFi light background + ===================================================== */ +.x-body { + color: var(--pm-text); + background-color: var(--pm-bg-base); +} + +.x-viewport>.x-body { + background-color: var(--pm-bg-base); +} + +body.x-border-layout-ct, +div.x-border-layout-ct { + background-color: var(--pm-bg-base); +} + +/* ===================================================== + LEGEND / CHARTS - Ensure chart visibility + ===================================================== */ +.x-legend-container { + background-color: var(--pm-bg-base); + border-radius: 0 !important; +} + +.x-legend-horizontal .x-legend-item, +.x-legend-item { + background-color: var(--pm-bg-base); + color: var(--pm-text-muted); + border: none !important; + border-radius: 0 !important; +} + +/* Legend color marker (dot) - keep circular */ +.x-legend-item-marker { + border-radius: 50% !important; +} + +/* Chart canvas and SVG visibility */ +.x-chart, +.rrd-chart canvas, +canvas.x-surface { + opacity: 1 !important; +} + +/* Chart grid lines */ +.x-chart-grid-horizontal line, +.x-chart-grid-vertical line { + stroke: #DDDDE0 !important; + stroke-opacity: 1 !important; +} + +/* Chart axis text */ +.x-chart-axis-label { + fill: #585C66 !important; +} + +/* RRDTool charts (Proxmox specific) - ensure PNG charts are visible */ +img.rrdimage, +.rrd-chart img, +div[class*="rrd"] img { + filter: none !important; + opacity: 1 !important; +} + +/* ===================================================== + MASKS & OVERLAYS + ===================================================== */ +.x-mask { + /* v5.48: Background blur + 0.5 opacity */ + backdrop-filter: blur(4px) !important; + -webkit-backdrop-filter: blur(4px) !important; + background-color: rgba(0, 0, 0, 0.3) !important; +} + +/* Disabled field-groups: keep the native "reduced opacity" look (no black mask overlay) */ +.x-item-disabled.x-masked-relative>.x-mask { + background-color: transparent !important; +} + +.x-tool .x-mask { + backdrop-filter: blur(4px); + background-color: #FFFFFF; + opacity: 0.6; +} + +/* v5.50: Hide ExtJS shadow element - use pure CSS shadow on window instead */ +.x-css-shadow { + display: none !important; +} + +/* ===================================================== + ICONS - Native colors for light mode (no inversion needed) + ===================================================== */ +/* General icons - gray color */ +.fa-tags::before, +.fa-file-o::before, +.fa-building::before, +.x-action-col-icon::before, +.fa-shield::before, +.fa-file-text-o::before, +.fa-clock-o::before, +.x-tab-icon-el-default, +.pve-icon-verify-lettering::after, +.x-tree-icon-custom.lock-migrate::after, +.x-grid-icon-custom.lock-migrate::after, +.x-tree-icon-leaf:not(.x-tree-icon-custom)::before, +.x-tree-icon-parent:not(.x-tree-icon-custom)::before, +.x-tree-icon-parent-expanded:not(.x-tree-icon-custom)::before, +.x-grid-filters-filtered-column .x-column-header-text::after { + color: #585C66; +} + +/* VM/CT icons - default gray, NOT green */ +.x-tree-icon-custom, +.x-grid-icon-custom { + color: #585C66; +} + +.x-tree-icon-parent:not(.x-tree-icon-custom)::before, +.x-tree-icon-parent-expanded:not(.x-tree-icon-custom)::before { + filter: none; +} + +.fa-ceph::before, +.fa-sdn::before, +.fa-network-wired::before, +.pve-itype-treelist-item-icon-cdrom, +.fa-chevron-right::before, +.x-grid-row-console, +.x-box-scroller-toolbar-default.x-box-scroller, +.x-tree-elbow-img, +.pve-itype-icon-qemu, +.x-tree-node-computer, +.x-grid-tree-node-expanded .x-tree-node-computer, +.pbs-icon-tape, +.pbs-icon-tape-drive, +.x-tree-icon-leaf:not(.x-tree-icon-custom), +.x-tree-icon-parent:not(.x-tree-icon-custom), +.x-tree-icon-parent-expanded:not(.x-tree-icon-custom) { + filter: none; +} + +/* v5.37: Resource grid icon inversion - exclude cells that contain text + The filter on TD cells was inverting both icons AND text, causing dark gray labels. + Solution: Remove filter from cells, apply via ::before pseudo-element to icon only */ +.pve-itype-icon-cpu, +.pve-itype-icon-cdrom, +.pve-itype-icon-memory, +.pve-itype-icon-pci, +.pve-itype-icon-serial, +.pve-itype-icon-die, +.x-tree-node-harddisk, +.x-grid-tree-node-expanded .x-tree-node-harddisk { + filter: none; +} + +/* v5.37: Resource grid cells (td elements) - isolate filter to icons only */ +td.pmx-itype-icon-processor, +td.pmx-itype-icon-memory, +td.pve-itype-icon-storage { + filter: none !important; + background-image: none !important; + position: relative !important; + padding-left: 26px !important; +} + +/* Pseudo-element icons with filter applied only to the icon (td cells only) */ +td.pmx-itype-icon-processor::before, +td.pmx-itype-icon-memory::before, +td.pve-itype-icon-storage::before { + content: '' !important; + position: absolute !important; + left: 6px !important; + top: 50% !important; + transform: translateY(-50%) !important; + width: 16px !important; + height: 16px !important; + background-size: contain !important; + background-repeat: no-repeat !important; + background-position: center !important; + filter: none !important; +} + +td.pmx-itype-icon-processor::before { + background-image: url('/pve2/images/icon-cpu.svg') !important; +} + +td.pmx-itype-icon-memory::before { + background-image: url('/pwt/images/icon-ram.svg') !important; +} + +td.pve-itype-icon-storage::before { + background-image: url('/pve2/images/icon-harddisk.svg') !important; +} + +/* v5.38: Summary panel icons (i elements) - reset to original Proxmox styling */ +i.pmx-itype-icon-processor, +i.pmx-itype-icon-memory, +.pmx-icon.pmx-itype-icon-processor, +.pmx-icon.pmx-itype-icon-memory { + filter: none !important; + background-repeat: no-repeat !important; + background-position: 3px center !important; + background-size: 14px 14px !important; + padding-left: 18px !important; + position: static !important; +} + +/* v5.94: Use relative paths for PVE+PBS compatibility + PVE serves from /pwt/themes/ → ../images/ resolves to /pwt/images/ + PBS serves from /widgettoolkit/themes/ → ../images/ resolves to /widgettoolkit/images/ */ +i.pmx-itype-icon-processor, +.pmx-icon.pmx-itype-icon-processor { + background-image: url('../images/icon-cpu.svg') !important; +} + +i.pmx-itype-icon-memory, +.pmx-icon.pmx-itype-icon-memory { + background-image: url('../images/icon-ram.svg') !important; +} + +/* Disable ::before pseudo-elements on Summary panel icons */ +i.pmx-itype-icon-processor::before, +i.pmx-itype-icon-memory::before, +.pmx-icon.pmx-itype-icon-processor::before, +.pmx-icon.pmx-itype-icon-memory::before { + content: none !important; + display: none !important; +} + +/* v5.38: Summary panel SWAP and Bootdisk FontAwesome icons - consistent sizing */ +.left-aligned .fa.fa-refresh, +.left-aligned .fa.fa-hdd-o { + font-size: 14px !important; +} + +/* v5.88: Fix "More" button position in IPs section of Summary panel + Move button next to "IPs" label, vertically centered with IP addresses. + Parent containers need overflow:visible because transform moves button outside bounds. + + Key insight: ExtJS positions button at container's right edge (after IP addresses). + Solution: Anchor to top: 0, then use transform to shift button left to "IPs" label. + Value -242px moves button from right edge to just after the 35px "IPs" label. + NOTE: This value may need adjustment if Proxmox UI layout changes. */ +[id^="pveIPViewLXC-"] .x-box-inner, +[id^="pveIPViewLXC-"] > .x-box-inner { + overflow: visible !important; +} + +[id^="pveIPViewLXC-"] [id^="button-"].x-btn { + top: 0 !important; + transform: translate(-242px, 5px) !important; +} + +/* Cell inner content alignment */ +.pmx-itype-icon-processor .x-grid-cell-inner, +.pmx-itype-icon-memory .x-grid-cell-inner, +.pve-itype-icon-storage .x-grid-cell-inner { + padding-left: 0 !important; +} + +/* v5.37: FontAwesome icons in resource grid (Swap, Root Disk) */ +.pve-itype-fa .x-grid-cell-inner { + padding-left: 4px !important; +} + +.pve-itype-fa .pve-grid-fa, +.pve-itype-fa .pve-grid-fa.fa, +.x-grid-item .pve-itype-fa .fa { + color: #1A1C21 !important; + margin-right: 4px !important; +} + +.x-tree-icon-custom, +.x-grid-icon-custom { + color: #585C66; +} + +/* Running VMs/CTs - type icon neutral; status indicator handled separately */ +.x-tree-icon-custom.running, +.x-grid-icon-custom.running { + color: #585C66; +} + +.x-tree-icon-custom::after, +.x-grid-icon-custom::after { + color: #585C66; + text-shadow: none; +} + +.x-tree-icon-custom.stopped, +.x-tree-icon-custom.offline, +.x-grid-icon-custom.stopped, +.x-grid-icon-custom.offline { + color: #A0A3AB; +} + +.x-tree-icon-custom.lxc::after, +.x-tree-icon-custom.qemu::after, +.x-grid-icon-custom.lxc::after, +.x-grid-icon-custom.qemu::after { + background-color: #FFFFFF; + color: #585C66; +} + +/* v5.55: Fix LXC/QEMU icon ::after in treelist navigation */ +.x-treelist-item-icon.lxc::after, +.x-treelist-item-icon.qemu::after { + background-color: transparent !important; + color: #585C66 !important; + margin-top: 4px !important; +} + +.x-tree-arrows .x-tree-expander { + filter: brightness(80%); +} + +/* ===================================================== + v5.6: Custom tree expander arrows (FontAwesome chevrons) + Replaces default sprite arrows with larger, animated icons + ===================================================== */ + +/* Base expander styling - replace sprite with FA icon */ +.x-tree-expander { + background-image: none !important; + position: relative !important; + width: 18px !important; + height: 18px !important; + margin-right: 4px !important; + vertical-align: middle !important; +} + +/* Arrow icon using FontAwesome chevron-right */ +.x-tree-expander::before { + content: "\f054" !important; + /* FA chevron-right */ + font-family: "FontAwesome" !important; + font-size: 11px !important; + color: #A0A3AB !important; + /* UniFi tertiary/muted color */ + position: absolute !important; + top: -2px !important; + left: 3px !important; + transition: transform 0.2s ease, color 0.15s ease !important; +} + +/* Expanded state - arrow rotates 90 degrees */ +.x-grid-tree-node-expanded .x-tree-expander::before { + transform: rotate(90deg) !important; + color: #585C66 !important; + /* UniFi secondary text */ +} + +/* Collapsed state - no rotation */ +tr:not(.x-grid-tree-node-expanded) .x-tree-expander::before { + transform: rotate(0deg) !important; +} + +/* Hover effect - UniFi blue accent */ +.x-tree-expander:hover::before { + color: #006EFF !important; +} + +/* Gap before node icon */ +.x-tree-icon-parent, +.x-tree-icon-leaf, +.x-tree-icon { + margin-left: 2px !important; +} + +/* Empty elbows - no extra margin */ +.x-tree-elbow-empty, +.x-tree-elbow { + margin-right: 0 !important; +} + +/* ===================================================== + v5.36: CHECKBOXES & RADIO BUTTONS - UniFi Authentic + Extracted from live UniFi Network Application + ===================================================== */ + +/* Remove the old filter-based styling */ +.x-form-checkbox-default, +.x-form-radio-default, +.x-column-header-checkbox .x-column-header-checkbox::after, +.x-grid-checkcolumn::after, +.x-menu-item-checked .x-menu-item-icon-default.x-menu-item-checkbox, +.x-menu-item-unchecked .x-menu-item-icon-default.x-menu-item-checkbox { + filter: none !important; +} + +/* The actual INPUT element that receives clicks - needs pointer cursor */ +.x-form-cb-input { + cursor: pointer !important; +} + +/* CHECKBOXES - Base styling (SPAN element - visual display) */ +.x-form-checkbox, +.x-form-checkbox-default { + display: inline-block !important; + width: 16px !important; + min-width: 16px !important; + height: 16px !important; + min-height: 16px !important; + border-radius: 4px !important; + border: 0.8px solid #B0B3BA !important; + background-color: rgba(255, 255, 255, 0.8) !important; + background-image: none !important; + cursor: pointer !important; + transition: border-color 0.2s linear, background-color 0.2s linear !important; + position: relative !important; + box-sizing: border-box !important; +} + +/* Checkbox - Checked state */ +.x-form-cb-checked .x-form-checkbox { + border-color: #4797FF !important; + background-color: #4797FF !important; + background-image: none !important; +} + +/* Checkbox checkmark using ::after pseudo-element */ +.x-form-cb-checked .x-form-checkbox::after { + content: '✓' !important; + position: absolute !important; + color: white !important; + font-size: 12px !important; + font-weight: bold !important; + top: 50% !important; + left: 50% !important; + transform: translate(-50%, -50%) !important; + pointer-events: none !important; +} + +/* Checkbox - Hover state */ +.x-form-checkbox:hover, +.x-form-cb:hover .x-form-checkbox, +.x-form-cb-wrap:hover .x-form-checkbox { + border-color: #4797FF !important; +} + +/* RADIO BUTTONS - Base styling */ +.x-form-radio, +.x-form-radio-default { + display: inline-block !important; + width: 16px !important; + min-width: 16px !important; + height: 16px !important; + min-height: 16px !important; + border-radius: 50% !important; + border: 0.8px solid #B0B3BA !important; + background-color: rgba(255, 255, 255, 0.8) !important; + background-image: none !important; + cursor: pointer !important; + position: relative !important; + transition: border-color 0.2s linear !important; + box-sizing: border-box !important; +} + +/* Radio - Checked state border */ +.x-form-cb-checked .x-form-radio { + border-color: #4797FF !important; + background-color: rgba(255, 255, 255, 0.8) !important; + background-image: none !important; +} + +/* Radio - Inner dot using ::after pseudo-element */ +.x-form-radio::after { + content: '' !important; + position: absolute !important; + top: 50% !important; + left: 50% !important; + width: 6px !important; + height: 6px !important; + border-radius: 50% !important; + background-color: transparent !important; + transform: translate(-50%, -50%) scale(0) !important; + transition: transform 0.2s ease, background-color 0.2s ease !important; + pointer-events: none !important; +} + +/* Radio - Checked inner dot */ +.x-form-cb-checked .x-form-radio::after { + background-color: #4797FF !important; + transform: translate(-50%, -50%) scale(1) !important; +} + +/* Radio - Hover state */ +.x-form-radio:hover, +.x-form-cb-wrap:hover .x-form-radio { + border-color: #4797FF !important; +} + +/* ===================================================== + BUTTONS - Clean, minimal style (UniFi authentic) + ===================================================== */ +/* v5.88: Respect inline display:none - Proxmox hides buttons dynamically and !important was overriding */ +.x-btn-default-small[style*="display: none"], +.x-btn-default-small[style*="display:none"] { + display: none !important; +} + +.x-btn-default-small { + background-color: #006EFF; + border: none; + border-radius: 6px; + padding: 5px 10px !important; + min-height: 26px !important; + /* v5.29: Header buttons (Create VM, Create CT, root@pam) - consistent 28px height with vertical centering */ + /* Exclude tag edit buttons (display:none when hidden, :has(.fa-check) for checkmark) */ + height: 28px !important; + min-height: 28px !important; + display: flex !important; + align-items: center !important; + padding: 3px 8px !important; +} + +.x-btn-default-small .x-btn-inner { + color: #ffffff; + padding: 2px 4px !important; + display: inline-flex !important; + align-items: center !important; +} + +/* Flex container logic (Merged from L3242) */ +.x-btn.x-btn-default-small .x-btn-button { + display: flex !important; + align-items: center !important; + justify-content: center !important; +} + +.x-btn.x-btn-default-small .x-btn-icon-el { + justify-content: center !important; +} + +.x-btn-default-small.x-btn-over, +.x-keyboard-mode .x-btn-default-small.x-btn-focus { + background-color: #338BFF; +} + +/* Pressed state */ +.x-btn-default-small.x-btn-pressed, +.x-btn-default-small.x-btn-menu-active { + background-color: #0056CC; +} + +.x-btn-default-small.x-btn.x-btn-disabled { + background-color: #006EFF; + opacity: 0.4; +} + +/* Toolbar Buttons - Compact & Transparent */ +.x-btn-default-toolbar-small { + background-color: transparent; + border: 1px solid #DDDDE0 !important; + padding: 4px 8px !important; + border-radius: 4px; +} + +.x-btn-default-toolbar-small .x-btn-inner-default-toolbar-small { + color: #585C66; +} + +.x-btn-default-toolbar-small .x-btn-icon-el-default-toolbar-small { + color: #585C66; +} + +/* v5.8: Toolbar button icon vertical centering fix */ +.x-btn-wrap.x-btn-wrap-default-toolbar-small { + align-items: center !important; +} + +.x-btn-icon-el.x-btn-icon-el-default-toolbar-small { + display: flex !important; + align-items: center !important; + justify-content: center !important; + line-height: 16px !important; + height: 16px !important; +} + +.x-btn-inner.x-btn-inner-default-toolbar-small { + display: flex !important; + align-items: center !important; +} + +.x-btn-default-toolbar-small .x-btn-wrap-default-toolbar-small.x-btn-arrow-right::after, +.x-btn-default-toolbar-small .x-btn-wrap-default-toolbar-small.x-btn-split-right::after { + filter: brightness(70%); +} + +.x-btn-default-toolbar-small.x-btn-over, +.x-keyboard-mode .x-btn-default-toolbar-small.x-btn-focus { + background-color: #ECEDF0; +} + +.x-btn-default-toolbar-small.x-btn.x-btn-disabled { + opacity: 0.4; +} + +.x-btn-default-toolbar-small.x-btn.x-btn-menu-active, +.x-btn-default-toolbar-small.x-btn.x-btn-pressed { + background-color: #006EFF; +} + +.x-btn-default-toolbar-small.x-btn.x-btn-pressed .x-btn-inner-default-toolbar-small, +.x-btn-default-toolbar-small.x-btn.x-btn-pressed .x-btn-icon-el-default-toolbar-small { + color: #ffffff; +} + +/* Server View cogwheel button height - match adjacent combobox (28px) */ +.x-box-target:has(#view)>.x-btn { + height: 28px !important; + min-height: 28px !important; +} + +/* Header buttons (Create VM, Create CT, root@pam) - consistent 28px height with vertical centering */ +/* v5.29: Exclude tag edit buttons (display:none when hidden, :has(.fa-check) for checkmark) */ +.x-btn.x-btn-default-small:not(.x-btn-default-toolbar-small):not([style*="display: none"]):not([style*="display:none"]):not(:has(.fa-check)) { + height: 28px !important; + min-height: 28px !important; + display: flex !important; + align-items: center !important; + padding: 3px 8px !important; +} + +.x-btn.x-btn-default-small:not(.x-btn-default-toolbar-small):not([style*="display: none"]):not([style*="display:none"]):not(:has(.fa-check)) .x-btn-wrap { + display: flex !important; + align-items: center !important; +} + +.x-btn.x-btn-default-small:not(.x-btn-default-toolbar-small):not([style*="display: none"]):not([style*="display:none"]):not(:has(.fa-check)) .x-btn-inner { + display: flex !important; + align-items: center !important; +} + +/* Fix dropdown arrows on split/arrow buttons */ +.x-btn-wrap.x-btn-arrow-right::after, +.x-btn-wrap.x-btn-split-right::after { + height: 16px !important; + min-height: 16px !important; + width: 20px !important; + display: flex !important; + align-items: center !important; +} + +/* v5.27: Fix icon-only buttons - hide   inner element when button has no text */ +/* ExtJS adds x-btn-no-text class to buttons with only an icon */ +.x-btn-no-text .x-btn-inner, +.x-btn-button.x-btn-no-text .x-btn-inner, +.x-btn-button-default-toolbar-small.x-btn-no-text .x-btn-inner-default-toolbar-small, +.x-btn-button-default-small.x-btn-no-text .x-btn-inner-default-small, +.x-btn-button-default-small.x-btn-no-text>.x-btn-inner-default-small { + display: none !important; +} + +/* ===================================================== + v5.8: TOOLBOX SCROLL ARROWS FIX + ExtJS behavior: + - Sets inline display:none when content NOT scrollable + - Adds x-box-scroller-disabled class at boundary + - No inline style when scrollable (show arrow) + ===================================================== */ + +/* Hide disabled scrollers (at boundary) */ +.x-box-scroller.x-box-scroller-disabled { + display: none !important; +} + +/* Hide scrollers when ExtJS sets inline display:none (not scrollable) */ +/* Note: ExtJS uses "display:none" without space, check both formats */ +.x-box-scroller.x-box-scroller-toolbar[style*="display:none"], +.x-box-scroller.x-box-scroller-toolbar[style*="display: none"] { + display: none !important; +} + +/* Show scrollers when content is scrollable (no inline display style, not disabled) */ +.x-toolbar-vertical .x-box-scroller-top:not(.x-box-scroller-disabled):not([style*="display"]), +.x-toolbar-vertical .x-box-scroller-bottom:not(.x-box-scroller-disabled):not([style*="display"]) { + display: flex !important; +} + +/* Style the vertical toolbar scrollers - arrow only, no background */ +.x-toolbar-vertical .x-box-scroller-top, +.x-toolbar-vertical .x-box-scroller-bottom { + width: 100% !important; + height: 16px !important; + left: 0 !important; + right: 0 !important; + background: transparent !important; + background-image: none !important; + filter: none !important; + display: flex !important; + align-items: center !important; + justify-content: center !important; + cursor: pointer !important; + opacity: 1 !important; + z-index: 100 !important; + border: none !important; +} + +.x-toolbar-vertical .x-box-scroller-top { + top: 0 !important; +} + +.x-toolbar-vertical .x-box-scroller-bottom { + bottom: 0 !important; +} + +/* Arrow icons */ +.x-toolbar-vertical .x-box-scroller-top::before { + content: '▲' !important; + font-size: 10px !important; + color: #585C66 !important; +} + +.x-toolbar-vertical .x-box-scroller-bottom::before { + content: '▼' !important; + font-size: 10px !important; + color: #585C66 !important; +} + +/* Hover states */ +.x-toolbar-vertical .x-box-scroller-top:hover::before, +.x-toolbar-vertical .x-box-scroller-bottom:hover::before { + color: #111217 !important; +} + +/* Re-hide disabled scrollers after styling */ +.x-toolbar-vertical .x-box-scroller.x-box-scroller-disabled { + display: none !important; +} + +/* ===================================================== + FORM ELEMENTS - Clean inputs (UniFi authentic) + ===================================================== */ +.x-form-trigger-default { + background-color: transparent; +} + +/* Boundlist dropdown popup - UniFi style 4px radius */ +.x-boundlist { + background-color: #F6F6F8; + border: 1px solid #DDDDE0; + border-radius: 4px !important; + box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12); + padding: 2px; +} + +.x-boundlist-item { + background-color: transparent; + border: none; + border-radius: 4px !important; + color: #1A1C21; + padding: 2px 8px; +} + +.x-boundlist-selected { + background-color: rgba(0, 0, 0, 0.08); + color: #111217; +} + +.x-boundlist-item-over { + background-color: rgba(0, 0, 0, 0.05); + color: #1A1C21; +} + +/* v5.38: Fix boundlist inner container inheriting 8px radius from global rule */ +.x-boundlist-list-ct { + border-radius: 4px !important; +} + +/* Dropdown/floating grid pickers (e.g. ISO selector): readable column headers */ +.x-layer.x-grid .x-grid-header-ct, +.x-layer.x-grid .x-column-header, +.x-boundlist .x-grid-header-ct, +.x-boundlist .x-column-header { + background-color: var(--pm-bg-surface) !important; + border-bottom: 1px solid rgba(0, 0, 0, 0.10) !important; +} + +.x-layer.x-grid .x-column-header-inner, +.x-layer.x-grid .x-column-header-text, +.x-layer.x-grid .x-column-header-text-inner, +.x-layer.x-grid .x-column-header-text-default, +.x-boundlist .x-column-header-inner, +.x-boundlist .x-column-header-text, +.x-boundlist .x-column-header-text-inner, +.x-boundlist .x-column-header-text-default { + color: var(--pm-text-bright) !important; + font-weight: 700 !important; +} + +.x-layer.x-grid .x-column-header-trigger, +.x-boundlist .x-column-header-trigger { + border-left-color: rgba(0, 0, 0, 0.10) !important; +} + +.x-form-display-field-default { + color: #585C66; +} + +.x-form-text-default { + background-color: transparent; + color: #111217; + border-radius: 4px 0 0 4px !important; + padding: 6px 10px !important; +} + +.x-form-trigger-wrap-default { + border-color: var(--pm-border); + border-radius: 4px !important; + background-color: var(--pm-hover-medium); +} + +.x-form-trigger-wrap-default.x-form-trigger-wrap-focus { + border-color: var(--pm-accent); + box-shadow: 0 0 0 3px var(--pm-focus-ring-color); +} + +.x-form-item-label-default { + color: #585C66; +} + +.x-form-spinner-default { + background-color: #F6F6F8; +} + +/* v5.59: Make spinner buttons fill container with FontAwesome arrows */ +.x-form-spinner-up, +.x-form-spinner-down { + height: 13px !important; + background-image: none !important; + display: flex !important; + align-items: center !important; + justify-content: center !important; + font-family: 'Font Awesome 6 Free', 'Font Awesome 5 Free', FontAwesome !important; + font-weight: 900 !important; + font-size: 7px !important; + color: #585C66 !important; +} + +.x-form-spinner-up::before { + content: '\f077' !important; + display: block !important; +} + +.x-form-spinner-down::before { + content: '\f078' !important; + display: block !important; +} + +/* v5.64: Dialog form field alignment - let ExtJS handle natural sizing */ +.x-window .x-container .x-form-trigger-wrap, +.x-window .x-form-item-body .x-form-trigger-wrap { + width: 100% !important; + max-width: none !important; +} + +/* Ensure input fills the trigger wrap */ +.x-window .x-container .x-form-trigger-wrap input.x-form-field { + width: calc(100% - 2px) !important; +} + +/* v5.63: Removed v5.61 margin-left rule that caused form alignment issues */ + +.x-form-cb-label-default { + color: #585C66; +} + +/* v5.41: Reduce gap between checkbox/radio and label */ +/* Label after checkbox - reduce left padding */ +.x-form-cb-label-after { + padding-left: 6px !important; +} + +/* Label before checkbox - reduce right padding */ +.x-form-cb-label-before { + padding-right: 6px !important; +} + +.x-fieldset-default { + border-color: #DDDDE0; +} + +.x-fieldset-header-default>.x-fieldset-header-text { + color: #111217; +} + +/* ===================================================== + GRID / TABLE - UniFi authentic row hover + ===================================================== */ +.x-column-header { + border-color: transparent !important; + background-color: transparent !important; +} + +/* Header Text - Bright White */ +.x-column-header-inner, +.x-column-header-text { + color: #111217 !important; + font-weight: 700 !important; + font-size: 13px !important; +} + +.x-grid-item, +.x-column-header-default, +.x-grid-cell-row-numberer { + color: #1A1C21 !important; + background-color: transparent !important; + border-color: transparent !important; + font-size: 13px !important; +} + +.x-column-header-trigger { + border-color: transparent !important; +} + +.x-grid-cell-special { + border-color: transparent !important; +} + +.x-grid-group-hd { + background-color: transparent !important; + border-color: transparent !important; +} + +.x-grid-group-title { + color: #111217 !important; + font-weight: 700 !important; +} + +.x-grid-header-ct { + border: none !important; + background-color: transparent !important; +} + +/* Row separators (use td borders; more reliable than box-shadow on ) */ +.x-grid td, +.x-grid-td, +.x-grid-cell, +td.x-grid-cell { + border: none !important; + border-bottom: 1px solid rgba(0, 0, 0, 0.08) !important; +} + +/* v5.53: Vertically center text in grid table cells */ +.x-grid-cell { + vertical-align: middle !important; +} + +/* Keep rows themselves flat; separators handled above */ +.x-grid-item { + box-shadow: none !important; +} + +/* Slightly roomier rows (matches UniFi table density) */ +.x-grid-cell-inner { + padding-top: 6px !important; + padding-bottom: 6px !important; +} + +/* + Tasks + Cluster Log: compact rows (validated via DevTools) + - Tasks: 4px top/bottom + - Cluster Log: 4.5px top/bottom + - Keep line-height stable and prevent action-column icons from inflating row height +*/ + +/* Tasks grid (bottom Tasks panel) */ +div[id^="pveTaskViewer-"] .x-grid-cell-inner, +div[id^="pveClusterTasks-"] .x-grid-cell-inner, +[aria-label="Tasks"] .x-grid-view .x-grid-cell-inner { + padding-top: 4px !important; + padding-bottom: 4px !important; + line-height: 15px !important; +} + +/* Tasks action-column (chevron) can inflate row height unless centered */ +div[id^="pveTaskViewer-"] .x-grid-cell-inner-action-col, +div[id^="pveClusterTasks-"] .x-grid-cell-inner-action-col, +[aria-label="Tasks"] .x-grid-view .x-grid-cell-inner-action-col { + display: flex !important; + align-items: center !important; + justify-content: center !important; + padding-top: 4px !important; + padding-bottom: 4px !important; + line-height: 15px !important; +} + +/* Cluster Log grid */ +div[id^="pveClusterLog-"] .x-grid-cell-inner, +div[id^="pveLogView-"] .x-grid-cell-inner, +[aria-label="Cluster Log"] .x-grid-view .x-grid-cell-inner { + padding-top: 4.5px !important; + padding-bottom: 4.5px !important; + line-height: 15px !important; +} + +.x-grid-item-alt { + background-color: transparent !important; +} + +/* Ensure alternating rows have readable text */ +.x-grid-item-alt .x-grid-cell-inner, +.x-grid-item-alt .x-grid-cell { + color: #1A1C21 !important; +} + +.x-grid-with-row-lines .x-grid-item { + border-bottom: none !important; + border: none !important; + box-shadow: none !important; +} + +/* Optional: no trailing divider after the last row */ +.x-grid-with-row-lines .x-grid-item:last-child td.x-grid-cell, +.x-grid-with-row-lines .x-grid-item:last-child .x-grid-td { + border-bottom: none !important; +} + +.x-grid-with-row-lines .x-grid-item.x-grid-item-over { + background-color: var(--pm-hover-subtle) !important; + border: none !important; +} + +.x-grid-with-row-lines .x-grid-item.x-grid-item-selected { + background-color: rgba(0, 110, 255, 0.10) !important; + box-shadow: rgba(0, 110, 255, 0.12) 0px 0px 0px 1000px inset !important; + border: none !important; +} + +.x-grid-item-over { + background-color: rgba(0, 0, 0, 0.03) !important; +} + +.x-grid-item-over .x-grid-cell { + background-color: transparent !important; +} + +/* Keep row separators stable on hover/selection (prevents 1px shift) */ +.x-grid-item-over .x-grid-cell, +.x-grid-item-over .x-grid-td, +.x-grid-item-over td.x-grid-cell, +.x-grid-item-selected .x-grid-cell, +.x-grid-item-selected .x-grid-td, +.x-grid-item-selected td.x-grid-cell { + border-bottom: 1px solid rgba(0, 0, 0, 0.08) !important; +} + +.x-grid-item-selected { + background-color: rgba(0, 110, 255, 0.10) !important; + box-shadow: rgba(0, 110, 255, 0.12) 0px 0px 0px 1000px inset !important; +} + +.x-grid-item-selected .x-grid-cell-inner { + color: #111217 !important; +} + +/* v5.16: Remove background highlight from parent nodes (folders/servers) when focused/selected via arrow */ +/* Only leaf nodes (VMs/CTs) should show the selection/focus background */ +.x-grid-item:not(.x-grid-tree-node-leaf).x-grid-item-focused, +.x-grid-item:not(.x-grid-tree-node-leaf).x-grid-item-selected { + background-color: transparent !important; +} + +/* More visible hover state */ +.x-grid-item-over .x-grid-cell-inner, +.x-grid-item-over .x-grid-cell { + color: #111217 !important; +} + +.x-column-header-over, +.x-column-header-open { + background-color: #ECEDF0; +} + +.x-column-header-sort-ASC, +.x-column-header-sort-DESC { + background-color: #E0EBF5; +} + +.x-grid-row-summary .x-grid-cell, +.x-grid-row-summary .x-grid-rowwrap, +.x-grid-row-summary .x-grid-cell-rowbody { + background-color: #FFFFFF !important; + border-color: #DDDDE0; +} + +.x-grid-with-col-lines .x-grid-cell, +.x-grid-with-col-lines .x-grid-item-over .x-grid-cell, +.x-grid-with-col-lines .x-grid-item-selected .x-grid-cell { + border-color: rgba(0, 0, 0, 0.08) !important; + border-right-color: transparent !important; +} + +.x-dd-drag-proxy { + background-color: #F6F6F8; + border: 1px solid #DDDDE0; + color: #585C66; +} + +.x-keyboard-mode .x-grid-item-focused { + background-color: rgba(0, 0, 0, 0.08); + color: #111217; +} + +.x-keyboard-mode .x-grid-item-focused .x-grid-cell-inner::before { + border-color: #006EFF; +} + +.x-grid-empty { + background-color: #FFFFFF; + color: #A0A3AB; +} + +/* ===================================================== + MENUS - Floating, clean (UniFi authentic) + ===================================================== */ +.x-menu-default { + border: 1px solid #DDDDE0; + border-radius: 8px; + box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12); +} + +.x-menu-body-default { + background-color: #F6F6F8; +} + +.x-menu-header { + background-color: #006EFF; +} + +.x-menu-item-default.x-menu-item-separator { + background-color: #F6F6F8; + border-color: #DDDDE0; +} + +.x-menu-item-default.x-menu-item-focus, +.x-menu-item-default.x-menu-item-active { + background-color: rgba(0, 0, 0, 0.08) !important; + color: #111217; +} + +.x-menu-item-text-default { + color: #1A1C21; +} + +.x-menu-item-icon-default { + color: #585C66; +} + +.x-menu-icon-separator-default { + background-color: transparent; + border-color: #DDDDE0; +} + +/* ===================================================== + PANELS - Card-like containers (UniFi authentic) + ===================================================== */ +.x-panel-header-default { + background-color: #FFFFFF; + border: none; +} + +.x-panel-header-default .x-tool-tool-el { + background-color: transparent; +} + +.x-tool-img { + filter: brightness(60%); +} + +.x-tool-over .x-tool-img { + filter: brightness(80%); +} + +/* v5.39: Replace pixelated close button sprite with crisp FontAwesome icon */ +.x-tool-tool-el.x-tool-close, +.x-tool-img.x-tool-close { + background-image: none !important; + font-family: "FontAwesome" !important; + font-size: 20px !important; + line-height: 16px !important; + text-align: center !important; + color: #A0A3AB !important; + transition: color 0.15s ease !important; + filter: none !important; + width: 16px !important; + height: 16px !important; +} + +.x-tool-tool-el.x-tool-close::before, +.x-tool-img.x-tool-close::before { + content: "\f00d" !important; +} + +.x-tool:hover .x-tool-tool-el.x-tool-close, +.x-tool:hover .x-tool-img.x-tool-close { + color: #1A1C21 !important; +} + +.x-panel-header-title-default { + color: #111217; +} + +/* Panel header text (VM/Container titles in toolbar) */ +.x-panel-header-text, +.x-panel-header-text-default, +.x-panel-header-text.x-box-item, +.x-toolbar .x-panel-header-text, +.x-toolbar-item.x-panel-header-text { + color: #111217 !important; +} + +/* Title text general */ +.x-title-text, +.x-title-text-default { + color: #111217 !important; + overflow: visible !important; +} + +/* Panel header container - ensure proper visibility */ +.x-panel-header, +.x-panel-header-default { + overflow: visible !important; +} + +.x-panel-body-default { + background-color: var(--pm-bg-base); + border-color: var(--pm-border); + color: var(--pm-text-muted); +} + +div[id^="pveResourceTree-"][id$="-body"] { + border-color: var(--pm-bg-base); +} + +/* ===================================================== + PROGRESS BARS - Clean, rounded (UniFi authentic) + v5.17: Consolidated - removed duplicate section at end of file + ===================================================== */ +/* Fix: Widget containers need overflow visible to not clip progress bars */ +.x-container[id^="pmxInfoWidget"], +.x-container.x-box-layout-ct { + overflow: visible !important; +} + +/* v5.32: Add padding gap to progress bar rows (CPU/Memory/SWAP/Bootdisk) + Only targets containers with VISIBLE progress bars (excludes Status/HA State/Node/Unprivileged) */ +/* v5.94: Reduced vertical padding from 5px to 3px to prevent PBS summary panel clipping + (ExtJS calculates body height before CSS padding → overflow hidden clips bottom rows) */ +.x-container[id^="pmxInfoWidget"].x-box-layout-ct:has(.x-progress:not([style*="display: none"]):not([style*="display:none"])) { + padding: 3px 25px !important; +} + +/* v5.51: Fix horizontal padding alignment for rows with HIDDEN progress bars + (Load average, KSM sharing, CPU(s), Kernel Version, Boot Mode, Manager Version) + Only adjusts horizontal padding to match visible progress bar rows, keeps vertical minimal */ +.x-container[id^="pmxInfoWidget"].x-box-layout-ct:has(.x-progress[style*="display: none"]), +.x-container[id^="pmxInfoWidget"].x-box-layout-ct:has(.x-progress[style*="display:none"]) { + padding-left: 25px !important; + padding-right: 25px !important; +} + +/* v5.51: Repository Status row uses different ID pattern */ +.x-container[id^="pmxNodeInfoRepoStatus"].x-box-layout-ct { + padding-left: 25px !important; + padding-right: 25px !important; +} + +/* v5.94: Fix PBS summary panel clipping - reduce body padding to fit all rows + PBS panel has 9 info widgets in a smaller body (243px); default 15px top/bottom + padding causes scrollHeight to exceed clientHeight → bottom rows clipped */ +div[id^="pbsNodeInfoPanel"][id$="-body"] { + padding-top: 5px !important; + padding-bottom: 5px !important; +} + +/* v5.22: Removed height:inherit - only min-height:auto is needed */ +/* height:inherit was breaking widget containers, ExtJS inline heights work without it */ +.x-container[id^="pmxInfoWidget"] .x-box-inner, +.x-container.x-box-layout-ct .x-box-inner { + min-height: auto !important; +} + +/* v5.22: Fix pmxInfoWidget container heights - need 24px to fit 8px progress bars */ +[id^="pmxInfoWidget"][id$="-innerCt"] { + min-height: 24px !important; + overflow: visible !important; +} + +/* Progress bar outer container (track) */ +.x-progress, +.x-progress-default { + height: 8px !important; + min-height: 8px !important; + max-height: 8px !important; + border-radius: 5px !important; + overflow: hidden !important; + background-color: var(--pwt-gauge-back) !important; + border: none !important; + padding: 0 !important; +} + +/* Progress bar inner fill - v5.31: Updated to UniFi blue #4797FF */ +.x-progress-bar, +.x-progress-bar-default, +.x-progress-default .x-progress-bar-default { + height: 8px !important; + min-height: 8px !important; + max-height: 8px !important; + border-radius: 5px !important; + border: none !important; + background-color: var(--pwt-gauge-default) !important; + background-image: none !important; +} + +/* Hide progress text overlay */ +.x-progress-text, +.x-progress-default .x-progress-text { + display: none !important; +} + +/* Warning state */ +.x-progress.warning .x-progress-bar, +.x-progress.warning .x-progress-bar-default { + background-color: var(--pwt-gauge-warn) !important; +} + +/* Critical state */ +.x-progress.critical .x-progress-bar, +.x-progress.critical .x-progress-bar-default { + background-color: var(--pwt-gauge-crit) !important; +} + +/* ===================================================== + SPLITTERS - Minimal + ===================================================== */ +.x-splitter { + background-color: var(--pm-bg-base); +} + +/* Horizontal splitter (between main content and Tasks panel) - visible divider line */ +.x-splitter-horizontal, +.x-splitter[aria-orientation="horizontal"] { + background-color: transparent !important; + border-top: 1px solid var(--pm-border) !important; +} + +/* Vertical splitter - gap with visible line */ +.x-splitter-vertical { + width: 7px !important; + min-width: 7px !important; + background-color: transparent !important; + border-right: 1px solid #C8C9CC !important; + z-index: 10 !important; +} + +.x-keyboard-mode .x-splitter-focus::after { + border-color: #006EFF; +} + +/* ===================================================== + TABS - Clean, flat (UniFi authentic) + ===================================================== */ +.x-tab-bar-default { + background-color: #FFFFFF; +} + +.x-tab-default.x-tab-over { + background-color: rgba(0, 0, 0, 0.05); + border: none; +} + +/* Remove white focus border/outline from tabs (v5.46) */ +.x-tab:focus, +.x-tab.x-tab-focus, +.x-tab.x-tab-active:focus, +.x-keyboard-mode .x-tab:focus, +.x-keyboard-mode .x-tab-focus, +.x-keyboard-mode .x-tab-active.x-tab-focus, +.x-tab-default:focus, +.x-tab-default.x-tab-focus, +.x-tab-bar .x-tab:focus, +.x-tab-bar .x-tab.x-tab-focus { + outline: none !important; + box-shadow: none !important; + border-color: transparent !important; +} + +.x-tab:focus::before, +.x-tab:focus::after, +.x-tab.x-tab-focus::before, +.x-tab.x-tab-focus::after, +.x-keyboard-mode .x-tab:focus::before, +.x-keyboard-mode .x-tab:focus::after { + border: none !important; + outline: none !important; + box-shadow: none !important; +} + +.x-tab-default.x-tab.x-tab-active { + background-color: #006EFF; + border: none; +} + +.x-tab-default.x-tab.x-tab-disabled { + background-color: transparent; + border: none; + color: #A0A3AB; +} + +.x-keyboard-mode .x-tab-default.x-tab-focus, +.x-keyboard-mode .x-tab-default.x-tab-focus.x-tab-active { + background-color: #006EFF; + border: none; +} + +.x-tab-default-top { + background-color: #FFFFFF; + border: none; +} + +.x-tab-inner-default { + color: #585C66; +} + +.x-tab-active .x-tab-inner-default { + color: #ffffff; +} + +/* ===================================================== + TOOLTIPS (UniFi authentic) + ===================================================== */ +.x-tip-default { + background-color: #F6F6F8; + border: 1px solid #DDDDE0; + border-radius: 6px; + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1); +} + +.x-tip-body-default { + color: #1A1C21; +} + +.x-tip-form-invalid { + background-color: #F6F6F8; + border-color: #f03a3e; +} + +.x-tip-body-form-invalid { + color: #f03a3e; +} + +/* ===================================================== + TOOLBARS - Minimal borders (UniFi authentic) + ===================================================== */ +.x-toolbar { + background-color: #FFFFFF; +} + +.x-toolbar-default { + background-color: #FFFFFF; + border: none; +} + +.x-toolbar-default.x-docked-top { + border: none; + border-bottom: 1px solid #DDDDE0; +} + +.x-toolbar-default .x-toolbar-separator { + border-color: #DDDDE0; +} + +.x-toolbar-text-default { + color: #585C66; +} + +/* ===================================================== + TREE LIST - Sidebar navigation (UniFi authentic) + ===================================================== */ +.x-treelist-item, +.x-treelist-item-tool { + background-color: #FFFFFF; + border-radius: 4px !important; +} + +/* v5.84: Fix horizontal scrollbar in resource tree + ExtJS sets inline 'overflow: hidden auto' which causes 1px horizontal scroll. + Force overflow-x: hidden while preserving vertical scroll. + Note: Must use .x-fit-item compound selector to win over rule at line ~3365 */ +[id^="pveResourceTree"] .x-tree-view, +[id^="pveResourceTree"] .x-tree-view.x-fit-item { + overflow-x: hidden !important; +} + +/* Add spacing between tree items - v5.33: Reduced padding for compactness */ +.x-treelist-row, +.x-tree-cell, +.x-grid-cell-treecolumn { + padding: 0px 8px !important; +} + +/* v5.9: UniFi-STYLE SELECTED ITEM (matching UniFi Controller) + Uses subtle background + blue icon AND text with ::before pseudo-element */ + +.x-treelist-item-text, +.x-treelist-item-icon { + color: rgba(0, 0, 0, 0.75); +} + +/* Remove ALL old hover/selected background styles */ +.x-treelist-row, +.x-treelist-row:hover, +.x-treelist-row-over, +.x-treelist-item-selected>.x-treelist-row, +.x-treelist-item-selected>.x-treelist-row:hover, +.x-treelist-item-expanded>.x-treelist-row, +.x-treelist-item-expanded>.x-treelist-row-over, +.x-treelist-item-expandable>.x-treelist-row, +.x-treelist-item-expandable>.x-treelist-row-over { + background: none !important; + background-color: transparent !important; + box-shadow: none !important; + border-left: none !important; + position: relative !important; + z-index: 1 !important; + border-radius: 4px !important; +} + +/* Pseudo-element for ALL background effects */ +.x-treelist-row::before { + content: '' !important; + display: block !important; + position: absolute !important; + top: 0 !important; + left: 0 !important; + right: 0 !important; + bottom: 0 !important; + width: 100% !important; + height: 100% !important; + border-radius: 4px !important; + background: transparent !important; + opacity: 0 !important; + transform: scale(0.95) !important; + transition: opacity 0.15s ease, transform 0.15s ease !important; + z-index: -1 !important; + pointer-events: none !important; +} + +/* Hover state - ONLY via :hover pseudo-class */ +.x-treelist-row:hover::before { + background: rgb(236, 237, 240) !important; + opacity: 0.5 !important; + transform: scale(1) !important; +} + +/* DISABLE the x-treelist-row-over class effect (ExtJS adds this to parents) */ +.x-treelist-row-over::before { + opacity: 0 !important; +} + +/* But if it's ALSO being hovered directly, show the effect */ +.x-treelist-row-over:hover::before { + background: rgb(236, 237, 240) !important; + opacity: 0.5 !important; + transform: scale(1) !important; +} + +/* Selected state background */ +.x-treelist-item-selected>.x-treelist-row::before { + background: rgb(236, 237, 240) !important; + opacity: 1 !important; + transform: scale(1) !important; +} + +/* Selected + hover - slightly lighter */ +.x-treelist-item-selected>.x-treelist-row:hover::before { + background: rgb(226, 227, 230) !important; + opacity: 1 !important; +} + +/* Selected item text - BLUE like UniFi */ +.x-treelist-item-selected>.x-treelist-row .x-treelist-item-text { + color: rgb(0, 110, 255) !important; +} + +/* Selected item icon - BLUE like UniFi */ +.x-treelist-item-selected>.x-treelist-row .x-treelist-item-icon { + color: rgb(0, 110, 255) !important; +} + +/* Parent item containing selected child - WHITE text and icon */ +.x-treelist-item:has(.x-treelist-item-selected)>.x-treelist-row .x-treelist-item-text { + color: #111217 !important; +} + +.x-treelist-item:has(.x-treelist-item-selected)>.x-treelist-row .x-treelist-item-icon { + color: #111217 !important; +} + +/* Reset non-selected child items */ +.x-treelist-item-selected .x-treelist-item:not(.x-treelist-item-selected):not(:has(.x-treelist-item-selected))>.x-treelist-row::before { + opacity: 0 !important; +} + +.x-treelist-item-selected .x-treelist-item:not(.x-treelist-item-selected):not(:has(.x-treelist-item-selected))>.x-treelist-row:hover::before { + opacity: 0.5 !important; +} + +.x-treelist-item-selected .x-treelist-item:not(.x-treelist-item-selected):not(:has(.x-treelist-item-selected)) .x-treelist-item-text, +.x-treelist-item-selected .x-treelist-item:not(.x-treelist-item-selected):not(:has(.x-treelist-item-selected)) .x-treelist-item-icon { + color: #585C66 !important; +} + +.x-treelist-pve-nav { + background-color: #FFFFFF; + border: none; +} + +/* ===================================================== + WINDOWS / DIALOGS (UniFi authentic) + ===================================================== */ +/* v5.50: Reduced shadow intensity for cleaner look */ +.x-window-default { + background-color: #FFFFFF; + border: 1px solid #DDDDE0; + border-radius: 8px; + box-shadow: 0 12px 40px rgba(0, 0, 0, 0.08); +} + +.x-window-header-default { + background-color: #F6F6F8; + border: none; + border-radius: 8px 8px 0 0; +} + +.x-window-header-default .x-mask { + background-color: rgba(246, 246, 248, 0.7); +} + +.x-window-header-title-default { + color: #111217; +} + +.x-window-body-default { + background-color: #FFFFFF; + border: none; + color: #585C66; +} + +.x-window-ghost { + background-color: #FFFFFF; +} + +.x-window-header-default .x-tool-img { + background-color: transparent; +} + +.x-message-box .x-window-body { + background-color: #F6F6F8; +} + +/* ===================================================== + v5.17 FIX: Dialog button overlap fix + ExtJS uses absolute positioning for buttons, but theme's + display:flex !important was overriding inline display:none + on hidden buttons (OK/Cancel in Yes/No dialogs) + ===================================================== */ +/* Respect ExtJS inline display:none on hidden dialog buttons */ +.x-message-box .x-btn.x-btn-default-small[style*="display: none"], +.x-message-box .x-btn.x-btn-default-small[style*="display:none"], +.x-window .x-toolbar-footer .x-btn[style*="display: none"], +.x-window .x-toolbar-footer .x-btn[style*="display:none"] { + display: none !important; +} + +/* ===================================================== + v5.37 FIX: Create Wizard footer clipping + Some wizards position their footer toolbar with inline top/height. + If theme tweaks change control heights/padding, the footer can extend + past the window bottom and get clipped (the window has overflow:hidden). + Anchor wizard footers to bottom to keep Back/Next/Advanced visible. + ===================================================== */ +.x-window[id^="pveQemuCreateWizard-"] .x-toolbar-footer, +.x-window[id^="pveLxcCreateWizard-"] .x-toolbar-footer { + top: auto !important; + bottom: 0 !important; + left: 0 !important; + right: 0 !important; + width: auto !important; + box-sizing: border-box !important; + padding: 8px 16px !important; + height: auto !important; + display: flex !important; + align-items: center !important; +} + +/* Dialog footer - use flexbox for proper button spacing */ +.x-message-box .x-toolbar-footer { + display: flex !important; + justify-content: flex-end !important; + align-items: center !important; + gap: 8px !important; + padding: 12px 16px !important; +} + +.x-message-box .x-toolbar-footer .x-box-inner, +.x-message-box .x-toolbar-footer .x-box-inner { + display: flex !important; + justify-content: flex-end !important; + align-items: center !important; + gap: 8px !important; + width: 100% !important; + height: auto !important; +} + +.x-message-box .x-toolbar-footer .x-box-target, +.x-message-box .x-toolbar-footer .x-box-target { + display: flex !important; + justify-content: flex-end !important; + align-items: center !important; + gap: 8px !important; + position: relative !important; + width: auto !important; + height: auto !important; +} + +/* Override absolute positioning on dialog buttons */ +.x-message-box .x-toolbar-footer .x-btn, +.x-message-box .x-toolbar-footer .x-btn { + position: relative !important; + left: auto !important; + top: auto !important; + margin: 0 !important; +} + +/* ===================================================== + v5.49: LOGIN MODAL / DIALOG FORM FIXES + - Form fields stretch to full width (override inline 380px) + - Footer checkbox/button gap fixed (was -7px overlap) + - Footer toolbar takes full width (override inline 374px) + v5.65: Fix mainPanel width constraint - ExtJS calculates based on + original parent width before CSS override, causing 549px instead + of ~580px. Force direct child panels to use full available width. + ===================================================== */ + +/* ===================================================== + v5.74: DIALOG LAYOUT FIXES - REMOVED OVERRIDES + Removed all forced width/padding rules for panel bodies + Removed forced width/padding rules for panel bodies to prevent layout cutoff. + ===================================================== */ + +/* Only ensure the footer toolbar behaves correctly */ +.x-window .x-toolbar-footer { + width: 100% !important; + padding-right: 10px !important; + box-sizing: border-box !important; +} + +.x-window .x-toolbar-footer .x-box-inner { + display: flex !important; + align-items: center !important; + justify-content: flex-end !important; + gap: 12px !important; + width: 100% !important; +} + +.x-window .x-toolbar-footer .x-box-target { + display: flex !important; + align-items: center !important; + justify-content: flex-end !important; + gap: 12px !important; + width: 100% !important; +} + +/* Remove absolute positioning from footer items */ +.x-window .x-toolbar-footer .x-form-type-checkbox, +.x-window .x-toolbar-footer .x-btn { + position: relative !important; + left: auto !important; + top: auto !important; + margin: 0 !important; +} + +/* Auto-width for checkbox label in footer */ +.x-window .x-toolbar-footer .x-form-type-checkbox .x-form-item-label { + width: auto !important; +} + +/* v5.75: Fix Help button alignment in dialog footers */ +/* The help button is an inline button and should be on the left */ +.x-window .x-toolbar-footer .proxmox-inline-button:first-child { + margin-right: auto !important; +} + +/* ===================================================== + PROXMOX LOGO - Native dark logo on light background + ===================================================== */ +img[id^="proxmoxlogo-"][id$="-img"] { + filter: none; +} + +img[id^="proxmoxLogoSvg-"][id$="-img"] { + filter: none; +} + +div[id^="versioninfo-"]+div[id^="panel-"]>div[id^="panel-"][id$="-bodyWrap"]>div, +div.eol-notice+div[id^="panel-"]>div[id^="panel-"][id$="-bodyWrap"]>div { + background-color: transparent; + border: none; +} + +/* ===================================================== + PROXMOX SPECIFIC (UniFi authentic) + ===================================================== */ +.proxmox-invalid-row { + background-color: rgba(240, 58, 62, 0.12); +} + +.x-keyboard-mode .proxmox-invalid-row .x-grid-item-focused { + background-color: rgba(240, 58, 62, 0.20); +} + +.proxmox-warning-row { + background-color: rgba(245, 166, 35, 0.12); +} + +.proxmox-disabled-row td { + color: #A0A3AB; +} + +.pmx-hint { + background-color: rgba(245, 166, 35, 0.12); + white-space: nowrap !important; +} + +/* Allow pmx-hint text to expand beyond parent container width */ +.x-container:has(> .x-box-inner > .x-box-target > .pmx-hint) .x-box-inner { + overflow: visible !important; +} + +.pmx-hint a { + color: #006EFF; +} + +.proxmox-inline-button { + background-color: #ECEDF0; + border: none; + color: #585C66; +} + +.proxmox-inline-button.x-btn-over { + background-color: rgba(0, 0, 0, 0.08); +} + +.proxmox-inline-button .x-btn-inner, +.proxmox-inline-button .x-btn-icon-el { + color: #585C66; +} + +/* Loading indicators */ +.x-grid-row-loading, +.x-treelist-item-loading .x-treelist-item-icon, +.x-mask-msg-text, +.x-grid-tree-loading .x-tree-icon { + filter: none; +} + +.x-mask-msg { + background-color: #F6F6F8; + border: 1px solid #DDDDE0; + border-radius: 8px; +} + +/* Markdown content */ +.pmx-md code { + background-color: #FFFFFF; +} + +.pmx-md pre code { + border-color: #DDDDE0; +} + +.pmx-md tbody tr td { + border-color: #DDDDE0; +} + +.pmx-md tbody tr:nth-of-type(2n) { + background-color: rgba(0, 0, 0, 0.03); +} + +.pmx-md tbody tr:hover td { + background-color: rgba(0, 0, 0, 0.05); +} + +.pmx-md a { + color: #006EFF; +} + +/* APT repos */ +.proxmox-apt-repos .x-grid-group-hd { + background-color: #FFFFFF; + border: none; +} + +.proxmox-apt-repos .x-grid-group-title { + color: #111217; +} + +/* Status colors */ +.info-blue { + color: #006EFF !important; +} + +.critical { + color: #f03a3e !important; +} + +/* Tags - Native contrast detection with proper visibility */ +.pve-edit-tag.editable span { + background-color: #F6F6F8; + color: #585C66; + border-color: #DDDDE0; +} + +/* Tags with LIGHT text (dark backgrounds like blue tags) */ +.pve-edit-tag.proxmox-tag-light, +.pve-edit-tag.proxmox-tag-light span { + color: #FFFFFF !important; +} + +/* Tags with DARK text (bright backgrounds like pink/yellow tags) - non-edit mode only */ +.pve-edit-tag.proxmox-tag-dark:not(.editable), +.pve-edit-tag.proxmox-tag-dark:not(.editable) span { + color: #1C1E21 !important; +} + +/* v5.88: In edit mode, force light text on ALL tags for better visibility */ +.pve-edit-tag.editable.proxmox-tag-dark, +.pve-edit-tag.editable.proxmox-tag-dark span { + color: #111217 !important; +} + +/* Individual tag styling */ +.pve-edit-tag { + display: inline-flex !important; + align-items: center !important; + padding: 2px 8px !important; + border-radius: 6px !important; +} + +/* v5.30: Tree view tags - match header tag styling */ +.x-tree-node-text .proxmox-tag-dark, +.x-tree-node-text .proxmox-tag-light, +.x-grid-cell-inner .proxmox-tag-dark, +.x-grid-cell-inner .proxmox-tag-light, +span.proxmox-tag-dark, +span.proxmox-tag-light { + border-radius: 6px !important; + padding: 2px 8px !important; + display: inline-flex !important; + align-items: center !important; +} + +/* v5.52: Make resource tree tags match search table tag height (19px) */ +.x-tree-node-text .proxmox-tag-dark, +.x-tree-node-text .proxmox-tag-light { + padding-top: 1px !important; + padding-bottom: 1px !important; +} + +/* v5.52: Force tree row height to stay at 25px when tags have reduced padding */ +.x-tree-panel .x-grid-row { + height: 25px !important; +} + +/* Pencil button for editing tags */ +/* v5.28: Removed display override - let Proxmox control visibility via inline style */ +.pve-tag-inline-button { + /* display controlled by inline style (none when not hovering, flex when editing) */ + align-items: center !important; + justify-content: center !important; + width: 20px !important; + height: 20px !important; + background: transparent !important; + cursor: pointer !important; +} + +.pve-tag-inline-button .fa-pencil, +.pve-tag-inline-button .x-fa.fa-pencil { + color: #8A919A !important; +} + +.pve-tag-inline-button:hover .fa-pencil { + color: #111217 !important; +} + +/* v5.29: Checkmark button in tag edit - match toolbar button size */ +/* The checkmark has x-btn-default-small (not toolbar-small) so we need specific sizing */ +.x-btn.x-btn-default-small:has(.fa-check) { + min-height: 24px !important; + height: 24px !important; + padding: 3px 8px !important; + border-radius: 4px !important; + background-color: #006EFF !important; + border: none !important; +} + +/* Disabled checkmark - gray/transparent */ +.x-btn.x-btn-default-small:has(.fa-check).x-btn-disabled { + background-color: transparent !important; + border: 1px solid #DDDDE0 !important; + opacity: 0.5 !important; +} + +/* Checkmark icon - white when enabled */ +.x-btn.x-btn-default-small:has(.fa-check) .fa-check { + color: #ffffff !important; +} + +/* Disabled checkmark icon - gray */ +.x-btn.x-btn-default-small:has(.fa-check).x-btn-disabled .fa-check { + color: #A0A3AB !important; +} + +/* Checkmark button hover - lighter blue */ +.x-btn.x-btn-default-small:has(.fa-check):not(.x-btn-disabled):hover { + background-color: #338BFF !important; +} + +/* Hide the   inner element on checkmark button */ +.x-btn.x-btn-default-small:has(.fa-check) .x-btn-inner { + display: none !important; +} + +.proxmox-tags-full .proxmox-tag-light, +.proxmox-tags-full .proxmox-tag-dark, +.proxmox-tags-circle .proxmox-tag-light, +.proxmox-tags-circle .proxmox-tag-dark { + outline: 1px solid rgba(0, 0, 0, 0.12); +} + +/* ===================================================== + DATE PICKER (UniFi authentic) + ===================================================== */ +.x-datepicker, +.x-datepicker-column-header, +.x-monthpicker { + background-color: #FFFFFF; + color: #585C66; + border: none; +} + +.x-datepicker-month .x-btn-over.x-btn-default-small { + background-color: #ECEDF0; +} + +.x-monthpicker-months { + border-color: #DDDDE0; +} + +.x-datepicker-header { + background-color: #FFFFFF; +} + +.x-datepicker-date, +.x-monthpicker-item-inner { + color: #585C66; +} + +.x-datepicker-prevday .x-datepicker-date, +.x-datepicker-nextday .x-datepicker-date { + color: #A0A3AB; +} + +.x-datepicker-footer, +.x-monthpicker-buttons { + background-color: #FFFFFF; +} + +.x-datepicker-selected div.x-datepicker-date, +.x-monthpicker-item a.x-monthpicker-selected, +a.x-monthpicker-item-inner:hover, +div.x-datepicker-date:hover { + background-color: #006EFF; + color: #fff; +} + +/* ===================================================== + USAGE BARS - UniFi authentic style + ===================================================== */ +/* v5.31: Reduced border-radius, removed wrapper padding for full-width fill */ +.usage-wrapper { + border: none !important; + border-radius: 2px !important; + background-color: #ECEDF0 !important; + overflow: hidden !important; + padding: 0 !important; +} + +.usage-negative { + background-color: transparent !important; + width: 100% !important; +} + +.usage { + background-color: #37BE5F !important; + border-radius: 2px !important; + width: 100% !important; +} + +/* ===================================================== + CONSOLE / TERMINAL + ===================================================== */ +div.monitor { + border-color: #DDDDE0; +} + +.install-mask { + background-color: #FFFFFF; + color: #585C66; +} + +.x-window.install-mask { + box-shadow: rgba(0, 0, 0, 0.15) 0 4px 20px !important; +} + +/* ===================================================== + OSD TABLE + ===================================================== */ +table.osds tr { + border-color: var(--pm-border); +} + +table.osds td { + border-color: var(--pm-border); +} + +/* ===================================================== + LINKS - UniFi Blue (authentic) + ===================================================== */ +a { + color: var(--pm-accent); +} + +a:hover { + color: var(--pm-accent-hover); +} + +/* ===================================================== + STATUS DOTS (like UniFi - authentic) + ===================================================== */ +/* Proxmox uses ::before for the type icon and ::after for the status glyph. + UniFi style: keep type icon neutral and show a green dot for "running". */ +.x-tree-icon-custom.running::before, +.x-grid-icon-custom.running::before { + color: #585C66 !important; +} + +.x-tree-icon-custom.running::after, +.x-grid-icon-custom.running::after { + content: "\f111" !important; + /* FontAwesome circle */ + font-family: "FontAwesome" !important; + font-size: 9px !important; + line-height: 1 !important; + color: var(--pm-success) !important; + background: transparent !important; + text-shadow: none !important; +} + +/* Align CT/LXC running dot with VM running dot (cube glyph is slightly narrower) */ +.x-tree-icon-custom.fa-cube.running::after, +.x-grid-icon-custom.fa-cube.running::after { + left: -3.8px !important; + right: 3.8px !important; +} + +/* v5.90: Lock icons (migrate, backup, suspend) override running dot + When VM is both running AND locked for operation, show the lock icon instead of green dot */ +.x-tree-icon-custom.running.lock-migrate::after, +.x-grid-icon-custom.running.lock-migrate::after { + content: "\f1d9" !important; /* FontAwesome paper-plane (migrate) */ + font-size: 0.75em !important; + color: var(--pm-warning) !important; /* Amber to indicate operation in progress */ +} + +.x-tree-icon-custom.running.lock-backup::after, +.x-grid-icon-custom.running.lock-backup::after { + content: "\f0c7" !important; /* FontAwesome save/floppy (backup) */ + font-size: 0.75em !important; + color: var(--pm-warning) !important; +} + +.x-tree-icon-custom.running.lock-suspending::after, +.x-grid-icon-custom.running.lock-suspending::after { + content: "\f019" !important; /* FontAwesome download (suspending) */ + font-size: 0.75em !important; + color: var(--pm-warning) !important; +} + +.x-tree-icon-custom.stopped::before, +.x-grid-icon-custom.stopped::before { + color: var(--pm-text-disabled); +} + +/* ===================================================== + SCROLLBARS - Minimal, light (UniFi Light) + v5.93: Increased width from 8px to 12px for better clickability + ===================================================== */ +::-webkit-scrollbar { + width: 12px; + height: 12px; +} + +::-webkit-scrollbar-track { + background: #FFFFFF; +} + +::-webkit-scrollbar-thumb { + background: #D0D1D4; + border-radius: 4px; +} + +::-webkit-scrollbar-thumb:hover { + background: rgba(0, 0, 0, 0.15); +} + +/* v5.84: Style scrollbar corner to match theme (eliminates white square) */ +::-webkit-scrollbar-corner { + background-color: #FFFFFF; +} + +/* ===================================================== + FIX: Labels and grid text - UniFi authentic colors + ===================================================== */ +.x-grid-cell-inner, +.x-grid-cell, +.x-form-display-field, +.x-form-display-field-default, +td, +.x-panel-body-default, +.x-grid-item { + color: #1A1C21 !important; +} + +/* Column headers should be brighter */ +.x-column-header-text, +.x-column-header-text-inner, +.x-column-header-text-default { + color: var(--pm-text-bright) !important; +} + +/* Fix specific grid/table text */ +.x-grid-cell-inner span, +.x-grid-cell-inner div { + color: #1A1C21; +} + +/* Resource panel labels */ +.x-form-item-label-inner { + color: #1A1C21 !important; +} + +/* ===================================================== + FIX: Summary/Stats panels - add borders/cards + ===================================================== */ +.pveStatusPanel, +.x-panel-default-framed, +.x-panel-body-default-framed { + background-color: #FFFFFF !important; + border: 1px solid #DDDDE0 !important; + border-radius: 12px !important; +} + +/* Stats panel body (Status, CPU, Memory, etc) - match Notes panel rounded corners */ +[id^="pveGuestStatusView-"][id$="-body"], +[id^="pmxNotesView-"] .x-panel-body { + border-radius: 8px !important; +} + +/* Panel headers in summary */ +.x-panel-header-default-framed { + background-color: #F6F6F8 !important; + border: none !important; + border-bottom: 1px solid #DDDDE0 !important; + border-radius: 12px 12px 0 0 !important; +} + +/* Summary status grid - the table with CPU/Memory/etc */ +/* FIX v5.18: Removed overflow:hidden to restore content visibility */ +.pve-info-grid { + border-radius: 12px !important; +} + +/* Form display fields in summary (status fields) */ +.x-form-display-field-default { + border-radius: 6px !important; +} + +/* Graph containers - ensure visibility */ +.pve-rrdview, +.rrdview { + background-color: #FFFFFF !important; + border: 1px solid #DDDDE0 !important; + border-radius: 12px !important; + padding: 12px !important; +} + +/* Chart/RRD panel specific - canvas should be transparent for chart lines to show */ +div[id*="rrdchart"], +.pve-rrddatastore, +.pmx-panel-rrd { + background-color: #FFFFFF !important; +} + +/* Canvas elements - don't set background, let charts be visible */ +.proxmox-rrd-panel canvas, +.proxmox-widget-toolkit canvas, +canvas.x-surface, +.x-surface canvas { + background-color: transparent !important; + opacity: 1 !important; +} + +/* Proxmox RRD chart widget - ensure visibility */ +.proxmox-rrd-panel, +.proxmox-rrd-chart { + background-color: #FFFFFF !important; +} + +/* Chart text/labels */ +.x-surface text, +svg text { + fill: #1A1C21 !important; +} + +/* Summary status panel */ +.pve-summary-status, +.x-container .pve-status { + background-color: #FFFFFF !important; + border: 1px solid #DDDDE0 !important; + border-radius: 8px !important; +} + +/* Notes panel */ +.x-panel-default[id*="notes"], +.pve-notes-view { + background-color: #FFFFFF !important; + border: 1px solid #DDDDE0 !important; + border-radius: 8px !important; +} + +/* ===================================================== + FIX: Fieldset and form sections + ===================================================== */ +.x-fieldset { + background-color: #FFFFFF !important; + border: 1px solid #DDDDE0 !important; + border-radius: 8px !important; + padding: 12px !important; +} + +.x-fieldset-header-text { + color: #111217 !important; + font-weight: 500 !important; +} + +/* ===================================================== + FIX: UniFi-style rounded corners on hover/selection + ===================================================== */ + +/* Grid row hover/selection - rounded corners */ +.x-grid-item-over, +.x-grid-item-selected, +.x-grid-with-row-lines .x-grid-item.x-grid-item-over, +.x-grid-with-row-lines .x-grid-item.x-grid-item-selected { + border-radius: 6px !important; +} + +/* Menu items - rounded corners */ +.x-menu-item-default.x-menu-item-focus, +.x-menu-item-default.x-menu-item-active, +.x-menu-item:hover { + border-radius: 6px !important; +} + +/* Treelist/sidebar items - rounded corners (v5.9: 4px to match UniFi) */ +/* Background now handled by ::before pseudo-element in treelist section */ + +/* Boundlist dropdown items - rounded corners (v5.10: 4px to match UniFi) */ +.x-boundlist-item-over, +.x-boundlist-selected { + border-radius: 4px !important; +} + +/* Tab hover - rounded corners */ +.x-tab-default.x-tab-over, +.x-tab-default.x-tab.x-tab-active { + border-radius: 6px 6px 0 0 !important; +} + +/* ===================================================== + FIX: Remove underlines from column headers + ===================================================== */ +.x-column-header-over, +.x-column-header-open, +.x-column-header-sort-ASC, +.x-column-header-sort-DESC, +.x-column-header-last .x-column-header-over .x-column-header-trigger { + border-bottom: none !important; + text-decoration: none !important; +} + +/* Column header text - no underline */ +.x-column-header-text, +.x-column-header-text-inner { + text-decoration: none !important; + border-bottom: none !important; +} + +/* Selected grid cells - no underlines */ +.x-grid-item-selected .x-grid-cell-inner, +.x-grid-item-over .x-grid-cell-inner { + text-decoration: none !important; +} + +/* ===================================================== + FIX: Data view and resource lists + ===================================================== */ +.x-dataview-item { + color: #1A1C21 !important; +} + +/* Resource grid specific */ +.pve-resource-grid .x-grid-cell-inner { + color: #1A1C21 !important; +} + +/* Override any remaining dark text */ +.x-form-item-body, +.x-form-item { + color: #1A1C21 !important; +} + +/* Tree node text */ +.x-tree-node-text { + color: #1A1C21 !important; +} + +.x-treelist-item-text { + color: rgba(0, 0, 0, 0.75) !important; +} + +/* Selected items should be white */ +.x-grid-item-selected .x-grid-cell-inner, +.x-treelist-item-selected .x-treelist-item-text, +.x-tree-selected .x-tree-node-text { + color: #ffffff !important; +} + +/* ===================================================== + FIX: Tab text readability + ===================================================== */ +.x-tab-inner-default { + color: #585C66 !important; +} + +.x-tab-active .x-tab-inner-default { + color: #ffffff !important; +} + +/* ===================================================== + SMOOTH TRANSITIONS - UniFi-style animations + ===================================================== */ + +/* Base transition for all interactive elements */ +.x-btn, +.x-btn-default-small, +.x-btn-default-toolbar-small, +.x-menu-item, +.x-grid-item, +.x-grid-row, +.x-treelist-item, +.x-treelist-row, +.x-tab, +.x-boundlist-item, +.x-tree-node, +.x-dataview-item, +.x-column-header, +.x-form-trigger, +.x-tool, +.x-panel-header { + transition: background-color 0.2s ease, + border-color 0.2s ease, + color 0.2s ease, + box-shadow 0.2s ease, + opacity 0.2s ease !important; +} + +/* Form elements transitions */ +.x-form-trigger-wrap, +.x-form-trigger-wrap-default, +.x-form-text, +.x-form-text-default, +.x-form-field { + transition: border-color 0.2s ease, + box-shadow 0.2s ease, + background-color 0.2s ease !important; +} + +/* Button hover glow effect */ +.x-btn-default-small:hover, +.x-btn-default-small.x-btn-over { + box-shadow: 0 2px 8px rgba(0, 102, 255, 0.2) !important; +} + +/* Toolbar fade moved to Button Section */ + +/* Grid row hover - smooth background change */ +.x-grid-item:hover, +.x-grid-item.x-grid-item-over { + background-color: var(--pm-hover-subtle) !important; +} + +/* Tree item hover - handled by ::before pseudo-element in treelist section */ + +/* Menu item hover */ +.x-menu-item:hover, +.x-menu-item-active { + background-color: #F0F0F2 !important; +} + +/* Tab hover */ +.x-tab:hover, +.x-tab.x-tab-over { + background-color: #F0F0F2 !important; +} + +/* Dropdown item hover - UniFi style */ +.x-boundlist-item:hover, +.x-boundlist-item-over { + background-color: rgba(0, 0, 0, 0.05) !important; + color: #111217 !important; +} + +/* Panel tool icons */ +.x-tool:hover { + opacity: 1 !important; +} + +.x-tool { + opacity: 0.7 !important; +} + +/* Links hover */ +a { + transition: color 0.2s ease !important; +} + +/* Input focus glow */ +.x-form-trigger-wrap-focus, +.x-form-trigger-wrap-default.x-form-trigger-wrap-focus { + box-shadow: 0 0 0 3px var(--pm-focus-ring-color) !important; +} + +/* Selected/active states should also transition smoothly */ +.x-grid-item-selected, +.x-treelist-item-selected>.x-treelist-row, +.x-tab-active { + transition: background-color 0.15s ease !important; +} + +/* Scrollbar smooth transition */ +::-webkit-scrollbar-thumb { + transition: background-color 0.2s ease !important; +} + +/* Progress bar animation */ +.x-progress-bar, +.x-progress-bar-default { + transition: width 0.3s ease !important; +} + +/* Splitter hover */ +.x-splitter { + transition: background-color 0.2s ease !important; +} + +.x-splitter:hover { + background-color: #ECEDF0 !important; +} + +/* Window/dialog fade */ +.x-window { + transition: opacity 0.2s ease, transform 0.2s ease !important; +} + +/* Tooltip fade */ +.x-tip, +.x-tip-default { + transition: opacity 0.15s ease !important; +} + +/* Mask fade */ +.x-mask { + transition: opacity 0.2s ease !important; +} + +/* ===================================================== + v5.1 FIX: Segmented buttons (Day/Hour dropdown) + Only parent should have border-radius, not children + ===================================================== */ +.x-segmented-button { + border-radius: 6px !important; + overflow: visible !important; + display: flex !important; + gap: 5px !important; +} + +.x-segmented-button .x-btn, +.x-segmented-button .x-btn-default-small, +.x-segmented-button .x-btn-inner, +.x-segmented-button .x-btn-wrap { + border-radius: 6px !important; +} + +/* v5.24: Fix segmented buttons - use flex for horizontal alignment with gap */ +.x-segmented-button .proxmox-inline-button, +.x-segmented-button .x-btn { + display: flex !important; +} + +/* v5.25: Pressed segmented button text should be white for visibility on blue background */ +.x-segmented-button .x-btn.x-btn-pressed .x-btn-inner { + color: #ffffff !important; +} + +/* ===================================================== + v5.1 FIX: Progress bars - increase container height + The bars were getting cut off at bottom + ===================================================== */ +.pve-widget-chart-container, +.proxmox-gauge-chart, +.pve-resource-chart, +div[class*="chart-container"], +div[class*="gauge"] { + overflow: visible !important; +} + +/* ===================================================== + v5.1 FIX: Separator between left panel sections + Line between server list (left) and options menu (right) + ===================================================== */ +/* Remove individual item borders */ +.x-treelist-item, +.x-grid-item { + border-bottom: none !important; +} + +/* v5.3 FIX: Single separator between resource tree and content panel */ +/* Remove double separator - only use the splitter */ +#content, +.x-container.x-border-item.x-container-default[id="content"] { + border-left: none !important; +} + + + +/* ===================================================== + v5.1 FIX: Server view dropdown - smaller and styled + ===================================================== */ +.x-btn-default-toolbar-small.x-btn-menu-active, +.x-btn.x-btn-arrow.x-btn-default-small { + padding: 4px 10px !important; + min-height: 26px !important; + font-size: 12px !important; +} + +/* View mode combo/dropdown */ +.x-form-trigger-wrap-default:not([id^="textarea-"]):not(.x-grid-body), +.x-form-trigger-wrap:not([id^="textarea-"]):not(.x-grid-body) { + height: 28px !important; +} + +/* ===================================================== + v5.5 FIX: Preserve parent icon color when children are hovered + ===================================================== */ +/* The selected parent row should ALWAYS have blue icon, regardless of child hover state */ +.x-treelist-item-selected.x-treelist-item-expanded>.x-treelist-row .x-treelist-item-icon { + color: #006EFF !important; +} + +/* Even when entire treelist has hover somewhere, selected parent icon stays blue */ +.x-treelist-item-selected>.x-treelist-row .x-treelist-item-icon { + color: #006EFF !important; +} + +/* ===================================================== + v5.2 FIX: Toolbar buttons - ensure border-radius applies + ===================================================== */ + +/* Toolbar button hover state */ +.x-btn-default-toolbar-small:hover, +.x-btn-default-toolbar-small.x-btn-over { + background-color: #ECEDF0 !important; + border-color: #C0C2C6 !important; +} + +/* Pressed/active state for toolbar buttons */ +.x-btn-default-toolbar-small.x-btn-pressed, +.x-btn-default-toolbar-small.x-btn-menu-active { + background-color: #006EFF !important; + border-color: #006EFF !important; +} + +/* Disabled state for toolbar buttons */ +.x-btn-default-toolbar-small.x-btn-disabled { + opacity: 0.4 !important; + cursor: not-allowed !important; +} + +/* ===================================================== + v5.2 FIX: Pointer cursor on tree items (entire item) + ===================================================== */ +.x-tree-node-text, +.x-grid-item, +.x-grid-cell, +.x-grid-cell-inner, +.x-tree-elbow-img, +.x-tree-icon, +#pveResourceTree .x-grid-item, +#pveResourceTree .x-grid-row, +.x-treelist-item, +.x-treelist-row, +.x-treelist-item-wrap, +.x-treelist-item-text, +.x-treelist-item-icon, +.x-treelistitem { + cursor: pointer !important; +} + +/* ===================================================== + v5.2 FIX: Navigation tree - reduced gaps & centered icons + ===================================================== */ +.x-treelist-item, +.x-treelistitem { + min-height: 28px !important; + height: auto !important; +} + +.x-treelist-row { + min-height: 28px !important; + padding: 2px 0 !important; + margin-right: 4px !important; + /* v5.7: symmetric spacing */ + display: flex !important; + align-items: center !important; +} + +/* v5.33: Reduce margin between toolbox navigation items */ +.x-treelist-pve-nav .x-treelist-row { + margin-top: 2px !important; +} + +/* v5.94: Increased margin-left (20px→28px) for better icon-to-label gap */ +.x-treelist-item-text { + margin-left: 28px !important; + line-height: 24px !important; + display: flex !important; + align-items: center !important; +} + +/* Center icons vertically in tree list */ +.x-treelist-item-icon { + display: flex !important; + align-items: center !important; + justify-content: center !important; + line-height: inherit !important; +} + +.x-treelist-item-wrap { + display: flex !important; + align-items: center !important; +} + +/* ===================================================== + v5.7 FIX: Toolbox tree expand/collapse animation + v5.18 FIX: Only apply animation to child containers, not main nav + ===================================================== */ +/* Main navigation container - must be visible */ +.x-treelist-pve-nav .x-treelist-container { + display: block !important; + overflow: visible !important; + overflow-y: auto !important; +} + +/* Child containers for expand/collapse animation */ +.x-treelist-item>.x-treelist-container { + overflow: hidden !important; + transition: max-height 0.25s ease-out, opacity 0.2s ease-out !important; +} + +/* Expanded state - show children */ +.x-treelist-item-expanded>.x-treelist-container { + max-height: 500px !important; + opacity: 1 !important; +} + +/* Collapsed state - hide children with animation */ +.x-treelist-item-collapsed>.x-treelist-container { + max-height: 0 !important; + opacity: 0 !important; +} + +/* ===================================================== + v5.9 FIX: Consistent 4px border-radius on treelist items (UniFi-style) + Note: Treelist hover/selected now handled by ::before pseudo-element + ===================================================== */ + +/* v5.54: Force 4px border-radius on treelist items and containers + (overrides default 8px from widget-toolkit) */ +.x-treelist-item-wrap, +.x-treelist-item-text, +.x-treelist-row, +.x-treelist-container, +.x-treelist-root-container, +.x-treelist, +.x-treelist-pve-nav { + border-radius: 4px !important; +} + +/* Resource tree selections - consistent 8px */ +.x-grid-item-selected, +.x-grid-item-focused, +.x-grid-item-over { + border-radius: 8px !important; +} + +/* v5.5 FIX: Symmetric wrap padding for treelist items */ +.x-treelist-item-wrap { + padding-left: 2px !important; + padding-right: 2px !important; +} + +/* v5.5 FIX: Same symmetric padding for selected items (no longer needs compensation) */ +.x-treelist-item-selected>.x-treelist-row .x-treelist-item-wrap { + padding-left: 2px !important; + padding-right: 2px !important; +} + +/* v5.5 FIX: Add left margin to icon for visual balance */ +.x-treelist-item-icon { + margin-left: 4px !important; +} + +/* ===================================================== + v5.2 FIX: Remove blue focus box on grid items + ===================================================== */ +.x-keyboard-mode .x-grid-cell-inner::before, +.x-grid-item-focused .x-grid-cell-inner::before, +.x-grid-cell-inner::before { + content: none !important; + border: none !important; + display: none !important; +} + +/* Remove focus outline */ +.x-grid-item-focused, +.x-grid-item-focused .x-grid-cell, +.x-grid-item-focused .x-grid-cell-inner { + outline: none !important; + box-shadow: none !important; +} + +/* ===================================================== + v5.2 FIX: Font weight for Datacenter and Node items only + ===================================================== */ +.fa-server~.x-tree-node-text, +.fa-building~.x-tree-node-text { + font-weight: 600 !important; +} + +/* ===================================================== + v5.2 FIX: Global smooth scrolling + ===================================================== */ +html { + scroll-behavior: smooth !important; +} + +/* ===================================================== + v5.4 FIX: Child items styling when parent is selected + ===================================================== */ +/* Reset text/icon color for non-selected children of selected parent */ +.x-treelist-item-selected .x-treelist-item:not(.x-treelist-item-selected) .x-treelist-item-text, +.x-treelist-item-selected .x-treelist-item:not(.x-treelist-item-selected) .x-treelist-item-icon { + color: #585C66 !important; +} + +/* ===================================================== + v5.4 FIX: Remove double separator between panels + ===================================================== */ +#pveResourceTree-1011-body, +.pve-resource-tree .x-panel-body, +.x-panel-body.x-grid-body { + border-right: none !important; +} + +/* ===================================================== + v5.4 FIX: Hover state for tree items + ===================================================== */ +/* Hover background for normal items */ +.x-treelist-item-over>.x-treelist-row { + background-color: #F0F0F2 !important; +} + +/* Hover background for child items inside selected parent - higher specificity */ +.x-treelist-item-selected .x-treelist-item.x-treelist-item-over:not(.x-treelist-item-selected)>.x-treelist-row { + background-color: #F0F0F2 !important; +} + +/* Hover text/icon color */ +.x-treelist-item-over>.x-treelist-row .x-treelist-item-text, +.x-treelist-item-over>.x-treelist-row .x-treelist-item-icon, +.x-treelist-item-selected .x-treelist-item.x-treelist-item-over:not(.x-treelist-item-selected)>.x-treelist-row .x-treelist-item-text, +.x-treelist-item-selected .x-treelist-item.x-treelist-item-over:not(.x-treelist-item-selected)>.x-treelist-row .x-treelist-item-icon { + color: #1A1C21 !important; +} + +/* ===================================================== + v5.4 FIX: Resource tree (grid) - left sidebar styling + ===================================================== */ +/* Server View resource tree is not a table: disable table row separators */ +[id^="pveResourceTree-"].x-tree-panel td.x-grid-cell, +[id^="pveResourceTree-"].x-tree-panel .x-grid-td, +[id^="pveResourceTree-"].x-tree-panel .x-grid-cell { + border-bottom: none !important; +} + +/* Server View resource tree: compact VM/CT leaf rows (verified via DevTools) */ +[id^="pveResourceTree-"].x-tree-panel tr.x-grid-row.x-grid-tree-node-leaf .x-grid-cell-inner, +[id^="pveResourceTree-"].x-tree-panel .x-grid-item.x-grid-tree-node-leaf .x-grid-cell-inner { + padding-top: 2px !important; + padding-bottom: 2px !important; +} + +/* Server View resource tree: prevent last-leaf indent shift (x-tree-elbow-end has extra margin) */ +[id^="pveResourceTree-"].x-tree-panel .x-tree-elbow-end { + margin-right: 0 !important; +} + +[id^="pveResourceTree-"].x-tree-panel tr.x-grid-row.x-grid-tree-node-leaf .x-tree-node-text, +[id^="pveResourceTree-"].x-tree-panel .x-grid-item.x-grid-tree-node-leaf .x-tree-node-text { + line-height: 17px !important; +} + +/* Non-selected items should show gray text */ +.x-grid-item:not(.x-grid-item-selected):not(.x-grid-item-focused) .x-tree-node-text { + color: #585C66 !important; +} + +/* Non-selected item icons should be gray */ +.x-grid-item:not(.x-grid-item-selected):not(.x-grid-item-focused) .x-tree-icon, +.x-grid-item:not(.x-grid-item-selected):not(.x-grid-item-focused) .fa { + color: #585C66 !important; +} + +/* v5.94: Preserve status icon colors in grid items + The broad .fa color rule above overrides .good/.warning/.critical from ext6-pmx.css */ +.x-grid-item:not(.x-grid-item-selected):not(.x-grid-item-focused) .fa.good { + color: var(--pm-success) !important; +} +.x-grid-item:not(.x-grid-item-selected):not(.x-grid-item-focused) .fa.warning { + color: var(--pm-warning) !important; +} +.x-grid-item:not(.x-grid-item-selected):not(.x-grid-item-focused) .fa.critical { + color: var(--pm-error) !important; +} + +/* Selected item text should be white */ +.x-grid-item-selected .x-tree-node-text, +.x-grid-item-focused .x-tree-node-text { + color: #FFFFFF !important; +} + +/* Selected item icons should be blue */ +.x-grid-item-selected .x-tree-icon, +.x-grid-item-selected .fa, +.x-grid-item-focused .x-tree-icon, +.x-grid-item-focused .fa { + color: #0062D6 !important; +} + +/* Hover state for grid items - text stays primary color */ +.x-grid-item-over:not(.x-grid-item-selected) .x-tree-node-text { + color: #1A1C21 !important; +} + +/* Hover state for grid items - icons color */ +.x-grid-item-over:not(.x-grid-item-selected) .x-tree-icon, +.x-grid-item-over:not(.x-grid-item-selected) .fa { + color: #1A1C21 !important; +} + + + + + + + + + +/* Content panel margin for splitter spacing */ +#content { + margin-left: 6px !important; +} + +/* ===================================================== + CHARTS - Remove border-radius from data area only + (Outer panel container keeps its rounded corners) + ===================================================== */ +/* Remove border-radius from chart canvas/data area ONLY */ +canvas.x-surface-canvas, +.x-surface-canvas, +.x-draw-component canvas, +.proxmox-rrd-chart canvas { + border-radius: 0 !important; +} + +/* SVG surface if used */ +svg.x-surface { + border-radius: 0 !important; +} + +/* Draw container that holds the canvas */ +.x-draw-container, +.x-surface { + border-radius: 0 !important; +} + +/* ===================================================== + HEADER BUTTONS - Vertical centering fix + ===================================================== */ +/* Button flex styles moved to Button Section */ + +/* Documentation button */ +.proxmox-inline-button { + height: 28px !important; + min-height: 28px !important; + display: flex !important; + align-items: center !important; + padding: 3px 8px !important; +} + +/* Specific fix for fa-desktop icon (Create VM) - visually bottom-heavy */ +.x-btn-icon-el.fa-desktop { + transform: translateY(1.1px) !important; +} + +/* v5.27: Fix icon-only button width (hide   inner element) - MUST be at end to override earlier rules */ +/* ExtJS adds x-btn-no-text class to buttons with only an icon */ +.x-btn-no-text .x-btn-inner, +.x-btn-button.x-btn-no-text .x-btn-inner, +.x-btn-button-default-toolbar-small.x-btn-no-text .x-btn-inner-default-toolbar-small, +.x-btn-button-default-small.x-btn-no-text .x-btn-inner-default-small, +.x-btn-button-default-small.x-btn-no-text>.x-btn-inner-default-small, +.x-btn.x-btn-default-small .x-btn-button.x-btn-no-text .x-btn-inner { + display: none !important; +} + +/* ===================================================== + v5.18 FIX: Scroll and overflow fixes for content visibility + ===================================================== */ +/* FIX 1: Remove overflow:hidden from grid containers to restore content visibility */ +.pve-info-grid, +.x-panel-default .x-grid, +.x-container .x-grid-view { + overflow: visible !important; + overflow-y: auto !important; +} + +/* FIX 2: Vertical toolbar scrolling with hidden scrollbar */ +.x-toolbar.x-vertical .x-box-scroller-body-vertical { + overflow-y: auto !important; + overflow-x: hidden !important; + scrollbar-width: none !important; + -ms-overflow-style: none !important; +} + +/* Hide scrollbar for Chrome/Safari/Opera */ +.x-toolbar.x-vertical .x-box-scroller-body-vertical::-webkit-scrollbar { + display: none !important; + width: 0 !important; +} + +/* FIX 3: Make sure the vertical toolbar doesn't hide overflow */ +.x-toolbar.x-vertical { + overflow: visible !important; + overflow-y: visible !important; +} + +/* ===================================================== + v5.35 FIX: Center "IPs" label vertically with IP addresses + Works together with v5.87 button repositioning + ===================================================== */ +/* IPs label container - translate down 9px for vertical centering */ +[id^="pveIPViewLXC-"]>.x-box-inner>.x-box-target>[id^="box-"] { + transform: translateY(9px) !important; +} + +/* ===================================================== + v5.18 FIX: CRITICAL - Restore grid/tree content visibility + These must be at the END of the file to override earlier rules + ===================================================== */ +/* Remove overflow:hidden that was hiding grid content */ +.pve-info-grid, +.x-panel-default .x-grid, +.x-container .x-grid-view, +.x-tree-view, +.x-tree-panel .x-panel-body, +.x-grid-view { + overflow: visible !important; +} + +/* Tree/grid scroll containers */ +.x-tree-view.x-fit-item, +.x-grid-view.x-fit-item { + overflow: auto !important; +} + +/* Grid item containers must be visible */ +.x-grid-item-container { + overflow: visible !important; +} + +/* ===================================================== + v5.57: Fix summary page widget panels border-radius + Column-layout panels (Health, Guests, Resources, etc.) + have visible borders that need rounded corners to + match the parent panel's 8px radius. + ===================================================== */ +.x-panel.x-column>.x-panel-bodyWrap>.x-panel-body.x-panel-body-default { + border-radius: 8px !important; +} + +/* Tree navigation container */ +.x-treelist-pve-nav .x-treelist-container { + overflow: visible !important; + overflow-y: auto !important; +} + +/* ===================================================== + v5.40: Fix floating grid picker border-radius + Storage dropdown, ISO selector, etc. use grid layers + Should match 4px boundlist style, not 12px summary panels + ===================================================== */ +.x-layer.x-grid .x-grid-view, +.x-panel.x-layer.x-grid .x-grid-view { + border-radius: 4px !important; +} + +.x-panel.x-layer.x-grid, +.x-layer.x-panel.x-grid { + border-radius: 4px !important; +} + +/* Grid items in floating pickers - 4px radius (matches boundlist style) */ +.x-layer.x-grid .x-grid-item-over, +.x-layer.x-grid .x-grid-item-selected, +.x-panel.x-layer.x-grid .x-grid-item-over, +.x-panel.x-layer.x-grid .x-grid-item-selected { + border-radius: 4px !important; +} + +/* TD cells have their own background - reset and apply only to first/last */ +.x-layer.x-grid .x-grid-item-over td, +.x-layer.x-grid .x-grid-item-selected td, +.x-layer.x-grid .x-grid-item-over .x-grid-cell, +.x-layer.x-grid .x-grid-item-selected .x-grid-cell, +.x-panel.x-layer.x-grid .x-grid-item-over td, +.x-panel.x-layer.x-grid .x-grid-item-selected td, +.x-panel.x-layer.x-grid .x-grid-item-over .x-grid-cell, +.x-panel.x-layer.x-grid .x-grid-item-selected .x-grid-cell { + border-radius: 0 !important; +} + +/* First cell gets left radius, last cell gets right radius */ +.x-layer.x-grid .x-grid-item-over td:first-child, +.x-layer.x-grid .x-grid-item-selected td:first-child, +.x-panel.x-layer.x-grid .x-grid-item-over td:first-child, +.x-panel.x-layer.x-grid .x-grid-item-selected td:first-child { + border-radius: 4px 0 0 4px !important; +} + +.x-layer.x-grid .x-grid-item-over td:last-child, +.x-layer.x-grid .x-grid-item-selected td:last-child, +.x-panel.x-layer.x-grid .x-grid-item-over td:last-child, +.x-panel.x-layer.x-grid .x-grid-item-selected td:last-child { + border-radius: 0 4px 4px 0 !important; +} + +/* ===================================================== + v5.42: Fix Bulk Actions dropdown button issues + Button was growing larger (24px → 26px) and text was gray instead of white + ===================================================== */ + +/* Toolbar menu fix moved to Button Section */ + +/* ===================================================== + v5.43: Compact tab bar for Tasks/Cluster log panel + Reduces wasted vertical space in bottom panel tabs + Tab bar height: 36px → 26px, padding: 6px → 3px + ===================================================== */ + +/* Reduce tab bar height for south panel (Tasks/Cluster log) */ +.x-panel.x-border-item .x-tab-bar.x-docked.x-tab-bar-default-horizontal { + height: 26px !important; +} + +/* Reduce inner body padding */ +.x-panel.x-border-item .x-tab-bar.x-docked .x-box-inner { + padding-top: 3px !important; + padding-bottom: 3px !important; +} + +/* Adjust panel body position to account for smaller tab bar */ +/* v5.56: Exclude grids - they need ExtJS inline positioning for proper header display */ +/* .x-panel.x-border-item:not(.x-grid) .x-panel-body.x-panel-body-default { + top: 26px !important; +} */ + +/* ===================================================== + v5.72: COMPREHENSIVE MODAL SPACING & CLIPPING FIX + + Problem: The v5.43 rule (top: 26px for south panel tabs) cascaded + to ALL panel bodies inside dialogs/windows, creating 52-70px gaps + between title/tabs and tabs/content, plus content clipping. + + Solution: Reset ALL panel bodies to 0, then restore 26px ONLY for + the body that immediately follows a tab bar (using sibling selector). + Uses ultra-high specificity with 'body' prefix to win CSS battles. + ===================================================== */ + +/* Restore 26px ONLY for the panel body that immediately follows a tab bar */ +body .x-window .x-panel .x-panel-bodyWrap>.x-tab-bar+.x-panel-body.x-panel-body-default { + top: 26px !important; +} + +/* Zero out padding in bodyWraps that could cause extra gaps */ +.x-window .x-panel-bodyWrap { + padding: 0 !important; +} + +/* v5.93: REMOVED overflow: visible rule that was breaking log viewer scrolling + The original rule was: + .x-window .x-panel-body { overflow: visible !important; } + This was added to "fix overflow clipping - allow visible overflow in modal panels" + but it breaks task viewer / log viewer scroll functionality. + If clipping issues appear elsewhere, use more targeted selectors. +*/ + +/* But keep auto overflow on the main window body for scrolling */ +/* .x-window .x-window-body { + overflow: auto !important; +} */ + +/* ===================================================== + v5.58: Fix modal form field width overflow + Form fields were extending past the right edge of the modal. + Constrain autocontainer and trigger wrap widths. + v5.64: REMOVED margin-right rule - was causing input field cutoff. + The autocontainer constraint is sufficient for overflow prevention. + + +/* v5.61: Trigger-wrap width rule removed (consolidated into form layout section) */ + + + +/* ===================================================== + v5.47: Restore right border on disk list panel in wizards + Restores right border for grids inside windows (fixed v5.4 over-reach). + ===================================================== */ + + +/* ===================================================== + v5.48: MODAL ANIMATIONS - Open Animation + Background Blur + CSS-ONLY implementation (no JavaScript required) + + Features: + - Smooth fade-in + scale animation when modals/dialogs open + - Subtle backdrop blur effect for modern look + - Menu/dropdown slide-in animation + + NOTE: Close animations are NOT possible with pure CSS because + ExtJS removes the window from the DOM immediately on close. + This is a pure CSS theme - no JavaScript modifications. + ===================================================== */ + +/* Opening animation keyframe */ +@keyframes modalFadeIn { + from { + opacity: 0; + transform: scale(0.95) translateY(-10px); + } + + to { + opacity: 1; + transform: scale(1) translateY(0); + } +} + +/* Menu slide animation keyframe */ +@keyframes menuSlideIn { + from { + opacity: 0; + transform: translateY(-5px); + } + + to { + opacity: 1; + transform: translateY(0); + } +} + + + +/* Window/Dialog - open animation */ +.x-window, +.x-window-default { + animation: modalFadeIn 0.2s ease-out forwards !important; + transform-origin: center top !important; +} + +/* Message boxes - centered origin */ +.x-message-box { + animation: modalFadeIn 0.2s ease-out forwards !important; + transform-origin: center center !important; +} + +/* Menus and dropdowns - slide animation */ +.x-menu, +.x-menu-default, +.x-boundlist { + animation: menuSlideIn 0.12s ease-out forwards !important; + transform-origin: top center !important; +} + +/* ===================================================== + v5.77: TREE SETTINGS DIALOG FIX + Force layout recalculation and visibility for tree settings + ===================================================== */ +.x-window[id^="pveTreeSettingsEdit"] .x-panel-body { + width: 100% !important; + min-width: 300px !important; +} + +.x-window[id^="pveTreeSettingsEdit"] .x-autocontainer-innerCt { + width: 100% !important; + display: block !important; +} + +.x-window[id^="pveTreeSettingsEdit"] .x-window-body { + overflow: visible !important; + height: auto !important; +} + +.x-window[id^="pveTreeSettingsEdit"] input { + width: 100% !important; + visibility: visible !important; + display: block !important; + opacity: 1 !important; +} + +.x-window[id^="pveTreeSettingsEdit"] .x-form-item-body, +.x-window[id^="pveTreeSettingsEdit"] .x-form-trigger-wrap, +.x-window[id^="pveTreeSettingsEdit"] .x-form-text-wrap { + width: 100% !important; + overflow: visible !important; +} + +/* v5.82: Fix Tree Settings Dialog Width (Force full width on containers) */ +.x-window[id^="pveTreeSettingsEdit"] .x-panel[id^="inputpanel"], +.x-window[id^="pveTreeSettingsEdit"] .x-panel[id^="inputpanel"] .x-panel-body, +.x-window[id^="pveTreeSettingsEdit"] .x-panel[id^="inputpanel"] .x-box-inner, +.x-window[id^="pveTreeSettingsEdit"] .x-panel[id^="inputpanel"] .x-box-target, +.x-window[id^="pveTreeSettingsEdit"] .x-panel[id^="inputpanel"] .x-container, +.x-window[id^="pveTreeSettingsEdit"] .x-panel[id^="inputpanel"] .x-field { + width: 100% !important; + box-sizing: border-box !important; +} + +/* ===================================================== + v5.78: LOGIN DIALOG FIXES + 1. Remove inner panel borders for cleaner "direct on window" look + 2. Rely on ExtJS natural sizing (facilitated by removing the + width:inherit rule above) + ===================================================== */ +.x-window:has(#pveloginrealm) .x-panel-body { + border: none !important; + background: transparent !important; + width: auto !important; +} + +/* ===================================================== + v5.81: VM WIZARD WIDTH FIX (REVISED) + 1. Keep window borders (user preference). + 2. Force internal elements to fit the measured content width + (718.4px) instead of overflowing at fixed 720px. + ===================================================== */ +.x-window[id^="pveQemuCreateWizard"] .x-window-body, +.x-window[id^="pveQemuCreateWizard"] .x-window-body>.x-panel, +.x-window[id^="pveQemuCreateWizard"] .x-panel-bodyWrap, +.x-window[id^="pveQemuCreateWizard"] .x-panel-body { + width: 100% !important; + box-sizing: border-box !important; +} + +/* ===================================================== + v5.86: TOOL ICONS - FontAwesome Replacements + Replace sprite-based ExtJS tool icons with crisp + FontAwesome icons for better consistency and clarity + ===================================================== */ + +/* Base styling for all tool icons - remove sprite backgrounds */ +.x-tool-tool-el.x-tool-minus, +.x-tool-img.x-tool-minus, +.x-tool-tool-el.x-tool-collapse-right, +.x-tool-img.x-tool-collapse-right, +.x-tool-tool-el.x-tool-collapse-left, +.x-tool-img.x-tool-collapse-left, +.x-tool-tool-el.x-tool-expand-right, +.x-tool-img.x-tool-expand-right, +.x-tool-tool-el.x-tool-expand-left, +.x-tool-img.x-tool-expand-left, +.x-tool-tool-el.x-tool-maximize, +.x-tool-img.x-tool-maximize, +.x-tool-tool-el.x-tool-restore, +.x-tool-img.x-tool-restore, +.x-tool-tool-el.x-tool-gear, +.x-tool-img.x-tool-gear, +.x-tool-tool-el.x-tool-refresh, +.x-tool-img.x-tool-refresh { + background-image: none !important; + font-family: "FontAwesome" !important; + font-size: 14px !important; + line-height: 16px !important; + text-align: center !important; + color: #A0A3AB !important; + transition: color 0.15s ease !important; + filter: none !important; + width: 16px !important; + height: 16px !important; + display: flex !important; + align-items: center !important; + justify-content: center !important; +} + +/* Undo Zoom button (minus icon) - use zoom-out icon */ +.x-tool-tool-el.x-tool-minus::before, +.x-tool-img.x-tool-minus::before { + content: "\f010" !important; /* fa-search-minus (zoom out) */ +} + +/* Collapse right - single chevron pointing right (>) + Panel is expanded, clicking will collapse it to the right */ +.x-tool-tool-el.x-tool-collapse-right::before, +.x-tool-img.x-tool-collapse-right::before { + content: "\f054" !important; /* fa-chevron-right (>) */ +} + +/* Expand left - single chevron pointing left (<) + Panel is collapsed on right, clicking will expand it to the left */ +.x-tool-tool-el.x-tool-expand-left::before, +.x-tool-img.x-tool-expand-left::before { + content: "\f053" !important; /* fa-chevron-left (<) */ +} + +/* Collapse left - single chevron pointing left (<) + Panel is expanded, clicking will collapse it to the left */ +.x-tool-tool-el.x-tool-collapse-left::before, +.x-tool-img.x-tool-collapse-left::before { + content: "\f053" !important; /* fa-chevron-left (<) */ +} + +/* Expand right - single chevron pointing right (>) + Panel is collapsed on left, clicking will expand it to the right */ +.x-tool-tool-el.x-tool-expand-right::before, +.x-tool-img.x-tool-expand-right::before { + content: "\f054" !important; /* fa-chevron-right (>) */ +} + +/* Maximize (expand icon) */ +.x-tool-tool-el.x-tool-maximize::before, +.x-tool-img.x-tool-maximize::before { + content: "\f065" !important; /* fa-expand */ +} + +/* Restore (compress icon) */ +.x-tool-tool-el.x-tool-restore::before, +.x-tool-img.x-tool-restore::before { + content: "\f066" !important; /* fa-compress */ +} + +/* Gear/Settings icon */ +.x-tool-tool-el.x-tool-gear::before, +.x-tool-img.x-tool-gear::before { + content: "\f013" !important; /* fa-cog */ +} + +/* Refresh icon */ +.x-tool-tool-el.x-tool-refresh::before, +.x-tool-img.x-tool-refresh::before { + content: "\f021" !important; /* fa-refresh */ +} + +/* Hover state - all tool icons */ +.x-tool:hover .x-tool-tool-el.x-tool-minus, +.x-tool:hover .x-tool-img.x-tool-minus, +.x-tool:hover .x-tool-tool-el.x-tool-collapse-right, +.x-tool:hover .x-tool-img.x-tool-collapse-right, +.x-tool:hover .x-tool-tool-el.x-tool-collapse-left, +.x-tool:hover .x-tool-img.x-tool-collapse-left, +.x-tool:hover .x-tool-tool-el.x-tool-expand-right, +.x-tool:hover .x-tool-img.x-tool-expand-right, +.x-tool:hover .x-tool-tool-el.x-tool-expand-left, +.x-tool:hover .x-tool-img.x-tool-expand-left, +.x-tool:hover .x-tool-tool-el.x-tool-maximize, +.x-tool:hover .x-tool-img.x-tool-maximize, +.x-tool:hover .x-tool-tool-el.x-tool-restore, +.x-tool:hover .x-tool-img.x-tool-restore, +.x-tool:hover .x-tool-tool-el.x-tool-gear, +.x-tool:hover .x-tool-img.x-tool-gear, +.x-tool:hover .x-tool-tool-el.x-tool-refresh, +.x-tool:hover .x-tool-img.x-tool-refresh { + color: #1A1C21 !important; +} + +/* Disabled state */ +.x-tool-disabled .x-tool-tool-el, +.x-tool-disabled .x-tool-img { + opacity: 0.4 !important; + cursor: default !important; +} + +/* ===================================================== + v5.86: GENERIC TOOL ICONS (Inline FontAwesome) + Some ExtJS tools use inline style="font-family:FontAwesome" + with text content for their icons instead of ::before + ===================================================== */ + +/* Style generic tools that use text content with FontAwesome */ +.x-tool-tool-el[style*="font-family:FontAwesome"], +.x-tool-tool-el[style*="font-family: FontAwesome"] { + color: #A0A3AB !important; + font-size: 14px !important; + line-height: 16px !important; + display: flex !important; + align-items: center !important; + justify-content: center !important; + width: 16px !important; + height: 16px !important; + transition: color 0.15s ease !important; + background-image: none !important; + background-color: transparent !important; +} + +/* Enabled state - pointer cursor */ +.x-tool:not(.x-tool-disabled) .x-tool-tool-el[style*="font-family:FontAwesome"], +.x-tool:not(.x-tool-disabled) .x-tool-tool-el[style*="font-family: FontAwesome"] { + cursor: pointer !important; +} + +/* Disabled state - default cursor and reduced opacity */ +.x-tool.x-tool-disabled .x-tool-tool-el[style*="font-family:FontAwesome"], +.x-tool.x-tool-disabled .x-tool-tool-el[style*="font-family: FontAwesome"] { + cursor: default !important; + opacity: 0.4 !important; +} + +/* Fix mask overlay on tool icons - transparent and non-blocking */ +.x-tool .x-mask { + background-color: transparent !important; + backdrop-filter: none !important; + pointer-events: none !important; +} + +/* Hover state for enabled generic tools */ +.x-tool:not(.x-tool-disabled):hover .x-tool-tool-el[style*="font-family:FontAwesome"], +.x-tool:not(.x-tool-disabled):hover .x-tool-tool-el[style*="font-family: FontAwesome"] { + color: #1A1C21 !important; +} diff --git a/themes/theme-unifi.css b/themes/theme-unifi.css new file mode 100644 index 0000000..e0a6a23 --- /dev/null +++ b/themes/theme-unifi.css @@ -0,0 +1,3951 @@ +/*!UniFi*/ +/* + * ProxMorph Theme: UniFi + * Authentic recreation of Ubiquiti UniFi Network Application UI + * Version: 5.94 + * Author: N.E.S.T. / Dr. Dranglog + * + * UniFi Color Palette (extracted from live instance): + * + * BACKGROUNDS: + * - Base/Body: #131416 (rgb 19,20,22) - main dark background + * - Header: #282B2F (rgb 40,43,47) - top navigation bar + * - Hover solid: #34383D (rgb 52,56,61) - button hover + * - Hover subtle: rgba(249, 250, 250, 0.02) - row hover + * - Hover medium: rgba(249, 250, 250, 0.04) - tertiary hover + * - Hover strong: rgba(249, 250, 250, 0.07) - input hover + * + * TEXT COLORS: + * - Primary: #DEE0E3 (rgb 222,224,227) - main text + * - Secondary: #B7BCC2 (rgb 183,188,194) - labels + * - Bright: #F9FAFA (rgb 249,250,250) - headings/emphasis + * - Muted: rgba(255, 255, 255, 0.65) - sidebar text + * - Tertiary: #737C87 (rgb 115,124,135) - disabled/hints + * + * ACCENT COLORS: + * - Primary Blue: #006EFF - links, active states + * - Blue Hover: #4797FF (rgb 71,151,255) + * - Success: #37BE5F (rgb 55,190,95) + * - Warning: #f5a623 + * - Danger: #f03a3e + * + * CSS VARIABLES (official Ubiquiti): + * - --ubnt-color-DN60: #151725 (darkest neutral) + * - --ubnt-color-DN50: #242635 (card background) + * - --ubnt-color-primary: #006fff + */ + +/* ===================================================== + CSS VARIABLES + ===================================================== */ +:root { + /* UniFi design tokens (only the ones actually used) */ + --ubnt-color-primary: #006fff; + --ubnt-color-danger: #f03a3e; + --ubnt-color-warning: #f5a623; + --ubnt-color-success: #39cc64; + + /* ProxMorph semantic variables */ + --pm-accent: #006EFF; + --pm-accent-hover: #4797FF; + --pm-accent-active: #0058cc; + + --pm-success: #37BE5F; + --pm-warning: var(--ubnt-color-warning); + --pm-error: var(--ubnt-color-danger); + + /* Base palette tuned to Proxmox UI (keeps existing theme look) */ + --pm-bg-base: #131416; + --pm-bg-surface: #282B2F; + --pm-bg-elevated: #34383D; + + --pm-border: #34383D; + --pm-border-strong: #444444; + + --pm-text: #DEE0E3; + --pm-text-dim: #B7BCC2; + --pm-text-muted: #B7BCC2; + --pm-text-disabled: #737C87; + --pm-text-bright: #F9FAFA; + + --pm-hover-subtle: rgba(249, 250, 250, 0.02); + --pm-hover-medium: rgba(249, 250, 250, 0.04); + --pm-hover-strong: rgba(249, 250, 250, 0.07); + + --pm-radius-sm: 4px; + --pm-radius-md: 6px; + --pm-radius-lg: 8px; + --pm-radius-xl: 12px; + + --pm-focus-ring-color: rgba(0, 111, 255, 0.15); + + /* Proxmox widget toolkit variables */ + --pwt-panel-background: var(--pm-bg-base); + --pwt-text-color: var(--pm-text-dim); + --pwt-gauge-default: var(--pm-accent-hover); + --pwt-gauge-back: var(--pm-bg-elevated); + --pwt-gauge-warn: var(--pm-warning); + --pwt-gauge-crit: var(--pm-error); + --pwt-chart-primary: var(--pm-success); + --pwt-chart-grid-stroke: var(--pm-border); + + color-scheme: dark; +} + +/* ===================================================== + GLOBAL BORDER-BOX ROUNDED CORNERS (UniFi style) + ===================================================== */ +.x-border-box, +.x-border-box * { + border-radius: var(--pm-radius-lg); +} + +/* Remove rounded corners from grids/tables/lists (Tasks, logs) */ +.x-grid, +.x-grid *, +.x-grid-header-ct, +.x-grid-header-ct *, +.x-grid-view, +.x-grid-view *, +.x-column-header, +.x-column-header *, +.x-grid-item, +.x-grid-cell, +.x-grid-cell-inner, +.x-grid-row, +table, +table *, +tr, +td, +th, +/* Legend elements - no rounded corners */ +.x-legend, +.x-legend *, +.x-legend-container, +.x-legend-container *, +.x-legend-item, +.x-legend-horizontal .x-legend-item, +.x-legend-vertical .x-legend-item, +.x-legend-horizontal .x-legend-item:first-child, +.x-legend-horizontal .x-legend-item:last-child, +.x-legend-vertical .x-legend-item:first-child, +.x-legend-vertical .x-legend-item:last-child, +/* Tool icons - no rounded corners */ +.x-tool, +.x-tool-tool-el, +.x-tool-default, +.x-tool-img { + border-radius: 0 !important; +} + +/* Form elements - exclude from global 8px, apply 4px (UniFi style) */ +/* Reset ALL form-related parent containers to prevent 8px inheritance */ +.x-form-item, +.x-form-item-default, +.x-form-item-body, +.x-form-item-body-default, +.x-form-text-field-body, +.x-form-text-field-body-default, +.x-form-fieldcontainer, +.x-field, +.x-field-default, +.x-form-type-text { + border-radius: 0 !important; +} + +/* Reset layout containers that clip form elements with overflow:hidden + 8px radius */ +.x-box-layout-ct, +.x-panel-bodyWrap, +.x-panel-bodyWrap-default, +.x-autocontainer-innerCt, +.x-autocontainer-outerCt, +.x-panel.x-tabpanel-child, +.x-panel.x-box-item, +.x-box-inner, +.x-box-target, +.x-container, +.x-container-default, +/* Window/dialog inner bodies - prevent 8px clipping on form elements */ +.x-window .x-panel-body, +.x-window .x-window-body, +.x-window .x-window-bodyWrap { + border-radius: 0 !important; +} + +/* Restore right border for grids inside windows (fixed v5.4 over-reach) */ +.x-window .x-panel-body.x-grid-body { + border-right: 1px solid #34383D !important; +} + +/* ===================================================== + v5.73: WINDOW/MODAL BORDER-RADIUS CONSISTENCY + Reset all children to 0, then re-apply specific radii + to ensure consistent 8px corners on login/modals + ===================================================== */ + +/* 1. Reset everything inside windows to 0 - overrides global x-border-box rule */ +.x-window *, +.x-window .x-autocontainer-innerCt, +.x-window .x-autocontainer-outerCt, +.x-window .x-form-layout-wrap, +.x-window .x-form-layout-auto-label, +.x-window .x-form-layout-colgroup, +.x-window .x-form-layout-column, +.x-window .x-field, +.x-window .x-form-item, +.x-window .x-form-item-body { + border-radius: 0 !important; +} + +/* 2. Window container - consistent 8px with overflow hidden */ +.x-window { + border-radius: 8px !important; + overflow: hidden !important; + min-width: 295px !important; + /* v5.85: Match Proxmox default to prevent scrollbars */ +} + +/* v5.86: Fix dialog header/body not matching dialog width when min-width is applied + Root cause: ExtJS sets inline width on header/body that's smaller than min-width forces. + Solution: Force header/body to use 100% width so they inherit parent's computed width. */ +.x-window > .x-window-header, +.x-window > .x-window-body, +.x-window > .x-window-bodyWrap, +.x-window-bodyWrap > .x-window-body { + width: 100% !important; +} + +/* Ensure box containers inside header use full width */ +.x-window-header > .x-box-inner, +.x-window-header > .x-box-inner > .x-box-target { + width: 100% !important; +} + +/* Header title should expand appropriately */ +.x-window-header-title { + width: auto !important; + flex: 1 !important; + max-width: calc(100% - 30px) !important; +} + +/* 3. Window header - top corners only */ +.x-window-header, +.x-window-header-default { + border-radius: 8px 8px 0 0 !important; +} + +/* 4. Re-apply button styling inside windows (6px) */ +.x-window .x-btn { + border-radius: 6px !important; +} + +/* 5. Re-apply checkbox styling inside windows (4px) */ +.x-window .x-form-checkbox { + border-radius: 4px !important; +} + +/* 6. Re-apply form inputs inside windows (4px with split corners) */ +.x-window .x-form-trigger-wrap, +.x-window .x-form-trigger-wrap-default { + border-radius: 4px !important; +} + +.x-window .x-form-text-wrap, +.x-window .x-form-text { + border-radius: 4px 0 0 4px !important; +} + +.x-window .x-form-arrow-trigger { + border-radius: 0 4px 4px 0 !important; +} + +.x-form-trigger-wrap, +.x-form-trigger-wrap *, +.x-form-text-wrap, +.x-form-text-wrap *, +.x-form-text, +.x-form-trigger { + border-radius: 0 !important; +} + +/* Form element containers - 4px radius (UniFi consistent) */ +.x-form-trigger-wrap, +.x-form-trigger-wrap-default { + border-radius: 4px !important; + overflow: hidden !important; +} + +/* Constrain autocontainer width (Moved from L3450) */ +.x-window .x-autocontainer-outerCt { + max-width: 100% !important; +} + +/* Form text wrap - left side rounded */ +.x-form-text-wrap, +.x-form-text-wrap-default { + border-radius: 4px 0 0 4px !important; +} + +/* Form input text - left side rounded */ +.x-form-text, +.x-form-text-default { + border-radius: 4px 0 0 4px !important; +} + +/* Form trigger button - right side rounded */ +.x-form-trigger, +.x-form-trigger-default, +.x-form-arrow-trigger, +.x-form-arrow-trigger-default { + border-radius: 0 4px 4px 0 !important; +} + +/* Cursor styles for combobox/dropdown elements (pointer indicates clickable) */ +.x-form-trigger-wrap, +.x-form-text-wrap, +.x-form-field[role="combobox"], +input.x-form-text[readonly], +.x-form-trigger, +.x-form-arrow-trigger { + cursor: pointer !important; +} + +/* Cursor for dropdown list items */ +.x-boundlist-item, +.x-boundlist-item-over, +.x-boundlist-selected { + cursor: pointer !important; +} + +/* ===================================================== + BASE / BODY - Authentic UniFi dark background + ===================================================== */ +.x-body { + color: var(--pm-text); + background-color: var(--pm-bg-base); +} + +.x-viewport>.x-body { + background-color: var(--pm-bg-base); +} + +body.x-border-layout-ct, +div.x-border-layout-ct { + background-color: var(--pm-bg-base); +} + +/* ===================================================== + LEGEND / CHARTS - Ensure chart visibility + ===================================================== */ +.x-legend-container { + background-color: var(--pm-bg-base); + border-radius: 0 !important; +} + +.x-legend-horizontal .x-legend-item, +.x-legend-item { + background-color: var(--pm-bg-base); + color: var(--pm-text-muted); + border: none !important; + border-radius: 0 !important; +} + +/* Legend color marker (dot) - keep circular */ +.x-legend-item-marker { + border-radius: 50% !important; +} + +/* Chart canvas and SVG visibility */ +.x-chart, +.rrd-chart canvas, +canvas.x-surface { + opacity: 1 !important; +} + +/* Chart grid lines */ +.x-chart-grid-horizontal line, +.x-chart-grid-vertical line { + stroke: #34383D !important; + stroke-opacity: 1 !important; +} + +/* Chart axis text */ +.x-chart-axis-label { + fill: #B7BCC2 !important; +} + +/* RRDTool charts (Proxmox specific) - ensure PNG charts are visible */ +img.rrdimage, +.rrd-chart img, +div[class*="rrd"] img { + filter: none !important; + opacity: 1 !important; +} + +/* ===================================================== + MASKS & OVERLAYS + ===================================================== */ +.x-mask { + /* v5.48: Background blur + 0.5 opacity */ + backdrop-filter: blur(4px) !important; + -webkit-backdrop-filter: blur(4px) !important; + background-color: rgba(0, 0, 0, 0.5) !important; +} + +/* Disabled field-groups: keep the native "reduced opacity" look (no black mask overlay) */ +.x-item-disabled.x-masked-relative>.x-mask { + background-color: transparent !important; +} + +.x-tool .x-mask { + backdrop-filter: blur(4px); + background-color: #131416; + opacity: 0.6; +} + +/* v5.50: Hide ExtJS shadow element - use pure CSS shadow on window instead */ +.x-css-shadow { + display: none !important; +} + +/* ===================================================== + ICONS - Inverted for dark mode + ===================================================== */ +/* General icons - gray color */ +.fa-tags::before, +.fa-file-o::before, +.fa-building::before, +.x-action-col-icon::before, +.fa-shield::before, +.fa-file-text-o::before, +.fa-clock-o::before, +.x-tab-icon-el-default, +.pve-icon-verify-lettering::after, +.x-tree-icon-custom.lock-migrate::after, +.x-grid-icon-custom.lock-migrate::after, +.x-tree-icon-leaf:not(.x-tree-icon-custom)::before, +.x-tree-icon-parent:not(.x-tree-icon-custom)::before, +.x-tree-icon-parent-expanded:not(.x-tree-icon-custom)::before, +.x-grid-filters-filtered-column .x-column-header-text::after { + color: #B7BCC2; +} + +/* VM/CT icons - default gray, NOT green */ +.x-tree-icon-custom, +.x-grid-icon-custom { + color: #B7BCC2; +} + +.x-tree-icon-parent:not(.x-tree-icon-custom)::before, +.x-tree-icon-parent-expanded:not(.x-tree-icon-custom)::before { + filter: invert(90%); +} + +.fa-ceph::before, +.fa-sdn::before, +.fa-network-wired::before, +.pve-itype-treelist-item-icon-cdrom, +.fa-chevron-right::before, +.x-grid-row-console, +.x-box-scroller-toolbar-default.x-box-scroller, +.x-tree-elbow-img, +.pve-itype-icon-qemu, +.x-tree-node-computer, +.x-grid-tree-node-expanded .x-tree-node-computer, +.pbs-icon-tape, +.pbs-icon-tape-drive, +.x-tree-icon-leaf:not(.x-tree-icon-custom), +.x-tree-icon-parent:not(.x-tree-icon-custom), +.x-tree-icon-parent-expanded:not(.x-tree-icon-custom) { + filter: invert(90%); +} + +/* v5.37: Resource grid icon inversion - tree node icons only + Harddisk tree nodes are SVG background images that need inversion for dark themes */ +.x-tree-node-harddisk, +.x-grid-tree-node-expanded .x-tree-node-harddisk { + filter: invert(90%); +} + +/* Fix #27: Resource grid cells (td.pve-itype-icon-* / td.pmx-itype-icon-*) — remove + filter from TD so text is NOT inverted. Strip original background-image and reconstruct + icon via ::before pseudo-element on .x-grid-cell-inner with filter applied to icon only. + Includes pmx-itype-icon-processor/memory used by LXC Resources tab (PVE 9.x). */ +td.pve-itype-icon-cpu, +td.pve-itype-icon-memory, +td.pve-itype-icon-cdrom, +td.pve-itype-icon-pci, +td.pve-itype-icon-serial, +td.pve-itype-icon-die, +td.pmx-itype-icon-processor, +td.pmx-itype-icon-memory { + filter: none !important; + background-image: none !important; + padding-left: 0px !important; +} + +/* Match FA row inner padding (4px) */ +td.pve-itype-icon-cpu > .x-grid-cell-inner, +td.pve-itype-icon-memory > .x-grid-cell-inner, +td.pve-itype-icon-cdrom > .x-grid-cell-inner, +td.pve-itype-icon-pci > .x-grid-cell-inner, +td.pve-itype-icon-serial > .x-grid-cell-inner, +td.pve-itype-icon-die > .x-grid-cell-inner, +td.pmx-itype-icon-processor > .x-grid-cell-inner, +td.pmx-itype-icon-memory > .x-grid-cell-inner { + padding-left: 4px !important; +} + +/* Inline-block pseudo-element icons — invert only the icon, not the text */ +td.pve-itype-icon-cpu > .x-grid-cell-inner::before, +td.pve-itype-icon-memory > .x-grid-cell-inner::before, +td.pve-itype-icon-cdrom > .x-grid-cell-inner::before, +td.pve-itype-icon-pci > .x-grid-cell-inner::before, +td.pve-itype-icon-serial > .x-grid-cell-inner::before, +td.pve-itype-icon-die > .x-grid-cell-inner::before, +td.pmx-itype-icon-processor > .x-grid-cell-inner::before, +td.pmx-itype-icon-memory > .x-grid-cell-inner::before { + content: '' !important; + display: inline-block !important; + width: 14px !important; + height: 14px !important; + vertical-align: middle !important; + margin-right: 4px !important; + background-size: 14px 14px !important; + background-repeat: no-repeat !important; + background-position: center !important; + filter: invert(90%) !important; +} + +/* Individual icon URLs — pve-itype-icon-* classes are PVE-specific, so use /pve2/images/ + (icon-cpu.svg exists in /pwt/images/ too, but memory/cdrom/pci/serial/die do NOT) */ +td.pve-itype-icon-cpu > .x-grid-cell-inner::before { + background-image: url('/pve2/images/icon-cpu.svg') !important; +} +td.pve-itype-icon-memory > .x-grid-cell-inner::before { + background-image: url('/pve2/images/icon-memory.svg') !important; +} +td.pve-itype-icon-cdrom > .x-grid-cell-inner::before { + background-image: url('/pve2/images/icon-cd-drive.svg') !important; +} +td.pve-itype-icon-pci > .x-grid-cell-inner::before { + background-image: url('/pve2/images/icon-pci.svg') !important; +} +td.pve-itype-icon-serial > .x-grid-cell-inner::before { + background-image: url('/pve2/images/icon-serial.svg') !important; +} +td.pve-itype-icon-die > .x-grid-cell-inner::before { + background-image: url('/pve2/images/icon-die.svg') !important; +} +/* pmx-itype-icon-* use relative paths for PVE+PBS compatibility */ +td.pmx-itype-icon-processor > .x-grid-cell-inner::before { + background-image: url('../images/icon-cpu.svg') !important; +} +td.pmx-itype-icon-memory > .x-grid-cell-inner::before { + background-image: url('../images/icon-ram.svg') !important; +} + +/* v5.38: Summary panel icons (i elements) - reset to original Proxmox styling */ +i.pmx-itype-icon-processor, +i.pmx-itype-icon-memory, +.pmx-icon.pmx-itype-icon-processor, +.pmx-icon.pmx-itype-icon-memory { + filter: invert(90%) !important; + background-repeat: no-repeat !important; + background-position: 3px center !important; + background-size: 14px 14px !important; + padding-left: 18px !important; + position: static !important; +} + +/* v5.94: Use relative paths for PVE+PBS compatibility + PVE serves from /pwt/themes/ → ../images/ resolves to /pwt/images/ + PBS serves from /widgettoolkit/themes/ → ../images/ resolves to /widgettoolkit/images/ */ +i.pmx-itype-icon-processor, +.pmx-icon.pmx-itype-icon-processor { + background-image: url('../images/icon-cpu.svg') !important; +} + +i.pmx-itype-icon-memory, +.pmx-icon.pmx-itype-icon-memory { + background-image: url('../images/icon-ram.svg') !important; +} + +/* Disable ::before pseudo-elements on Summary panel icons */ +i.pmx-itype-icon-processor::before, +i.pmx-itype-icon-memory::before, +.pmx-icon.pmx-itype-icon-processor::before, +.pmx-icon.pmx-itype-icon-memory::before { + content: none !important; + display: none !important; +} + +/* v5.38: Summary panel SWAP and Bootdisk FontAwesome icons - consistent sizing */ +.left-aligned .fa.fa-refresh, +.left-aligned .fa.fa-hdd-o { + font-size: 14px !important; +} + +/* v5.88: Fix "More" button position in IPs section of Summary panel + Move button next to "IPs" label, vertically centered with IP addresses. + Parent containers need overflow:visible because transform moves button outside bounds. + + Key insight: ExtJS positions button at container's right edge (after IP addresses). + Solution: Anchor to top: 0, then use transform to shift button left to "IPs" label. + Value -242px moves button from right edge to just after the 35px "IPs" label. + NOTE: This value may need adjustment if Proxmox UI layout changes. */ +[id^="pveIPViewLXC-"] .x-box-inner, +[id^="pveIPViewLXC-"] > .x-box-inner { + overflow: visible !important; +} + +[id^="pveIPViewLXC-"] [id^="button-"].x-btn { + top: 0 !important; + transform: translate(-242px, 5px) !important; +} + +/* Cell inner content alignment — handled by Fix #27 td.pve-itype-icon-* rules above */ + +/* v5.37: FontAwesome icons in resource grid (Swap, Root Disk) */ +.pve-itype-fa .x-grid-cell-inner { + padding-left: 4px !important; +} + +.pve-itype-fa .pve-grid-fa, +.pve-itype-fa .pve-grid-fa.fa, +.x-grid-item .pve-itype-fa .fa { + color: #DEE0E3 !important; + margin-right: 4px !important; +} + +.x-tree-icon-custom, +.x-grid-icon-custom { + color: #B7BCC2; +} + +/* Running VMs/CTs - type icon neutral; status indicator handled separately */ +.x-tree-icon-custom.running, +.x-grid-icon-custom.running { + color: #B7BCC2; +} + +.x-tree-icon-custom::after, +.x-grid-icon-custom::after { + color: #B7BCC2; + text-shadow: none; +} + +.x-tree-icon-custom.stopped, +.x-tree-icon-custom.offline, +.x-grid-icon-custom.stopped, +.x-grid-icon-custom.offline { + color: #737C87; +} + +.x-tree-icon-custom.lxc::after, +.x-tree-icon-custom.qemu::after, +.x-grid-icon-custom.lxc::after, +.x-grid-icon-custom.qemu::after { + background-color: #131416; + color: #B7BCC2; +} + +/* v5.55: Fix LXC/QEMU icon ::after in treelist navigation */ +.x-treelist-item-icon.lxc::after, +.x-treelist-item-icon.qemu::after { + background-color: transparent !important; + color: #B7BCC2 !important; + margin-top: 4px !important; +} + +.x-tree-arrows .x-tree-expander { + filter: brightness(200%); +} + +/* ===================================================== + v5.6: Custom tree expander arrows (FontAwesome chevrons) + Replaces default sprite arrows with larger, animated icons + ===================================================== */ + +/* Base expander styling - replace sprite with FA icon */ +.x-tree-expander { + background-image: none !important; + position: relative !important; + width: 18px !important; + height: 18px !important; + margin-right: 4px !important; + vertical-align: middle !important; +} + +/* Arrow icon using FontAwesome chevron-right */ +.x-tree-expander::before { + content: "\f054" !important; + /* FA chevron-right */ + font-family: "FontAwesome" !important; + font-size: 11px !important; + color: #737C87 !important; + /* UniFi tertiary/muted color */ + position: absolute !important; + top: -2px !important; + left: 3px !important; + transition: transform 0.2s ease, color 0.15s ease !important; +} + +/* Expanded state - arrow rotates 90 degrees */ +.x-grid-tree-node-expanded .x-tree-expander::before { + transform: rotate(90deg) !important; + color: #B7BCC2 !important; + /* UniFi secondary text */ +} + +/* Collapsed state - no rotation */ +tr:not(.x-grid-tree-node-expanded) .x-tree-expander::before { + transform: rotate(0deg) !important; +} + +/* Hover effect - UniFi blue accent */ +.x-tree-expander:hover::before { + color: #006EFF !important; +} + +/* Gap before node icon */ +.x-tree-icon-parent, +.x-tree-icon-leaf, +.x-tree-icon { + margin-left: 2px !important; +} + +/* Empty elbows - no extra margin */ +.x-tree-elbow-empty, +.x-tree-elbow { + margin-right: 0 !important; +} + +/* ===================================================== + v5.36: CHECKBOXES & RADIO BUTTONS - UniFi Authentic + Extracted from live UniFi Network Application + ===================================================== */ + +/* Remove the old filter-based styling */ +.x-form-checkbox-default, +.x-form-radio-default, +.x-column-header-checkbox .x-column-header-checkbox::after, +.x-grid-checkcolumn::after, +.x-menu-item-checked .x-menu-item-icon-default.x-menu-item-checkbox, +.x-menu-item-unchecked .x-menu-item-icon-default.x-menu-item-checkbox { + filter: none !important; +} + +/* The actual INPUT element that receives clicks - needs pointer cursor */ +.x-form-cb-input { + cursor: pointer !important; +} + +/* CHECKBOXES - Base styling (SPAN element - visual display) */ +.x-form-checkbox, +.x-form-checkbox-default { + display: inline-block !important; + width: 16px !important; + min-width: 16px !important; + height: 16px !important; + min-height: 16px !important; + border-radius: 4px !important; + border: 0.8px solid #737C87 !important; + background-color: rgba(0, 0, 0, 0.01) !important; + background-image: none !important; + cursor: pointer !important; + transition: border-color 0.2s linear, background-color 0.2s linear !important; + position: relative !important; + box-sizing: border-box !important; +} + +/* Checkbox - Checked state */ +.x-form-cb-checked .x-form-checkbox { + border-color: #4797FF !important; + background-color: #4797FF !important; + background-image: none !important; +} + +/* Checkbox checkmark using ::after pseudo-element */ +.x-form-cb-checked .x-form-checkbox::after { + content: '✓' !important; + position: absolute !important; + color: white !important; + font-size: 12px !important; + font-weight: bold !important; + top: 50% !important; + left: 50% !important; + transform: translate(-50%, -50%) !important; + pointer-events: none !important; +} + +/* Checkbox - Hover state */ +.x-form-checkbox:hover, +.x-form-cb:hover .x-form-checkbox, +.x-form-cb-wrap:hover .x-form-checkbox { + border-color: #4797FF !important; +} + +/* RADIO BUTTONS - Base styling */ +.x-form-radio, +.x-form-radio-default { + display: inline-block !important; + width: 16px !important; + min-width: 16px !important; + height: 16px !important; + min-height: 16px !important; + border-radius: 50% !important; + border: 0.8px solid #737C87 !important; + background-color: rgba(0, 0, 0, 0.01) !important; + background-image: none !important; + cursor: pointer !important; + position: relative !important; + transition: border-color 0.2s linear !important; + box-sizing: border-box !important; +} + +/* Radio - Checked state border */ +.x-form-cb-checked .x-form-radio { + border-color: #4797FF !important; + background-color: rgba(0, 0, 0, 0.01) !important; + background-image: none !important; +} + +/* Radio - Inner dot using ::after pseudo-element */ +.x-form-radio::after { + content: '' !important; + position: absolute !important; + top: 50% !important; + left: 50% !important; + width: 6px !important; + height: 6px !important; + border-radius: 50% !important; + background-color: transparent !important; + transform: translate(-50%, -50%) scale(0) !important; + transition: transform 0.2s ease, background-color 0.2s ease !important; + pointer-events: none !important; +} + +/* Radio - Checked inner dot */ +.x-form-cb-checked .x-form-radio::after { + background-color: #4797FF !important; + transform: translate(-50%, -50%) scale(1) !important; +} + +/* Radio - Hover state */ +.x-form-radio:hover, +.x-form-cb-wrap:hover .x-form-radio { + border-color: #4797FF !important; +} + +/* ===================================================== + BUTTONS - Clean, minimal style (UniFi authentic) + ===================================================== */ +/* v5.88: Respect inline display:none - Proxmox hides buttons dynamically and !important was overriding */ +.x-btn-default-small[style*="display: none"], +.x-btn-default-small[style*="display:none"] { + display: none !important; +} + +.x-btn-default-small { + background-color: #006EFF; + border: none; + border-radius: 6px; + padding: 5px 10px !important; + min-height: 26px !important; + /* v5.29: Header buttons (Create VM, Create CT, root@pam) - consistent 28px height with vertical centering */ + /* Exclude tag edit buttons (display:none when hidden, :has(.fa-check) for checkmark) */ + height: 28px !important; + min-height: 28px !important; + display: flex !important; + align-items: center !important; + padding: 3px 8px !important; +} + +.x-btn-default-small .x-btn-inner { + color: #ffffff; + padding: 2px 4px !important; + display: inline-flex !important; + align-items: center !important; +} + +/* Flex container logic (Merged from L3242) */ +.x-btn.x-btn-default-small .x-btn-button { + display: flex !important; + align-items: center !important; + justify-content: center !important; +} + +.x-btn.x-btn-default-small .x-btn-icon-el { + justify-content: center !important; +} + +.x-btn-default-small.x-btn-over, +.x-keyboard-mode .x-btn-default-small.x-btn-focus { + background-color: #338BFF; +} + +/* Pressed state */ +.x-btn-default-small.x-btn-pressed, +.x-btn-default-small.x-btn-menu-active { + background-color: #0056CC; +} + +/* Fix #29: Disabled buttons — explicit muted colors instead of opacity */ +.x-btn-default-small.x-btn.x-btn-disabled { + opacity: 1 !important; + background-color: #003A80 !important; + border-color: #002D66 !important; +} +.x-btn-default-small.x-btn.x-btn-disabled .x-btn-inner { + color: #8A9099 !important; +} + +/* Toolbar Buttons - Compact & Transparent */ +.x-btn-default-toolbar-small { + background-color: transparent; + border: 1px solid #34383D !important; + padding: 4px 8px !important; + border-radius: 4px; +} + +.x-btn-default-toolbar-small .x-btn-inner-default-toolbar-small { + color: #B7BCC2; +} + +.x-btn-default-toolbar-small .x-btn-icon-el-default-toolbar-small { + color: #B7BCC2; +} + +/* v5.8: Toolbar button icon vertical centering fix */ +.x-btn-wrap.x-btn-wrap-default-toolbar-small { + align-items: center !important; +} + +.x-btn-icon-el.x-btn-icon-el-default-toolbar-small { + display: flex !important; + align-items: center !important; + justify-content: center !important; + line-height: 16px !important; + height: 16px !important; +} + +.x-btn-inner.x-btn-inner-default-toolbar-small { + display: flex !important; + align-items: center !important; +} + +.x-btn-default-toolbar-small .x-btn-wrap-default-toolbar-small.x-btn-arrow-right::after, +.x-btn-default-toolbar-small .x-btn-wrap-default-toolbar-small.x-btn-split-right::after { + filter: brightness(150%); +} + +.x-btn-default-toolbar-small.x-btn-over, +.x-keyboard-mode .x-btn-default-toolbar-small.x-btn-focus { + background-color: #34383D; +} + +.x-btn-default-toolbar-small.x-btn.x-btn-disabled { + opacity: 1 !important; + background-color: rgba(40, 43, 47, 0.5) !important; + border-color: #282B2F !important; +} +.x-btn-default-toolbar-small.x-btn.x-btn-disabled .x-btn-inner { + color: #555B63 !important; +} + +.x-btn-default-toolbar-small.x-btn.x-btn-menu-active, +.x-btn-default-toolbar-small.x-btn.x-btn-pressed { + background-color: #006EFF; + padding: 4px 8px !important; /* Fix #30: prevent width change when dropdown opens */ +} + +.x-btn-default-toolbar-small.x-btn.x-btn-pressed .x-btn-inner-default-toolbar-small, +.x-btn-default-toolbar-small.x-btn.x-btn-pressed .x-btn-icon-el-default-toolbar-small { + color: #ffffff; +} + +/* Server View cogwheel button height - match adjacent combobox (28px) */ +.x-box-target:has(#view)>.x-btn { + height: 28px !important; + min-height: 28px !important; +} + +/* Header buttons (Create VM, Create CT, root@pam) - consistent 28px height with vertical centering */ +/* v5.29: Exclude tag edit buttons (display:none when hidden, :has(.fa-check) for checkmark) */ +.x-btn.x-btn-default-small:not(.x-btn-default-toolbar-small):not([style*="display: none"]):not([style*="display:none"]):not(:has(.fa-check)) { + height: 28px !important; + min-height: 28px !important; + display: flex !important; + align-items: center !important; + padding: 3px 8px !important; +} + +.x-btn.x-btn-default-small:not(.x-btn-default-toolbar-small):not([style*="display: none"]):not([style*="display:none"]):not(:has(.fa-check)) .x-btn-wrap { + display: flex !important; + align-items: center !important; +} + +.x-btn.x-btn-default-small:not(.x-btn-default-toolbar-small):not([style*="display: none"]):not([style*="display:none"]):not(:has(.fa-check)) .x-btn-inner { + display: flex !important; + align-items: center !important; +} + +/* Fix dropdown arrows on split/arrow buttons */ +.x-btn-wrap.x-btn-arrow-right::after, +.x-btn-wrap.x-btn-split-right::after { + height: 16px !important; + min-height: 16px !important; + width: 20px !important; + display: flex !important; + align-items: center !important; +} + +/* v5.27: Fix icon-only buttons - hide   inner element when button has no text */ +/* ExtJS adds x-btn-no-text class to buttons with only an icon */ +.x-btn-no-text .x-btn-inner, +.x-btn-button.x-btn-no-text .x-btn-inner, +.x-btn-button-default-toolbar-small.x-btn-no-text .x-btn-inner-default-toolbar-small, +.x-btn-button-default-small.x-btn-no-text .x-btn-inner-default-small, +.x-btn-button-default-small.x-btn-no-text>.x-btn-inner-default-small { + display: none !important; +} + +/* ===================================================== + v5.8: TOOLBOX SCROLL ARROWS FIX + ExtJS behavior: + - Sets inline display:none when content NOT scrollable + - Adds x-box-scroller-disabled class at boundary + - No inline style when scrollable (show arrow) + ===================================================== */ + +/* Hide disabled scrollers (at boundary) */ +.x-box-scroller.x-box-scroller-disabled { + display: none !important; +} + +/* Hide scrollers when ExtJS sets inline display:none (not scrollable) */ +/* Note: ExtJS uses "display:none" without space, check both formats */ +.x-box-scroller.x-box-scroller-toolbar[style*="display:none"], +.x-box-scroller.x-box-scroller-toolbar[style*="display: none"] { + display: none !important; +} + +/* Show scrollers when content is scrollable (no inline display style, not disabled) */ +.x-toolbar-vertical .x-box-scroller-top:not(.x-box-scroller-disabled):not([style*="display"]), +.x-toolbar-vertical .x-box-scroller-bottom:not(.x-box-scroller-disabled):not([style*="display"]) { + display: flex !important; +} + +/* Style the vertical toolbar scrollers - arrow only, no background */ +.x-toolbar-vertical .x-box-scroller-top, +.x-toolbar-vertical .x-box-scroller-bottom { + width: 100% !important; + height: 16px !important; + left: 0 !important; + right: 0 !important; + background: transparent !important; + background-image: none !important; + filter: none !important; + display: flex !important; + align-items: center !important; + justify-content: center !important; + cursor: pointer !important; + opacity: 1 !important; + z-index: 100 !important; + border: none !important; +} + +.x-toolbar-vertical .x-box-scroller-top { + top: 0 !important; +} + +.x-toolbar-vertical .x-box-scroller-bottom { + bottom: 0 !important; +} + +/* Arrow icons */ +.x-toolbar-vertical .x-box-scroller-top::before { + content: '▲' !important; + font-size: 10px !important; + color: #B7BCC2 !important; +} + +.x-toolbar-vertical .x-box-scroller-bottom::before { + content: '▼' !important; + font-size: 10px !important; + color: #B7BCC2 !important; +} + +/* Hover states */ +.x-toolbar-vertical .x-box-scroller-top:hover::before, +.x-toolbar-vertical .x-box-scroller-bottom:hover::before { + color: #F9FAFA !important; +} + +/* Re-hide disabled scrollers after styling */ +.x-toolbar-vertical .x-box-scroller.x-box-scroller-disabled { + display: none !important; +} + +/* ===================================================== + FORM ELEMENTS - Clean inputs (UniFi authentic) + ===================================================== */ +.x-form-trigger-default { + background-color: transparent; +} + +/* Boundlist dropdown popup - UniFi style 4px radius */ +.x-boundlist { + background-color: #282B2F; + border: 1px solid #34383D; + border-radius: 4px !important; + box-shadow: 0 8px 24px rgba(0, 0, 0, 0.5); + padding: 2px; +} + +.x-boundlist-item { + background-color: transparent; + border: none; + border-radius: 4px !important; + color: #DEE0E3; + padding: 2px 8px; +} + +.x-boundlist-selected { + background-color: rgba(249, 250, 250, 0.07); + color: #F9FAFA; +} + +.x-boundlist-item-over { + background-color: rgba(249, 250, 250, 0.04); + color: #DEE0E3; +} + +/* v5.38: Fix boundlist inner container inheriting 8px radius from global rule */ +.x-boundlist-list-ct { + border-radius: 4px !important; +} + +/* Dropdown/floating grid pickers (e.g. ISO selector): readable column headers */ +.x-layer.x-grid .x-grid-header-ct, +.x-layer.x-grid .x-column-header, +.x-boundlist .x-grid-header-ct, +.x-boundlist .x-column-header { + background-color: var(--pm-bg-surface) !important; + border-bottom: 1px solid rgba(255, 255, 255, 0.08) !important; +} + +.x-layer.x-grid .x-column-header-inner, +.x-layer.x-grid .x-column-header-text, +.x-layer.x-grid .x-column-header-text-inner, +.x-layer.x-grid .x-column-header-text-default, +.x-boundlist .x-column-header-inner, +.x-boundlist .x-column-header-text, +.x-boundlist .x-column-header-text-inner, +.x-boundlist .x-column-header-text-default { + color: var(--pm-text-bright) !important; + font-weight: 700 !important; +} + +.x-layer.x-grid .x-column-header-trigger, +.x-boundlist .x-column-header-trigger { + border-left-color: rgba(255, 255, 255, 0.08) !important; +} + +.x-form-display-field-default { + color: #B7BCC2; +} + +.x-form-text-default { + background-color: transparent; + color: #F9FAFA; + border-radius: 4px 0 0 4px !important; + padding: 6px 10px !important; +} + +.x-form-trigger-wrap-default { + border-color: var(--pm-border); + border-radius: 4px !important; + background-color: var(--pm-hover-medium); +} + +.x-form-trigger-wrap-default.x-form-trigger-wrap-focus { + border-color: var(--pm-accent); + box-shadow: 0 0 0 3px var(--pm-focus-ring-color); +} + +.x-form-item-label-default { + color: #B7BCC2; +} + +.x-form-spinner-default { + background-color: #282B2F; +} + +/* v5.59: Make spinner buttons fill container with FontAwesome arrows */ +.x-form-spinner-up, +.x-form-spinner-down { + height: 13px !important; + background-image: none !important; + display: flex !important; + align-items: center !important; + justify-content: center !important; + font-family: 'Font Awesome 6 Free', 'Font Awesome 5 Free', FontAwesome !important; + font-weight: 900 !important; + font-size: 7px !important; + color: #B7BCC2 !important; +} + +.x-form-spinner-up::before { + content: '\f077' !important; + display: block !important; +} + +.x-form-spinner-down::before { + content: '\f078' !important; + display: block !important; +} + +/* v5.64: Dialog form field alignment - let ExtJS handle natural sizing */ +.x-window .x-container .x-form-trigger-wrap, +.x-window .x-form-item-body .x-form-trigger-wrap { + width: 100% !important; + max-width: none !important; +} + +/* Ensure input fills the trigger wrap */ +.x-window .x-container .x-form-trigger-wrap input.x-form-field { + width: calc(100% - 2px) !important; +} + +/* v5.63: Removed v5.61 margin-left rule that caused form alignment issues */ + +.x-form-cb-label-default { + color: #B7BCC2; +} + +/* v5.41: Reduce gap between checkbox/radio and label */ +/* Label after checkbox - reduce left padding */ +.x-form-cb-label-after { + padding-left: 6px !important; +} + +/* Label before checkbox - reduce right padding */ +.x-form-cb-label-before { + padding-right: 6px !important; +} + +.x-fieldset-default { + border-color: #34383D; +} + +.x-fieldset-header-default>.x-fieldset-header-text { + color: #F9FAFA; +} + +/* ===================================================== + GRID / TABLE - UniFi authentic row hover + ===================================================== */ +.x-column-header { + border-color: transparent !important; + background-color: transparent !important; +} + +/* Header Text - Bright White */ +.x-column-header-inner, +.x-column-header-text { + color: #F9FAFA !important; + font-weight: 700 !important; + font-size: 13px !important; +} + +.x-grid-item, +.x-column-header-default, +.x-grid-cell-row-numberer { + color: #DEE0E3 !important; + background-color: transparent !important; + border-color: transparent !important; + font-size: 13px !important; +} + +.x-column-header-trigger { + border-color: transparent !important; +} + +.x-grid-cell-special { + border-color: transparent !important; +} + +.x-grid-group-hd { + background-color: transparent !important; + border-color: transparent !important; +} + +.x-grid-group-title { + color: #F9FAFA !important; + font-weight: 700 !important; +} + +.x-grid-header-ct { + border: none !important; + background-color: transparent !important; +} + +/* Row separators (use td borders; more reliable than box-shadow on ) */ +.x-grid td, +.x-grid-td, +.x-grid-cell, +td.x-grid-cell { + border: none !important; + border-bottom: 1px solid rgba(255, 255, 255, 0.06) !important; +} + +/* v5.53: Vertically center text in grid table cells */ +.x-grid-cell { + vertical-align: middle !important; +} + +/* Keep rows themselves flat; separators handled above */ +.x-grid-item { + box-shadow: none !important; +} + +/* Slightly roomier rows (matches UniFi table density) */ +.x-grid-cell-inner { + padding-top: 6px !important; + padding-bottom: 6px !important; +} + +/* + Tasks + Cluster Log: compact rows (validated via DevTools) + - Tasks: 4px top/bottom + - Cluster Log: 4.5px top/bottom + - Keep line-height stable and prevent action-column icons from inflating row height +*/ + +/* Tasks grid (bottom Tasks panel) */ +div[id^="pveTaskViewer-"] .x-grid-cell-inner, +div[id^="pveClusterTasks-"] .x-grid-cell-inner, +[aria-label="Tasks"] .x-grid-view .x-grid-cell-inner { + padding-top: 4px !important; + padding-bottom: 4px !important; + line-height: 15px !important; +} + +/* Tasks action-column (chevron) can inflate row height unless centered */ +div[id^="pveTaskViewer-"] .x-grid-cell-inner-action-col, +div[id^="pveClusterTasks-"] .x-grid-cell-inner-action-col, +[aria-label="Tasks"] .x-grid-view .x-grid-cell-inner-action-col { + display: flex !important; + align-items: center !important; + justify-content: center !important; + padding-top: 4px !important; + padding-bottom: 4px !important; + line-height: 15px !important; +} + +/* Cluster Log grid */ +div[id^="pveClusterLog-"] .x-grid-cell-inner, +div[id^="pveLogView-"] .x-grid-cell-inner, +[aria-label="Cluster Log"] .x-grid-view .x-grid-cell-inner { + padding-top: 4.5px !important; + padding-bottom: 4.5px !important; + line-height: 15px !important; +} + +.x-grid-item-alt { + background-color: transparent !important; +} + +/* Ensure alternating rows have readable text */ +.x-grid-item-alt .x-grid-cell-inner, +.x-grid-item-alt .x-grid-cell { + color: #DEE0E3 !important; +} + +.x-grid-with-row-lines .x-grid-item { + border-bottom: none !important; + border: none !important; + box-shadow: none !important; +} + +/* Optional: no trailing divider after the last row */ +.x-grid-with-row-lines .x-grid-item:last-child td.x-grid-cell, +.x-grid-with-row-lines .x-grid-item:last-child .x-grid-td { + border-bottom: none !important; +} + +.x-grid-with-row-lines .x-grid-item.x-grid-item-over { + background-color: var(--pm-hover-subtle) !important; + border: none !important; +} + +.x-grid-with-row-lines .x-grid-item.x-grid-item-selected { + background-color: rgba(0, 110, 255, 0.08) !important; + box-shadow: rgba(71, 151, 255, 0.1) 0px 0px 0px 1000px inset !important; + border: none !important; +} + +.x-grid-item-over { + background-color: hsla(214, 8%, 98%, 0.02) !important; +} + +.x-grid-item-over .x-grid-cell { + background-color: transparent !important; +} + +/* Keep row separators stable on hover/selection (prevents 1px shift) */ +.x-grid-item-over .x-grid-cell, +.x-grid-item-over .x-grid-td, +.x-grid-item-over td.x-grid-cell, +.x-grid-item-selected .x-grid-cell, +.x-grid-item-selected .x-grid-td, +.x-grid-item-selected td.x-grid-cell { + border-bottom: 1px solid rgba(255, 255, 255, 0.06) !important; +} + +.x-grid-item-selected { + background-color: rgba(0, 110, 255, 0.08) !important; + box-shadow: rgba(71, 151, 255, 0.1) 0px 0px 0px 1000px inset !important; +} + +.x-grid-item-selected .x-grid-cell-inner { + color: hsla(0, 0%, 100%, 1) !important; +} + +/* v5.16: Remove background highlight from parent nodes (folders/servers) when focused/selected via arrow */ +/* Only leaf nodes (VMs/CTs) should show the selection/focus background */ +.x-grid-item:not(.x-grid-tree-node-leaf).x-grid-item-focused, +.x-grid-item:not(.x-grid-tree-node-leaf).x-grid-item-selected { + background-color: transparent !important; +} + +/* More visible hover state */ +.x-grid-item-over .x-grid-cell-inner, +.x-grid-item-over .x-grid-cell { + color: #F9FAFA !important; +} + +.x-column-header-over, +.x-column-header-open { + background-color: #34383D; +} + +.x-column-header-sort-ASC, +.x-column-header-sort-DESC { + background-color: #1b384c; +} + +.x-grid-row-summary .x-grid-cell, +.x-grid-row-summary .x-grid-rowwrap, +.x-grid-row-summary .x-grid-cell-rowbody { + background-color: #131416 !important; + border-color: #34383D; +} + +.x-grid-with-col-lines .x-grid-cell, +.x-grid-with-col-lines .x-grid-item-over .x-grid-cell, +.x-grid-with-col-lines .x-grid-item-selected .x-grid-cell { + border-color: hsla(214, 8%, 98%, 0.07) !important; + border-right-color: transparent !important; +} + +.x-dd-drag-proxy { + background-color: #282B2F; + border: 1px solid #34383D; + color: #B7BCC2; +} + +.x-keyboard-mode .x-grid-item-focused { + background-color: rgba(249, 250, 250, 0.07); + color: #F9FAFA; +} + +.x-keyboard-mode .x-grid-item-focused .x-grid-cell-inner::before { + border-color: #006EFF; +} + +.x-grid-empty { + background-color: #131416; + color: #737C87; +} + +/* ===================================================== + MENUS - Floating, clean (UniFi authentic) + ===================================================== */ +.x-menu-default { + border: 1px solid #34383D; + border-radius: 8px; + box-shadow: 0 8px 24px rgba(0, 0, 0, 0.5); +} + +.x-menu-body-default { + background-color: #282B2F; +} + +.x-menu-header { + background-color: #006EFF; +} + +.x-menu-item-default.x-menu-item-separator { + background-color: #282B2F; + border-color: #34383D; +} + +.x-menu-item-default.x-menu-item-focus, +.x-menu-item-default.x-menu-item-active { + background-color: rgba(249, 250, 250, 0.07) !important; + color: #F9FAFA; +} + +.x-menu-item-text-default { + color: #DEE0E3; +} + +.x-menu-item-icon-default { + color: #B7BCC2; +} + +.x-menu-icon-separator-default { + background-color: transparent; + border-color: #34383D; +} + +/* ===================================================== + PANELS - Card-like containers (UniFi authentic) + ===================================================== */ +.x-panel-header-default { + background-color: #131416; + border: none; +} + +.x-panel-header-default .x-tool-tool-el { + background-color: transparent; +} + +.x-tool-img { + filter: brightness(175%); +} + +.x-tool-over .x-tool-img { + filter: brightness(200%); +} + +/* v5.39: Replace pixelated close button sprite with crisp FontAwesome icon */ +.x-tool-tool-el.x-tool-close, +.x-tool-img.x-tool-close { + background-image: none !important; + font-family: "FontAwesome" !important; + font-size: 20px !important; + line-height: 16px !important; + text-align: center !important; + color: #737C87 !important; + transition: color 0.15s ease !important; + filter: none !important; + width: 16px !important; + height: 16px !important; +} + +.x-tool-tool-el.x-tool-close::before, +.x-tool-img.x-tool-close::before { + content: "\f00d" !important; +} + +.x-tool:hover .x-tool-tool-el.x-tool-close, +.x-tool:hover .x-tool-img.x-tool-close { + color: #DEE0E3 !important; +} + +.x-panel-header-title-default { + color: #F9FAFA; +} + +/* Panel header text (VM/Container titles in toolbar) */ +.x-panel-header-text, +.x-panel-header-text-default, +.x-panel-header-text.x-box-item, +.x-toolbar .x-panel-header-text, +.x-toolbar-item.x-panel-header-text { + color: #F9FAFA !important; +} + +/* Title text general */ +.x-title-text, +.x-title-text-default { + color: #F9FAFA !important; + overflow: visible !important; +} + +/* Panel header container - ensure proper visibility */ +.x-panel-header, +.x-panel-header-default { + overflow: visible !important; +} + +.x-panel-body-default { + background-color: var(--pm-bg-base); + border-color: var(--pm-border); + color: var(--pm-text-muted); +} + +div[id^="pveResourceTree-"][id$="-body"] { + border-color: var(--pm-bg-base); +} + +/* ===================================================== + PROGRESS BARS - Clean, rounded (UniFi authentic) + v5.17: Consolidated - removed duplicate section at end of file + ===================================================== */ +/* Fix: Widget containers need overflow visible to not clip progress bars */ +.x-container[id^="pmxInfoWidget"], +.x-container.x-box-layout-ct { + overflow: visible !important; +} + +/* v5.32: Add padding gap to progress bar rows (CPU/Memory/SWAP/Bootdisk) + Only targets containers with VISIBLE progress bars (excludes Status/HA State/Node/Unprivileged) */ +/* v5.94: Reduced vertical padding from 5px to 3px to prevent PBS summary panel clipping + (ExtJS calculates body height before CSS padding → overflow hidden clips bottom rows) */ +.x-container[id^="pmxInfoWidget"].x-box-layout-ct:has(.x-progress:not([style*="display: none"]):not([style*="display:none"])) { + padding: 3px 25px !important; +} + +/* v5.51: Fix horizontal padding alignment for rows with HIDDEN progress bars + (Load average, KSM sharing, CPU(s), Kernel Version, Boot Mode, Manager Version) + Only adjusts horizontal padding to match visible progress bar rows, keeps vertical minimal */ +.x-container[id^="pmxInfoWidget"].x-box-layout-ct:has(.x-progress[style*="display: none"]), +.x-container[id^="pmxInfoWidget"].x-box-layout-ct:has(.x-progress[style*="display:none"]) { + padding-left: 25px !important; + padding-right: 25px !important; +} + +/* v5.51: Repository Status row uses different ID pattern */ +.x-container[id^="pmxNodeInfoRepoStatus"].x-box-layout-ct { + padding-left: 25px !important; + padding-right: 25px !important; +} + +/* v5.94: Fix PBS summary panel clipping - reduce body padding to fit all rows + PBS panel has 9 info widgets in a smaller body (243px); default 15px top/bottom + padding causes scrollHeight to exceed clientHeight → bottom rows clipped */ +div[id^="pbsNodeInfoPanel"][id$="-body"] { + padding-top: 5px !important; + padding-bottom: 5px !important; +} + +/* v5.22: Removed height:inherit - only min-height:auto is needed */ +/* height:inherit was breaking widget containers, ExtJS inline heights work without it */ +.x-container[id^="pmxInfoWidget"] .x-box-inner, +.x-container.x-box-layout-ct .x-box-inner { + min-height: auto !important; +} + +/* v5.22: Fix pmxInfoWidget container heights - need 24px to fit 8px progress bars */ +[id^="pmxInfoWidget"][id$="-innerCt"] { + min-height: 24px !important; + overflow: visible !important; +} + +/* Progress bar outer container (track) */ +.x-progress, +.x-progress-default { + height: 8px !important; + min-height: 8px !important; + max-height: 8px !important; + border-radius: 5px !important; + overflow: hidden !important; + background-color: var(--pwt-gauge-back) !important; + border: none !important; + padding: 0 !important; +} + +/* Progress bar inner fill - v5.31: Updated to UniFi blue #4797FF */ +.x-progress-bar, +.x-progress-bar-default, +.x-progress-default .x-progress-bar-default { + height: 8px !important; + min-height: 8px !important; + max-height: 8px !important; + border-radius: 5px !important; + border: none !important; + background-color: var(--pwt-gauge-default) !important; + background-image: none !important; +} + +/* Hide progress text overlay */ +.x-progress-text, +.x-progress-default .x-progress-text { + display: none !important; +} + +/* Warning state */ +.x-progress.warning .x-progress-bar, +.x-progress.warning .x-progress-bar-default { + background-color: var(--pwt-gauge-warn) !important; +} + +/* Critical state */ +.x-progress.critical .x-progress-bar, +.x-progress.critical .x-progress-bar-default { + background-color: var(--pwt-gauge-crit) !important; +} + +/* ===================================================== + SPLITTERS - Minimal + ===================================================== */ +.x-splitter { + background-color: var(--pm-bg-base); +} + +/* Horizontal splitter (between main content and Tasks panel) - visible divider line */ +.x-splitter-horizontal, +.x-splitter[aria-orientation="horizontal"] { + background-color: transparent !important; + border-top: 1px solid var(--pm-border) !important; +} + +/* Vertical splitter - gap with visible line */ +.x-splitter-vertical { + width: 7px !important; + min-width: 7px !important; + background-color: transparent !important; + border-right: 1px solid #444444 !important; + z-index: 10 !important; +} + +.x-keyboard-mode .x-splitter-focus::after { + border-color: #006EFF; +} + +/* ===================================================== + TABS - Clean, flat (UniFi authentic) + ===================================================== */ +.x-tab-bar-default { + background-color: #131416; +} + +.x-tab-default.x-tab-over { + background-color: rgba(249, 250, 250, 0.04); + border: none; +} + +/* Remove white focus border/outline from tabs (v5.46) */ +.x-tab:focus, +.x-tab.x-tab-focus, +.x-tab.x-tab-active:focus, +.x-keyboard-mode .x-tab:focus, +.x-keyboard-mode .x-tab-focus, +.x-keyboard-mode .x-tab-active.x-tab-focus, +.x-tab-default:focus, +.x-tab-default.x-tab-focus, +.x-tab-bar .x-tab:focus, +.x-tab-bar .x-tab.x-tab-focus { + outline: none !important; + box-shadow: none !important; + border-color: transparent !important; +} + +.x-tab:focus::before, +.x-tab:focus::after, +.x-tab.x-tab-focus::before, +.x-tab.x-tab-focus::after, +.x-keyboard-mode .x-tab:focus::before, +.x-keyboard-mode .x-tab:focus::after { + border: none !important; + outline: none !important; + box-shadow: none !important; +} + +.x-tab-default.x-tab.x-tab-active { + background-color: #006EFF; + border: none; +} + +.x-tab-default.x-tab.x-tab-disabled { + background-color: transparent; + border: none; + color: #737C87; +} + +.x-keyboard-mode .x-tab-default.x-tab-focus, +.x-keyboard-mode .x-tab-default.x-tab-focus.x-tab-active { + background-color: #006EFF; + border: none; +} + +.x-tab-default-top { + background-color: #131416; + border: none; +} + +.x-tab-inner-default { + color: #B7BCC2; +} + +.x-tab-active .x-tab-inner-default { + color: #ffffff; +} + +/* ===================================================== + TOOLTIPS (UniFi authentic) + ===================================================== */ +.x-tip-default { + background-color: #282B2F; + border: 1px solid #34383D; + border-radius: 6px; + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.4); +} + +.x-tip-body-default { + color: #DEE0E3; +} + +.x-tip-form-invalid { + background-color: #282B2F; + border-color: #f03a3e; +} + +.x-tip-body-form-invalid { + color: #f03a3e; +} + +/* ===================================================== + TOOLBARS - Minimal borders (UniFi authentic) + ===================================================== */ +.x-toolbar { + background-color: #131416; +} + +.x-toolbar-default { + background-color: #131416; + border: none; +} + +.x-toolbar-default.x-docked-top { + border: none; + border-bottom: 1px solid #282B2F; +} + +.x-toolbar-default .x-toolbar-separator { + border-color: #34383D; +} + +.x-toolbar-text-default { + color: #B7BCC2; +} + +/* ===================================================== + TREE LIST - Sidebar navigation (UniFi authentic) + ===================================================== */ +.x-treelist-item, +.x-treelist-item-tool { + background-color: #131416; + border-radius: 4px !important; +} + +/* v5.84: Fix horizontal scrollbar in resource tree + ExtJS sets inline 'overflow: hidden auto' which causes 1px horizontal scroll. + Force overflow-x: hidden while preserving vertical scroll. + Note: Must use .x-fit-item compound selector to win over rule at line ~3365 */ +[id^="pveResourceTree"] .x-tree-view, +[id^="pveResourceTree"] .x-tree-view.x-fit-item { + overflow-x: hidden !important; +} + +/* Add spacing between tree items - v5.33: Reduced padding for compactness */ +.x-treelist-row, +.x-tree-cell, +.x-grid-cell-treecolumn { + padding: 0px 8px !important; +} + +/* v5.9: UniFi-STYLE SELECTED ITEM (matching UniFi Controller) + Uses subtle background + blue icon AND text with ::before pseudo-element */ + +.x-treelist-item-text, +.x-treelist-item-icon { + color: rgba(255, 255, 255, 0.75); +} + +/* Remove ALL old hover/selected background styles */ +.x-treelist-row, +.x-treelist-row:hover, +.x-treelist-row-over, +.x-treelist-item-selected>.x-treelist-row, +.x-treelist-item-selected>.x-treelist-row:hover, +.x-treelist-item-expanded>.x-treelist-row, +.x-treelist-item-expanded>.x-treelist-row-over, +.x-treelist-item-expandable>.x-treelist-row, +.x-treelist-item-expandable>.x-treelist-row-over { + background: none !important; + background-color: transparent !important; + box-shadow: none !important; + border-left: none !important; + position: relative !important; + z-index: 1 !important; + border-radius: 4px !important; +} + +/* Pseudo-element for ALL background effects */ +.x-treelist-row::before { + content: '' !important; + display: block !important; + position: absolute !important; + top: 0 !important; + left: 0 !important; + right: 0 !important; + bottom: 0 !important; + width: 100% !important; + height: 100% !important; + border-radius: 4px !important; + background: transparent !important; + opacity: 0 !important; + transform: scale(0.95) !important; + transition: opacity 0.15s ease, transform 0.15s ease !important; + z-index: -1 !important; + pointer-events: none !important; +} + +/* Hover state - ONLY via :hover pseudo-class */ +.x-treelist-row:hover::before { + background: rgb(40, 43, 47) !important; + opacity: 0.5 !important; + transform: scale(1) !important; +} + +/* DISABLE the x-treelist-row-over class effect (ExtJS adds this to parents) */ +.x-treelist-row-over::before { + opacity: 0 !important; +} + +/* But if it's ALSO being hovered directly, show the effect */ +.x-treelist-row-over:hover::before { + background: rgb(40, 43, 47) !important; + opacity: 0.5 !important; + transform: scale(1) !important; +} + +/* Selected state background */ +.x-treelist-item-selected>.x-treelist-row::before { + background: rgb(40, 43, 47) !important; + opacity: 1 !important; + transform: scale(1) !important; +} + +/* Selected + hover - slightly lighter */ +.x-treelist-item-selected>.x-treelist-row:hover::before { + background: rgb(50, 53, 57) !important; + opacity: 1 !important; +} + +/* Selected item text - BLUE like UniFi */ +.x-treelist-item-selected>.x-treelist-row .x-treelist-item-text { + color: rgb(71, 151, 255) !important; +} + +/* Selected item icon - BLUE like UniFi */ +.x-treelist-item-selected>.x-treelist-row .x-treelist-item-icon { + color: rgb(71, 151, 255) !important; +} + +/* Parent item containing selected child - WHITE text and icon */ +.x-treelist-item:has(.x-treelist-item-selected)>.x-treelist-row .x-treelist-item-text { + color: #F9FAFA !important; +} + +.x-treelist-item:has(.x-treelist-item-selected)>.x-treelist-row .x-treelist-item-icon { + color: #F9FAFA !important; +} + +/* Reset non-selected child items */ +.x-treelist-item-selected .x-treelist-item:not(.x-treelist-item-selected):not(:has(.x-treelist-item-selected))>.x-treelist-row::before { + opacity: 0 !important; +} + +.x-treelist-item-selected .x-treelist-item:not(.x-treelist-item-selected):not(:has(.x-treelist-item-selected))>.x-treelist-row:hover::before { + opacity: 0.5 !important; +} + +.x-treelist-item-selected .x-treelist-item:not(.x-treelist-item-selected):not(:has(.x-treelist-item-selected)) .x-treelist-item-text, +.x-treelist-item-selected .x-treelist-item:not(.x-treelist-item-selected):not(:has(.x-treelist-item-selected)) .x-treelist-item-icon { + color: #B7BCC2 !important; +} + +.x-treelist-pve-nav { + background-color: #131416; + border: none; +} + +/* ===================================================== + WINDOWS / DIALOGS (UniFi authentic) + ===================================================== */ +/* v5.50: Reduced shadow intensity for cleaner look */ +.x-window-default { + background-color: #131416; + border: 1px solid #34383D; + border-radius: 8px; + box-shadow: 0 12px 40px rgba(0, 0, 0, 0.1); +} + +.x-window-header-default { + background-color: #282B2F; + border: none; + border-radius: 8px 8px 0 0; +} + +.x-window-header-default .x-mask { + background-color: rgba(40, 43, 47, 0.7); +} + +.x-window-header-title-default { + color: #F9FAFA; +} + +.x-window-body-default { + background-color: #131416; + border: none; + color: #B7BCC2; +} + +.x-window-ghost { + background-color: #131416; +} + +.x-window-header-default .x-tool-img { + background-color: transparent; +} + +.x-message-box .x-window-body { + background-color: #282B2F; +} + +/* ===================================================== + v5.17 FIX: Dialog button overlap fix + ExtJS uses absolute positioning for buttons, but theme's + display:flex !important was overriding inline display:none + on hidden buttons (OK/Cancel in Yes/No dialogs) + ===================================================== */ +/* Respect ExtJS inline display:none on hidden dialog buttons */ +.x-message-box .x-btn.x-btn-default-small[style*="display: none"], +.x-message-box .x-btn.x-btn-default-small[style*="display:none"], +.x-window .x-toolbar-footer .x-btn[style*="display: none"], +.x-window .x-toolbar-footer .x-btn[style*="display:none"] { + display: none !important; +} + +/* ===================================================== + v5.37 FIX: Create Wizard footer clipping + Some wizards position their footer toolbar with inline top/height. + If theme tweaks change control heights/padding, the footer can extend + past the window bottom and get clipped (the window has overflow:hidden). + Anchor wizard footers to bottom to keep Back/Next/Advanced visible. + ===================================================== */ +.x-window[id^="pveQemuCreateWizard-"] .x-toolbar-footer, +.x-window[id^="pveLxcCreateWizard-"] .x-toolbar-footer { + top: auto !important; + bottom: 0 !important; + left: 0 !important; + right: 0 !important; + width: auto !important; + box-sizing: border-box !important; + padding: 8px 16px !important; + height: auto !important; + display: flex !important; + align-items: center !important; +} + +/* Dialog footer - use flexbox for proper button spacing */ +.x-message-box .x-toolbar-footer { + display: flex !important; + justify-content: flex-end !important; + align-items: center !important; + gap: 8px !important; + padding: 12px 16px !important; +} + +.x-message-box .x-toolbar-footer .x-box-inner, +.x-message-box .x-toolbar-footer .x-box-inner { + display: flex !important; + justify-content: flex-end !important; + align-items: center !important; + gap: 8px !important; + width: 100% !important; + height: auto !important; +} + +.x-message-box .x-toolbar-footer .x-box-target, +.x-message-box .x-toolbar-footer .x-box-target { + display: flex !important; + justify-content: flex-end !important; + align-items: center !important; + gap: 8px !important; + position: relative !important; + width: auto !important; + height: auto !important; +} + +/* Override absolute positioning on dialog buttons */ +.x-message-box .x-toolbar-footer .x-btn, +.x-message-box .x-toolbar-footer .x-btn { + position: relative !important; + left: auto !important; + top: auto !important; + margin: 0 !important; +} + +/* ===================================================== + v5.49: LOGIN MODAL / DIALOG FORM FIXES + - Form fields stretch to full width (override inline 380px) + - Footer checkbox/button gap fixed (was -7px overlap) + - Footer toolbar takes full width (override inline 374px) + v5.65: Fix mainPanel width constraint - ExtJS calculates based on + original parent width before CSS override, causing 549px instead + of ~580px. Force direct child panels to use full available width. + ===================================================== */ + +/* ===================================================== + v5.74: DIALOG LAYOUT FIXES - REMOVED OVERRIDES + Removed all forced width/padding rules for panel bodies + Removed forced width/padding rules for panel bodies to prevent layout cutoff. + ===================================================== */ + +/* Only ensure the footer toolbar behaves correctly */ +.x-window .x-toolbar-footer { + width: 100% !important; + padding-right: 10px !important; + box-sizing: border-box !important; +} + +.x-window .x-toolbar-footer .x-box-inner { + display: flex !important; + align-items: center !important; + justify-content: flex-end !important; + gap: 12px !important; + width: 100% !important; +} + +.x-window .x-toolbar-footer .x-box-target { + display: flex !important; + align-items: center !important; + justify-content: flex-end !important; + gap: 12px !important; + width: 100% !important; +} + +/* Remove absolute positioning from footer items */ +.x-window .x-toolbar-footer .x-form-type-checkbox, +.x-window .x-toolbar-footer .x-btn { + position: relative !important; + left: auto !important; + top: auto !important; + margin: 0 !important; +} + +/* Auto-width for checkbox label in footer */ +.x-window .x-toolbar-footer .x-form-type-checkbox .x-form-item-label { + width: auto !important; +} + +/* v5.75: Fix Help button alignment in dialog footers */ +/* The help button is an inline button and should be on the left */ +.x-window .x-toolbar-footer .proxmox-inline-button:first-child { + margin-right: auto !important; +} + +/* ===================================================== + PROXMOX LOGO - Invert for dark + ===================================================== */ +img[id^="proxmoxlogo-"][id$="-img"] { + filter: invert(1) hue-rotate(180deg); +} + +img[id^="proxmoxLogoSvg-"][id$="-img"] { + filter: invert(1) hue-rotate(180deg); +} + +div[id^="versioninfo-"]+div[id^="panel-"]>div[id^="panel-"][id$="-bodyWrap"]>div, +div.eol-notice+div[id^="panel-"]>div[id^="panel-"][id$="-bodyWrap"]>div { + background-color: transparent; + border: none; +} + +/* ===================================================== + PROXMOX SPECIFIC (UniFi authentic) + ===================================================== */ +.proxmox-invalid-row { + background-color: rgba(240, 58, 62, 0.15); +} + +.x-keyboard-mode .proxmox-invalid-row .x-grid-item-focused { + background-color: rgba(240, 58, 62, 0.25); +} + +.proxmox-warning-row { + background-color: rgba(245, 166, 35, 0.15); +} + +.proxmox-disabled-row td { + color: #737C87; +} + +.pmx-hint { + background-color: rgba(245, 166, 35, 0.15); + white-space: nowrap !important; +} + +/* Allow pmx-hint text to expand beyond parent container width */ +.x-container:has(> .x-box-inner > .x-box-target > .pmx-hint) .x-box-inner { + overflow: visible !important; +} + +.pmx-hint a { + color: #006EFF; +} + +.proxmox-inline-button { + background-color: #34383D; + border: none; + color: #B7BCC2; +} + +.proxmox-inline-button.x-btn-over { + background-color: rgba(249, 250, 250, 0.07); +} + +.proxmox-inline-button .x-btn-inner, +.proxmox-inline-button .x-btn-icon-el { + color: #B7BCC2; +} + +/* Loading indicators */ +.x-grid-row-loading, +.x-treelist-item-loading .x-treelist-item-icon, +.x-mask-msg-text, +.x-grid-tree-loading .x-tree-icon { + filter: invert(90%); +} + +.x-mask-msg { + background-color: #282B2F; + border: 1px solid #34383D; + border-radius: 8px; +} + +/* Markdown content */ +.pmx-md code { + background-color: #131416; +} + +.pmx-md pre code { + border-color: #34383D; +} + +.pmx-md tbody tr td { + border-color: #34383D; +} + +.pmx-md tbody tr:nth-of-type(2n) { + background-color: rgba(249, 250, 250, 0.02); +} + +.pmx-md tbody tr:hover td { + background-color: rgba(249, 250, 250, 0.04); +} + +.pmx-md a { + color: #006EFF; +} + +/* APT repos */ +.proxmox-apt-repos .x-grid-group-hd { + background-color: #131416; + border: none; +} + +.proxmox-apt-repos .x-grid-group-title { + color: #F9FAFA; +} + +/* Status colors */ +.info-blue { + color: #006EFF !important; +} + +.critical { + color: #f03a3e !important; +} + +/* Tags - Native contrast detection with proper visibility */ +.pve-edit-tag.editable span { + background-color: #282B2F; + color: #B7BCC2; + border-color: #34383D; +} + +/* Tags with LIGHT text (dark backgrounds like blue tags) */ +.pve-edit-tag.proxmox-tag-light, +.pve-edit-tag.proxmox-tag-light span { + color: #FFFFFF !important; +} + +/* Tags with DARK text (bright backgrounds like pink/yellow tags) - non-edit mode only */ +.pve-edit-tag.proxmox-tag-dark:not(.editable), +.pve-edit-tag.proxmox-tag-dark:not(.editable) span { + color: #1C1E21 !important; +} + +/* v5.88: In edit mode, force light text on ALL tags for better visibility */ +.pve-edit-tag.editable.proxmox-tag-dark, +.pve-edit-tag.editable.proxmox-tag-dark span { + color: #F9FAFA !important; +} + +/* Individual tag styling */ +.pve-edit-tag { + display: inline-flex !important; + align-items: center !important; + padding: 2px 8px !important; + border-radius: 6px !important; +} + +/* v5.30: Tree view tags - match header tag styling */ +.x-tree-node-text .proxmox-tag-dark, +.x-tree-node-text .proxmox-tag-light, +.x-grid-cell-inner .proxmox-tag-dark, +.x-grid-cell-inner .proxmox-tag-light, +span.proxmox-tag-dark, +span.proxmox-tag-light { + border-radius: 6px !important; + padding: 2px 8px !important; + display: inline-flex !important; + align-items: center !important; +} + +/* v5.52: Make resource tree tags match search table tag height (19px) */ +.x-tree-node-text .proxmox-tag-dark, +.x-tree-node-text .proxmox-tag-light { + padding-top: 1px !important; + padding-bottom: 1px !important; +} + +/* v5.52: Force tree row height to stay at 25px when tags have reduced padding */ +.x-tree-panel .x-grid-row { + height: 25px !important; +} + +/* Pencil button for editing tags */ +/* v5.28: Removed display override - let Proxmox control visibility via inline style */ +.pve-tag-inline-button { + /* display controlled by inline style (none when not hovering, flex when editing) */ + align-items: center !important; + justify-content: center !important; + width: 20px !important; + height: 20px !important; + background: transparent !important; + cursor: pointer !important; +} + +.pve-tag-inline-button .fa-pencil, +.pve-tag-inline-button .x-fa.fa-pencil { + color: #8A919A !important; +} + +.pve-tag-inline-button:hover .fa-pencil { + color: #F9FAFA !important; +} + +/* v5.29: Checkmark button in tag edit - match toolbar button size */ +/* The checkmark has x-btn-default-small (not toolbar-small) so we need specific sizing */ +.x-btn.x-btn-default-small:has(.fa-check) { + min-height: 24px !important; + height: 24px !important; + padding: 3px 8px !important; + border-radius: 4px !important; + background-color: #006EFF !important; + border: none !important; +} + +/* Disabled checkmark - gray/transparent */ +.x-btn.x-btn-default-small:has(.fa-check).x-btn-disabled { + background-color: transparent !important; + border: 1px solid #34383D !important; + opacity: 0.5 !important; +} + +/* Checkmark icon - white when enabled */ +.x-btn.x-btn-default-small:has(.fa-check) .fa-check { + color: #ffffff !important; +} + +/* Disabled checkmark icon - gray */ +.x-btn.x-btn-default-small:has(.fa-check).x-btn-disabled .fa-check { + color: #737C87 !important; +} + +/* Checkmark button hover - lighter blue */ +.x-btn.x-btn-default-small:has(.fa-check):not(.x-btn-disabled):hover { + background-color: #338BFF !important; +} + +/* Hide the   inner element on checkmark button */ +.x-btn.x-btn-default-small:has(.fa-check) .x-btn-inner { + display: none !important; +} + +.proxmox-tags-full .proxmox-tag-light, +.proxmox-tags-full .proxmox-tag-dark, +.proxmox-tags-circle .proxmox-tag-light, +.proxmox-tags-circle .proxmox-tag-dark { + outline: 1px solid rgba(52, 56, 61, 0.3); +} + +/* ===================================================== + DATE PICKER (UniFi authentic) + ===================================================== */ +.x-datepicker, +.x-datepicker-column-header, +.x-monthpicker { + background-color: #131416; + color: #B7BCC2; + border: none; +} + +.x-datepicker-month .x-btn-over.x-btn-default-small { + background-color: #34383D; +} + +.x-monthpicker-months { + border-color: #34383D; +} + +.x-datepicker-header { + background-color: #131416; +} + +.x-datepicker-date, +.x-monthpicker-item-inner { + color: #B7BCC2; +} + +.x-datepicker-prevday .x-datepicker-date, +.x-datepicker-nextday .x-datepicker-date { + color: #737C87; +} + +.x-datepicker-footer, +.x-monthpicker-buttons { + background-color: #131416; +} + +.x-datepicker-selected div.x-datepicker-date, +.x-monthpicker-item a.x-monthpicker-selected, +a.x-monthpicker-item-inner:hover, +div.x-datepicker-date:hover { + background-color: #006EFF; + color: #fff; +} + +/* ===================================================== + USAGE BARS - UniFi authentic style + ===================================================== */ +/* v5.31: Reduced border-radius, removed wrapper padding for full-width fill */ +.usage-wrapper { + border: none !important; + border-radius: 2px !important; + background-color: #34383D !important; + overflow: hidden !important; + padding: 0 !important; +} + +.usage-negative { + background-color: transparent !important; + width: 100% !important; +} + +.usage { + background-color: #37BE5F !important; + border-radius: 2px !important; + width: 100% !important; +} + +/* ===================================================== + CONSOLE / TERMINAL + ===================================================== */ +div.monitor { + border-color: #34383D; +} + +.install-mask { + background-color: #131416; + color: #B7BCC2; +} + +.x-window.install-mask { + box-shadow: rgba(0, 0, 0, 0.5) 0 4px 20px !important; +} + +/* ===================================================== + OSD TABLE + ===================================================== */ +table.osds tr { + border-color: var(--pm-border); +} + +table.osds td { + border-color: var(--pm-border); +} + +/* ===================================================== + LINKS - UniFi Blue (authentic) + ===================================================== */ +a { + color: var(--pm-accent); +} + +a:hover { + color: var(--pm-accent-hover); +} + +/* ===================================================== + STATUS DOTS (like UniFi - authentic) + ===================================================== */ +/* Proxmox uses ::before for the type icon and ::after for the status glyph. + UniFi style: keep type icon neutral and show a green dot for "running". */ +.x-tree-icon-custom.running::before, +.x-grid-icon-custom.running::before { + color: #B7BCC2 !important; +} + +.x-tree-icon-custom.running::after, +.x-grid-icon-custom.running::after { + content: "\f111" !important; + /* FontAwesome circle */ + font-family: "FontAwesome" !important; + font-size: 9px !important; + line-height: 1 !important; + color: var(--pm-success) !important; + background: transparent !important; + text-shadow: none !important; +} + +/* Align CT/LXC running dot with VM running dot (cube glyph is slightly narrower) */ +.x-tree-icon-custom.fa-cube.running::after, +.x-grid-icon-custom.fa-cube.running::after { + left: -3.8px !important; + right: 3.8px !important; +} + +/* v5.90: Lock icons (migrate, backup, suspend) override running dot + When VM is both running AND locked for operation, show the lock icon instead of green dot */ +.x-tree-icon-custom.running.lock-migrate::after, +.x-grid-icon-custom.running.lock-migrate::after { + content: "\f1d9" !important; /* FontAwesome paper-plane (migrate) */ + font-size: 0.75em !important; + color: var(--pm-warning) !important; /* Amber to indicate operation in progress */ +} + +.x-tree-icon-custom.running.lock-backup::after, +.x-grid-icon-custom.running.lock-backup::after { + content: "\f0c7" !important; /* FontAwesome save/floppy (backup) */ + font-size: 0.75em !important; + color: var(--pm-warning) !important; +} + +.x-tree-icon-custom.running.lock-suspending::after, +.x-grid-icon-custom.running.lock-suspending::after { + content: "\f019" !important; /* FontAwesome download (suspending) */ + font-size: 0.75em !important; + color: var(--pm-warning) !important; +} + +.x-tree-icon-custom.stopped::before, +.x-grid-icon-custom.stopped::before { + color: var(--pm-text-disabled); +} + +/* ===================================================== + SCROLLBARS - Minimal, dark (UniFi authentic) + v5.93: Increased width from 8px to 12px for better clickability + ===================================================== */ +::-webkit-scrollbar { + width: 12px; + height: 12px; +} + +::-webkit-scrollbar-track { + background: #131416; +} + +::-webkit-scrollbar-thumb { + background: #34383D; + border-radius: 4px; +} + +::-webkit-scrollbar-thumb:hover { + background: rgba(249, 250, 250, 0.07); +} + +/* v5.84: Style scrollbar corner to match theme (eliminates white square) */ +::-webkit-scrollbar-corner { + background-color: #131416; +} + +/* ===================================================== + FIX: Labels and grid text - UniFi authentic colors + ===================================================== */ +.x-grid-cell-inner, +.x-grid-cell, +.x-form-display-field, +.x-form-display-field-default, +td, +.x-panel-body-default, +.x-grid-item { + color: #DEE0E3 !important; +} + +/* Column headers should be brighter */ +.x-column-header-text, +.x-column-header-text-inner, +.x-column-header-text-default { + color: var(--pm-text-bright) !important; +} + +/* Fix specific grid/table text */ +.x-grid-cell-inner span, +.x-grid-cell-inner div { + color: #DEE0E3; +} + +/* Resource panel labels */ +.x-form-item-label-inner { + color: #DEE0E3 !important; +} + +/* ===================================================== + FIX: Summary/Stats panels - add borders/cards + ===================================================== */ +.pveStatusPanel, +.x-panel-default-framed, +.x-panel-body-default-framed { + background-color: #131416 !important; + border: 1px solid #34383D !important; + border-radius: 12px !important; +} + +/* Stats panel body (Status, CPU, Memory, etc) - match Notes panel rounded corners */ +[id^="pveGuestStatusView-"][id$="-body"], +[id^="pmxNotesView-"] .x-panel-body { + border-radius: 8px !important; +} + +/* Panel headers in summary */ +.x-panel-header-default-framed { + background-color: #282B2F !important; + border: none !important; + border-bottom: 1px solid #34383D !important; + border-radius: 12px 12px 0 0 !important; +} + +/* Summary status grid - the table with CPU/Memory/etc */ +/* FIX v5.18: Removed overflow:hidden to restore content visibility */ +.pve-info-grid { + border-radius: 12px !important; +} + +/* Form display fields in summary (status fields) */ +.x-form-display-field-default { + border-radius: 6px !important; +} + +/* Graph containers - ensure visibility */ +.pve-rrdview, +.rrdview { + background-color: #131416 !important; + border: 1px solid #34383D !important; + border-radius: 12px !important; + padding: 12px !important; +} + +/* Chart/RRD panel specific - canvas should be transparent for chart lines to show */ +div[id*="rrdchart"], +.pve-rrddatastore, +.pmx-panel-rrd { + background-color: #131416 !important; +} + +/* Canvas elements - don't set background, let charts be visible */ +.proxmox-rrd-panel canvas, +.proxmox-widget-toolkit canvas, +canvas.x-surface, +.x-surface canvas { + background-color: transparent !important; + opacity: 1 !important; +} + +/* Proxmox RRD chart widget - ensure visibility */ +.proxmox-rrd-panel, +.proxmox-rrd-chart { + background-color: #131416 !important; +} + +/* Chart text/labels */ +.x-surface text, +svg text { + fill: #DEE0E3 !important; +} + +/* Summary status panel */ +.pve-summary-status, +.x-container .pve-status { + background-color: #131416 !important; + border: 1px solid #34383D !important; + border-radius: 8px !important; +} + +/* Notes panel */ +.x-panel-default[id*="notes"], +.pve-notes-view { + background-color: #131416 !important; + border: 1px solid #34383D !important; + border-radius: 8px !important; +} + +/* ===================================================== + FIX: Fieldset and form sections + ===================================================== */ +.x-fieldset { + background-color: #131416 !important; + border: 1px solid #34383D !important; + border-radius: 8px !important; + padding: 12px !important; +} + +.x-fieldset-header-text { + color: #F9FAFA !important; + font-weight: 500 !important; +} + +/* ===================================================== + FIX: UniFi-style rounded corners on hover/selection + ===================================================== */ + +/* Grid row hover/selection - rounded corners */ +.x-grid-item-over, +.x-grid-item-selected, +.x-grid-with-row-lines .x-grid-item.x-grid-item-over, +.x-grid-with-row-lines .x-grid-item.x-grid-item-selected { + border-radius: 6px !important; +} + +/* Menu items - rounded corners */ +.x-menu-item-default.x-menu-item-focus, +.x-menu-item-default.x-menu-item-active, +.x-menu-item:hover { + border-radius: 6px !important; +} + +/* Treelist/sidebar items - rounded corners (v5.9: 4px to match UniFi) */ +/* Background now handled by ::before pseudo-element in treelist section */ + +/* Boundlist dropdown items - rounded corners (v5.10: 4px to match UniFi) */ +.x-boundlist-item-over, +.x-boundlist-selected { + border-radius: 4px !important; +} + +/* Tab hover - rounded corners */ +.x-tab-default.x-tab-over, +.x-tab-default.x-tab.x-tab-active { + border-radius: 6px 6px 0 0 !important; +} + +/* ===================================================== + FIX: Remove underlines from column headers + ===================================================== */ +.x-column-header-over, +.x-column-header-open, +.x-column-header-sort-ASC, +.x-column-header-sort-DESC, +.x-column-header-last .x-column-header-over .x-column-header-trigger { + border-bottom: none !important; + text-decoration: none !important; +} + +/* Column header text - no underline */ +.x-column-header-text, +.x-column-header-text-inner { + text-decoration: none !important; + border-bottom: none !important; +} + +/* Selected grid cells - no underlines */ +.x-grid-item-selected .x-grid-cell-inner, +.x-grid-item-over .x-grid-cell-inner { + text-decoration: none !important; +} + +/* ===================================================== + FIX: Data view and resource lists + ===================================================== */ +.x-dataview-item { + color: #DEE0E3 !important; +} + +/* Resource grid specific */ +.pve-resource-grid .x-grid-cell-inner { + color: #DEE0E3 !important; +} + +/* Override any remaining dark text */ +.x-form-item-body, +.x-form-item { + color: hsla(214, 8%, 88%, 1) !important; +} + +/* Tree node text */ +.x-tree-node-text { + color: hsla(214, 8%, 88%, 1) !important; +} + +.x-treelist-item-text { + color: rgba(255, 255, 255, 0.75) !important; +} + +/* Selected items should be white */ +.x-grid-item-selected .x-grid-cell-inner, +.x-treelist-item-selected .x-treelist-item-text, +.x-tree-selected .x-tree-node-text { + color: #ffffff !important; +} + +/* ===================================================== + FIX: Tab text readability + ===================================================== */ +.x-tab-inner-default { + color: #B7BCC2 !important; +} + +.x-tab-active .x-tab-inner-default { + color: #ffffff !important; +} + +/* ===================================================== + SMOOTH TRANSITIONS - UniFi-style animations + ===================================================== */ + +/* Base transition for all interactive elements */ +.x-btn, +.x-btn-default-small, +.x-btn-default-toolbar-small, +.x-menu-item, +.x-grid-item, +.x-grid-row, +.x-treelist-item, +.x-treelist-row, +.x-tab, +.x-boundlist-item, +.x-tree-node, +.x-dataview-item, +.x-column-header, +.x-form-trigger, +.x-tool, +.x-panel-header { + transition: background-color 0.2s ease, + border-color 0.2s ease, + color 0.2s ease, + box-shadow 0.2s ease, + opacity 0.2s ease !important; +} + +/* Form elements transitions */ +.x-form-trigger-wrap, +.x-form-trigger-wrap-default, +.x-form-text, +.x-form-text-default, +.x-form-field { + transition: border-color 0.2s ease, + box-shadow 0.2s ease, + background-color 0.2s ease !important; +} + +/* Button hover glow effect */ +.x-btn-default-small:hover, +.x-btn-default-small.x-btn-over { + box-shadow: 0 2px 8px rgba(0, 102, 255, 0.3) !important; +} + +/* Toolbar fade moved to Button Section */ + +/* Grid row hover - smooth background change */ +.x-grid-item:hover, +.x-grid-item.x-grid-item-over { + background-color: var(--pm-hover-subtle) !important; +} + +/* Tree item hover - handled by ::before pseudo-element in treelist section */ + +/* Menu item hover */ +.x-menu-item:hover, +.x-menu-item-active { + background-color: #22252d !important; +} + +/* Tab hover */ +.x-tab:hover, +.x-tab.x-tab-over { + background-color: #1a1c22 !important; +} + +/* Dropdown item hover - UniFi style */ +.x-boundlist-item:hover, +.x-boundlist-item-over { + background-color: rgba(249, 250, 250, 0.04) !important; + color: #F9FAFA !important; +} + +/* Panel tool icons */ +.x-tool:hover { + opacity: 1 !important; +} + +.x-tool { + opacity: 0.7 !important; +} + +/* Links hover */ +a { + transition: color 0.2s ease !important; +} + +/* Input focus glow */ +.x-form-trigger-wrap-focus, +.x-form-trigger-wrap-default.x-form-trigger-wrap-focus { + box-shadow: 0 0 0 3px var(--pm-focus-ring-color) !important; +} + +/* Selected/active states should also transition smoothly */ +.x-grid-item-selected, +.x-treelist-item-selected>.x-treelist-row, +.x-tab-active { + transition: background-color 0.15s ease !important; +} + +/* Scrollbar smooth transition */ +::-webkit-scrollbar-thumb { + transition: background-color 0.2s ease !important; +} + +/* Progress bar animation */ +.x-progress-bar, +.x-progress-bar-default { + transition: width 0.3s ease !important; +} + +/* Splitter hover */ +.x-splitter { + transition: background-color 0.2s ease !important; +} + +.x-splitter:hover { + background-color: #2a2d36 !important; +} + +/* Window/dialog fade */ +.x-window { + transition: opacity 0.2s ease, transform 0.2s ease !important; +} + +/* Tooltip fade */ +.x-tip, +.x-tip-default { + transition: opacity 0.15s ease !important; +} + +/* Mask fade */ +.x-mask { + transition: opacity 0.2s ease !important; +} + +/* ===================================================== + v5.1 FIX: Segmented buttons (Day/Hour dropdown) + Only parent should have border-radius, not children + ===================================================== */ +.x-segmented-button { + border-radius: 6px !important; + overflow: visible !important; + display: flex !important; + gap: 5px !important; +} + +.x-segmented-button .x-btn, +.x-segmented-button .x-btn-default-small, +.x-segmented-button .x-btn-inner, +.x-segmented-button .x-btn-wrap { + border-radius: 6px !important; +} + +/* v5.24: Fix segmented buttons - use flex for horizontal alignment with gap */ +.x-segmented-button .proxmox-inline-button, +.x-segmented-button .x-btn { + display: flex !important; +} + +/* v5.25: Pressed segmented button text should be white for visibility on blue background */ +.x-segmented-button .x-btn.x-btn-pressed .x-btn-inner { + color: #ffffff !important; +} + +/* ===================================================== + v5.1 FIX: Progress bars - increase container height + The bars were getting cut off at bottom + ===================================================== */ +.pve-widget-chart-container, +.proxmox-gauge-chart, +.pve-resource-chart, +div[class*="chart-container"], +div[class*="gauge"] { + overflow: visible !important; +} + +/* ===================================================== + v5.1 FIX: Separator between left panel sections + Line between server list (left) and options menu (right) + ===================================================== */ +/* Remove individual item borders */ +.x-treelist-item, +.x-grid-item { + border-bottom: none !important; +} + +/* v5.3 FIX: Single separator between resource tree and content panel */ +/* Remove double separator - only use the splitter */ +#content, +.x-container.x-border-item.x-container-default[id="content"] { + border-left: none !important; +} + + + +/* ===================================================== + v5.1 FIX: Server view dropdown - smaller and styled + ===================================================== */ +.x-btn-default-toolbar-small.x-btn-menu-active, +.x-btn.x-btn-arrow.x-btn-default-small { + padding: 4px 10px !important; + min-height: 26px !important; + font-size: 12px !important; +} + +/* View mode combo/dropdown */ +.x-form-trigger-wrap-default:not([id^="textarea-"]):not(.x-grid-body), +.x-form-trigger-wrap:not([id^="textarea-"]):not(.x-grid-body) { + height: 28px !important; +} + +/* ===================================================== + v5.5 FIX: Preserve parent icon color when children are hovered + ===================================================== */ +/* The selected parent row should ALWAYS have blue icon, regardless of child hover state */ +.x-treelist-item-selected.x-treelist-item-expanded>.x-treelist-row .x-treelist-item-icon { + color: #006EFF !important; +} + +/* Even when entire treelist has hover somewhere, selected parent icon stays blue */ +.x-treelist-item-selected>.x-treelist-row .x-treelist-item-icon { + color: #006EFF !important; +} + +/* ===================================================== + v5.2 FIX: Toolbar buttons - ensure border-radius applies + ===================================================== */ + +/* Toolbar button hover state */ +.x-btn-default-toolbar-small:hover, +.x-btn-default-toolbar-small.x-btn-over { + background-color: #34383D !important; + border-color: #4A4F56 !important; +} + +/* Pressed/active state for toolbar buttons */ +.x-btn-default-toolbar-small.x-btn-pressed, +.x-btn-default-toolbar-small.x-btn-menu-active { + background-color: #006EFF !important; + border-color: #006EFF !important; +} + +/* Disabled state for toolbar buttons */ +.x-btn-default-toolbar-small.x-btn-disabled { + opacity: 0.4 !important; + cursor: not-allowed !important; +} + +/* ===================================================== + v5.2 FIX: Pointer cursor on tree items (entire item) + ===================================================== */ +.x-tree-node-text, +.x-grid-item, +.x-grid-cell, +.x-grid-cell-inner, +.x-tree-elbow-img, +.x-tree-icon, +#pveResourceTree .x-grid-item, +#pveResourceTree .x-grid-row, +.x-treelist-item, +.x-treelist-row, +.x-treelist-item-wrap, +.x-treelist-item-text, +.x-treelist-item-icon, +.x-treelistitem { + cursor: pointer !important; +} + +/* ===================================================== + v5.2 FIX: Navigation tree - reduced gaps & centered icons + ===================================================== */ +.x-treelist-item, +.x-treelistitem { + min-height: 28px !important; + height: auto !important; +} + +.x-treelist-row { + min-height: 28px !important; + padding: 2px 0 !important; + margin-right: 4px !important; + /* v5.7: symmetric spacing */ + display: flex !important; + align-items: center !important; +} + +/* v5.33: Reduce margin between toolbox navigation items */ +.x-treelist-pve-nav .x-treelist-row { + margin-top: 2px !important; +} + +/* v5.94: Increased margin-left (20px→28px) for better icon-to-label gap */ +.x-treelist-item-text { + margin-left: 28px !important; + line-height: 24px !important; + display: flex !important; + align-items: center !important; +} + +/* Center icons vertically in tree list */ +.x-treelist-item-icon { + display: flex !important; + align-items: center !important; + justify-content: center !important; + line-height: inherit !important; +} + +.x-treelist-item-wrap { + display: flex !important; + align-items: center !important; +} + +/* ===================================================== + v5.7 FIX: Toolbox tree expand/collapse animation + v5.18 FIX: Only apply animation to child containers, not main nav + ===================================================== */ +/* Main navigation container - must be visible */ +.x-treelist-pve-nav .x-treelist-container { + display: block !important; + overflow: visible !important; + overflow-y: auto !important; +} + +/* Child containers for expand/collapse animation */ +.x-treelist-item>.x-treelist-container { + overflow: hidden !important; + transition: max-height 0.25s ease-out, opacity 0.2s ease-out !important; +} + +/* Expanded state - show children */ +.x-treelist-item-expanded>.x-treelist-container { + max-height: 500px !important; + opacity: 1 !important; +} + +/* Collapsed state - hide children with animation */ +.x-treelist-item-collapsed>.x-treelist-container { + max-height: 0 !important; + opacity: 0 !important; +} + +/* ===================================================== + v5.9 FIX: Consistent 4px border-radius on treelist items (UniFi-style) + Note: Treelist hover/selected now handled by ::before pseudo-element + ===================================================== */ + +/* v5.54: Force 4px border-radius on treelist items and containers + (overrides default 8px from widget-toolkit) */ +.x-treelist-item-wrap, +.x-treelist-item-text, +.x-treelist-row, +.x-treelist-container, +.x-treelist-root-container, +.x-treelist, +.x-treelist-pve-nav { + border-radius: 4px !important; +} + +/* Resource tree selections - consistent 8px */ +.x-grid-item-selected, +.x-grid-item-focused, +.x-grid-item-over { + border-radius: 8px !important; +} + +/* v5.5 FIX: Symmetric wrap padding for treelist items */ +.x-treelist-item-wrap { + padding-left: 2px !important; + padding-right: 2px !important; +} + +/* v5.5 FIX: Same symmetric padding for selected items (no longer needs compensation) */ +.x-treelist-item-selected>.x-treelist-row .x-treelist-item-wrap { + padding-left: 2px !important; + padding-right: 2px !important; +} + +/* v5.5 FIX: Add left margin to icon for visual balance */ +.x-treelist-item-icon { + margin-left: 4px !important; +} + +/* ===================================================== + v5.2 FIX: Remove blue focus box on grid items + ===================================================== */ +.x-keyboard-mode .x-grid-cell-inner::before, +.x-grid-item-focused .x-grid-cell-inner::before, +.x-grid-cell-inner::before { + content: none !important; + border: none !important; + display: none !important; +} + +/* Remove focus outline */ +.x-grid-item-focused, +.x-grid-item-focused .x-grid-cell, +.x-grid-item-focused .x-grid-cell-inner { + outline: none !important; + box-shadow: none !important; +} + +/* ===================================================== + v5.2 FIX: Font weight for Datacenter and Node items only + ===================================================== */ +.fa-server~.x-tree-node-text, +.fa-building~.x-tree-node-text { + font-weight: 600 !important; +} + +/* ===================================================== + v5.2 FIX: Global smooth scrolling + ===================================================== */ +html { + scroll-behavior: smooth !important; +} + +/* ===================================================== + v5.4 FIX: Child items styling when parent is selected + ===================================================== */ +/* Reset text/icon color for non-selected children of selected parent */ +.x-treelist-item-selected .x-treelist-item:not(.x-treelist-item-selected) .x-treelist-item-text, +.x-treelist-item-selected .x-treelist-item:not(.x-treelist-item-selected) .x-treelist-item-icon { + color: #B7BCC2 !important; +} + +/* ===================================================== + v5.4 FIX: Remove double separator between panels + ===================================================== */ +#pveResourceTree-1011-body, +.pve-resource-tree .x-panel-body, +.x-panel-body.x-grid-body { + border-right: none !important; +} + +/* ===================================================== + v5.4 FIX: Hover state for tree items + ===================================================== */ +/* Hover background for normal items */ +.x-treelist-item-over>.x-treelist-row { + background-color: #23262A !important; +} + +/* Hover background for child items inside selected parent - higher specificity */ +.x-treelist-item-selected .x-treelist-item.x-treelist-item-over:not(.x-treelist-item-selected)>.x-treelist-row { + background-color: #23262A !important; +} + +/* Hover text/icon color */ +.x-treelist-item-over>.x-treelist-row .x-treelist-item-text, +.x-treelist-item-over>.x-treelist-row .x-treelist-item-icon, +.x-treelist-item-selected .x-treelist-item.x-treelist-item-over:not(.x-treelist-item-selected)>.x-treelist-row .x-treelist-item-text, +.x-treelist-item-selected .x-treelist-item.x-treelist-item-over:not(.x-treelist-item-selected)>.x-treelist-row .x-treelist-item-icon { + color: #FFFFFF !important; +} + +/* ===================================================== + v5.4 FIX: Resource tree (grid) - left sidebar styling + ===================================================== */ +/* Server View resource tree is not a table: disable table row separators */ +[id^="pveResourceTree-"].x-tree-panel td.x-grid-cell, +[id^="pveResourceTree-"].x-tree-panel .x-grid-td, +[id^="pveResourceTree-"].x-tree-panel .x-grid-cell { + border-bottom: none !important; +} + +/* Server View resource tree: compact VM/CT leaf rows (verified via DevTools) */ +[id^="pveResourceTree-"].x-tree-panel tr.x-grid-row.x-grid-tree-node-leaf .x-grid-cell-inner, +[id^="pveResourceTree-"].x-tree-panel .x-grid-item.x-grid-tree-node-leaf .x-grid-cell-inner { + padding-top: 2px !important; + padding-bottom: 2px !important; +} + +/* Server View resource tree: prevent last-leaf indent shift (x-tree-elbow-end has extra margin) */ +[id^="pveResourceTree-"].x-tree-panel .x-tree-elbow-end { + margin-right: 0 !important; +} + +[id^="pveResourceTree-"].x-tree-panel tr.x-grid-row.x-grid-tree-node-leaf .x-tree-node-text, +[id^="pveResourceTree-"].x-tree-panel .x-grid-item.x-grid-tree-node-leaf .x-tree-node-text { + line-height: 17px !important; +} + +/* Non-selected items should show gray text */ +.x-grid-item:not(.x-grid-item-selected):not(.x-grid-item-focused) .x-tree-node-text { + color: #B7BCC2 !important; +} + +/* Non-selected item icons should be gray */ +.x-grid-item:not(.x-grid-item-selected):not(.x-grid-item-focused) .x-tree-icon, +.x-grid-item:not(.x-grid-item-selected):not(.x-grid-item-focused) .fa { + color: #B7BCC2 !important; +} + +/* v5.94: Preserve status icon colors in grid items + The broad .fa color rule above overrides .good/.warning/.critical from ext6-pmx.css */ +.x-grid-item:not(.x-grid-item-selected):not(.x-grid-item-focused) .fa.good { + color: var(--pm-success) !important; +} +.x-grid-item:not(.x-grid-item-selected):not(.x-grid-item-focused) .fa.warning { + color: var(--pm-warning) !important; +} +.x-grid-item:not(.x-grid-item-selected):not(.x-grid-item-focused) .fa.critical { + color: var(--pm-error) !important; +} + +/* Selected item text should be white */ +.x-grid-item-selected .x-tree-node-text, +.x-grid-item-focused .x-tree-node-text { + color: #FFFFFF !important; +} + +/* Selected item icons should be blue */ +.x-grid-item-selected .x-tree-icon, +.x-grid-item-selected .fa, +.x-grid-item-focused .x-tree-icon, +.x-grid-item-focused .fa { + color: #3B8BEB !important; +} + +/* Hover state for grid items - text stays primary color */ +.x-grid-item-over:not(.x-grid-item-selected) .x-tree-node-text { + color: #DEE0E3 !important; +} + +/* Hover state for grid items - icons color */ +.x-grid-item-over:not(.x-grid-item-selected) .x-tree-icon, +.x-grid-item-over:not(.x-grid-item-selected) .fa { + color: #DEE0E3 !important; +} + + + + + + + + + +/* Content panel margin for splitter spacing */ +#content { + margin-left: 6px !important; +} + +/* ===================================================== + CHARTS - Remove border-radius from data area only + (Outer panel container keeps its rounded corners) + ===================================================== */ +/* Remove border-radius from chart canvas/data area ONLY */ +canvas.x-surface-canvas, +.x-surface-canvas, +.x-draw-component canvas, +.proxmox-rrd-chart canvas { + border-radius: 0 !important; +} + +/* SVG surface if used */ +svg.x-surface { + border-radius: 0 !important; +} + +/* Draw container that holds the canvas */ +.x-draw-container, +.x-surface { + border-radius: 0 !important; +} + +/* ===================================================== + HEADER BUTTONS - Vertical centering fix + ===================================================== */ +/* Button flex styles moved to Button Section */ + +/* Documentation button */ +.proxmox-inline-button { + height: 28px !important; + min-height: 28px !important; + display: flex !important; + align-items: center !important; + padding: 3px 8px !important; +} + +/* Specific fix for fa-desktop icon (Create VM) - visually bottom-heavy */ +.x-btn-icon-el.fa-desktop { + transform: translateY(1.1px) !important; +} + +/* v5.27: Fix icon-only button width (hide   inner element) - MUST be at end to override earlier rules */ +/* ExtJS adds x-btn-no-text class to buttons with only an icon */ +.x-btn-no-text .x-btn-inner, +.x-btn-button.x-btn-no-text .x-btn-inner, +.x-btn-button-default-toolbar-small.x-btn-no-text .x-btn-inner-default-toolbar-small, +.x-btn-button-default-small.x-btn-no-text .x-btn-inner-default-small, +.x-btn-button-default-small.x-btn-no-text>.x-btn-inner-default-small, +.x-btn.x-btn-default-small .x-btn-button.x-btn-no-text .x-btn-inner { + display: none !important; +} + +/* ===================================================== + v5.18 FIX: Scroll and overflow fixes for content visibility + ===================================================== */ +/* FIX 1: Remove overflow:hidden from grid containers to restore content visibility */ +.pve-info-grid, +.x-panel-default .x-grid, +.x-container .x-grid-view { + overflow: visible !important; + overflow-y: auto !important; +} + +/* FIX 2: Vertical toolbar scrolling with hidden scrollbar */ +.x-toolbar.x-vertical .x-box-scroller-body-vertical { + overflow-y: auto !important; + overflow-x: hidden !important; + scrollbar-width: none !important; + -ms-overflow-style: none !important; +} + +/* Hide scrollbar for Chrome/Safari/Opera */ +.x-toolbar.x-vertical .x-box-scroller-body-vertical::-webkit-scrollbar { + display: none !important; + width: 0 !important; +} + +/* FIX 3: Make sure the vertical toolbar doesn't hide overflow */ +.x-toolbar.x-vertical { + overflow: visible !important; + overflow-y: visible !important; +} + +/* ===================================================== + v5.35 FIX: Center "IPs" label vertically with IP addresses + Works together with v5.87 button repositioning + ===================================================== */ +/* IPs label container - translate down 9px for vertical centering */ +[id^="pveIPViewLXC-"]>.x-box-inner>.x-box-target>[id^="box-"] { + transform: translateY(9px) !important; +} + +/* ===================================================== + v5.18 FIX: CRITICAL - Restore grid/tree content visibility + These must be at the END of the file to override earlier rules + ===================================================== */ +/* Remove overflow:hidden that was hiding grid content */ +.pve-info-grid, +.x-panel-default .x-grid, +.x-container .x-grid-view, +.x-tree-view, +.x-tree-panel .x-panel-body, +.x-grid-view { + overflow: visible !important; +} + +/* Tree/grid scroll containers */ +.x-tree-view.x-fit-item, +.x-grid-view.x-fit-item { + overflow: auto !important; +} + +/* Grid item containers must be visible */ +.x-grid-item-container { + overflow: visible !important; +} + +/* ===================================================== + v5.57: Fix summary page widget panels border-radius + Column-layout panels (Health, Guests, Resources, etc.) + have visible borders that need rounded corners to + match the parent panel's 8px radius. + ===================================================== */ +.x-panel.x-column>.x-panel-bodyWrap>.x-panel-body.x-panel-body-default { + border-radius: 8px !important; +} + +/* Tree navigation container */ +.x-treelist-pve-nav .x-treelist-container { + overflow: visible !important; + overflow-y: auto !important; +} + +/* ===================================================== + v5.40: Fix floating grid picker border-radius + Storage dropdown, ISO selector, etc. use grid layers + Should match 4px boundlist style, not 12px summary panels + ===================================================== */ +.x-layer.x-grid .x-grid-view, +.x-panel.x-layer.x-grid .x-grid-view { + border-radius: 4px !important; +} + +.x-panel.x-layer.x-grid, +.x-layer.x-panel.x-grid { + border-radius: 4px !important; +} + +/* Grid items in floating pickers - 4px radius (matches boundlist style) */ +.x-layer.x-grid .x-grid-item-over, +.x-layer.x-grid .x-grid-item-selected, +.x-panel.x-layer.x-grid .x-grid-item-over, +.x-panel.x-layer.x-grid .x-grid-item-selected { + border-radius: 4px !important; +} + +/* TD cells have their own background - reset and apply only to first/last */ +.x-layer.x-grid .x-grid-item-over td, +.x-layer.x-grid .x-grid-item-selected td, +.x-layer.x-grid .x-grid-item-over .x-grid-cell, +.x-layer.x-grid .x-grid-item-selected .x-grid-cell, +.x-panel.x-layer.x-grid .x-grid-item-over td, +.x-panel.x-layer.x-grid .x-grid-item-selected td, +.x-panel.x-layer.x-grid .x-grid-item-over .x-grid-cell, +.x-panel.x-layer.x-grid .x-grid-item-selected .x-grid-cell { + border-radius: 0 !important; +} + +/* First cell gets left radius, last cell gets right radius */ +.x-layer.x-grid .x-grid-item-over td:first-child, +.x-layer.x-grid .x-grid-item-selected td:first-child, +.x-panel.x-layer.x-grid .x-grid-item-over td:first-child, +.x-panel.x-layer.x-grid .x-grid-item-selected td:first-child { + border-radius: 4px 0 0 4px !important; +} + +.x-layer.x-grid .x-grid-item-over td:last-child, +.x-layer.x-grid .x-grid-item-selected td:last-child, +.x-panel.x-layer.x-grid .x-grid-item-over td:last-child, +.x-panel.x-layer.x-grid .x-grid-item-selected td:last-child { + border-radius: 0 4px 4px 0 !important; +} + +/* ===================================================== + v5.42: Fix Bulk Actions dropdown button issues + Button was growing larger (24px → 26px) and text was gray instead of white + ===================================================== */ + +/* Toolbar menu fix moved to Button Section */ + +/* ===================================================== + v5.43: Compact tab bar for Tasks/Cluster log panel + Reduces wasted vertical space in bottom panel tabs + Tab bar height: 36px → 26px, padding: 6px → 3px + ===================================================== */ + +/* Reduce tab bar height for south panel (Tasks/Cluster log) */ +.x-panel.x-border-item .x-tab-bar.x-docked.x-tab-bar-default-horizontal { + height: 26px !important; +} + +/* Reduce inner body padding */ +.x-panel.x-border-item .x-tab-bar.x-docked .x-box-inner { + padding-top: 3px !important; + padding-bottom: 3px !important; +} + +/* Adjust panel body position to account for smaller tab bar */ +/* v5.56: Exclude grids - they need ExtJS inline positioning for proper header display */ +/* .x-panel.x-border-item:not(.x-grid) .x-panel-body.x-panel-body-default { + top: 26px !important; +} */ + +/* ===================================================== + v5.72: COMPREHENSIVE MODAL SPACING & CLIPPING FIX + + Problem: The v5.43 rule (top: 26px for south panel tabs) cascaded + to ALL panel bodies inside dialogs/windows, creating 52-70px gaps + between title/tabs and tabs/content, plus content clipping. + + Solution: Reset ALL panel bodies to 0, then restore 26px ONLY for + the body that immediately follows a tab bar (using sibling selector). + Uses ultra-high specificity with 'body' prefix to win CSS battles. + ===================================================== */ + +/* Restore 26px ONLY for the panel body that immediately follows a tab bar */ +body .x-window .x-panel .x-panel-bodyWrap>.x-tab-bar+.x-panel-body.x-panel-body-default { + top: 26px !important; +} + +/* Zero out padding in bodyWraps that could cause extra gaps */ +.x-window .x-panel-bodyWrap { + padding: 0 !important; +} + +/* v5.93: REMOVED overflow: visible rule that was breaking log viewer scrolling + The original rule was: + .x-window .x-panel-body { overflow: visible !important; } + This was added to "fix overflow clipping - allow visible overflow in modal panels" + but it breaks task viewer / log viewer scroll functionality. + If clipping issues appear elsewhere, use more targeted selectors. +*/ + +/* But keep auto overflow on the main window body for scrolling */ +/* .x-window .x-window-body { + overflow: auto !important; +} */ + +/* ===================================================== + v5.58: Fix modal form field width overflow + Form fields were extending past the right edge of the modal. + Constrain autocontainer and trigger wrap widths. + v5.64: REMOVED margin-right rule - was causing input field cutoff. + The autocontainer constraint is sufficient for overflow prevention. + + +/* v5.61: Trigger-wrap width rule removed (consolidated into form layout section) */ + + + +/* ===================================================== + v5.47: Restore right border on disk list panel in wizards + Restores right border for grids inside windows (fixed v5.4 over-reach). + ===================================================== */ + + +/* ===================================================== + v5.48: MODAL ANIMATIONS - Open Animation + Background Blur + CSS-ONLY implementation (no JavaScript required) + + Features: + - Smooth fade-in + scale animation when modals/dialogs open + - Subtle backdrop blur effect for modern look + - Menu/dropdown slide-in animation + + NOTE: Close animations are NOT possible with pure CSS because + ExtJS removes the window from the DOM immediately on close. + This is a pure CSS theme - no JavaScript modifications. + ===================================================== */ + +/* Opening animation keyframe */ +@keyframes modalFadeIn { + from { + opacity: 0; + transform: scale(0.95) translateY(-10px); + } + + to { + opacity: 1; + transform: scale(1) translateY(0); + } +} + +/* Menu slide animation keyframe */ +@keyframes menuSlideIn { + from { + opacity: 0; + transform: translateY(-5px); + } + + to { + opacity: 1; + transform: translateY(0); + } +} + + + +/* Window/Dialog - open animation */ +.x-window, +.x-window-default { + animation: modalFadeIn 0.2s ease-out forwards !important; + transform-origin: center top !important; +} + +/* Message boxes - centered origin */ +.x-message-box { + animation: modalFadeIn 0.2s ease-out forwards !important; + transform-origin: center center !important; +} + +/* Menus and dropdowns - slide animation */ +.x-menu, +.x-menu-default, +.x-boundlist { + animation: menuSlideIn 0.12s ease-out forwards !important; + transform-origin: top center !important; +} + +/* ===================================================== + v5.77: TREE SETTINGS DIALOG FIX + Force layout recalculation and visibility for tree settings + ===================================================== */ +.x-window[id^="pveTreeSettingsEdit"] .x-panel-body { + width: 100% !important; + min-width: 300px !important; +} + +.x-window[id^="pveTreeSettingsEdit"] .x-autocontainer-innerCt { + width: 100% !important; + display: block !important; +} + +.x-window[id^="pveTreeSettingsEdit"] .x-window-body { + overflow: visible !important; + height: auto !important; +} + +.x-window[id^="pveTreeSettingsEdit"] input { + width: 100% !important; + visibility: visible !important; + display: block !important; + opacity: 1 !important; +} + +.x-window[id^="pveTreeSettingsEdit"] .x-form-item-body, +.x-window[id^="pveTreeSettingsEdit"] .x-form-trigger-wrap, +.x-window[id^="pveTreeSettingsEdit"] .x-form-text-wrap { + width: 100% !important; + overflow: visible !important; +} + +/* v5.82: Fix Tree Settings Dialog Width (Force full width on containers) */ +.x-window[id^="pveTreeSettingsEdit"] .x-panel[id^="inputpanel"], +.x-window[id^="pveTreeSettingsEdit"] .x-panel[id^="inputpanel"] .x-panel-body, +.x-window[id^="pveTreeSettingsEdit"] .x-panel[id^="inputpanel"] .x-box-inner, +.x-window[id^="pveTreeSettingsEdit"] .x-panel[id^="inputpanel"] .x-box-target, +.x-window[id^="pveTreeSettingsEdit"] .x-panel[id^="inputpanel"] .x-container, +.x-window[id^="pveTreeSettingsEdit"] .x-panel[id^="inputpanel"] .x-field { + width: 100% !important; + box-sizing: border-box !important; +} + +/* ===================================================== + v5.78: LOGIN DIALOG FIXES + 1. Remove inner panel borders for cleaner "direct on window" look + 2. Rely on ExtJS natural sizing (facilitated by removing the + width:inherit rule above) + ===================================================== */ +.x-window:has(#pveloginrealm) .x-panel-body { + border: none !important; + background: transparent !important; + width: auto !important; +} + +/* ===================================================== + v5.81: VM WIZARD WIDTH FIX (REVISED) + 1. Keep window borders (user preference). + 2. Force internal elements to fit the measured content width + (718.4px) instead of overflowing at fixed 720px. + ===================================================== */ +.x-window[id^="pveQemuCreateWizard"] .x-window-body, +.x-window[id^="pveQemuCreateWizard"] .x-window-body>.x-panel, +.x-window[id^="pveQemuCreateWizard"] .x-panel-bodyWrap, +.x-window[id^="pveQemuCreateWizard"] .x-panel-body { + width: 100% !important; + box-sizing: border-box !important; +} + +/* ===================================================== + v5.86: TOOL ICONS - FontAwesome Replacements + Replace sprite-based ExtJS tool icons with crisp + FontAwesome icons for better consistency and clarity + ===================================================== */ + +/* Base styling for all tool icons - remove sprite backgrounds */ +.x-tool-tool-el.x-tool-minus, +.x-tool-img.x-tool-minus, +.x-tool-tool-el.x-tool-collapse-right, +.x-tool-img.x-tool-collapse-right, +.x-tool-tool-el.x-tool-collapse-left, +.x-tool-img.x-tool-collapse-left, +.x-tool-tool-el.x-tool-expand-right, +.x-tool-img.x-tool-expand-right, +.x-tool-tool-el.x-tool-expand-left, +.x-tool-img.x-tool-expand-left, +.x-tool-tool-el.x-tool-maximize, +.x-tool-img.x-tool-maximize, +.x-tool-tool-el.x-tool-restore, +.x-tool-img.x-tool-restore, +.x-tool-tool-el.x-tool-gear, +.x-tool-img.x-tool-gear, +.x-tool-tool-el.x-tool-refresh, +.x-tool-img.x-tool-refresh { + background-image: none !important; + font-family: "FontAwesome" !important; + font-size: 14px !important; + line-height: 16px !important; + text-align: center !important; + color: #737C87 !important; + transition: color 0.15s ease !important; + filter: none !important; + width: 16px !important; + height: 16px !important; + display: flex !important; + align-items: center !important; + justify-content: center !important; +} + +/* Undo Zoom button (minus icon) - use zoom-out icon */ +.x-tool-tool-el.x-tool-minus::before, +.x-tool-img.x-tool-minus::before { + content: "\f010" !important; /* fa-search-minus (zoom out) */ +} + +/* Collapse right - single chevron pointing right (>) + Panel is expanded, clicking will collapse it to the right */ +.x-tool-tool-el.x-tool-collapse-right::before, +.x-tool-img.x-tool-collapse-right::before { + content: "\f054" !important; /* fa-chevron-right (>) */ +} + +/* Expand left - single chevron pointing left (<) + Panel is collapsed on right, clicking will expand it to the left */ +.x-tool-tool-el.x-tool-expand-left::before, +.x-tool-img.x-tool-expand-left::before { + content: "\f053" !important; /* fa-chevron-left (<) */ +} + +/* Collapse left - single chevron pointing left (<) + Panel is expanded, clicking will collapse it to the left */ +.x-tool-tool-el.x-tool-collapse-left::before, +.x-tool-img.x-tool-collapse-left::before { + content: "\f053" !important; /* fa-chevron-left (<) */ +} + +/* Expand right - single chevron pointing right (>) + Panel is collapsed on left, clicking will expand it to the right */ +.x-tool-tool-el.x-tool-expand-right::before, +.x-tool-img.x-tool-expand-right::before { + content: "\f054" !important; /* fa-chevron-right (>) */ +} + +/* Maximize (expand icon) */ +.x-tool-tool-el.x-tool-maximize::before, +.x-tool-img.x-tool-maximize::before { + content: "\f065" !important; /* fa-expand */ +} + +/* Restore (compress icon) */ +.x-tool-tool-el.x-tool-restore::before, +.x-tool-img.x-tool-restore::before { + content: "\f066" !important; /* fa-compress */ +} + +/* Gear/Settings icon */ +.x-tool-tool-el.x-tool-gear::before, +.x-tool-img.x-tool-gear::before { + content: "\f013" !important; /* fa-cog */ +} + +/* Refresh icon */ +.x-tool-tool-el.x-tool-refresh::before, +.x-tool-img.x-tool-refresh::before { + content: "\f021" !important; /* fa-refresh */ +} + +/* Hover state - all tool icons */ +.x-tool:hover .x-tool-tool-el.x-tool-minus, +.x-tool:hover .x-tool-img.x-tool-minus, +.x-tool:hover .x-tool-tool-el.x-tool-collapse-right, +.x-tool:hover .x-tool-img.x-tool-collapse-right, +.x-tool:hover .x-tool-tool-el.x-tool-collapse-left, +.x-tool:hover .x-tool-img.x-tool-collapse-left, +.x-tool:hover .x-tool-tool-el.x-tool-expand-right, +.x-tool:hover .x-tool-img.x-tool-expand-right, +.x-tool:hover .x-tool-tool-el.x-tool-expand-left, +.x-tool:hover .x-tool-img.x-tool-expand-left, +.x-tool:hover .x-tool-tool-el.x-tool-maximize, +.x-tool:hover .x-tool-img.x-tool-maximize, +.x-tool:hover .x-tool-tool-el.x-tool-restore, +.x-tool:hover .x-tool-img.x-tool-restore, +.x-tool:hover .x-tool-tool-el.x-tool-gear, +.x-tool:hover .x-tool-img.x-tool-gear, +.x-tool:hover .x-tool-tool-el.x-tool-refresh, +.x-tool:hover .x-tool-img.x-tool-refresh { + color: #DEE0E3 !important; +} + +/* Disabled state */ +.x-tool-disabled .x-tool-tool-el, +.x-tool-disabled .x-tool-img { + opacity: 0.4 !important; + cursor: default !important; +} + +/* ===================================================== + v5.86: GENERIC TOOL ICONS (Inline FontAwesome) + Some ExtJS tools use inline style="font-family:FontAwesome" + with text content for their icons instead of ::before + ===================================================== */ + +/* Style generic tools that use text content with FontAwesome */ +.x-tool-tool-el[style*="font-family:FontAwesome"], +.x-tool-tool-el[style*="font-family: FontAwesome"] { + color: #737C87 !important; + font-size: 14px !important; + line-height: 16px !important; + display: flex !important; + align-items: center !important; + justify-content: center !important; + width: 16px !important; + height: 16px !important; + transition: color 0.15s ease !important; + background-image: none !important; + background-color: transparent !important; +} + +/* Enabled state - pointer cursor */ +.x-tool:not(.x-tool-disabled) .x-tool-tool-el[style*="font-family:FontAwesome"], +.x-tool:not(.x-tool-disabled) .x-tool-tool-el[style*="font-family: FontAwesome"] { + cursor: pointer !important; +} + +/* Disabled state - default cursor and reduced opacity */ +.x-tool.x-tool-disabled .x-tool-tool-el[style*="font-family:FontAwesome"], +.x-tool.x-tool-disabled .x-tool-tool-el[style*="font-family: FontAwesome"] { + cursor: default !important; + opacity: 0.4 !important; +} + +/* Fix mask overlay on tool icons - transparent and non-blocking */ +.x-tool .x-mask { + background-color: transparent !important; + backdrop-filter: none !important; + pointer-events: none !important; +} + +/* Hover state for enabled generic tools */ +.x-tool:not(.x-tool-disabled):hover .x-tool-tool-el[style*="font-family:FontAwesome"], +.x-tool:not(.x-tool-disabled):hover .x-tool-tool-el[style*="font-family: FontAwesome"] { + color: #DEE0E3 !important; +} \ No newline at end of file