Files
Smart-Dashboard/css/solar.css
T
adminandClaude Opus 5 d285ec27a0 Einstellungsseite, Skoda-Seite und Karte
Sammelstand der offenen Arbeit im Dashboard.

Einstellungen: eine Eingabemaske fuer die Energiepreise unter
restricted/settings.php, dazu costs.php als Modell und ajax/settings.php
als Endpunkt. Die Preise stehen jetzt in gridCosts, gasCosts und fuelCosts
statt fest im Quelltext von getStats.php; die Jahresstatistik rechnet ueber
LEAD() den jeweils gueltigen Zeitraum aus und schlaegt den anteiligen
Grundpreis auf. Eingegeben wird in gewohnten Einheiten - l/100 km,
kWh/100 km, Euro je Liter -, umgerechnet wird beim Speichern.
solarLog_costs.sql beschreibt die Umstellung der Tabellen.

Skoda: eigene Seite mit Live-Werten ueber MQTT und Historie ueber
ajax/skoda.php, Kommandos ueber ajax/skodaCmd.php.

Karte: Leaflet mit einem eigenen Kachel-Zwischenspeicher (ajax/tile.php),
dessen Ablage unter tiles/ nicht ins Repository gehoert.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-02 21:21:27 +02:00

909 lines
29 KiB
CSS

