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>
909 lines
29 KiB
CSS
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; }
|