.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; } /* === Protokollseite ====================================================== Ein Log liest sich nur in einer Schrift mit fester Breite: die Zeitstempel stehen dann untereinander, und das Auge findet die Stelle, an der etwas anders wird. Die Zeilen umbrechen statt seitlich zu scrollen - ein Traceback ist lang, und waagerecht zu blaettern verliert man sofort. */ .log-ausgabe { max-height: calc(100vh - 22rem); min-height: 20rem; overflow-y: auto; font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: .78rem; line-height: 1.45; background: var(--bs-body-bg, #1b1e21); border: 1px solid var(--bs-border-color, #2c3034); border-radius: .375rem; } .log-ausgabe .log-zeile { display: flex; gap: .6rem; padding: .1rem .6rem; border-left: 3px solid transparent; white-space: pre-wrap; word-break: break-word; } .log-ausgabe .log-zeile:hover { background: rgba(255, 255, 255, .04); } .log-ausgabe .log-zeit { flex: 0 0 5rem; color: var(--bs-secondary-color, #8b9198); } .log-ausgabe .log-level { flex: 0 0 4.5rem; font-weight: 600; } .log-ausgabe .log-text { flex: 1 1 auto; } /* Fortsetzungszeilen - die zweite bis letzte Zeile eines Tracebacks - tragen kein eigenes Level. Sie bleiben in der Farbe ihrer Kopfzeile, ruecken aber ein: so sieht man auf einen Blick, was zusammengehoert. */ .log-ausgabe .log-fortsetzung .log-text { padding-left: 1.2rem; opacity: .85; } .log-ausgabe .log-debug { color: var(--bs-secondary-color, #8b9198); } .log-ausgabe .log-info .log-level { color: #6ea8dc; } .log-ausgabe .log-warning { border-left-color: #d9a441; background: rgba(217, 164, 65, .07); } .log-ausgabe .log-warning .log-level { color: #d9a441; } .log-ausgabe .log-error { border-left-color: #e06060; background: rgba(224, 96, 96, .09); } .log-ausgabe .log-error .log-level { color: #f08a8a; } /* Tagestrenner: das Datum steht einmal da, nicht in jeder Zeile. */ .log-ausgabe .log-tag { position: sticky; top: 0; padding: .15rem .6rem; font-size: .72rem; letter-spacing: .04em; color: var(--bs-secondary-color, #8b9198); background: var(--bs-tertiary-bg, #23272b); border-top: 1px solid var(--bs-border-color, #2c3034); border-bottom: 1px solid var(--bs-border-color, #2c3034); } /* Die Dateiliste links: der aktive Eintrag wird von AdminLTE eingefaerbt, die Zustandszeile darunter soll trotzdem lesbar bleiben. */ .log-liste .log-wahl.active .text-secondary, .log-liste .log-wahl.active .text-warning { color: rgba(255, 255, 255, .75) !important; } /* Etagenschalter im Grundriss der Home-Ansicht. Vorher waren sie ein duenner Ring in einem Amber (#aa7713), das sonst nirgends im Dashboard vorkommt - und alle vier sahen immer gleich aus, die aktive Etage war an ihnen nicht zu erkennen. Jetzt tragen sie dieselbe Scheibe wie die Kacheln im Grundriss, und die aktive Etage bekommt die Akzentfarbe der Schieberegler. */ .floorBtn { cursor: pointer; } .floorBtn circle { fill: #0006; stroke: #9aa0a6; stroke-width: 4; opacity: .55; transition: stroke .25s ease, opacity .25s ease; } .floorBtn text { font: 600 34px Poppins, system-ui, sans-serif; fill: #9aa0a6; opacity: .8; transition: fill .25s ease, opacity .25s ease; /* Der Kreis faengt den Klick, nicht die Beschriftung - sonst wandert der Textcursor ueber die Schrift, sobald man sie streift. */ user-select: none; pointer-events: none; } .floorBtn:hover circle { opacity: .8; } .floorBtn:hover text { opacity: 1; } .floorBtn.active circle { stroke: #00788F; opacity: 1; } .floorBtn.active text { fill: #e8ede9; opacity: 1; }