:root { --v4-bg: #02040A; --v4-surface: rgba(0, 20, 40, 0.35); --v4-surface-2: rgba(0, 30, 60, 0.5); --v4-border: rgba(0, 229, 255, 0.25); --v4-border-hover: rgba(0, 229, 255, 0.55); --v4-text: #E6F7FF; --v4-text-secondary: rgba(230, 247, 255, 0.6); --v4-cyan: #00E5FF; --v4-green: #00FF9C; --v4-amber: #FFB300; --v4-red: #FF3B5C; --v4-mono: 'Consolas', 'JetBrains Mono', 'Courier New', monospace; --v4-sans: 'Segoe UI', system-ui, -apple-system, Arial, sans-serif; --v4-radius: 10px; --v4-glow-cyan: 0 0 12px rgba(0, 229, 255, 0.35); --v4-glow-green: 0 0 12px rgba(0, 255, 156, 0.35); --v4-glow-amber: 0 0 12px rgba(255, 179, 0, 0.35); --v4-glow-red: 0 0 12px rgba(255, 59, 92, 0.35); } * { box-sizing: border-box; } html, body { margin: 0; padding: 0; font-family: var(--v4-sans); background: var(--v4-bg); color: var(--v4-text); min-height: 100vh; } /* ===== Sternenfeld ===== */ body::before { content: ''; position: fixed; inset: 0; background-image: radial-gradient(1px 1px at 20% 30%, rgba(255,255,255,0.4) 50%, transparent 50%), radial-gradient(1px 1px at 70% 15%, rgba(255,255,255,0.3) 50%, transparent 50%), radial-gradient(1.5px 1.5px at 40% 70%, rgba(255,255,255,0.25) 50%, transparent 50%), radial-gradient(1px 1px at 85% 60%, rgba(255,255,255,0.35) 50%, transparent 50%), radial-gradient(1px 1px at 10% 80%, rgba(255,255,255,0.3) 50%, transparent 50%), radial-gradient(1.5px 1.5px at 55% 40%, rgba(255,255,255,0.2) 50%, transparent 50%), radial-gradient(1px 1px at 90% 90%, rgba(255,255,255,0.3) 50%, transparent 50%), radial-gradient(1px 1px at 30% 10%, rgba(255,255,255,0.4) 50%, transparent 50%); pointer-events: none; z-index: 0; } /* ===== Scanlines ===== */ .v4-scanlines { position: fixed; inset: 0; pointer-events: none; z-index: 9999; background: repeating-linear-gradient( 0deg, rgba(0, 0, 0, 0.12) 0px, rgba(0, 0, 0, 0.12) 1px, transparent 1px, transparent 3px ); opacity: 0; transition: opacity 0.3s ease; } .v4-scanlines.v4-scanlines--on { opacity: 1; } /* ===== Boot-Sequence ===== */ .v4-boot { position: fixed; inset: 0; background: var(--v4-bg); display: flex; align-items: center; justify-content: center; z-index: 10000; transition: opacity 0.6s ease; } .v4-boot.v4-boot--hidden { opacity: 0; pointer-events: none; } .v4-boot-inner { width: 420px; max-width: 90vw; border: 1px solid var(--v4-border); border-radius: var(--v4-radius); padding: 24px; background: var(--v4-surface); box-shadow: var(--v4-glow-cyan); } .v4-boot-logo { text-align: center; font-family: var(--v4-mono); font-size: 1.1rem; color: var(--v4-cyan); text-shadow: var(--v4-glow-cyan); margin-bottom: 20px; letter-spacing: 2px; } .v4-boot-line { display: flex; justify-content: space-between; font-family: var(--v4-mono); font-size: 0.85rem; color: var(--v4-text-secondary); padding: 4px 0; } .v4-boot-status { color: var(--v4-amber); } .v4-boot-status.v4-boot-ok { color: var(--v4-green); } .v4-boot-bar { height: 6px; background: rgba(255,255,255,0.08); border-radius: 3px; margin-top: 16px; overflow: hidden; } .v4-boot-bar-fill { height: 100%; width: 0%; background: linear-gradient(90deg, var(--v4-cyan), var(--v4-green)); box-shadow: var(--v4-glow-cyan); transition: width 0.3s ease; } .v4-boot-done { text-align: center; font-family: var(--v4-mono); font-size: 1rem; color: var(--v4-green); text-shadow: var(--v4-glow-green); margin-top: 16px; letter-spacing: 3px; opacity: 0; transition: opacity 0.4s ease; } .v4-boot-done.v4-boot-done--show { opacity: 1; } /* ===== Seite ===== */ .v4-page { position: relative; z-index: 1; max-width: 1500px; margin: 0 auto; padding: 12px; display: flex; flex-direction: column; gap: 12px; } /* ===== Header ===== */ .v4-header { display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: 10px; padding: 10px 16px; background: var(--v4-surface); border: 1px solid var(--v4-border); border-radius: var(--v4-radius); box-shadow: var(--v4-glow-cyan); } .v4-header-logo { font-family: var(--v4-mono); font-size: 1.2rem; font-weight: 700; color: var(--v4-cyan); text-shadow: var(--v4-glow-cyan); letter-spacing: 2px; } .v4-header-clock { display: flex; align-items: baseline; gap: 10px; } .v4-clock-time { font-family: var(--v4-mono); font-size: 1.6rem; font-weight: 700; color: var(--v4-cyan); text-shadow: var(--v4-glow-cyan); font-variant-numeric: tabular-nums; } .v4-clock-date { font-size: 0.85rem; color: var(--v4-text-secondary); } .v4-header-sun { display: flex; gap: 12px; } .v4-sun-item { font-family: var(--v4-mono); font-size: 0.9rem; color: var(--v4-amber); text-shadow: var(--v4-glow-amber); } .v4-header-status { display: flex; align-items: center; gap: 8px; } .v4-status-orb { width: 12px; height: 12px; border-radius: 50%; background: var(--v4-red); box-shadow: var(--v4-glow-red); transition: background 0.3s ease, box-shadow 0.3s ease; } .v4-status-orb.v4-status-orb--on { background: var(--v4-green); box-shadow: var(--v4-glow-green); animation: v4-pulse 2s ease-in-out infinite; } .v4-status-text { font-size: 0.8rem; color: var(--v4-text-secondary); } /* ===== Grid ===== */ .v4-grid { display: grid; grid-template-columns: 1fr 1.2fr 1fr; gap: 12px; align-items: start; } /* ===== Zone ===== */ .v4-zone { background: var(--v4-surface); border: 1px solid var(--v4-border); border-radius: var(--v4-radius); padding: 14px; position: relative; box-shadow: 0 0 20px rgba(0, 0, 0, 0.4); } /* Eck-Clips (Cockpit-Look) */ .v4-zone::before, .v4-zone::after { content: ''; position: absolute; width: 14px; height: 14px; border: 2px solid var(--v4-cyan); opacity: 0.6; } .v4-zone::before { top: -1px; left: -1px; border-right: none; border-bottom: none; } .v4-zone::after { bottom: -1px; right: -1px; border-left: none; border-top: none; } .v4-zone-title { display: flex; align-items: center; gap: 8px; font-family: var(--v4-mono); font-size: 0.95rem; font-weight: 700; color: var(--v4-cyan); text-shadow: var(--v4-glow-cyan); letter-spacing: 2px; margin-bottom: 12px; padding-bottom: 8px; border-bottom: 1px solid var(--v4-border); } .v4-zone-icon { font-size: 1.1rem; } .v4-sub-title { font-family: var(--v4-mono); font-size: 0.75rem; font-weight: 700; color: var(--v4-text-secondary); letter-spacing: 2px; margin: 14px 0 8px; text-transform: uppercase; } /* ===== Buttons ===== */ .v4-btn { appearance: none; border: 1px solid var(--v4-border); background: var(--v4-surface-2); color: var(--v4-text); border-radius: 6px; padding: 8px 14px; font-weight: 600; font-size: 0.85rem; cursor: pointer; transition: transform 0.12s ease, background 0.2s ease, border-color 0.2s ease, box-shadow 0.2s ease; display: inline-flex; align-items: center; gap: 6px; } .v4-btn:hover { background: rgba(0, 229, 255, 0.12); border-color: var(--v4-border-hover); transform: translateY(-1px); box-shadow: var(--v4-glow-cyan); } .v4-btn:active { transform: translateY(0); } .v4-btn--primary { border-color: rgba(0, 229, 255, 0.4); background: rgba(0, 229, 255, 0.1); color: var(--v4-cyan); } .v4-btn--on { border-color: rgba(0, 255, 156, 0.4); background: rgba(0, 255, 156, 0.1); color: var(--v4-green); } .v4-btn--off { border-color: rgba(255, 59, 92, 0.4); background: rgba(255, 59, 92, 0.1); color: var(--v4-red); } .v4-btn--big { padding: 12px 18px; font-size: 0.95rem; } .v4-btn--icon { padding: 6px 10px; font-size: 1rem; } /* ===== Flash-Feedback ===== */ @keyframes v4-flash-ok-anim { from { box-shadow: 0 0 0 2px rgba(0, 255, 156, 0.9); } to { box-shadow: 0 0 0 2px rgba(0, 255, 156, 0); } } @keyframes v4-flash-err-anim { from { box-shadow: 0 0 0 2px rgba(255, 59, 92, 0.9); } to { box-shadow: 0 0 0 2px rgba(255, 59, 92, 0); } } .v4-flash-ok { animation: v4-flash-ok-anim 0.6s ease-out; } .v4-flash-err { animation: v4-flash-err-anim 0.6s ease-out; } /* ===== Energie-Zone ===== */ .v4-gauge-wrap { display: flex; justify-content: center; margin-bottom: 10px; } #v4_gauge { width: 100%; max-width: 360px; height: auto; aspect-ratio: 3 / 2; display: block; } .v4-energy-stats { display: grid; grid-template-columns: repeat(4, 1fr); gap: 8px; margin-bottom: 12px; } .v4-stat { background: var(--v4-surface-2); border: 1px solid var(--v4-border); border-radius: 6px; padding: 8px; text-align: center; } .v4-stat-label { display: block; font-size: 0.65rem; color: var(--v4-text-secondary); text-transform: uppercase; letter-spacing: 1px; margin-bottom: 4px; } .v4-stat-value { font-family: var(--v4-mono); font-size: 0.95rem; font-weight: 700; color: var(--v4-text); } .v4-chart-wrap { background: rgba(0, 0, 0, 0.3); border: 1px solid var(--v4-border); border-radius: 6px; padding: 6px; margin-bottom: 10px; overflow: hidden; } #v4_power_chart, #v4_daily_chart, #v4_water_chart { width: 100%; height: auto; aspect-ratio: 2 / 1; display: block; } .v4-water { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; margin-bottom: 10px; } .v4-water-item { background: var(--v4-surface-2); border: 1px solid var(--v4-border); border-radius: 6px; padding: 8px; text-align: center; } .v4-water-label { display: block; font-size: 0.65rem; color: var(--v4-text-secondary); text-transform: uppercase; letter-spacing: 1px; margin-bottom: 4px; } .v4-water-value { font-family: var(--v4-mono); font-size: 0.9rem; font-weight: 700; color: var(--v4-cyan); } .v4-wemos { font-family: var(--v4-mono); font-size: 0.8rem; color: var(--v4-text-secondary); text-align: center; padding: 6px; border: 1px dashed var(--v4-border); border-radius: 6px; } /* ===== Kommando-Zone: Licht-Tiles ===== */ .v4-tiles { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; } .v4-tile { background: var(--v4-surface-2); border: 1px solid var(--v4-border); border-radius: 8px; padding: 12px 6px; text-align: center; cursor: pointer; transition: background 0.2s ease, border-color 0.2s ease, box-shadow 0.2s ease, transform 0.1s ease; position: relative; overflow: hidden; } .v4-tile:hover { border-color: var(--v4-border-hover); } .v4-tile:active { transform: scale(0.96); } .v4-tile-name { display: block; font-size: 0.75rem; font-weight: 600; color: var(--v4-text-secondary); margin-bottom: 6px; } .v4-tile-orb { display: block; width: 14px; height: 14px; margin: 0 auto; border-radius: 50%; background: rgba(255, 255, 255, 0.15); transition: background 0.3s ease, box-shadow 0.3s ease; } .v4-tile--on { background: rgba(0, 255, 156, 0.12); border-color: rgba(0, 255, 156, 0.5); box-shadow: var(--v4-glow-green); } .v4-tile--on .v4-tile-name { color: var(--v4-green); } .v4-tile--on .v4-tile-orb { background: var(--v4-green); box-shadow: var(--v4-glow-green); animation: v4-pulse 2s ease-in-out infinite; } /* Ripple */ .v4-tile-ripple { position: absolute; border-radius: 50%; background: rgba(0, 229, 255, 0.3); transform: scale(0); animation: v4-ripple 0.5s ease-out; pointer-events: none; } @keyframes v4-ripple { to { transform: scale(3); opacity: 0; } } /* ===== WLED ===== */ .v4-wled { display: flex; flex-direction: column; gap: 10px; } .v4-wled-row { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; } .v4-wled-label { font-size: 0.8rem; color: var(--v4-text-secondary); min-width: 80px; } .v4-slider { flex: 1; min-width: 120px; accent-color: var(--v4-cyan); } .v4-color { width: 48px; height: 36px; padding: 0; border: 1px solid var(--v4-border); border-radius: 6px; background: transparent; cursor: pointer; } /* ===== Rolladen ===== */ .v4-rolladen { display: flex; flex-direction: column; gap: 6px; } .v4-roll-row { display: flex; align-items: center; justify-content: space-between; gap: 8px; background: var(--v4-surface-2); border: 1px solid var(--v4-border); border-radius: 6px; padding: 6px 10px; } .v4-roll-name { font-size: 0.8rem; font-weight: 600; } .v4-roll-btns { display: flex; gap: 4px; } .v4-roll-btns .v4-btn { padding: 4px 8px; font-size: 0.75rem; } /* ===== Steckdosen ===== */ .v4-sockets { display: flex; flex-direction: column; gap: 6px; } .v4-socket-row { display: flex; align-items: center; justify-content: space-between; gap: 8px; background: var(--v4-surface-2); border: 1px solid var(--v4-border); border-radius: 6px; padding: 6px 10px; } .v4-socket-name { font-size: 0.8rem; font-weight: 600; } .v4-socket-orb { width: 16px; height: 16px; border-radius: 50%; background: rgba(255, 255, 255, 0.15); cursor: pointer; transition: background 0.3s ease, box-shadow 0.3s ease; } .v4-socket-orb.v4-socket-orb--on { background: var(--v4-green); box-shadow: var(--v4-glow-green); animation: v4-pulse 2s ease-in-out infinite; } /* ===== Haus ===== */ .v4-house { display: flex; flex-direction: column; gap: 8px; } /* ===== Funksteckdosen ===== */ .v4-funk { display: flex; flex-direction: column; gap: 6px; } .v4-funk-row { display: flex; align-items: center; justify-content: space-between; gap: 8px; background: var(--v4-surface-2); border: 1px solid var(--v4-border); border-radius: 6px; padding: 6px 10px; } .v4-funk-state { background: rgba(0, 0, 0, 0.25); border: 1px solid var(--v4-border); border-radius: 6px; padding: 8px; margin-bottom: 10px; } .v4-funk-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 6px; } .v4-funk-item { display: flex; align-items: center; justify-content: space-between; gap: 6px; background: var(--v4-surface-2); border: 1px solid var(--v4-border); border-radius: 6px; padding: 5px 8px; } .v4-funk-name { font-size: 0.75rem; font-weight: 600; color: var(--v4-text-secondary); } .v4-funk-val { font-family: var(--v4-mono); font-size: 0.8rem; font-weight: 700; color: var(--v4-text); } .v4-funk-val.v4-funk-val--on { color: var(--v4-green); text-shadow: var(--v4-glow-green); } .v4-funk-val.v4-funk-val--off { color: var(--v4-red); text-shadow: var(--v4-glow-red); } .v4-btn-group { display: flex; gap: 4px; flex-wrap: wrap; } .v4-funk-row .v4-btn { padding: 4px 8px; font-size: 0.75rem; } /* ===== Status-Zone: Heizung ===== */ .v4-heat { display: flex; flex-direction: column; gap: 6px; } .v4-heat-row { display: grid; grid-template-columns: 1fr 1fr; grid-template-rows: auto auto; gap: 6px 12px; align-items: center; background: var(--v4-surface-2); border: 1px solid var(--v4-border); border-radius: 6px; padding: 8px 10px; transition: border-color 0.2s ease; } .v4-heat-row:hover { border-color: var(--v4-border-hover); } .v4-heat-name { font-size: 0.8rem; font-weight: 600; grid-column: 1; grid-row: 1; } .v4-heat-tempwrap { grid-column: 2; grid-row: 1; justify-self: end; display: flex; align-items: center; gap: 6px; } .v4-heat-temp { font-family: var(--v4-mono); font-size: 1.1rem; font-weight: 700; text-align: right; } .v4-heat-temp--normal { color: var(--v4-text); } .v4-heat-temp--warm { color: var(--v4-amber); } .v4-heat-temp--hot { color: var(--v4-red); } .v4-heat-dot { width: 10px; height: 10px; border-radius: 50%; background: rgba(255, 255, 255, 0.15); } .v4-heat-dot--on { background: var(--v4-amber); box-shadow: var(--v4-glow-amber); animation: v4-pulse 1.5s ease-in-out infinite; } .v4-heat-bar-wrap { grid-column: 1 / 3; grid-row: 2; height: 8px; background: rgba(255, 255, 255, 0.08); border-radius: 4px; position: relative; overflow: hidden; } .v4-heat-set { display: flex; align-items: center; gap: 4px; } .v4-heat-set--min { grid-column: 1; grid-row: 3; } .v4-heat-set--max { grid-column: 2; grid-row: 3; } .v4-heat-input { width: 46px; padding: 4px 6px; font-size: 0.8rem; } .v4-btn--sm { padding: 4px 8px; font-size: 0.75rem; } /* ===== Stepper (Drehschalter) ===== */ .v4-stepper { display: inline-flex; align-items: center; gap: 2px; background: rgba(0, 0, 0, 0.3); border: 1px solid var(--v4-border); border-radius: 999px; padding: 2px; } .v4-stepper-btn { appearance: none; border: none; background: var(--v4-surface-2); color: var(--v4-cyan); width: 26px; height: 26px; border-radius: 50%; font-size: 1.1rem; font-weight: 700; line-height: 1; cursor: pointer; transition: background 0.2s ease, box-shadow 0.2s ease, transform 0.1s ease; display: inline-flex; align-items: center; justify-content: center; } .v4-stepper-btn:hover { background: rgba(0, 229, 255, 0.2); box-shadow: var(--v4-glow-cyan); } .v4-stepper-btn:active { transform: scale(0.9); } .v4-stepper-val { font-family: var(--v4-mono); font-size: 0.85rem; font-weight: 700; color: var(--v4-text); min-width: 48px; text-align: center; padding: 0 4px; } .v4-heat-bar { position: absolute; left: 0; top: 0; bottom: 0; width: 0%; background: linear-gradient(90deg, var(--v4-cyan), var(--v4-amber), var(--v4-red)); border-radius: 4px; transition: width 0.5s ease; } .v4-heat-band { position: absolute; top: 0; bottom: 0; background: rgba(255, 255, 255, 0.15); border-left: 1px solid rgba(255, 255, 255, 0.3); border-right: 1px solid rgba(255, 255, 255, 0.3); } /* ===== Pool ===== */ .v4-pool { display: flex; flex-direction: column; gap: 8px; } .v4-pool-bar { position: relative; height: 20px; background: rgba(255, 255, 255, 0.08); border: 1px solid var(--v4-border); border-radius: 999px; overflow: hidden; } .v4-pool-bar-fill { position: absolute; left: 0; top: 0; bottom: 0; width: 0%; background: linear-gradient(90deg, rgba(0, 229, 255, 0.5), var(--v4-cyan)); border-radius: 999px; box-shadow: var(--v4-glow-cyan); transition: width 0.6s ease; } .v4-pool-bar-fill--done { background: linear-gradient(90deg, rgba(0, 255, 156, 0.5), var(--v4-green)); box-shadow: var(--v4-glow-green); } .v4-pool-bar-label { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; font-family: var(--v4-mono); font-size: 0.75rem; font-weight: 600; color: var(--v4-text); text-shadow: 0 1px 3px rgba(0, 0, 0, 0.8); pointer-events: none; } .v4-pool-set { display: flex; align-items: center; gap: 8px; } .v4-pool-set-label { font-size: 0.75rem; color: var(--v4-text-secondary); } .v4-input { background: rgba(0, 0, 0, 0.3); color: var(--v4-text); border: 1px solid var(--v4-border); border-radius: 6px; padding: 6px 10px; font-size: 0.9rem; width: 80px; text-align: center; } .v4-input:focus { outline: none; border-color: var(--v4-cyan); } /* ===== Urlaub ===== */ .v4-urlaub { display: flex; align-items: center; gap: 10px; background: var(--v4-surface-2); border: 1px solid var(--v4-border); border-radius: 6px; padding: 10px; } .v4-urlaub-indicator { width: 16px; height: 16px; border-radius: 50%; background: rgba(255, 255, 255, 0.15); transition: background 0.3s ease, box-shadow 0.3s ease; } .v4-urlaub-indicator.v4-urlaub-indicator--on { background: var(--v4-amber); box-shadow: var(--v4-glow-amber); animation: v4-pulse 1.5s ease-in-out infinite; } .v4-urlaub-text { font-family: var(--v4-mono); font-size: 0.9rem; font-weight: 700; color: var(--v4-text-secondary); flex: 1; } /* ===== Footer ===== */ .v4-footer { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; padding: 10px 16px; background: var(--v4-surface); border: 1px solid var(--v4-border); border-radius: var(--v4-radius); box-shadow: var(--v4-glow-cyan); } .v4-footer-label { font-family: var(--v4-mono); font-size: 0.8rem; color: var(--v4-cyan); text-shadow: var(--v4-glow-cyan); letter-spacing: 1px; } /* ===== Toasts ===== */ .v4-toasts { position: fixed; bottom: 20px; right: 20px; display: flex; flex-direction: column; gap: 8px; z-index: 10001; } .v4-toast { background: var(--v4-surface-2); border: 1px solid var(--v4-border); border-left: 3px solid var(--v4-cyan); border-radius: 6px; padding: 10px 14px; font-size: 0.85rem; color: var(--v4-text); box-shadow: 0 4px 12px rgba(0, 0, 0, 0.5); animation: v4-toast-in 0.3s ease; max-width: 300px; } .v4-toast--ok { border-left-color: var(--v4-green); } .v4-toast--err { border-left-color: var(--v4-red); } @keyframes v4-toast-in { from { transform: translateX(30px); opacity: 0; } to { transform: translateX(0); opacity: 1; } } .v4-toast.v4-toast--out { animation: v4-toast-out 0.3s ease forwards; } @keyframes v4-toast-out { to { transform: translateX(30px); opacity: 0; } } /* ===== Animationen ===== */ @keyframes v4-pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.6; } } /* ===== Responsive ===== */ @media (max-width: 1100px) { .v4-grid { grid-template-columns: 1fr; } } @media (max-width: 768px) { .v4-page { padding: 8px; } .v4-header { flex-direction: column; align-items: flex-start; } .v4-energy-stats { grid-template-columns: repeat(2, 1fr); } .v4-tiles { grid-template-columns: repeat(2, 1fr); } .v4-water { grid-template-columns: 1fr; } } /* ===== Scrollbar ===== */ ::-webkit-scrollbar { width: 8px; } ::-webkit-scrollbar-track { background: var(--v4-bg); } ::-webkit-scrollbar-thumb { background: var(--v4-border); border-radius: 4px; } ::-webkit-scrollbar-thumb:hover { background: var(--v4-border-hover); }