.winddir {
position:absolute;
left:60%;
width:25%;
height:40%;
padding: 0;
background-image: url('../assets/img/arrow.svg');
background-size:contain;
background-repeat: no-repeat;
background-position: center;
}
/* Schieberegler in den Modals (Autoladung, Heizstab, Thermostat).
Der gefuellte Anteil kommt aus --background-size, gesetzt von
bindModalSlider() in js/solar/common.js. */
input[type='range']::-webkit-slider-runnable-track {
background: linear-gradient(to right, #00788F, #00788F), #D7D7D7;
background-size: var(--background-size, 0%) 100%;
background-repeat: no-repeat;
}
/* Diagramme (Chart.js). Die Hoehe kommt aus diesem Container, nicht aus dem
canvas - die Charts laufen mit maintainAspectRatio: false. Auf dem Handy
ist der Container nur rund 300 px breit; mit 400 px Hoehe wird aus einer
Zeitreihe ein Hochformat, in dem die Zeitachse die kurze Seite ist. */
.chart-container {
position: relative;
width: 100%;
height: 400px;
}
@media (max-width: 767.98px) {
.chart-container {
height: 250px;
}
}
/* Statistik-Kacheln (ajax/getStats.php). Sie lagen in nackten .col ohne
Breitenangabe - Bootstrap laesst sie dann nach Textlaenge umbrechen, mal
zwei, mal drei je Zeile und unterschiedlich breit. Die Breite kommt jetzt
aus row-cols-* in getStats.php; hier sorgt die volle Kartenhoehe dafuer,
dass die Werte trotz ein- oder zweizeiliger Titel auf einer Linie
stehen. */
.card.stats {
height: 100%;
}
.card.stats .card-body {
flex: 1 1 auto;
}
/* Auf dem Handy gehen von 375 px rund 75 an Innenabstaende verloren, und
zwischen den Karten stehen 24 px. Beides wird hier enger gefasst - nur
im Inhaltsbereich, damit Seitenleiste, Kopfzeile und Modals unberuehrt
bleiben. Die Abstandsklassen von Bootstrap (mb-4) tragen !important,
deshalb steht es auch hier. */
@media (max-width: 767.98px) {
.app-content {
padding: 0 .25rem;
}
.app-content-header {
padding: .5rem .25rem;
}
.app-content .row {
--bs-gutter-x: .5rem;
}
.app-content .card {
margin-bottom: .75rem !important;
}
/* Nur der Standardwert wird kleiner; eigene Angaben im Markup (p-0 fuer
das Realtime-SVG, p-2 fuer die Statistik) gelten weiter. */
.app-content .card-body {
padding: .5rem;
}
/* Eine Kachel ist auf dem Handy rund 150 px breit. In voller Schrift
passt "Verbrauchsersparnis" dort nicht in eine Zeile und wird mitten
im Wort umbrochen. */
.card.stats .card-body {
font-size: .8rem;
}
}
/* Editor der Automatiken. Eine Bedingungszeile traegt Geraet, Messwert,
Vergleich, Wert, Einheit und den Papierkorb nebeneinander - auf einem
Handy bleiben davon "Therm OG Bad" und "te" uebrig, weil die Felder in
der input-group einfach mitschrumpfen. Unter 576 px bekommen deshalb
Geraet und Messwert je eine eigene Zeile; Vergleich, Wert und Einheit
sind kurz genug, um zusammen in die naechste zu passen. */
@media (max-width: 575.98px) {
/* Die input-group-Klasse muss mit in den Selektor: solar.css wird vor
AdminLTE geladen, und Bootstraps ".input-group > .form-select" haette
sonst dasselbe Gewicht und wuerde als spaeteres Blatt gewinnen. */
.input-group.auto-zeile > .auto-geraet,
.input-group.auto-zeile > .auto-messwert {
flex: 1 1 100%;
width: auto;
}
}
/* Raum-Modal. Ein Kommando mit mehreren Parametern ("Position+Neigung")
traegt Beschriftung, zwei Zahlenfelder und den Ausloeseknopf in einer
input-group - auf einem Handy schrumpfen die Felder dabei auf Nullbreite.
Eine Mindestbreite laesst die Zeile stattdessen umbrechen. */
.input-group.raum-cmd > .form-control,
.input-group.raum-cmd > .form-select {
min-width: 5rem;
}
/* --------------------------------------------------------------------------
Raum-Modal: Bedienelemente
Erzeugt von restricted/roomControls.php, verdrahtet in js/solar/homeMQTT.js.
-------------------------------------------------------------------------- */
/* Die Geraetegruppen als Reiter. Auf einem Handy passen fuenf
Beschriftungen nicht nebeneinander - dann scrollt die Leiste seitwaerts,
statt die Namen umzubrechen. Die durchgehende Linie unter den Reitern
darf dabei nicht mitscrollen, sie gehoert an den unteren Rand. */
.raum-tabs {
overflow-x: auto;
overflow-y: hidden;
scrollbar-width: none;
flex-wrap: nowrap;
}
.raum-tabs::-webkit-scrollbar {
display: none;
}
.raum-tabs .nav-link {
padding: 0.3rem 0.7rem;
font-size: 0.8rem;
white-space: nowrap;
border-bottom-color: transparent;
}
/* Waehrend ein Kommando unterwegs ist. Ein "Zu" an einer Jalousie dauert
ueber eine Minute; ohne sichtbare Sperre tippt man in der Zeit nach. */
.raum-geraet.raum-warte {
opacity: 0.55;
pointer-events: none;
}
.raum-geraet.raum-warte::after {
content: "";
position: absolute;
top: 0.5rem;
right: 0.5rem;
width: 0.9rem;
height: 0.9rem;
border: 2px solid currentColor;
border-right-color: transparent;
border-radius: 50%;
animation: raum-dreht 0.8s linear infinite;
}
.raum-geraet {
position: relative;
}
@keyframes raum-dreht {
to { transform: rotate(360deg); }
}
/* --------------------------------------------------------------------------
Regler im Raum-Modal
Eigenes Aussehen statt des Bootstrap-Standards: dessen weisse Bahn mit dem
blauen Griff sticht auf den dunklen Karten heraus, und in einem Raum mit
drei Jalousien sind das sechs helle Balken. Bahn und Griff tragen deshalb
dasselbe Blaugruen wie der Temperaturregler, und der ungefuellte Teil ist
ein Grau, das in beiden Themes traegt.
Bewusst nur innerhalb von #roomView: die Regler in den Modals fuer
Autoladung und Heizstab bleiben, wie sie sind.
-------------------------------------------------------------------------- */
#roomView input[type='range'] {
-webkit-appearance: none;
appearance: none;
width: 100%;
height: 1.5rem;
padding: 0;
margin: 0;
background: transparent;
}
#roomView input[type='range']:focus {
outline: 0;
}
/* Getrennt notiert, nicht als Liste: einen Selektor, den er nicht kennt,
wirft der Browser samt der ganzen Regel weg - und dann bliebe die Bahn
ungestaltet. */
#roomView input[type='range']::-webkit-slider-runnable-track {
height: 0.375rem;
border: 0;
border-radius: 0.375rem;
background: linear-gradient(to right, #00788F, #00788F), rgba(128, 128, 128, 0.32);
background-size: var(--background-size, 0%) 100%;
background-repeat: no-repeat;
}
#roomView input[type='range']::-moz-range-track {
height: 0.375rem;
border: 0;
border-radius: 0.375rem;
background: linear-gradient(to right, #00788F, #00788F), rgba(128, 128, 128, 0.32);
background-size: var(--background-size, 0%) 100%;
background-repeat: no-repeat;
}
#roomView input[type='range']::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
width: 1.05rem;
height: 1.05rem;
/* (Bahnhoehe - Griffhoehe) / 2, damit der Griff auf der Bahn sitzt. */
margin-top: -0.34rem;
border: 2px solid #fff;
border-radius: 50%;
background: #00788F;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.45);
}
#roomView input[type='range']::-moz-range-thumb {
width: 1.05rem;
height: 1.05rem;
border: 2px solid #fff;
border-radius: 50%;
background: #00788F;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.45);
}
/* Schieberegler stehen dicht untereinander (Helligkeit, Farbe). Ohne den
Abstand kleben Beschriftung und Bahn aneinander.
Die senkrechten Spalten stehen dagegen nebeneinander - dort wuerde der
Abstand die zweite Spalte um genau diese 0,35 rem tiefer setzen. */
.raum-regler + .raum-regler:not(.raum-spalte) {
margin-top: 0.35rem;
}
/* Messwerte als Gitter statt als Textwurst: ein Stromzaehler hat sechzehn
Werte, die in einer Zeile niemand findet. auto-fill statt fester Spalten,
damit auf dem Handy zwei und auf dem Schirm vier nebeneinander passen. */
.raum-werte {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(6.5rem, 1fr));
gap: 0.4rem;
}
.raum-wert {
background: rgba(128, 128, 128, 0.08);
border-radius: 0.35rem;
padding: 0.3rem 0.45rem;
overflow: hidden;
}
.raum-wert-zahl {
font-size: 0.95rem;
font-weight: 600;
line-height: 1.2;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.raum-wert-einheit {
font-size: 0.7rem;
font-weight: 400;
opacity: 0.6;
}
.raum-wert-name {
font-size: 0.68rem;
opacity: 0.6;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
/* --------------------------------------------------------------------------
Raum-Modal: Jalousien
-------------------------------------------------------------------------- */
/* Fahrknoepfe, Hoehe und Neigung nebeneinander. Die Neigung nimmt den Rest -
sie ist die einzige der drei Spalten, die von Breite profitiert. */
.raum-jalousie {
display: flex;
align-items: stretch;
justify-content: space-between;
gap: 0.4rem;
}
/* Das Fensterbild steht zwischen Knoepfen und Reglern - schmal, mit Luft
zu beiden Seiten. Der uebrige Platz verteilt sich auf die Zwischenraeume
(space-between an .raum-jalousie), statt das Bild breitzuziehen. */
.raum-jalousie .raum-lamellen {
flex: 0 1 5rem;
min-width: 2.2rem;
margin: 0 0.4rem;
}
.raum-jalousie .dropdown {
align-self: flex-start;
}
/* Auf, Stop, Zu untereinander - die Knoepfe zeigen in die Richtung, in die
sie fahren. Breit genug fuer einen Daumen: sie sind das, was man im
Vorbeigehen antippt, die Regler daneben braucht man seltener. */
.raum-fahrt {
flex: 0 0 3.1rem;
}
.raum-fahrt .btn {
padding: 0.3rem 0;
line-height: 1.5;
}
/* Eine Spalte mit senkrechtem Regler: Name, oberes Wort, Bahn, unteres
Wort, Zahl. Breit genug fuer "Position" in der kleinen Schrift. */
.raum-spalte {
flex: 0 0 3.4rem;
display: flex;
flex-direction: column;
align-items: center;
text-align: center;
}
.raum-name {
font-size: 0.62rem;
opacity: 0.8;
white-space: nowrap;
line-height: 1.2;
}
/* Der Kasten, in dem ein gewoehnlicher Regler auf der Seite liegt.
Gedreht statt writing-mode: so gebaute Regler lassen sich am Handy kaum
anfassen - das Ziehen wird als Wischen gelesen und blaettert die Seite.
Gedreht bewegt sich der Regler in seinen eigenen Koordinaten waagerecht,
und touch-action haelt die Seite still, solange der Finger auf ihm liegt.
rotate(90deg) legt den kleinen Wert nach oben: "oben" ist 0 %. */
.raum-senkrecht {
position: relative;
width: 1.6rem;
height: 6.5rem;
margin: 0.1rem 0;
}
#roomView .raum-senkrecht input[type='range'] {
position: absolute;
top: 50%;
left: 50%;
width: 6.5rem; /* = Hoehe des Kastens, die Laenge der Bahn */
height: 1.6rem; /* = Breite des Kastens, die Flaeche zum Treffen */
transform: translate(-50%, -50%) rotate(90deg);
touch-action: none;
}
/* Die Endstellungen in Worten statt in Prozent. */
.raum-ende {
font-size: 0.68rem;
opacity: 0.65;
line-height: 1.1;
}
/* Die Lamellen zur Neigung. Ihre Hoehe setzt lamellenZeichnen() in
js/solar/homeMQTT.js - schmal mit Luft dazwischen heisst offen,
aneinanderliegend heisst geschlossen. */
.raum-lamellen {
display: block;
align-self: center;
height: 6.9rem;
/* Der Rahmen macht aus dem Streifen ein Fenster - ohne ihn liest sich das
geschlossene Bild wie eine zweite Reglerbahn. */
background: rgba(0, 120, 143, 0.14);
border: 1px solid rgba(128, 128, 128, 0.35);
border-radius: 0.2rem;
}
.raum-lamelle {
fill: currentColor;
opacity: 0.6;
stroke: rgba(0, 0, 0, 0.35);
stroke-width: 0.6;
vector-effect: non-scaling-stroke;
}
.raum-endschiene {
fill: currentColor;
opacity: 0.85;
}
/* --- Einstellungen: Preistabellen ------------------------------------ */
/* Der Spaltenkopf steht ueber der ersten Zeile und muss deren Einrueckung
treffen, sonst rutschen Beschriftung und Feld auseinander. Er bleibt
einzeilig, braucht also keinen senkrechten Gutter - und ohne den entfaellt
auch Bootstraps negative Marge von selbst. */
.preis-kopf {
--bs-gutter-y: 0;
padding: 0 0.25rem 0.35rem;
}
/* Eine Zeile ist selbst eine .row mit g-2. Bootstrap zieht so eine Reihe um
die Gutter-Hoehe nach oben und gibt jeder Spalte dieselbe Marge nach unten
zurueck - gedacht fuer Reihen, die nebeneinander im Raster stehen. Hier
stehen sie untereinander, und der Zug nach oben frisst den unteren
Innenabstand der vorigen Zeile auf: auf dem Handy, wo der Papierkorb in
einer eigenen Zeile landet, klebte er am Trennstrich.
Die senkrechte Gutter-Marge wird hier gebraucht - sie haelt die umbrochenen
Feldzeilen auseinander -, der Zug nach oben nicht. Die Regel braucht eine
Klasse mehr als Bootstraps .row: solar.css wird vor AdminLTE geladen und
verliert bei gleicher Spezifitaet. */
.preis-zeilen .preis-zeile {
margin-top: 0;
}
/* Oben um die Gutter-Hoehe weniger Innenabstand, damit ueber der ersten und
unter der letzten Feldzeile gleich viel Luft steht. */
.preis-zeile {
padding: 0.15rem 0.25rem 0.65rem;
border-top: 1px solid rgba(128, 128, 128, 0.25);
}
/* Die Einheit ist Beiwerk und darf der Zahl nicht den Platz nehmen: hinter
"kWh/100 km" bliebe in voller Schrift kaum ein Drittel der Spalte fuer das
Eingabefeld uebrig. */
.preis-zeile .input-group-text {
font-size: 0.75rem;
padding-left: 0.4rem;
padding-right: 0.4rem;
}
/* Der Zeitraum, der heute gilt - der einzige, den man beim Nachschlagen
wirklich sucht. */
.preis-heute {
background: rgba(0, 120, 143, 0.12);
border-radius: 0.4rem;
}
/* ==========================================================================
Skoda-Seite (restricted/skoda.php)
Farben kommen aus den Bootstrap-Variablen des Themes, damit die Seite dem
Hell-/Dunkelmodus folgt, ohne eine zweite Palette zu pflegen. Nur drei
Bedeutungsfarben stehen fuer sich: bernstein fuer "offen", gelb fuer
eingeschaltetes Licht, gruen fuer Laden.
========================================================================== */
.skoda-auto,
.skoda-teile,
.skoda-karte {
--skoda-offen: #e0904f;
--skoda-licht: #f2d16b;
--skoda-laden: #4caf7d;
--skoda-blech: 128, 138, 148;
}
/* --- Fahrzeug in Draufsicht ----------------------------------------------
Massstaeblich: 4648 x 1877 mm ergeben das Seitenverhaeltnis 2,48:1, der
Radstand von 2765 mm die Lage der Raeder. */
.skoda-auto {
width: 100%;
max-width: 215px;
height: auto;
}
.skoda-auto .karosserie {
fill: rgba(var(--skoda-blech), 0.17);
stroke: rgba(var(--skoda-blech), 0.55);
stroke-width: 2;
}
.skoda-auto .rad rect { fill: rgba(18, 20, 24, 0.9); }
.skoda-auto .spiegel rect { fill: rgba(var(--skoda-blech), 0.55); }
.skoda-auto .reling rect { fill: rgba(var(--skoda-blech), 0.62); }
.skoda-auto .spoiler { fill: rgba(var(--skoda-blech), 0.5); }
.skoda-auto .sicke {
fill: none;
stroke: rgba(var(--skoda-blech), 0.35);
stroke-width: 1.5;
}
/* Das Tech-Deck Face: beim Enyaq eine glaenzend schwarze Blende ueber die
volle Bugbreite. Von oben sieht man ihre Oberkante. */
.skoda-auto .techdeck {
fill: rgba(12, 14, 18, 0.92);
stroke: rgba(var(--skoda-blech), 0.4);
stroke-width: 1;
}
.skoda-auto .scheibe,
.skoda-auto .dach {
fill: rgba(var(--skoda-blech), 0.28);
stroke: rgba(var(--skoda-blech), 0.45);
stroke-width: 1.5;
}
/* Grundzustand aller schaltbaren Teile: geschlossen und unauffaellig. */
.skoda-auto .teil > *,
.skoda-auto .teil > g > * {
fill: rgba(var(--skoda-blech), 0.34);
stroke: rgba(var(--skoda-blech), 0.6);
stroke-width: 1.5;
transition: fill .25s, stroke .25s, filter .25s;
}
.skoda-auto .teil-fenster > rect { fill: rgba(var(--skoda-blech), 0.5); }
/* Offen: bernstein und leicht leuchtend. Die Farbe allein traegt die Aussage
nicht - die Zeile unter dem Bild benennt jedes offene Teil zusaetzlich. */
.skoda-auto .teil.offen > *,
.skoda-auto .teil.offen > g > * {
fill: var(--skoda-offen);
stroke: var(--skoda-offen);
filter: drop-shadow(0 0 6px rgba(224, 144, 79, 0.65));
}
/* Licht: vorn die vier LED-Elemente je Seite, hinten das Leuchtenband. */
.skoda-auto .teil-licht.an > rect {
fill: var(--skoda-licht);
stroke: var(--skoda-licht);
filter: drop-shadow(0 0 8px rgba(242, 209, 107, 0.75));
}
.skoda-auto .teil-licht.an > rect.rueck {
fill: #e06060;
stroke: #e06060;
filter: drop-shadow(0 0 8px rgba(224, 96, 96, 0.7));
}
.skoda-auto .teil-stecker > path { fill: none; stroke-width: 2; }
.skoda-auto .teil-stecker.laedt > circle {
fill: var(--skoda-laden);
stroke: var(--skoda-laden);
animation: skodaPuls 1.8s ease-in-out infinite;
}
.skoda-auto .teil-stecker.laedt > path { stroke: #0d1210; }
@keyframes skodaPuls {
0%, 100% { filter: drop-shadow(0 0 3px rgba(76, 175, 125, 0.5)); }
50% { filter: drop-shadow(0 0 12px rgba(76, 175, 125, 0.95)); }
}
/* Hervorheben, wenn der zugehoerige Eintrag darunter beruehrt wird - und
umgekehrt. Sichtbarer Fokus, damit das auch mit der Tastatur geht. */
.skoda-auto .teil.hervor > *,
.skoda-auto .teil.hervor > g > * {
stroke: var(--bs-primary, #0d6efd);
stroke-width: 2.5;
}
@media (hover: hover) {
.skoda-auto .teil:hover > *,
.skoda-auto .teil > g:hover > * {
stroke: var(--bs-primary, #0d6efd);
stroke-width: 2.5;
}
}
.skoda-auto .teil:focus,
.skoda-auto .teil > g:focus { outline: none; }
.skoda-auto .teil:focus-visible > *,
.skoda-auto .teil > g:focus-visible > * {
stroke: var(--bs-primary, #0d6efd);
stroke-width: 3;
}
@media (prefers-reduced-motion: reduce) {
.skoda-auto .teil > *,
.skoda-auto .teil > g > * { transition: none; }
.skoda-auto .teil-stecker.laedt > circle { animation: none; }
}
/* --- Zustandszeile unter dem Fahrzeug ------------------------------------ */
.skoda-teile {
display: flex;
flex-wrap: wrap;
gap: .35rem;
justify-content: center;
margin-top: .9rem;
}
.skoda-teile .chip {
display: inline-flex;
align-items: center;
gap: .35rem;
font-size: .78rem;
padding: .2rem .55rem;
border-radius: 1rem;
border: 1px solid var(--bs-border-color, rgba(128, 128, 128, .35));
color: var(--bs-secondary-color, #9aa0a6);
cursor: default;
white-space: nowrap;
}
.skoda-teile .chip.offen { border-color: var(--skoda-offen); color: var(--skoda-offen); }
.skoda-teile .chip.hervor {
border-color: var(--bs-primary, #0d6efd);
color: var(--bs-body-color, #e8ede9);
}
/* Auf Beruehrungsgeraeten sind die Ziele zu klein: eine Fingerkuppe deckt
rund 9 mm ab, die Chips waren keine 6 mm hoch. Gleiches gilt fuer die
Fahrtzeilen und den Umschalter. */
@media (pointer: coarse) {
.skoda-teile { gap: .5rem; }
.skoda-teile .chip {
font-size: .85rem;
padding: .45rem .8rem;
cursor: pointer;
}
.skoda-liste .zeile { padding: .75rem .9rem; }
.skoda-umschalter button { font-size: .85rem; padding: .5rem .9rem; }
}
.skoda-teile .chip.an { border-color: var(--skoda-licht); color: var(--skoda-licht); }
/* --- Ladestandsring ------------------------------------------------------ */
.skoda-ring { width: 100%; max-width: 190px; height: auto; }
.skoda-ring .ring-bahn {
fill: none;
stroke: rgba(128, 138, 148, 0.22);
stroke-width: 16;
}
.skoda-ring .ring-wert {
fill: none;
stroke: #4caf7d;
stroke-width: 16;
stroke-linecap: round;
transform: rotate(-90deg);
transform-origin: 100px 100px;
transition: stroke-dashoffset .6s ease, stroke .3s;
}
.skoda-ring .ring-ziel {
stroke: var(--bs-body-color, #e8ede9);
stroke-width: 3;
opacity: .75;
transform-origin: 100px 100px;
}
.skoda-ring .ring-zahl {
fill: var(--bs-body-color, #e8ede9);
font-size: 46px;
font-weight: 600;
text-anchor: middle;
font-variant-numeric: tabular-nums;
}
.skoda-ring .ring-einheit {
fill: var(--bs-secondary-color, #9aa0a6);
font-size: 14px;
letter-spacing: .12em;
text-anchor: middle;
text-transform: uppercase;
}
/* --- Wertetabelle -------------------------------------------------------- */
.skoda-werte {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(9.5rem, 1fr));
gap: .75rem 1.25rem;
}
.skoda-wert { display: flex; flex-direction: column; }
.skoda-wert .k {
font-size: .7rem;
letter-spacing: .09em;
text-transform: uppercase;
color: var(--bs-secondary-color, #9aa0a6);
}
.skoda-wert .v {
font-size: 1.15rem;
font-variant-numeric: tabular-nums;
}
/* --- Herkunft des Ladestroms --------------------------------------------- */
.skoda-balken {
display: flex;
height: .7rem;
border-radius: .35rem;
overflow: hidden;
background: rgba(128, 138, 148, 0.2);
}
.skoda-balken > div { transition: width .5s ease; }
.skoda-balken .teil-pv { background: #f0b429; }
.skoda-balken .teil-netz { background: #7a8791; }
/* --- Listen (Ladungen, Fahrten) ------------------------------------------ */
/* Der Innenabstand oben trennt die erste Zeile von der Ueberschrift. Ohne
ihn klebt sie am Umschalter, was auf dem Handy besonders auffaellt. */
.skoda-liste {
max-height: 400px;
overflow-y: auto;
padding-top: .5rem;
}
.skoda-liste .zeile {
display: flex;
justify-content: space-between;
align-items: baseline;
gap: .75rem;
padding: .5rem .9rem;
border-top: 1px solid var(--bs-border-color, rgba(128, 128, 128, .25));
}
.skoda-liste .zeile:first-child { border-top: none; }
@media (hover: hover) {
.skoda-liste .zeile:hover { background: rgba(128, 138, 148, 0.08); }
}
.skoda-liste .wann { font-size: .82rem; color: var(--bs-secondary-color, #9aa0a6); }
.skoda-liste .was { font-size: .95rem; font-variant-numeric: tabular-nums; text-align: right; }
.skoda-liste .neben { display: block; font-size: .75rem; color: var(--bs-secondary-color, #9aa0a6); }
.skoda-liste .leer { padding: 1.5rem .9rem; color: var(--bs-secondary-color, #9aa0a6); }
/* Umschalter kWh <-> Prozent in der Ueberschrift der Fahrtenliste. Welche
Einheit sichtbar ist, entscheidet die Klasse auf der Kachel - so bleibt die
Auswahl bestehen, wenn die Liste neu gebaut wird. */
.zeigt-kwh .v-prozent,
.zeigt-prozent .v-kwh,
.zeigt-prozent #skodaVerbrauchBasis { display: none; }
.skoda-umschalter {
display: inline-flex;
border: 1px solid var(--bs-border-color, rgba(128, 128, 128, .35));
border-radius: .3rem;
overflow: hidden;
}
.skoda-umschalter button {
background: none;
border: none;
color: var(--bs-secondary-color, #9aa0a6);
font-size: .72rem;
line-height: 1;
padding: .25rem .5rem;
cursor: pointer;
}
.skoda-umschalter button + button {
border-left: 1px solid var(--bs-border-color, rgba(128, 128, 128, .35));
}
.skoda-umschalter button:hover { background: rgba(128, 138, 148, .12); }
.skoda-umschalter button.aktiv {
background: rgba(128, 138, 148, .22);
color: var(--bs-body-color, #e8ede9);
}
.skoda-umschalter button:focus-visible {
outline: 2px solid var(--bs-primary, #0d6efd);
outline-offset: -2px;
}
/* Fahrtzeilen, die sich auf der Karte zeigen lassen. Der Zeiger und die
Markierung sind der einzige Hinweis darauf - ohne den waere die Kopplung
nicht zu erraten. */
.skoda-liste .zeile.anklickbar { cursor: pointer; }
.skoda-liste .zeile.anklickbar:focus-visible {
outline: 2px solid var(--bs-primary, #0d6efd);
outline-offset: -2px;
}
/* Dieselbe Farbe wie die gewaehlte Linie auf der Karte - die Zuordnung
zwischen Zeile und Linie soll ohne Nachdenken erkennbar sein. */
.skoda-liste .zeile.gewaehlt {
background: rgba(224, 144, 79, 0.14);
box-shadow: inset 3px 0 0 #e0904f;
}
/* --- Karte (Leaflet) -----------------------------------------------------
Die Kacheln kommen ueber ajax/tile.php aus dem eigenen Zwischenspeicher.
OpenStreetMap-Kacheln sind hell; im dunklen Dashboard wuerden sie wie ein
Scheinwerfer wirken. invert + hue-rotate dreht sie ins Dunkle, ohne einen
zweiten Anbieter samt eigener Bedingungen ins Spiel zu bringen. Der Filter
sitzt auf den Kacheln allein - Marker, Linien und Bedienelemente behalten
ihre Farben. */
.skoda-karte {
height: 420px;
width: 100%;
border-radius: .4rem;
background: rgba(128, 138, 148, 0.12);
z-index: 0; /* sonst legt sich die Karte ueber die Seitenleiste */
}
.skoda-karte .leaflet-tile-pane {
filter: invert(1) hue-rotate(180deg) brightness(0.92) contrast(0.9);
}
/* Bedienelemente und Sprechblasen an das dunkle Theme angleichen. */
.skoda-karte .leaflet-bar a,
.skoda-karte .leaflet-bar a:hover {
background: #23282c;
color: var(--bs-body-color, #e8ede9);
border-bottom-color: #33393e;
}
.skoda-karte .leaflet-bar a:hover { background: #2d3338; }
.skoda-karte .leaflet-popup-content-wrapper,
.skoda-karte .leaflet-popup-tip {
background: #23282c;
color: var(--bs-body-color, #e8ede9);
box-shadow: 0 3px 14px rgba(0, 0, 0, .5);
}
.skoda-karte .leaflet-popup-content { margin: .6rem .8rem; line-height: 1.5; }
.skoda-karte .leaflet-popup-close-button { color: var(--bs-secondary-color, #9aa0a6); }
/* Die Nennung von OpenStreetMap ist Pflicht und darf nicht versteckt werden -
nur ruhiger gesetzt, damit sie das Bild nicht dominiert.
Ohne Hintergrundkasten, dafuer mit Schattenwurf: ein durchsichtiger
Hintergrund allein liesse den Text ueber hellen Kartenstellen verschwinden,
und unlesbar waere so gut wie versteckt. Der Schatten haelt ihn auf jedem
Untergrund erkennbar, ohne einen Balken ins Bild zu setzen. */
/* Der doppelte Klassenname ist noetig, nicht Zierde: Leaflet setzt den
Hintergrund ueber .leaflet-container .leaflet-control-attribution, also mit
derselben Spezifitaet wie ein einfaches .skoda-karte davor - und leaflet.css
wird spaeter geladen, gewinnt bei Gleichstand also. Der Kartencontainer
traegt beide Klassen, damit sticht diese Regel. */
.skoda-karte.leaflet-container .leaflet-control-attribution {
background: transparent;
color: #c9d0d6;
font-size: .68rem;
padding: 0 .4rem;
text-shadow: 0 1px 2px rgba(0, 0, 0, .9), 0 0 4px rgba(0, 0, 0, .75);
}
.skoda-karte.leaflet-container .leaflet-control-attribution a {
color: #a9c8f0;
text-shadow: inherit;
}
.skoda-kartenlegende {
display: inline-flex;
gap: .9rem;
font-size: .75rem;
color: var(--bs-secondary-color, #9aa0a6);
}
.skoda-kartenlegende span { display: inline-flex; align-items: center; gap: .3rem; }
.skoda-kartenlegende .pkt { width: .55rem; height: .55rem; border-radius: 50%; }
.skoda-kartenlegende .pkt.jetzt { background: #4caf7d; }
.skoda-kartenlegende .pkt.halt { background: #8a949c; }
.skoda-kartenlegende .lin {
width: 1.1rem;
border-top: 2px dashed #8a949c;
}
/* --- Befund -------------------------------------------------------------- */
.skoda-befund .zahl {
font-size: 2.4rem;
font-weight: 600;
line-height: 1.1;
font-variant-numeric: tabular-nums;
}
.skoda-befund .zahl .einheit {
font-size: .95rem;
font-weight: 400;
color: var(--bs-secondary-color, #9aa0a6);
margin-left: .35rem;
}
.skoda-befund dl { margin: 1rem 0 0; display: grid; gap: .5rem; }
.skoda-befund dl > div { display: flex; justify-content: space-between; gap: 1rem; }
.skoda-befund dt {
font-weight: 400;
color: var(--bs-secondary-color, #9aa0a6);
font-size: .85rem;
}
.skoda-befund dd { margin: 0; font-variant-numeric: tabular-nums; font-size: .9rem; }
/* --- Steuerung ----------------------------------------------------------
Die Befehle sitzen im Modal, das ueber die anklickbaren Stellen im
Fahrzeugbild aufgeht. */
.skoda-steuerung .knoepfe { display: flex; flex-wrap: wrap; gap: .5rem; }
.skoda-steuerung .knoepfe button { flex: 1 1 11rem; }
.skoda-steuerung .temperatur {
display: flex;
align-items: center;
justify-content: space-between;
gap: .75rem;
font-size: .9rem;
}
.skoda-steuerung .temperatur span { display: flex; align-items: center; gap: .35rem; }
.skoda-steuerung .temperatur input { width: 5.5rem; }
@media (pointer: coarse) {
.skoda-steuerung .knoepfe button { padding: .7rem 1rem; }
}
.skoda-rueckmeldung {
font-size: .9rem;
padding: .5rem .75rem;
border-radius: .35rem;
display: none;
}
.skoda-rueckmeldung.warte,
.skoda-rueckmeldung.gut,
.skoda-rueckmeldung.schlecht { display: block; }
.skoda-rueckmeldung.warte { background: rgba(128, 138, 148, .16); color: var(--bs-secondary-color, #9aa0a6); }
.skoda-rueckmeldung.gut { background: rgba(76, 175, 125, .16); color: #6fd3a0; }
.skoda-rueckmeldung.schlecht { background: rgba(224, 96, 96, .16); color: #f08a8a; }
/* --- Anklickbare Stellen im Fahrzeugbild --------------------------------
Der Ring unterscheidet Bedienung von Anzeige: die uebrigen Teile zeigen
nur ihren Zustand, diese beiden aendern etwas. */
.skoda-auto .steuer { cursor: pointer; }
.skoda-auto .steuer .ring {
fill: none;
stroke: var(--bs-primary, #4b8fd6);
stroke-width: 1.5;
stroke-dasharray: 3 3;
opacity: .55;
transition: opacity .2s, stroke-width .2s;
}
.skoda-auto .steuer .flaeche {
fill: rgba(75, 143, 214, .22);
stroke: var(--bs-primary, #4b8fd6);
stroke-width: 1.5;
}
.skoda-auto .steuer .glyphe {
fill: none;
stroke: var(--bs-primary, #4b8fd6);
stroke-width: 1.8;
stroke-linecap: round;
}
@media (hover: hover) {
.skoda-auto .steuer:hover .ring { opacity: 1; stroke-width: 2.5; }
}
.skoda-auto .steuer:focus { outline: none; }
.skoda-auto .steuer:focus-visible .ring { opacity: 1; stroke-width: 3; }
.skoda-hinweis {
margin: .6rem 0 0;
font-size: .75rem;
color: var(--bs-secondary-color, #9aa0a6);
text-align: center;
}
.skoda-alter { font-size: .85rem; }