mirror of
https://github.com/ChuckBuilds/LEDMatrix.git
synced 2026-08-01 08:48:05 +00:00
The floating preview opened empty and stayed empty until the display next CHANGED - the SSE stream only pushes frames on change, and the panel only consumed frames while already open, so the connection's initial frame (sent while the panel was closed) was dropped. Reported from mobile testing as "the button doesn't work". - updateDisplayPreview now caches the latest frame globally regardless of panel state; opening the panel populates the image from that cache instantly, then live frames take over. - Resizable: a size button cycles 192/256/384/512px presets (persisted per browser; works on touch), and desktop additionally gets a native drag handle (CSS resize: both). The image is fluid within the panel; on phones the panel is capped to the viewport width. The size icon (fa-up-right-and-down-left-from-center) is verified present in the vendored FA 6.0.0. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KEZK1P1Q1fu5pcuVrkrCFZ
1400 lines
39 KiB
CSS
1400 lines
39 KiB
CSS
/* LED Matrix v3 Custom Styles */
|
|
/* Modern, clean design with utility classes */
|
|
|
|
/* CSS Custom Properties for Theme Colors */
|
|
:root {
|
|
--color-primary: #2563eb;
|
|
--color-primary-hover: #1d4ed8;
|
|
--color-secondary: #059669;
|
|
--color-secondary-hover: #047857;
|
|
--color-accent: #7c3aed;
|
|
--color-accent-hover: #6d28d9;
|
|
--color-background: #f9fafb;
|
|
--color-surface: #ffffff;
|
|
--color-text-primary: #111827;
|
|
--color-text-secondary: #374151;
|
|
--color-text-tertiary: #4b5563;
|
|
--color-border: #e5e7eb;
|
|
--color-border-light: #f3f4f6;
|
|
--color-success: #059669;
|
|
--color-success-bg: #d1fae5;
|
|
--color-error: #dc2626;
|
|
--color-error-bg: #fee2e2;
|
|
--color-warning: #d97706;
|
|
--color-warning-bg: #fef3c7;
|
|
--color-info: #2563eb;
|
|
--color-info-bg: #dbeafe;
|
|
--color-purple-bg: #f3e8ff;
|
|
--color-purple-text: #6b21a8;
|
|
--shadow-sm: 0 1px 2px 0 rgb(0 0 0 / 5%);
|
|
--shadow: 0 1px 3px 0 rgb(0 0 0 / 10%), 0 1px 2px 0 rgb(0 0 0 / 6%);
|
|
--shadow-md: 0 4px 6px -1px rgb(0 0 0 / 10%), 0 2px 4px -1px rgb(0 0 0 / 6%);
|
|
--shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 10%), 0 4px 6px -2px rgb(0 0 0 / 5%);
|
|
}
|
|
|
|
/* Dark Theme Overrides */
|
|
[data-theme="dark"] {
|
|
--color-primary: #3b82f6;
|
|
--color-primary-hover: #60a5fa;
|
|
--color-secondary: #10b981;
|
|
--color-secondary-hover: #34d399;
|
|
--color-accent: #8b5cf6;
|
|
--color-accent-hover: #a78bfa;
|
|
--color-background: #111827;
|
|
--color-surface: #1f2937;
|
|
--color-text-primary: #f9fafb;
|
|
--color-text-secondary: #d1d5db;
|
|
--color-text-tertiary: #9ca3af;
|
|
--color-border: #374151;
|
|
--color-border-light: #1f2937;
|
|
--color-success: #34d399;
|
|
--color-success-bg: #064e3b;
|
|
--color-error: #f87171;
|
|
--color-error-bg: #7f1d1d;
|
|
--color-warning: #fbbf24;
|
|
--color-warning-bg: #78350f;
|
|
--color-info: #60a5fa;
|
|
--color-info-bg: #1e3a5f;
|
|
--color-purple-bg: #2e1065;
|
|
--color-purple-text: #c4b5fd;
|
|
--shadow-sm: 0 1px 2px 0 rgb(0 0 0 / 30%);
|
|
--shadow: 0 1px 3px 0 rgb(0 0 0 / 40%), 0 1px 2px 0 rgb(0 0 0 / 30%);
|
|
--shadow-md: 0 4px 6px -1px rgb(0 0 0 / 40%), 0 2px 4px -1px rgb(0 0 0 / 30%);
|
|
--shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 40%), 0 4px 6px -2px rgb(0 0 0 / 30%);
|
|
}
|
|
|
|
/* Dark Mode - Utility Class Overrides */
|
|
[data-theme="dark"] .bg-white { background-color: var(--color-surface); }
|
|
[data-theme="dark"] .bg-gray-50 { background-color: var(--color-background); }
|
|
[data-theme="dark"] .bg-gray-100 { background-color: var(--color-surface); }
|
|
[data-theme="dark"] .bg-gray-200 { background-color: var(--color-border); }
|
|
|
|
[data-theme="dark"] .text-gray-900 { color: var(--color-text-primary); }
|
|
[data-theme="dark"] .text-gray-600 { color: var(--color-text-tertiary); }
|
|
[data-theme="dark"] .text-gray-500 { color: var(--color-text-tertiary); }
|
|
[data-theme="dark"] .text-gray-400 { color: var(--color-text-tertiary); }
|
|
[data-theme="dark"] .text-green-600 { color: var(--color-success); }
|
|
[data-theme="dark"] .text-red-600 { color: var(--color-error); }
|
|
|
|
[data-theme="dark"] .border-gray-200 { border-color: var(--color-border); }
|
|
[data-theme="dark"] .border-gray-300 { border-color: #4b5563; }
|
|
|
|
[data-theme="dark"] .hover\:bg-gray-50:hover { background-color: var(--color-border); }
|
|
[data-theme="dark"] .hover\:bg-gray-200:hover { background-color: #4b5563; }
|
|
[data-theme="dark"] .hover\:text-gray-700:hover { color: #e5e7eb; }
|
|
[data-theme="dark"] .hover\:border-gray-300:hover { border-color: #6b7280; }
|
|
[data-theme="dark"] .bg-red-100 { background-color: #450a0a; }
|
|
[data-theme="dark"] .bg-yellow-100 { background-color: #422006; }
|
|
[data-theme="dark"] .bg-green-100 { background-color: #022c22; }
|
|
[data-theme="dark"] .text-red-700 { color: #fca5a5; }
|
|
[data-theme="dark"] .hover\:bg-red-200:hover { background-color: #7f1d1d; }
|
|
|
|
/* Base styles */
|
|
* {
|
|
box-sizing: border-box;
|
|
}
|
|
|
|
html {
|
|
scroll-behavior: smooth;
|
|
}
|
|
|
|
body {
|
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
|
|
line-height: 1.6;
|
|
color: var(--color-text-primary);
|
|
background-color: var(--color-background);
|
|
}
|
|
|
|
/* Utility classes */
|
|
.bg-gray-50 { background-color: #f9fafb; }
|
|
.bg-gray-100 { background-color: #f3f4f6; }
|
|
.bg-white { background-color: #ffffff; }
|
|
.bg-gray-800 { background-color: #1f2937; }
|
|
.bg-gray-900 { background-color: #111827; }
|
|
.bg-green-500 { background-color: #10b981; }
|
|
.bg-red-500 { background-color: #ef4444; }
|
|
.bg-blue-500 { background-color: #3b82f6; }
|
|
.bg-yellow-500 { background-color: #f59e0b; }
|
|
.bg-green-600 { background-color: #059669; }
|
|
.bg-red-600 { background-color: #dc2626; }
|
|
.bg-blue-600 { background-color: #2563eb; }
|
|
.bg-yellow-600 { background-color: #d97706; }
|
|
.bg-gray-200 { background-color: #e5e7eb; }
|
|
|
|
/* Log level row backgrounds (subtle tints on dark log container) */
|
|
.log-level-error { background-color: rgb(127 29 29 / 10%); }
|
|
.log-level-warning { background-color: rgb(120 53 15 / 10%); }
|
|
.log-level-debug { background-color: rgb(31 41 55 / 30%); }
|
|
|
|
.text-gray-100 { color: #f3f4f6; }
|
|
.text-gray-200 { color: #e5e7eb; }
|
|
.text-gray-300 { color: #d1d5db; }
|
|
.text-gray-900 { color: #111827; }
|
|
.text-gray-600 { color: #374151; }
|
|
.text-gray-500 { color: #4b5563; }
|
|
.text-gray-400 { color: #6b7280; }
|
|
.text-red-300 { color: #fca5a5; }
|
|
.text-yellow-300 { color: #fcd34d; }
|
|
.text-white { color: #ffffff; }
|
|
.text-green-600 { color: #059669; }
|
|
.text-red-600 { color: #dc2626; }
|
|
|
|
/* Status badge chips (e.g. tools.html's dirty/clean and power-status badges) */
|
|
.bg-red-100 { background-color: #fee2e2; }
|
|
.bg-yellow-100 { background-color: #fef9c3; }
|
|
.bg-green-100 { background-color: #dcfce7; }
|
|
.text-red-800 { color: #991b1b; }
|
|
.text-yellow-800 { color: #854d0e; }
|
|
.text-green-800 { color: #166534; }
|
|
|
|
.border-gray-200 { border-color: #e5e7eb; }
|
|
.border-gray-300 { border-color: #d1d5db; }
|
|
.border-gray-700 { border-color: #374151; }
|
|
.border-transparent { border-color: transparent; }
|
|
|
|
.rounded-lg { border-radius: 0.5rem; }
|
|
.rounded-md { border-radius: 0.375rem; }
|
|
.rounded-full { border-radius: 9999px; }
|
|
.rounded { border-radius: 0.25rem; }
|
|
|
|
.shadow { box-shadow: var(--shadow); }
|
|
.shadow-sm { box-shadow: var(--shadow-sm); }
|
|
.shadow-md { box-shadow: var(--shadow-md); }
|
|
.shadow-lg { box-shadow: var(--shadow-lg); }
|
|
|
|
.p-6 { padding: 1.5rem; }
|
|
.p-4 { padding: 1rem; }
|
|
.p-2 { padding: 0.5rem; }
|
|
.px-4 { padding-left: 1rem; padding-right: 1rem; }
|
|
.py-1\.5 { padding-top: 0.375rem; padding-bottom: 0.375rem; }
|
|
.py-2 { padding-top: 0.5rem; padding-bottom: 0.5rem; }
|
|
.py-3 { padding-top: 0.75rem; padding-bottom: 0.75rem; }
|
|
.pb-4 { padding-bottom: 1rem; }
|
|
.mb-6 { margin-bottom: 1.5rem; }
|
|
.mb-4 { margin-bottom: 1rem; }
|
|
.mb-8 { margin-bottom: 2rem; }
|
|
.mb-2 { margin-bottom: 0.5rem; }
|
|
.mt-1 { margin-top: 0.25rem; }
|
|
.mt-4 { margin-top: 1rem; }
|
|
.mr-2 { margin-right: 0.5rem; }
|
|
.ml-3 { margin-left: 0.75rem; }
|
|
|
|
.w-full { width: 100%; }
|
|
.w-0 { width: 0; }
|
|
.w-2 { width: 0.5rem; }
|
|
.w-4 { width: 1rem; }
|
|
.h-2 { height: 0.5rem; }
|
|
.h-4 { height: 1rem; }
|
|
.h-10 { height: 2.5rem; }
|
|
.h-16 { height: 4rem; }
|
|
.h-24 { height: 6rem; }
|
|
.h-32 { height: 8rem; }
|
|
.h-96 { height: 24rem; }
|
|
|
|
.flex { display: flex; }
|
|
.inline-flex { display: inline-flex; }
|
|
.flex-wrap { flex-wrap: wrap; }
|
|
.flex-shrink-0 { flex-shrink: 0; }
|
|
.flex-1 { flex: 1; }
|
|
.items-center { align-items: center; }
|
|
.justify-center { justify-content: center; }
|
|
.justify-between { justify-content: space-between; }
|
|
.space-x-1 > * + * { margin-left: 0.25rem; }
|
|
.space-x-2 > * + * { margin-left: 0.5rem; }
|
|
.space-x-4 > * + * { margin-left: 1rem; }
|
|
.space-y-1 > * + * { margin-top: 0.25rem; }
|
|
.space-y-1\.5 > * + * { margin-top: 0.375rem; }
|
|
.space-y-2 > * + * { margin-top: 0.5rem; }
|
|
.space-y-4 > * + * { margin-top: 1rem; }
|
|
.space-y-6 > * + * { margin-top: 1.5rem; }
|
|
.space-y-8 > * + * { margin-top: 2rem; }
|
|
|
|
.grid { display: grid; }
|
|
.grid-cols-1 { grid-template-columns: repeat(1, minmax(0, 1fr)); }
|
|
.grid-cols-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
|
|
.grid-cols-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
|
|
.grid-cols-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
|
|
.gap-1\.5 { gap: 0.375rem; }
|
|
.gap-2 { gap: 0.5rem; }
|
|
.gap-3 { gap: 0.75rem; }
|
|
.gap-4 { gap: 1rem; }
|
|
.gap-6 { gap: 1.5rem; }
|
|
.gap-x-2 { column-gap: 0.5rem; }
|
|
.gap-x-3 { column-gap: 0.75rem; }
|
|
.gap-x-4 { column-gap: 1rem; }
|
|
.gap-x-6 { column-gap: 1.5rem; }
|
|
.gap-x-8 { column-gap: 2rem; }
|
|
.gap-y-2 { row-gap: 0.5rem; }
|
|
|
|
/* Enhanced Typography */
|
|
.text-xs { font-size: 0.75rem; line-height: 1.4; }
|
|
.text-sm { font-size: 0.875rem; line-height: 1.5; }
|
|
.text-base { font-size: 1rem; line-height: 1.5; }
|
|
.text-lg { font-size: 1.125rem; line-height: 1.75; }
|
|
.text-xl { font-size: 1.25rem; line-height: 1.75; }
|
|
.text-2xl { font-size: 1.5rem; line-height: 2; }
|
|
.text-4xl { font-size: 2.25rem; line-height: 2.5; }
|
|
.font-medium { font-weight: 500; }
|
|
.font-semibold { font-weight: 600; }
|
|
.font-bold { font-weight: 700; }
|
|
|
|
/* Headings with improved hierarchy */
|
|
h1, h2, h3, h4, h5, h6 {
|
|
font-weight: 600;
|
|
line-height: 1.4;
|
|
color: var(--color-text-primary);
|
|
/* Improved line-height from 1.3 to 1.4 for better readability */
|
|
}
|
|
|
|
h1 { font-size: 1.875rem; }
|
|
h2 { font-size: 1.5rem; }
|
|
h3 { font-size: 1.25rem; }
|
|
h4 { font-size: 1.125rem; }
|
|
|
|
.border-b { border-bottom-width: 1px; }
|
|
.border-b-2 { border-bottom-width: 2px; }
|
|
|
|
.relative { position: relative; }
|
|
.fixed { position: fixed; }
|
|
.absolute { position: absolute; }
|
|
.z-50 { z-index: 50; }
|
|
|
|
.top-4 { top: 1rem; }
|
|
.right-4 { right: 1rem; }
|
|
|
|
.max-w-7xl { max-width: 56rem; }
|
|
.max-w-full { max-width: 100%; }
|
|
.mx-auto { margin-left: auto; margin-right: auto; }
|
|
.overflow-x-auto { overflow-x: auto; }
|
|
.overflow-hidden { overflow: hidden; }
|
|
|
|
.aspect-video { aspect-ratio: 16 / 9; }
|
|
|
|
.truncate { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
|
|
.transition { transition-property: transform, opacity, color, border-color; transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); transition-duration: 150ms; }
|
|
/* Optimized: Replaced 'all' with specific properties to avoid animating expensive properties */
|
|
|
|
/* Removed .duration-300 - not used anywhere */
|
|
|
|
.hover\:bg-green-700:hover { background-color: #047857; }
|
|
.hover\:bg-red-700:hover { background-color: #b91c1c; }
|
|
.hover\:bg-gray-50:hover { background-color: #f9fafb; }
|
|
.hover\:bg-gray-800:hover { background-color: #1f2937; }
|
|
.hover\:bg-yellow-700:hover { background-color: #b45309; }
|
|
.hover\:text-gray-700:hover { color: #374151; }
|
|
.hover\:border-gray-300:hover { border-color: #d1d5db; }
|
|
|
|
.focus\:outline-none:focus { outline: 2px solid transparent; outline-offset: 2px; }
|
|
.focus\:ring-2:focus {
|
|
--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);
|
|
box-shadow: var(--tw-ring-offset-shadow), var(--tw-shadow, 0 0 #0000);
|
|
}
|
|
/* Optimized: Split complex selector onto multiple lines for readability */
|
|
.focus\:ring-blue-500:focus { --tw-ring-color: #3b82f6; }
|
|
|
|
.animate-pulse {
|
|
animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
|
|
}
|
|
|
|
@keyframes pulse {
|
|
0%, 100% { opacity: 1; }
|
|
50% { opacity: .5; }
|
|
}
|
|
|
|
/* Smooth transitions for all interactive elements */
|
|
/* Optimized: Only transition properties that don't trigger expensive repaints */
|
|
a, button, input, select, textarea {
|
|
transition: color 0.15s ease, border-color 0.15s ease, opacity 0.15s ease;
|
|
/* Removed background-color transition - can trigger repaints, use opacity or border-color instead */
|
|
}
|
|
|
|
/* Custom scrollbar for webkit browsers */
|
|
::-webkit-scrollbar {
|
|
width: 8px;
|
|
height: 8px;
|
|
}
|
|
|
|
::-webkit-scrollbar-track {
|
|
background: #f1f5f9;
|
|
}
|
|
|
|
::-webkit-scrollbar-thumb {
|
|
background: #cbd5e1;
|
|
border-radius: 4px;
|
|
}
|
|
|
|
::-webkit-scrollbar-thumb:hover {
|
|
background: #94a3b8;
|
|
}
|
|
|
|
/* Logs container specific scrollbar */
|
|
#logs-container::-webkit-scrollbar {
|
|
width: 10px;
|
|
}
|
|
|
|
#logs-container::-webkit-scrollbar-track {
|
|
background: #374151;
|
|
}
|
|
|
|
#logs-container::-webkit-scrollbar-thumb {
|
|
background: #6b7280;
|
|
border-radius: 5px;
|
|
}
|
|
|
|
#logs-container::-webkit-scrollbar-thumb:hover {
|
|
background: #9ca3af;
|
|
}
|
|
|
|
/* Smooth scrolling for logs container */
|
|
#logs-container {
|
|
scroll-behavior: smooth;
|
|
position: relative;
|
|
overflow-y: auto !important;
|
|
}
|
|
|
|
/* Ensure logs content doesn't cause overflow issues */
|
|
.log-entry {
|
|
word-wrap: break-word;
|
|
overflow-wrap: break-word;
|
|
max-width: 100%;
|
|
box-sizing: border-box;
|
|
}
|
|
|
|
/* Ensure proper containment of logs */
|
|
#logs-loading {
|
|
position: absolute;
|
|
top: 0;
|
|
left: 0;
|
|
right: 0;
|
|
bottom: 0;
|
|
z-index: 1;
|
|
}
|
|
|
|
#logs-empty {
|
|
position: absolute;
|
|
top: 0;
|
|
left: 0;
|
|
right: 0;
|
|
bottom: 0;
|
|
z-index: 2;
|
|
}
|
|
|
|
#logs-display {
|
|
position: absolute;
|
|
top: 0;
|
|
left: 0;
|
|
right: 0;
|
|
bottom: 0;
|
|
z-index: 3;
|
|
}
|
|
|
|
.logs-content {
|
|
height: 100%;
|
|
overflow-y: auto;
|
|
padding: 0;
|
|
}
|
|
|
|
/* Logs container responsive height - simplified for better scrolling */
|
|
@media (max-width: 768px) {
|
|
#logs-container {
|
|
height: 400px !important;
|
|
min-height: 300px !important;
|
|
}
|
|
}
|
|
|
|
@media (max-width: 640px) {
|
|
#logs-container {
|
|
height: 350px !important;
|
|
min-height: 250px !important;
|
|
}
|
|
}
|
|
|
|
/* Responsive breakpoints */
|
|
@media (min-width: 640px) {
|
|
.sm\:px-6 { padding-left: 1.5rem; padding-right: 1.5rem; }
|
|
.sm\:block { display: block; }
|
|
.sm\:grid-cols-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
|
|
.sm\:text-sm { font-size: 0.875rem; line-height: 1.25rem; }
|
|
}
|
|
|
|
@media (min-width: 768px) {
|
|
.md\:grid-cols-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
|
|
.md\:grid-cols-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
|
|
.md\:grid-cols-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
|
|
.md\:flex { display: flex; }
|
|
.md\:hidden { display: none; }
|
|
.md\:block { display: block; }
|
|
.md\:w-auto { width: auto; }
|
|
}
|
|
|
|
@media (min-width: 1024px) {
|
|
.lg\:grid-cols-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
|
|
.lg\:grid-cols-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
|
|
.lg\:grid-cols-5 { grid-template-columns: repeat(5, minmax(0, 1fr)); }
|
|
.lg\:grid-cols-6 { grid-template-columns: repeat(6, minmax(0, 1fr)); }
|
|
.lg\:px-8 { padding-left: 2rem; padding-right: 2rem; }
|
|
.lg\:gap-x-3 { column-gap: 0.75rem; }
|
|
.lg\:gap-x-6 { column-gap: 1.5rem; }
|
|
.lg\:block { display: block; }
|
|
.lg\:flex { display: flex; }
|
|
.lg\:w-64 { width: 16rem; }
|
|
}
|
|
|
|
@media (min-width: 1280px) {
|
|
.xl\:grid-cols-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
|
|
.xl\:grid-cols-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
|
|
.xl\:grid-cols-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
|
|
.xl\:grid-cols-5 { grid-template-columns: repeat(5, minmax(0, 1fr)); }
|
|
.xl\:grid-cols-6 { grid-template-columns: repeat(6, minmax(0, 1fr)); }
|
|
.xl\:grid-cols-7 { grid-template-columns: repeat(7, minmax(0, 1fr)); }
|
|
.xl\:grid-cols-8 { grid-template-columns: repeat(8, minmax(0, 1fr)); }
|
|
.xl\:px-12 { padding-left: 3rem; padding-right: 3rem; }
|
|
.xl\:space-x-6 > * + * { margin-left: 1.5rem; }
|
|
.xl\:gap-x-4 { column-gap: 1rem; }
|
|
.xl\:gap-x-8 { column-gap: 2rem; }
|
|
}
|
|
|
|
@media (min-width: 1536px) {
|
|
.2xl\:grid-cols-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
|
|
.2xl\:grid-cols-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
|
|
.2xl\:grid-cols-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
|
|
.2xl\:grid-cols-5 { grid-template-columns: repeat(5, minmax(0, 1fr)); }
|
|
.2xl\:grid-cols-6 { grid-template-columns: repeat(6, minmax(0, 1fr)); }
|
|
.2xl\:grid-cols-7 { grid-template-columns: repeat(7, minmax(0, 1fr)); }
|
|
.2xl\:grid-cols-8 { grid-template-columns: repeat(8, minmax(0, 1fr)); }
|
|
.2xl\:grid-cols-9 { grid-template-columns: repeat(9, minmax(0, 1fr)); }
|
|
.2xl\:grid-cols-10 { grid-template-columns: repeat(10, minmax(0, 1fr)); }
|
|
.2xl\:px-16 { padding-left: 4rem; padding-right: 4rem; }
|
|
.2xl\:space-x-8 > * + * { margin-left: 2rem; }
|
|
}
|
|
|
|
/* ===== Mobile navigation drawer =====
|
|
Below md the #site-nav wrapper becomes an off-canvas drawer; at md and up
|
|
none of these rules apply and the nav renders exactly as before. */
|
|
@media (max-width: 767.98px) {
|
|
.site-nav {
|
|
position: fixed;
|
|
top: 0;
|
|
left: 0;
|
|
bottom: 0;
|
|
z-index: 60;
|
|
width: min(85vw, 320px);
|
|
background-color: var(--color-surface);
|
|
border-right: 1px solid var(--color-border);
|
|
transform: translateX(-100%);
|
|
transition: transform 0.25s ease;
|
|
overflow-y: auto;
|
|
padding: 1rem;
|
|
-webkit-overflow-scrolling: touch;
|
|
}
|
|
.site-nav.open {
|
|
transform: translateX(0);
|
|
box-shadow: 0 0 24px rgba(0, 0, 0, 0.25);
|
|
}
|
|
/* Tabs become full-width rows with >=44px touch targets */
|
|
.site-nav .nav-tab {
|
|
display: flex;
|
|
width: 100%;
|
|
align-items: center;
|
|
gap: 0.5rem;
|
|
text-align: left;
|
|
padding: 0.75rem 1rem;
|
|
min-height: 44px;
|
|
}
|
|
.site-nav nav.-mb-px {
|
|
display: block;
|
|
}
|
|
.nav-backdrop {
|
|
position: fixed;
|
|
inset: 0;
|
|
z-index: 55;
|
|
background-color: rgba(0, 0, 0, 0.4);
|
|
}
|
|
/* Header widgets relocated into the drawer (see placeHeaderWidgets in
|
|
app.js). The originals carry `hidden`/breakpoint classes tuned for the
|
|
header, so re-enable them explicitly in the drawer context. */
|
|
#drawer-widgets #settings-search-wrap {
|
|
display: block !important;
|
|
margin-bottom: 1rem;
|
|
}
|
|
#drawer-widgets #settings-search-wrap input {
|
|
width: 100%;
|
|
}
|
|
#drawer-widgets #settings-search-results {
|
|
position: static;
|
|
width: 100%;
|
|
max-height: 50vh;
|
|
margin-top: 0.25rem;
|
|
}
|
|
#drawer-widgets #system-stats {
|
|
display: flex !important;
|
|
justify-content: space-between;
|
|
margin-bottom: 1rem;
|
|
}
|
|
/* Larger touch targets inside horizontally scrolling tables */
|
|
.overflow-x-auto table button {
|
|
min-width: 44px;
|
|
min-height: 44px;
|
|
}
|
|
.overflow-x-auto table input:not([type="checkbox"]),
|
|
.overflow-x-auto table select {
|
|
min-height: 40px;
|
|
}
|
|
.overflow-x-auto table input[type="checkbox"] {
|
|
width: 1.25rem;
|
|
height: 1.25rem;
|
|
}
|
|
}
|
|
|
|
@media (min-width: 768px) {
|
|
/* Hard guards: even if mobileNavOpen was left true when the viewport
|
|
crossed the breakpoint, the drawer/backdrop must render as plain
|
|
in-flow nav on desktop. */
|
|
.site-nav {
|
|
position: static;
|
|
transform: none;
|
|
width: auto;
|
|
padding: 0;
|
|
border-right: none;
|
|
box-shadow: none;
|
|
background-color: transparent;
|
|
overflow-y: visible;
|
|
}
|
|
.nav-backdrop {
|
|
display: none !important;
|
|
}
|
|
#drawer-widgets {
|
|
display: none;
|
|
}
|
|
}
|
|
|
|
/* Mobile modal sizing: every .modal-content dialog fits the viewport with
|
|
internal scrolling instead of overflowing it. */
|
|
@media (max-width: 640px) {
|
|
.modal-content {
|
|
width: 95vw !important;
|
|
max-width: 95vw !important;
|
|
max-height: 90vh;
|
|
overflow-y: auto;
|
|
}
|
|
}
|
|
|
|
/* Edge-fade hint that a container scrolls horizontally (pure CSS,
|
|
Lea Verou scrolling-shadows technique — backgrounds sit behind content). */
|
|
.overflow-x-auto {
|
|
background:
|
|
linear-gradient(90deg, var(--color-surface) 30%, rgba(255, 255, 255, 0)) left / 24px 100%,
|
|
linear-gradient(270deg, var(--color-surface) 30%, rgba(255, 255, 255, 0)) right / 24px 100%,
|
|
radial-gradient(farthest-side at 0 50%, rgba(0, 0, 0, 0.18), rgba(0, 0, 0, 0)) left / 12px 100%,
|
|
radial-gradient(farthest-side at 100% 50%, rgba(0, 0, 0, 0.18), rgba(0, 0, 0, 0)) right / 12px 100%;
|
|
background-repeat: no-repeat;
|
|
background-attachment: local, local, scroll, scroll;
|
|
}
|
|
|
|
/* HTMX loading states */
|
|
.htmx-request .loading {
|
|
display: inline-block;
|
|
}
|
|
|
|
.htmx-request .btn-text {
|
|
opacity: 0.5;
|
|
}
|
|
|
|
/* Enhanced Button styles */
|
|
.btn {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
padding: 0.625rem 1.25rem;
|
|
border-radius: 0.5rem;
|
|
font-size: 0.875rem;
|
|
font-weight: 600;
|
|
line-height: 1.5;
|
|
text-decoration: none;
|
|
transition: transform 0.15s ease, opacity 0.15s ease;
|
|
cursor: pointer;
|
|
border: none;
|
|
/* Removed ::before pseudo-element animation for better performance */
|
|
}
|
|
|
|
.btn:hover {
|
|
transform: translateY(-1px);
|
|
opacity: 0.9;
|
|
}
|
|
|
|
.btn:active {
|
|
transform: translateY(0);
|
|
}
|
|
|
|
.btn:disabled {
|
|
opacity: 0.6;
|
|
cursor: not-allowed;
|
|
transform: none !important;
|
|
}
|
|
|
|
.btn:disabled:hover {
|
|
transform: none;
|
|
}
|
|
|
|
.btn:focus {
|
|
outline: 2px solid transparent;
|
|
outline-offset: 2px;
|
|
box-shadow: 0 0 0 3px rgb(37 99 235 / 30%);
|
|
}
|
|
|
|
/* Global button text contrast fix: Ensure buttons with white backgrounds have dark text */
|
|
button.bg-white {
|
|
color: #111827 !important; /* text-gray-900 equivalent - ensures good contrast on white background */
|
|
}
|
|
|
|
/* Form styles */
|
|
.form-group {
|
|
margin-bottom: 1rem;
|
|
}
|
|
|
|
.form-group label {
|
|
display: block;
|
|
font-size: 0.875rem;
|
|
font-weight: 500;
|
|
color: var(--color-text-secondary);
|
|
margin-bottom: 0.25rem;
|
|
}
|
|
|
|
.form-control {
|
|
display: block;
|
|
width: 100%;
|
|
padding: 0.5rem 0.75rem;
|
|
border: 1px solid #d1d5db;
|
|
border-radius: 0.375rem;
|
|
background-color: #ffffff;
|
|
color: #111827; /* text-gray-900 - ensure dark text on white background */
|
|
font-size: 0.875rem;
|
|
line-height: 1.25rem;
|
|
transition: border-color 0.15s ease-in-out;
|
|
/* Removed box-shadow transition - using border-color only for better performance */
|
|
}
|
|
|
|
.form-control:focus {
|
|
border-color: var(--color-primary);
|
|
/* Using outline instead of box-shadow for focus state (better performance) */
|
|
outline: 2px solid rgb(37 99 235 / 20%);
|
|
outline-offset: 2px;
|
|
}
|
|
|
|
.form-control:disabled {
|
|
background-color: #f9fafb;
|
|
opacity: 0.6;
|
|
cursor: not-allowed;
|
|
}
|
|
|
|
/* Enhanced Card styles */
|
|
.card {
|
|
background-color: var(--color-surface);
|
|
border-radius: 0.5rem;
|
|
box-shadow: var(--shadow);
|
|
overflow: hidden;
|
|
transition: transform 0.15s ease;
|
|
contain: layout style paint;
|
|
/* Removed box-shadow transition for better performance - using transform only (GPU accelerated) */
|
|
/* Added CSS containment for better performance isolation */
|
|
}
|
|
|
|
.card:hover {
|
|
transform: translateY(-2px);
|
|
}
|
|
|
|
/* Plugin Card Styles */
|
|
.plugin-card {
|
|
background-color: var(--color-surface);
|
|
border: 1px solid var(--color-border);
|
|
border-radius: 0.75rem;
|
|
padding: 1.25rem;
|
|
transition: transform 0.15s ease, border-color 0.15s ease;
|
|
cursor: pointer;
|
|
position: relative;
|
|
contain: layout style paint;
|
|
/* Simplified transitions - using only transform and border-color (cheaper than box-shadow) */
|
|
/* Added CSS containment for better performance isolation */
|
|
}
|
|
|
|
.plugin-card::before {
|
|
content: '';
|
|
position: absolute;
|
|
top: 0;
|
|
left: 0;
|
|
right: 0;
|
|
height: 3px;
|
|
background: linear-gradient(90deg, var(--color-primary), var(--color-secondary));
|
|
opacity: 0;
|
|
transition: opacity 0.15s ease;
|
|
}
|
|
|
|
.plugin-card:hover {
|
|
transform: translateY(-2px);
|
|
border-color: var(--color-primary);
|
|
/* Removed box-shadow transition for better performance */
|
|
}
|
|
|
|
.plugin-card:hover::before {
|
|
opacity: 1;
|
|
}
|
|
|
|
.plugin-card:focus {
|
|
outline: 2px solid var(--color-primary);
|
|
outline-offset: 2px;
|
|
}
|
|
|
|
.plugin-card:active {
|
|
transform: translateY(0);
|
|
}
|
|
|
|
/* Status indicators */
|
|
.status-indicator {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
padding: 0.25rem 0.75rem;
|
|
border-radius: 9999px;
|
|
font-size: 0.75rem;
|
|
font-weight: 500;
|
|
}
|
|
|
|
.status-indicator.success {
|
|
background-color: #dcfce7;
|
|
color: #166534;
|
|
}
|
|
|
|
.status-indicator.error {
|
|
background-color: #fef2f2;
|
|
color: #991b1b;
|
|
}
|
|
|
|
.status-indicator.warning {
|
|
background-color: #fffbeb;
|
|
color: #92400e;
|
|
}
|
|
|
|
.status-indicator.info {
|
|
background-color: var(--color-info-bg);
|
|
color: var(--color-info);
|
|
}
|
|
|
|
/* Badge Styles */
|
|
.badge {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
padding: 0.25rem 0.625rem;
|
|
border-radius: 0.375rem;
|
|
font-size: 0.75rem;
|
|
font-weight: 600;
|
|
line-height: 1.4;
|
|
}
|
|
|
|
.badge-success {
|
|
background-color: var(--color-success-bg);
|
|
color: var(--color-success);
|
|
}
|
|
|
|
.badge-error {
|
|
background-color: var(--color-error-bg);
|
|
color: var(--color-error);
|
|
}
|
|
|
|
.badge-warning {
|
|
background-color: var(--color-warning-bg);
|
|
color: var(--color-warning);
|
|
}
|
|
|
|
.badge-info {
|
|
background-color: var(--color-info-bg);
|
|
color: var(--color-info);
|
|
}
|
|
|
|
.badge-accent {
|
|
background-color: var(--color-purple-bg);
|
|
color: var(--color-purple-text);
|
|
}
|
|
|
|
/* Filter Pill Toggle States */
|
|
.filter-pill,
|
|
.category-filter-pill {
|
|
cursor: pointer;
|
|
user-select: none;
|
|
transition: background-color 0.15s ease, border-color 0.15s ease, color 0.15s ease, box-shadow 0.15s ease, opacity 0.15s ease;
|
|
}
|
|
|
|
.filter-pill[data-active="true"],
|
|
.category-filter-pill[data-active="true"] {
|
|
background-color: var(--color-info-bg);
|
|
border-color: var(--color-info);
|
|
color: var(--color-info);
|
|
font-weight: 600;
|
|
}
|
|
|
|
.filter-pill[data-active="true"]:hover,
|
|
.category-filter-pill[data-active="true"]:hover {
|
|
opacity: 0.85;
|
|
}
|
|
|
|
.category-filter-pill[data-active="true"] {
|
|
box-shadow: 0 0 0 1px var(--color-info);
|
|
}
|
|
|
|
/* Section Headers with Subtle Gradients */
|
|
.section-header {
|
|
background: linear-gradient(135deg, rgb(255 255 255 / 90%) 0%, rgb(249 250 251 / 90%) 100%);
|
|
border-bottom: 1px solid var(--color-border);
|
|
padding: 1rem 0;
|
|
margin-bottom: 1.5rem;
|
|
}
|
|
|
|
/* Enhanced Empty States */
|
|
.empty-state {
|
|
text-align: center;
|
|
padding: 3rem 1rem;
|
|
color: var(--color-text-tertiary);
|
|
}
|
|
|
|
.empty-state-icon {
|
|
font-size: 3rem;
|
|
color: var(--color-text-tertiary);
|
|
opacity: 0.5;
|
|
margin-bottom: 1rem;
|
|
}
|
|
|
|
/* Enhanced Loading Skeleton */
|
|
.skeleton {
|
|
background-color: #f0f0f0;
|
|
border-radius: 0.375rem;
|
|
animation: skeletonPulse 1.5s ease-in-out infinite;
|
|
/* Simplified from gradient animation to opacity pulse for better performance */
|
|
}
|
|
|
|
@keyframes skeletonPulse {
|
|
0%, 100% { opacity: 1; }
|
|
50% { opacity: 0.6; }
|
|
}
|
|
|
|
/* Enhanced Modal Styling */
|
|
.modal-backdrop {
|
|
background-color: rgb(0 0 0 / 50%);
|
|
/* Removed backdrop-filter: blur() for better performance on Raspberry Pi */
|
|
transition: opacity 0.2s ease;
|
|
}
|
|
|
|
.modal-content {
|
|
background: var(--color-surface);
|
|
border-radius: 0.75rem;
|
|
box-shadow: var(--shadow-lg);
|
|
animation: modalSlideIn 0.2s ease;
|
|
contain: layout style paint;
|
|
/* Added CSS containment for better performance isolation */
|
|
}
|
|
|
|
@keyframes modalSlideIn {
|
|
from {
|
|
opacity: 0;
|
|
transform: translateY(-10px);
|
|
}
|
|
to {
|
|
opacity: 1;
|
|
transform: translateY(0);
|
|
}
|
|
}
|
|
|
|
/* ============================================================================ */
|
|
/* Settings tooltips (help_tip macro + tooltips.js) */
|
|
/* ============================================================================ */
|
|
|
|
/* The (i) info trigger placed next to a setting label. */
|
|
.help-tip {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
width: 1.15rem;
|
|
height: 1.15rem;
|
|
margin-left: 0.375rem;
|
|
padding: 0;
|
|
border: none;
|
|
background: transparent;
|
|
color: var(--color-text-tertiary);
|
|
font-size: 0.8125rem;
|
|
line-height: 1;
|
|
cursor: help;
|
|
vertical-align: middle;
|
|
border-radius: 9999px;
|
|
transition: color 0.12s ease;
|
|
}
|
|
|
|
.help-tip:hover,
|
|
.help-tip:focus-visible {
|
|
color: var(--color-primary);
|
|
}
|
|
|
|
.help-tip:focus-visible {
|
|
outline: 2px solid var(--color-primary);
|
|
outline-offset: 2px;
|
|
}
|
|
|
|
/* Singleton tooltip panel appended to <body> by tooltips.js. */
|
|
#ledm-tooltip {
|
|
position: fixed;
|
|
z-index: 1000;
|
|
max-width: 20rem;
|
|
padding: 0.5rem 0.75rem;
|
|
background: var(--color-surface);
|
|
color: var(--color-text-secondary);
|
|
border: 1px solid var(--color-border);
|
|
border-radius: 0.5rem;
|
|
box-shadow: var(--shadow-lg);
|
|
font-size: 0.8125rem;
|
|
line-height: 1.45;
|
|
white-space: pre-line; /* renders authored "\n" line breaks */
|
|
pointer-events: none; /* never steals hover/click from the page */
|
|
animation: tooltipFade 0.12s ease;
|
|
}
|
|
|
|
#ledm-tooltip[hidden] {
|
|
display: none;
|
|
}
|
|
|
|
@keyframes tooltipFade {
|
|
from { opacity: 0; }
|
|
to { opacity: 1; }
|
|
}
|
|
|
|
/* ============================================================================ */
|
|
/* Settings search — global header dropdown + per-tab filter */
|
|
/* ============================================================================ */
|
|
|
|
#settings-search-results {
|
|
background: var(--color-surface);
|
|
border: 1px solid var(--color-border);
|
|
border-radius: 0.5rem;
|
|
box-shadow: var(--shadow-lg);
|
|
z-index: 50;
|
|
padding: 0.25rem;
|
|
max-height: min(60vh, 24rem);
|
|
overflow-y: auto;
|
|
}
|
|
|
|
.ssr-group {
|
|
padding: 0.375rem 0.625rem 0.25rem;
|
|
font-size: 0.6875rem;
|
|
font-weight: 700;
|
|
text-transform: uppercase;
|
|
letter-spacing: 0.04em;
|
|
color: var(--color-text-tertiary);
|
|
position: sticky;
|
|
top: 0;
|
|
background: var(--color-surface);
|
|
}
|
|
|
|
.ssr-option {
|
|
display: flex;
|
|
flex-direction: column;
|
|
width: 100%;
|
|
text-align: left;
|
|
padding: 0.4rem 0.625rem;
|
|
border: none;
|
|
background: transparent;
|
|
border-radius: 0.375rem;
|
|
cursor: pointer;
|
|
color: var(--color-text-primary);
|
|
}
|
|
|
|
.ssr-option:hover,
|
|
.ssr-option.active {
|
|
background: var(--color-info-bg);
|
|
}
|
|
|
|
.ssr-label {
|
|
font-size: 0.875rem;
|
|
font-weight: 500;
|
|
}
|
|
|
|
.ssr-help {
|
|
font-size: 0.75rem;
|
|
color: var(--color-text-tertiary);
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
white-space: nowrap;
|
|
max-width: 100%;
|
|
}
|
|
|
|
.ssr-empty {
|
|
padding: 0.75rem 0.625rem;
|
|
font-size: 0.8125rem;
|
|
color: var(--color-text-tertiary);
|
|
}
|
|
|
|
/* Flash highlight applied to a field after search navigation. */
|
|
@keyframes settingFlash {
|
|
0% { box-shadow: 0 0 0 0 rgba(37, 99, 235, 0); }
|
|
25% { box-shadow: 0 0 0 3px var(--color-primary); }
|
|
100% { box-shadow: 0 0 0 0 rgba(37, 99, 235, 0); }
|
|
}
|
|
|
|
.setting-flash {
|
|
animation: settingFlash 1.4s ease;
|
|
border-radius: 0.5rem;
|
|
}
|
|
|
|
@media (prefers-reduced-motion: reduce) {
|
|
#ledm-tooltip { animation: none; }
|
|
.setting-flash {
|
|
animation: none;
|
|
outline: 2px solid var(--color-primary);
|
|
outline-offset: 2px;
|
|
}
|
|
}
|
|
|
|
/* Removed .divider and .divider-light - not used anywhere */
|
|
|
|
/* Enhanced Spacing Utilities - Only unique classes not in main utility section */
|
|
.mt-2 { margin-top: 0.5rem; }
|
|
.mt-3 { margin-top: 0.75rem; }
|
|
.mt-6 { margin-top: 1.5rem; }
|
|
.mb-3 { margin-bottom: 0.75rem; }
|
|
.p-3 { padding: 0.75rem; }
|
|
.p-5 { padding: 1.25rem; }
|
|
.px-3 { padding-left: 0.75rem; padding-right: 0.75rem; }
|
|
.px-5 { padding-left: 1.25rem; padding-right: 1.25rem; }
|
|
.py-2\.5 { padding-top: 0.625rem; padding-bottom: 0.625rem; }
|
|
.py-4 { padding-top: 1rem; padding-bottom: 1rem; }
|
|
/* Removed duplicates: mt-4, mb-2, mb-4, mb-6, mb-8, p-4, p-6, px-4, py-2, py-3 (already defined above) */
|
|
|
|
/* Additional Utility Classes */
|
|
.min-w-0 { min-width: 0; }
|
|
.leading-relaxed { line-height: 1.625; }
|
|
|
|
/* Enhanced Navigation Tab Styles */
|
|
.nav-tab {
|
|
position: relative;
|
|
display: inline-flex;
|
|
align-items: center;
|
|
padding: 0.5rem 0.25rem;
|
|
border-bottom-width: 2px;
|
|
border-bottom-style: solid;
|
|
border-bottom-color: transparent;
|
|
font-size: 0.875rem;
|
|
font-weight: 500;
|
|
line-height: 1.5;
|
|
color: #374151; /* text-gray-700 for better readability */
|
|
white-space: nowrap;
|
|
transition: color 0.15s ease, background-color 0.15s ease, border-color 0.15s ease, opacity 0.15s ease;
|
|
cursor: pointer;
|
|
background-color: transparent;
|
|
border-top: none;
|
|
border-left: none;
|
|
border-right: none;
|
|
}
|
|
|
|
.nav-tab i {
|
|
transition: color 0.15s ease;
|
|
margin-right: 0.5rem;
|
|
}
|
|
|
|
/* Inactive state - improved contrast */
|
|
.nav-tab:not(.nav-tab-active) {
|
|
color: #374151; /* text-gray-700 */
|
|
}
|
|
|
|
.nav-tab:not(.nav-tab-active) i {
|
|
color: #374151; /* text-gray-700 */
|
|
}
|
|
|
|
/* Hover state - enhanced visibility */
|
|
.nav-tab:not(.nav-tab-active):hover {
|
|
color: #111827; /* text-gray-900 */
|
|
background-color: #f3f4f6; /* bg-gray-100 */
|
|
border-bottom-color: #d1d5db; /* border-gray-300 */
|
|
}
|
|
|
|
.nav-tab:not(.nav-tab-active):hover i {
|
|
color: #111827; /* text-gray-900 */
|
|
}
|
|
|
|
/* Active state - prominent with gradient background */
|
|
.nav-tab-active {
|
|
color: #1d4ed8; /* text-blue-700 */
|
|
font-weight: 600;
|
|
border-bottom-width: 3px;
|
|
border-bottom-color: #2563eb; /* border-blue-600 */
|
|
background: linear-gradient(135deg, rgb(37 99 235 / 10%) 0%, rgb(59 130 246 / 5%) 100%);
|
|
box-shadow: 0 2px 4px rgb(37 99 235 / 10%);
|
|
}
|
|
|
|
.nav-tab-active i {
|
|
color: #1d4ed8; /* text-blue-700 */
|
|
}
|
|
|
|
/* Responsive padding adjustments */
|
|
@media (min-width: 1024px) {
|
|
.nav-tab {
|
|
padding-left: 0.5rem;
|
|
padding-right: 0.5rem;
|
|
}
|
|
}
|
|
|
|
@media (min-width: 1280px) {
|
|
.nav-tab {
|
|
padding-left: 0.75rem;
|
|
padding-right: 0.75rem;
|
|
}
|
|
}
|
|
|
|
/* ==========================================================
|
|
Dark Mode - Component Overrides
|
|
========================================================== */
|
|
|
|
/* Header */
|
|
[data-theme="dark"] header {
|
|
background-color: var(--color-surface);
|
|
border-color: var(--color-border);
|
|
}
|
|
|
|
/* Form controls */
|
|
[data-theme="dark"] .form-control {
|
|
background-color: var(--color-border);
|
|
color: var(--color-text-primary);
|
|
border-color: #4b5563;
|
|
}
|
|
|
|
[data-theme="dark"] .form-control:focus {
|
|
border-color: var(--color-primary);
|
|
outline-color: rgb(59 130 246 / 30%);
|
|
}
|
|
|
|
[data-theme="dark"] .form-control:disabled {
|
|
background-color: var(--color-surface);
|
|
}
|
|
|
|
/* Buttons with bg-white */
|
|
[data-theme="dark"] button.bg-white {
|
|
background-color: var(--color-border) !important;
|
|
color: var(--color-text-primary) !important;
|
|
}
|
|
|
|
/* Nav tabs */
|
|
[data-theme="dark"] .nav-tab:not(.nav-tab-active) {
|
|
color: var(--color-text-secondary);
|
|
}
|
|
|
|
[data-theme="dark"] .nav-tab:not(.nav-tab-active) i {
|
|
color: var(--color-text-secondary);
|
|
}
|
|
|
|
[data-theme="dark"] .nav-tab:not(.nav-tab-active):hover {
|
|
color: var(--color-text-primary);
|
|
background-color: var(--color-border);
|
|
border-bottom-color: #6b7280;
|
|
}
|
|
|
|
[data-theme="dark"] .nav-tab:not(.nav-tab-active):hover i {
|
|
color: var(--color-text-primary);
|
|
}
|
|
|
|
[data-theme="dark"] .nav-tab-active {
|
|
color: #93c5fd;
|
|
border-bottom-color: #3b82f6;
|
|
background: linear-gradient(135deg, rgb(59 130 246 / 15%) 0%, rgb(59 130 246 / 5%) 100%);
|
|
}
|
|
|
|
[data-theme="dark"] .nav-tab-active i {
|
|
color: #93c5fd;
|
|
}
|
|
|
|
/* Section header */
|
|
[data-theme="dark"] .section-header {
|
|
background: linear-gradient(135deg, rgb(31 41 55 / 90%) 0%, rgb(17 24 39 / 90%) 100%);
|
|
}
|
|
|
|
/* Status indicators */
|
|
[data-theme="dark"] .status-indicator.success {
|
|
background-color: #064e3b;
|
|
color: #6ee7b7;
|
|
}
|
|
|
|
[data-theme="dark"] .status-indicator.error {
|
|
background-color: #7f1d1d;
|
|
color: #fca5a5;
|
|
}
|
|
|
|
[data-theme="dark"] .status-indicator.warning {
|
|
background-color: #78350f;
|
|
color: #fcd34d;
|
|
}
|
|
|
|
/* Skeleton loading */
|
|
[data-theme="dark"] .skeleton {
|
|
background-color: var(--color-border);
|
|
}
|
|
|
|
/* Scrollbar */
|
|
[data-theme="dark"] ::-webkit-scrollbar-track {
|
|
background: var(--color-surface);
|
|
}
|
|
|
|
[data-theme="dark"] ::-webkit-scrollbar-thumb {
|
|
background: #4b5563;
|
|
}
|
|
|
|
[data-theme="dark"] ::-webkit-scrollbar-thumb:hover {
|
|
background: #6b7280;
|
|
}
|
|
|
|
/* Log panel - slightly deeper than surface for contrast */
|
|
[data-theme="dark"] #logs-container {
|
|
background-color: #0f1623;
|
|
border-color: var(--color-border);
|
|
}
|
|
|
|
[data-theme="dark"] #logs-display,
|
|
[data-theme="dark"] #logs-loading,
|
|
[data-theme="dark"] #logs-empty {
|
|
background-color: #0f1623;
|
|
}
|
|
|
|
/* Warning/info boxes used in various partials */
|
|
[data-theme="dark"] .bg-yellow-50 { background-color: #422006; }
|
|
[data-theme="dark"] .border-yellow-200 { border-color: #78350f; }
|
|
[data-theme="dark"] .text-yellow-800 { color: #fcd34d; }
|
|
[data-theme="dark"] .text-yellow-700 { color: #fbbf24; }
|
|
[data-theme="dark"] .text-yellow-600 { color: #fbbf24; }
|
|
[data-theme="dark"] .bg-blue-50 { background-color: #1e3a5f; }
|
|
[data-theme="dark"] .border-blue-200 { border-color: #1e40af; }
|
|
[data-theme="dark"] .text-blue-800 { color: #93c5fd; }
|
|
[data-theme="dark"] .text-blue-700 { color: #93c5fd; }
|
|
[data-theme="dark"] .bg-red-50 { background-color: #450a0a; }
|
|
[data-theme="dark"] .border-red-200 { border-color: #7f1d1d; }
|
|
[data-theme="dark"] .text-red-800 { color: #fca5a5; }
|
|
[data-theme="dark"] .text-red-700 { color: #fca5a5; }
|
|
[data-theme="dark"] .bg-green-50 { background-color: #022c22; }
|
|
[data-theme="dark"] .border-green-200 { border-color: #064e3b; }
|
|
[data-theme="dark"] .text-green-800 { color: #6ee7b7; }
|
|
[data-theme="dark"] .text-green-700 { color: #6ee7b7; }
|
|
|
|
/* Theme toggle button */
|
|
.theme-toggle-btn {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
min-width: 44px;
|
|
min-height: 44px;
|
|
font-size: 1.1rem;
|
|
line-height: 1;
|
|
cursor: pointer;
|
|
border: none;
|
|
background: transparent;
|
|
color: #4b5563;
|
|
}
|
|
|
|
.theme-toggle-btn:hover {
|
|
opacity: 0.8;
|
|
}
|
|
|
|
[data-theme="dark"] .theme-toggle-btn {
|
|
color: #fbbf24;
|
|
}
|
|
|
|
/* Update available banner */
|
|
.update-banner {
|
|
background-color: #eff6ff;
|
|
border-color: #bfdbfe;
|
|
color: #1e40af;
|
|
}
|
|
.update-banner-action {
|
|
background-color: #3b82f6;
|
|
color: #fff;
|
|
}
|
|
.update-banner-action:hover {
|
|
background-color: #2563eb;
|
|
}
|
|
.update-banner-dismiss {
|
|
color: #1e40af;
|
|
opacity: 0.6;
|
|
}
|
|
.update-banner-dismiss:hover {
|
|
opacity: 1;
|
|
}
|
|
|
|
[data-theme="dark"] .update-banner {
|
|
background-color: #1e293b;
|
|
border-color: #334155;
|
|
color: #93c5fd;
|
|
}
|
|
[data-theme="dark"] .update-banner-action {
|
|
background-color: #2563eb;
|
|
}
|
|
[data-theme="dark"] .update-banner-action:hover {
|
|
background-color: #3b82f6;
|
|
}
|
|
[data-theme="dark"] .update-banner-dismiss {
|
|
color: #93c5fd;
|
|
}
|
|
|
|
/* Under-voltage / throttling warning banner */
|
|
.power-warning-banner {
|
|
background-color: #fef2f2;
|
|
border-color: #fecaca;
|
|
color: #991b1b;
|
|
}
|
|
.power-warning-banner-dismiss {
|
|
color: #991b1b;
|
|
opacity: 0.6;
|
|
}
|
|
.power-warning-banner-dismiss:hover {
|
|
opacity: 1;
|
|
}
|
|
|
|
[data-theme="dark"] .power-warning-banner {
|
|
background-color: #450a0a;
|
|
border-color: #7f1d1d;
|
|
color: #fca5a5;
|
|
}
|
|
[data-theme="dark"] .power-warning-banner-dismiss {
|
|
color: #fca5a5;
|
|
}
|
|
|
|
/* ===== Floating live preview (all tabs except Overview) ===== */
|
|
.floating-preview {
|
|
position: fixed;
|
|
right: 1rem;
|
|
bottom: 1rem;
|
|
z-index: 70;
|
|
background-color: #111827;
|
|
border: 1px solid #374151;
|
|
border-radius: 0.5rem;
|
|
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.4);
|
|
overflow: hidden;
|
|
/* Desktop: draggable resize handle (bottom-left visually, since the
|
|
panel is anchored to the right). Touch devices use the size button. */
|
|
resize: both;
|
|
min-width: 160px;
|
|
max-width: 90vw;
|
|
}
|
|
.floating-preview img {
|
|
background-color: #000;
|
|
}
|
|
.floating-preview-toggle {
|
|
position: fixed;
|
|
right: 1rem;
|
|
bottom: 1rem;
|
|
z-index: 70;
|
|
width: 44px;
|
|
height: 44px;
|
|
border-radius: 9999px;
|
|
background-color: var(--color-primary);
|
|
color: #ffffff;
|
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.35);
|
|
align-items: center;
|
|
justify-content: center;
|
|
}
|
|
@media (max-width: 640px) {
|
|
/* Whatever size is chosen, never wider than the phone viewport */
|
|
.floating-preview {
|
|
max-width: calc(100vw - 2rem);
|
|
}
|
|
}
|