4ab6b9fca5
Debug-Mode: Zugaenge und Dongle stehen nicht mehr verstreut oben in den Einstellungen, sondern zusammen hinter einem Schalter am Seitenende - dazu neu der letzte Datensatz des Dongles (geraet.py). "Letzter Datensatz" heisst dabei: alle Entitaeten des Geraets, deren Aktualisierung hoechstens zwei Sekunden nach der juengsten liegt - die flespi-Integration setzt einen Datensatz in Millisekunden. Angezeigt mit Ankunft, Geraetezeit und dem Rueckstand zwischen beiden. Beim Verifizieren gefunden: app_version_veroeffentlichen() lief nur beim Start und nach einer Aktion, und beim Start haben die Entitaeten des Geraets noch keinen Zustand - die Kachel waere dauerhaft leer geblieben. Laeuft jetzt im Minutentakt mit, ohne Netzaufruf. Ausserdem: - "Version" und "Integration-Update" sind eine Kachel - Speichern/Verwerfen als zwei gleich breite Knoepfe, der bestaetigende gefuellt und rechts; "Verwerfen" war in der App blosser Text - Bilder werden nach dem ersten Zeichnen in der Leerlaufzeit vorgeladen UND dekodiert. Die Verzoegerung beim Seitenwechsel kam nicht vom Netz (31 Tage Cache), sondern vom asynchronen Dekodieren eines frisch erzeugten <img>. 214/214 Tests, Panel als Modul geparst, live gegen audi_ha_test geprueft.
1674 lines
78 KiB
CSS
1674 lines
78 KiB
CSS
/* audi-dashboard.css — Stil des Panels, aufgebaut auf den Tokens und
|
||
Komponenten des Design-Systems AudiDashUI (_ds_bundle.css). Klassennamen
|
||
wie im Prototyp/Panel (unpräfixiert), Werte 1:1 aus dem Design-System. */
|
||
|
||
:host {
|
||
--red: #F50537;
|
||
--r-tile: 20px;
|
||
--r-pill: 999px;
|
||
--r-func: 8px;
|
||
--rahmen-hg: #111;
|
||
--sp-1: 4px; --sp-2: 8px; --sp-3: 12px; --sp-4: 16px; --sp-5: 22px;
|
||
--canvas: #161b23;
|
||
--tile: #1f2733;
|
||
--tile-2: #2a3341;
|
||
--line: rgba(255,255,255,.10);
|
||
--line-strong: rgba(255,255,255,.20);
|
||
--fg: #FFFFFF;
|
||
--fg2: #9aa1ad;
|
||
/* A2: von #657081 (3,0:1 auf --tile) auf 4,6:1 angehoben. Unterhalb von
|
||
12 px wird diese Farbe nicht mehr verwendet. */
|
||
--fg3: #8a94a3;
|
||
--ok: #15da15;
|
||
--warn: #ffaa00;
|
||
--bad: #fd2c4e;
|
||
--shade: rgba(255,255,255,.05);
|
||
--font-stack: "Audi Type", Helvetica, Arial, sans-serif;
|
||
/* Bugfix: in der echten HA-Einbettung liefert partial-panel-resolver
|
||
(display:inline, height:auto) keine definierte Höhe - eine
|
||
height:100%-Kette von hier nach oben rechnet also gegen eine
|
||
Auto-Box und kollabiert auf die Inhaltshöhe (nur Topbar+Tabbar
|
||
sichtbar, main#view ohne Fläche zum Scrollen). Deshalb wie im
|
||
ursprünglichen Prototyp direkt an der Viewport-Höhe verankert,
|
||
unabhängig von der Elternkette - und zentriert wie eine
|
||
Telefon-Karte, statt randlos zu füllen. */
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
height: 100vh;
|
||
height: 100dvh;
|
||
overflow: hidden;
|
||
}
|
||
:host([data-theme=tag]) {
|
||
--canvas: #FFFFFF;
|
||
--tile: #f2f2f2;
|
||
--tile-2: #e5e5e5;
|
||
--line: rgba(0,0,0,.10);
|
||
--line-strong: rgba(0,0,0,.22);
|
||
--fg: #000000;
|
||
--fg2: #4c4c4c;
|
||
--fg3: #666666;
|
||
--ok: #0DA20D;
|
||
--warn: #ffaa00;
|
||
--bad: #eb0d3f;
|
||
--shade: rgba(0,0,0,.04);
|
||
}
|
||
|
||
* { box-sizing: border-box; }
|
||
|
||
/* Sichtbarer Tastatur-Fokus. Bis hierher gab es .feld input:focus als einzige
|
||
Fokus-Regel im ganzen Blatt - alle Knöpfe, Kacheln und Tabs waren zwar
|
||
fokussierbar, aber ohne jede sichtbare Markierung. Auf dem Telefon fällt das
|
||
nicht auf, per Bluetooth-Tastatur (iPadOS/Desktop über Tailscale) oder mit
|
||
iOS-Vollzugriff per Tastatur ist die App dadurch praktisch unbedienbar.
|
||
:focus-visible statt :focus, damit Maus- und Tipp-Bedienung unverändert
|
||
ohne Rahmen bleibt - der Browser entscheidet, was "echte" Tastaturnavigation
|
||
ist. */
|
||
:focus-visible {
|
||
outline: 2px solid var(--red);
|
||
outline-offset: 2px;
|
||
border-radius: 2px;
|
||
}
|
||
|
||
/* Zwischen-Wrapper, den _aufbauen() in den Shadow Root haengt - bekommt hier
|
||
die einzige "echte" (viewport-verankerte) Höhe der ganzen Kette; .phone
|
||
darunter kann sich dann gefahrlos mit height:100% darauf beziehen. */
|
||
:host > div {
|
||
width: 100%;
|
||
max-width: 412px;
|
||
height: min(880px, calc(100vh - 24px));
|
||
height: min(880px, calc(100dvh - 24px));
|
||
min-height: 0;
|
||
/* Verhindert, dass eine Zieh-Geste, die main#view unten nach oben hin
|
||
verlaesst, an die dahinterliegende HA-Seite weitergereicht wird - sonst
|
||
kann der Browser selbst ein natives Overscroll/Pull-to-Refresh starten
|
||
und der eigene Ziehen-zum-Aktualisieren-Indikator bekommt die Geste nie
|
||
zu Ende. */
|
||
overscroll-behavior: none;
|
||
}
|
||
|
||
/* ------------------------------------------------------------- Gerüst */
|
||
.phone {
|
||
display: flex;
|
||
flex-direction: column;
|
||
height: 100%;
|
||
min-height: 0;
|
||
/* B4: Bezugsrahmen für Action Sheet und Popups. */
|
||
position: relative;
|
||
background: var(--canvas);
|
||
color: var(--fg);
|
||
font-family: var(--font-stack);
|
||
font-variant-numeric: tabular-nums;
|
||
overflow: hidden;
|
||
/* B2: kein graues Safari-Rechteck beim Tippen - Rückmeldung kommt aus den
|
||
:active-Regeln unten. */
|
||
-webkit-tap-highlight-color: transparent;
|
||
}
|
||
.topbar {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: var(--sp-3);
|
||
/* B1: oben Platz für Statusbalken/Dynamic Island. */
|
||
padding: max(22px, calc(env(safe-area-inset-top) + 10px)) 20px 14px;
|
||
flex: 0 0 auto;
|
||
background: var(--canvas);
|
||
}
|
||
.back {
|
||
/* B6: 44 px Trefferfläche. */
|
||
width: 44px; height: 44px;
|
||
margin-left: -5px;
|
||
flex: 0 0 auto;
|
||
display: inline-flex; align-items: center; justify-content: center;
|
||
border: none; border-radius: 50%;
|
||
background: none;
|
||
color: var(--fg3);
|
||
cursor: pointer;
|
||
padding: 0;
|
||
opacity: 0;
|
||
pointer-events: none;
|
||
}
|
||
.back.on { opacity: 1; pointer-events: auto; }
|
||
.back:hover { background: var(--tile-2); color: var(--fg); }
|
||
.back:active { background: var(--tile-2); color: var(--fg); transform: scale(.92); }
|
||
.head { flex: 1; min-width: 0; }
|
||
.eyebrow {
|
||
font-size: 11px;
|
||
letter-spacing: .18em;
|
||
text-transform: uppercase;
|
||
color: var(--fg3);
|
||
min-height: 12px;
|
||
}
|
||
.title {
|
||
font-size: 23px;
|
||
letter-spacing: -.015em;
|
||
line-height: 1.15;
|
||
color: var(--fg);
|
||
overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
|
||
}
|
||
.sync {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 6px;
|
||
margin-top: 4px;
|
||
font-size: 11px;
|
||
color: var(--fg3);
|
||
white-space: nowrap;
|
||
}
|
||
.themebtn, .rings {
|
||
display: inline-flex; align-items: center; justify-content: center;
|
||
border: none; background: none; color: var(--fg3);
|
||
cursor: pointer; padding: 0; flex: 0 0 auto;
|
||
}
|
||
.themebtn { width: 44px; height: 44px; border-radius: 50%; }
|
||
/* A6: Die Topbar-Taste ist entfallen - die Wahl liegt in den Einstellungen und
|
||
folgt sonst der Systemeinstellung. display:inline-flex oben würde das
|
||
hidden-Attribut sonst überstimmen. */
|
||
.themebtn[hidden] { display: none; }
|
||
.themebtn:hover { background: var(--tile-2); color: var(--fg); }
|
||
.themebtn:active { background: var(--tile-2); color: var(--fg); transform: scale(.92); }
|
||
.themebtn svg { fill: none; stroke: currentColor; stroke-width: 1.5; stroke-linecap: round; }
|
||
/* Wie .themebtn (44px Trefferflaeche), aber ohne die Kontur-Stroke-Regel -
|
||
fuer CI-Symbole (ciSVG()), deren Pfade ihr eigenes fill="currentColor"
|
||
mitbringen (z. B. list-s im Kopf der Batteriespannungs-Kachel). */
|
||
.iconbtn {
|
||
display: inline-flex; align-items: center; justify-content: center;
|
||
width: 44px; height: 44px; border-radius: 50%;
|
||
border: none; background: none; color: var(--fg3);
|
||
cursor: pointer; padding: 0; flex: 0 0 auto;
|
||
}
|
||
.iconbtn:hover { background: var(--tile-2); color: var(--fg); }
|
||
.iconbtn:active { background: var(--tile-2); color: var(--fg); transform: scale(.92); }
|
||
/* "Neue Räder anlegen" auf der Reifen-Seite: bewusst dauerhaft mit
|
||
sichtbarem Hintergrund statt nur bei Hover/Tap wie .iconbtn sonst - sitzt
|
||
direkt neben dem gefüllten "Montiert"-Knopf und wirkt ohne eigene Fläche
|
||
zu unscheinbar, um dort als eigenständiger Knopf erkannt zu werden. */
|
||
.archivbtn { background: var(--tile-2); color: var(--fg2); }
|
||
.archivbtn:hover, .archivbtn:active { color: var(--fg); }
|
||
/* D4 war urspruenglich: die Ringe sind Marke, kein Knopf. Seit die
|
||
iOS-Auflage in Telefonbreite das Zahnrad ausblendet, sind sie dort aber der
|
||
einzige Zugang zu den Einstellungen - und als reines div mit
|
||
pointer-events:none war dieser Zugang fuer Tastatur und Sprachausgabe gar
|
||
nicht erreichbar. Sie sind deshalb jetzt ein echter Knopf, in jeder Breite
|
||
bedienbar. Auf grossen Bildschirmen gibt es damit zwei Wege in die
|
||
Einstellungen (Ringe und Zahnrad) - unschaedlich, und der Zugang haengt
|
||
nicht mehr davon ab, ob audi-dashboard-ios.css geladen wurde. */
|
||
/* Design-Audit 2026-08-13: in Telefonbreite ist dies der einzige Zugang zu
|
||
den Einstellungen (siehe Kommentar oben), war mit 42px aber deutlich
|
||
kleiner als jeder andere Symbol-Knopf in der Kopfzeile (.themebtn/
|
||
.profilbtn/.back sind alle 44px) und lag damit unter der ueblichen
|
||
44px-Mindestgroesse fuer Tippflaechen. */
|
||
.rings { width: 58px; height: 32px; color: var(--fg); }
|
||
.rings svg { width: 58px; height: auto; }
|
||
|
||
/* Der Markenklon in der Seitenleiste wird vom Skript unbedingt in die
|
||
Menueleiste gehaengt; sichtbar macht ihn erst die iOS-Auflage ab 860px.
|
||
Das Verstecken gehoert deshalb hierher: laedt die Auflage nicht (404,
|
||
Cache), waere er sonst ein sechstes Element im fuenfspaltigen Raster und
|
||
die Menueleiste zerfiele. */
|
||
.navmarke { display: none; }
|
||
.profilbtn {
|
||
display: inline-flex; align-items: center; justify-content: center;
|
||
width: 44px; height: 44px; border-radius: 50%;
|
||
border: none; background: var(--tile); color: var(--fg2);
|
||
cursor: pointer; padding: 0; flex: 0 0 auto;
|
||
}
|
||
/* Flaeche statt Kontur, seit das Zahnrad settings-s aus dem CI-Satz ist
|
||
(02.09.2026): der Pfad bringt sein eigenes fill="currentColor" mit, und ein
|
||
geerbter stroke wuerde zusaetzlich um jede Flaeche gezeichnet - dieselbe
|
||
Falle wie bei .voll/RahmenFlaeche in der App. */
|
||
.profilbtn svg { width: 19px; height: 19px; fill: currentColor; stroke: none; }
|
||
.profilbtn:hover { color: var(--fg); }
|
||
.profilbtn:active { background: var(--tile-2); color: var(--fg); transform: scale(.94); }
|
||
|
||
.ptr {
|
||
height: 0;
|
||
overflow: hidden;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
gap: 8px;
|
||
color: var(--fg3);
|
||
font-size: 12.5px;
|
||
transition: height .2s;
|
||
flex: 0 0 auto;
|
||
}
|
||
.ptr.spin svg { animation: drehen 1s linear infinite; }
|
||
@keyframes drehen { to { transform: rotate(360deg); } }
|
||
|
||
main#view {
|
||
/* Der seitliche Rand steht als Variable, weil randlose Elemente ihn per
|
||
negativem Rand ausgleichen muessen (siehe .standort-vollbild). Wer das
|
||
Padding aendert, ohne die Variable zu benutzen, verschiebt die randlosen
|
||
Elemente unbemerkt. */
|
||
--seitenrand: 20px;
|
||
flex: 1 1 0;
|
||
min-height: 0;
|
||
overflow-y: auto;
|
||
overflow-x: hidden;
|
||
padding: 10px var(--seitenrand) 34px;
|
||
scroll-behavior: smooth;
|
||
-webkit-overflow-scrolling: touch;
|
||
scrollbar-width: none;
|
||
/* Ohne das hier greift auf echten Touch-Geraeten oft das native
|
||
Overscroll/Pull-to-Refresh des Browsers, sobald am oberen Rand weiter
|
||
nach unten gezogen wird - das nimmt der eigenen "Ziehen zum
|
||
Aktualisieren"-Geste (siehe ptrY0-Logik in ereignisseVerdrahten()) die
|
||
Kontrolle weg, obwohl deren JS/CSS für sich genommen korrekt arbeitet. */
|
||
overscroll-behavior-y: contain;
|
||
}
|
||
main#view::-webkit-scrollbar { width: 0; height: 0; }
|
||
|
||
#overlay:empty { display: none; }
|
||
|
||
.tabbar {
|
||
display: grid;
|
||
grid-template-columns: repeat(5, 1fr);
|
||
border-top: 1px solid var(--line);
|
||
flex: 0 0 auto;
|
||
background: var(--canvas);
|
||
/* B1: Luft über dem Home-Indikator. */
|
||
padding-bottom: max(6px, env(safe-area-inset-bottom));
|
||
}
|
||
/* B5: kein roter Oberkantenstrich (Desktop-Muster), sondern eine gefüllte
|
||
Pille um das aktive Symbol - wie in der myAudi-App. */
|
||
.tab {
|
||
display: flex; flex-direction: column; align-items: center; gap: 7px;
|
||
padding: 12px 0 10px;
|
||
background: none; border: none;
|
||
color: var(--fg3);
|
||
font-family: inherit;
|
||
cursor: pointer;
|
||
transition: color .15s;
|
||
}
|
||
.tab.on { color: var(--fg); }
|
||
/* Die Pille ist ein eigenes Feld um das Symbol - so bleibt ihre Groesse
|
||
unabhaengig vom Symbol und der Wechsel laeuft sauber ueber background. */
|
||
.tabpille {
|
||
display: flex; align-items: center; justify-content: center;
|
||
width: 60px; height: 34px; border-radius: var(--r-pill);
|
||
transition: background .18s;
|
||
}
|
||
.tab.on .tabpille { background: var(--tile-2); }
|
||
.tab svg {
|
||
fill: none; stroke: currentColor; stroke-width: 1.6;
|
||
stroke-linecap: round; stroke-linejoin: round;
|
||
transition: transform .18s;
|
||
}
|
||
.tab svg.voll { fill: currentColor; stroke: none; }
|
||
.tab:active svg { transform: scale(.9); }
|
||
.tab span { font-size: 11px; letter-spacing: .01em; }
|
||
/* :not(.tabpille) - die Icon-Huelle ist selbst ein <span>, ein blosses
|
||
".tab span" hier hiess frueher auch der Pille (samt Icon) display:none.
|
||
Ueberschrieben von derselben Regel in audi-dashboard-ios.css (dieselbe
|
||
Spezifitaet, spaeter geladen), aber auch hier falsch und daher fixiert. */
|
||
.tabbar.ohne .tab span:not(.tabpille) { display: none; }
|
||
.tabbar.ohne .tab { padding: 14px 0 12px; }
|
||
.tabbar.ohne .tab svg { width: 26px; height: 26px; }
|
||
|
||
/* -------------------------------------------------------------- Kacheln */
|
||
.tile {
|
||
background: var(--tile);
|
||
border-radius: var(--r-tile);
|
||
padding: var(--sp-5);
|
||
margin-bottom: var(--sp-4);
|
||
position: relative;
|
||
}
|
||
.tile.flat { background: none; padding: 0; }
|
||
button.tile, .tilebtn {
|
||
display: block;
|
||
width: 100%;
|
||
border: none;
|
||
font-family: inherit;
|
||
text-align: left;
|
||
cursor: pointer;
|
||
color: inherit;
|
||
}
|
||
button.tile:hover { background: var(--tile-2); }
|
||
button.tile:active, .tilebtn:active { background: var(--tile-2); transform: scale(.99); }
|
||
button.tile, .tilebtn { transition: background .15s, transform .1s; }
|
||
.go {
|
||
position: absolute;
|
||
top: var(--sp-5); right: var(--sp-5);
|
||
width: 6px; height: 10px;
|
||
color: var(--fg3);
|
||
fill: none; stroke: currentColor; stroke-width: 1.4;
|
||
}
|
||
.zahnrad {
|
||
position: absolute;
|
||
top: 8px; right: 8px;
|
||
width: 44px; height: 44px;
|
||
display: inline-flex; align-items: center; justify-content: center;
|
||
border: none; border-radius: 50%;
|
||
background: none; color: var(--fg3);
|
||
cursor: pointer; padding: 0;
|
||
}
|
||
.zahnrad:hover { background: var(--tile-2); color: var(--fg); }
|
||
.zahnrad:active { background: var(--tile-2); color: var(--fg); transform: scale(.92); }
|
||
.zahnrad svg { width: 17px; height: 17px; }
|
||
/* Titelzeile nie unter dem Zahnrad/Chevron hindurchlaufen lassen - und die
|
||
Zeile hoch genug für die 44px-Trefferfläche des Zahnrads machen. Ohne die
|
||
Mindesthöhe ragte es in den Kachelinhalt und lag auf dem ersten Knopf
|
||
(Versicherung, "Inland · <Nummer>"; gemeldet 02.09.2026). Gleiche Regel in
|
||
der App (.dm-kachel--zahnrad). */
|
||
.tile:has(> .zahnrad) > .label:first-child,
|
||
.tile:has(> .go) > .label:first-child { padding-right: 48px; }
|
||
.tile:has(> .zahnrad) > .label:first-child { min-height: 34px; }
|
||
|
||
/* C1: Abschnittstitel gemischt geschrieben, 14 px, ohne Sperrung - wie in der
|
||
aktuellen myAudi-App. Versalien trägt nur noch .eyebrow über dem Seitentitel. */
|
||
.label {
|
||
font-size: 14px;
|
||
letter-spacing: normal;
|
||
color: var(--fg2);
|
||
display: block;
|
||
line-height: 1.3;
|
||
}
|
||
/* HIG "Loading": statt reinem Text ein sichtbar laufender Indikator, solange
|
||
DATEN_GELADEN false ist - hilft auch, "lädt noch" optisch von "hängt fest"
|
||
zu unterscheiden (dieser Bildschirm hatte schon ein echtes Hänger-Problem). */
|
||
.lade-spinner {
|
||
width: 16px; height: 16px; flex: none;
|
||
border: 2px solid var(--line-strong);
|
||
border-top-color: var(--fg2);
|
||
border-radius: 50%;
|
||
animation: lade-spin .8s linear infinite;
|
||
}
|
||
@keyframes lade-spin { to { transform: rotate(360deg); } }
|
||
/* Echte Überschrift innerhalb einer Kachel (z.B. "Sommerräder"/"Winterräder")
|
||
statt des sonst üblichen kleinen, gedämpften .label-Abschnittstitels -
|
||
selbe Typografie-Stufe wie .title (Seitentitel), nur etwas kleiner, weil
|
||
sie innerhalb einer Kachel steht statt in der Kopfzeile. */
|
||
.tile-headline {
|
||
font-size: 20px;
|
||
letter-spacing: -.01em;
|
||
line-height: 1.2;
|
||
color: var(--fg);
|
||
display: block;
|
||
}
|
||
/* Icon + Text statt reinem Fließtext-Label (z.B. Batterie-Symbol vor
|
||
"Ruhespannung") - dieselbe Zeilen-Geometrie wie .sync in der Kopfzeile. */
|
||
.bv-skala-kopf { display: flex; align-items: center; gap: 6px; }
|
||
|
||
/* A4: Messwerte erben nie mehr das uppercase der Label-Klasse. */
|
||
.wert {
|
||
font-size: 14px;
|
||
letter-spacing: normal;
|
||
text-transform: none;
|
||
color: var(--fg2);
|
||
}
|
||
.fig {
|
||
font-family: "Audi Type Wide", var(--font-stack);
|
||
font-weight: 300;
|
||
letter-spacing: -.02em;
|
||
line-height: .95;
|
||
color: var(--fg);
|
||
}
|
||
.fig .unit {
|
||
/* A3: relativ zur Zahl, aber nie unter der Lesbarkeitsgrenze - bei einer
|
||
29-px-Zahl ergäbe .32em nur 9,3 px. */
|
||
font-size: max(11px, .32em);
|
||
font-weight: 400;
|
||
letter-spacing: normal;
|
||
color: var(--fg2);
|
||
margin-left: .32em;
|
||
}
|
||
.werte { font-size: 14px; color: var(--fg); display: block; }
|
||
|
||
.rows { margin: 0; }
|
||
.row {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: baseline;
|
||
gap: var(--sp-4);
|
||
padding: 15px 0;
|
||
border-bottom: 1px solid var(--line);
|
||
}
|
||
.row dt { font-size: 13px; color: var(--fg2); line-height: 1.4; }
|
||
.row dd { margin: 0; font-size: 14px; color: var(--fg); text-align: right; }
|
||
.row dd small { display: block; font-size: 12.5px; color: var(--fg3); margin-top: 3px; }
|
||
.rows-fest dd { min-width: 120px; }
|
||
|
||
/* Tankstelle im Einzelbeleg (Vorgabe des Eigentuemers, 04.09.2026).
|
||
|
||
Vorher eine gewoehnliche Zeile: Name rechts in der 120px-Wertespalte, die
|
||
ganze Anschrift als Kleintext darunter - "Hermann Mogler Mineraloelg. GmbH,
|
||
Heidenheimerstr.6, 89551 Koenigsbronn" stand dort vier- bis fuenfzeilig.
|
||
Hier bekommt sie die volle Kachelbreite unter der Beschriftung, zwei Zeilen
|
||
(Tankstelle und Strasse / Ort), und fuehrt beim Tippen in den Kartendienst -
|
||
deshalb der Chevron rechts. Deckungsgleich mit .dm-tankstellenzeile in der
|
||
App. */
|
||
.row.tankstellenzeile { flex-direction: column; align-items: stretch; gap: 4px; border-bottom: 0; }
|
||
/* flex:0 0 auto hebt .rows-fest dt{flex:0 0 150px} auf: in einer Spalte
|
||
ist die Flex-Basis die HOEHE - der Titel waere sonst 150px hoch. */
|
||
.row.tankstellenzeile dt { font-size: 13px; color: var(--fg2); flex: 0 0 auto; }
|
||
.row.tankstellenzeile dd { min-width: 0; text-align: left; flex: 0 0 auto; }
|
||
.row.tankstellenzeile dd > a,
|
||
.row.tankstellenzeile dd > span {
|
||
display: flex; align-items: center; justify-content: space-between;
|
||
gap: var(--sp-3); color: inherit; text-decoration: none;
|
||
}
|
||
.row.tankstellenzeile dd > a:active { opacity: .6; }
|
||
.tankstellenzeile-ort { display: block; font-size: 14px; color: var(--fg); line-height: 1.35; min-width: 0; }
|
||
.tankstellenzeile-ort small { display: block; margin-top: 2px; font-size: 12.5px; color: var(--fg3); }
|
||
/* .row-fussnote ist mit dem Umbau der Service-Seite auf .termingruppe
|
||
entfallen (2026-08-18) - dort gibt es keine dt/dd-Spalten mehr, die um
|
||
Platz konkurrieren. Die beiden Regeln dafuer standen seither ohne
|
||
passendes Markup da. */
|
||
/* Sammelzeilen der Sicherheit-Ansicht (vSicherheit()): Kreis-Häkchen + Text
|
||
+ optionaler Chevron statt dt/dd. Erbt Abstand/Trennlinie von .row, ersetzt
|
||
aber dessen space-between-Layout und setzt die Button-Vorgaben zurück, wenn
|
||
die Zeile klickbar ist (Türen und Klappen). */
|
||
.sicherheitszeile {
|
||
justify-content: flex-start;
|
||
width: 100%;
|
||
background: none;
|
||
border: none;
|
||
border-bottom: 1px solid var(--line);
|
||
font: inherit;
|
||
color: inherit;
|
||
text-align: left;
|
||
cursor: default;
|
||
}
|
||
button.sicherheitszeile { cursor: pointer; }
|
||
button.sicherheitszeile:active { background: var(--tile-2); }
|
||
.sicherheitsliste .sicherheitszeile:last-child { border-bottom: 0; }
|
||
.sicherheitszeile-text { flex: 1; font-size: 14px; color: var(--fg); }
|
||
.sicherheitszeile .chev { margin-left: auto; }
|
||
/* Wert als Kommentar statt als Angabe - fuer Zeilen, deren rechte Seite nur
|
||
beschreibt, was hinter der Kachel liegt (Mein Audi, "Details"). Groesse
|
||
und Farbe wie jede andere Nebenzeile. */
|
||
.row dd.row-hinweis { font-size: 12.5px; color: var(--fg3); }
|
||
|
||
|
||
.leaf {
|
||
display: flex; align-items: center; justify-content: space-between;
|
||
gap: var(--sp-4);
|
||
width: 100%;
|
||
background: none; border: none;
|
||
font-family: inherit; text-align: left;
|
||
padding: 14px 0 14px 40px;
|
||
min-height: 56px;
|
||
border-bottom: 1px solid var(--line);
|
||
color: inherit;
|
||
}
|
||
/* Das Label nimmt den freien Platz und kuerzt bei Bedarf mit Auslassung.
|
||
|
||
Ohne flex:1 blieb in der Zeile freier Raum, und weil sie DREI Kinder hat
|
||
(Label, Werte, Pfeil), verteilte space-between ihn ZWISCHEN alle drei - die
|
||
Wertespalte stand damit in der Mitte, ihre Lage abhaengig von der Laenge des
|
||
Ortsnamens. Gemessen: rechte Kante bei 549px in der einen Zeile, 520px in
|
||
der naechsten. Mit flex:1 bleibt kein freier Raum uebrig, Werte und Pfeil
|
||
sitzen buendig rechts.
|
||
|
||
min-width:0 ist noetig, damit ein Flex-Kind ueberhaupt unter seine
|
||
Inhaltsbreite schrumpfen darf - ohne das greift text-overflow nie. */
|
||
.leaf .k { font-size: 14px; color: var(--fg); display: flex; flex-direction: column; gap: 3px; line-height: 1.35; flex: 1 1 auto; min-width: 0; }
|
||
.leaf .k > * { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
||
.leaf .k small { font-size: 12.5px; color: var(--fg3); }
|
||
/* Feste Mindestbreite, damit Strecke und Verbrauch ueber alle Zeilen hinweg
|
||
in einer Spalte stehen. Ohne sie waechst der Kasten mit dem Inhalt: gemessen
|
||
86px bei "11,4 l/100 km" gegen 37px bei einer Zeile ohne Werte, und die
|
||
Zahlen standen entsprechend versetzt. 92px traegt die laengste Form
|
||
("11,4 l/100 km") ohne Umbruch. */
|
||
.leaf .v { font-size: 13px; color: var(--fg2); text-align: right; display: flex; flex-direction: column; gap: 3px; flex: 0 0 92px; }
|
||
.leaf .v small { font-size: 12.5px; color: var(--fg3); }
|
||
/* .teaser (die "Zuletzt"-Kachel auf der Übersicht, teaser()): genau zwei
|
||
Zeilen mit sehr unterschiedlich breiten Werten ("offen" vs. "51,59 l") -
|
||
.v ist sonst flex:0 0 auto und damit genau so breit wie sein eigener
|
||
Inhalt, wodurch die linke Kante des Wertes je Zeile unterschiedlich weit
|
||
rechts beginnt (rechte Kante bleibt an der Chevron-Spalte gleich, das
|
||
täuscht Ausrichtung nur vor). min-width sorgt für eine gemeinsame
|
||
Spaltenbreite, damit beide Werte auf derselben linken Kante beginnen.
|
||
Das allein reicht aber nicht: .leaf selbst verteilt seine drei Kinder
|
||
(.k/.v/Chevron) per justify-content:space-between, und .k hat kein
|
||
flex-grow - unterschiedlich lange Beschriftungen ("→" vs. "Hermann Mogler
|
||
Mineralölg. GmbH") verschieben dadurch die GESAMTE restliche Zeile
|
||
(.v + Chevron) um die Differenz, obwohl .v selbst jetzt gleich breit ist.
|
||
.k bekommt deshalb flex:1, damit es den verbleibenden Platz füllt und .v
|
||
dadurch wirklich immer am selben Abstand vom rechten Rand sitzt. */
|
||
.teaser .leaf .k { flex: 1 1 auto; min-width: 0; }
|
||
.teaser .leaf .v { min-width: 72px; }
|
||
/* cursor/:active nur für echte .leaf-Buttons (data-go, navigieren bei Klick)
|
||
- die Batterie-Messwertliste (vBatterieliste()) ist bewusst ein reines
|
||
<div class="leaf">, keine Zeilennavigation, nur Wischen zum Löschen; sie
|
||
soll deshalb weder den Hand-Cursor noch die Tipp-Rückmeldung zeigen, die
|
||
sonst "hier passiert beim Klick etwas" versprechen. */
|
||
button.leaf { cursor: pointer; transition: background .15s; }
|
||
button.leaf:active { background: var(--tile-2); }
|
||
.chev { width: 6px; height: 10px; color: var(--fg3); flex: 0 0 auto; fill: none; stroke: currentColor; stroke-width: 1.4; }
|
||
|
||
/* ------------------------------------------------------------- Status */
|
||
.status {
|
||
display: flex; align-items: center; gap: var(--sp-3);
|
||
width: 100%;
|
||
background: none; border: none; padding: 16px 0 0;
|
||
min-height: 44px;
|
||
text-align: left; font-family: inherit; cursor: pointer;
|
||
color: inherit;
|
||
}
|
||
.dot { width: 11px; height: 11px; border-radius: 50%; flex: 0 0 auto; background: var(--ok); display: inline-block; }
|
||
.dot.warn { background: var(--warn); }
|
||
.dot.bad { background: var(--bad); }
|
||
/* Kreis-Häkchen statt einfarbigem Punkt - für die Sicherheit-Ansicht
|
||
(vSicherheit()/vTuerenKlappen()), nach Nutzer-Vorlage: erfüllt/offen/
|
||
unbekannt sofort am Symbol erkennbar, nicht nur an der Farbe. */
|
||
.statuskreis { width: 22px; height: 22px; border-radius: 50%; flex: 0 0 auto; background: var(--ok); display: inline-flex; align-items: center; justify-content: center; }
|
||
.statuskreis.warn { background: var(--warn); }
|
||
.statuskreis.bad { background: var(--bad); }
|
||
.status .t { font-size: 14px; color: var(--fg); }
|
||
.status { transition: opacity .15s; }
|
||
.status:active { opacity: .55; }
|
||
|
||
/* -------------------------------------------------------------- Übersicht */
|
||
.tankzeile { display: flex; align-items: flex-end; justify-content: space-between; gap: 14px; margin-bottom: 14px; }
|
||
.pct { font-size: 15px; color: var(--fg2); padding-bottom: 6px; }
|
||
.balken { height: 4px; border-radius: var(--r-pill); background: var(--line); overflow: hidden; }
|
||
.balken i { display: block; height: 100%; background: var(--fg); border-radius: var(--r-pill); }
|
||
/* Der Außenabstand sitzt am Raster, nicht an den Kacheln - sonst wird er im
|
||
2×2-Raster (vHome) zum zusätzlichen internen Zeilenabstand und der Abstand
|
||
innerhalb der Gruppe wäre größer als der zur nächsten. */
|
||
/* Übersicht: "Nächster Service" als tippbare Kennzahl, darunter der
|
||
Kilometerstand als Wertezeile (siehe Kommentar in vHome()). Der Knopf sitzt
|
||
INNERHALB einer normalen .tile - nicht die Kachel selbst ist der Knopf,
|
||
sondern nur ihr oberer Teil, damit die Kilometerstand-Zeile erkennbar reine
|
||
Anzeige bleibt. Der Chevron steht deshalb auf right:0 relativ zum Knopf und
|
||
landet damit genau auf demselben Innenabstand wie ein normales .go in einer
|
||
gepolsterten Kachel. */
|
||
.serviceblock {
|
||
position: relative;
|
||
display: block; width: 100%;
|
||
border: 0; background: none; padding: 0;
|
||
font-family: inherit; text-align: left; color: inherit; cursor: pointer;
|
||
}
|
||
.serviceblock > .go { top: 3px; right: 0; }
|
||
/* Rückmeldung beim Tippen: ein Hintergrundwechsel wie bei .tilebtn ginge hier
|
||
nicht, der Knopf liegt ja schon auf der Kachelfläche. */
|
||
.serviceblock:active { opacity: .55; }
|
||
/* Beschriftung nie unter dem Chevron hindurchlaufen lassen */
|
||
.serviceblock > .label:first-child { padding-right: 24px; }
|
||
/* Serviceart-Icon links der Kennzahl statt des Wortes "bis zum/zur ...". */
|
||
.fig-zeile { display: flex; align-items: center; gap: 8px; margin-top: 8px; }
|
||
.fig-zeile svg { color: var(--fg2); flex: 0 0 auto; }
|
||
.servicezeile {
|
||
display: flex; align-items: baseline; justify-content: space-between;
|
||
gap: var(--sp-4);
|
||
border-top: 1px solid var(--line);
|
||
margin-top: 14px; padding-top: 13px;
|
||
}
|
||
|
||
/* Anstehende Termine (vService): drei sichtbar getrennte Bloecke statt einer
|
||
dt/dd-Liste - Apple HIG ("essential information... don't obscure it by
|
||
crowding it with nonessential details") plus Audi-CI (Flaeche mit Haarlinien
|
||
statt Karten, eigene Groessenklasse fuer Zahlen). Trennung ueber Abstand und
|
||
eine Haarlinie zwischen den Bloecken, nicht ueber verschachtelte Kacheln.
|
||
Jeder Block: Kopfzeile (Icon + Art-Name, optional ein Chip fuer einen
|
||
vereinbarten Werkstatttermin), optionale Herstellervorgabe-Zeile, der Wert,
|
||
optional die eigene Prognose als Fusszeile. */
|
||
.termingruppe { padding: 18px 0; border-top: 1px solid var(--line); }
|
||
.termingruppe:first-of-type { padding-top: 2px; border-top: 0; }
|
||
.tg-kopf { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
|
||
.tg-name { display: flex; align-items: center; gap: 9px; min-width: 0; }
|
||
.tg-name svg { color: var(--fg2); flex: 0 0 auto; }
|
||
.tg-name span { font-size: 16px; color: var(--fg); font-weight: 400; }
|
||
/* Chip statt rotem Fliesstext fuer einen vereinbarten Werkstatttermin - Rot
|
||
bleibt Akzent (Text/Rahmen), nie Flaeche, wie im Rest der App. */
|
||
.tg-chip {
|
||
font-size: 10.5px; color: var(--red);
|
||
border: 1px solid var(--red); border-radius: var(--r-pill);
|
||
padding: 3px 8px; white-space: nowrap; flex: 0 0 auto;
|
||
}
|
||
.tg-vorgabe { font-size: 12.5px; color: var(--fg2); margin-top: 8px; }
|
||
.tg-wert {
|
||
font-family: "Audi Type Wide", var(--font-stack); font-weight: 300;
|
||
font-size: 22px; color: var(--fg); letter-spacing: -.005em; margin-top: 4px;
|
||
}
|
||
.tg-wert.leer { font-family: var(--font-stack); font-weight: 400; font-size: 15px; color: var(--fg3); margin-top: 8px; }
|
||
.tg-prognose { font-size: 12.5px; color: var(--fg2); margin-top: 6px; }
|
||
|
||
.badge { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
|
||
.badge img { height: 18px; width: auto; display: none; }
|
||
:host([data-theme=nacht]) .badge img.negative { display: block; }
|
||
:host([data-theme=tag]) .badge img.positive { display: block; }
|
||
.badge .zusatz { font-size: 13px; color: var(--fg2); }
|
||
|
||
.szene { position: relative; padding: 8px 0 18px; }
|
||
/* C5: randloses Fahrzeugbild - hebt die 20 px Seitenrand von main#view auf und
|
||
blendet nach unten in die Fläche aus. */
|
||
.szene.bleed { margin: -10px -20px 0; padding: 0 0 10px; }
|
||
.szene.bleed .carbox { padding: 0 8px; }
|
||
/* Der Ausblend-Verlauf und der Bodenschatten sind am 2026-08-31 entfallen.
|
||
Beide lagen ueber dem unteren Teil des Fotos, und der Eigentuemer hat
|
||
zweimal darum gebeten, das Fahrzeug unverdeckt zu sehen. Zurueckholen
|
||
waere ein linear-gradient auf .szene.bleed::before bzw. ein
|
||
radial-gradient auf .szene.strasse::after - beides steht in der
|
||
Versionsgeschichte. */
|
||
.carbox { position: relative; }
|
||
.carfix { width: 100%; aspect-ratio: 16 / 9; }
|
||
/* Das Fahrzeugfoto wird nicht mehr beschnitten.
|
||
|
||
Gemessen am echten Foto (2026-08-31): es ist 2000x1125 gross, also 16:9.
|
||
Der Kasten stand auf 16:8 - bei object-fit:cover wurde das Bild auf die
|
||
Kastenbreite skaliert und oben wie unten je ein Viertel abgeschnitten
|
||
(796x220 Kasten, 796x448 skaliertes Bild). Das Dach lag darin.
|
||
|
||
Statt das Seitenverhaeltnis auf 16:9 festzuschreiben - was beim naechsten
|
||
Foto in einem anderen Format wieder schneiden wuerde - bestimmt jetzt das
|
||
Bild selbst die Hoehe. Der Platzhalter behaelt sein festes Verhaeltnis,
|
||
er hat ja keines von sich aus. */
|
||
.bildbox.carfix.klein { aspect-ratio: auto; height: auto; }
|
||
img.carfix.klein { aspect-ratio: auto; height: auto; }
|
||
/* Reifenfoto ist oft eine breite Aufnahme; statt beide Ränder symmetrisch
|
||
wegzuschneiden (object-fit:cover-Standard), bleibt bewusst der rechte Rand
|
||
des Originalfotos erhalten - dort sitzt das Rad meist im Bild. */
|
||
.radbild { object-position: right center; }
|
||
/* .bildbox.radbild statt .radbild allein: .bildbox unten setzt width/aspect-
|
||
ratio auf derselben Spezifitaet (eine Klasse) und gewinnt als spaeter
|
||
notierte Regel sonst automatisch - die Box blieb dadurch bislang die volle
|
||
Kachelbreite im 4:3-Format statt eines echten 96x96-Quadrats. Rechtsbündig
|
||
sitzt es jetzt ueber .radkopf-row (display:flex; justify-content:space-
|
||
between), kein margin-left:auto mehr noetig. */
|
||
.bildbox.radbild { width: 96px; height: 96px; aspect-ratio: 1 / 1; }
|
||
|
||
.bildbox { position: relative; width: 100%; aspect-ratio: 4 / 3; border-radius: 12px; overflow: hidden; }
|
||
.bildbox img { display: block; width: 100%; height: 100%; object-fit: cover; }
|
||
.bildbox .platzhalter { display: none; position: absolute; inset: 0; }
|
||
.bildbox.bild-fehlt img { display: none; }
|
||
.bildbox.bild-fehlt .platzhalter { display: flex; }
|
||
/* D1: Solange kein Foto vorliegt, bleibt die Bildfläche flach - vorher standen
|
||
260 px gestrichelte Leerfläche vor der Reichweite, der wichtigsten Zahl der
|
||
App. Mit Foto gilt wieder das volle Seitenverhältnis. */
|
||
.bildbox.bild-fehlt.carfix { aspect-ratio: auto; height: 132px; }
|
||
/* Der Platzhalter belegt denselben Kasten wie ein echtes Foto (16:8). Er war
|
||
zwischenzeitlich auf 120 und dann 72px gestaucht, um die Reichweite
|
||
hoeher zu ruecken - auf Ansage des Besitzers steht er wieder in voller
|
||
Groesse, weil ein Streifen nicht erkennen laesst, was dort hingehoert. */
|
||
.bildbox.bild-fehlt.carfix.klein { aspect-ratio: 16 / 8; height: auto; }
|
||
/* Die Draufsicht auf der Fahrzeugseite ist eine Beigabe, keine Szene: sie
|
||
steht ueber den Sicherheitszeilen und soll die Zeilen nicht nach unten
|
||
draengen. Statt randlos ueber die volle Breite (rund 374px auf einem
|
||
Telefon, mit 16:8 also 187px hoch) steht sie eingerueckt und mittig -
|
||
60% Breite, die Hoehe geht im selben Verhaeltnis mit auf rund 112px
|
||
zurueck. Auf Ansage des Eigentuemers am 02.09.2026 ("Draufsicht-Foto
|
||
Bereich ist zu gross"): schmaler, nicht flacher - flacher haette bei
|
||
einem Foto, das nicht sehr breit ist, oben und unten geschnitten. */
|
||
.szene.bleed.schmal { margin: 0; padding: 22px 0 26px; }
|
||
.szene.bleed.schmal .carbox { width: 60%; margin: 0 auto; padding: 0; }
|
||
|
||
.szene.bleed:has(.bild-fehlt)::before { display: none; }
|
||
.szene.bleed:has(.bild-fehlt) { margin-left: 0; margin-right: 0; }
|
||
.szene.bleed:has(.bild-fehlt) .carbox { padding: 0; }
|
||
|
||
/* A5/C5: kein gestrichelter Rahmen und kein Dateiname mehr - Motivname plus
|
||
Aufforderung, die Fläche ist tippbar. */
|
||
.platzhalter {
|
||
width: 100%; height: 100%;
|
||
flex-direction: column; align-items: center; justify-content: center; gap: 7px;
|
||
background: var(--shade);
|
||
border: 1px solid var(--line);
|
||
border-radius: inherit;
|
||
color: var(--fg3);
|
||
text-align: center;
|
||
padding: var(--sp-3);
|
||
}
|
||
.platzhalter-icon { width: 26px; height: 26px; color: var(--fg3); }
|
||
.platzhalter-label { font-size: 13px; letter-spacing: normal; color: var(--fg2); }
|
||
.platzhalter-aktion { font-size: 12.5px; color: var(--fg3); }
|
||
|
||
.dots { display: flex; gap: 6px; justify-content: center; margin-top: 12px; }
|
||
.dots i { width: 5px; height: 5px; border-radius: 50%; background: var(--line-strong); }
|
||
.dots i.on { background: var(--red); }
|
||
|
||
/* white-space:nowrap: ohne die brach "SmartDeal-Ersparnis" neben dem
|
||
Markenlogo um. Kein Platzmangel, sondern ein Rundungsfehler - am
|
||
Einzelbeleg gemessen (04.09.2026, 375px breit): die dt-Spalte war 150,00px
|
||
breit, ihr eigener Inhalt 150,20px, also rutschte der Text hinter dem Logo
|
||
in eine zweite Zeile und die Zeile wurde 44,8px statt 26,4px hoch. Die
|
||
Zeile hat reichlich Platz (307px fuer 150 + 16 + 55), sie darf ihn nur nicht
|
||
abgeschnitten bekommen - dafuer gibt die Wertespalte in genau dieser Zeile
|
||
ihre feste Mindestbreite auf (.row-marke). */
|
||
.marke { display: inline-flex; align-items: center; gap: 6px; white-space: nowrap; }
|
||
.rows-fest .row-marke dd { min-width: 0; }
|
||
.marke-logo { display: inline-flex; align-items: center; }
|
||
/* 19,2px = 16px + 20%. Der Eigentuemer wollte das Markenlogo in JEDER
|
||
Darstellung um ein Fuenftel groesser; es steht ueberall neben Text der
|
||
Zeilenhoehe 16px, also hier eine Zahl statt mehrerer Sondergroessen. */
|
||
.marke-logo img { height: 19.2px; width: auto; }
|
||
.marke-logo .ph { display: none; font-size: 11px; letter-spacing: .06em; text-transform: uppercase; color: var(--fg3); }
|
||
.marke-logo.logo-fehlt img { display: none; }
|
||
.marke-logo.logo-fehlt .ph { display: inline; }
|
||
|
||
/* -------------------------------------------------------------- Formulare */
|
||
.feld {
|
||
display: flex; justify-content: space-between; align-items: center;
|
||
gap: var(--sp-4);
|
||
padding: 14px 0;
|
||
min-height: 56px;
|
||
border-bottom: 1px solid var(--line);
|
||
}
|
||
/* :not(.switch): der Schalter (Tanken/Einstellungen etc.) ist selbst ein
|
||
<label class="switch">, kein Textlabel - ohne den Ausschluss erbte er
|
||
dieselbe flex:1 1 auto-Regel und zog sich über die ganze Zeilenbreite. */
|
||
.feld label:not(.switch) { font-size: 14px; color: var(--fg2); flex: 1 1 auto; min-width: 0; line-height: 1.35; }
|
||
/* Eingaben nie breiter als die Kachel: die im Markup gesetzten festen
|
||
Breiten (width:132px) bleiben Obergrenze, schrumpfen aber mit. */
|
||
.feld input, .feld select, .notiz {
|
||
background: var(--tile-2);
|
||
border: 1px solid var(--line);
|
||
color: var(--fg);
|
||
font-family: inherit;
|
||
/* Muss >= 16px bleiben: Safari/WKWebView (und damit auch die HA-Companion-App
|
||
auf dem iPhone) zoomt die Seite beim Fokussieren automatisch hinein, wenn
|
||
das Feld kleiner als 16px gesetzt ist - der Nutzer muss dann nach jedem
|
||
Feld von Hand wieder herauszoomen. Vorher standen hier 15px. */
|
||
font-size: 16px;
|
||
padding: 11px 13px;
|
||
border-radius: 12px;
|
||
text-align: right;
|
||
min-width: 0;
|
||
max-width: 100%;
|
||
flex: 0 1 auto;
|
||
-webkit-appearance: none;
|
||
appearance: none;
|
||
}
|
||
.feld input:focus, .feld select:focus, .notiz:focus { outline: none; border-color: var(--red); }
|
||
/* z. B. Fahrgestellnummer bei aktivem "automatisch"-Schalter: der Wert kommt
|
||
aus den zugeordneten Sensoren, Handeingabe ist erst nach dem Ausschalten
|
||
wieder möglich - das Feld soll das auf den ersten Blick zeigen. */
|
||
.feld input:disabled { opacity: .5; cursor: not-allowed; }
|
||
/* Label und Eingabe untereinander statt nebeneinander, die Eingabe über die
|
||
volle Zeilenbreite - für Felder, deren Wert typischerweise länger ist als
|
||
ein Kurztext (Kommentar bei Sommer-/Winterrädern, live wie archiviert).
|
||
Sonst gilt .feld input oben: die Eingabe wächst nie über ihre intrinsische
|
||
Breite, nur das Label tut das (flex:1 1 auto) - für einen Reifenkommentar
|
||
("Profiltiefe 5,1 mm bei der letzten Montage") reichte das nicht. */
|
||
.feld--breit { display: block; }
|
||
.feld--breit label { display: block; margin-bottom: 8px; }
|
||
.feld--breit input { width: 100%; text-align: left; }
|
||
/* Das AUFGEKLAPPTE <select>-Popup ist Browser-/OS-Chrome, kein Teil des
|
||
Seiten-DOMs - color-scheme (siehe :host weiter oben) beeinflusst es nur
|
||
teilweise, der Rest bleibt hell. Einzige zuverlaessige Stellschraube:
|
||
Chrome (u.a.) rendert die Zeilen im Popup tatsaechlich mit dem hier
|
||
gesetzten background-color/color statt Systemfarben - deckende Werte,
|
||
var(--tile-2) im Nacht-Theme ist transparent und wuerde durchscheinen. */
|
||
.feld select option { background-color: var(--canvas); color: var(--fg); }
|
||
/* Pull-down-Button-Optik (Apple HIG): einzelner Abwaerts-Chevron statt des
|
||
durch appearance:none oben entfernten nativen Browser-Pfeils. */
|
||
.feld select {
|
||
padding-right: 30px;
|
||
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'%3E%3Cpath d='M2.5 4.5l3.5 3.5 3.5-3.5' fill='none' stroke='%238a94a3' stroke-width='1.4' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
|
||
background-repeat: no-repeat;
|
||
background-position: right 11px center;
|
||
background-size: 10px 10px;
|
||
}
|
||
:host([data-theme=tag]) .feld select {
|
||
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'%3E%3Cpath d='M2.5 4.5l3.5 3.5 3.5-3.5' fill='none' stroke='%23666666' stroke-width='1.4' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
|
||
}
|
||
.feld > span { flex: 0 1 auto; min-width: 0; }
|
||
.mitEinheit { display: inline-flex; align-items: center; gap: var(--sp-2); max-width: 100%; }
|
||
.mitEinheit input { min-width: 0; width: 96px; text-align: right; }
|
||
.mitEinheit span:last-child { font-size: 13px; color: var(--fg2); }
|
||
.druckfeld { width: 58px !important; min-width: 0 !important; }
|
||
.notiz { width: 100%; text-align: left; margin-top: 14px; line-height: 1.55; resize: vertical; }
|
||
|
||
.switch { position: relative; display: inline-block; flex-shrink: 0; width: 46px; height: 27px; }
|
||
.switch input { position: absolute; inset: 0; opacity: 0; margin: 0; cursor: pointer; min-width: 0; }
|
||
.switch .track {
|
||
position: absolute; inset: 0;
|
||
background: var(--tile-2);
|
||
border: 1px solid var(--line);
|
||
border-radius: var(--r-pill);
|
||
transition: background .18s;
|
||
pointer-events: none;
|
||
}
|
||
.switch .track::before {
|
||
content: ""; position: absolute; left: 2px; top: 1px;
|
||
width: 23px; height: 23px; background: #fff; border-radius: 50%;
|
||
transition: transform .18s;
|
||
}
|
||
/* A7: Rot bleibt Akzent und Destruktiv. Der aktive Schalter trägt --fg mit
|
||
dunklem Knopf. */
|
||
.switch input:checked + .track { background: var(--fg); border-color: var(--fg); }
|
||
.switch input:checked + .track::before { transform: translateX(19px); background: var(--canvas); }
|
||
|
||
/* Schieberegler - Zwilling von .ads-schieber im Design-System.
|
||
|
||
Ein echtes input[type=range], damit Tastatur und Vorlesefunktion ohne
|
||
Zutun stimmen; gemalt wird selbst, sonst saehe er im Panel wie Chrome und
|
||
in der App wie WebKit aus. Der gefuellte Teil kommt aus --fuell, weil ein
|
||
Range-Feld seinen Wert nicht ans Stylesheet weitergibt und accent-color
|
||
entfaellt, sobald man die Spur selbst gestaltet (gesetzt beim Rendern und
|
||
im input-Zweig der Ereignisse).
|
||
|
||
Die beiden Spur-Regeln lassen sich NICHT zusammenfassen: einen unbekannten
|
||
Selektor verwirft der Browser samt der ganzen Regel. */
|
||
.schieber { display: flex; align-items: center; gap: 16px; min-width: 0; }
|
||
/* 28 px hoch bei 4 px Spur: das ist die Trefferflaeche des Daumens. */
|
||
.schieber input[type=range] {
|
||
-webkit-appearance: none; appearance: none;
|
||
flex: 1 1 auto; min-width: 0; height: 28px;
|
||
margin: 0; padding: 0; background: transparent; cursor: pointer;
|
||
}
|
||
.schieber input[type=range]::-webkit-slider-runnable-track {
|
||
height: 4px; border-radius: var(--r-pill);
|
||
background: linear-gradient(to right, var(--fg) var(--fuell, 0%), var(--ios-fill) var(--fuell, 0%));
|
||
}
|
||
.schieber input[type=range]::-moz-range-track {
|
||
height: 4px; border-radius: var(--r-pill);
|
||
background: linear-gradient(to right, var(--fg) var(--fuell, 0%), var(--ios-fill) var(--fuell, 0%));
|
||
}
|
||
/* margin-top zentriert den Daumen auf der Spur: (4 - 28) / 2 = -12. */
|
||
.schieber input[type=range]::-webkit-slider-thumb {
|
||
-webkit-appearance: none; appearance: none; box-sizing: border-box;
|
||
width: 28px; height: 28px; margin-top: -12px; border-radius: 50%;
|
||
/* Der Ring ist der Trick fuer den Tagmodus: --line-strong ist dort
|
||
rgba(0,0,0,.22) und zeichnet den weissen Daumen gegen die helle Kachel
|
||
ab, im Nachtmodus rgba(255,255,255,.20) - auf Weiss also unsichtbar, wo
|
||
er nicht gebraucht wird. Ein Token, zwei Themen. */
|
||
border: 1px solid var(--line-strong);
|
||
background: #fff; box-shadow: 0 1px 3px rgba(0,0,0,.22), 0 4px 10px rgba(0,0,0,.16);
|
||
}
|
||
.schieber input[type=range]::-moz-range-thumb {
|
||
box-sizing: border-box; width: 28px; height: 28px; border-radius: 50%;
|
||
border: 1px solid var(--line-strong);
|
||
background: #fff; box-shadow: 0 1px 3px rgba(0,0,0,.22), 0 4px 10px rgba(0,0,0,.16);
|
||
}
|
||
.schieber input[type=range]:focus-visible { outline: none; }
|
||
.schieber input[type=range]:focus-visible::-webkit-slider-thumb {
|
||
box-shadow: 0 0 0 3px var(--line-strong), 0 3px 8px rgba(0,0,0,.16);
|
||
}
|
||
/* Feste Mindestbreite und Ziffern gleicher Laufweite: sonst ruckelt der
|
||
Regler seitlich, sobald der Wert von 9 auf 10 springt. */
|
||
/* Knopf in einer Listenzeile - heute nur "Fahrt beenden" in der
|
||
Zuletzt-Kachel. 36 px sichtbar, 44 px Trefferhoehe ueber das
|
||
Pseudoelement, damit die Zeile nicht hoeher wird als ihre Nachbarin. */
|
||
.zeilenknopf {
|
||
position: relative; flex: 0 0 auto;
|
||
font-family: inherit; font-size: 13px; letter-spacing: .01em;
|
||
color: var(--fg); background: none; border: 1px solid var(--line-strong);
|
||
border-radius: var(--r-pill); padding: 8px 15px; min-height: 36px; cursor: pointer;
|
||
}
|
||
.zeilenknopf:hover { background: var(--shade); }
|
||
.zeilenknopf:active { opacity: .55; }
|
||
.zeilenknopf::before { content: ""; position: absolute; inset: -4px 0; }
|
||
/* Gruen wie der Sicherheits-Haken: es laeuft gerade etwas. */
|
||
.leaf .k small.laeuft { color: var(--ok); }
|
||
.leaf .v small.vorlaeufig { color: var(--fg3); }
|
||
|
||
.schieber output {
|
||
flex: 0 0 auto; min-width: 62px; text-align: right;
|
||
font-size: 13px; font-variant-numeric: tabular-nums; color: var(--fg2);
|
||
}
|
||
|
||
/* C3: gemischt geschrieben, 15 px, 48 px hoch. .primaer ist gefüllt,
|
||
.aktion allein bleibt die Umriss-Sekundäraktion. */
|
||
.aktion {
|
||
display: block; width: 100%;
|
||
font-family: inherit; font-size: 15px;
|
||
letter-spacing: normal;
|
||
color: var(--fg);
|
||
background: none;
|
||
border: 1px solid var(--line-strong);
|
||
border-radius: var(--r-pill);
|
||
padding: 14px 18px;
|
||
min-height: 48px;
|
||
margin-top: var(--sp-4);
|
||
cursor: pointer;
|
||
transition: border-color .15s, background .15s, transform .1s, opacity .15s;
|
||
}
|
||
.aktion + .aktion, .aktion + label.aktion { margin-top: 10px; }
|
||
.aktion:hover { border-color: var(--line-strong); background: var(--shade); }
|
||
.aktion:active { transform: scale(.985); background: var(--shade); }
|
||
.aktion.primaer { background: var(--fg); border-color: var(--fg); color: var(--canvas); }
|
||
.aktion.primaer:hover { opacity: .9; background: var(--fg); }
|
||
.aktion.primaer:active { opacity: .8; background: var(--fg); }
|
||
.aktion.loeschen { color: var(--bad); border-color: var(--bad); background: none; }
|
||
.aktion.loeschen:hover { background: var(--bad); color: #fff; }
|
||
.aktion.loeschen:active { background: var(--bad); color: #fff; }
|
||
|
||
/* C4: eine Bahn mit wanderndem Knopf statt zwei getrennter Umrisspillen. */
|
||
.seg {
|
||
display: flex; gap: 0;
|
||
background: var(--tile-2);
|
||
border-radius: var(--r-pill);
|
||
padding: 3px;
|
||
}
|
||
.seg button {
|
||
flex: 1;
|
||
border: none;
|
||
background: none;
|
||
color: var(--fg2);
|
||
font-family: inherit;
|
||
font-size: 14px;
|
||
letter-spacing: normal;
|
||
padding: 11px 8px;
|
||
min-height: 44px;
|
||
border-radius: var(--r-pill);
|
||
cursor: pointer;
|
||
transition: background .18s, color .18s;
|
||
}
|
||
.seg button.on { background: var(--fg); color: var(--canvas); }
|
||
.seg button:active { opacity: .8; }
|
||
|
||
.pill {
|
||
display: inline-flex; align-items: center;
|
||
font-size: 12.5px; letter-spacing: normal;
|
||
color: var(--fg2);
|
||
background: none;
|
||
border: 1px solid var(--line-strong);
|
||
border-radius: var(--r-pill);
|
||
padding: 6px 12px;
|
||
}
|
||
|
||
/* ------------------------------------------------------------ Akkordeon */
|
||
.acc-h {
|
||
display: flex; align-items: center; gap: var(--sp-3);
|
||
width: 100%;
|
||
background: none; border: none;
|
||
font-family: inherit; text-align: left;
|
||
padding: 15px 0;
|
||
min-height: 56px;
|
||
cursor: pointer;
|
||
border-bottom: 1px solid var(--line);
|
||
color: inherit;
|
||
}
|
||
.acc-h .k { flex: 1; font-size: 15px; color: var(--fg); }
|
||
.acc-h .v { font-size: 12.5px; color: var(--fg2); text-align: right; white-space: nowrap; flex: 0 0 auto; }
|
||
/* Ohne eigene Regel erbt <small> den UA-Wert "smaller" (0,833x) - im
|
||
Akkordeonkopf sind das 10,4px und damit unter der 11px-Untergrenze, die
|
||
dieses Projekt aus den Apple-Richtlinien uebernommen hat. */
|
||
.acc-h .v small { font-size: 11px; }
|
||
.acc-h { transition: background .15s; }
|
||
.acc-h:active { background: var(--tile-2); }
|
||
.mark {
|
||
/* Design-Audit 2026-08-13: die Border-Ecken-Technik (zwei Kanten +
|
||
45deg-Drehung) braucht ein Quadrat, um einen sauberen Chevron zu
|
||
ergeben - bei 6x10px (nicht quadratisch, wie fuer die SVG-Chevrons
|
||
.chev/.go gedacht) sind die beiden Kantenlaengen ungleich lang und das
|
||
Ergebnis sah eher wie ein Haekchen als ein Pfeil aus. */
|
||
width: 8px; height: 8px;
|
||
border-right: 1.4px solid var(--fg3);
|
||
border-bottom: 1.4px solid var(--fg3);
|
||
transform: rotate(-45deg);
|
||
transition: transform .15s, border-color .15s;
|
||
flex: 0 0 auto;
|
||
}
|
||
/* A8: ein Chevron, eine Farbe - nur die Drehung zeigt den Zustand. */
|
||
.acc-h[aria-expanded=true] .mark { transform: rotate(45deg); }
|
||
/* Kachelkoepfe der Statistik verhalten sich wie Aufklapp-Zeilen. */
|
||
.stat-kopfzeile { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-3); }
|
||
.stat-kopfzeile .label { flex: 1; }
|
||
.tile-h[aria-expanded=true] .mark { transform: rotate(45deg); }
|
||
.acc-b { display: none; }
|
||
.acc-b.on { display: block; }
|
||
.lvl2 { margin-left: 22px; }
|
||
.lvl2 .acc-h .k { font-size: 13px; }
|
||
|
||
/* Fahrten- und Tankliste: Abschnittsköpfe statt Einrückung.
|
||
|
||
Gemessen am 02.09.2026 im laufenden Panel: von der Innenkante der
|
||
Kachel bis zum Ortsnamen lagen 58px tote Breite - 22px Einrückung der
|
||
Monatsebene plus 40px linkes Polster der Zeile. Auf einem Telefon blieb
|
||
für "Eichstätt → Adelschlag" so wenig übrig, dass der Name umbrach
|
||
(gemeldet vom Eigentümer mit Bildschirmfoto).
|
||
|
||
Apples Richtlinien lösen Gruppierung nicht über Einrückung, sondern über
|
||
Abschnittsköpfe, die über die volle Breite laufen; die Zeilen darunter
|
||
stehen alle auf derselben Kante. Genau das ist hier umgesetzt - die
|
||
Monatszeile bleibt kleiner und grau und liest sich dadurch als Kopf,
|
||
ohne Platz zu kosten. Beschränkt auf .liste, weil das linke Polster von
|
||
.leaf anderswo (Batteriewerte, Servicebuch) gewollt ist. */
|
||
.liste .lvl2 { margin-left: 0; }
|
||
/* Jahr und Monat tragen DENSELBEN Kopf, die Fahrtzeile traegt den Inhalt.
|
||
|
||
In der Liste standen drei Elemente in drei Formaten: 2026 in 16px weiss,
|
||
September in 11px grau gesperrt in Versalien, der Ortsname wieder in 16px
|
||
weiss. Der Eigentuemer hat das am 02.09.2026 als unprofessionell
|
||
bezeichnet - zu Recht: zwei Koepfe, die dasselbe tun, sollen auch gleich
|
||
aussehen.
|
||
|
||
Beide jetzt 13px in der Zweitfarbe, gemischt geschrieben und ohne
|
||
Sperrung. Das ist zugleich die heutige Apple-Form: Abschnittskoepfe
|
||
klein und in Sekundaerfarbe, aber gemischt - Versalien sind der Stil vor
|
||
iOS 13. Der Inhalt bleibt groesser als sein Kopf, wie es die Richtlinien
|
||
verlangen. Unterschieden werden die beiden Ebenen ueber die Position,
|
||
nicht ueber die Schrift.
|
||
|
||
Von drei Vorschlaegen (Monat als eigener Abschnitt ohne Aufklappen /
|
||
beide Koepfe gleich / Jahr als Seitenueberschrift) hat der Eigentuemer
|
||
diesen gewaehlt: das Zusammenklappen ganzer Jahre bleibt erhalten. */
|
||
.liste .acc-h .k {
|
||
font-size: 13px;
|
||
color: var(--fg2);
|
||
}
|
||
/* 20px statt 0: die Zeilen standen sonst 34px vom Bildschirmrand entfernt und
|
||
damit sichtbar enger als alles andere in der Kachel (gemeldet 02.09.2026).
|
||
20px ist nicht geraten, sondern die Spalte des Aufklapp-Pfeils - die
|
||
Zeilen stehen damit auf derselben Kante wie der Text der Kopfzeilen, so
|
||
wie iOS es in gruppierten Listen macht.
|
||
|
||
Nachgemessen bei 375px: die Beschriftungsspalte behaelt 157px, der
|
||
laengste Ortsname der Testdaten ("Ingolstadt -> Adelschlag") braucht
|
||
142,7px. Von den 58px, die vorher verschenkt waren, bleiben 38 gewonnen. */
|
||
.liste .leaf { padding-left: 20px; }
|
||
|
||
.tile-h {
|
||
display: block; width: 100%;
|
||
background: none; border: none;
|
||
font-family: inherit; text-align: left;
|
||
padding: 0; cursor: pointer; color: inherit;
|
||
}
|
||
.tile-b { display: none; }
|
||
.tile-b.on { display: block; }
|
||
|
||
/* -------------------------------------------------------------- Statistik */
|
||
/* Fuenf Spalten (Jahr/Monat/Woche/Tag/Absolut) passen auf einem Telefon nicht
|
||
nebeneinander: bei 307px Innenbreite blieben je 51px, und "209.177" braucht
|
||
bei 16px Audi Type Wide rund 60. auto-fit bricht deshalb um - auf dem Telefon
|
||
drei plus zwei, auf einem breiten Bildschirm alle fuenf in einer Reihe. */
|
||
/* Vier feste Spalten - Jahr, Monat, Woche, Tag muessen in EINE Zeile passen.
|
||
|
||
Vorher stand hier repeat(auto-fit, minmax(84px, 1fr)). Auf dem Telefon ist
|
||
die Kachel innen 307px breit, damit passten bei 12px Abstand nur drei
|
||
Spalten (3 x 84 + 2 x 12 = 276; vier waeren 372) - die vierte rutschte in
|
||
eine zweite Zeile.
|
||
|
||
Mit vier festen Spalten bleiben 67,75px je Spalte. Der laengste realistisch
|
||
vorkommende Wert ist ein sechsstelliger Kilometerstand wie "209.177": am
|
||
laufenden Panel gemessen 67px in Audi Type Wide 300 bei 16px. Es passt
|
||
also, aber ohne Reserve - eine fuenfte Spalte gaebe es nur mit kleinerer
|
||
Schrift, und genau deshalb steht der Gesamtwert jetzt in der Kopfzeile der
|
||
Kachel statt in einer eigenen Spalte.
|
||
|
||
Bewusst kein white-space:nowrap: waere ein Wert doch einmal breiter,
|
||
umbricht er innerhalb seiner Spalte, statt aus der Kachel zu laufen. */
|
||
.quad { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: var(--sp-3); margin-top: var(--sp-3); }
|
||
.quad .n { display: block; font-family: "Audi Type Wide", var(--font-stack); font-size: 16px; font-weight: 300; color: var(--fg); line-height: 1.2; }
|
||
.quad .l { display: block; margin-top: 4px; font-size: 11px; letter-spacing: normal; color: var(--fg3); line-height: 1.3; }
|
||
.bar { display: flex; height: 4px; border-radius: var(--r-pill); overflow: hidden; gap: 2px; }
|
||
.bar i { display: block; border-radius: var(--r-pill); }
|
||
.legend { display: flex; flex-wrap: wrap; gap: var(--sp-3); margin-top: var(--sp-2); font-size: 11px; color: var(--fg2); }
|
||
.legend span { display: inline-flex; align-items: center; gap: 6px; }
|
||
.legend i { width: 8px; height: 8px; border-radius: 50%; display: inline-block; }
|
||
|
||
/* -------------------------------------------------------------- Wischen */
|
||
.swipe-wrap { position: relative; overflow: hidden; }
|
||
/* Der rote Loeschknopf liegt dauerhaft hinter der Zeile. Zeilenhoehen sind
|
||
gebrochen (z. B. 66,28 px), dadurch fiel die Kante von .swipe-content nicht
|
||
aufs Geraetepixelraster und der rote Knopf blitzte als duenne Linie an den
|
||
Zeilenraendern durch - sichtbar als roter Teilrahmen um jede Listenzeile.
|
||
Er wird deshalb erst sichtbar, sobald wirklich gewischt wird ("wischt"
|
||
waehrend der Geste, "swiped" fuer die offen stehende Zeile). */
|
||
.swipe-delete { position: absolute; inset: 0 0 0 auto; width: 84px; display: flex; visibility: hidden; }
|
||
.swipe-wrap.wischt .swipe-delete,
|
||
.swipe-wrap.swiped .swipe-delete { visibility: visible; }
|
||
.swipe-loeschen {
|
||
width: 100%;
|
||
background: var(--bad); color: #fff; border: none;
|
||
font-family: inherit; font-size: 13px;
|
||
letter-spacing: normal;
|
||
cursor: pointer;
|
||
}
|
||
.swipe-loeschen:active { filter: brightness(.88); }
|
||
.swipe-content { position: relative; background: var(--tile); touch-action: pan-y; transition: transform .18s; }
|
||
.swipe-wrap.swiped .swipe-content { transform: translateX(-84px); }
|
||
|
||
/* -------------------------------------------------------------- Karte */
|
||
/* position:relative, damit der Zentrieren-Knopf im Einzelbeleg (absolut
|
||
positioniert, siehe .kartensteuerung-klein) sich an dieser Kachel ausrichtet
|
||
und nicht am naechsten Vorfahren weiter oben. */
|
||
.mapbox { position: relative; border-radius: var(--r-tile); overflow: hidden; height: 210px; background: var(--tile); }
|
||
.mapbox #map { width: 100%; height: 100%; }
|
||
|
||
/* --------------------------------------------------------- Standort
|
||
Vorschau-Kachel (Übersicht) + Vollbildansicht + Fahrzeug-Menü. Höhen sind
|
||
bewusst fest statt prozentual/vererbt - eine relative Höhe wird von
|
||
panel_custom nicht zuverlässig durchgereicht (siehe audi-dashboard-
|
||
ios.css-Kommentar zur selben Falle). */
|
||
.standort-kachel { padding: 0; overflow: hidden; }
|
||
.standort-kachelbtn {
|
||
display: block; width: 100%; position: relative;
|
||
border: none; padding: 0; margin: 0; background: none; cursor: pointer;
|
||
}
|
||
.standort-vorschau { width: 100%; height: 190px; background: var(--tile); }
|
||
.standort-leer {
|
||
position: absolute; inset: 0;
|
||
display: flex; align-items: center; justify-content: center;
|
||
font-size: 13px; color: var(--fg3); text-align: center; padding: 0 30px;
|
||
background: var(--tile);
|
||
}
|
||
|
||
.fahrzeug-pin-wrap { background: none; border: none; }
|
||
/* poi-car/poi aus dem CI-Satz sind reine Konturformen (Ring aus zwei
|
||
gegenlaeufigen Randlinien + duenne Detaillinien) - eine Pixelprobe ergab
|
||
nur 13-40% gefuellte Flaeche in der eigenen Bounding-Box und war auf
|
||
Kartenkacheln praktisch unsichtbar (Nutzer-Feedback "Pin ist transparent").
|
||
fahrzeugMarkerSVG()/tankstellenMarkerSVG() rendern deshalb zusaetzlich eine
|
||
Vollton-Silhouette (CI.*Sil, exakt der aeussere Ballon-Umriss desselben
|
||
CI-Pfads, keine Neuzeichnung) als unterste Ebene; die Iconfarbe hier ist
|
||
deshalb weiss statt dunkel, damit Umriss und Detaillinien auf der jetzt
|
||
massiven Flaeche lesbar bleiben. Feste Farben statt Theme-Variablen, damit
|
||
die Nadeln in Tag- und Nachtansicht gleich aussehen. */
|
||
.fahrzeug-pin {
|
||
display: flex; align-items: center; justify-content: center;
|
||
color: #fff;
|
||
filter: drop-shadow(0 2px 4px rgba(0,0,0,.4));
|
||
}
|
||
.user-pin-wrap { background: none; border: none; }
|
||
.user-pin {
|
||
position: relative; width: 16px; height: 16px; border-radius: 50%;
|
||
background: #0A84FF; border: 3px solid #fff;
|
||
box-shadow: 0 2px 6px rgba(0,0,0,.3);
|
||
}
|
||
.user-pin::after {
|
||
content: ""; position: absolute; inset: -14px; border-radius: 50%;
|
||
background: rgba(10,132,255,.18);
|
||
animation: user-pulse 2.4s ease-out infinite;
|
||
}
|
||
@keyframes user-pulse { 0% { transform: scale(.4); opacity: .9; } 100% { transform: scale(1); opacity: 0; } }
|
||
|
||
.standort-vollbild { position: relative; height: min(640px, calc(100dvh - 190px)); border-radius: var(--r-tile); overflow: hidden; margin: 0 calc(-1 * var(--seitenrand)); }
|
||
.standort-karte { width: 100%; height: 100%; }
|
||
|
||
.kartensteuerung {
|
||
position: absolute; z-index: 400; top: 16px; right: 16px;
|
||
display: flex; flex-direction: column; gap: 12px;
|
||
}
|
||
.kartensteuerung button {
|
||
width: 48px; height: 48px; border-radius: 50%;
|
||
display: flex; align-items: center; justify-content: center;
|
||
background: rgba(16, 20, 26, .84); color: #fff;
|
||
border: none; box-shadow: 0 4px 14px rgba(0,0,0,.32);
|
||
-webkit-backdrop-filter: blur(10px); backdrop-filter: blur(10px);
|
||
cursor: pointer; padding: 0;
|
||
}
|
||
/* Tag-Theme: helle Kapsel mit dunklem Symbol - die CI-Symbole selbst tragen
|
||
fill="currentColor" und folgen der Textfarbe, es gibt keine zweite Datei. */
|
||
:host([data-theme="tag"]) .kartensteuerung button {
|
||
background: rgba(255,255,255,.92); color: #101418;
|
||
box-shadow: 0 4px 14px rgba(0,0,0,.18);
|
||
}
|
||
.kartensteuerung button:active { transform: scale(.94); }
|
||
:host([data-theme="tag"]) .kartensteuerung button:active { background: #fff; }
|
||
/* Variante in der Belegkarte: die Karte ist dort nur 210px hoch, ein 48er-
|
||
Knopf mit 16px Abstand wuerde ein Viertel davon verdecken. */
|
||
.kartensteuerung-klein { top: 10px; right: 10px; }
|
||
.kartensteuerung-klein button { width: 36px; height: 36px; }
|
||
.kartensteuerung-klein button:disabled { opacity: .45; cursor: default; }
|
||
.kartensteuerung-klein button:disabled:active { transform: none; }
|
||
|
||
/* Sichtbarer Anteil im geschlossenen Zustand (STANDORT_PEEK_PX im Frontend) -
|
||
beide Werte müssen zusammenpassen, siehe Kommentar dort. Der Rest des
|
||
Blatts wird nach unten geschoben und mit einem Zug nach oben geöffnet. */
|
||
.standortmenu {
|
||
position: absolute; z-index: 410; left: 0; right: 0; bottom: 0;
|
||
--standort-peek: 96px;
|
||
/* Deckend, nicht durchscheinend - unter dem Blatt liegt die Karte. */
|
||
background: var(--tile-deckend, var(--canvas));
|
||
border-radius: var(--r-tile) var(--r-tile) 0 0;
|
||
box-shadow: 0 -6px 24px rgba(0,0,0,.35);
|
||
/* Kein env(safe-area-inset-bottom) mehr: das Blatt liegt nicht am unteren
|
||
Bildschirmrand, sondern ueber der Tableiste - und die haelt den Bereich
|
||
des Home-Indikators bereits frei. Der Einzug wurde dadurch doppelt
|
||
gezaehlt, das Blatt war auf dem Geraet rund 16px hoeher als noetig und
|
||
schob sich entsprechend weiter hoch. Am Rechner faellt das nicht auf,
|
||
dort ist der Einzug 0. */
|
||
padding: 0 20px 34px;
|
||
transform: translateY(calc(100% - var(--standort-peek)));
|
||
transition: transform .28s cubic-bezier(.22,.61,.36,1);
|
||
}
|
||
/* Aufgezogen bleibt unter den Knoepfen ein fester Abstand stehen, statt dass
|
||
sie buendig mit der Menueleiste abschliessen.
|
||
|
||
Vorher stand hier min-height:50% - Apples "medium detent". Gemessen ergab
|
||
das 89px (Panel) bzw. 76px (App) Luft unter dem letzten Knopf, und das war
|
||
sichtbar zu viel: das Blatt zog ueber die Haelfte des Bildschirms auf,
|
||
obwohl sein Inhalt dort laengst zu Ende war. Eine Raste ist nur dann
|
||
richtig, wenn zwischen ihr und der Inhaltshoehe kein grosses Loch klafft.
|
||
|
||
Jetzt bestimmt der Inhalt die Hoehe, und die 34px Fussabstand halten die
|
||
Knoepfe von der Leiste frei - hergeleitet aus der Beanstandung, nicht
|
||
geraten: 18px waren zu wenig, 76-89px zu viel. */
|
||
.standortmenu.offen { transform: translateY(0); }
|
||
.standortmenu-griffzone { padding: 10px 0 14px; touch-action: none; cursor: grab; position: relative; }
|
||
/* Der Griff ist jetzt ein Knopf (Tastaturzugang zum Menue). Die Knopf-
|
||
Voreinstellungen des Browsers werden deshalb zurueckgesetzt; die
|
||
Trefferflaeche waechst per Pseudo-Element auf 44px, ohne den sichtbaren
|
||
Strich zu vergroessern. */
|
||
.standortmenu-griff {
|
||
position: relative; display: block; width: 36px; height: 4px;
|
||
border: 0; padding: 0; border-radius: 2px;
|
||
background: var(--line-strong); margin: 0 auto; cursor: pointer;
|
||
}
|
||
.standortmenu-griff::after {
|
||
content: ""; position: absolute; left: 50%; top: 50%;
|
||
transform: translate(-50%, -50%); width: 88px; height: 44px;
|
||
}
|
||
/* --ios-fill statt --tile: das Blatt selbst ist deckend, im Tagmodus also
|
||
weiss - und --tile ist dort ebenfalls #FFFFFF. Der Knopf war damit weiss
|
||
auf weiss und als Knopf nicht zu erkennen. Nachts faellt es nicht auf,
|
||
weil --tile dort ein Schleier ueber dunklem Grund ist. --ios-fill ist in
|
||
diesem Projekt ohnehin das Zeichen fuer "das hier laesst sich bedienen"
|
||
und traegt in beiden Themes. */
|
||
.standortmenu-schliessen {
|
||
position: absolute; top: 14px; right: 0; width: 32px; height: 32px; border-radius: 50%;
|
||
display: flex; align-items: center; justify-content: center;
|
||
background: var(--ios-fill); border: none; color: var(--fg2); cursor: pointer; padding: 0;
|
||
}
|
||
/* Sichtbar nur im aufgezogenen Blatt (Begruendung am Knopf im Markup). */
|
||
.standortmenu-schliessen { display: none; }
|
||
.standortmenu.offen .standortmenu-schliessen { display: flex; }
|
||
.standortmenu-kopf { margin-top: 8px; padding-right: 44px; }
|
||
.standortmenu-name { font-size: 17px; color: var(--fg); }
|
||
.standortmenu-distanz { font-size: 12.5px; color: var(--fg3); margin-top: 4px; }
|
||
/* Abstand als leere Zeile zwischen Kopf und Details */
|
||
.standortmenu-adresse { font-size: 13px; color: var(--fg2); margin-top: 20px; }
|
||
.standortmenu-status { display: flex; align-items: center; gap: 9px; margin-top: 8px; font-size: 13px; color: var(--fg2); }
|
||
.standortmenu-status svg { color: var(--fg3); flex: 0 0 auto; }
|
||
.standortmenu-werte { display: flex; align-items: center; gap: 10px; margin-top: 8px; font-size: 13px; color: var(--fg2); }
|
||
.standortmenu-werte svg { color: var(--fg3); flex: 0 0 auto; }
|
||
.standortmenu-aktionen { display: flex; gap: 10px; margin-top: 18px; padding-bottom: 4px; }
|
||
/* Beide Pillen folgen der Knopfsprache des restlichen Panels (.aktion /
|
||
.aktion.primaer weiter oben): Umriss fuer die Nebenaktion, gefuellt fuer
|
||
die Hauptaktion.
|
||
|
||
Vorher stand hier background: var(--tile) fuer "Teilen" und
|
||
background: var(--line-strong) fuer "Route". Beides ging im Tagmodus
|
||
schief: das Blatt darunter ist var(--tile-deckend), und die iOS-Auflage
|
||
(audi-dashboard-ios.css) setzt im Tagmodus --tile UND --tile-deckend
|
||
beide auf #FFFFFF - "Teilen" war damit weiss auf weiss, Kontrast 1,0:1,
|
||
also schlicht unsichtbar. --line-strong als Flaeche war ausserdem eine
|
||
Linienfarbe in der Rolle einer Fuellung.
|
||
|
||
Der Umriss haengt jetzt an denselben Tokens wie jeder andere Knopf und
|
||
traegt deshalb in beiden Themes und auch unter der iOS-Auflage, ohne dass
|
||
hier eine eigene Farbe gepflegt werden muss. */
|
||
.standort-pille {
|
||
display: inline-flex; align-items: center; justify-content: center; gap: 8px;
|
||
height: 40px; padding: 0 20px; border-radius: var(--r-pill);
|
||
border: 1px solid var(--line-strong); background: none; color: var(--fg);
|
||
font-family: inherit; font-size: 14px; text-decoration: none; cursor: pointer;
|
||
}
|
||
.standort-pille.primaer {
|
||
background: var(--fg); border-color: var(--fg); color: var(--canvas);
|
||
}
|
||
.standort-pille:active { transform: scale(.97); }
|
||
.standort-pille[disabled] { opacity: .4; pointer-events: none; }
|
||
|
||
/* ------------------------------------------------------- Bilderverwaltung */
|
||
/* ---------------------------------------------------------- Blätter
|
||
Apples Vorgabe kennt für etwas Modales auf dem Telefon kein frei
|
||
schwebendes Fenster: es kommt von der unteren Kante. Das Aktionsblatt
|
||
(eine kurze Liste von Wegen) und das Formularblatt (eine Eingabe) sind
|
||
die beiden Formen; die Karte in der Bildschirmmitte war keine von
|
||
beiden und stand ausserdem ohne abgedunkelten Grund über der voll
|
||
sichtbaren Seite.
|
||
|
||
Der Schleier gehört dazu und ist nicht Geschmack: modal heisst, dass
|
||
der Inhalt dahinter nicht bedienbar ist - das soll man sehen. */
|
||
.bildmenu-catcher {
|
||
position: absolute; inset: 0; z-index: 1000;
|
||
background: rgba(0,0,0,.45);
|
||
animation: sheet-fade .18s ease-out;
|
||
}
|
||
.bildmenu {
|
||
position: absolute; z-index: 1001;
|
||
left: 10px; right: 10px;
|
||
bottom: max(10px, env(safe-area-inset-bottom));
|
||
top: auto;
|
||
transform: none;
|
||
background: var(--tile-deckend, var(--canvas));
|
||
border-radius: 16px;
|
||
overflow: hidden;
|
||
padding: 0;
|
||
display: flex; flex-direction: column;
|
||
animation: sheet-rein .24s cubic-bezier(.22,.61,.36,1);
|
||
}
|
||
/* Die beiden Lage-Varianten sind gegenstandslos geworden - ein Blatt
|
||
kommt immer von unten. Die Klassen bleiben im Markup stehen, damit die
|
||
Aufrufstellen unberührt bleiben; hier tragen sie nichts mehr bei. */
|
||
.bildmenu.rad, .bildmenu.ansicht { left: 10px; right: 10px; top: auto; transform: none; }
|
||
.bildmenu button {
|
||
display: block; width: 100%; text-align: left;
|
||
background: none; border: none;
|
||
color: var(--fg); font-family: inherit; font-size: 16px;
|
||
padding: 16px 18px; min-height: 52px; border-radius: 0;
|
||
border-bottom: 1px solid var(--line);
|
||
cursor: pointer;
|
||
}
|
||
.bildmenu button:last-child { border-bottom: none; }
|
||
.bildmenu button:active { background: var(--shade); }
|
||
.bildmenu button.loeschen { color: var(--bad); }
|
||
|
||
/* Formularblatt (siehe Kasten oben): unten angeschlagen, nur oben rund,
|
||
blickdicht. Stand vorher als Karte 60px unter dem oberen Rand - ausser
|
||
Daumenreichweite und ohne sichtbaren Weg hinaus. */
|
||
.sdpopup {
|
||
position: absolute; z-index: 1001;
|
||
left: 0; right: 0; bottom: 0; top: auto;
|
||
background: var(--tile-deckend, var(--canvas));
|
||
border-radius: 16px 16px 0 0;
|
||
padding: var(--sp-4) 20px max(20px, env(safe-area-inset-bottom));
|
||
animation: blatt-hoch .28s cubic-bezier(.22,.61,.36,1);
|
||
}
|
||
@keyframes blatt-hoch { from { transform: translateY(100%) } to { transform: none } }
|
||
|
||
/* Beleg-Fenster: PDF hineinziehen (Rechner) oder einfügen (Telefon). */
|
||
.beleg-catcher {
|
||
position: absolute; inset: 0; z-index: 1000;
|
||
background: rgba(0,0,0,.45);
|
||
animation: sheet-fade .18s ease-out;
|
||
}
|
||
/* Formularblatt (siehe Kasten oben). Traegt drei Fenster: Beleg
|
||
hochladen, Daten importieren, Datensatz sichern/laden. */
|
||
.beleg-popup {
|
||
position: absolute; z-index: 1001;
|
||
left: 0; right: 0; bottom: 0;
|
||
top: auto; transform: none;
|
||
max-height: 88%;
|
||
overflow-y: auto;
|
||
/* --tile-2 ist im Nacht-Theme transluzent; ein Blatt ueber der Seite
|
||
braucht einen blickdichten Grund. */
|
||
background: var(--tile-deckend, var(--canvas));
|
||
border-radius: 16px 16px 0 0;
|
||
padding: var(--sp-4) 20px max(20px, env(safe-area-inset-bottom));
|
||
animation: blatt-hoch .28s cubic-bezier(.22,.61,.36,1);
|
||
}
|
||
.beleg-drop {
|
||
margin-top: var(--sp-3);
|
||
border: 1px dashed var(--line-strong);
|
||
border-radius: 14px;
|
||
padding: 28px var(--sp-4);
|
||
text-align: center;
|
||
display: flex; flex-direction: column; gap: 6px;
|
||
}
|
||
.beleg-drop strong { font-size: 15px; color: var(--fg); }
|
||
.beleg-drop span { font-size: 12.5px; color: var(--fg2); }
|
||
.beleg-drop.darueber { border-color: var(--fg); border-style: solid; background: var(--shade); }
|
||
|
||
/* Kopfzeile der Reifen-Kachel: Überschrift+km links, Radfoto rechts, beide
|
||
oben bündig - ersetzt die frühere Überlagerung (Montiert absolut über dem
|
||
Foto), seit Überschrift und km ihren eigenen Platz über Montiert bekommen
|
||
haben. */
|
||
.radkopf-row { display: flex; justify-content: space-between; align-items: flex-start; gap: var(--sp-4); }
|
||
.radkopf { display: flex; flex-direction: column; }
|
||
|
||
/* Editier-Symbol links neben der km-Anzeige (Audi-CI edit-s) - oeffnet das
|
||
Korrekturfeld fuer den manuell gepflegten Kilometerstand des Reifensatzes.
|
||
44x44pt Tippflaeche per unsichtbarem ::before wie bei .montiert/.zahnrad,
|
||
optisch bleibt nur das kleine Symbol sichtbar. */
|
||
.km-edit {
|
||
position: relative;
|
||
display: inline-flex; align-items: center; justify-content: center;
|
||
width: 22px; height: 22px;
|
||
border: none; background: none; color: var(--fg3);
|
||
padding: 0; cursor: pointer; flex: 0 0 auto;
|
||
}
|
||
.km-edit::before { content: ""; position: absolute; inset: -11px; }
|
||
.km-edit:hover { color: var(--fg); }
|
||
.km-edit:active { color: var(--fg); transform: scale(.92); }
|
||
|
||
/* Zeile aus einer bearbeitbaren Liste entfernen (z. B. Selbstbeteiligung im
|
||
Vertrag) - 44x44pt Tippflaeche per unsichtbarem ::before wie bei .km-edit,
|
||
optisch bleibt nur das kleine × sichtbar. */
|
||
.zeile-loeschen {
|
||
position: relative;
|
||
display: inline-flex; align-items: center; justify-content: center;
|
||
width: 22px; height: 22px;
|
||
border: none; background: none; color: var(--fg3);
|
||
font-size: 18px; line-height: 1;
|
||
padding: 0; cursor: pointer; flex: 0 0 auto;
|
||
}
|
||
.zeile-loeschen::before { content: ""; position: absolute; inset: -11px; }
|
||
.zeile-loeschen:hover { color: var(--bad); }
|
||
.zeile-loeschen:active { color: var(--bad); transform: scale(.92); }
|
||
|
||
/* Kompakte Pille statt voller Breite (Apple-HIG-Pull-down-Maß): normale
|
||
Flusslage unter der Kachel-Überschrift/km, nicht mehr über dem Foto
|
||
überlagert (das saß nur dort, solange Überschrift+km diesen Platz noch
|
||
nicht beanspruchten). */
|
||
.montiert {
|
||
position: relative;
|
||
display: inline-flex; align-items: center; justify-content: center;
|
||
font-family: inherit; font-size: 12.5px; letter-spacing: normal;
|
||
color: var(--fg2);
|
||
background: none;
|
||
border: 1px solid var(--line-strong);
|
||
border-radius: var(--r-pill);
|
||
padding: 7px 13px;
|
||
cursor: pointer;
|
||
transition: background .15s, color .15s, border-color .15s, transform .1s;
|
||
}
|
||
/* Optisch bleibt die Pille klein, die Tippflaeche wird per unsichtbarem
|
||
Pseudo-Element auf Apple-HIG-Mindestmass 44x44pt gebracht (Klick auf die
|
||
Flaeche des ::before zaehlt als Klick auf den echten Button). */
|
||
.montiert::before { content: ""; position: absolute; top: -8px; bottom: -8px; left: 0; right: 0; }
|
||
.montiert:hover { background: var(--shade); }
|
||
.montiert:active { transform: scale(.96); background: var(--shade); }
|
||
.montiert.on { background: var(--fg); border-color: var(--fg); color: var(--canvas); }
|
||
|
||
/* ------------------------------------------------- B4: Action Sheet
|
||
Ersetzt confirm()/alert(). Von unten eingeblendet, destruktive Zeile rot,
|
||
Abbrechen abgesetzt - iOS-Muster. */
|
||
.sheet-catcher {
|
||
position: absolute; inset: 0; z-index: 1200;
|
||
background: rgba(0,0,0,.45);
|
||
animation: sheet-fade .18s ease-out;
|
||
}
|
||
.sheet {
|
||
position: absolute; z-index: 1201;
|
||
left: 10px; right: 10px;
|
||
bottom: max(10px, env(safe-area-inset-bottom));
|
||
display: flex; flex-direction: column; gap: 8px;
|
||
animation: sheet-rein .24s cubic-bezier(.22,.61,.36,1);
|
||
}
|
||
@keyframes sheet-fade { from { opacity: 0 } to { opacity: 1 } }
|
||
@keyframes sheet-rein { from { transform: translateY(18px); opacity: 0 } to { transform: none; opacity: 1 } }
|
||
.sheet-gruppe {
|
||
/* --tile-2 is translucent in the iOS overlay's night theme (rgba white,
|
||
meant for tile-on-tile layering) - a confirm sheet sits directly over
|
||
whatever page content triggered it, so a see-through card made titles
|
||
like "Doppelt zugeordnet" hard to read against the busy background
|
||
bleeding through. Same fix already applied to .setup-popup/.standortmenu
|
||
for the same reason - opaque surface token, with the --canvas fallback
|
||
this file already uses elsewhere for when the (purely additive, in
|
||
principle removable) overlay isn't loaded. */
|
||
background: var(--tile-deckend, var(--canvas));
|
||
border-radius: 16px;
|
||
overflow: hidden;
|
||
display: flex; flex-direction: column;
|
||
}
|
||
.sheet-kopf {
|
||
padding: 15px 18px 14px;
|
||
border-bottom: 1px solid var(--line);
|
||
display: flex; flex-direction: column; gap: 4px;
|
||
}
|
||
.sheet-kopf strong { font-size: 15px; font-weight: 400; color: var(--fg); }
|
||
.sheet-kopf span { font-size: 13px; color: var(--fg2); line-height: 1.45; }
|
||
.sheet-gruppe button {
|
||
background: none; border: none;
|
||
font-family: inherit; font-size: 16px;
|
||
color: var(--fg);
|
||
padding: 16px 18px; min-height: 52px;
|
||
text-align: left; cursor: pointer;
|
||
border-bottom: 1px solid var(--line);
|
||
}
|
||
.sheet-gruppe button:last-child { border-bottom: none; }
|
||
.sheet-gruppe button:active { background: var(--shade); }
|
||
.sheet-gruppe button.loeschen { color: var(--bad); }
|
||
.sheet-abbrechen {
|
||
background: var(--tile-deckend, var(--canvas)); border: none; border-radius: 16px;
|
||
font-family: inherit; font-size: 16px; color: var(--fg);
|
||
padding: 16px; min-height: 52px; cursor: pointer;
|
||
}
|
||
.sheet-abbrechen:active { background: var(--shade); }
|
||
|
||
/* ------------------------------------------------------- Setup-Popup
|
||
Sensor-zu-Entität-Zuordnung (Einstellungen -> Fahrzeug einrichten ->
|
||
Setup). Gleiche Catcher/Karten-Bauweise wie .bildmenu/.sdpopup oben,
|
||
aber großformatig und scrollbar statt Bottom-Sheet-Größe; nutzt die
|
||
bereits vorhandenen sheet-fade/sheet-rein-Keyframes. z-index bewusst
|
||
unter .sheet (1200er), damit ein Fehlerhinweis (hinweis()) bei
|
||
fehlgeschlagenem Speichern über dem noch offenen Setup-Popup liegt. */
|
||
.setup-catcher {
|
||
position: absolute; inset: 0; z-index: 1000;
|
||
background: rgba(0,0,0,.45);
|
||
animation: sheet-fade .18s ease-out;
|
||
}
|
||
.setup-popup {
|
||
position: absolute; z-index: 1001;
|
||
left: 10px; right: 10px;
|
||
top: max(10px, env(safe-area-inset-top));
|
||
bottom: max(10px, env(safe-area-inset-bottom));
|
||
/* --tile-2 ist inzwischen transluzent (rgba(255,255,255,.1) im Nacht-
|
||
Theme) - fuer ein frei ueber dem Inhalt schwebendes Popup braucht es
|
||
einen blickdichten Hintergrund, gleiches Muster wie .standortmenu
|
||
oben. */
|
||
background: var(--tile-deckend, var(--canvas));
|
||
border-radius: var(--r-tile);
|
||
display: flex; flex-direction: column;
|
||
overflow: hidden;
|
||
animation: sheet-rein .24s cubic-bezier(.22,.61,.36,1);
|
||
}
|
||
.setup-kopf {
|
||
flex: 0 0 auto;
|
||
padding: 18px 20px 14px;
|
||
border-bottom: 1px solid var(--line);
|
||
display: flex; flex-direction: column; gap: 4px;
|
||
}
|
||
.setup-kopf strong { font-size: 17px; font-weight: 400; color: var(--fg); }
|
||
.setup-kopf span { font-size: 13px; color: var(--fg2); line-height: 1.45; }
|
||
.setup-kopf-schalter { display: flex; align-items: center; gap: 10px; margin-top: 10px; }
|
||
.setup-kopf-schalter span { font-size: 13px; color: var(--fg); }
|
||
.setup-koerper { flex: 1 1 0; min-height: 0; overflow-y: auto; padding: 4px 20px 20px; }
|
||
.setup-gruppe { margin-top: 18px; }
|
||
.setup-gruppe:first-child { margin-top: 6px; }
|
||
.setup-gruppe-titel { font-size: 11px; letter-spacing: .1em; text-transform: uppercase; color: var(--fg3); margin-bottom: 6px; }
|
||
.setup-feldzeile { padding: 12px 0; border-bottom: 1px solid var(--line); }
|
||
.setup-feldzeile:last-child { border-bottom: none; }
|
||
/* Nutzerwunsch: die Kennung des zugeordneten Sensors (entitaetIdKurz() in
|
||
audi-dashboard-app.js) steht NEBEN der Feld-Überschrift, nicht mehr wie
|
||
die frühere statische Beschreibung darunter - deshalb Zeile statt Spalte.
|
||
Die erwartete Einheit (feldEinheitAnzeige()) hängt direkt am Label selbst
|
||
("Tankfüllstand [%]"), losgelöst davon, ob/welcher Sensor zugeordnet ist.
|
||
2026-08-28, Nutzerkorrektur: EINE Zeile "(z. B. sensor_id)" statt zwei -
|
||
der Klammertext "(z. B. "/")" in derselben Größe/Farbe wie das Label links
|
||
(.setup-feld-label), die Sensor-ID selbst darin in derselben kleinen/
|
||
grauen Schrift wie die Einheit daneben (.setup-feld-einheit,
|
||
"[on/off]"/"[km]") - deshalb teilt sich .setup-feld-hinweis die Klasse
|
||
.setup-feld-einheit für den inneren Span statt einer eigenen Regel. */
|
||
.setup-feld-kopf { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; margin-bottom: 8px; }
|
||
.setup-feld-label { font-size: 14px; color: var(--fg); flex: 0 1 auto; }
|
||
.setup-feld-einheit { color: var(--fg3); font-size: 12.5px; }
|
||
.setup-feld-hinweis {
|
||
font-size: 14px; color: var(--fg); line-height: 1.4; text-align: right;
|
||
max-width: 55%;
|
||
}
|
||
.setup-unterfelder { display: flex; flex-direction: column; gap: 12px; }
|
||
.setup-unterfeld { display: flex; flex-direction: column; gap: 4px; }
|
||
/* Positionsname links, Erwartungswert rechts - derselbe Bau wie
|
||
.setup-feld-kopf eine Ebene darueber, damit beide Zeilen dieselbe Kante
|
||
haben. Der Hinweis erbt hier die kleine graue Schrift des Labels; die
|
||
14px/--fg-Form von .setup-feld-hinweis passt nur in die Kopfzeile. */
|
||
.setup-unterfeld-label {
|
||
font-size: 12.5px; color: var(--fg3);
|
||
display: flex; align-items: baseline; justify-content: space-between; gap: 10px;
|
||
}
|
||
.setup-unterfeld-label .setup-feld-hinweis {
|
||
font-size: inherit; color: inherit; max-width: none; flex: 0 0 auto;
|
||
}
|
||
|
||
.entitaet-combo { position: relative; }
|
||
.entitaet-combo-icon {
|
||
position: absolute; left: 12px; top: 50%; transform: translateY(-50%);
|
||
color: var(--fg3); display: flex; pointer-events: none;
|
||
}
|
||
.entitaet-combo-input {
|
||
width: 100%; box-sizing: border-box;
|
||
background: var(--tile-deckend, var(--canvas)); border: 1px solid var(--line); color: var(--fg);
|
||
font-family: inherit; font-size: 16px; /* siehe .feld input weiter oben: >=16px gegen Safari-Autozoom */
|
||
padding: 11px 34px 11px 36px;
|
||
border-radius: 12px;
|
||
text-align: left;
|
||
-webkit-appearance: none; appearance: none;
|
||
}
|
||
.entitaet-combo-input:focus { outline: none; border-color: var(--red); }
|
||
/* Die Zuordnung passt zum Beispielnamen der Rolle (siehe
|
||
entitaetPasstZumBeispiel). Bewusst zurueckhaltend: eine Bestaetigung im
|
||
Vorbeigehen, kein Ausrufezeichen. Deshalb die Farbe ueber color-mix aus dem
|
||
vorhandenen Erfolgs-Ton und dem Feldgrund statt eines eigenen Gruens - so
|
||
bleibt sie in beiden Themen ruhig und passt zum Rest der Oberflaeche.
|
||
Der Rahmen traegt etwas mehr Farbe als die Flaeche, sonst verschwindet die
|
||
Markierung auf dunklem Grund. */
|
||
.entitaet-combo-input.passend {
|
||
background: color-mix(in srgb, var(--ok, #2e7d32) 9%, var(--tile-deckend, var(--canvas)));
|
||
border-color: color-mix(in srgb, var(--ok, #2e7d32) 38%, var(--line));
|
||
}
|
||
.entitaet-combo-input.passend:focus { border-color: var(--red); }
|
||
.entitaet-liste {
|
||
position: absolute; z-index: 5; left: 0; right: 0; top: calc(100% + 4px);
|
||
max-height: 240px; overflow-y: auto;
|
||
background: var(--tile-deckend, var(--canvas)); border: 1px solid var(--line-strong);
|
||
border-radius: 12px;
|
||
box-shadow: 0 12px 28px rgba(0,0,0,.35);
|
||
}
|
||
.entitaet-eintrag {
|
||
display: flex; flex-direction: column; gap: 1px;
|
||
width: 100%; text-align: left;
|
||
background: none; border: none; border-bottom: 1px solid var(--line);
|
||
color: var(--fg); font-family: inherit;
|
||
padding: 9px 12px; cursor: pointer;
|
||
}
|
||
.entitaet-eintrag:last-child { border-bottom: none; }
|
||
.entitaet-eintrag:active, .entitaet-eintrag.aktiv { background: var(--shade); }
|
||
.entitaet-eintrag-name { font-size: 14px; color: var(--fg); }
|
||
.entitaet-eintrag-id { font-size: 12.5px; color: var(--fg3); font-family: ui-monospace, SFMono-Regular, Menlo, monospace; }
|
||
.entitaet-eintrag-wert { font-size: 12.5px; color: var(--fg2); margin-top: 1px; }
|
||
.entitaet-eintrag-wert.unbekannt { color: var(--warn); }
|
||
.entitaet-leer { padding: 14px 12px; font-size: 13px; color: var(--fg2); }
|
||
.setup-feld-warnung { font-size: 12.5px; color: var(--warn); line-height: 1.4; margin-top: 6px; }
|
||
|
||
.setup-fuss {
|
||
flex: 0 0 auto;
|
||
display: flex; gap: 10px;
|
||
padding: 14px 20px max(14px, env(safe-area-inset-bottom));
|
||
border-top: 1px solid var(--line);
|
||
}
|
||
.setup-fuss .aktion { flex: 1; margin-top: 0; }
|
||
|
||
/* ------------------------------------------------- B3: Push/Pop
|
||
Seitenwechsel wie auf iOS: neue Ebene kommt von rechts, zurück geht sie
|
||
dorthin. */
|
||
.push-rein { animation: push-rein .26s cubic-bezier(.32,.72,0,1); }
|
||
.push-raus { animation: push-raus .26s cubic-bezier(.32,.72,0,1); }
|
||
@keyframes push-rein { from { transform: translateX(26px); opacity: 0 } to { transform: none; opacity: 1 } }
|
||
@keyframes push-raus { from { transform: translateX(-18px); opacity: 0 } to { transform: none; opacity: 1 } }
|
||
|
||
/* D5: Leerzustand nennt die Ursache und die nächste Handlung. */
|
||
.leer { display: flex; flex-direction: column; gap: 8px; padding: 4px 0 2px; }
|
||
.leer strong { font-size: 16px; font-weight: 400; color: var(--fg); }
|
||
.leer p { margin: 0; font-size: 13px; line-height: 1.55; color: var(--fg2); text-wrap: pretty; }
|
||
|
||
/* B7 */
|
||
@media (prefers-reduced-motion: reduce) {
|
||
*, *::before, *::after {
|
||
animation-duration: .01ms !important;
|
||
animation-iteration-count: 1 !important;
|
||
transition-duration: .01ms !important;
|
||
scroll-behavior: auto !important;
|
||
}
|
||
}
|
||
|
||
/* Ein Paar aus Bestaetigen und Abbrechen steht nebeneinander, beide gleich
|
||
breit: es ist eine Entscheidung zwischen zwei Wegen, keine Haupt- und
|
||
Nebensache. Welcher der gewollte ist, sagt die Fuellung, nicht die Groesse -
|
||
und der bestaetigende steht rechts, wie ueberall in iOS. */
|
||
.knopfpaar {
|
||
display: flex;
|
||
gap: 10px;
|
||
margin-top: var(--sp-4);
|
||
}
|
||
.knopfpaar .aktion {
|
||
flex: 1 1 0;
|
||
margin-top: 0;
|
||
}
|