Troege als Pflanzkuebel (statt Einkaufskorb), Vorn als Baum im Gras, Beete als Hochbeet - gezeichnet im Stil der uebrigen Symbole (ZONENBILDER in energiefluss.js). Eine Zone kann weiter ein Bootstrap-Icon nutzen (zeichen statt bild). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
4068 lines
158 KiB
CSS
4068 lines
158 KiB
CSS
/* ==========================================================================
|
|
Grundton der Oberflaeche
|
|
|
|
Die Seite laeuft auf AdminLTE, also auf Bootstrap. Beide beziehen ihre
|
|
Farben aus Variablen - deshalb wird hier nicht Regel fuer Regel
|
|
ueberschrieben, sondern die Palette ausgetauscht: ein paar Variablen am
|
|
Wurzelelement, und Karten, Tabellen, Abzeichen und Knoepfe folgen von
|
|
selbst. Was danach noch kommt, sind wenige gezielte Regeln fuer die Dinge,
|
|
die Bootstrap fest verdrahtet hat (Kartenrahmen, Kopfzeilen, Trennlinien).
|
|
|
|
Die Palette selbst ist die des Jahresvergleichs: ein leicht blaustichiges
|
|
Anthrazit als Grund, eine Spur hellere Flaeche fuer Karten, Haarlinien statt
|
|
Rahmen - und Bernstein als einzige Akzentfarbe, weil das auf dieser Seite
|
|
die Farbe der eigenen Anlage ist. Gruen, Rot und Gelb bleiben den
|
|
Zustaenden vorbehalten und sind kein Schmuck.
|
|
========================================================================== */
|
|
|
|
:root,
|
|
[data-bs-theme="dark"] {
|
|
--ton-grund: #191d20; /* Seitenhintergrund */
|
|
--ton-flaeche: #23282c; /* Karten */
|
|
--ton-flaeche-2: #2b3237; /* Kopfzeilen, Tabellenkopf */
|
|
--ton-linie: rgba(138, 148, 158, .20);
|
|
--ton-linie-satt: rgba(138, 148, 158, .38);
|
|
--ton-schrift: #e8ede9;
|
|
--ton-schrift-2: #9aa6ad;
|
|
--ton-schrift-3: #6f7a81;
|
|
--ton-sonne: #f0b429; /* die eigene Anlage */
|
|
--ton-sonne-rgb: 240, 180, 41;
|
|
--ton-gut: #4caf7d;
|
|
--ton-schlecht: #e06060;
|
|
|
|
/* Zwei Radien statt einem. Der grosse gilt fuer Flaechen (Karten, Modale,
|
|
Eingabefelder), der kleine fuer alles, was in einer Reihe steht -
|
|
Schalter, kleine Knoepfe, Abzeichen. Bootstrap kennt beide, benutzte
|
|
bisher aber nur den grossen; der kleine stand auf seiner Vorgabe von
|
|
.25rem und wirkte daneben eckig. */
|
|
--ton-radius: .875rem;
|
|
--ton-radius-klein: .5rem;
|
|
|
|
/* Die Anzeigeschrift. Poppins liegt seit jeher unter assets/fonts und trug
|
|
bisher nur die Etagenknoepfe im Aussenplan - eine ganze Schrift fuer vier
|
|
Buchstaben. Als Variable traegt sie jetzt alle Ueberschriften: waermer
|
|
und eine Spur weniger technisch als die Source Sans 3 des Fliesstextes,
|
|
ohne dass eine zweite Datei geladen wird. Zahlenkolonnen und Fliesstext
|
|
bleiben unberuehrt - Poppins hat keine Tabellenziffern. */
|
|
--font-anzeige: Poppins, system-ui, -apple-system, "Segoe UI", sans-serif;
|
|
|
|
/* ... und dieselben Werte dort, wo Bootstrap sie sucht. */
|
|
--bs-body-bg: var(--ton-grund);
|
|
--bs-body-bg-rgb: 25, 29, 32;
|
|
--bs-body-color: var(--ton-schrift);
|
|
--bs-body-color-rgb: 232, 237, 233;
|
|
--bs-emphasis-color: #fff;
|
|
--bs-secondary-color: var(--ton-schrift-2);
|
|
--bs-secondary-bg: var(--ton-flaeche-2);
|
|
--bs-tertiary-color: var(--ton-schrift-3);
|
|
--bs-tertiary-bg: var(--ton-flaeche-2);
|
|
--bs-border-color: var(--ton-linie-satt);
|
|
--bs-border-radius: var(--ton-radius);
|
|
--bs-border-radius-sm: var(--ton-radius-klein);
|
|
--bs-link-color: var(--ton-sonne);
|
|
--bs-link-hover-color: #ffc94d;
|
|
--bs-heading-color: var(--ton-schrift);
|
|
}
|
|
|
|
/* Ueberschriften in der Anzeigeschrift. Bewusst nur Ueberschriften: der
|
|
Fliesstext und alle Zahlenkolonnen bleiben bei der Schrift des Themes,
|
|
weil Poppins keine Tabellenziffern mitbringt und Messwerte sonst
|
|
springen wuerden. */
|
|
h1, h2, h3, h4, h5, h6,
|
|
.h1, .h2, .h3, .h4, .h5, .h6,
|
|
.card-title,
|
|
.modal-title {
|
|
font-family: var(--font-anzeige);
|
|
font-weight: 600;
|
|
letter-spacing: -.01em;
|
|
}
|
|
|
|
/* Der Rumpf traegt zwei Grundfarben: die Seite und die Leisten drumherum.
|
|
AdminLTE setzt sie ueber eigene Klassen, die hier auf denselben Ton
|
|
gebracht werden - sonst steht eine Karte auf drei verschiedenen Grautoenen. */
|
|
body.bg-body-tertiary,
|
|
.app-content,
|
|
.app-content-header { background: var(--ton-grund); }
|
|
|
|
.app-header.bg-body,
|
|
.app-sidebar.bg-body-secondary {
|
|
background: var(--ton-flaeche) !important;
|
|
border-color: var(--ton-linie) !important;
|
|
}
|
|
.app-header { box-shadow: 0 1px 0 var(--ton-linie); }
|
|
|
|
/* --- Karten --------------------------------------------------------------
|
|
Eine Karte ist eine Flaeche, kein Kasten: ein Ton heller als der Grund, eine
|
|
Haarlinie als Rand, kein Schlagschatten. Der Schatten trennte frueher, was
|
|
der Farbunterschied jetzt allein leistet. */
|
|
.card {
|
|
background: var(--ton-flaeche);
|
|
border: 1px solid var(--ton-linie);
|
|
border-radius: var(--ton-radius);
|
|
box-shadow: none;
|
|
}
|
|
.card-header {
|
|
background: transparent;
|
|
border-bottom: 1px solid var(--ton-linie);
|
|
padding-inline: 1rem;
|
|
}
|
|
.card-title {
|
|
font-size: 1rem;
|
|
font-weight: 500;
|
|
letter-spacing: -.01em;
|
|
}
|
|
.card-body { padding: 1rem; }
|
|
.card-footer {
|
|
background: transparent;
|
|
border-top: 1px solid var(--ton-linie);
|
|
}
|
|
|
|
/* Werkzeugknoepfe in der Kopfzeile: ruhig, bis man sie braucht. */
|
|
.btn-tool {
|
|
color: var(--ton-schrift-3);
|
|
transition: color .18s, background .18s;
|
|
border-radius: .35rem;
|
|
}
|
|
.btn-tool:hover,
|
|
.btn-tool:focus-visible { color: var(--ton-schrift); background: rgba(138, 148, 158, .12); }
|
|
|
|
/* --- Menue ---------------------------------------------------------------
|
|
Der aktive Punkt traegt die Akzentfarbe, nicht das Blau des Themes -
|
|
sonst haette die Seite zwei Hauptfarben. */
|
|
.sidebar-menu .nav-link {
|
|
border-radius: .45rem;
|
|
color: var(--ton-schrift-2);
|
|
}
|
|
.sidebar-menu .nav-link:hover { background: rgba(138, 148, 158, .1); color: var(--ton-schrift); }
|
|
.sidebar-menu .nav-link.active,
|
|
.sidebar-menu .nav-link.active:hover {
|
|
background: rgba(var(--ton-sonne-rgb), .16);
|
|
color: var(--ton-sonne);
|
|
}
|
|
.sidebar-brand { border-bottom: 1px solid var(--ton-linie); }
|
|
.brand-text { font-weight: 400; letter-spacing: .01em; }
|
|
|
|
/* --- Schrift -------------------------------------------------------------
|
|
Zahlen stehen ueberall in Spalten untereinander - mit Ziffern gleicher
|
|
Breite bleiben sie ausgerichtet, auch wenn sich der Wert aendert. */
|
|
.card-body,
|
|
.table,
|
|
.info-box-number,
|
|
.progress-bar { font-variant-numeric: tabular-nums; }
|
|
|
|
.app-content-header h3 {
|
|
font-weight: 500;
|
|
letter-spacing: -.01em;
|
|
}
|
|
|
|
/* --- Tabellen ------------------------------------------------------------ */
|
|
.table {
|
|
--bs-table-bg: transparent;
|
|
--bs-table-color: var(--ton-schrift);
|
|
--bs-table-border-color: var(--ton-linie);
|
|
--bs-table-hover-bg: rgba(138, 148, 158, .06);
|
|
--bs-table-striped-bg: rgba(138, 148, 158, .04);
|
|
}
|
|
.table > thead {
|
|
color: var(--ton-schrift-2);
|
|
font-size: .82rem;
|
|
font-weight: 500;
|
|
}
|
|
|
|
/* --- Abzeichen -----------------------------------------------------------
|
|
Gedaempft statt grell: ein Abzeichen soll den Zustand sagen, nicht die
|
|
Kachel dominieren. */
|
|
.badge { font-weight: 500; letter-spacing: .01em; }
|
|
.badge.text-bg-secondary {
|
|
background: rgba(138, 148, 158, .18) !important;
|
|
color: var(--ton-schrift-2) !important;
|
|
}
|
|
.badge.text-bg-success {
|
|
background: rgba(76, 175, 125, .18) !important;
|
|
color: var(--ton-gut) !important;
|
|
}
|
|
.badge.text-bg-warning {
|
|
background: rgba(240, 180, 41, .18) !important;
|
|
color: var(--ton-sonne) !important;
|
|
}
|
|
.badge.text-bg-danger {
|
|
background: rgba(224, 96, 96, .18) !important;
|
|
color: var(--ton-schlecht) !important;
|
|
}
|
|
.badge.text-bg-info {
|
|
background: rgba(122, 167, 199, .18) !important;
|
|
color: #9cc4de !important;
|
|
}
|
|
|
|
/* --- Formulare ----------------------------------------------------------- */
|
|
.form-control,
|
|
.form-select {
|
|
background: rgba(0, 0, 0, .18);
|
|
border-color: var(--ton-linie-satt);
|
|
color: var(--ton-schrift);
|
|
}
|
|
.form-control:focus,
|
|
.form-select:focus {
|
|
background: rgba(0, 0, 0, .18);
|
|
border-color: var(--ton-sonne);
|
|
box-shadow: 0 0 0 .2rem rgba(var(--ton-sonne-rgb), .2);
|
|
color: var(--ton-schrift);
|
|
}
|
|
.form-check-input:checked { background-color: var(--ton-sonne); border-color: var(--ton-sonne); }
|
|
.form-check-input:focus { box-shadow: 0 0 0 .2rem rgba(var(--ton-sonne-rgb), .2); }
|
|
|
|
/* Sichtbarer Tastaturfokus, einheitlich - AdminLTE setzt ihn stellenweise ab. */
|
|
a:focus-visible,
|
|
button:focus-visible,
|
|
[tabindex]:focus-visible {
|
|
outline: 2px solid var(--ton-sonne);
|
|
outline-offset: 2px;
|
|
}
|
|
|
|
/* --- Trennlinien und Modals ---------------------------------------------- */
|
|
hr { border-color: var(--ton-linie); opacity: 1; }
|
|
.modal-content {
|
|
background: var(--ton-flaeche);
|
|
border: 1px solid var(--ton-linie-satt);
|
|
border-radius: var(--ton-radius);
|
|
}
|
|
.modal-header,
|
|
.modal-footer { border-color: var(--ton-linie); }
|
|
|
|
|
|
/* ==========================================================================
|
|
Jahresstatistik (js/solar/jahresstatistik.js)
|
|
|
|
Die Tabelle traegt die Seite "Vergangenheit" und steht in kleiner Form auch
|
|
auf der Solarseite. Sie ist zum Lesen einer Zeile gebaut: Kennzahlen links,
|
|
Jahre nebeneinander, die Veraenderung als Zahl - nicht als blosser Pfeil.
|
|
========================================================================== */
|
|
|
|
/* Der Baustein setzt seine Bloecke selbst auf Abstand - und zwar auf denselben
|
|
wie den zwischen den Leitzahlen und den Innenabstand der Karte. Alle Nahtstellen
|
|
sind dadurch gleich weit, gleich ob die Werkzeugleiste dabei ist oder nicht. */
|
|
.jahresstatistik {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: var(--stat-abstand, 1.25rem);
|
|
}
|
|
|
|
/* Der Innenabstand der Karte gehoert zum selben Mass - sonst sitzt die erste
|
|
Kachel enger unter der Ueberschrift als die zweite unter der ersten.
|
|
|
|
Der Vorsatz .app-content ist noetig, nicht schmueckend: weiter unten in
|
|
dieser Datei setzt .app-content .card-body auf dem Handy einen kleineren
|
|
Innenabstand, und bei gleicher Spezifitaet gewaenne die spaetere Regel. */
|
|
.app-content .card-body.statistik { padding: var(--stat-abstand, 1.25rem); }
|
|
|
|
/* Auf dem Handy ruecken alle Nahtstellen zusammen - aber gemeinsam, sonst
|
|
waere die Gleichheit wieder dahin. */
|
|
@media (max-width: 767.98px) {
|
|
.jahresstatistik,
|
|
.app-content .card-body.statistik { --stat-abstand: 1rem; }
|
|
}
|
|
|
|
/* --- Leitzahlen ---------------------------------------------------------- */
|
|
.jahresstatistik .leitzahlen {
|
|
display: grid;
|
|
grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
|
|
gap: var(--stat-abstand, 1.25rem);
|
|
}
|
|
.jahresstatistik .leitzahl {
|
|
background: rgba(138, 148, 158, .07);
|
|
border: 1px solid var(--ton-linie);
|
|
border-radius: var(--ton-radius);
|
|
padding: .9rem 1.05rem 1rem;
|
|
}
|
|
.jahresstatistik .leitzahl .name { font-size: .78rem; color: var(--ton-schrift-2); }
|
|
.jahresstatistik .leitzahl .zahl {
|
|
display: flex;
|
|
align-items: baseline;
|
|
gap: .35rem;
|
|
margin-top: .3rem;
|
|
font-size: 1.9rem;
|
|
font-weight: 500;
|
|
line-height: 1.1;
|
|
font-variant-numeric: tabular-nums;
|
|
}
|
|
.jahresstatistik .leitzahl .einheit {
|
|
font-size: .95rem;
|
|
font-weight: 400;
|
|
color: var(--ton-schrift-2);
|
|
}
|
|
.jahresstatistik .leitzahl .fuss {
|
|
margin-top: .45rem;
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
align-items: center;
|
|
gap: .5rem;
|
|
font-size: .76rem;
|
|
color: var(--ton-schrift-3);
|
|
}
|
|
.jahresstatistik .leitzahl.betont { border-color: rgba(var(--ton-sonne-rgb), .45); }
|
|
.jahresstatistik .leitzahl.betont .zahl { color: var(--ton-sonne); }
|
|
|
|
/* Die Veraenderung: Richtung und Groesse, nicht nur Richtung. */
|
|
.jahresstatistik .delta {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: .25rem;
|
|
font-size: .78rem;
|
|
font-variant-numeric: tabular-nums;
|
|
white-space: nowrap;
|
|
}
|
|
.jahresstatistik .delta.gut { color: var(--ton-gut); }
|
|
.jahresstatistik .delta.schlecht { color: var(--ton-schlecht); }
|
|
.jahresstatistik .delta.gleich { color: var(--ton-schrift-3); }
|
|
|
|
/* --- Werkzeugleiste ------------------------------------------------------ */
|
|
.jahresstatistik .werkzeuge {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
align-items: center;
|
|
gap: .75rem 1.25rem;
|
|
}
|
|
.jahresstatistik .umschalter {
|
|
display: inline-flex;
|
|
border: 1px solid var(--ton-linie-satt);
|
|
border-radius: .45rem;
|
|
overflow: hidden;
|
|
}
|
|
.jahresstatistik .umschalter button {
|
|
appearance: none;
|
|
border: 0;
|
|
background: none;
|
|
color: var(--ton-schrift-2);
|
|
font: inherit;
|
|
font-size: .82rem;
|
|
padding: .4rem .9rem;
|
|
cursor: pointer;
|
|
transition: background .18s, color .18s;
|
|
}
|
|
.jahresstatistik .umschalter button + button { border-left: 1px solid var(--ton-linie-satt); }
|
|
.jahresstatistik .umschalter button:hover { background: rgba(138, 148, 158, .1); }
|
|
.jahresstatistik .umschalter button[aria-pressed="true"] {
|
|
background: rgba(var(--ton-sonne-rgb), .16);
|
|
color: var(--ton-sonne);
|
|
}
|
|
|
|
/* Das Jahrfenster: zwei Pfeile und dazwischen, was gerade zu sehen ist. */
|
|
.jahresstatistik .jahrwahl {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: .35rem;
|
|
font-size: .82rem;
|
|
color: var(--ton-schrift-2);
|
|
}
|
|
.jahresstatistik .jahrwahl button {
|
|
appearance: none;
|
|
border: 1px solid var(--ton-linie-satt);
|
|
background: none;
|
|
color: var(--ton-schrift-2);
|
|
border-radius: .35rem;
|
|
width: 1.9rem;
|
|
height: 1.9rem;
|
|
line-height: 1;
|
|
cursor: pointer;
|
|
transition: background .18s, color .18s, opacity .18s;
|
|
}
|
|
.jahresstatistik .jahrwahl button:hover:not(:disabled) {
|
|
background: rgba(138, 148, 158, .12);
|
|
color: var(--ton-schrift);
|
|
}
|
|
.jahresstatistik .jahrwahl button:disabled { opacity: .3; cursor: default; }
|
|
.jahresstatistik .jahrwahl .fenster { font-variant-numeric: tabular-nums; min-width: 5.5rem; text-align: center; }
|
|
|
|
.jahresstatistik .kasten {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: .45rem;
|
|
font-size: .82rem;
|
|
color: var(--ton-schrift-2);
|
|
cursor: pointer;
|
|
user-select: none;
|
|
}
|
|
.jahresstatistik .kasten input { accent-color: var(--ton-sonne); width: 1rem; height: 1rem; }
|
|
|
|
/* --- Die Tabelle --------------------------------------------------------- */
|
|
.jahresstatistik .tafel-scroll {
|
|
overflow-x: auto;
|
|
border: 1px solid var(--ton-linie);
|
|
border-radius: var(--ton-radius);
|
|
}
|
|
.jahresstatistik .tafel {
|
|
width: 100%;
|
|
border-collapse: collapse;
|
|
font-size: .88rem;
|
|
margin: 0;
|
|
}
|
|
.jahresstatistik .tafel thead th {
|
|
background: var(--ton-flaeche-2);
|
|
text-align: right;
|
|
font-weight: 500;
|
|
font-size: .78rem;
|
|
padding: .55rem .9rem .5rem;
|
|
border-bottom: 1px solid var(--ton-linie-satt);
|
|
white-space: nowrap;
|
|
}
|
|
.jahresstatistik .tafel thead th:first-child { text-align: left; }
|
|
.jahresstatistik .tafel thead th.jetzt { color: var(--ton-sonne); }
|
|
.jahresstatistik .tafel thead .zeitraum {
|
|
display: block;
|
|
font-weight: 400;
|
|
font-size: .68rem;
|
|
color: var(--ton-schrift-3);
|
|
letter-spacing: .03em;
|
|
}
|
|
|
|
.jahresstatistik .tafel tbody td {
|
|
padding: .4rem .9rem;
|
|
border-bottom: 1px solid var(--ton-linie);
|
|
text-align: right;
|
|
font-variant-numeric: tabular-nums;
|
|
white-space: nowrap;
|
|
}
|
|
.jahresstatistik .tafel tbody td.name {
|
|
text-align: left;
|
|
width: 40%;
|
|
min-width: 14rem;
|
|
white-space: normal;
|
|
}
|
|
.jahresstatistik .tafel tbody tr:last-child td { border-bottom: 0; }
|
|
@media (hover: hover) {
|
|
.jahresstatistik .tafel tbody tr:hover td { background: rgba(138, 148, 158, .06); }
|
|
.jahresstatistik .tafel tbody tr.gruppe:hover td { background: none; }
|
|
}
|
|
|
|
/* Gruppenkopf: kein Kasten, nur eine Zaesur. */
|
|
.jahresstatistik .tafel tr.gruppe td {
|
|
padding: 1rem .9rem .25rem;
|
|
border-bottom: 1px solid var(--ton-linie-satt);
|
|
font-size: .7rem;
|
|
letter-spacing: .13em;
|
|
text-transform: uppercase;
|
|
color: var(--ton-schrift-3);
|
|
text-align: left;
|
|
}
|
|
|
|
/* Die Summenzeile traegt das Gewicht, die Teile darunter nicht. */
|
|
.jahresstatistik .tafel tr.summe td { font-size: .95rem; }
|
|
.jahresstatistik .tafel tr.summe td.name { font-weight: 500; }
|
|
.jahresstatistik .tafel tr.summe .wert-jetzt { color: var(--ton-sonne); }
|
|
|
|
/* Einrueckung: "davon" teilt die Summe auf, "darin" greift etwas heraus, das
|
|
schon in einer Zeile darueber steckt. */
|
|
.jahresstatistik .tafel td.name .stufe-1 {
|
|
padding-left: 1.4rem;
|
|
position: relative;
|
|
display: inline-block;
|
|
}
|
|
.jahresstatistik .tafel td.name .stufe-1::before {
|
|
content: "";
|
|
position: absolute;
|
|
left: .45rem;
|
|
top: .75em;
|
|
width: .55rem;
|
|
border-top: 1px solid var(--ton-linie-satt);
|
|
}
|
|
.jahresstatistik .tafel tr.teilmenge td { color: var(--ton-schrift-2); font-size: .82rem; }
|
|
|
|
/* Zweite Stufe. Der Strich sitzt tiefer eingerueckt als der der ersten und
|
|
zeigt damit, an welcher Zeile die Teilmenge haengt. */
|
|
.jahresstatistik .tafel td.name .stufe-2 {
|
|
padding-left: 2.8rem;
|
|
position: relative;
|
|
display: inline-block;
|
|
}
|
|
.jahresstatistik .tafel td.name .stufe-2::before {
|
|
content: "";
|
|
position: absolute;
|
|
left: 1.85rem;
|
|
top: .75em;
|
|
width: .55rem;
|
|
border-top: 1px dashed var(--ton-linie-satt);
|
|
}
|
|
.jahresstatistik .tafel .darin {
|
|
font-size: .68rem;
|
|
letter-spacing: .06em;
|
|
text-transform: uppercase;
|
|
color: var(--ton-schrift-3);
|
|
margin-right: .4rem;
|
|
}
|
|
.jahresstatistik .tafel .einheit-klein {
|
|
font-size: .7rem;
|
|
color: var(--ton-schrift-3);
|
|
margin-left: .4rem;
|
|
}
|
|
|
|
.jahresstatistik .tafel .wert-alt { color: var(--ton-schrift-2); }
|
|
.jahresstatistik .tafel .leer { color: var(--ton-schrift-3); text-align: left; }
|
|
|
|
/* Die Gesamtspalte ist eine andere Art Zahl als ein Jahreswert - sie steht
|
|
deshalb abgesetzt und ruhiger. */
|
|
.jahresstatistik .tafel .gesamt {
|
|
border-left: 1px solid var(--ton-linie-satt);
|
|
color: var(--ton-schrift-2);
|
|
}
|
|
.jahresstatistik .tafel thead th.gesamt { color: var(--ton-schrift-2); }
|
|
|
|
/* Aufklappbare Teilzeilen */
|
|
.jahresstatistik .tafel button.klapp {
|
|
appearance: none;
|
|
background: none;
|
|
border: 0;
|
|
color: inherit;
|
|
font: inherit;
|
|
padding: 0;
|
|
cursor: pointer;
|
|
display: inline-flex;
|
|
flex-wrap: wrap;
|
|
align-items: center;
|
|
gap: .2rem .4rem;
|
|
text-align: left;
|
|
}
|
|
.jahresstatistik .tafel button.klapp .pfeil {
|
|
display: inline-block;
|
|
width: .55rem;
|
|
color: var(--ton-schrift-3);
|
|
transition: transform .18s;
|
|
}
|
|
.jahresstatistik .tafel button.klapp[aria-expanded="true"] .pfeil { transform: rotate(90deg); }
|
|
|
|
/* Was hinter einer zugeklappten Zeile steckt - sonst waere das Zugeklappte
|
|
nicht nur zusammengefasst, sondern verschwunden. */
|
|
.jahresstatistik .tafel .posten {
|
|
margin-left: .55rem;
|
|
padding: .05rem .45rem;
|
|
border: 1px solid var(--ton-linie-satt);
|
|
border-radius: 1rem;
|
|
font-size: .68rem;
|
|
font-weight: 400;
|
|
letter-spacing: .03em;
|
|
color: var(--ton-schrift-3);
|
|
white-space: nowrap;
|
|
}
|
|
@media (hover: hover) {
|
|
.jahresstatistik .tafel button.klapp:hover .posten {
|
|
border-color: var(--ton-sonne);
|
|
color: var(--ton-sonne);
|
|
}
|
|
}
|
|
.jahresstatistik .tafel tr.versteckt { display: none; }
|
|
|
|
/* --- Monatsverlauf ------------------------------------------------------- */
|
|
.jahresstatistik .tafel th.verlauf,
|
|
.jahresstatistik .tafel td.verlauf { width: 7.5rem; }
|
|
.jahresstatistik .spark {
|
|
display: block;
|
|
/* Waagerecht faehrt der Finger die Monate ab, senkrecht scrollt die Seite
|
|
weiter - ohne diese Angabe verschluckt der Browser das Wischen. */
|
|
touch-action: pan-y;
|
|
}
|
|
.jahresstatistik .spark rect.balken { fill: var(--ton-linie-satt); transition: fill .15s; }
|
|
.jahresstatistik .spark rect.balken.jetzt { fill: var(--ton-sonne); }
|
|
.jahresstatistik .spark rect.balken.aktiv { fill: var(--ton-sonne); }
|
|
.jahresstatistik .spark line.basis { stroke: var(--ton-linie); stroke-width: 1; }
|
|
|
|
/* Die ganze Zelle nimmt die Beruehrung an, nicht nur die Balken darin -
|
|
ein SVG-Wurzelelement laesst sich nicht mit Innenabstand vergroessern. */
|
|
.jahresstatistik .tafel td.verlauf { touch-action: pan-y; cursor: crosshair; }
|
|
|
|
.spark-tipp {
|
|
position: fixed;
|
|
z-index: 1080;
|
|
pointer-events: none;
|
|
background: #12161a;
|
|
border: 1px solid var(--ton-linie-satt);
|
|
border-radius: .35rem;
|
|
padding: .3rem .55rem;
|
|
font-size: .75rem;
|
|
font-variant-numeric: tabular-nums;
|
|
box-shadow: 0 .4rem 1.2rem rgba(0, 0, 0, .5);
|
|
opacity: 0;
|
|
transition: opacity .12s;
|
|
}
|
|
.spark-tipp.an { opacity: 1; }
|
|
|
|
/* --- Fussnoten ----------------------------------------------------------- */
|
|
.jahresstatistik .fussnoten {
|
|
display: grid;
|
|
gap: .5rem;
|
|
font-size: .78rem;
|
|
color: var(--ton-schrift-2);
|
|
max-width: 68ch;
|
|
}
|
|
.jahresstatistik .fussnoten p { margin: 0; }
|
|
.jahresstatistik .fussnoten b { color: var(--ton-schrift); font-weight: 500; }
|
|
|
|
@media (max-width: 575.98px) {
|
|
.jahresstatistik .tafel tbody td.name { min-width: 11rem; }
|
|
.jahresstatistik .werkzeuge { gap: .6rem .9rem; }
|
|
}
|
|
|
|
@media (prefers-reduced-motion: reduce) {
|
|
.jahresstatistik .umschalter button,
|
|
.jahresstatistik .jahrwahl button,
|
|
.jahresstatistik .spark rect.balken,
|
|
.jahresstatistik .tafel button.klapp .pfeil,
|
|
.spark-tipp { transition: none; }
|
|
}
|
|
|
|
|
|
.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;
|
|
}
|
|
}
|
|
|
|
/* 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) gelten weiter. */
|
|
.app-content .card-body {
|
|
padding: .5rem;
|
|
}
|
|
|
|
/* Die Jahrestabelle scrollt auf dem Handy seitwaerts; damit moeglichst
|
|
viel davon ohne Schieben zu sehen ist, ruecken die Spalten enger
|
|
zusammen. */
|
|
.jahresstatistik .tafel tbody td,
|
|
.jahresstatistik .tafel thead th {
|
|
padding-inline: .55rem;
|
|
}
|
|
}
|
|
|
|
/* --------------------------------------------------------------------------
|
|
Drei Klassen, die der Automatik-Editor gebraucht hat - hier, nicht dort
|
|
|
|
Sie stehen absichtlich in der gemeinsamen Datei und nicht als Sonderfall
|
|
im Editor. Zwei davon sind allgemein genug, um anderswo zu taugen; die
|
|
dritte ist eine echte Ausnahme und als einzelne Klasse auch als solche
|
|
erkennbar.
|
|
-------------------------------------------------------------------------- */
|
|
|
|
/* Ein Auswahlfeld, das wie Text aussieht, bis man es anfaehrt.
|
|
|
|
Eine Bedingung hat sechs Bestandteile, aber nur zwei davon traegt man
|
|
wirklich ein: Vergleich und Wert. Standen alle sechs als gleich schwere
|
|
Kaesten nebeneinander, sagte nichts mehr, worauf es ankommt. Die
|
|
gepunktete Linie sagt "anklickbar", ohne den Platz und das Gewicht eines
|
|
Eingabefelds zu nehmen.
|
|
|
|
Bewusst allgemein: dieselbe Not haben das Raum-Modal und die
|
|
Kachel-Einstellungen, wo ebenfalls jede Kleinigkeit in einem Kasten
|
|
steht. Taugt fuer <select> wie fuer <button>. */
|
|
.feld-als-text {
|
|
appearance: none;
|
|
-webkit-appearance: none;
|
|
max-width: 100%;
|
|
padding: 0 0 1px;
|
|
border: 0;
|
|
border-bottom: 1px dashed var(--ton-linie-satt);
|
|
border-radius: 0;
|
|
background: none;
|
|
color: inherit;
|
|
font: inherit;
|
|
text-align: left;
|
|
text-overflow: ellipsis;
|
|
white-space: nowrap;
|
|
overflow: hidden;
|
|
cursor: pointer;
|
|
}
|
|
|
|
.feld-als-text:hover,
|
|
.feld-als-text:focus-visible {
|
|
border-bottom-color: var(--bs-link-color);
|
|
color: var(--bs-emphasis-color);
|
|
outline: 0;
|
|
}
|
|
|
|
/* Ein Messwert, wie er in diesem Moment dasteht.
|
|
|
|
Steht neben einer Bedingung und beantwortet die Frage, die man wirklich
|
|
hat: "warum laeuft die nicht?". Das ist die Ausnahme unter den dreien -
|
|
Bedingungen gibt es sonst nirgends auf der Seite. */
|
|
.wert-jetzt {
|
|
font-size: .8125rem;
|
|
color: var(--ton-schrift-3);
|
|
font-variant-numeric: tabular-nums;
|
|
white-space: nowrap;
|
|
text-overflow: ellipsis;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.wert-jetzt b { font-weight: 400; color: var(--ton-schrift-2); }
|
|
.wert-jetzt.erfuellt b { color: var(--ton-gut); }
|
|
|
|
/* Erfuellt oder noch nicht. Bewusst kein Rot: eine Bedingung, die gerade
|
|
nicht zutrifft, ist der Normalfall und kein Fehler. */
|
|
.punkt {
|
|
display: inline-block;
|
|
width: .7rem;
|
|
height: .7rem;
|
|
border: 1.5px solid var(--ton-schrift-3);
|
|
border-radius: 50%;
|
|
}
|
|
|
|
.punkt.an {
|
|
border-color: var(--ton-gut);
|
|
background: var(--ton-gut);
|
|
}
|
|
|
|
/* Atmet leise, wo etwas mitlaeuft - ein Wort "live" daneben braucht es dann
|
|
nicht. */
|
|
.punkt.atmet { animation: punkt-atmen 2.4s ease-in-out infinite; }
|
|
|
|
@keyframes punkt-atmen {
|
|
0%, 100% { opacity: 1; }
|
|
50% { opacity: .35; }
|
|
}
|
|
|
|
@media (prefers-reduced-motion: reduce) {
|
|
.punkt.atmet { animation: none; }
|
|
}
|
|
|
|
|
|
/* --------------------------------------------------------------------------
|
|
Editor der Automatiken: die Bedingungszeile
|
|
|
|
Frueher eine input-group aus sechs gleich schweren Kaesten. Jetzt ein
|
|
Raster, in dem Geraet und Messwert uebereinander stehen (das Geraet
|
|
beantwortet "woher", nicht "was") und nur Vergleich und Wert noch wie
|
|
Eingabefelder aussehen.
|
|
|
|
Auf schmalen Schirmen bricht die Zeile in zwei: oben, worum es geht,
|
|
unten der Vergleich. Frueher schrumpften die Felder stattdessen mit, bis
|
|
von "Thermostat OG Bad" ein "Therm" uebrig war.
|
|
-------------------------------------------------------------------------- */
|
|
.auto-zeile {
|
|
display: grid;
|
|
grid-template-columns: 1.75rem minmax(0, 1fr) 5.25rem 8rem 8.5rem .75rem 1.75rem;
|
|
grid-template-areas: "sym was op wert jetzt punkt weg";
|
|
gap: .625rem;
|
|
align-items: center;
|
|
padding: .45rem .55rem;
|
|
border-radius: var(--ton-radius-klein);
|
|
}
|
|
|
|
.auto-zeile:nth-of-type(even) { background: rgba(255, 255, 255, .022); }
|
|
|
|
.auto-zeile > .auto-symbol { grid-area: sym; color: var(--ton-schrift-2); }
|
|
.auto-zeile > .auto-was { grid-area: was; min-width: 0; }
|
|
.auto-zeile > .auto-op { grid-area: op; }
|
|
.auto-zeile > .auto-wert { grid-area: wert; }
|
|
.auto-zeile > .wert-jetzt { grid-area: jetzt; }
|
|
.auto-zeile > .punkt { grid-area: punkt; }
|
|
.auto-zeile > .auto-weg { grid-area: weg; }
|
|
.auto-zeile > .auto-werte { grid-area: werte; }
|
|
|
|
/* Die Aktionszeile: dasselbe Raster, andere Spalten. Statt Vergleich, Wert
|
|
und laufendem Messwert steht dort ein Block mit den Parametern des
|
|
Kommandos - mal keiner ("Auf"), mal zwei ("Position+Neigung"). */
|
|
.auto-zeile.tat {
|
|
grid-template-columns: 1.75rem minmax(0, 1fr) auto 1.75rem;
|
|
grid-template-areas: "sym was werte weg";
|
|
}
|
|
|
|
/* Eine Zeile ohne Geraet: dann gibt es nur eines zu tun, und das darf die
|
|
ganze Breite haben. Vergleich, Wert und der laufende Messwert gibt es in
|
|
diesem Zustand noch gar nicht - ihre Spalten stuenden sonst nur leer
|
|
herum, waehrend die eine Schaltflaeche in eine schmale Spalte gequetscht
|
|
waere. */
|
|
.auto-zeile.leer { grid-template-areas: "sym was was was was punkt weg"; }
|
|
|
|
/* Geraet klein und matt ueber dem Messwert - und trotzdem anklickbar. */
|
|
.auto-was { display: flex; flex-direction: column; gap: .05rem; }
|
|
|
|
/* Nur in der Bedingungszeile: die Aktionszeile benutzt .auto-geraet
|
|
weiterhin als vollwertige Auswahlflaeche und darf davon nichts
|
|
abbekommen. */
|
|
/* Nicht in der leeren Zeile: dort traegt derselbe Knopf zusaetzlich
|
|
.feld-als-text und ist die einzige Handlung, die es gibt - klein und matt
|
|
waere er dort genau die Falle, die er vorher war. Die Klasse .auto-geraet
|
|
behaelt er trotzdem, weil daran haengt, WAS er ist: der Klick-Horcher
|
|
erkennt ihn daran. Verhalten und Aussehen sind absichtlich zwei
|
|
verschiedene Klassen. */
|
|
.auto-was > .auto-geraet:not(.feld-als-text) {
|
|
align-self: start;
|
|
max-width: 100%;
|
|
padding: 0;
|
|
border: 0;
|
|
background: none;
|
|
color: var(--ton-schrift-3);
|
|
font-size: .72rem;
|
|
line-height: 1.3;
|
|
text-align: left;
|
|
text-overflow: ellipsis;
|
|
white-space: nowrap;
|
|
overflow: hidden;
|
|
cursor: pointer;
|
|
}
|
|
|
|
.auto-was > .auto-geraet:not(.feld-als-text):hover,
|
|
.auto-was > .auto-geraet:not(.feld-als-text):focus-visible {
|
|
color: var(--bs-link-color);
|
|
outline: 0;
|
|
}
|
|
|
|
.auto-messwert { align-self: start; }
|
|
|
|
/* Der Papierkorb erscheint erst beim Ueberfahren. Acht rote Knoepfe im
|
|
Ruhezustand zogen alle Aufmerksamkeit auf die seltenste Handlung.
|
|
Wo es kein Ueberfahren gibt, steht er dauerhaft da. */
|
|
.auto-zeile > .auto-weg {
|
|
padding: 0;
|
|
border: 0;
|
|
background: none;
|
|
color: var(--ton-schrift-3);
|
|
opacity: 0;
|
|
transition: opacity .15s ease, color .15s ease;
|
|
}
|
|
|
|
.auto-zeile:hover > .auto-weg,
|
|
.auto-zeile:focus-within > .auto-weg { opacity: 1; }
|
|
.auto-zeile > .auto-weg:hover { color: var(--ton-schlecht); }
|
|
|
|
@media (hover: none) {
|
|
.auto-zeile > .auto-weg { opacity: 1; }
|
|
}
|
|
|
|
/* Ein Segment je Bedingung, im Kopf des Bandes und ueber jeder Gruppe.
|
|
Eine Zahl allein ("2 von 4") liest man, die Reihe sieht man. */
|
|
.auto-segment {
|
|
width: .8rem;
|
|
height: .3rem;
|
|
border-radius: .15rem;
|
|
background: var(--ton-linie-satt);
|
|
}
|
|
|
|
.auto-segment.an { background: var(--ton-gut); }
|
|
|
|
/* Was der Browser nicht entscheiden kann, bleibt hohl - siehe ZEITARTEN in
|
|
autoActionFuncs.js. */
|
|
.auto-segment.offen {
|
|
background: none;
|
|
box-shadow: inset 0 0 0 1px var(--ton-linie-satt);
|
|
}
|
|
|
|
@media (max-width: 767.98px) {
|
|
.auto-zeile {
|
|
grid-template-columns: 1.75rem 5.25rem minmax(0, 1fr) .75rem 1.75rem;
|
|
/* Drei Zeilen statt zwei: der laufende Wert quetschte sich sonst mit
|
|
dem Wertfeld in dieselbe Reihe und blieb als "gerad…" stehen. Auf
|
|
einem Handy ist Hoehe billig und Breite teuer. */
|
|
grid-template-areas:
|
|
"sym was was punkt weg"
|
|
"sym op wert wert wert"
|
|
"sym jetzt jetzt jetzt jetzt";
|
|
row-gap: .35rem;
|
|
}
|
|
|
|
.auto-zeile.leer { grid-template-areas: "sym was was punkt weg"; }
|
|
|
|
.auto-zeile.tat {
|
|
grid-template-columns: 1.75rem minmax(0, 1fr) 1.75rem;
|
|
grid-template-areas:
|
|
"sym was weg"
|
|
"sym werte werte";
|
|
}
|
|
|
|
.auto-zeile.tat.leer { grid-template-areas: "sym was weg"; }
|
|
}
|
|
|
|
/* 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. */
|
|
|
|
/* 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 die
|
|
Bedeutungsfarben stehen fuer sich: bernstein fuer "offen", gelb fuer
|
|
eingeschaltetes Licht, gruen fuer Laden, rot fuer einen leeren Akku.
|
|
|
|
Sie haengen alle an .skoda-seite (dem <main> der Seite) und werden von dort
|
|
vererbt - Fahrzeugbild, Kennzahlen, Balken und Karte holen sie sich also
|
|
aus einer einzigen Quelle. Wo eine Farbe mit Deckkraft gebraucht wird,
|
|
steht sie zusaetzlich als RGB-Tripel bereit, denn rgba() kann eine
|
|
Hex-Variable nicht aufloesen.
|
|
========================================================================== */
|
|
|
|
.skoda-seite {
|
|
--skoda-offen: #e0904f; /* offene Tuer, Klappe, Fenster */
|
|
--skoda-licht: #f2d16b; /* eingeschaltetes Licht */
|
|
--skoda-laden: #4caf7d; /* Laden, gesunder Ladestand */
|
|
--skoda-laden-rgb: 76, 175, 125;
|
|
--skoda-niedrig: #e06060; /* Ladestand unter 15 Prozent */
|
|
--skoda-ruhe: #7aa7c7; /* Ladestand ohne Ladung */
|
|
--skoda-ruhe-rgb: 122, 167, 199;
|
|
--skoda-pv: #f0b429; /* Strom aus der eigenen Anlage */
|
|
--skoda-netz: #7a8791; /* Strom aus dem Netz */
|
|
--skoda-blech: 128, 138, 148; /* alles Unbeteiligte am Fahrzeug */
|
|
}
|
|
|
|
/* --- Reiter --------------------------------------------------------------
|
|
Eine Bauart fuer die ganze Seite: Einstellungen, Raum-Modal, Automatiken.
|
|
Gebaut werden sie von restricted/reiter.php, umgeschaltet von Bootstrap.
|
|
|
|
Statt der Ordnerlaschen von Bootstrap eine Unterstreichung: die Laschen
|
|
brauchen einen Rahmen um die Flaeche darunter, damit sie nicht in der Luft
|
|
haengen - und der Rahmen ist genau das, was diese Oberflaeche sonst
|
|
nirgends hat. Der aktive Reiter traegt die Akzentfarbe.
|
|
|
|
Jede Regel nennt .nav-tabs UND .reiter, obwohl .reiter allein die Leiste
|
|
schon trifft. Das ist noetig, nicht schmueckend: adminlte.min.css wird nach
|
|
dieser Datei geladen und bringt eigene Regeln fuer .nav-tabs .nav-link mit.
|
|
Bei gleicher Spezifitaet gewaenne die spaetere - der aktive Reiter waere
|
|
weiss statt bernstein. */
|
|
.nav-tabs.reiter {
|
|
border-bottom: 1px solid var(--ton-linie, rgba(138, 148, 158, .2));
|
|
gap: .1rem;
|
|
}
|
|
.nav-tabs.reiter .nav-link {
|
|
border: 0;
|
|
border-bottom: 2px solid transparent;
|
|
border-radius: .35rem .35rem 0 0;
|
|
padding: .45rem .9rem;
|
|
color: var(--ton-schrift-2, #9aa6ad);
|
|
background: transparent;
|
|
transition: color .18s, background .18s, border-color .18s;
|
|
}
|
|
@media (hover: hover) {
|
|
.nav-tabs.reiter .nav-link:hover {
|
|
background: rgba(138, 148, 158, .08);
|
|
color: var(--ton-schrift, #e8ede9);
|
|
border-bottom-color: var(--ton-linie-satt, rgba(138, 148, 158, .38));
|
|
}
|
|
}
|
|
.nav-tabs.reiter .nav-link.active {
|
|
background: transparent;
|
|
color: var(--ton-sonne, #f0b429);
|
|
border-bottom-color: var(--ton-sonne, #f0b429);
|
|
}
|
|
.nav-tabs.reiter .nav-link:focus-visible {
|
|
outline: 2px solid var(--ton-sonne, #f0b429);
|
|
outline-offset: -2px;
|
|
}
|
|
.nav-tabs.reiter .nav-link i { margin-right: .5rem; }
|
|
|
|
/* Schmale Fassung fuer enge Stellen (Raum-Modal): kleinere Reiter, die
|
|
waagerecht scrollen statt umzubrechen - eine Zeile bleibt eine Zeile. */
|
|
.nav-tabs.reiter-schmal {
|
|
flex-wrap: nowrap;
|
|
overflow-x: auto;
|
|
overflow-y: hidden;
|
|
scrollbar-width: none;
|
|
}
|
|
.nav-tabs.reiter-schmal::-webkit-scrollbar { display: none; }
|
|
.nav-tabs.reiter-schmal .nav-link {
|
|
padding: .3rem .7rem;
|
|
font-size: .8rem;
|
|
white-space: nowrap;
|
|
}
|
|
.nav-tabs.reiter-schmal .nav-link i { margin-right: .3rem; }
|
|
|
|
@media (prefers-reduced-motion: reduce) {
|
|
.nav-tabs.reiter .nav-link { transition: none; }
|
|
}
|
|
|
|
/* --- Aufbau der Fahrzeugkachel -------------------------------------------
|
|
Links das Bild, rechts die Zahlen dazu. Die Kachel bricht um, sobald die
|
|
Zahlenspalte unter 24rem faellt; das Bild behaelt dann seine Breite und
|
|
rueckt in die Mitte. Die drei Bloecke rechts verteilen sich ueber die Hoehe
|
|
des Bildes, damit die Kachel unten nicht ausfranst. */
|
|
.skoda-fahrzeug {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
justify-content: center;
|
|
gap: clamp(1rem, 3vw, 2.5rem);
|
|
align-items: stretch;
|
|
}
|
|
.skoda-bild {
|
|
flex: 0 0 auto;
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
}
|
|
/* Die Zahlenspalte laeuft nicht ueber die ganze Breite mit: ein Balken von
|
|
einem Meter Laenge teilt nicht besser als einer von dreissig Zentimetern.
|
|
Auf sehr breiten Schirmen steht die Kachel deshalb mittig statt gedehnt. */
|
|
/* Mittig statt oben buendig: ohne Ladung faellt der Ladestrombalken weg, und
|
|
die uebrigen Bloecke sollen sich dann gleichmaessig neben dem Fahrzeug
|
|
verteilen statt eine Luecke in der Mitte zu lassen. */
|
|
.skoda-daten {
|
|
flex: 1 1 24rem;
|
|
max-width: 48rem;
|
|
display: flex;
|
|
flex-direction: column;
|
|
justify-content: center;
|
|
gap: 1.5rem;
|
|
}
|
|
|
|
/* Kleine Beschriftung ueber einem Block oder einer Zahl. Einmal beschrieben,
|
|
von Kennzahlen, Ladestrom und Zustandszeile gemeinsam benutzt. */
|
|
.skoda-marke,
|
|
.kennzahl .k,
|
|
.skoda-fahrleistung .posten .k {
|
|
font-size: .7rem;
|
|
letter-spacing: .09em;
|
|
text-transform: uppercase;
|
|
color: var(--bs-secondary-color, #9aa0a6);
|
|
}
|
|
|
|
/* --- 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: 297px; /* 294,4 Einheiten viewBox, eine Einheit ein Bildpunkt */
|
|
height: auto;
|
|
}
|
|
|
|
.skoda-auto .karosserie {
|
|
fill: rgba(var(--skoda-blech), 0.17);
|
|
stroke: rgba(var(--skoda-blech), 0.55);
|
|
stroke-width: 2;
|
|
}
|
|
|
|
/* --- Strasse ------------------------------------------------------------
|
|
Sichtbar nur waehrend der Fahrt, und sie traegt die eigentliche Bewegung.
|
|
|
|
Die Masse stehen im SVG: Leitlinie 6 m Strich auf 12 m Luecke, rechts
|
|
durchgezogen, das Ganze im Viertel des Fahrzeugmassstabs. Hier bleibt die
|
|
Bewegung: eine Umdrehung ist eine Strich-Lueckenlaenge (472,5 Einheiten),
|
|
in 1,08 s - das sind 437 Einheiten je Sekunde und in diesem Massstab gut
|
|
60 km/h. Der Takt der vorbeiziehenden Striche bleibt damit derselbe wie
|
|
zuvor, die Bewegung selbst ist ruhiger.
|
|
|
|
Nur die Leitlinie laeuft. Die durchgezogene Linie hat nichts, woran man
|
|
Bewegung saehe - genau wie in echt. */
|
|
.skoda-auto .strasse { display: none; }
|
|
.skoda-auto.faehrt .strasse { display: block; }
|
|
|
|
.skoda-auto .strasse .belag {
|
|
fill: rgba(8, 10, 12, 0.35);
|
|
}
|
|
|
|
.skoda-auto .strasse line {
|
|
stroke: rgba(232, 237, 233, 0.5);
|
|
stroke-width: 4.2; /* etwas breiter als massstaeblich (3,15), damit
|
|
sich die Markierung vom Fahrtwind abhebt */
|
|
}
|
|
|
|
.skoda-auto .strasse .leitlinie {
|
|
stroke-dasharray: 157.5 315; /* 6 m Strich, 12 m Luecke, geviertelt */
|
|
animation: skoda-leitlinie 1.08s linear infinite;
|
|
}
|
|
|
|
@keyframes skoda-leitlinie {
|
|
from { transform: translateY(0); }
|
|
to { transform: translateY(472.5px); }
|
|
}
|
|
|
|
/* --- Bananenschale ------------------------------------------------------
|
|
Der Ostergruss. Ausgeloest wird er selten und nur waehrend der Fahrt (siehe
|
|
bananeVielleicht() in js/solar/skodaMQTT.js); hier steht, wie er aussieht.
|
|
|
|
Zwei Bewegungen greifen ineinander: die Schale laeuft mit der Strasse mit,
|
|
und wenn sie unter der Vorderachse ist, kommt der Wagen ins Schleudern. Der
|
|
Vorlauf der zweiten Bewegung ist deshalb kein Gefuehl, sondern gerechnet:
|
|
die Schale startet 40 Einheiten ueber dem Bild, die Vorderachse liegt bei
|
|
97, macht 137 Einheiten - bei 437 Einheiten je Sekunde sind das 0,31 s.
|
|
|
|
Der Wagen dreht sich um seinen Schwerpunkt, nicht um die Bildmitte; ohne
|
|
transform-box: view-box bezoege sich transform-origin auf den Rahmen der
|
|
Gruppe und der Bogen saehe falsch aus. */
|
|
.skoda-auto .bananenschale { display: none; }
|
|
.skoda-auto.banane .bananenschale {
|
|
display: block;
|
|
animation: skoda-schale 1.5s linear;
|
|
}
|
|
.skoda-auto .bananenschale use {
|
|
fill: #e8c74a;
|
|
stroke: rgba(120, 92, 12, 0.75);
|
|
stroke-width: 0.8;
|
|
}
|
|
.skoda-auto .bananenschale .strunk { fill: #b8912c; }
|
|
|
|
.skoda-auto.banane #wagen {
|
|
transform-box: view-box;
|
|
transform-origin: 112px 250px;
|
|
animation: skoda-schleudern 1.2s 0.31s ease-in-out;
|
|
}
|
|
|
|
@keyframes skoda-schale {
|
|
from { transform: translateY(-40px); }
|
|
to { transform: translateY(560px); }
|
|
}
|
|
|
|
/* Erst ein Ausbrechen nach rechts, dann das Gegenlenken, dann austrudeln -
|
|
in dieser Reihenfolge faengt sich ein Fahrzeug wieder. */
|
|
@keyframes skoda-schleudern {
|
|
0% { transform: rotate(0deg) translateX(0); }
|
|
18% { transform: rotate(4.5deg) translateX(5px); }
|
|
45% { transform: rotate(-3.5deg) translateX(-4px); }
|
|
70% { transform: rotate(1.8deg) translateX(2px); }
|
|
88% { transform: rotate(-0.7deg) translateX(-1px); }
|
|
100% { transform: rotate(0deg) translateX(0); }
|
|
}
|
|
|
|
/* --- Fahrtwind ----------------------------------------------------------
|
|
Vier Streifen neben dem Wagen, die von vorn nach hinten laufen. Sichtbar
|
|
nur, solange zeichneFahrt() dem SVG die Klasse "faehrt" gibt.
|
|
|
|
Die Laenge der Streifen steckt im Markup (y1/y2), die Bewegung hier: jede
|
|
Spur laeuft in eigenem Takt und mit eigenem Vorlauf ueber das Bild, sonst
|
|
marschieren die vier im Gleichschritt und es sieht nach Zebrastreifen aus
|
|
statt nach Fahrt. Der Weg reicht von weit oberhalb bis weit unterhalb der
|
|
viewBox (-8 bis 508), damit kein Streifen im Bild entsteht oder endet. */
|
|
.skoda-auto .fahrtwind { display: none; }
|
|
.skoda-auto.faehrt .fahrtwind { display: block; }
|
|
/* Die Streifen ueber dem Wagen liegen ueber den beiden Knoepfen; sie duerfen
|
|
deren Beruehrungen nicht abfangen. */
|
|
.skoda-auto .fahrtwind-oben { pointer-events: none; }
|
|
|
|
.skoda-auto .fahrtwind line {
|
|
stroke: rgba(var(--skoda-blech), 0.75);
|
|
stroke-width: 2.5;
|
|
stroke-linecap: round;
|
|
animation: skoda-fahrtwind 1.1s linear infinite;
|
|
}
|
|
/* Vier Spuren, jede mit eigenem Takt und Vorlauf. Sie laufen so schnell wie
|
|
die Strasse darunter - ein Streifen, der die Fahrbahnmarkierung ueberholt,
|
|
faellt sofort auf. Mit der Strasse halbiert sich also auch ihr Tempo. */
|
|
.skoda-auto .fahrtwind .b1 { animation-duration: 1.56s; animation-delay: -0.60s; opacity: .5; }
|
|
.skoda-auto .fahrtwind .b6 { animation-duration: 1.72s; animation-delay: -1.10s; opacity: .5; }
|
|
|
|
/* Ueber dem Fahrzeug: heller, duenner, durchsichtiger. Der Wind zieht ueber
|
|
das Blech hinweg - er soll sich darauf legen, nicht hineinschneiden. Die
|
|
Streifen stehen dafuer in einer eigenen Gruppe am Ende des SVG (siehe
|
|
dort); ihre geringe Deckung haelt Ladestand und Umrisse lesbar. */
|
|
.skoda-auto .fahrtwind .ueber {
|
|
stroke: rgba(232, 237, 233, 0.85);
|
|
stroke-width: 2;
|
|
}
|
|
.skoda-auto .fahrtwind .b7 { animation-duration: 1.48s; animation-delay: -0.40s; opacity: .34; }
|
|
.skoda-auto .fahrtwind .b10 { animation-duration: 1.64s; animation-delay: -0.90s; opacity: .34; }
|
|
|
|
@keyframes skoda-fahrtwind {
|
|
from { transform: translateY(0); }
|
|
to { transform: translateY(680px); }
|
|
}
|
|
|
|
/* Wer Bewegung abbestellt hat, bekommt sie nicht - aber auch keine leere
|
|
Stelle: die Streifen stehen dann ruhig neben dem Wagen, und das Abzeichen
|
|
"unterwegs" im Kopf der Kachel sagt es ohnehin in Worten. */
|
|
@media (prefers-reduced-motion: reduce) {
|
|
.skoda-auto .fahrtwind line {
|
|
animation: none;
|
|
transform: translateY(250px);
|
|
opacity: .45;
|
|
}
|
|
/* Auch die Leitlinie bleibt stehen - zu sehen ist dann eine Standaufnahme
|
|
statt einer Fahrt, und das Abzeichen "unterwegs" sagt den Rest. */
|
|
.skoda-auto .strasse .leitlinie {
|
|
animation: none;
|
|
}
|
|
/* Der Ostergruss faellt ganz aus: ein schleuderndes Fahrzeug ist genau die
|
|
Art Bewegung, die abbestellt wurde. Ausgeloest wird er hier gar nicht
|
|
erst - das prueft das Skript zusaetzlich. */
|
|
.skoda-auto.banane .bananenschale,
|
|
.skoda-auto.banane #wagen {
|
|
animation: none;
|
|
}
|
|
.skoda-auto.banane .bananenschale { display: none; }
|
|
}
|
|
|
|
/* Die Reifen liegen als unterste Lage unter der ganzen Karosserie (siehe die
|
|
Schichtung in restricted/skoda.php) und sind schwarz wie am Auto. Unter zwei
|
|
getoenten Flaechen bleibt davon nicht viel uebrig, vorn unter der Haube fast
|
|
nichts - das ist so gewollt. Von oben saehe man die Reifen ohnehin nicht;
|
|
sie stehen im Bild, damit die Achsen einen Ort haben, nicht damit man sie
|
|
liest. */
|
|
.skoda-auto .rad rect { fill: rgba(14, 16, 19, 0.95); }
|
|
.skoda-auto .spiegel rect { fill: rgba(var(--skoda-blech), 0.55); }
|
|
/* Die Kupplung ist schwarz und bleibt es: sie steht hinten heraus und liegt
|
|
dort auf dem Hintergrund, nicht unter dem Blech - sie braucht die
|
|
Aufhellung der Reifen also nicht. */
|
|
.skoda-auto .kupplung rect,
|
|
.skoda-auto .kupplung circle { fill: rgba(10, 12, 14, 0.95); }
|
|
/* Dachspoiler und Reling sind an diesem Fahrzeug schwarz, nicht lackiert -
|
|
und nur dadurch heben sie sich vom Dach ab, auf dem sie liegen. Vorher
|
|
hatten sie den Ton des Blechs und verschwanden darin. */
|
|
.skoda-auto .spoiler { fill: rgba(26, 29, 33, 0.85); }
|
|
|
|
/* Dachreling als Linie mit runden Enden - eine Strichstaerke beschreibt sie
|
|
vollstaendig, und die Enden runden sich von selbst. */
|
|
.skoda-auto .reling line {
|
|
stroke: rgba(26, 29, 33, 0.85);
|
|
stroke-width: 6;
|
|
stroke-linecap: round;
|
|
}
|
|
.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. */
|
|
/* Die Blende ist glaenzendes Schwarz, aber nicht das dunkelste im Bild: mit
|
|
voller Deckung sprang sie nach vorn und las sich wie ein Loch statt wie eine
|
|
Flaeche. Etwas durchscheinend und mit ruhiger Kante bleibt sie das, was sie
|
|
ist - eine Blende auf dem Blech. */
|
|
.skoda-auto .techdeck {
|
|
fill: rgba(20, 24, 30, 0.66);
|
|
stroke: rgba(var(--skoda-blech), 0.3);
|
|
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); }
|
|
|
|
/* Die Heckscheibe liegt in der Heckklappe - sie geht mit ihr auf, also ist
|
|
sie kein eigenes Teil. Aussehen soll sie trotzdem wie Glas und nicht wie
|
|
Blech; die Regel steht nach der allgemeinen und gewinnt damit. */
|
|
.skoda-auto .teil > .scheibe {
|
|
fill: rgba(var(--skoda-blech), 0.28);
|
|
stroke: rgba(var(--skoda-blech), 0.45);
|
|
}
|
|
/* Steht die Klappe offen, faerbt sich auch ihre Scheibe - nur durchsichtiger
|
|
als das Blech, sonst waere das Glas ploetzlich das Kraeftigste am Heck.
|
|
Der Rahmen kommt aus der allgemeinen Regel und ist damit derselbe. */
|
|
.skoda-auto .teil.offen > .scheibe { fill: rgba(224, 144, 79, 0.42); }
|
|
|
|
/* --- Antriebsbatterie ----------------------------------------------------
|
|
Die Platte im Fahrzeugboden ist die Ladestandsanzeige der Seite. Welche
|
|
Farbe sie traegt, steht in einer einzigen Variablen: die Zustandsklasse am
|
|
<svg> setzt --akku-farbe, und Huelle, Fuellung, Pegelkante, Stroemung und
|
|
Verlauf lesen sie von dort. Ein weiterer Zustand ist damit eine Zeile und
|
|
keine Suche durch die Datei. */
|
|
.skoda-auto { --akku-farbe: var(--skoda-ruhe); }
|
|
.skoda-auto.akku-laedt { --akku-farbe: var(--skoda-laden); }
|
|
.skoda-auto.akku-niedrig { --akku-farbe: var(--skoda-niedrig); }
|
|
.skoda-auto.akku-unbekannt { --akku-farbe: rgb(var(--skoda-blech)); }
|
|
|
|
/* Der Farbverlauf steht in <defs> und damit ausserhalb der Akkugruppe -
|
|
deshalb haengt --akku-farbe am <svg> und nicht an .akku. */
|
|
.skoda-auto #akkuVerlauf stop { stop-color: var(--akku-farbe); }
|
|
|
|
.skoda-auto .akku .huelle {
|
|
fill: rgba(8, 10, 12, .35);
|
|
stroke: var(--akku-farbe);
|
|
stroke-opacity: .55;
|
|
stroke-width: 1.5;
|
|
}
|
|
.skoda-auto .akku .fuellung {
|
|
fill: url(#akkuVerlauf);
|
|
stroke: none;
|
|
transition: y .8s ease, height .8s ease;
|
|
}
|
|
|
|
/* Die helle Kante auf der Fuellung. Sie macht den Stand auch dort ablesbar,
|
|
wo die getoente Flaeche darunter kaum auffaellt. */
|
|
.skoda-auto .akku .kante {
|
|
fill: var(--akku-farbe);
|
|
transition: y .8s ease;
|
|
}
|
|
.skoda-auto.akku-laedt .akku .kante {
|
|
filter: drop-shadow(0 0 5px var(--akku-farbe));
|
|
}
|
|
|
|
/* Modulfugen. Sie liegen auf 20, 40, 60 und 80 Prozent und sind damit
|
|
zugleich die Skala, an der sich der Stand ablesen laesst. */
|
|
.skoda-auto .akku .fugen line {
|
|
stroke: rgba(var(--skoda-blech), 0.4);
|
|
stroke-width: 1;
|
|
stroke-dasharray: 3 4;
|
|
}
|
|
|
|
/* Ladestrom: Streifen, die im gefuellten Teil nach vorn wandern. Der Schnitt
|
|
auf den Pegel kommt aus #akkuPegel, das zeichneAkku() mitfuehrt. */
|
|
.skoda-auto .akku .stroemung { opacity: 0; transition: opacity .4s; }
|
|
.skoda-auto .akku .stroemung rect { fill: var(--akku-farbe); }
|
|
.skoda-auto.akku-laedt .akku .stroemung { opacity: .4; }
|
|
.skoda-auto.akku-laedt .akku .stroemung .bahn {
|
|
animation: akkuStroemung 2.4s linear infinite;
|
|
}
|
|
@keyframes akkuStroemung {
|
|
from { transform: translateY(0); }
|
|
to { transform: translateY(-54px); } /* genau ein Streifenabstand */
|
|
}
|
|
|
|
/* Zielmarke. Sie wird als Ganzes verschoben, damit Linie und Beschriftung
|
|
zusammenbleiben und der Weg dorthin weich laeuft. */
|
|
.skoda-auto .akku .zielmarke { transition: transform .8s ease; }
|
|
.skoda-auto .akku .zielmarke line {
|
|
stroke: var(--bs-body-color, #e8ede9);
|
|
stroke-width: 1.5;
|
|
stroke-dasharray: 5 3;
|
|
opacity: .6;
|
|
}
|
|
.skoda-auto .akku .zielmarke text {
|
|
fill: var(--bs-body-color, #e8ede9);
|
|
font-size: 10px;
|
|
font-weight: 500;
|
|
text-anchor: end;
|
|
opacity: .8;
|
|
}
|
|
|
|
/* Zahlen in der Platte. Der dunkle Umriss liegt hinter der Fuellung der
|
|
Zeichen (paint-order), damit sie ueber geladenem wie leerem Teil der
|
|
Platte gleich gut lesbar bleiben. */
|
|
.skoda-auto .akku text {
|
|
paint-order: stroke;
|
|
stroke: rgba(8, 10, 12, .7);
|
|
stroke-linejoin: round;
|
|
stroke-width: 2.5;
|
|
}
|
|
.skoda-auto .akku .wert {
|
|
fill: var(--bs-body-color, #e8ede9);
|
|
font-size: 40px;
|
|
font-weight: 600;
|
|
text-anchor: middle;
|
|
font-variant-numeric: tabular-nums;
|
|
stroke-width: 4;
|
|
}
|
|
.skoda-auto .akku .wert .einheit {
|
|
font-size: 17px;
|
|
font-weight: 500;
|
|
opacity: .65;
|
|
}
|
|
.skoda-auto .akku .neben {
|
|
fill: var(--bs-body-color, #e8ede9);
|
|
fill-opacity: .8;
|
|
font-size: 14px;
|
|
text-anchor: middle;
|
|
}
|
|
|
|
/* Der Weg des Ladestroms vom Anschluss in die Platte. Die Striche laufen in
|
|
Fahrtrichtung des Stroms, also zum Akku hin. */
|
|
.skoda-auto .ladefluss {
|
|
fill: none;
|
|
stroke: var(--skoda-laden);
|
|
stroke-width: 2.5;
|
|
stroke-linecap: round;
|
|
stroke-dasharray: 3 7;
|
|
opacity: 0;
|
|
transition: opacity .3s;
|
|
}
|
|
.skoda-auto.akku-laedt .ladefluss {
|
|
opacity: .95;
|
|
animation: akkuFluss 1s linear infinite;
|
|
}
|
|
@keyframes akkuFluss {
|
|
from { stroke-dashoffset: 20; }
|
|
to { stroke-dashoffset: 0; }
|
|
}
|
|
|
|
/* 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));
|
|
}
|
|
|
|
/* Ladeanschluss. Er ist gebaut wie der Klimaknopf; den Ladezustand traegt
|
|
nicht die Form, sondern die Farbe: blau wie jeder Knopf, gruen solange
|
|
geladen wird, dazu das Pulsen als Schein um die Scheibe. Die Scheibe selbst
|
|
bleibt deckend - gruen ausgefuellt verschluckte sie den Blitz. */
|
|
.skoda-auto .teil-stecker .glyphe { stroke-width: 2.2; }
|
|
.skoda-auto .teil-stecker.laedt .ring,
|
|
.skoda-auto .teil-stecker.laedt .flaeche { stroke: var(--skoda-laden); }
|
|
.skoda-auto .teil-stecker.laedt .glyphe { stroke: var(--skoda-laden); }
|
|
.skoda-auto .teil-stecker.laedt .flaeche {
|
|
animation: skodaPuls 1.8s ease-in-out infinite;
|
|
}
|
|
|
|
@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 .flaeche { animation: none; }
|
|
/* Der Ladestand bleibt sichtbar, nur nicht mehr in Bewegung. */
|
|
.skoda-auto .akku .fuellung,
|
|
.skoda-auto .akku .kante,
|
|
.skoda-auto .akku .zielmarke { transition: none; }
|
|
.skoda-auto.akku-laedt .akku .stroemung .bahn,
|
|
.skoda-auto.akku-laedt .ladefluss,
|
|
.skoda-auto.klima-laeuft .steuer .luefter .blaetter { animation: none; }
|
|
}
|
|
|
|
/* --- Zustandszeile unter dem Fahrzeug ------------------------------------ */
|
|
.skoda-teile {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
gap: .35rem;
|
|
justify-content: flex-start;
|
|
margin-top: .45rem;
|
|
}
|
|
.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;
|
|
}
|
|
/* Ein Punkt vor dem Wort traegt dieselbe Aussage wie die Farbe im Bild und
|
|
macht die Zeile auf einen Blick ueberfliegbar. */
|
|
.skoda-teile .chip::before {
|
|
content: "";
|
|
width: .45rem;
|
|
height: .45rem;
|
|
border-radius: 50%;
|
|
background: rgba(var(--skoda-blech), .75);
|
|
flex: 0 0 auto;
|
|
}
|
|
.skoda-teile .chip.offen { border-color: var(--skoda-offen); color: var(--skoda-offen); }
|
|
.skoda-teile .chip.offen::before { background: var(--skoda-offen); }
|
|
.skoda-teile .chip.an::before { background: var(--skoda-licht); }
|
|
.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); }
|
|
|
|
/* --- Kennzahlen neben dem Fahrzeug ---------------------------------------
|
|
Was sich nicht ins Bild zeichnen laesst, steht in gleich gebauten Kacheln:
|
|
Zeichen, Bezeichnung, Wert und bei Bedarf eine Nebenzeile. Eine Kachel
|
|
bekommt die Klasse .aktiv, solange ihre Zahl gerade etwas aussagt - die
|
|
Ladeleistung waehrend des Ladens, das Klima, solange es laeuft. Welche
|
|
Farbe die Hervorhebung traegt, steht in --kennzahl-rgb. */
|
|
.skoda-kennzahlen {
|
|
display: grid;
|
|
grid-template-columns: repeat(auto-fit, minmax(10.5rem, 1fr));
|
|
gap: .75rem;
|
|
}
|
|
.kennzahl {
|
|
--kennzahl-rgb: var(--skoda-laden-rgb);
|
|
display: flex;
|
|
align-items: center;
|
|
gap: .75rem;
|
|
padding: .7rem .85rem;
|
|
border: 1px solid var(--bs-border-color, rgba(128, 128, 128, .25));
|
|
border-radius: .7rem;
|
|
background: rgba(var(--skoda-blech), .07);
|
|
transition: border-color .3s, background .3s;
|
|
}
|
|
.kennzahl .zeichen {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
flex: 0 0 auto;
|
|
width: 2.1rem;
|
|
height: 2.1rem;
|
|
border-radius: 50%;
|
|
background: rgba(var(--skoda-blech), .16);
|
|
color: var(--bs-secondary-color, #9aa0a6);
|
|
transition: background .3s, color .3s;
|
|
}
|
|
.kennzahl .text { display: flex; flex-direction: column; min-width: 0; }
|
|
.kennzahl .v {
|
|
font-size: 1.2rem;
|
|
line-height: 1.3;
|
|
font-variant-numeric: tabular-nums;
|
|
}
|
|
.kennzahl .neben {
|
|
font-size: .72rem;
|
|
color: var(--bs-secondary-color, #9aa0a6);
|
|
}
|
|
.kennzahl .neben:empty { display: none; }
|
|
|
|
.kennzahl.aktiv {
|
|
border-color: rgba(var(--kennzahl-rgb), .5);
|
|
background: rgba(var(--kennzahl-rgb), .1);
|
|
}
|
|
.kennzahl.aktiv .zeichen {
|
|
background: rgba(var(--kennzahl-rgb), .2);
|
|
color: rgb(var(--kennzahl-rgb));
|
|
}
|
|
#skodaKachelKlima { --kennzahl-rgb: var(--skoda-ruhe-rgb); }
|
|
|
|
/* --- Fahrleistung --------------------------------------------------------
|
|
Drei Zahlen nebeneinander, durch einen Strich getrennt. Kein Kasten und
|
|
keine Kachel: es ist eine Nebenauskunft, kein Messwert des Augenblicks.
|
|
Ein Wert, dessen Zeitraum weiter zurueckreicht als die Aufzeichnung, wird
|
|
gestrichelt unterstrichen und nennt im Titel, seit wann gemessen wird. */
|
|
.skoda-fahrleistung .reihe {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
gap: .35rem 1.4rem;
|
|
margin-top: .5rem;
|
|
}
|
|
.skoda-fahrleistung .posten {
|
|
display: flex;
|
|
flex-direction: column;
|
|
min-width: 5.5rem;
|
|
}
|
|
.skoda-fahrleistung .posten + .posten {
|
|
border-left: 1px solid var(--bs-border-color, rgba(128, 128, 128, .25));
|
|
padding-left: 1.4rem;
|
|
}
|
|
/* Auf dem Handy zaehlt jeder Millimeter: die Trennstriche weichen, damit die
|
|
drei Zahlen in einer Zeile bleiben statt in zwei umzubrechen. */
|
|
@media (max-width: 30rem) {
|
|
.skoda-fahrleistung .reihe { gap: .3rem .9rem; }
|
|
.skoda-fahrleistung .posten { min-width: 0; }
|
|
.skoda-fahrleistung .posten + .posten { border-left: none; padding-left: 0; }
|
|
}
|
|
|
|
.skoda-fahrleistung .posten .v {
|
|
font-size: 1.15rem;
|
|
line-height: 1.3;
|
|
font-variant-numeric: tabular-nums;
|
|
}
|
|
/* --- Erklärungen ---------------------------------------------------------
|
|
Ein Element mit Erklärung traegt ein Info-Zeichen. Das ist der einzige
|
|
Hinweis darauf, dass es dort etwas zu lesen gibt - am Zeiger genuegte das
|
|
Ueberfahren, am Finger gibt es das nicht. Angetippt oder ueberfahren oeffnet
|
|
setzeHinweis() ein Popover; das Zeichen sagt vorher, dass sich das lohnt. */
|
|
/* Kein Textmarkieren beim Antippen: der Finger trifft Text, gemeint ist der
|
|
Auslöser - eine blau markierte Zahl waere die falsche Antwort darauf. */
|
|
.hat-hinweis {
|
|
cursor: help;
|
|
-webkit-user-select: none;
|
|
user-select: none;
|
|
-webkit-tap-highlight-color: transparent;
|
|
}
|
|
.skoda-fahrleistung .posten.hat-hinweis .v::after,
|
|
#skodaVerbrauchBasis.hat-hinweis::after {
|
|
content: "\f431"; /* bi-info-circle */
|
|
font-family: bootstrap-icons;
|
|
font-size: .78em;
|
|
margin-left: .3em;
|
|
opacity: .65;
|
|
vertical-align: .05em;
|
|
}
|
|
.hat-hinweis:focus { outline: none; }
|
|
.hat-hinweis:focus-visible {
|
|
outline: 2px solid var(--bs-primary, #4b8fd6);
|
|
outline-offset: 3px;
|
|
border-radius: .2rem;
|
|
}
|
|
|
|
/* Das Fenster selbst: dunkel wie die Kacheln, schmal genug zum Lesen. Auf dem
|
|
Handy darf es die halbe Breite einnehmen, mehr nicht. */
|
|
.skoda-erklaerung {
|
|
--bs-popover-max-width: 22rem;
|
|
--bs-popover-bg: #23282c;
|
|
--bs-popover-border-color: rgba(128, 138, 148, .35);
|
|
--bs-popover-body-color: var(--bs-body-color, #e8ede9);
|
|
--bs-popover-body-padding-x: .8rem;
|
|
--bs-popover-body-padding-y: .6rem;
|
|
--bs-popover-font-size: .82rem;
|
|
box-shadow: 0 .5rem 1.5rem rgba(0, 0, 0, .45);
|
|
}
|
|
|
|
/* --- Herkunft des Ladestroms ---------------------------------------------
|
|
Der Balken teilt die Ladeleistung in den Anteil aus der eigenen Anlage und
|
|
den Rest aus dem Netz. Die Legende nennt beide Anteile in Zahlen - ein
|
|
Farbstueck allein sagt nicht, wie viel es ist. */
|
|
.skoda-quelle .kopf {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: baseline;
|
|
gap: .75rem;
|
|
margin-bottom: .4rem;
|
|
}
|
|
.skoda-quelle .summe {
|
|
font-size: .85rem;
|
|
font-variant-numeric: tabular-nums;
|
|
color: var(--bs-secondary-color, #9aa0a6);
|
|
}
|
|
.skoda-balken {
|
|
display: flex;
|
|
height: .8rem;
|
|
border-radius: .4rem;
|
|
overflow: hidden;
|
|
background: rgba(var(--skoda-blech), 0.2);
|
|
}
|
|
.skoda-balken > div { transition: width .5s ease; }
|
|
.skoda-balken .teil-pv { background: var(--skoda-pv); }
|
|
.skoda-balken .teil-netz { background: var(--skoda-netz); }
|
|
|
|
.skoda-quelle .legende {
|
|
display: flex;
|
|
gap: 1.1rem;
|
|
margin-top: .45rem;
|
|
font-size: .78rem;
|
|
color: var(--bs-secondary-color, #9aa0a6);
|
|
}
|
|
.skoda-quelle .legende span { display: inline-flex; align-items: center; gap: .35rem; }
|
|
.skoda-quelle .legende b {
|
|
color: var(--bs-body-color, #e8ede9);
|
|
font-weight: 600;
|
|
font-variant-numeric: tabular-nums;
|
|
}
|
|
.skoda-quelle .legende .pkt { width: .55rem; height: .55rem; border-radius: 50%; }
|
|
.skoda-quelle .legende .pkt.pv { background: var(--skoda-pv); }
|
|
.skoda-quelle .legende .pkt.netz { background: var(--skoda-netz); }
|
|
|
|
/* --- 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;
|
|
}
|
|
/* Der Knopf sitzt mitten auf der Akkuplatte und muss sich gegen jeden
|
|
Fuellstand behaupten - gegen die dunkle leere Zelle ebenso wie gegen die
|
|
gefuellte. Eine durchscheinende Flaeche kann das nicht: sie nimmt die Farbe
|
|
an, die zufaellig darunter liegt. Deshalb eine eigene, deckende Scheibe. */
|
|
.skoda-auto .steuer .flaeche {
|
|
fill: rgba(10, 13, 17, .92);
|
|
stroke: var(--bs-primary, #4b8fd6);
|
|
stroke-width: 1.5;
|
|
filter: drop-shadow(0 0 3px rgba(0, 0, 0, .55));
|
|
}
|
|
.skoda-auto .steuer .glyphe {
|
|
fill: none;
|
|
stroke: #7db3f0; /* dieselbe Farbe wie die Luefterfluegel */
|
|
stroke-width: 1.8;
|
|
stroke-linecap: round;
|
|
stroke-linejoin: round;
|
|
}
|
|
|
|
/* Luefterrad des Klimaknopfs. Es dreht sich, solange die Klimatisierung
|
|
arbeitet - dasselbe Mittel wie beim Ladeanschluss: der Zustand steht als
|
|
Klasse am <svg>, die Form bleibt, wo sie ist. */
|
|
.skoda-auto .steuer .luefter use { fill: #7db3f0; }
|
|
.skoda-auto .steuer .luefter .nabe { fill: rgba(10, 13, 17, .92); }
|
|
.skoda-auto .steuer .luefter .blaetter { transform-origin: 0 0; }
|
|
.skoda-auto.klima-laeuft .steuer .luefter .blaetter {
|
|
animation: klimaDreht 3.2s linear infinite;
|
|
}
|
|
@keyframes klimaDreht {
|
|
from { transform: rotate(0deg); }
|
|
to { transform: rotate(360deg); }
|
|
}
|
|
@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; }
|
|
|
|
/* === Einstellungen: Werte auf den Home-Kacheln ===========================
|
|
Eine Zeile je Raum, aufklappbar. Die Zeile zeigt im zugeklappten Zustand
|
|
schon, was auf der Kachel steht - sonst muesste man zwanzig Raeume
|
|
aufklappen, um einen zu finden. */
|
|
|
|
.kachel-etage { margin-bottom: 1.25rem; }
|
|
.kachel-etage:last-child { margin-bottom: 0; }
|
|
.kachel-etage-name {
|
|
font-size: .7rem;
|
|
letter-spacing: .13em;
|
|
text-transform: uppercase;
|
|
color: var(--ton-schrift-3, #6f7a81);
|
|
margin-bottom: .35rem;
|
|
}
|
|
|
|
.kachel-zeile {
|
|
border: 1px solid var(--ton-linie, rgba(138, 148, 158, .2));
|
|
border-radius: .5rem;
|
|
margin-bottom: .4rem;
|
|
overflow: hidden;
|
|
}
|
|
.kachel-zeile.offen { border-color: var(--ton-linie-satt, rgba(138, 148, 158, .38)); }
|
|
|
|
.kachel-kopf {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: .6rem;
|
|
width: 100%;
|
|
padding: .5rem .75rem;
|
|
background: none;
|
|
border: 0;
|
|
color: inherit;
|
|
font: inherit;
|
|
text-align: left;
|
|
cursor: pointer;
|
|
}
|
|
@media (hover: hover) {
|
|
.kachel-kopf:hover { background: rgba(138, 148, 158, .08); }
|
|
}
|
|
.kachel-kopf .pfeil {
|
|
color: var(--ton-schrift-3, #6f7a81);
|
|
transition: transform .18s;
|
|
flex: 0 0 auto;
|
|
}
|
|
.kachel-zeile.offen .kachel-kopf .pfeil { transform: rotate(90deg); }
|
|
.kachel-kopf .name { min-width: 8rem; }
|
|
.kachel-kopf .werte {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
gap: .3rem;
|
|
flex: 1 1 auto;
|
|
}
|
|
.kachel-chip {
|
|
font-size: .72rem;
|
|
padding: .1rem .45rem;
|
|
border: 1px solid var(--ton-linie, rgba(138, 148, 158, .2));
|
|
border-radius: 1rem;
|
|
color: var(--ton-schrift-2, #9aa6ad);
|
|
white-space: nowrap;
|
|
}
|
|
.kachel-chip.leer { font-style: italic; }
|
|
.kachel-chip .bi { margin-right: .3rem; opacity: .8; }
|
|
|
|
.kachel-editor {
|
|
padding: .25rem .75rem .75rem;
|
|
border-top: 1px solid var(--ton-linie, rgba(138, 148, 158, .2));
|
|
}
|
|
|
|
/* Eine Wertzeile. Auf breiten Schirmen nebeneinander, auf dem Handy
|
|
untereinander - die Felder sind zu kurz, um sie zu quetschen. */
|
|
.kachel-wert {
|
|
display: grid;
|
|
grid-template-columns: 7.5rem minmax(10rem, 1fr) 7rem 5.5rem 9.5rem auto;
|
|
gap: .4rem;
|
|
align-items: center;
|
|
padding: .5rem 0;
|
|
border-bottom: 1px dashed var(--ton-linie, rgba(138, 148, 158, .2));
|
|
}
|
|
.kachel-wert:last-of-type { border-bottom: 0; }
|
|
/* Symbolname mit Vorschau davor: die Vorschau sagt, was der Name bedeutet -
|
|
"moisture" allein sagt es nicht. */
|
|
.kachel-wert .kw-symbol {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: .35rem;
|
|
}
|
|
.kachel-wert .kw-symbol-schau {
|
|
flex: none;
|
|
width: 1.5rem;
|
|
text-align: center;
|
|
font-size: 1.05rem;
|
|
line-height: 1;
|
|
color: var(--ton-schrift-2, #9aa6ad);
|
|
}
|
|
.kachel-wert .kw-symbol-schau .unbekannt { color: var(--ton-schlecht, #e06060); }
|
|
.kachel-wert .kw-symbol input { min-width: 0; }
|
|
|
|
.kachel-wert .kw-schalter {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: .5rem;
|
|
white-space: nowrap;
|
|
}
|
|
.kachel-wert .kw-schalter .kw-format {
|
|
width: auto;
|
|
font-size: .78rem;
|
|
padding-top: .1rem;
|
|
padding-bottom: .1rem;
|
|
}
|
|
.kachel-wert .kw-schalter label {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: .25rem;
|
|
font-size: .78rem;
|
|
color: var(--ton-schrift-2, #9aa6ad);
|
|
cursor: pointer;
|
|
}
|
|
|
|
@media (max-width: 991.98px) {
|
|
.kachel-wert {
|
|
grid-template-columns: 1fr 1fr;
|
|
}
|
|
.kachel-wert .kw-topic { grid-column: 1 / -1; }
|
|
}
|
|
|
|
.kachel-fuss {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: .75rem;
|
|
margin-top: .75rem;
|
|
}
|
|
|
|
/* === Geraetetafel (Einstellungen) ========================================
|
|
Sechzig Zeilen, in denen die meiste Arbeit an einer Handvoll haengt: den
|
|
Geraeten ohne Raum und denen, die seit Monaten schweigen. Beide sind
|
|
markiert, damit man sie nicht suchen muss - der Rest bleibt ruhig. */
|
|
.geraete-sieb {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: .9rem;
|
|
margin-bottom: .75rem;
|
|
}
|
|
.geraete-sieb input[type="search"] { max-width: 22rem; }
|
|
.geraete-sieb .form-check { flex: none; }
|
|
|
|
/* Kein eigener Rollbalken: die Tafel ist so lang, wie sie ist, und die Seite
|
|
scrollt als Ganzes. Ein Kasten mit eigenem Balken in einer Karte, die selbst
|
|
in einer scrollenden Seite steht, ist ein Balken zu viel - man weiss beim
|
|
Wischen nie, welcher der beiden gerade dran ist. */
|
|
.geraete-tafel {
|
|
/* Bewusst ohne Rahmen und ohne overflow: beides machte aus der Tafel
|
|
wieder einen eigenen Scroll-Kasten, und der klebende Tabellenkopf haette
|
|
nichts mehr, woran er kleben kann. */
|
|
margin-bottom: 0;
|
|
}
|
|
/* Der Kopf bleibt trotzdem stehen: er klebt an der Kopfzeile der Seite, denn
|
|
gescrollt wird bei AdminLTE in .app-main, und dort ist oben die Navigation.
|
|
Ab Zeile zwanzig weiss man sonst nicht mehr, welche Spalte der Raum war. */
|
|
.geraete-tafel thead th {
|
|
position: sticky;
|
|
top: 0;
|
|
z-index: 1;
|
|
background: var(--ton-flaeche-2, #2b3237);
|
|
font-size: .72rem;
|
|
letter-spacing: .08em;
|
|
text-transform: uppercase;
|
|
color: var(--ton-schrift-3, #6f7a81);
|
|
white-space: nowrap;
|
|
border-bottom: 1px solid var(--bs-border-color, #2c3034);
|
|
box-shadow: 0 1px 0 var(--ton-grund, #191d20); /* deckt die Zeile darunter */
|
|
}
|
|
.geraete-tafel td { vertical-align: middle; }
|
|
.geraete-tafel .name { line-height: 1.25; }
|
|
.geraete-tafel .name .neben {
|
|
display: block;
|
|
font-size: .72rem;
|
|
color: var(--ton-schrift-3, #6f7a81);
|
|
}
|
|
.geraete-tafel .raum { min-width: 11rem; }
|
|
.geraete-tafel .raum select { min-width: 9rem; }
|
|
.geraete-tafel .alter { color: var(--ton-schrift-2, #9aa4ab); white-space: nowrap; }
|
|
.geraete-tafel .alter.lange { color: var(--ton-sonne, #f0b429); }
|
|
/* Ohne Raum: eine Kante links statt einer eingefaerbten Zeile - Letzteres
|
|
sieht bei zwanzig offenen Geraeten nach Fehler aus, ist aber nur Arbeit.
|
|
Als ::before und nicht als border, weil Bootstrap Tabellenzellen im
|
|
Hover mit einem inset-Schatten fuellt und den Rand damit ueberdeckt. */
|
|
.geraete-tafel tr.ohne-raum td:first-child { position: relative; }
|
|
.geraete-tafel tr.ohne-raum td:first-child::before {
|
|
content: "";
|
|
position: absolute;
|
|
left: 0; top: 0; bottom: 0;
|
|
width: 3px;
|
|
background: var(--ton-sonne, #f0b429);
|
|
}
|
|
|
|
/* Der Papierkorb haelt sich zurueck, bis man ihn braucht. */
|
|
.geraete-tafel .geraet-weg {
|
|
color: var(--ton-schrift-3, #6f7a81);
|
|
border-color: transparent;
|
|
line-height: 1;
|
|
}
|
|
.geraete-tafel .geraet-weg:hover:not(:disabled),
|
|
.geraete-tafel .geraet-weg:focus-visible:not(:disabled) {
|
|
color: var(--ton-schlecht, #e06060);
|
|
border-color: var(--ton-schlecht, #e06060);
|
|
}
|
|
.geraete-tafel .geraet-weg:disabled { opacity: .25; }
|
|
|
|
.geraete-fuss {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
gap: .75rem;
|
|
margin-top: .5rem;
|
|
}
|
|
|
|
@media (max-width: 575.98px) {
|
|
.geraete-sieb { flex-wrap: wrap; }
|
|
.geraete-sieb input[type="search"] { max-width: none; }
|
|
}
|
|
|
|
/* === 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 var(--font-anzeige);
|
|
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; }
|
|
|
|
/* ===========================================================================
|
|
Einstellungen -> Grundriss (js/solar/grundriss.js)
|
|
|
|
Links der Plan, rechts die Formulare. Die Kachel im Plan sieht aus wie auf
|
|
der Startseite (restricted/home.php): dunkles Rechteck, weisse Schrift -
|
|
nur ohne Messwerte, dafuer mit Rand, wenn sie gewaehlt ist.
|
|
=========================================================================== */
|
|
.gr-etagen {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
gap: .4rem;
|
|
margin-bottom: .9rem;
|
|
}
|
|
/* Eine Klasse mehr als Bootstrap: solar.css laedt vor AdminLTE. */
|
|
.gr-etagen .btn.gr-etage {
|
|
display: inline-flex;
|
|
align-items: baseline;
|
|
gap: .4rem;
|
|
border: 1px solid var(--ton-linie-satt, rgba(138, 148, 158, .38));
|
|
color: var(--ton-schrift-2, #9aa6ad);
|
|
}
|
|
.gr-etagen .btn.gr-etage.aktiv {
|
|
border-color: #00788F;
|
|
color: var(--ton-schrift, #e8ede9);
|
|
background: rgba(0, 120, 143, .18);
|
|
}
|
|
.gr-etage-code { font: 600 .9rem var(--font-anzeige); }
|
|
.gr-etage-name { font-size: .75rem; }
|
|
.gr-etage-std { font-size: .65rem; color: var(--ton-sonne, #f0b429); }
|
|
|
|
.gr-plan-huelle {
|
|
position: relative;
|
|
border-radius: var(--ton-radius-klein, .5rem);
|
|
overflow: hidden;
|
|
background: #0b0d10;
|
|
}
|
|
.gr-plan-huelle.platzieren .gr-plan { cursor: crosshair; }
|
|
.gr-plan-leer {
|
|
aspect-ratio: 4 / 3;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
padding: 2rem;
|
|
text-align: center;
|
|
color: var(--ton-schrift-3, #6f7a81);
|
|
font-size: .85rem;
|
|
}
|
|
.gr-plan {
|
|
display: block;
|
|
width: 100%;
|
|
height: auto;
|
|
touch-action: none;
|
|
user-select: none;
|
|
}
|
|
.gr-ohne-bild {
|
|
fill: var(--ton-schrift-3, #6f7a81);
|
|
font: 12px sans-serif;
|
|
text-anchor: middle;
|
|
}
|
|
.gr-kachel { cursor: grab; }
|
|
.gr-kachel.zieht { cursor: grabbing; }
|
|
.gr-kachel rect {
|
|
fill: #0006;
|
|
stroke: #ffffff55;
|
|
stroke-width: .5;
|
|
}
|
|
.gr-kachel:hover rect { stroke: #ffffffaa; }
|
|
.gr-kachel.gewaehlt rect { stroke: var(--ton-sonne, #f0b429); stroke-width: 1; }
|
|
.gr-kachel text {
|
|
fill: #fff;
|
|
font: 4.8px sans-serif;
|
|
text-anchor: middle;
|
|
pointer-events: none;
|
|
}
|
|
.gr-geist rect {
|
|
fill: rgba(240, 180, 41, .28);
|
|
stroke: var(--ton-sonne, #f0b429);
|
|
stroke-width: .8;
|
|
pointer-events: none;
|
|
}
|
|
|
|
.gr-block {
|
|
border: 1px solid var(--ton-linie, rgba(138, 148, 158, .2));
|
|
border-radius: var(--ton-radius-klein, .5rem);
|
|
padding: .6rem .75rem;
|
|
margin-bottom: .6rem;
|
|
}
|
|
.gr-block-titel {
|
|
font-size: .7rem;
|
|
letter-spacing: .13em;
|
|
text-transform: uppercase;
|
|
color: var(--ton-schrift-3, #6f7a81);
|
|
margin-bottom: .35rem;
|
|
}
|
|
.gr-knoepfe {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
align-items: center;
|
|
gap: .35rem;
|
|
margin-top: .6rem;
|
|
}
|
|
/* Papierkorb wie in der Geraetetafel: erst rot, wenn man ihn anfasst. */
|
|
.gr-knoepfe .btn.gr-etage-weg,
|
|
.gr-knoepfe .btn.gr-raum-weg {
|
|
margin-left: auto;
|
|
color: var(--ton-schrift-3, #6f7a81);
|
|
}
|
|
.gr-knoepfe .btn.gr-etage-weg:hover,
|
|
.gr-knoepfe .btn.gr-raum-weg:hover { color: var(--ton-schlecht, #e06060); }
|
|
|
|
.gr-raeume { display: flex; flex-direction: column; gap: .15rem; }
|
|
.gr-raum {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: .4rem;
|
|
padding: .1rem .3rem;
|
|
border-radius: .35rem;
|
|
}
|
|
.gr-raum.gewaehlt { background: rgba(240, 180, 41, .12); }
|
|
.gr-raum-name {
|
|
flex: 1 1 auto;
|
|
background: none;
|
|
border: 0;
|
|
padding: .2rem 0;
|
|
color: inherit;
|
|
font: inherit;
|
|
font-size: .88rem;
|
|
text-align: left;
|
|
cursor: pointer;
|
|
}
|
|
.gr-raum-stand { color: var(--ton-schrift-3, #6f7a81); font-size: .8rem; }
|
|
.gr-raum .btn.gr-platzieren { padding: 0 .45rem; font-size: .75rem; }
|
|
|
|
/* ===========================================================================
|
|
Automatismen als Zeitleiste (js/solar/zeitleiste.js)
|
|
|
|
Eine Bahn je Geraeteart, die Spur ist der Tag von 0 bis 24 Uhr. Die Nacht
|
|
liegt als leichter Schatten dahinter, jetzt ist eine duenne Linie in der
|
|
Sonnenfarbe. Jede Bahn traegt ihre Akzentfarbe als --zl-farbe; Punkte,
|
|
Balken und Etiketten nehmen sie auf.
|
|
=========================================================================== */
|
|
.zl {
|
|
--zl-linie: var(--ton-linie, rgba(138, 148, 158, .2));
|
|
--zl-farbe: #9aa6ad;
|
|
--zl-farbe-rgb: 154, 166, 173;
|
|
}
|
|
.zl-bahn-licht { --zl-farbe: #f0b429; --zl-farbe-rgb: 240, 180, 41; }
|
|
.zl-bahn-beschattung { --zl-farbe: #5fb0dc; --zl-farbe-rgb: 95, 176, 220; }
|
|
.zl-bahn-heizung { --zl-farbe: #e8836a; --zl-farbe-rgb: 232, 131, 106; }
|
|
.zl-bahn-bewaesserung { --zl-farbe: #4cc18a; --zl-farbe-rgb: 76, 193, 138; }
|
|
.zl-bahn-schalter { --zl-farbe: #b59cf0; --zl-farbe-rgb: 181, 156, 240; }
|
|
|
|
/* Kopf */
|
|
.zl-kopf {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
align-items: center;
|
|
gap: .6rem 1rem;
|
|
margin-bottom: .9rem;
|
|
}
|
|
.zl-tag .btn.zl-tag-name { min-width: 9.5rem; font-variant-numeric: tabular-nums; }
|
|
.zl-etagen { display: flex; flex-wrap: wrap; gap: .3rem; }
|
|
.zl-chip {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: .35rem;
|
|
padding: .2rem .65rem;
|
|
border: 1px solid var(--zl-linie);
|
|
border-radius: 999px;
|
|
background: transparent;
|
|
color: var(--ton-schrift-2, #9aa6ad);
|
|
font: 500 .8rem var(--font-anzeige, inherit);
|
|
cursor: pointer;
|
|
transition: background .15s, border-color .15s, color .15s;
|
|
}
|
|
.zl-chip:hover { border-color: var(--ton-linie-satt, rgba(138, 148, 158, .38)); color: var(--ton-schrift, #e8ede9); }
|
|
.zl-chip.an {
|
|
background: rgba(0, 120, 143, .22);
|
|
border-color: #00788F;
|
|
color: var(--ton-schrift, #e8ede9);
|
|
}
|
|
.zl-chip.leer { opacity: .55; }
|
|
.zl-chip-zahl {
|
|
font-size: .68rem;
|
|
padding: 0 .35rem;
|
|
border-radius: 999px;
|
|
background: rgba(138, 148, 158, .18);
|
|
color: var(--ton-schrift-2, #9aa6ad);
|
|
}
|
|
.zl-zahl {
|
|
margin-left: auto;
|
|
font-size: .8rem;
|
|
color: var(--ton-schrift-2, #9aa6ad);
|
|
white-space: nowrap;
|
|
}
|
|
.zl-zahl-leise { color: var(--ton-schrift-3, #6f7a81); }
|
|
|
|
/* Raster */
|
|
.zl-rahmen {
|
|
overflow-x: auto;
|
|
border-radius: var(--ton-radius-klein, .5rem);
|
|
}
|
|
.zl-raster { position: relative; }
|
|
.zl-zeile {
|
|
display: grid;
|
|
grid-template-columns: var(--zl-kopf) minmax(0, 1fr);
|
|
}
|
|
.zl-bahn .zl-spur { border-top: 1px solid var(--zl-linie); }
|
|
.zl-bahn-kopf {
|
|
position: sticky;
|
|
left: 0;
|
|
z-index: 3;
|
|
display: flex;
|
|
align-items: flex-start;
|
|
gap: .45rem;
|
|
padding: .6rem .6rem 0 0;
|
|
background: var(--ton-flaeche, #23282c);
|
|
font: 500 .82rem var(--font-anzeige, inherit);
|
|
color: var(--ton-schrift, #e8ede9);
|
|
}
|
|
.zl-bahn-kopf .bi { color: var(--zl-farbe); font-size: .95rem; line-height: 1.1; }
|
|
/* Schmal nur das Symbol; der Name steht im Hinweis beim Antippen der Eintraege. */
|
|
.zl-rahmen.schmal .zl-bahn-kopf { justify-content: center; padding-right: 0; }
|
|
.zl-rahmen.schmal .zl-bahn-kopf span { display: none; }
|
|
.zl-bahn-zahl {
|
|
margin-left: auto;
|
|
font-size: .68rem;
|
|
color: var(--ton-schrift-3, #6f7a81);
|
|
}
|
|
.zl-spur {
|
|
position: relative;
|
|
min-height: 38px;
|
|
/* Alle drei Stunden eine Linie, jede volle Stunde ein Hauch. */
|
|
background-image:
|
|
linear-gradient(to right, rgba(138, 148, 158, .16) 1px, transparent 1px),
|
|
linear-gradient(to right, rgba(138, 148, 158, .06) 1px, transparent 1px);
|
|
background-size: 12.5% 100%, 4.1667% 100%;
|
|
}
|
|
.zl-nacht {
|
|
position: absolute;
|
|
top: 0;
|
|
bottom: 0;
|
|
background: rgba(0, 0, 0, .24);
|
|
pointer-events: none;
|
|
}
|
|
.zl-jetzt {
|
|
position: absolute;
|
|
top: 0;
|
|
bottom: 0;
|
|
width: 0;
|
|
border-left: 1.5px solid var(--ton-sonne, #f0b429);
|
|
opacity: .8;
|
|
z-index: 2;
|
|
pointer-events: none;
|
|
}
|
|
|
|
/* Achse */
|
|
.zl-achse .zl-bahn-kopf { padding-top: 0; }
|
|
.zl-achse .zl-spur { height: 26px; min-height: 0; background: none; }
|
|
.zl-stunde {
|
|
position: absolute;
|
|
bottom: 4px;
|
|
transform: translateX(-50%);
|
|
font-size: .7rem;
|
|
color: var(--ton-schrift-3, #6f7a81);
|
|
font-variant-numeric: tabular-nums;
|
|
}
|
|
.zl-stunde.anfang { transform: none; }
|
|
.zl-stunde.ende { transform: translateX(-100%); }
|
|
.zl-sonne {
|
|
position: absolute;
|
|
top: -2px;
|
|
transform: translateX(-50%);
|
|
font-size: .78rem;
|
|
color: var(--ton-sonne, #f0b429);
|
|
opacity: .75;
|
|
cursor: help;
|
|
}
|
|
.zl-jetzt-marke {
|
|
position: absolute;
|
|
top: 1px;
|
|
transform: translateX(-50%);
|
|
padding: 0 .35rem;
|
|
border-radius: 999px;
|
|
background: var(--ton-sonne, #f0b429);
|
|
color: #1b1f22;
|
|
font: 600 .66rem var(--font-anzeige, inherit);
|
|
z-index: 2;
|
|
}
|
|
|
|
/* Eintraege */
|
|
.zl-ding {
|
|
position: absolute;
|
|
height: 24px;
|
|
display: flex;
|
|
align-items: center;
|
|
cursor: pointer;
|
|
z-index: 1;
|
|
}
|
|
.zl-ding:hover { z-index: 4; }
|
|
.zl-marke {
|
|
flex: none;
|
|
width: 12px;
|
|
height: 12px;
|
|
border-radius: 50%;
|
|
border: 2px solid var(--zl-farbe);
|
|
background: var(--ton-flaeche, #23282c);
|
|
box-sizing: border-box;
|
|
}
|
|
.zl-punkt { transform: translateX(-6px); }
|
|
.zl-punkt.links { flex-direction: row-reverse; transform: translateX(calc(-100% + 6px)); }
|
|
.zl-etikett {
|
|
margin-left: 6px;
|
|
padding: .1rem .5rem;
|
|
border-radius: 6px;
|
|
border: 1px solid transparent;
|
|
background: rgba(var(--zl-farbe-rgb), .1);
|
|
color: var(--ton-schrift, #e8ede9);
|
|
font-size: .75rem;
|
|
line-height: 1.35;
|
|
white-space: nowrap;
|
|
transition: background .15s, border-color .15s;
|
|
}
|
|
.zl-punkt.links .zl-etikett { margin-left: 0; margin-right: 6px; }
|
|
.zl-etikett b {
|
|
font-weight: 600;
|
|
margin-right: .4rem;
|
|
color: var(--zl-farbe);
|
|
font-variant-numeric: tabular-nums;
|
|
}
|
|
.zl-etikett .bi-check2 { color: var(--ton-gut, #4caf7d); }
|
|
.zl-ding:hover .zl-etikett {
|
|
background: rgba(var(--zl-farbe-rgb), .2);
|
|
border-color: rgba(var(--zl-farbe-rgb), .45);
|
|
}
|
|
|
|
/* Zustaende */
|
|
.zl-ding.gelaufen .zl-marke { background: var(--zl-farbe); }
|
|
.zl-ding.vorbei { opacity: .5; }
|
|
.zl-ding.vorbei .zl-etikett b { color: var(--ton-schrift-2, #9aa6ad); }
|
|
.zl-ding.aktiv .zl-marke { box-shadow: 0 0 0 3px rgba(var(--zl-farbe-rgb), .25); }
|
|
/* Nicht dran: statt eines gestrichelten Kreises nur ein kleiner blasser Punkt
|
|
dicht am Etikett - das Kalender-Symbol darin sagt schon, was los ist. Die
|
|
Marke behaelt ihre 12px, damit Zeit, Stapeln und Kettenlinien stimmen. */
|
|
.zl-ding.nichtdran .zl-marke {
|
|
border: 0;
|
|
background: radial-gradient(circle, var(--ton-schrift-3, #6f7a81) 2.5px, transparent 3px);
|
|
}
|
|
.zl-punkt.nichtdran .zl-etikett { margin-left: 1px; }
|
|
.zl-punkt.nichtdran.links .zl-etikett { margin-left: 0; margin-right: 1px; }
|
|
.zl-ding.nichtdran .zl-etikett {
|
|
background: transparent;
|
|
border: 1px dashed var(--zl-linie);
|
|
color: var(--ton-schrift-3, #6f7a81);
|
|
}
|
|
.zl-ding.nichtdran .zl-etikett b { color: var(--ton-schrift-3, #6f7a81); }
|
|
.zl-nichtdran {
|
|
margin-right: .35rem;
|
|
font-size: .72rem;
|
|
color: var(--ton-schrift-2, #9aa6ad);
|
|
}
|
|
|
|
/* Zeitfenster: der Balken traegt Laeufe und die frueheste Marke. */
|
|
.zl-fenster { min-width: 10px; }
|
|
.zl-balken {
|
|
position: absolute;
|
|
left: 0;
|
|
right: 0;
|
|
top: 8px;
|
|
height: 8px;
|
|
border-radius: 4px;
|
|
background: rgba(var(--zl-farbe-rgb), .22);
|
|
border: 1px solid rgba(var(--zl-farbe-rgb), .4);
|
|
}
|
|
.zl-fenster .zl-etikett {
|
|
position: relative;
|
|
margin-left: 0;
|
|
background: var(--ton-flaeche, #23282c);
|
|
border-color: rgba(var(--zl-farbe-rgb), .3);
|
|
}
|
|
/* Reicht der Platz bis zum rechten Rand nicht, wird der Name gekuerzt. */
|
|
.zl-etikett.gekappt {
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
}
|
|
.zl-lauf {
|
|
margin-left: .25rem;
|
|
color: var(--ton-gut, #4caf7d);
|
|
font-variant-numeric: tabular-nums;
|
|
}
|
|
.zl-fenster.nichtdran .zl-balken { background: transparent; border-style: dashed; border-color: var(--zl-linie); }
|
|
.zl-marke-innen {
|
|
position: absolute;
|
|
top: 50%;
|
|
width: 10px;
|
|
height: 10px;
|
|
transform: translate(-50%, -50%);
|
|
}
|
|
|
|
/* Ketten */
|
|
.zl-ketten {
|
|
position: absolute;
|
|
left: 0;
|
|
top: 0;
|
|
pointer-events: none;
|
|
z-index: 0;
|
|
overflow: visible;
|
|
}
|
|
/* Die Linie liegt ueber dem Raster, aber unter den Etiketten. Ein dunkler
|
|
Grund darunter trennt sie von den Stundenlinien, sonst verschwindet sie
|
|
dort, wo sie eine kreuzt. */
|
|
.zl-ketten .zl-kette-grund {
|
|
fill: none;
|
|
stroke: var(--ton-flaeche, #23282c);
|
|
stroke-width: 4;
|
|
opacity: .7;
|
|
}
|
|
.zl-ketten .zl-kette {
|
|
fill: none;
|
|
stroke: rgba(214, 222, 227, .72);
|
|
stroke-width: 1.6;
|
|
stroke-dasharray: 4 3;
|
|
transition: stroke .15s;
|
|
}
|
|
.zl-ketten .zl-kette-ende { fill: rgba(214, 222, 227, .85); transition: fill .15s; }
|
|
.zl-ketten .zl-kette.hell { stroke: var(--ton-sonne, #f0b429); stroke-dasharray: none; }
|
|
.zl-ketten .zl-kette-ende.hell { fill: var(--ton-sonne, #f0b429); }
|
|
|
|
.zl-leer {
|
|
padding: 1.2rem 0 .6rem 132px;
|
|
color: var(--ton-schrift-3, #6f7a81);
|
|
font-size: .85rem;
|
|
}
|
|
|
|
/* Baender */
|
|
.zl-baender {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: .45rem;
|
|
margin-top: .8rem;
|
|
padding-top: .7rem;
|
|
border-top: 1px solid var(--zl-linie);
|
|
}
|
|
.zl-band {
|
|
display: grid;
|
|
grid-template-columns: 132px minmax(0, 1fr);
|
|
align-items: start;
|
|
}
|
|
.zl-band-chips { display: flex; flex-wrap: wrap; gap: .35rem; }
|
|
@media (max-width: 575.98px) {
|
|
.zl-band { grid-template-columns: minmax(0, 1fr); gap: .3rem; }
|
|
.zl-zahl { margin-left: 0; }
|
|
}
|
|
.zl-band-titel {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: .4rem;
|
|
padding-top: .2rem;
|
|
font: 500 .82rem var(--font-anzeige, inherit);
|
|
color: var(--ton-schrift-2, #9aa6ad);
|
|
}
|
|
.zl-band-chip {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: .4rem;
|
|
padding: .2rem .6rem;
|
|
border-radius: 6px;
|
|
border: 1px solid var(--zl-linie);
|
|
background: rgba(138, 148, 158, .07);
|
|
color: var(--ton-schrift, #e8ede9);
|
|
font-size: .75rem;
|
|
cursor: pointer;
|
|
}
|
|
.zl-band-chip:hover { border-color: var(--ton-linie-satt, rgba(138, 148, 158, .38)); }
|
|
.zl-band-pause .zl-band-chip { color: var(--ton-schrift-2, #9aa6ad); }
|
|
.zl-band-chip.nichtdran { border-style: dashed; }
|
|
.zl-band-etage {
|
|
font-size: .64rem;
|
|
padding: 0 .3rem;
|
|
border-radius: 4px;
|
|
background: rgba(138, 148, 158, .16);
|
|
color: var(--ton-schrift-3, #6f7a81);
|
|
}
|
|
|
|
/* Legende */
|
|
.zl-legende {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
gap: .4rem 1.1rem;
|
|
margin-top: .8rem;
|
|
font-size: .72rem;
|
|
color: var(--ton-schrift-3, #6f7a81);
|
|
}
|
|
.zl-legende span { display: inline-flex; align-items: center; gap: .4rem; }
|
|
.zl-legende i { display: inline-block; }
|
|
.zl-l-punkt { width: 10px; height: 10px; border-radius: 50%; border: 2px solid #5fb0dc; }
|
|
.zl-l-punkt.gelaufen { background: #5fb0dc; }
|
|
.zl-l-punkt.nichtdran { border-style: dashed; border-color: var(--ton-schrift-3, #6f7a81); }
|
|
.zl-l-balken { width: 22px; height: 7px; border-radius: 4px; background: rgba(95, 176, 220, .22); border: 1px solid rgba(95, 176, 220, .4); }
|
|
.zl-l-kette { width: 22px; border-top: 1.2px dashed rgba(154, 166, 173, .7); }
|
|
|
|
/* Karte zu einem Eintrag: schwebt ueber der Zeitleiste, Akzent der Bahn. */
|
|
.zl { position: relative; }
|
|
.zl-karte {
|
|
position: absolute;
|
|
z-index: 20;
|
|
width: min(22rem, 100%);
|
|
padding: .7rem .85rem .75rem;
|
|
border-radius: var(--ton-radius-klein, .5rem);
|
|
border: 1px solid rgba(var(--zl-farbe-rgb), .45);
|
|
border-top: 3px solid var(--zl-farbe);
|
|
background: var(--ton-flaeche-2, #2b3237);
|
|
box-shadow: 0 10px 28px rgba(0, 0, 0, .45);
|
|
font-size: .8rem;
|
|
}
|
|
.zl-karte-kopf {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: .45rem;
|
|
margin-bottom: .45rem;
|
|
}
|
|
.zl-karte-kopf .bi { color: var(--zl-farbe); }
|
|
.zl-karte-name {
|
|
flex: 1 1 auto;
|
|
font: 500 .92rem var(--font-anzeige, inherit);
|
|
color: var(--ton-schrift, #e8ede9);
|
|
}
|
|
.zl-karte .btn-close.zl-karte-zu { font-size: .6rem; opacity: .6; }
|
|
.zl-karte-zeile {
|
|
display: flex;
|
|
gap: .5rem;
|
|
align-items: baseline;
|
|
padding: .12rem 0;
|
|
color: var(--ton-schrift, #e8ede9);
|
|
}
|
|
.zl-karte-zeile .bi { color: var(--ton-schrift-3, #6f7a81); flex: none; }
|
|
.zl-karte-stand.gut, .zl-karte-stand.gut .bi { color: var(--ton-gut, #4caf7d); }
|
|
.zl-karte-stand.leise { color: var(--ton-schrift-2, #9aa6ad); }
|
|
.zl-karte-wenn {
|
|
margin-top: .35rem;
|
|
padding-top: .35rem;
|
|
border-top: 1px solid var(--zl-linie);
|
|
color: var(--ton-schrift-3, #6f7a81);
|
|
font-size: .72rem;
|
|
line-height: 1.4;
|
|
max-height: 5.6em;
|
|
overflow: auto;
|
|
}
|
|
.zl-karte-knoepfe {
|
|
display: flex;
|
|
gap: .35rem;
|
|
margin-top: .65rem;
|
|
}
|
|
.zl-karte-knoepfe .btn.zl-karte-weg {
|
|
margin-left: auto;
|
|
color: var(--ton-schrift-3, #6f7a81);
|
|
}
|
|
.zl-karte-knoepfe .btn.zl-karte-weg:hover { color: var(--ton-schlecht, #e06060); }
|
|
|
|
/* ===========================================================================
|
|
Einfuehrung (restricted/einfuehrung.php, js/solar/einfuehrung.js)
|
|
|
|
Eine Folie: links das Bild in einem ruhigen Rahmen (Handy-Aufnahmen
|
|
schmal wie ein Telefon, Desktop-Aufnahmen breit), rechts der Text mit den
|
|
nummerierten Erklaerungen. Auf schmalen Schirmen untereinander.
|
|
=========================================================================== */
|
|
.ef {
|
|
max-width: 1180px;
|
|
margin: 0 auto 2rem;
|
|
outline: none;
|
|
}
|
|
.ef-kopf {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
align-items: center;
|
|
gap: .6rem 1rem;
|
|
margin-bottom: .6rem;
|
|
}
|
|
.ef-teile { display: flex; gap: .35rem; flex-wrap: wrap; }
|
|
.ef-teil {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: .5rem;
|
|
padding: .3rem .8rem .3rem .35rem;
|
|
border: 1px solid var(--ton-linie, rgba(138, 148, 158, .2));
|
|
border-radius: 999px;
|
|
background: transparent;
|
|
color: var(--ton-schrift-2, #9aa6ad);
|
|
font: 500 .85rem var(--font-anzeige, inherit);
|
|
cursor: pointer;
|
|
transition: background .15s, border-color .15s, color .15s;
|
|
}
|
|
.ef-teil-nr {
|
|
display: inline-grid;
|
|
place-items: center;
|
|
width: 1.5rem;
|
|
height: 1.5rem;
|
|
border-radius: 50%;
|
|
background: rgba(138, 148, 158, .18);
|
|
font-size: .75rem;
|
|
}
|
|
.ef-teil.aktiv {
|
|
border-color: var(--ton-sonne, #f0b429);
|
|
color: var(--ton-schrift, #e8ede9);
|
|
background: rgba(var(--ton-sonne-rgb, 240, 180, 41), .1);
|
|
}
|
|
.ef-teil.aktiv .ef-teil-nr { background: var(--ton-sonne, #f0b429); color: #1b1f22; }
|
|
.ef-kopf .form-select.ef-kapitel { width: auto; min-width: 12rem; margin-left: auto; }
|
|
.ef-zaehler {
|
|
font-size: .8rem;
|
|
color: var(--ton-schrift-3, #6f7a81);
|
|
font-variant-numeric: tabular-nums;
|
|
min-width: 3.5rem;
|
|
text-align: right;
|
|
}
|
|
.ef-fortschritt {
|
|
height: 3px;
|
|
border-radius: 2px;
|
|
background: var(--ton-linie, rgba(138, 148, 158, .2));
|
|
margin-bottom: 1.2rem;
|
|
overflow: hidden;
|
|
}
|
|
.ef-fortschritt span {
|
|
display: block;
|
|
height: 100%;
|
|
width: 0;
|
|
background: var(--ton-sonne, #f0b429);
|
|
transition: width .35s ease;
|
|
}
|
|
|
|
/* Buehne und Folie */
|
|
.ef-buehne { position: relative; }
|
|
.ef-folie {
|
|
display: grid;
|
|
gap: 2rem;
|
|
align-items: center;
|
|
padding: 1.6rem;
|
|
border-radius: var(--ton-radius, .875rem);
|
|
background: var(--ton-flaeche, #23282c);
|
|
border: 1px solid var(--ton-linie, rgba(138, 148, 158, .2));
|
|
min-height: 34rem;
|
|
}
|
|
.ef-folie.mit-bild.form-handy { grid-template-columns: minmax(0, 330px) minmax(0, 1fr); }
|
|
.ef-folie.mit-bild.form-breit { grid-template-columns: minmax(0, 1.45fr) minmax(0, 1fr); }
|
|
.ef-folie.ohne-bild { grid-template-columns: minmax(0, 46rem); justify-content: center; }
|
|
.ef-folie.rein-vor { animation: ef-rein-vor .32s ease both; }
|
|
.ef-folie.rein-rueck { animation: ef-rein-rueck .32s ease both; }
|
|
@keyframes ef-rein-vor { from { opacity: 0; transform: translateX(18px); } to { opacity: 1; transform: none; } }
|
|
@keyframes ef-rein-rueck { from { opacity: 0; transform: translateX(-18px); } to { opacity: 1; transform: none; } }
|
|
@media (prefers-reduced-motion: reduce) {
|
|
.ef-folie.rein-vor, .ef-folie.rein-rueck { animation: none; }
|
|
}
|
|
|
|
.ef-bild { margin: 0; justify-self: center; width: 100%; }
|
|
.ef-rahmen {
|
|
position: relative;
|
|
border-radius: 14px;
|
|
overflow: visible;
|
|
box-shadow: 0 18px 40px rgba(0, 0, 0, .35);
|
|
}
|
|
.ef-rahmen img {
|
|
display: block;
|
|
width: 100%;
|
|
height: auto;
|
|
border-radius: 14px;
|
|
border: 1px solid var(--ton-linie-satt, rgba(138, 148, 158, .38));
|
|
}
|
|
/* Handy-Aufnahmen in einem angedeuteten Telefon. */
|
|
.form-handy .ef-rahmen {
|
|
max-width: 330px;
|
|
margin: 0 auto;
|
|
padding: 10px;
|
|
border-radius: 30px;
|
|
background: #0d0f11;
|
|
border: 1px solid rgba(138, 148, 158, .3);
|
|
}
|
|
.form-handy .ef-rahmen img { border-radius: 22px; border: 0; }
|
|
|
|
/* Die nummerierten Punkte im Bild */
|
|
.ef-marke {
|
|
position: absolute;
|
|
transform: translate(-50%, -50%);
|
|
display: grid;
|
|
place-items: center;
|
|
width: 26px;
|
|
height: 26px;
|
|
border-radius: 50%;
|
|
background: var(--ton-sonne, #f0b429);
|
|
color: #1b1f22;
|
|
font: 700 .8rem var(--font-anzeige, inherit);
|
|
box-shadow: 0 0 0 3px rgba(27, 31, 34, .85), 0 4px 10px rgba(0, 0, 0, .45);
|
|
cursor: pointer;
|
|
z-index: 2;
|
|
transition: transform .15s ease, box-shadow .15s ease;
|
|
}
|
|
.ef-marke::after {
|
|
content: "";
|
|
position: absolute;
|
|
inset: -6px;
|
|
border-radius: 50%;
|
|
border: 2px solid rgba(var(--ton-sonne-rgb, 240, 180, 41), .55);
|
|
animation: ef-puls 2.4s ease-out infinite;
|
|
}
|
|
.ef-marke.hell { transform: translate(-50%, -50%) scale(1.25); box-shadow: 0 0 0 3px rgba(27, 31, 34, .85), 0 0 0 8px rgba(var(--ton-sonne-rgb, 240, 180, 41), .35); }
|
|
@keyframes ef-puls { 0% { transform: scale(.8); opacity: .9; } 70%, 100% { transform: scale(1.5); opacity: 0; } }
|
|
@media (prefers-reduced-motion: reduce) { .ef-marke::after { animation: none; opacity: 0; } }
|
|
|
|
/* Text */
|
|
.ef-kapitelname {
|
|
font-size: .72rem;
|
|
letter-spacing: .12em;
|
|
text-transform: uppercase;
|
|
color: var(--ton-sonne, #f0b429);
|
|
margin-bottom: .4rem;
|
|
}
|
|
.ef-titel {
|
|
font: 600 1.7rem/1.2 var(--font-anzeige, inherit);
|
|
color: var(--ton-schrift, #e8ede9);
|
|
margin: 0 0 .8rem;
|
|
}
|
|
.ef-einleitung {
|
|
font-size: 1.02rem;
|
|
line-height: 1.6;
|
|
color: var(--ton-schrift-2, #9aa6ad);
|
|
margin-bottom: 1.1rem;
|
|
}
|
|
.ef-einleitung b, .ef-marken b, .ef-punkte b, .ef-tipp b { color: var(--ton-schrift, #e8ede9); font-weight: 600; }
|
|
.ef-marken {
|
|
list-style: none;
|
|
padding: 0;
|
|
margin: 0 0 1rem;
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: .35rem;
|
|
}
|
|
.ef-marken li {
|
|
display: flex;
|
|
gap: .7rem;
|
|
align-items: flex-start;
|
|
padding: .45rem .6rem;
|
|
border-radius: 10px;
|
|
color: var(--ton-schrift-2, #9aa6ad);
|
|
line-height: 1.5;
|
|
cursor: pointer;
|
|
transition: background .15s;
|
|
}
|
|
.ef-marken li:hover, .ef-marken li.hell { background: rgba(var(--ton-sonne-rgb, 240, 180, 41), .09); }
|
|
.ef-marke-nr {
|
|
flex: none;
|
|
display: grid;
|
|
place-items: center;
|
|
width: 22px;
|
|
height: 22px;
|
|
margin-top: 1px;
|
|
border-radius: 50%;
|
|
background: var(--ton-sonne, #f0b429);
|
|
color: #1b1f22;
|
|
font: 700 .72rem var(--font-anzeige, inherit);
|
|
}
|
|
.ef-punkte {
|
|
padding-left: 1.1rem;
|
|
margin: 0 0 1rem;
|
|
color: var(--ton-schrift-2, #9aa6ad);
|
|
line-height: 1.6;
|
|
}
|
|
.ef-punkte li { margin-bottom: .45rem; }
|
|
.ef-punkte li::marker { color: var(--ton-sonne, #f0b429); }
|
|
.ef-tipp {
|
|
display: flex;
|
|
gap: .6rem;
|
|
align-items: flex-start;
|
|
margin: .4rem 0 0;
|
|
padding: .7rem .9rem;
|
|
border-radius: 10px;
|
|
background: rgba(0, 120, 143, .14);
|
|
border: 1px solid rgba(0, 120, 143, .35);
|
|
color: var(--ton-schrift, #e8ede9);
|
|
font-size: .92rem;
|
|
line-height: 1.5;
|
|
}
|
|
.ef-tipp .bi { color: #35b6cf; margin-top: .1rem; }
|
|
|
|
/* Fuss */
|
|
.ef-fuss {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 1rem;
|
|
margin-top: 1rem;
|
|
}
|
|
.ef-punkte-nav {
|
|
flex: 1 1 auto;
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
justify-content: center;
|
|
gap: 5px;
|
|
}
|
|
.ef-punkt {
|
|
width: 8px;
|
|
height: 8px;
|
|
border-radius: 50%;
|
|
background: rgba(138, 148, 158, .3);
|
|
cursor: pointer;
|
|
transition: background .15s, transform .15s;
|
|
}
|
|
.ef-punkt.neuer-teil { margin-left: 10px; }
|
|
.ef-punkt.aktiv { background: var(--ton-sonne, #f0b429); transform: scale(1.35); }
|
|
|
|
@media (max-width: 991.98px) {
|
|
.ef-folie.mit-bild.form-handy,
|
|
.ef-folie.mit-bild.form-breit { grid-template-columns: minmax(0, 1fr); gap: 1.4rem; }
|
|
.ef-folie { padding: 1rem; min-height: 0; }
|
|
.form-handy .ef-rahmen { max-width: 280px; }
|
|
.ef-titel { font-size: 1.4rem; }
|
|
.ef-kopf .form-select.ef-kapitel { margin-left: 0; flex: 1 1 12rem; }
|
|
.ef-punkte-nav { display: none; }
|
|
.ef-fuss { justify-content: space-between; position: sticky; bottom: 0; padding: .6rem 0; background: var(--ton-grund, #191d20); z-index: 5; }
|
|
}
|
|
|
|
/* Ansicht umschalten: eine Klasse mehr als Bootstrap (solar.css laedt vorher). */
|
|
.zl-ansicht .btn.active {
|
|
background: rgba(0, 120, 143, .25);
|
|
border-color: #00788F;
|
|
color: var(--ton-schrift, #e8ede9);
|
|
}
|
|
|
|
/* ==========================================================================
|
|
Energiefluss-Übersicht (js/solar/energiefluss.js, Katalog in
|
|
js/solar/energieflussKatalog.js).
|
|
|
|
Farben je Kreis kommen als --farbe aus dem Katalog, Breite und Tempo der
|
|
Flüsse als --breite/--dauer aus dem Renderer. Alles Übrige steht hier.
|
|
Transformationen liegen nie auf Elementen mit transform-Attribut (Kreis-
|
|
gruppe, Plakette) - CSS würde deren Lage überschreiben.
|
|
========================================================================== */
|
|
.enf-behaelter { position: relative; }
|
|
svg.enf {
|
|
display: block; width: 100%; height: auto; max-height: 80vh;
|
|
font-family: "Poppins", system-ui, sans-serif;
|
|
user-select: none; -webkit-tap-highlight-color: transparent;
|
|
}
|
|
svg.enf.enf-hoch { max-height: none; }
|
|
|
|
/* --- Kreis ------------------------------------------------------------- */
|
|
.enf .enf-hof { fill: #1c2024; stroke: rgba(255, 255, 255, .06); stroke-width: 1.5; transition: stroke .3s, stroke-width .3s; }
|
|
.enf .enf-spur { fill: none; stroke: #2b3139; stroke-width: 14; }
|
|
.enf .enf-bogen {
|
|
fill: none; stroke-width: 14; stroke-dasharray: 0 100;
|
|
transition: stroke-dasharray 1s cubic-bezier(.2, .7, .2, 1), stroke-dashoffset 1s cubic-bezier(.2, .7, .2, 1), stroke .4s;
|
|
}
|
|
.enf .enf-scheibe { fill: #20252b; }
|
|
.enf .enf-wert { fill: var(--ton-schrift, #e8ede9); font-size: 32px; font-weight: 600; text-anchor: middle; font-variant-numeric: tabular-nums; }
|
|
.enf .enf-neben { fill: var(--ton-schrift-2, #9aa6ad); font-size: 14.5px; text-anchor: middle; font-variant-numeric: tabular-nums; }
|
|
.enf .enf-name {
|
|
fill: var(--ton-schrift-2, #9aa6ad); font-size: 16px; font-weight: 600; text-anchor: middle; letter-spacing: .08em; text-transform: uppercase;
|
|
/* Kontur in Kartenfarbe: bleibt lesbar, wo ein Fluss unter dem Namen durchlaeuft. */
|
|
paint-order: stroke; stroke: var(--ton-flaeche, #23282c); stroke-width: 7px; stroke-linejoin: round;
|
|
}
|
|
|
|
.enf .enf-koerper { transform-box: view-box; transform-origin: 0 0; transition: transform .3s cubic-bezier(.2, .7, .2, 1), opacity .6s; }
|
|
.enf .enf-ruhe .enf-koerper { opacity: .6; }
|
|
.enf .enf-ruhe .enf-name { opacity: .7; }
|
|
.enf .enf-aus { opacity: .3; }
|
|
.enf .enf-aus .enf-spur { stroke-dasharray: 8 8; }
|
|
|
|
.enf .enf-klickbar { cursor: pointer; outline: none; }
|
|
.enf .enf-klickbar:hover .enf-koerper { transform: scale(1.045); }
|
|
.enf .enf-klickbar:hover .enf-hof,
|
|
.enf .enf-klickbar:focus-visible .enf-hof { stroke: var(--farbe); stroke-width: 3; }
|
|
.enf .enf-tipp circle { fill: #262c33; stroke: #3a424b; stroke-width: 1.5; }
|
|
.enf .enf-tipp path { fill: none; stroke: var(--farbe); stroke-width: 2.6; stroke-linecap: round; stroke-linejoin: round; transition: transform .25s; }
|
|
.enf .enf-klickbar:hover .enf-tipp path { transform: translateX(2px); }
|
|
|
|
/* --- Füllstand als Welle ------------------------------------------------ */
|
|
.enf .enf-fuellung {
|
|
--r: 67;
|
|
transform: translateY(calc(var(--r) * (1 - 2 * var(--stand)) * 1px));
|
|
transition: transform 1.4s cubic-bezier(.2, .7, .2, 1);
|
|
}
|
|
.enf .enf-welle { fill: var(--farbe); fill-opacity: .14; animation: enf-wogen 8s linear infinite; }
|
|
@keyframes enf-wogen { to { transform: translateX(calc(var(--r) * 2px)); } }
|
|
|
|
/* --- Symbole ------------------------------------------------------------ */
|
|
.enf .enf-symbol { color: var(--farbe); fill: none; stroke: currentColor; stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round; }
|
|
.enf .enf-s-fein { stroke-width: 1.1; opacity: .75; }
|
|
.enf .enf-s-kern { fill: currentColor; fill-opacity: .2; transition: fill-opacity .6s; }
|
|
.enf .enf-an .enf-s-kern { fill-opacity: .55; }
|
|
.enf .enf-s-strahlen { transform-box: view-box; transform-origin: 0 0; opacity: .55; transition: opacity .6s; }
|
|
.enf .enf-an .enf-s-strahlen { opacity: 1; animation: enf-drehen 30s linear infinite; }
|
|
@keyframes enf-drehen { to { transform: rotate(360deg); } }
|
|
|
|
.enf .enf-s-stand {
|
|
fill: currentColor; stroke: none; opacity: .45;
|
|
transform-box: fill-box; transform-origin: 50% 100%;
|
|
transform: scaleY(var(--stand, 0)); transition: transform 1.2s cubic-bezier(.2, .7, .2, 1);
|
|
}
|
|
.enf .enf-s-blitz { fill: currentColor; stroke: none; opacity: 0; transition: opacity .4s; }
|
|
.enf .enf-sym-akku .enf-s-blitz { fill: #fff; }
|
|
.enf .enf-s-blitz.enf-s-an,
|
|
.enf .enf-laden .enf-s-blitz,
|
|
.enf .enf-an.enf-knoten .enf-sym-wallbox .enf-s-blitz { opacity: 1; }
|
|
.enf .enf-laden .enf-s-blitz,
|
|
.enf .enf-an .enf-sym-wallbox .enf-s-blitz { animation: enf-puls 1.8s ease-in-out infinite; }
|
|
@keyframes enf-puls { 50% { opacity: .35; } }
|
|
|
|
.enf .enf-an .enf-s-welle { animation: enf-puls 1.4s ease-in-out infinite; }
|
|
.enf .enf-s-ebene { fill: currentColor; stroke: none; opacity: .38; }
|
|
.enf .enf-an .enf-sym-wallbox .enf-s-kabel { stroke-dasharray: 2.4 2.4; animation: enf-kabel .9s linear infinite; }
|
|
@keyframes enf-kabel { to { stroke-dashoffset: -4.8; } }
|
|
.enf .enf-s-temps rect { stroke: none; fill: #2b3139; opacity: .9; transition: fill 1.5s; }
|
|
.enf .enf-s-spirale { stroke-width: 1.3; transition: stroke .4s; }
|
|
.enf .enf-an .enf-s-spirale { stroke: #ffb04a; animation: enf-gluehen 1.1s ease-in-out infinite alternate; }
|
|
@keyframes enf-gluehen { to { stroke: #ff5a2a; } }
|
|
|
|
/* --- Plaketten ---------------------------------------------------------- */
|
|
.enf .enf-plakette { animation: enf-einblenden .5s both; animation-delay: calc(var(--i) * 80ms); }
|
|
.enf .enf-plakette circle,
|
|
.enf .enf-plakette rect { fill: #1c2024; stroke: var(--pfarbe); stroke-width: 2; }
|
|
.enf .enf-plakette-glyph { font-family: bootstrap-icons; font-size: 16px; fill: var(--pfarbe); text-anchor: middle; dominant-baseline: central; }
|
|
.enf .enf-plakette-text { font-size: 14px; font-weight: 600; fill: var(--ton-schrift, #e8ede9); dominant-baseline: central; }
|
|
|
|
/* --- Bewässerung --------------------------------------------------------- */
|
|
.enf .enf-zone-glyph { font-family: bootstrap-icons; font-size: 17px; fill: currentColor; color: #6c757d; text-anchor: middle; dominant-baseline: central; transition: color .4s; }
|
|
.enf .enf-zone-bild { color: #6c757d; fill: none; stroke: currentColor; stroke-width: 1.7; stroke-linecap: round; stroke-linejoin: round; transition: color .4s; }
|
|
.enf .enf-zone-name { font-size: 15px; fill: var(--ton-schrift-2, #9aa6ad); dominant-baseline: central; }
|
|
.enf .enf-zone-status { font-size: 15px; font-weight: 600; fill: var(--ton-schrift, #e8ede9); text-anchor: end; dominant-baseline: central; font-variant-numeric: tabular-nums; }
|
|
|
|
/* --- Flüsse -------------------------------------------------------------- */
|
|
.enf .enf-bett {
|
|
fill: none; stroke: #252b31; stroke-linecap: round;
|
|
stroke-width: calc(var(--breite, 0) * 1px + 5px);
|
|
stroke-dasharray: 1 1; stroke-dashoffset: 1;
|
|
transition: stroke-width .8s;
|
|
animation: enf-zeichnen .9s cubic-bezier(.5, 0, .2, 1) forwards; animation-delay: var(--verz);
|
|
}
|
|
@keyframes enf-zeichnen { to { stroke-dashoffset: 0; } }
|
|
.enf .enf-strom,
|
|
.enf .enf-strom-hof {
|
|
fill: none; stroke: var(--farbe); stroke-linecap: round;
|
|
stroke-dasharray: 0 20;
|
|
/* Stufen statt stetig: stroke-dashoffset laeuft nicht auf dem Compositor,
|
|
jede Stufe ist ein Neuzeichnen. 20 je Abschnitt sehen fluessig aus. */
|
|
animation: enf-fliessen var(--dauer, 1.5s) steps(20) infinite;
|
|
transition: stroke-width .8s, opacity .6s;
|
|
}
|
|
.enf .enf-strom { stroke-width: calc(var(--breite, 0) * 1px); }
|
|
.enf .enf-strom-hof { stroke-width: calc(var(--breite, 0) * 1.9px); opacity: .14; }
|
|
.enf .enf-rueck .enf-strom,
|
|
.enf .enf-rueck .enf-strom-hof { animation-direction: reverse; }
|
|
.enf .enf-still .enf-strom,
|
|
.enf .enf-still .enf-strom-hof { opacity: 0; animation: none; }
|
|
@keyframes enf-fliessen { to { stroke-dashoffset: -20; } }
|
|
|
|
/* --- Auftritt ------------------------------------------------------------ */
|
|
.enf .enf-koerper { animation: enf-erscheinen .7s cubic-bezier(.2, .9, .3, 1.25) backwards; animation-delay: var(--verz); }
|
|
.enf .enf-name { animation: enf-einblenden .7s backwards; animation-delay: calc(var(--verz) + 150ms); }
|
|
@keyframes enf-erscheinen { from { opacity: 0; transform: scale(.55); } }
|
|
@keyframes enf-einblenden { from { opacity: 0; } }
|
|
|
|
.enf.enf-pause,
|
|
.enf.enf-pause * { animation-play-state: paused !important; }
|
|
|
|
/* --- Bearbeiten (Einstellungen) ------------------------------------------ */
|
|
.enf.enf-bearbeiten .enf-koerper,
|
|
.enf.enf-bearbeiten .enf-name,
|
|
.enf.enf-bearbeiten .enf-bett { animation: none; stroke-dashoffset: 0; }
|
|
.enf.enf-bearbeiten .enf-ziehbar { cursor: grab; touch-action: none; }
|
|
.enf.enf-bearbeiten .enf-zieht { cursor: grabbing; }
|
|
.enf.enf-bearbeiten .enf-zieht .enf-hof { stroke: var(--farbe); stroke-width: 3; }
|
|
|
|
@media (prefers-reduced-motion: reduce) {
|
|
.enf, .enf * { animation: none !important; transition: none !important; }
|
|
.enf .enf-bett { stroke-dashoffset: 0; }
|
|
}
|
|
|
|
/* --- Einstellungen: Reiter "Übersicht" ------------------------------------ */
|
|
.enf-vorschau { background: var(--ton-grund, #191d20); border-radius: var(--ton-radius, .875rem); padding: .5rem; position: sticky; top: 4.5rem; }
|
|
.enf-e-zeile {
|
|
display: grid; grid-template-columns: auto minmax(0, 1fr) auto 1.2rem; gap: .35rem .7rem; align-items: center;
|
|
padding: .45rem 0; border-bottom: 1px solid var(--ton-linie, rgba(138, 148, 158, .2));
|
|
}
|
|
.enf-e-zeile.enf-e-aus .enf-e-name { opacity: .5; }
|
|
.enf-e-name { display: flex; align-items: center; gap: .55rem; margin: 0; }
|
|
.enf-e-punkt { flex: 0 0 auto; width: .7rem; height: .7rem; border-radius: 50%; background: var(--farbe); box-shadow: 0 0 0 3px color-mix(in srgb, var(--farbe) 22%, transparent); }
|
|
.enf-e-eltern { white-space: nowrap; }
|
|
.enf-e-flaechen { grid-column: 2 / -1; padding: .2rem 0 .3rem; }
|
|
.enf-e-flaeche { display: grid; grid-template-columns: 2.2rem minmax(0, 1fr) 4.2rem 4.2rem 1.2rem; gap: .35rem; align-items: center; margin-bottom: .3rem; }
|
|
.enf-e-flaeche .form-control.form-control-color { width: 2.2rem; height: 1.9rem; padding: .15rem; }
|
|
|
|
/* ==========================================================================
|
|
Anlage-Ansicht (js/solar/anlage.js, Katalog js/solar/anlageKatalog.js).
|
|
Dieselben Töne wie die Energiefluss-Übersicht.
|
|
========================================================================== */
|
|
.anl { display: grid; gap: .9rem; }
|
|
.anl .anl-flaechen { display: grid; grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr)); gap: .6rem; }
|
|
.anl .anl-flaeche { background: var(--ton-grund, #191d20); border-radius: .8rem; padding: .6rem .85rem .55rem; display: grid; gap: .35rem; }
|
|
.anl .anl-flaeche-kopf { display: flex; align-items: baseline; gap: .5rem; }
|
|
.anl .anl-flaeche-kopf i { width: .6rem; height: .6rem; border-radius: 50%; background: var(--farbe); align-self: center; box-shadow: 0 0 0 3px color-mix(in srgb, var(--farbe) 25%, transparent); }
|
|
.anl .anl-flaeche-kopf span { font-weight: 600; color: var(--ton-schrift, #e8ede9); }
|
|
.anl .anl-flaeche-kopf b { margin-left: auto; font-size: 1.2rem; font-weight: 600; font-variant-numeric: tabular-nums; }
|
|
.anl .anl-flaeche-balken { height: 5px; border-radius: 3px; background: #2b3139; overflow: hidden; }
|
|
.anl .anl-flaeche-balken span { display: block; height: 100%; background: var(--farbe); border-radius: 3px; transition: width 1s cubic-bezier(.2, .7, .2, 1); }
|
|
.anl .anl-flaeche small { color: var(--ton-schrift-3, #6f7a81); font-size: .76rem; }
|
|
@media (max-width: 575.98px) {
|
|
/* Auf dem Handy drei schmale Kacheln nebeneinander statt drei Zeilen. */
|
|
.anl .anl-flaechen { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: .4rem; }
|
|
.anl .anl-flaeche { padding: .45rem .55rem; }
|
|
.anl .anl-flaeche-kopf { flex-wrap: wrap; gap: .1rem .4rem; }
|
|
.anl .anl-flaeche-kopf span { font-size: .8rem; }
|
|
.anl .anl-flaeche-kopf b { margin-left: 0; width: 100%; font-size: 1rem; }
|
|
.anl .anl-flaeche small { display: none; }
|
|
}
|
|
|
|
.anl .anl-plan-rahmen { background: var(--ton-grund, #191d20); border-radius: .9rem; padding: .4rem; }
|
|
svg.anl-plan { display: block; width: 100%; height: auto; max-height: 72vh; font-family: "Poppins", system-ui, sans-serif; user-select: none; -webkit-tap-highlight-color: transparent; }
|
|
svg.anl-plan.anl-hoch { max-height: none; }
|
|
|
|
.anl-plan .anl-dachflaeche { fill: var(--farbe); fill-opacity: .06; stroke: var(--farbe); stroke-opacity: .18; stroke-width: 22; stroke-linejoin: round; }
|
|
.anl-plan .anl-bereich { fill: var(--farbe); fill-opacity: .035; stroke: var(--farbe); stroke-opacity: .25; stroke-width: 2; stroke-dasharray: 7 7; }
|
|
|
|
.anl-plan .anl-teil { transform-box: fill-box; transform-origin: center; animation: anl-auf .55s cubic-bezier(.2, .9, .3, 1.2) backwards; animation-delay: calc(var(--d) * 1ms); }
|
|
@keyframes anl-auf { from { opacity: 0; transform: scale(.4); } }
|
|
.anl-plan .anl-koerper { fill: #2f353c; stroke: rgba(255, 255, 255, .1); stroke-width: 1; transition: fill 1s, stroke .2s, stroke-width .2s; }
|
|
.anl-plan .anl-platte .anl-koerper,
|
|
.anl-plan .anl-string .anl-koerper { fill: var(--fuellung, #3b3a32); }
|
|
.anl-plan .anl-platte.anl-offline .anl-koerper { fill: #262b31; stroke: #5c646d; stroke-dasharray: 4 3; }
|
|
.anl-plan .anl-zellen,
|
|
.anl-plan .anl-glanz { pointer-events: none; }
|
|
.anl-plan .anl-glanz { fill: #fff; opacity: 0; }
|
|
/* Lichtwelle: jede Platte hellt kurz auf, versetzt nach ihrer Lage. */
|
|
.anl-plan.anl-sonnig .anl-hell .anl-glanz {
|
|
animation: anl-glanz 7s ease-in-out infinite; animation-delay: calc(var(--glanz) * 7s); }
|
|
@keyframes anl-glanz { 0%, 100% { opacity: 0; } 7% { opacity: .3; } 15% { opacity: 0; } }
|
|
|
|
.anl-plan .anl-platte,
|
|
.anl-plan .anl-string { cursor: pointer; }
|
|
.anl-plan .anl-platte:hover .anl-koerper,
|
|
.anl-plan .anl-string:hover .anl-koerper { stroke: rgba(255, 255, 255, .7); stroke-width: 2; }
|
|
.anl-plan .anl-geschwister .anl-koerper { stroke: #e3e6ea; stroke-width: 2; stroke-dasharray: 6 4; }
|
|
.anl-plan .anl-gewaehlt .anl-koerper { stroke: #fff; stroke-width: 3.5; stroke-dasharray: none; }
|
|
|
|
.anl-plan .anl-w { font-size: 17px; font-weight: 600; fill: #c9d0d6; text-anchor: middle; dominant-baseline: central; pointer-events: none; font-variant-numeric: tabular-nums; }
|
|
.anl-plan .anl-hell .anl-w { fill: #15181c; }
|
|
.anl-plan .anl-offline .anl-w { fill: #8d96a0; }
|
|
.anl-plan.anl-klein .anl-w { display: none; }
|
|
|
|
.anl-plan .anl-warnung { display: none; pointer-events: none; }
|
|
.anl-plan .anl-schwach .anl-warnung { display: inline; }
|
|
.anl-plan .anl-warnung circle { fill: #e5624f; stroke: #1c2024; stroke-width: 2; }
|
|
.anl-plan .anl-warnung .anl-warnung-hof { stroke: none; opacity: .5; transform-box: fill-box; transform-origin: center; animation: anl-puls 1.8s ease-out infinite; }
|
|
@keyframes anl-puls { from { transform: scale(.6); opacity: .6; } to { transform: scale(1.5); opacity: 0; } }
|
|
.anl-plan .anl-warnung text { fill: #fff; font-size: 13px; font-weight: 700; text-anchor: middle; dominant-baseline: central; }
|
|
|
|
.anl-plan .anl-schild { pointer-events: none; }
|
|
.anl-plan .anl-schild rect { fill: rgba(21, 24, 28, .86); stroke: rgba(255, 255, 255, .08); }
|
|
.anl-plan .anl-schild-wert { font-size: 23px; font-weight: 600; fill: var(--ton-schrift, #e8ede9); text-anchor: middle; dominant-baseline: central; font-variant-numeric: tabular-nums; }
|
|
.anl-plan .anl-schild-name { font-size: 11px; font-weight: 600; fill: var(--ton-schrift-2, #9aa6ad); text-anchor: middle; dominant-baseline: central; text-transform: uppercase; letter-spacing: .08em; }
|
|
.anl-plan .anl-nord path { fill: #808090; }
|
|
.anl-plan .anl-nord text { fill: #808090; font-size: 15px; font-weight: 600; text-anchor: middle; }
|
|
.anl-plan.anl-pause,
|
|
.anl-plan.anl-pause * { animation-play-state: paused !important; }
|
|
|
|
.anl .anl-legende { display: flex; flex-wrap: wrap; gap: .3rem 1.1rem; font-size: .78rem; color: var(--ton-schrift-2, #9aa6ad); padding: 0 .3rem; }
|
|
.anl .anl-legende i { display: inline-block; width: .75rem; height: .75rem; border-radius: 3px; margin-right: .35rem; vertical-align: -.1rem; }
|
|
.anl .anl-l-verlauf { width: 2.6rem !important; background: linear-gradient(90deg, #3b3a32, #f7c000); }
|
|
.anl .anl-l-warnung { background: #e5624f; border-radius: 50% !important; color: #fff; font-style: normal; font-size: .6rem; font-weight: 700; text-align: center; line-height: .75rem; }
|
|
.anl .anl-l-offline { background: #262b31; box-shadow: inset 0 0 0 1px #5c646d; }
|
|
|
|
.anl .anl-unten { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: .9rem; align-items: start; }
|
|
@media (max-width: 860px) { .anl .anl-unten { grid-template-columns: minmax(0, 1fr); } }
|
|
.anl .anl-fach { background: var(--ton-grund, #191d20); border-radius: .9rem; padding: .9rem 1rem; display: grid; gap: .7rem; align-content: start; }
|
|
.anl .anl-ueberschrift { font-size: .78rem; font-weight: 600; text-transform: uppercase; letter-spacing: .08em; color: var(--ton-schrift-2, #9aa6ad); margin: 0; }
|
|
.anl .anl-kopf { display: flex; justify-content: space-between; align-items: center; gap: .6rem; }
|
|
.anl .anl-pille { font-size: .72rem; font-weight: 600; border-radius: 99px; padding: .1rem .55rem; white-space: nowrap; color: var(--ton-schrift-2, #9aa6ad); background: rgba(255, 255, 255, .06); }
|
|
.anl .anl-pille.anl-ok { color: #6cbe58; background: rgba(108, 190, 88, .13); }
|
|
.anl .anl-pille.anl-warn { color: #e8a33a; background: rgba(232, 163, 58, .14); }
|
|
.anl .anl-pille.anl-krit { color: #e5624f; background: rgba(229, 98, 79, .14); }
|
|
.anl .anl-gross { display: flex; flex-wrap: wrap; align-items: baseline; gap: .2rem .8rem; }
|
|
.anl .anl-gross b { font-size: 2rem; font-weight: 600; line-height: 1.1; font-variant-numeric: tabular-nums; color: var(--ton-schrift, #e8ede9); }
|
|
.anl .anl-gross span { color: var(--ton-schrift-2, #9aa6ad); font-size: .88rem; }
|
|
.anl .anl-funken { width: 100%; height: auto; display: block; }
|
|
.anl .anl-gitter { stroke: #2a3037; }
|
|
.anl .anl-funken-flaeche { fill: rgba(247, 192, 0, .14); }
|
|
.anl .anl-funken-linie { fill: none; stroke: #f7c000; stroke-width: 2; stroke-linejoin: round; }
|
|
.anl .anl-funken-punkt { fill: #f7c000; }
|
|
.anl .anl-achse { fill: var(--ton-schrift-3, #6f7a81); font-size: 10px; }
|
|
.anl .anl-funken-leer { color: var(--ton-schrift-3, #6f7a81); font-size: .82rem; padding: .7rem 0; }
|
|
.anl .anl-paare { display: grid; grid-template-columns: auto 1fr; gap: .25rem .9rem; font-size: .88rem; margin: 0; }
|
|
.anl .anl-paare dt { color: var(--ton-schrift-2, #9aa6ad); font-weight: 400; }
|
|
.anl .anl-paare dd { margin: 0; text-align: right; font-variant-numeric: tabular-nums; }
|
|
.anl .anl-hinweis { font-size: .84rem; color: var(--ton-schrift-2, #9aa6ad); margin: 0; }
|
|
.anl button.anl-link { all: unset; cursor: pointer; color: #8fb8de; }
|
|
.anl button.anl-link:hover { text-decoration: underline; }
|
|
|
|
.anl .anl-wr,
|
|
.anl .anl-eingaenge,
|
|
.anl .anl-hinweise { list-style: none; margin: 0; padding: 0; display: grid; gap: .15rem; }
|
|
.anl .anl-wr button,
|
|
.anl .anl-eingaenge button,
|
|
.anl .anl-hinweise button { all: unset; box-sizing: border-box; cursor: pointer; width: 100%; border-radius: .5rem; padding: .42rem .55rem; transition: background .2s; }
|
|
.anl .anl-wr button:hover,
|
|
.anl .anl-eingaenge button:hover,
|
|
.anl .anl-hinweise button:hover { background: var(--ton-flaeche-2, #2b3237); }
|
|
.anl .anl-wr button:focus-visible,
|
|
.anl .anl-eingaenge button:focus-visible,
|
|
.anl .anl-hinweise button:focus-visible,
|
|
.anl button.anl-link:focus-visible { outline: 2px solid #8fb8de; outline-offset: 1px; }
|
|
.anl .anl-wr button { display: grid; grid-template-columns: minmax(0, 1fr) auto 6.5rem; gap: .7rem; align-items: center; font-size: .9rem; }
|
|
.anl .anl-wr button > .anl-pille { justify-self: end; }
|
|
.anl .anl-wr button[aria-pressed="true"] { background: var(--ton-flaeche-2, #2b3237); box-shadow: inset 3px 0 0 #f7c000; }
|
|
.anl .anl-wr-name small { display: block; color: var(--ton-schrift-3, #6f7a81); font-size: .74rem; }
|
|
.anl .anl-wr-wert { text-align: right; font-variant-numeric: tabular-nums; font-weight: 600; }
|
|
.anl .anl-wr-last { display: block; width: 4rem; height: 3px; margin: .25rem 0 0 auto; border-radius: 2px; background: #2b3139; overflow: hidden; }
|
|
.anl .anl-wr-last span { display: block; height: 100%; background: #f7c000; transition: width 1s; }
|
|
.anl .anl-eingaenge button { display: grid; grid-template-columns: 6.5rem minmax(0, 1fr) 4.2rem; gap: .6rem; align-items: center; font-size: .86rem; }
|
|
.anl .anl-eingaenge b { text-align: right; font-weight: 600; font-variant-numeric: tabular-nums; }
|
|
.anl .anl-balken { height: 7px; border-radius: 4px; background: #2b3139; overflow: hidden; }
|
|
.anl .anl-balken span { display: block; height: 100%; border-radius: 4px; background: #f7c000; transition: width .8s cubic-bezier(.2, .7, .2, 1); }
|
|
.anl .anl-balken.anl-mittel span { background: #c98a22; }
|
|
.anl .anl-balken.anl-schwach span { background: #e5624f; }
|
|
.anl .anl-balken.anl-offline span,
|
|
.anl .anl-balken.anl-dunkel span { background: #5c646d; }
|
|
.anl .anl-hinweise button { display: flex; align-items: center; gap: .6rem; font-size: .88rem; }
|
|
|
|
@media (prefers-reduced-motion: reduce) {
|
|
.anl *, .anl-plan * { animation: none !important; transition: none !important; }
|
|
}
|
|
|
|
/* ==========================================================================
|
|
Speicher-Ansicht (js/solar/speicher.js). Töne wie Übersicht und Anlage.
|
|
========================================================================== */
|
|
.spk { display: grid; gap: .9rem; }
|
|
.spk .spk-meldung { border-radius: .7rem; padding: .55rem .9rem; font-size: .88rem; background: rgba(232, 163, 58, .12); color: #e8a33a; }
|
|
.spk .spk-meldung.spk-fehler { background: rgba(229, 98, 79, .14); color: #e5624f; }
|
|
.spk .spk-fach { background: var(--ton-grund, #191d20); border-radius: .9rem; padding: .9rem 1rem; display: grid; gap: .7rem; align-content: start; min-width: 0; }
|
|
.spk .spk-kopf { display: flex; flex-wrap: wrap; justify-content: space-between; align-items: center; gap: .4rem .8rem; }
|
|
.spk .spk-ueberschrift { font-size: .78rem; font-weight: 600; text-transform: uppercase; letter-spacing: .08em; color: var(--ton-schrift-2, #9aa6ad); margin: 0; }
|
|
.spk .spk-stand { font-size: .78rem; color: var(--ton-schrift-3, #6f7a81); }
|
|
.spk .spk-leer { color: var(--ton-schrift-3, #6f7a81); font-size: .85rem; margin: .5rem 0; }
|
|
|
|
/* Kennzahlen */
|
|
.spk .spk-kennzahlen { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: .6rem; }
|
|
@media (max-width: 991.98px) { .spk .spk-kennzahlen { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
|
|
.spk .spk-notiz { font-size: .74rem; color: var(--ton-schrift-3, #6f7a81); margin-top: -.4rem; }
|
|
.spk .spk-einheit { font-weight: 600; }
|
|
.spk .spk-kachel { position: relative; background: var(--ton-grund, #191d20); border-radius: .8rem; padding: .65rem .85rem .7rem; display: grid; gap: .1rem; overflow: hidden; }
|
|
.spk .spk-kachel-titel { font-size: .74rem; color: var(--ton-schrift-2, #9aa6ad); display: flex; align-items: center; gap: .4rem; }
|
|
.spk .spk-kachel-titel i { font-family: bootstrap-icons; font-style: normal; font-size: .9rem; color: #6cbe58; }
|
|
.spk .spk-kachel b { font-size: 1.45rem; font-weight: 600; color: var(--ton-schrift, #e8ede9); font-variant-numeric: tabular-nums; line-height: 1.25; }
|
|
.spk .spk-kachel small { font-size: .74rem; color: var(--ton-schrift-3, #6f7a81); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
|
.spk .spk-kachel.spk-gut b { color: #8fd37a; }
|
|
.spk .spk-kachel.spk-warm b { color: #e8a33a; }
|
|
.spk .spk-kachel.spk-warm .spk-kachel-titel i { color: #e8a33a; }
|
|
.spk .spk-kachel.spk-krit b,
|
|
.spk .spk-kachel.spk-krit .spk-kachel-titel i { color: #e5624f; }
|
|
.spk .spk-kachel-balken { position: absolute; left: 0; right: 0; bottom: 0; height: 3px; background: #2b3139; }
|
|
.spk .spk-kachel-balken span { display: block; height: 100%; background: linear-gradient(90deg, #4f8fb8, #6cbe58); transition: width 1.2s cubic-bezier(.2, .7, .2, 1); }
|
|
|
|
/* Turm und Detail */
|
|
.spk .spk-mitte { display: grid; grid-template-columns: minmax(0, 1.25fr) minmax(0, 1fr); gap: .9rem; align-items: start; }
|
|
@media (max-width: 991.98px) { .spk .spk-mitte { grid-template-columns: minmax(0, 1fr); } }
|
|
.spk .spk-turm { position: relative; display: grid; gap: 4px; }
|
|
.spk .spk-bmu {
|
|
display: flex; align-items: center; gap: .6rem; padding: .5rem .8rem; font-size: .82rem;
|
|
background: linear-gradient(#2c3238, #24292f); border: 1px solid #333a42; border-radius: .7rem .7rem .25rem .25rem;
|
|
}
|
|
.spk .spk-bmu b { font-weight: 600; }
|
|
.spk .spk-bmu span:last-child { color: var(--ton-schrift-3, #6f7a81); font-size: .74rem; margin-left: auto; }
|
|
.spk .spk-led { width: .55rem; height: .55rem; border-radius: 50%; background: #444b53; }
|
|
.spk .spk-led.an { background: #6cbe58; box-shadow: 0 0 .5rem #6cbe58; animation: spk-led 2.4s ease-in-out infinite; }
|
|
@keyframes spk-led { 50% { opacity: .55; } }
|
|
.spk .spk-modul {
|
|
all: unset; box-sizing: border-box; cursor: pointer; position: relative; overflow: hidden;
|
|
display: grid; grid-template-columns: 2.2rem minmax(0, 1fr) 7.4rem; gap: .7rem; align-items: center;
|
|
padding: .45rem .7rem; border-radius: .25rem; border: 1px solid #2f363d;
|
|
background: linear-gradient(90deg, #1f2429, #262c32 50%, #1f2429);
|
|
transition: border-color .2s, box-shadow .2s;
|
|
animation: spk-modul-auf .5s cubic-bezier(.2, .9, .3, 1.1) backwards; animation-delay: calc(var(--i) * 45ms);
|
|
}
|
|
@keyframes spk-modul-auf { from { opacity: 0; transform: translateY(8px); } }
|
|
.spk .spk-modul:hover { border-color: #46505a; }
|
|
.spk .spk-modul:focus-visible { outline: 2px solid #8fb8de; outline-offset: 1px; }
|
|
.spk .spk-modul.gewaehlt { border-color: #6cbe58; box-shadow: inset 3px 0 0 #6cbe58; }
|
|
.spk .spk-nr { font-weight: 600; color: var(--ton-schrift-2, #9aa6ad); font-size: .9rem; }
|
|
.spk .spk-zellen { display: grid; grid-template-columns: repeat(16, minmax(0, 1fr)); gap: 2px; height: 2rem; align-items: end; }
|
|
.spk .spk-zellen i { display: block; height: var(--h); background: var(--f); border-radius: 2px 2px 1px 1px; transition: height 1s cubic-bezier(.2, .7, .2, 1), background 1s; }
|
|
.spk .spk-werte { text-align: right; line-height: 1.25; font-variant-numeric: tabular-nums; }
|
|
.spk .spk-werte b { display: block; font-size: .8rem; font-weight: 600; }
|
|
.spk .spk-werte small { font-size: .74rem; color: var(--ton-schrift-3, #6f7a81); }
|
|
.spk .spk-sockel { height: .6rem; margin-top: -2px; border-radius: 0 0 .6rem .6rem; background: #1a1e22; border: 1px solid #2f363d; border-top: 0; }
|
|
/* Laden: Licht wandert nach oben durch die Module, Entladen nach unten. */
|
|
.spk .spk-turm.spk-laden .spk-modul::after,
|
|
.spk .spk-turm.spk-entladen .spk-modul::after {
|
|
content: ""; position: absolute; inset: 0; pointer-events: none;
|
|
background: linear-gradient(90deg, transparent, rgba(108, 190, 88, .16), transparent);
|
|
transform: translateX(-100%); animation: spk-strom 2.6s ease-in-out infinite;
|
|
}
|
|
.spk .spk-turm.spk-laden .spk-modul::after { animation-delay: calc((8 - var(--i)) * 180ms); }
|
|
.spk .spk-turm.spk-entladen .spk-modul::after { background: linear-gradient(90deg, transparent, rgba(232, 163, 58, .14), transparent); animation-delay: calc(var(--i) * 180ms); }
|
|
@keyframes spk-strom { 0% { transform: translateX(-100%); } 60%, 100% { transform: translateX(100%); } }
|
|
.spk.spk-pause *,
|
|
.spk-pause .spk * { animation-play-state: paused !important; }
|
|
.spk .spk-legende { display: flex; flex-wrap: wrap; gap: .3rem 1rem; font-size: .76rem; color: var(--ton-schrift-2, #9aa6ad); }
|
|
.spk .spk-legende i { display: inline-block; width: .7rem; height: .7rem; border-radius: 2px; margin-right: .35rem; vertical-align: -.08rem; }
|
|
|
|
.spk .spk-pille { font-size: .72rem; font-weight: 600; border-radius: 99px; padding: .1rem .55rem; }
|
|
.spk .spk-pille.ok { color: #6cbe58; background: rgba(108, 190, 88, .13); }
|
|
.spk .spk-pille.warn { color: #e8a33a; background: rgba(232, 163, 58, .14); }
|
|
.spk .spk-gross { display: flex; flex-wrap: wrap; align-items: baseline; gap: .2rem .8rem; }
|
|
.spk .spk-gross b { font-size: 2rem; font-weight: 600; line-height: 1.1; color: var(--ton-schrift, #e8ede9); font-variant-numeric: tabular-nums; }
|
|
.spk .spk-gross span { color: var(--ton-schrift-2, #9aa6ad); font-size: .88rem; }
|
|
.spk .spk-zellchart { width: 100%; height: auto; display: block; }
|
|
.spk .spk-zelle { transform-box: fill-box; transform-origin: 50% 100%; animation: spk-zelle .6s cubic-bezier(.2, .9, .3, 1.1) backwards; animation-delay: calc(var(--j) * 25ms); }
|
|
.spk .spk-zelle.markiert { stroke: #fff; stroke-width: 1.5; }
|
|
@keyframes spk-zelle { from { transform: scaleY(0); } }
|
|
.spk .spk-gitter { stroke: #2a3037; stroke-width: 1; }
|
|
.spk .spk-mittel { stroke: #8d96a0; stroke-dasharray: 3 3; }
|
|
.spk .spk-achse { fill: var(--ton-schrift-3, #6f7a81); font-size: 10px; font-family: "Poppins", system-ui, sans-serif; }
|
|
.spk .spk-fuehler { display: grid; grid-template-columns: repeat(8, minmax(0, 1fr)); gap: 3px; }
|
|
.spk .spk-fuehler span { text-align: center; font-size: .74rem; font-weight: 600; padding: .2rem 0; border-radius: .3rem; color: #15181c; background: var(--f); font-variant-numeric: tabular-nums; }
|
|
.spk .spk-paare { display: grid; grid-template-columns: auto 1fr; gap: .25rem .9rem; font-size: .86rem; margin: 0; }
|
|
.spk .spk-paare dt { color: var(--ton-schrift-2, #9aa6ad); font-weight: 400; }
|
|
.spk .spk-paare dd { margin: 0; text-align: right; font-variant-numeric: tabular-nums; }
|
|
|
|
/* Verlauf */
|
|
.spk .spk-diagramme { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: .9rem; }
|
|
@media (max-width: 991.98px) { .spk .spk-diagramme { grid-template-columns: minmax(0, 1fr); } }
|
|
.spk .spk-zeitraum { display: inline-flex; gap: 2px; padding: 2px; border-radius: .5rem; background: #23282c; }
|
|
.spk .spk-zeitraum button { all: unset; cursor: pointer; font-size: .76rem; font-weight: 600; padding: .15rem .6rem; border-radius: .4rem; color: var(--ton-schrift-2, #9aa6ad); }
|
|
.spk .spk-zeitraum button.aktiv { background: #2f363d; color: var(--ton-schrift, #e8ede9); }
|
|
.spk .spk-zeitraum button:focus-visible { outline: 2px solid #8fb8de; }
|
|
.spk .spk-diagramm { position: relative; min-height: 190px; }
|
|
.spk .spk-verlauf { display: block; width: 100%; height: auto; touch-action: pan-y; }
|
|
.spk .spk-flaeche { opacity: .22; }
|
|
.spk .spk-linie { fill: none; stroke-width: 2; stroke-linejoin: round; stroke-linecap: round; }
|
|
.spk .spk-verlauf.neu .spk-linie { stroke-dasharray: 1 1; stroke-dashoffset: 1; animation: spk-zeichnen 1.2s cubic-bezier(.5, 0, .2, 1) forwards; animation-delay: calc(var(--i) * 150ms); }
|
|
.spk .spk-verlauf.neu .spk-flaeche { animation: spk-einblenden 1.2s backwards; }
|
|
@keyframes spk-zeichnen { to { stroke-dashoffset: 0; } }
|
|
@keyframes spk-einblenden { from { opacity: 0; } }
|
|
.spk .spk-zeiger { stroke: rgba(255, 255, 255, .35); stroke-width: 1; pointer-events: none; }
|
|
.spk .spk-tipp {
|
|
position: absolute; top: .4rem; z-index: 2; pointer-events: none; min-width: 9rem;
|
|
background: rgba(21, 24, 28, .94); border: 1px solid #333a42; border-radius: .55rem; padding: .4rem .6rem;
|
|
font-size: .76rem; display: grid; gap: .1rem; box-shadow: 0 .4rem 1rem rgba(0, 0, 0, .35);
|
|
}
|
|
.spk .spk-tipp b { font-weight: 600; margin-bottom: .1rem; }
|
|
.spk .spk-tipp span { display: flex; align-items: center; gap: .4rem; color: var(--ton-schrift-2, #9aa6ad); }
|
|
.spk .spk-tipp em { font-style: normal; margin-left: auto; padding-left: .8rem; color: var(--ton-schrift, #e8ede9); font-variant-numeric: tabular-nums; }
|
|
.spk .spk-tipp i,
|
|
.spk .spk-reihen i { display: inline-block; width: .6rem; height: .6rem; border-radius: 2px; }
|
|
.spk .spk-reihen { display: flex; flex-wrap: wrap; gap: .2rem 1rem; font-size: .76rem; color: var(--ton-schrift-2, #9aa6ad); margin-top: .2rem; }
|
|
.spk .spk-reihen span { display: inline-flex; align-items: center; gap: .35rem; }
|
|
@media (max-width: 575.98px) {
|
|
.spk .spk-kennzahlen { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: .45rem; }
|
|
.spk .spk-kachel b { font-size: 1.2rem; }
|
|
.spk .spk-modul { grid-template-columns: 1.8rem minmax(0, 1fr) 5.6rem; gap: .45rem; padding: .4rem .5rem; }
|
|
.spk .spk-werte b { font-size: .72rem; }
|
|
}
|
|
@media (prefers-reduced-motion: reduce) {
|
|
.spk *, .spk *::after { animation: none !important; transition: none !important; }
|
|
.spk .spk-verlauf.neu .spk-linie { stroke-dashoffset: 0; }
|
|
}
|
|
|
|
/* ==========================================================================
|
|
Anzeige-Modus (index.php?action=anzeige, js/solar/anzeige.js): die
|
|
Solar-Seite auf einem festen Display, z.B. Raspberry Pi mit 800 x 480.
|
|
Leiste links; die Realtime-Karte füllt genau einen Bildschirm, die
|
|
Diagramme folgen darunter und rasten beim Wischen karteweise ein.
|
|
========================================================================== */
|
|
html:has(body.anzeige) { scroll-snap-type: y proximity; scrollbar-width: none; }
|
|
html:has(body.anzeige)::-webkit-scrollbar { display: none; }
|
|
body.anzeige { -webkit-tap-highlight-color: transparent; }
|
|
body.anzeige-ohne-maus,
|
|
body.anzeige-ohne-maus * { cursor: none !important; }
|
|
|
|
.anzeige .anzeige-leiste {
|
|
position: fixed; left: 0; top: 0; bottom: 0; width: 3.2rem; z-index: 1030;
|
|
display: flex; flex-direction: column; align-items: center; gap: .4rem; padding: .5rem 0;
|
|
background: var(--ton-flaeche, #23282c); border-right: 1px solid var(--ton-linie, rgba(138, 148, 158, .2));
|
|
}
|
|
.anzeige .anzeige-leiste button {
|
|
all: unset; box-sizing: border-box; width: 2.6rem; height: 2.6rem; border-radius: .7rem;
|
|
display: grid; place-items: center; font-size: 1.3rem; color: var(--ton-schrift-2, #9aa6ad);
|
|
}
|
|
.anzeige .anzeige-leiste button[aria-pressed="true"] { background: var(--ton-flaeche-2, #2b3237); color: #f7c000; }
|
|
.anzeige .anzeige-fuss { margin-top: auto; display: grid; justify-items: center; gap: .3rem; }
|
|
.anzeige .anzeige-punkt { width: .6rem; height: .6rem; border-radius: 50%; background: #e5624f; }
|
|
.anzeige .anzeige-punkt.warn { background: #e8a33a; }
|
|
.anzeige .anzeige-punkt.gut { background: #6cbe58; }
|
|
.anzeige .anzeige-uhr { font-size: .72rem; font-weight: 600; color: var(--ton-schrift-2, #9aa6ad); font-variant-numeric: tabular-nums; }
|
|
|
|
.anzeige .app-wrapper { display: block; }
|
|
.anzeige .app-main { margin-left: 3.2rem; }
|
|
.anzeige .app-content-header { display: none; }
|
|
.anzeige .app-content { padding: 0 .35rem; }
|
|
.anzeige .app-content .container-fluid { padding: 0; }
|
|
.anzeige .app-content .row { --bs-gutter-x: 0; }
|
|
.anzeige .app-content .card { scroll-snap-align: start; }
|
|
|
|
/* Realtime-Karte: ein ganzer Bildschirm, ohne Kopf - die Leiste ersetzt ihn. */
|
|
.anzeige .card#energieflussKarte { height: 100vh; margin-bottom: .5rem !important; border: 0; border-radius: 0; background: transparent; }
|
|
.anzeige .card#energieflussKarte .card-header { display: none !important; }
|
|
.anzeige .card#energieflussKarte .card-body { height: 100%; padding: .2rem 0 !important; }
|
|
.anzeige #energiefluss { height: 100%; overflow: hidden; }
|
|
.anzeige #energiefluss svg.enf { width: 100%; height: 100%; max-height: none; }
|
|
.anzeige #anlage,
|
|
.anzeige #speicher { height: 100%; overflow-y: auto; scrollbar-width: none; }
|
|
|
|
/* Die Umbrüche von Anlage und Speicher richten sich nach der Fensterbreite
|
|
und würden am 800er-Display zu früh greifen. */
|
|
.anzeige .anl svg.anl-plan { max-height: calc(100vh - 7.5rem); }
|
|
.anzeige .spk .spk-kennzahlen { grid-template-columns: repeat(4, minmax(0, 1fr)); gap: .35rem; }
|
|
.anzeige .spk .spk-kachel { padding: .4rem .55rem .45rem; }
|
|
.anzeige .spk .spk-kachel b { font-size: 1.05rem; }
|
|
.anzeige .spk .spk-kachel small,
|
|
.anzeige .spk .spk-kachel-titel { font-size: .66rem; }
|
|
.anzeige .spk .spk-mitte,
|
|
.anzeige .spk .spk-diagramme { grid-template-columns: minmax(0, 1.15fr) minmax(0, 1fr); gap: .5rem; }
|
|
.anzeige .spk .spk-fach { padding: .6rem .7rem; gap: .5rem; }
|
|
.anzeige .spk .spk-modul { grid-template-columns: 1.7rem minmax(0, 1fr) 5.4rem; gap: .4rem; padding: .3rem .45rem; }
|
|
.anzeige .spk .spk-zellen { height: 1.4rem; }
|
|
.anzeige .spk .spk-werte b { font-size: .68rem; }
|
|
.anzeige .spk .spk-werte small { font-size: .62rem; }
|
|
.anzeige .spk .spk-gross b { font-size: 1.4rem; }
|
|
|
|
/* Bedienfenster: passen auf 480 px Höhe und lassen sich mit dem Finger bedienen. */
|
|
.anzeige .modal-dialog { margin: .4rem auto; }
|
|
.anzeige .modal-body { max-height: calc(100vh - 9rem); overflow-y: auto; }
|
|
.anzeige .modal .form-range { height: 2rem; }
|
|
.anzeige .modal .btn { min-height: 2.4rem; }
|
|
|
|
/* Ruhig (Vorgabe am Pi): alles Zierwerk aus, nur die Flüsse laufen - in
|
|
groben Stufen, damit ein Raspberry Pi 3 nicht dauernd neu zeichnet. */
|
|
.anzeige-ruhig *,
|
|
.anzeige-ruhig *::after { animation: none !important; }
|
|
.anzeige-ruhig .enf .enf-bett,
|
|
.anzeige-ruhig .spk .spk-verlauf.neu .spk-linie { stroke-dashoffset: 0; }
|
|
.anzeige-ruhig .enf .enf-strom-hof { display: none; }
|
|
.anzeige-ruhig .enf .enf-strom { animation: enf-fliessen var(--dauer, 1.5s) steps(8) infinite !important; }
|
|
.anzeige-ruhig .enf .enf-rueck .enf-strom { animation-direction: reverse !important; }
|
|
.anzeige-ruhig .enf .enf-still .enf-strom,
|
|
.anzeige-ruhig .enf.enf-pause .enf-strom { animation: none !important; }
|
|
.anzeige-ruhig .enf .enf-koerper { transition: none; }
|
|
|
|
/* ==========================================================================
|
|
Ladefenster der Wallboxen (ajax/carForm.php, js/solar/ladefenster.js).
|
|
Oben der Zustand, dann ein Knopf, darunter Modus, Planung, Strom.
|
|
========================================================================== */
|
|
.lade { display: grid; gap: 1rem; padding: 1rem 1.1rem 1.1rem; --lade-wallbox: #60afbf; }
|
|
.lade .lade-links,
|
|
.lade .lade-rechts { display: grid; gap: .9rem; align-content: start; min-width: 0; }
|
|
|
|
.lade .lade-status { display: grid; grid-template-columns: 7.5rem minmax(0, 1fr); gap: .9rem; align-items: center; }
|
|
.lade .lade-ring { position: relative; width: 7.5rem; height: 7.5rem; }
|
|
.lade .lade-ring svg { width: 100%; height: 100%; transform: rotate(-90deg); }
|
|
.lade .lade-spur { fill: none; stroke: #2b3237; stroke-width: 12; }
|
|
.lade .lade-ist { fill: none; stroke: #6cbe58; stroke-width: 12; stroke-linecap: round; stroke-dasharray: 0 100; transition: stroke-dasharray .7s cubic-bezier(.2, .7, .2, 1); }
|
|
.lade .lade-ziel { fill: none; stroke: var(--lade-wallbox); stroke-width: 12; opacity: .45; stroke-dasharray: 0 100; transition: stroke-dasharray .7s, stroke-dashoffset .7s; }
|
|
.lade .lade-ring-mitte { position: absolute; inset: 0; display: grid; place-content: center; text-align: center; }
|
|
.lade .lade-ring-mitte b { font-size: 1.55rem; font-weight: 600; line-height: 1; font-variant-numeric: tabular-nums; }
|
|
.lade .lade-ring-mitte span { font-size: .7rem; color: var(--lade-wallbox); font-weight: 600; margin-top: .25rem; }
|
|
.lade .lade-text { display: grid; gap: .25rem; min-width: 0; }
|
|
.lade .lade-auto { font-size: .8rem; color: var(--ton-schrift-2, #9aa6ad); display: flex; flex-wrap: wrap; align-items: center; gap: .4rem; }
|
|
.lade .lade-pille { font-size: .68rem; font-weight: 600; border-radius: 99px; padding: .05rem .5rem; background: rgba(255, 255, 255, .06); color: var(--ton-schrift-2, #9aa6ad); }
|
|
.lade .lade-pille:empty { display: none; }
|
|
.lade .lade-pille.an { color: #6cbe58; background: rgba(108, 190, 88, .14); }
|
|
.lade .lade-gross { font-size: 1.45rem; font-weight: 600; font-variant-numeric: tabular-nums; }
|
|
.lade .lade-gross small { font-size: .8rem; font-weight: 400; color: var(--ton-schrift-2, #9aa6ad); margin-left: .35rem; }
|
|
.lade .lade-zeile { font-size: .82rem; color: var(--ton-schrift-2, #9aa6ad); }
|
|
.lade .lade-zeile:empty { display: none; }
|
|
|
|
.lade .lade-start {
|
|
all: unset; box-sizing: border-box; cursor: pointer; display: flex; align-items: center; justify-content: center; gap: .6rem;
|
|
height: 3.1rem; border-radius: .9rem; font-weight: 600; font-size: 1rem;
|
|
background: linear-gradient(180deg, #6cbe58, #57a646); color: #0f1a0c; box-shadow: 0 .35rem 1rem rgba(108, 190, 88, .22);
|
|
transition: transform .15s, filter .2s;
|
|
}
|
|
.lade .lade-start:hover { filter: brightness(1.06); }
|
|
.lade .lade-start:active { transform: scale(.98); }
|
|
.lade .lade-start:focus-visible { outline: 2px solid #fff; outline-offset: 2px; }
|
|
.lade .lade-start.laeuft { background: linear-gradient(180deg, #3a4147, #30363b); color: var(--ton-schrift, #e8ede9); box-shadow: none; border: 1px solid var(--ton-linie, rgba(138, 148, 158, .2)); }
|
|
.lade .lade-start.aus { background: #2b3237; color: var(--ton-schrift-3, #6f7a81); box-shadow: none; cursor: default; }
|
|
.lade .lade-start.aus .lade-punkt { display: none; }
|
|
.lade .lade-start.gesperrt { background: linear-gradient(180deg, #e8a33a, #cf8f2c); color: #1d1406; box-shadow: 0 .35rem 1rem rgba(232, 163, 58, .2); }
|
|
.lade .lade-punkt { width: .55rem; height: .55rem; border-radius: 50%; background: currentColor; }
|
|
.lade .lade-start.laeuft .lade-punkt { background: #6cbe58; animation: lade-puls 1.6s infinite; }
|
|
@keyframes lade-puls { 0% { box-shadow: 0 0 0 0 rgba(108, 190, 88, .6); } 70%, 100% { box-shadow: 0 0 0 .5rem rgba(108, 190, 88, 0); } }
|
|
.lade .lade-erklaerung { padding: .5rem .7rem; border-radius: .6rem; background: rgba(96, 175, 191, .1); color: #bfe3ea; font-size: .8rem; }
|
|
.lade .lade-erklaerung:empty { display: none; }
|
|
|
|
.lade .lade-abschnitt { display: grid; gap: .45rem; }
|
|
.lade h3 { margin: 0; font-size: .7rem; font-weight: 600; letter-spacing: .08em; text-transform: uppercase; color: var(--ton-schrift-2, #9aa6ad); }
|
|
.lade .lade-modi { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: .45rem; }
|
|
.lade .lade-modus {
|
|
all: unset; box-sizing: border-box; cursor: pointer; display: grid; gap: .2rem; justify-items: start; padding: .6rem .65rem;
|
|
border-radius: .75rem; background: var(--ton-flaeche-2, #2b3237); border: 1.5px solid transparent; transition: border-color .2s, background .2s;
|
|
}
|
|
.lade .lade-modus:hover { background: #333b41; }
|
|
.lade .lade-modus:focus-visible { outline: 2px solid var(--lade-wallbox); outline-offset: 1px; }
|
|
.lade .lade-modus b { font-weight: 600; font-size: .88rem; }
|
|
.lade .lade-modus > span:last-child { font-size: .7rem; color: var(--ton-schrift-2, #9aa6ad); line-height: 1.3; }
|
|
.lade .lade-sym { width: 1.7rem; height: 1.7rem; border-radius: .5rem; display: grid; place-items: center; background: rgba(255, 255, 255, .06); }
|
|
.lade .lade-sym svg { width: 1.1rem; height: 1.1rem; stroke: var(--c); fill: none; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
|
|
.lade .lade-modus[aria-checked="true"] { border-color: var(--c); background: color-mix(in srgb, var(--c) 12%, var(--ton-flaeche-2, #2b3237)); }
|
|
.lade .lade-modus[aria-checked="true"] .lade-sym { background: color-mix(in srgb, var(--c) 25%, transparent); }
|
|
|
|
.lade .lade-planung { display: grid; gap: .7rem; padding: .7rem .75rem; border-radius: .75rem; background: var(--ton-flaeche-2, #2b3237); animation: lade-auf .3s cubic-bezier(.2, .7, .2, 1); }
|
|
.lade .lade-planung[hidden] { display: none; }
|
|
@keyframes lade-auf { from { opacity: 0; transform: translateY(-.35rem); } }
|
|
.lade .lade-plan-zeile { display: flex; justify-content: space-between; align-items: baseline; gap: .5rem; }
|
|
.lade .lade-plan-zeile label { font-size: .82rem; color: var(--ton-schrift-2, #9aa6ad); margin: 0; }
|
|
.lade .lade-plan-zeile output { font-weight: 600; font-variant-numeric: tabular-nums; }
|
|
.lade .lade-plan-zeile output small { color: var(--ton-schrift-2, #9aa6ad); font-weight: 400; margin-left: .3rem; }
|
|
.lade input[type="range"] { -webkit-appearance: none; appearance: none; width: 100%; height: 1.9rem; background: transparent; margin: 0; }
|
|
.lade input[type="range"]::-webkit-slider-runnable-track { height: .5rem; border-radius: .25rem; background: linear-gradient(90deg, #6cbe58 0 var(--ist, 0%), var(--lade-wallbox) var(--ist, 0%) var(--wert, 0%), #394046 var(--wert, 0%)); }
|
|
.lade input[type="range"]::-moz-range-track { height: .5rem; border-radius: .25rem; background: linear-gradient(90deg, #6cbe58 0 var(--ist, 0%), var(--lade-wallbox) var(--ist, 0%) var(--wert, 0%), #394046 var(--wert, 0%)); }
|
|
.lade input[type="range"]::-webkit-slider-thumb { -webkit-appearance: none; width: 1.6rem; height: 1.6rem; margin-top: -.55rem; border-radius: 50%; background: #fff; border: 4px solid var(--lade-wallbox); box-shadow: 0 .15rem .5rem rgba(0, 0, 0, .4); }
|
|
.lade input[type="range"]::-moz-range-thumb { width: 1.1rem; height: 1.1rem; border-radius: 50%; background: #fff; border: 4px solid var(--lade-wallbox); }
|
|
.lade input[type="range"]:focus-visible { outline: 2px solid var(--lade-wallbox); outline-offset: 4px; }
|
|
.lade .lade-marken { display: flex; justify-content: space-between; font-size: .68rem; color: var(--ton-schrift-3, #6f7a81); margin-top: -.2rem; }
|
|
.lade .lade-chips { display: flex; flex-wrap: wrap; gap: .35rem; }
|
|
.lade .lade-chip { all: unset; cursor: pointer; padding: .35rem .7rem; border-radius: 99px; background: #363d43; font-size: .8rem; font-weight: 500; font-variant-numeric: tabular-nums; }
|
|
.lade .lade-chip[aria-pressed="true"] { background: var(--lade-wallbox); color: #0c1a1d; font-weight: 600; }
|
|
.lade .lade-chip:focus-visible { outline: 2px solid var(--lade-wallbox); outline-offset: 1px; }
|
|
.lade .lade-chip-eigen { position: relative; display: inline-flex; align-items: center; gap: .35rem; }
|
|
.lade .lade-chip-eigen .bi { font-size: .85em; }
|
|
/* Unsichtbar, aber an Ort und Stelle: der Wähler öffnet sich am Knopf. */
|
|
.lade .lade-zeitfeld { position: absolute; inset: 0; width: 100%; height: 100%; opacity: 0; pointer-events: none; border: 0; padding: 0; }
|
|
|
|
.lade .lade-strom { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: .3rem; padding: .25rem; border-radius: .75rem; background: var(--ton-flaeche-2, #2b3237); }
|
|
.lade .lade-strom button { all: unset; cursor: pointer; text-align: center; padding: .45rem .2rem; border-radius: .55rem; display: grid; gap: .05rem; }
|
|
.lade .lade-strom button b { font-weight: 600; }
|
|
.lade .lade-strom button span { font-size: .68rem; color: var(--ton-schrift-2, #9aa6ad); }
|
|
.lade .lade-strom button[aria-checked="true"] { background: #363d43; box-shadow: inset 0 0 0 1.5px var(--lade-wallbox); }
|
|
.lade .lade-strom button:focus-visible { outline: 2px solid var(--lade-wallbox); }
|
|
.lade .lade-meldung { font-size: .76rem; color: var(--ton-schrift-3, #6f7a81); }
|
|
.lade .lade-meldung.gut { color: #6cbe58; }
|
|
.lade .lade-meldung.fehler { color: #e5624f; }
|
|
@media (max-width: 420px) { .lade .lade-modus > span:last-child { display: none; } }
|
|
|
|
/* Am 800er-Display zweispaltig ohne Scrollen. */
|
|
.anzeige #modalEV .modal-dialog:has(.lade) { max-width: 46rem; }
|
|
.anzeige .lade { grid-template-columns: 15rem minmax(0, 1fr); gap: 1rem; padding: .7rem .9rem; }
|
|
.anzeige .lade .lade-status { grid-template-columns: 1fr; justify-items: center; text-align: center; gap: .5rem; }
|
|
.anzeige .lade .lade-auto { justify-content: center; }
|
|
.anzeige .lade .lade-modus > span:last-child { display: none; }
|
|
.anzeige .lade .lade-rechts,
|
|
.anzeige .lade .lade-links { gap: .6rem; }
|
|
.anzeige #modalEV .modal-body:has(.lade) { max-height: none; overflow: visible; }
|
|
.anzeige #modalEV .modal-content:has(.lade) .modal-footer { display: none; }
|
|
.anzeige #modalEV .modal-content:has(.lade) .modal-header { padding: .45rem .9rem; }
|
|
|
|
/* --- Karte: Umschalter Übersicht / Anlage -------------------------------- */
|
|
.enf-umschalter { display: inline-flex; gap: 2px; padding: 3px; border-radius: var(--ton-radius-klein, .5rem); background: var(--ton-grund, #191d20); }
|
|
.enf-umschalter .btn.btn-sm { border: 0; color: var(--ton-schrift-2, #9aa6ad); font-weight: 600; padding: .2rem .8rem; }
|
|
.enf-umschalter .btn.btn-sm.active { background: var(--ton-flaeche-2, #2b3237); color: var(--ton-schrift, #e8ede9); }
|
|
.enf-ansicht[hidden] { display: none !important; }
|
|
.enf-ansicht.enf-rein { animation: enf-ansicht-rein .35s cubic-bezier(.2, .7, .2, 1); }
|
|
@keyframes enf-ansicht-rein { from { opacity: 0; transform: scale(.98); } }
|