Vollständiger Panel-companion-app-Paritätsaudit (11 Kapitel)

Systematischer Bildvergleich der companion-app gegen das HA-Panel (companion-app/AGENTS.md
Kapitel 1-11): Farbtoken/Radien aus dem falschen Stylesheet gelesen (iOS-Overlay statt Basis-CSS,
betraf fast jede Kachel/Farbe/Radius app-weit), vier app-weite @audi-dash/ui-Bugs (Switch/Seg/Feld
rot statt neutral bzw. falsche Feldbreite), Reifen-Seite strukturell neu gebaut (beide Radsätze
gleichzeitig statt Umschalter, editierbare Felder, Anzugsmoment-/km-Korrektur), Standort-Feature
komplett neu (fehlte bisher ganz), sowie diverse Struktur-/Typografie-/Datenlücken in
MeinAudi/Service/Versicherung/Sicherheit/Fahrten/Tanken/Statistik/Batterie/Einstellungen.

Manifest auf 2026.8.30.2 angehoben, OTA-Bündel neu gebaut und in audi_ha_test verifiziert
(sauberer Neustart, keine Tracebacks).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-30 12:21:58 +02:00
parent 4fa5d4bc2d
commit e1ebe6d694
43 changed files with 3256 additions and 451 deletions
+523 -73
View File
@@ -234,11 +234,23 @@ input[type="date"].dm-eingabe {
/* ------------------------------------------------------------ Übersicht */
/* Deckungsgleich mit .szene.bleed im Panel: randlos, keine Kartenfläche -
Fahrzeugbild und Name/Kennzeichen sitzen direkt auf dem Seitenhintergrund,
nicht in einer grauen Karte. War hier bis 2026-08-30 fälschlich als
Kachel mit Hintergrund gebaut (Parität-Audit). */
.dm-szene {
position: relative;
border-radius: var(--r-tile);
overflow: hidden;
background: var(--tile);
}
/* Panel: .carbox ~120px, .szene ~130px hoch - ein schmales, breites Band,
nicht das 4:3-Seitenverhältnis, das ImagePlaceholder sonst für Galerien
verwendet (dort korrekt, hier war es das nie - "carfix klein" im Panel ist
16:8). Scoped auf die Übersicht-Szene, damit andere ImagePlaceholder-
Stellen (Mein Audi, Reifen, ...) ihre eigene, richtige Größe behalten. */
.dm-szene .ads-bildbox {
aspect-ratio: 16 / 8;
}
.dm-szene .ads-bild,
@@ -247,8 +259,14 @@ input[type="date"].dm-eingabe {
display: block;
}
/* Kein linkes/rechtes Innenpolster: das Panel stellt Kennzeichen/Marke in
eine randlose "tile flat" (padding:0) - links/rechts eingerückt zu haben
ließ diesen Text nicht mit "Reichweite" & Co. auf einer Kante stehen
(Nutzerbericht "nicht linksbündig zum Rest der Seite", live gemessen:
38px hier gegen 22px bei "Reichweite" - im Panel beide bei 16px). Nur
oben/unten bleibt Abstand (zum Bild bzw. zur nächsten Kachel). */
.dm-szene__text {
padding: var(--sp-4) var(--sp-4) var(--sp-5);
padding: var(--sp-4) 0 var(--sp-5);
}
/* Übersicht: "Nächster Service" als tippbare Kennzahl innerhalb der Kachel,
@@ -267,9 +285,15 @@ input[type="date"].dm-eingabe {
font: inherit;
text-align: left;
color: inherit;
}
/* Nur wenn es wirklich ein Knopf ist (ein Termin vorhanden, siehe
Uebersicht.tsx) - der "kein Eintrag"-Zustand ist ein reines <div>, ohne
Zeigehand/Press-Feedback, deckungsgleich mit der nicht-klickbaren
.tile-Variante im Panel. */
button.dm-serviceblock {
cursor: pointer;
}
.dm-serviceblock:active {
button.dm-serviceblock:active {
opacity: 0.55;
}
.dm-serviceblock__chevron {
@@ -282,10 +306,19 @@ input[type="date"].dm-eingabe {
}
/* Serviceart-Icon links der Kennzahl statt des Wortes "bis zum/zur ..." -
deckungsgleich mit .fig-zeile im Panel (audi-dashboard.css). */
/* margin-top deckungsgleich mit .fig-zeile im Panel - fehlte hier, "Nächster
Service:" und die Kennzahl standen ohne Abstand aufeinander (Parität-
Audit 2026-08-30). Der zweite Selektor deckt den Fall ohne Serviceart-
Icon ab (Hauptuntersuchung), wo das Panel dasselbe margin-top direkt auf
.fig setzt statt auf eine Wrapper-Zeile. */
.dm-servicefig {
display: flex;
align-items: center;
gap: 8px;
margin-top: 8px;
}
.dm-serviceblock > .ads-fig {
margin-top: 8px;
}
.dm-servicefig svg {
color: var(--fg2);
@@ -339,6 +372,9 @@ input[type="date"].dm-eingabe {
margin-top: 8px;
}
.dm-tgwert {
/* Fehlte hier ganz - fiel auf die schmale Grundschrift zurück statt auf
Audi Type Wide wie .tg-wert im Panel (Parität-Audit 2026-08-29). */
font-family: var(--font-wide);
font-weight: 300;
font-size: 22px;
color: var(--fg);
@@ -357,14 +393,19 @@ input[type="date"].dm-eingabe {
margin-top: 6px;
}
.dm-tanktext {
/* Reichweiten-Kachel auf der Übersicht - deckungsgleich mit .tankzeile/.pct
im Panel (audi-dashboard.css). */
.dm-tankzeile {
display: flex;
align-items: flex-end;
justify-content: space-between;
gap: var(--sp-3);
margin-top: var(--sp-2);
font-size: 12.5px;
font-weight: 300;
gap: 14px;
margin-bottom: 14px;
}
.dm-tankzeile__pct {
font-size: 15px;
color: var(--fg2);
padding-bottom: 6px;
}
.dm-navikachel__wert {
@@ -374,16 +415,27 @@ input[type="date"].dm-eingabe {
color: var(--fg);
}
/* "Letzte Fahrt"/"Letzte Tankung" auf der Übersicht - deckungsgleich mit
.leaf .v/.leaf .v small im Panel (15px/400/var(--fg2), Zusatzzeile
12.5px/var(--fg3), KEINE Wide-Schrift/Hero-Zahl). War hier 20px/300 ohne
Farbangabe - eine erfundene "große Zahl"-Behandlung, die dieser Kachel im
Panel nie zustand (Parität-Audit 2026-08-30). Nur hier verwendet (die
anderen NaviKachel-Aufrufe in MeinAudi.tsx/Service.tsx/Versicherung.tsx
nutzen .dm-navikachel__wert direkt, unangetastet). */
.dm-navikachel__zahl {
font-size: 20px;
font-weight: 300;
font-size: 15px;
font-weight: 400;
color: var(--fg2);
}
.dm-navikachel__wert .dm-navikachel__zahl + small {
font-size: 12.5px;
}
.dm-navikachel__wert small,
.dm-wertzeile small {
display: block;
margin-top: 2px;
font-size: 11.5px;
font-size: 12.5px;
color: var(--fg3);
}
@@ -420,12 +472,17 @@ input[type="date"].dm-eingabe {
margin: var(--sp-3) 0 0;
}
/* Live am Panel gemessen (.row/dt/dd, audi-dashboard.css): beide Spalten
16px/400, dt (Feldname) in var(--fg) - NICHT grau, das ist der Wert (dd,
var(--fg2)) - genau umgekehrt zu dem, was hier vorher stand (13px/grau
Label, 14px/hell Wert). Betrifft jede Wertzeile app-weit (Parität-Audit
2026-08-30). */
.dm-wertzeile {
display: flex;
align-items: baseline;
justify-content: space-between;
gap: var(--sp-4);
padding: 10px 0;
padding: 11px 0;
border-bottom: 1px solid var(--line);
}
@@ -434,15 +491,16 @@ input[type="date"].dm-eingabe {
}
.dm-wertzeile dt {
font-size: 13px;
font-weight: 300;
color: var(--fg2);
font-size: 16px;
font-weight: 400;
color: var(--fg);
}
.dm-wertzeile dd {
margin: 0;
font-size: 14px;
font-weight: 300;
font-size: 16px;
font-weight: 400;
color: var(--fg2);
text-align: right;
}
@@ -454,6 +512,60 @@ input[type="date"].dm-eingabe {
padding: var(--sp-3) 2px 0;
}
/* Wechselbild "Mein Audi" - deckungsgleich mit carImg("galerie")/.dots im
Panel: ein antippbares Bild, das zum nächsten Galerieplatz weiterschaltet,
plus Punktanzeige darunter. */
.dm-galerie-wechsel {
display: block;
width: 100%;
border: 0;
background: none;
padding: 0;
cursor: pointer;
}
/* 16:9, wie carImg("galerie") im Panel ("carfix", nicht "carfix klein" -
das 16:8-Maß gilt nur für die Übersicht-Szene). */
.dm-galerie-wechsel .ads-bildbox {
aspect-ratio: 16 / 9;
}
.dm-galerie-punkte {
display: flex;
gap: 6px;
justify-content: center;
margin-top: 12px;
}
.dm-galerie-punkte span {
width: 5px;
height: 5px;
border-radius: 50%;
background: var(--line-strong);
}
.dm-galerie-punkte span.an {
background: var(--red);
}
/* Klickbare Wertzeile (Batteriespannung → Verlauf) - deckungsgleich mit
`.row[data-go]` im Panel: derselbe Zeilenaufbau wie .dm-wertzeile, nur als
<button> statt <div>, mit Chevron in der Wertespalte. */
.dm-wertzeile--knopf {
width: 100%;
border: 0;
background: none;
font: inherit;
text-align: inherit;
color: inherit;
cursor: pointer;
}
.dm-wertzeile--knopf dd {
display: flex;
align-items: center;
gap: 6px;
}
.dm-wertzeile__chevron {
color: var(--fg3);
font-size: 13px;
}
.dm-fussnote {
margin: var(--sp-3) 0 0;
font-size: 11.5px;
@@ -465,60 +577,12 @@ input[type="date"].dm-eingabe {
/* ------------------------------------------------------ Fahrzeugstatus */
.dm-pruefliste {
list-style: none;
margin: var(--sp-3) 0 0;
padding: 0;
}
.dm-pruefliste__zeile {
display: flex;
align-items: center;
gap: var(--sp-3);
padding: 10px 0;
border-bottom: 1px solid var(--line);
}
.dm-pruefliste__zeile:last-child {
border-bottom: 0;
}
.dm-pruefliste__label {
flex: 1;
font-size: 14px;
font-weight: 300;
}
.dm-pruefliste__wert {
font-size: 12.5px;
font-weight: 300;
color: var(--fg2);
}
.dm-punkt {
flex: none;
width: 9px;
height: 9px;
border-radius: 50%;
}
.dm-punkt--ok {
background: var(--ok);
}
.dm-punkt--offen {
background: var(--bad);
}
/* Unbekannt bewusst als hohler Ring: sichtbar anders als grün und als rot,
damit "keine Meldung" nie wie eine Aussage aussieht. */
.dm-punkt--unbekannt {
border: 1.5px solid var(--fg3);
}
/* Kreis-Häkchen für die vier Sammelzeilen der Sicherheit-Seite - Zustand ist
so schon am Symbol erkennbar, nicht nur an der Farbe (siehe .dm-punkt
oben, das bleibt für die Detailliste unverändert). */
so schon am Symbol erkennbar, nicht nur an der Farbe. Die Detailliste
"Türen und Klappen" (TuerenKlappen.tsx) verwendet stattdessen die
gewöhnliche .dm-wertzeile-Zeile mit dem einfachen @audi-dash/ui .ads-dot -
deckungsgleich mit dem Panel, dessen vTuerenKlappen() ebenfalls den
schlichten Punkt statt des Kreis-Häkchens zeigt. */
.dm-statuskreis {
flex: none;
width: 22px;
@@ -558,6 +622,21 @@ button.dm-sicherheitszeile:active { background: var(--tile-2); }
.dm-sicherheitszeile__text { flex: 1; font-size: 14.5px; }
.dm-sicherheitszeile__chev { margin-left: auto; flex: none; color: var(--fg3); }
/* Sammelzeile über den vier Sicherheitszeilen - deckungsgleich mit dem
obersten Kasten in vSicherheit() (style="display:flex;align-items:center;
gap:12px;padding:16px 20px"), dasselbe Kreis-Häkchen-Symbol wie die Zeilen
darunter, keine Zeitangabe. */
.ads-tile.dm-sicherheitssammel {
display: flex;
align-items: center;
gap: 12px;
padding: 16px 20px;
}
.dm-sicherheitssammel span {
font-size: 15px;
color: var(--fg);
}
/* ------------------------------------------------------------ Galerie */
.dm-galerie {
@@ -666,6 +745,14 @@ button.dm-listenzeile {
letter-spacing: -0.02em;
}
/* Einzelfahrt/Einzelbeleg: das Panel zeichnet die Distanz- bzw. Liter-Zahl in
vTrip()/dem Tankvorgang-Detail eigens bei 52px (style="font-size:52px"),
größer als die übrigen Detailseiten mit ihrer gemeinsamen 40px-.fig - kein
Versehen, sondern die Hauptzahl der jeweiligen Seite. */
.dm-detail__zahl--gross {
font-size: 52px;
}
.dm-detail__einheit {
font-size: 15px;
color: var(--fg2);
@@ -795,6 +882,103 @@ button.dm-listenzeile {
margin-top: var(--sp-4);
}
/* Ausklappbares Korrekturfeld (Anzugsmoment/Reifenkilometer) - deckungsgleich
mit dem entsprechenden Block im Panel (margin-top:14-18px, Trennlinie
darüber). */
.dm-bearbeiten-block {
margin-top: var(--sp-4);
padding-top: var(--sp-4);
border-top: 1px solid var(--line);
}
/* Reifen-Kachel: Kopfzeile aus Überschrift+km links, Radfoto rechts, beide
oben bündig - deckungsgleich mit .radkopf-row/.radkopf/.tile-headline im
Panel. */
.dm-radkopf-row {
display: flex;
justify-content: space-between;
align-items: flex-start;
gap: var(--sp-4);
}
.dm-radkopf {
display: flex;
flex-direction: column;
}
.dm-tile-headline {
font-size: 20px;
letter-spacing: -0.01em;
line-height: 1.2;
color: var(--fg);
display: block;
}
.dm-reifenzeile {
display: flex;
align-items: center;
gap: 8px;
margin-top: 14px;
}
.dm-reifenzeile .ads-icon-button {
width: 24px;
height: 24px;
color: var(--fg3);
}
.dm-reifenzeile .ads-icon-button svg {
width: 16px;
height: 16px;
}
.dm-radfoto .ads-bildbox {
width: 96px;
height: 96px;
aspect-ratio: 1 / 1;
}
/* Kompakte Pille (Montiert) statt voller Breite - deckungsgleich mit
.montiert/.montiert.on im Panel. */
.dm-montiert-reihe {
display: flex;
justify-content: space-between;
align-items: center;
margin-top: var(--sp-4);
}
.dm-montiert {
position: relative;
display: inline-flex;
align-items: center;
justify-content: center;
font-size: 12px;
letter-spacing: normal;
color: var(--fg2);
background: none;
border: 1px solid var(--line-strong);
border-radius: var(--r-pill);
padding: 7px 13px;
cursor: pointer;
}
.dm-montiert::before {
content: "";
position: absolute;
top: -8px;
bottom: -8px;
left: 0;
right: 0;
}
.dm-montiert:active {
transform: scale(0.96);
}
.dm-montiert--an {
background: var(--fg);
border-color: var(--fg);
color: var(--canvas);
}
.dm-archivbtn {
background: var(--tile-2);
color: var(--fg2);
}
.dm-archivbtn:hover,
.dm-archivbtn:active {
color: var(--fg);
}
.dm-waehlen {
display: flex;
flex-wrap: wrap;
@@ -836,14 +1020,18 @@ button.dm-listenzeile {
}
/* Der Zusatz neben dem Typenschild darf umbrechen — abgeschnittener Text mit
Auslassungspunkten sieht nach Fehler aus, ein Umbruch nicht. */
Auslassungspunkten sieht nach Fehler aus, ein Umbruch nicht. Größe/Farbe
deckungsgleich mit ".badge .zusatz" im Panel (13px, var(--fg2), nicht
kursiv) - war hier 19px, geerbt von der (falschen) "ads-title"-Klasse am
Umschließer (Parität-Audit 2026-08-30). */
.dm-szene__zusatz {
min-width: 0;
white-space: normal;
overflow: visible;
text-overflow: clip;
font-size: 19px;
line-height: 1.2;
font-size: 13px;
line-height: normal;
color: var(--fg2);
}
/* Die Galerie richtet sich nach der festen Kachelbreite der Bibliothek (78px),
@@ -854,3 +1042,265 @@ button.dm-listenzeile {
justify-content: space-between;
gap: var(--sp-3);
}
/* ---------------------------------------------------------------- Standort
Live-GPS-Position des Fahrzeugs — deckungsgleich mit .standort-kachel/
.standort-vollbild/.standortmenu im Panel (audi-dashboard.css). War bis
2026-08-29 komplett unportiert (Parität-Audit). */
.dm-standort-kachelbtn {
display: block;
width: 100%;
position: relative;
border: none;
padding: 0;
margin: 0 0 var(--sp-3);
background: none;
cursor: pointer;
border-radius: var(--r-tile);
overflow: hidden;
}
.dm-standort-vorschau {
width: 100%;
height: 190px;
background: var(--tile);
}
.dm-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);
}
.dm-fahrzeug-pin-wrap,
.dm-user-pin-wrap {
background: none;
border: none;
}
.dm-fahrzeug-pin {
display: flex;
align-items: center;
justify-content: center;
color: #fff;
filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.4));
}
.dm-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, 0.3);
}
.dm-user-pin::after {
content: "";
position: absolute;
inset: -14px;
border-radius: 50%;
background: rgba(10, 132, 255, 0.18);
animation: dm-user-pulse 2.4s ease-out infinite;
}
@keyframes dm-user-pulse {
0% {
transform: scale(0.4);
opacity: 0.9;
}
100% {
transform: scale(1);
opacity: 0;
}
}
/* Füllt die verfügbare Höhe der Seite, statt bei 640px zu kappen und darunter
leeren, mit dem geschlossenen Blatt verwechselbaren Seitenhintergrund
stehen zu lassen (Nutzerbericht "Standort Slide Up ist leer" - der Inhalt
fehlte nicht, er saß nur unterhalb der Kappungsgrenze in leerem Weiß).
`.dm-inhalt > *{flex:none}` (rahmen.css) gilt für jede andere Seite zu
Recht - hier gezielt aufgehoben, die einzige Seite ohne weiteren Inhalt
unter einer einzelnen großen Fläche. */
.dm-inhalt > .dm-standort-vollbild {
flex: 1 1 auto;
}
.dm-standort-vollbild {
position: relative;
min-height: 400px;
border-radius: var(--r-tile);
overflow: hidden;
margin: 0 calc(-1 * var(--sp-5));
}
.dm-standort-karte {
width: 100%;
height: 100%;
}
.dm-kartensteuerung {
position: absolute;
z-index: 400;
top: 16px;
right: 16px;
display: flex;
flex-direction: column;
gap: 12px;
}
.dm-kartensteuerung button {
width: 48px;
height: 48px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
background: rgba(16, 20, 26, 0.84);
color: #fff;
border: none;
box-shadow: 0 4px 14px rgba(0, 0, 0, 0.32);
-webkit-backdrop-filter: blur(10px);
backdrop-filter: blur(10px);
cursor: pointer;
padding: 0;
}
[data-theme="tag"] .dm-kartensteuerung button {
background: rgba(255, 255, 255, 0.92);
color: #101418;
box-shadow: 0 4px 14px rgba(0, 0, 0, 0.18);
}
.dm-kartensteuerung button:active {
transform: scale(0.94);
}
.dm-standortmenu {
position: absolute;
z-index: 410;
left: 0;
right: 0;
bottom: 0;
--dm-standort-peek: 96px;
background: var(--canvas);
border-radius: var(--r-tile) var(--r-tile) 0 0;
box-shadow: 0 -6px 24px rgba(0, 0, 0, 0.35);
padding: 0 20px max(18px, env(safe-area-inset-bottom));
transform: translateY(calc(100% - var(--dm-standort-peek)));
transition: transform 0.28s cubic-bezier(0.22, 0.61, 0.36, 1);
}
.dm-standortmenu--offen {
transform: translateY(0);
}
.dm-standortmenu__griffzone {
padding: 10px 0 14px;
position: relative;
}
.dm-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;
}
.dm-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(--tile);
border: none;
color: var(--fg2);
cursor: pointer;
padding: 0;
}
.dm-standortmenu__kopf {
margin-top: 8px;
padding-right: 44px;
}
.dm-standortmenu__name {
font-size: 17px;
color: var(--fg);
}
.dm-standortmenu__distanz {
font-size: 12.5px;
color: var(--fg3);
margin-top: 4px;
}
.dm-standortmenu__adresse {
font-size: 13.5px;
color: var(--fg2);
margin-top: 20px;
}
.dm-standortmenu__status {
display: flex;
align-items: center;
gap: 9px;
margin-top: 8px;
font-size: 13.5px;
color: var(--fg2);
}
.dm-standortmenu__status svg {
color: var(--fg3);
flex: none;
}
.dm-standortmenu__punkt {
width: 8px;
height: 8px;
border-radius: 50%;
background: var(--ok);
flex: none;
}
.dm-standortmenu__werte {
display: flex;
align-items: center;
gap: 10px;
margin-top: 8px;
font-size: 13.5px;
color: var(--fg2);
}
.dm-standortmenu__werte svg {
color: var(--fg3);
flex: none;
}
.dm-standortmenu__aktionen {
display: flex;
gap: 10px;
margin-top: 18px;
padding-bottom: 4px;
}
.dm-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-size: 14px;
text-decoration: none;
cursor: pointer;
}
.dm-standort-pille--primaer {
background: var(--fg);
border-color: var(--fg);
color: var(--canvas);
}
.dm-standort-pille:active {
transform: scale(0.97);
}
.dm-standort-pille:disabled {
opacity: 0.4;
pointer-events: none;
}