/* 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 , 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; } /* Luft unter der Kachelueberschrift. Der Abstand zur ersten Inhaltszeile haengt heute davon ab, ob das folgende Element zufaellig einen eigenen oberen Rand mitbringt - am 05.09.2026 gemessen: 0px, 10px oder 12px, quer durch die Kacheln. Wo er 0 war, klebte die Ueberschrift an der ersten Zeile und las sich als deren Beischrift statt als Titel (gemeldet: "Anstehende Termine" wirkte, als gehoere es zu Oelwechsel). Der Rand steht bewusst an der UEBERSCHRIFT, nicht am folgenden Element: .tile ist ein normaler Blockcontainer, benachbarte Raender fallen also zusammen. Vorhandene 10 oder 12px werden dadurch auf 14 angehoben statt addiert, und absolut gesetzte Nachbarn - Zahnrad, Chevron - bleiben unberuehrt, weil sie gar nicht im Fluss stehen. Nur die ERSTE Beschriftung einer Kachel: .label traegt auch Inhaltszeilen wie die Anschrift des Autohauses, und die sollen bleiben, wie sie sind (Entscheidung des Eigentuemers, 05.09.2026). */ .tile > .label:first-child { margin-bottom: 14px; } /* 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 · "; 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
, 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 */ /* Die Reichweite ueber dem Tankbalken ist die einzige Zahl im Panel, die nicht im Light-Schnitt steht. Der Eigentuemer verglich sie am 05.09.2026 mit der myAudi-App ("die Ziffern der Reichweite sind in der Audi App dicker") und entschied am 06.09.2026, es bei genau dieser einen Zahl zu belassen: alle uebrigen grossen Zahlen sind wieder Light (300), weil der fette Schnitt dort als Fremdkoerper wirkte. Deshalb eine Ausnahme am Tankbalken statt einer Regel an .fig. Wortgleich mit .dm-tankzeile .ads-fig in der App. */ .tankzeile .fig { font-weight: 700; } .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