@@ -340,6 +340,11 @@ const BILDER = [
{ name : "Cockpit" , label : "Innenraum Cockpit" , datei : "cockpit.webp" } ,
{ name : "Scheinwerfer" , label : "Scheinwerfer" , datei : "scheinwerfer.webp" } ,
{ name : "Sitze" , label : "Innenraum Sitze" , datei : "sitze.webp" } ,
// Steht auf der Seite "Fahrzeug" über den Sicherheitszeilen. Bis zum
// 02.09.2026 war sie der einzige sichtbare Bildplatz, der in den
// Einstellungen NICHT auswählbar war - hochladen ließ sie sich damit gar
// nicht (gemeldet vom Eigentümer). bilder.py kannte den Dateinamen längst.
{ name : "Draufsicht" , label : "Auto von oben" , datei : "draufsicht.webp" } ,
] ;
let bild = 0 ;
const SEITE _WINTER = { label : "Auto Seite mit Winterrädern" , datei : "seitenansicht-winter.webp" } ;
@@ -1274,6 +1279,16 @@ function standortKachel() {
/ * S y m b o l e a u s d e m A u d i - C I - S a t z ( a s s e t s / i c o n s / ) - h i e r e i n g e b e t t e t , w e i l d i e
Panel - Datei ohne zusaetzliche Abrufe auskommen soll . * /
const CI = {
/ * f u e l - s t a t i o n - s a u s d e m A u d i - C I - S a t z ( 2 4 e r - R a s t e r ) - d i e Z a p f s a e u l e d e s
Tanken - Reiters . Ersetzt seit dem 02.09 . 2026 eine handgezeichnete Saeule .
Die 48 er - Variante hiesse fuel - station - l und wird nicht gebraucht : die
Reiter zeichnen mit 21 bzw . 26 px , also im 24 er - Raster . * /
fuelStationS : '<path fill="currentColor" d="M4 3.5A2.5 2.5 0 0 1 6.5 1h6A2.5 2.5 0 0 1 15 3.5V10h.5a2.5 2.5 0 0 1 2.5 2.5v5a1.5 1.5 0 0 0 3 0V8.07a16.4 16.4 0 0 0-2.89-5.76l.78-.62a17.4 17.4 0 0 1 3.1 6.17l.01.07v9.57a2.5 2.5 0 0 1-5 0v-5c0-.83-.67-1.5-1.5-1.5H15v11h1v1H3v-1h1zM5 22h9V3.5c0-.83-.67-1.5-1.5-1.5h-6C5.67 2 5 2.67 5 3.5zm1-12h7v1H6z"/>' ,
/ * s e t t i n g s - s a u s d e m A u d i - C I - S a t z ( 2 4 e r - R a s t e r ) - d a s Z a h n r a d i n d e r
rechten oberen Ecke einer Kachel . Stand bis zum 02.09 . 2026 sechsmal
wortgleich im Markup ; die 48 er - Variante hiesse settings - l und wird hier
nirgends gebraucht , das Zahnrad wird immer 17 px dargestellt . * /
settingsS : '<path fill="currentColor" d="M9.4 2h4.2v2.84c.37.13.75.27 1.11.44L16.7 3.3l3 3.01-1.98 1.99c.17.36.31.74.44 1.11H21v4.3h-2.84c-.13.37-.27.75-.44 1.11l2 2-3.03 2.89-1.98-1.98c-.36.17-.74.31-1.11.44V21H9.4v-2.84a9 9 0 0 1-1.11-.44L6.3 19.7l-3-3.01 1.98-1.99a9 9 0 0 1-.44-1.11H2V9.4h2.84c.13-.37.27-.75.44-1.11L3.3 6.3l3.01-3L8.3 5.28c.36-.17.74-.31 1.11-.44V2Zm1 1v2.56l-.34.11c-.61.2-1.16.4-1.6.66l-.34.2L6.3 4.71 4.7 6.3l1.83 1.82-.2.34c-.27.44-.45.99-.66 1.6l-.11.34H3v2.2h2.56l.11.34c.2.61.4 1.16.66 1.6l.2.34-1.82 1.82 1.59 1.6 1.82-1.83.34.2c.44.27.99.45 1.6.66l.34.11V20h2.2v-2.56l.34-.11a8.3 8.3 0 0 0 1.6-.66l.34-.2 1.83 1.83 1.57-1.5-1.81-1.82.2-.34c.27-.44.45-.99.66-1.6l.11-.34H20v-2.3h-2.56l-.11-.34a8.2 8.2 0 0 0-.66-1.6l-.2-.34 1.82-1.82-1.59-1.6-1.82 1.83-.34-.2a8.2 8.2 0 0 0-1.6-.66l-.34-.11V3zm-2.9 8.5c0-2.18 1.82-4 4-4s4 1.82 4 4-1.82 4-4 4-4-1.82-4-4m4-3c-1.62 0-3 1.38-3 3s1.38 3 3 3 3-1.38 3-3-1.38-3-3-3"/>' ,
mapLayer : '<path fill="currentColor" d="m11.7 19.4-8.97-5.66.54-.85 8.96 5.67c.17.1.37.1.54 0l8.96-5.67.54.85-8.97 5.66a1.5 1.5 0 0 1-1.6 0m.53-3.84c.17.1.37.1.54 0l8.3-5.25-8.3-5.23a.5.5 0 0 0-.54 0l-8.3 5.23zm-.53.84-9.64-6.09 9.64-6.08a1.5 1.5 0 0 1 1.6 0l9.64 6.08-9.64 6.1c-.49.3-1.11.3-1.6 0Z"/>' ,
carSearch : '<path fill="currentColor" d="M1 7.8a6.16 6.16 0 0 0 6.1 6.1h.4A5.7 5.7 0 0 0 13 7.91V7.9a6.1 6.1 0 0 0-5.91-6A5.93 5.93 0 0 0 1 7.8m-1 0C0 3.92 3.23.8 7.11.9a7.1 7.1 0 0 1 6.89 7c.06 2.33-1 4.44-2.73 5.71L14.8 19H20v1.5c0 .28.22.5.5.5h2a.5.5 0 0 0 .5-.5v-7.8l-1.9-1.9-.04-.06a55 55 0 0 0-2.84-4.71c-1.42-.1-2.49-.17-3.2-.2l.04-1c.77.04 1.93.1 3.48.22l.24.02.14.2a55 55 0 0 1 2.99 4.93L24 12.3v8.2c0 .83-.67 1.5-1.5 1.5h-2a1.5 1.5 0 0 1-1.5-1.5V20h-3.55l1.67 2.54-.84.54L14.26 20 5 19.96v.54c0 .83-.67 1.5-1.5 1.5h-2A1.5 1.5 0 0 1 0 20.5v-7.08h1v7.08c0 .28.22.5.5.5h2a.5.5 0 0 0 .5-.5v-1.54l9.6.02-3.17-4.83c-.87.45-1.85.72-2.92.75H7.1c-3.88 0-7-3.13-7.1-7.09zm5.47-2.75c1.86-.12 3.37-.2 4.52-.24l.03 1c-1.08.03-2.5.1-4.24.22L4.51 8c-.27.43-.6 1-1 1.7l-.87-.48c.4-.72.74-1.3 1.03-1.76q.6-.96 1.41-2.19l.14-.2z"/>' ,
gps : '<path fill="currentColor" d="M12.5 3.51V6.5h-1V3.51a8.46 8.46 0 0 0-7.99 7.99H6.5v1H3.51a8.46 8.46 0 0 0 7.99 7.99V17.5h1v2.99a8.46 8.46 0 0 0 7.99-7.99H17.5v-1h2.99a8.46 8.46 0 0 0-7.99-7.99m0-1a9.46 9.46 0 0 1 8.99 8.99h2.01v1h-2.01a9.46 9.46 0 0 1-8.99 8.99v2.01h-1v-2.01a9.46 9.46 0 0 1-8.99-8.99H.5v-1h2.01a9.46 9.46 0 0 1 8.99-8.99V.5h1z"/>' ,
@@ -1486,7 +1501,7 @@ function teaser() {
< span class = "v" > $ { streckeText ( t . distance _km , "—" ) } < small > $ { fahrtVerbrauch ( t ) != null ? de ( fahrtVerbrauch ( t ) , 1 ) + " l/100 km" : "—" } < / s m a l l > < / s p a n >
< svg class = "chev" viewBox = "0 0 6 10" > < polyline points = "1,1 5,5 1,9" / > < / s v g > < / b u t t o n > ` : " " }
$ { f ? ` <button class="leaf" style="padding-left:0;border-bottom:0" data-go="fill: ${ f . tank _id } ">
< span class = "k" > Letzter Tankvorgang < small > $ { esc ( f . station _name || "" ) } < / s m a l l > < / s p a n >
< span class = "k" > Letzter Tankvorgang < small > $ { f . ts ? dedat ( new Date ( f . ts ) ) : "" } < / s m a l l > < / s p a n >
< span class = "v" > $ { f . liters != null ? de ( f . liters , 2 ) + " l" : "" } < small > $ { f . fuel _total _eur != null ? eur ( f . fuel _total _eur ) + " €" : "" } < / s m a l l > < / s p a n >
< svg class = "chev" viewBox = "0 0 6 10" > < polyline points = "1,1 5,5 1,9" / > < / s v g > < / b u t t o n > ` : " " } < / d i v > ` ;
}
@@ -1848,7 +1863,7 @@ function vSicherheit() {
/ * C 6 : D r a u f s i c h t o b e n , g r ü n e S a m m e l m e l d u n g , d a n n d i e v i e r S a m m e l z e i l e n -
dieselbe Reihenfolge wie der Fahrzeugstatus in der myAudi - App . * /
return `
< div class = "szene bleed" > < div class = "carbox" > $ { bildMitPlatzhalter ( ` /local/bilder/draufsicht.webp?v= ${ bildVersion } ` , "draufsicht.webp" , "Draufsicht" , "carfix klein" ) } < / d i v > < / d i v >
< div class = "szene bleed schmal " > < div class = "carbox" > $ { bildMitPlatzhalter ( ` /local/bilder/draufsicht.webp?v= ${ bildVersion } ` , "draufsicht.webp" , "Draufsicht" , "carfix klein" ) } < / d i v > < / d i v >
< div class = "tile" style = "display:flex;align-items:center;gap:12px;padding:16px 20px" >
$ { statusKreis ( g ) }
< span style = "font-size:15px;color:var(--fg)" > $ { esc ( sammelText ) } < / s p a n >
@@ -2404,7 +2419,7 @@ function vService() {
< div class = "tile" >
< span class = "label" > Autohaus < / s p a n >
< button class = "zahnrad" data - go = "werkstatt:x" aria - label = "Angaben ändern" >
< svg viewBox = "0 0 24 24" fill = "currentColor" > < path d = "M9.4 2h4.2v2.84c.37.13.75.27 1.11.44L16.7 3.3l3 3.01-1.98 1.99c.17.36.31.74.44 1.11H21v4.3h-2.84c-.13.37-.27.75-.44 1.11l2 2-3.03 2.89-1.98-1.98c-.36.17-.74.31-1.11.44V21H9.4v-2.84a9 9 0 0 1-1.11-.44L6.3 19.7l-3-3.01 1.98-1.99a9 9 0 0 1-.44-1.11H2V9.4h2.84c.13-.37.27-.75.44-1.11L3.3 6.3l3.01-3L8.3 5.28c.36-.17.74-.31 1.11-.44V2Zm1 1v2.56l-.34.11c-.61.2-1.16.4-1.6.66l-.34.2L6.3 4.71 4.7 6.3l1.83 1.82-.2.34c-.27.44-.45.99-.66 1.6l-.11.34H3v2.2h2.56l.11.34c.2.61.4 1.16.66 1.6l.2.34-1.82 1.82 1.59 1.6 1.82-1.83.34.2c.44.27.99.45 1.6.66l.34.11V20h2.2v-2.56l.34-.11a8.3 8.3 0 0 0 1.6-.66l.34-.2 1.83 1.83 1.57-1.5-1.81-1.82.2-.34c.27-.44.45-.99.66-1.6l.11-.34H20v-2.3h-2.56l-.11-.34a8.2 8.2 0 0 0-.66-1.6l-.2-.34 1.82-1.82-1.59-1.6-1.82 1.83-.34-.2a8.2 8.2 0 0 0-1.6-.66l-.34-.11V3zm-2.9 8.5c0-2.18 1.82-4 4-4s4 1.82 4 4-1.82 4-4 4-4-1.82-4-4m4-3c-1.62 0-3 1.38-3 3s1.38 3 3 3 3-1.38 3-3-1.38-3-3-3" / > < / s v g >
$ { ciSVG ( CI . settingsS , 17 ) }
< / b u t t o n >
< div style = "font-size:15px;margin-top:12px" > $ { esc ( sv . autohaus . name ) } < / d i v >
< span class = "label" style = "margin-top:8px" > $ { esc ( sv . autohaus . adresse ) } < / s p a n >
@@ -2655,7 +2670,7 @@ function vVers() {
return `
< div class = "tile" > < span class = "label" > Versicherung - Schaden Notruf 24 / 7 < / s p a n >
< button class = "zahnrad" data - go = "notruf:x" aria - label = "Rufnummern ändern" >
< svg viewBox = "0 0 24 24" fill = "currentColor" > < path d = "M9.4 2h4.2v2.84c.37.13.75.27 1.11.44L16.7 3.3l3 3.01-1.98 1.99c.17.36.31.74.44 1.11H21v4.3h-2.84c-.13.37-.27.75-.44 1.11l2 2-3.03 2.89-1.98-1.98c-.36.17-.74.31-1.11.44V21H9.4v-2.84a9 9 0 0 1-1.11-.44L6.3 19.7l-3-3.01 1.98-1.99a9 9 0 0 1-.44-1.11H2V9.4h2.84c.13-.37.27-.75.44-1.11L3.3 6.3l3.01-3L8.3 5.28c.36-.17.74-.31 1.11-.44V2Zm1 1v2.56l-.34.11c-.61.2-1.16.4-1.6.66l-.34.2L6.3 4.71 4.7 6.3l1.83 1.82-.2.34c-.27.44-.45.99-.66 1.6l-.11.34H3v2.2h2.56l.11.34c.2.61.4 1.16.66 1.6l.2.34-1.82 1.82 1.59 1.6 1.82-1.83.34.2c.44.27.99.45 1.6.66l.34.11V20h2.2v-2.56l.34-.11a8.3 8.3 0 0 0 1.6-.66l.34-.2 1.83 1.83 1.57-1.5-1.81-1.82.2-.34c.27-.44.45-.99.66-1.6l.11-.34H20v-2.3h-2.56l-.11-.34a8.2 8.2 0 0 0-.66-1.6l-.2-.34 1.82-1.82-1.59-1.6-1.82 1.83-.34-.2a8.2 8.2 0 0 0-1.6-.66l-.34-.11V3zm-2.9 8.5c0-2.18 1.82-4 4-4s4 1.82 4 4-1.82 4-4 4-4-1.82-4-4m4-3c-1.62 0-3 1.38-3 3s1.38 3 3 3 3-1.38 3-3-1.38-3-3-3" / > < / s v g >
$ { ciSVG ( CI . settingsS , 17 ) }
< / b u t t o n >
< a class = "aktion" href = "tel:${esc(v.service.replace(/\s/g, " "))}"
style = "display:block;text-decoration:none;margin-top:14px;text-align:center" >
@@ -2666,7 +2681,7 @@ function vVers() {
< / d i v >
< div class = "tile" > < span class = "label" > Jahresbeitrag ab $ { dedat ( new Date ( v . gueltigAb ) ) } < / s p a n >
< button class = "zahnrad" data - go = "beitrag:x" aria - label = "Beitrag anpassen" >
< svg viewBox = "0 0 24 24" fill = "currentColor" > < path d = "M9.4 2h4.2v2.84c.37.13.75.27 1.11.44L16.7 3.3l3 3.01-1.98 1.99c.17.36.31.74.44 1.11H21v4.3h-2.84c-.13.37-.27.75-.44 1.11l2 2-3.03 2.89-1.98-1.98c-.36.17-.74.31-1.11.44V21H9.4v-2.84a9 9 0 0 1-1.11-.44L6.3 19.7l-3-3.01 1.98-1.99a9 9 0 0 1-.44-1.11H2V9.4h2.84c.13-.37.27-.75.44-1.11L3.3 6.3l3.01-3L8.3 5.28c.36-.17.74-.31 1.11-.44V2Zm1 1v2.56l-.34.11c-.61.2-1.16.4-1.6.66l-.34.2L6.3 4.71 4.7 6.3l1.83 1.82-.2.34c-.27.44-.45.99-.66 1.6l-.11.34H3v2.2h2.56l.11.34c.2.61.4 1.16.66 1.6l.2.34-1.82 1.82 1.59 1.6 1.82-1.83.34.2c.44.27.99.45 1.6.66l.34.11V20h2.2v-2.56l.34-.11a8.3 8.3 0 0 0 1.6-.66l.34-.2 1.83 1.83 1.57-1.5-1.81-1.82.2-.34c.27-.44.45-.99.66-1.6l.11-.34H20v-2.3h-2.56l-.11-.34a8.2 8.2 0 0 0-.66-1.6l-.2-.34 1.82-1.82-1.59-1.6-1.82 1.83-.34-.2a8.2 8.2 0 0 0-1.6-.66l-.34-.11V3zm-2.9 8.5c0-2.18 1.82-4 4-4s4 1.82 4 4-1.82 4-4 4-4-1.82-4-4m4-3c-1.62 0-3 1.38-3 3s1.38 3 3 3 3-1.38 3-3-1.38-3-3-3" / > < / s v g >
$ { ciSVG ( CI . settingsS , 17 ) }
< / b u t t o n >
< div class = "fig" style = "font-size:46px;margin-top:12px" > $ { eur ( v . beitrag ) } < span class = "unit" > € < / s p a n > < / d i v >
< span class = "label" style = "margin-top:14px" > $ { esc ( v . zahlweise ) } · enthält $ { eur ( v . steueranteil ) } € Versicherungsteuer ( $ { esc ( v . steuersatz ) } ) < / s p a n >
@@ -2681,7 +2696,7 @@ function vVers() {
< / d i v >
< div class = "tile" > < span class = "label" > Vertrag < / s p a n >
< button class = "zahnrad" data - go = "vertrag:x" aria - label = "Vertrag bearbeiten" >
< svg viewBox = "0 0 24 24" fill = "currentColor" > < path d = "M9.4 2h4.2v2.84c.37.13.75.27 1.11.44L16.7 3.3l3 3.01-1.98 1.99c.17.36.31.74.44 1.11H21v4.3h-2.84c-.13.37-.27.75-.44 1.11l2 2-3.03 2.89-1.98-1.98c-.36.17-.74.31-1.11.44V21H9.4v-2.84a9 9 0 0 1-1.11-.44L6.3 19.7l-3-3.01 1.98-1.99a9 9 0 0 1-.44-1.11H2V9.4h2.84c.13-.37.27-.75.44-1.11L3.3 6.3l3.01-3L8.3 5.28c.36-.17.74-.31 1.11-.44V2Zm1 1v2.56l-.34.11c-.61.2-1.16.4-1.6.66l-.34.2L6.3 4.71 4.7 6.3l1.83 1.82-.2.34c-.27.44-.45.99-.66 1.6l-.11.34H3v2.2h2.56l.11.34c.2.61.4 1.16.66 1.6l.2.34-1.82 1.82 1.59 1.6 1.82-1.83.34.2c.44.27.99.45 1.6.66l.34.11V20h2.2v-2.56l.34-.11a8.3 8.3 0 0 0 1.6-.66l.34-.2 1.83 1.83 1.57-1.5-1.81-1.82.2-.34c.27-.44.45-.99.66-1.6l.11-.34H20v-2.3h-2.56l-.11-.34a8.2 8.2 0 0 0-.66-1.6l-.2-.34 1.82-1.82-1.59-1.6-1.82 1.83-.34-.2a8.2 8.2 0 0 0-1.6-.66l-.34-.11V3zm-2.9 8.5c0-2.18 1.82-4 4-4s4 1.82 4 4-1.82 4-4 4-4-1.82-4-4m4-3c-1.62 0-3 1.38-3 3s1.38 3 3 3 3-1.38 3-3-1.38-3-3-3" / > < / s v g >
$ { ciSVG ( CI . settingsS , 17 ) }
< / b u t t o n >
< dl class = "rows" style = "margin-top:8px" >
< div class = "row" > < dt > Gesellschaft < / d t > < d d > $ { e s c ( v . g e s e l l s c h a f t ) } < / d d > < / d i v >
@@ -2827,7 +2842,7 @@ function vSteuer() {
return `
< div class = "tile" style = "margin-top:26px" > < span class = "label" > Kfz - Steuer < / s p a n >
< button class = "zahnrad" data - go = "steuer:x" aria - label = "Kfz-Steuer bearbeiten" >
< svg viewBox = "0 0 24 24" fill = "currentColor" > < path d = "M9.4 2h4.2v2.84c.37.13.75.27 1.11.44L16.7 3.3l3 3.01-1.98 1.99c.17.36.31.74.44 1.11H21v4.3h-2.84c-.13.37-.27.75-.44 1.11l2 2-3.03 2.89-1.98-1.98c-.36.17-.74.31-1.11.44V21H9.4v-2.84a9 9 0 0 1-1.11-.44L6.3 19.7l-3-3.01 1.98-1.99a9 9 0 0 1-.44-1.11H2V9.4h2.84c.13-.37.27-.75.44-1.11L3.3 6.3l3.01-3L8.3 5.28c.36-.17.74-.31 1.11-.44V2Zm1 1v2.56l-.34.11c-.61.2-1.16.4-1.6.66l-.34.2L6.3 4.71 4.7 6.3l1.83 1.82-.2.34c-.27.44-.45.99-.66 1.6l-.11.34H3v2.2h2.56l.11.34c.2.61.4 1.16.66 1.6l.2.34-1.82 1.82 1.59 1.6 1.82-1.83.34.2c.44.27.99.45 1.6.66l.34.11V20h2.2v-2.56l.34-.11a8.3 8.3 0 0 0 1.6-.66l.34-.2 1.83 1.83 1.57-1.5-1.81-1.82.2-.34c.27-.44.45-.99.66-1.6l.11-.34H20v-2.3h-2.56l-.11-.34a8.2 8.2 0 0 0-.66-1.6l-.2-.34 1.82-1.82-1.59-1.6-1.82 1.83-.34-.2a8.2 8.2 0 0 0-1.6-.66l-.34-.11V3zm-2.9 8.5c0-2.18 1.82-4 4-4s4 1.82 4 4-1.82 4-4 4-4-1.82-4-4m4-3c-1.62 0-3 1.38-3 3s1.38 3 3 3 3-1.38 3-3-1.38-3-3-3" / > < / s v g >
$ { ciSVG ( CI . settingsS , 17 ) }
< / b u t t o n >
< dl class = "rows" style = "margin-top:10px" >
< div class = "row" > < dt > Betrag < / d t > < d d > $ { e u r ( t . b e t r a g ) } € < s m a l l > $ { t . z e i t r a u m = = = " j ä h r l i c h " ? " i m J a h r " : e s c ( t . z e i t r a u m ) } < / s m a l l > < / d d > < / d i v >
@@ -2937,7 +2952,10 @@ function vEinst() {
const info = bildInfo ( startIndex ( ) ) ;
return ` <div style="margin-top:12px">
< div data - bildklick = "${esc(info.datei)}" >
$ { bildMitPlatzhalter ( info . src , info . datei , info . label , "carfix" , null , true ) }
$ { / * " k l e i n " = d a s B i l d b e s t i m m t d i e H o e h e , s t a t t i m 1 6 : 9 - K a s t e n
beschnitten zu werden ( siehe . carfix . klein ) . Wer hier prueft ,
ob das richtige Foto hochgeladen ist , muss es ganz sehen . * / " "
} $ { bildMitPlatzhalter ( info . src , info . datei , info . label , "carfix klein" , null , true ) }
< / d i v >
< input type = "file" accept = "image/*" hidden data - bildupload = "${esc(info.datei)}" >
$ { bildMenuOffen === info . datei ? `
@@ -3399,7 +3417,7 @@ function vReifen() {
return `
< div class = "tile" > < span class = "label" > Anzugsmoment der Radschrauben < / s p a n >
< button class = "zahnrad" data - nmauf aria - label = "Anzugsmoment ändern" >
< svg viewBox = "0 0 24 24" fill = "currentColor" > < path d = "M9.4 2h4.2v2.84c.37.13.75.27 1.11.44L16.7 3.3l3 3.01-1.98 1.99c.17.36.31.74.44 1.11H21v4.3h-2.84c-.13.37-.27.75-.44 1.11l2 2-3.03 2.89-1.98-1.98c-.36.17-.74.31-1.11.44V21H9.4v-2.84a9 9 0 0 1-1.11-.44L6.3 19.7l-3-3.01 1.98-1.99a9 9 0 0 1-.44-1.11H2V9.4h2.84c.13-.37.27-.75.44-1.11L3.3 6.3l3.01-3L8.3 5.28c.36-.17.74-.31 1.11-.44V2Zm1 1v2.56l-.34.11c-.61.2-1.16.4-1.6.66l-.34.2L6.3 4.71 4.7 6.3l1.83 1.82-.2.34c-.27.44-.45.99-.66 1.6l-.11.34H3v2.2h2.56l.11.34c.2.61.4 1.16.66 1.6l.2.34-1.82 1.82 1.59 1.6 1.82-1.83.34.2c.44.27.99.45 1.6.66l.34.11V20h2.2v-2.56l.34-.11a8.3 8.3 0 0 0 1.6-.66l.34-.2 1.83 1.83 1.57-1.5-1.81-1.82.2-.34c.27-.44.45-.99.66-1.6l.11-.34H20v-2.3h-2.56l-.11-.34a8.2 8.2 0 0 0-.66-1.6l-.2-.34 1.82-1.82-1.59-1.6-1.82 1.83-.34-.2a8.2 8.2 0 0 0-1.6-.66l-.34-.11V3zm-2.9 8.5c0-2.18 1.82-4 4-4s4 1.82 4 4-1.82 4-4 4-4-1.82-4-4m4-3c-1.62 0-3 1.38-3 3s1.38 3 3 3 3-1.38 3-3-1.38-3-3-3" / > < / s v g >
$ { ciSVG ( CI . settingsS , 17 ) }
< / b u t t o n >
< div class = "fig" style = "font-size:34px;margin-top:12px" > $ { de ( r . anzugsmoment ) } < span class = "unit" > Nm < / s p a n > < / d i v >
$ { nmOffen ? `
@@ -3438,12 +3456,17 @@ function vReifenArchiv() {
return ` <div class="tile"><span class="label">Archiv</span>
$ { archiv . map ( ( a , i ) => {
const satzLabel = a . satz === "winter" ? "Winterräder" : "Sommerräder" ;
return ` <button class="acc-h" aria-expanded="false" data-acc="rfarch ${ i } "><span class="mark"></span>
/ * N a c h l i n k s w i s c h e n z u m L ö s c h e n , w i e i n d e r F a h r t e n - u n d
Tankvorgangsliste . Der Löschknopf in der aufgeklappten Zeile bleibt :
am Rechner ist er der kürzere Weg . Umschlossen ist nur die
Kopfzeile , nicht der aufgeklappte Rumpf - sonst verschöbe ein
waagerechtes Ziehen in einem Eingabefeld die ganze Zeile . * /
return swipeZeile ( ` rfarch: ${ a . id } ` , ` <button class="acc-h" aria-expanded="false" data-acc="rfarch ${ i } "><span class="mark"></span>
< span class = "k" > $ { satzLabel } < / s p a n >
< span class = "v" style = "display:flex;flex-direction:column;align-items:flex-end;gap:3px" >
< span style = "color:var(--fg);font-size:15px" > $ { a . km != null ? de ( a . km ) + " km" : "– " } < / s p a n >
< small > Ersetzt am $ { dedat ( new Date ( a . ersetzt _am ) ) } < / s m a l l >
< / s p a n > < / b u t t o n >
< / s p a n > < / b u t t o n > ` ) + `
< div class = "acc-b" id = "rfarch${i}" >
< div class = "feld" > < label > Ersetzt am < / l a b e l > < i n p u t t y p e = " d a t e " v a l u e = " $ { e s c ( a . e r s e t z t _ a m ? ? " " ) } " d a t a - r f a = " $ { a . i d } | e r s e t z t _ a m " > < / d i v >
< div class = "feld" > < label > Gefahrene Strecke < / l a b e l >
@@ -3682,18 +3705,24 @@ function statTile(id, label, fig, unit, extra, body) {
km im selben Zeitraum ) , da einzelne Fahrten keinen eigenen Verbrauchswert
tragen - erst über einen Zeitraum gemittelt ergibt das einen sinnvollen
l / 100 km - Wert . * /
/ * L ä n g e d e r r o l l e n d e n Z e i t r ä u m e i n T a g e n .
Bis zum 02.09 . 2026 waren die Spannen kalendarisch : Jahr ab 1. Januar , Monat
ab dem Ersten , Woche ab Montag , Tag ab Mitternacht . Das ergab regelmäßig
einen unmöglichen Vergleich — am 02.09 . 2026 stand in der realen Instanz
"Monat" UNTER "Woche" , weil die Woche am Montag , dem 31.08 . , begann und
damit zwei Tage mitzählte , die der Monat nicht kennt . Zwischen Monat und
Jahr passiert dasselbe am Jahreswechsel .
Rollende Fenster können das nicht : 1 ⊂ 7 ⊂ 30 ⊂ 365 gilt an jedem Tag des
Jahres . Der Preis ist , dass "Jahr" nicht mehr das Kalenderjahr meint ,
sondern die letzten 365 Tage — so entschieden vom Eigentümer am 02.09 . 2026.
Gleichlautend in companion - app / src / daten / statistik . ts ( ZEITRAUM _TAGE ) . * /
const ZEITRAUM _TAGE = { jahr : 365 , monat : 30 , woche : 7 , tag : 1 } ;
function periodStart ( art ) {
// Alles, was je erfasst wurde - kein Zeitraum, sondern die Summe.
if ( art === "absolut" ) return new Date ( 0 ) ;
const jetzt = new Date ( ) ;
if ( art === "jahr" ) return new Date ( jetzt . getFullYear ( ) , 0 , 1 ) ;
if ( art === "monat" ) return new Date ( jetzt . getFullYear ( ) , jetzt . getMonth ( ) , 1 ) ;
if ( art === "woche" ) {
const d = new Date ( jetzt ) ; d . setHours ( 0 , 0 , 0 , 0 ) ;
d . setDate ( d . getDate ( ) - ( ( d . getDay ( ) + 6 ) % 7 ) ) ;
return d ;
}
const d = new Date ( jetzt ) ; d . setHours ( 0 , 0 , 0 , 0 ) ; return d ;
return new Date ( Date . now ( ) - ZEITRAUM _TAGE [ art ] * 24 * 60 * 60 * 1000 ) ;
}
const fahrtenSeit = ( art ) => TRIPS . filter ( ( t ) => t . distance _km != null && new Date ( t . ts _start ) >= periodStart ( art ) ) ;
const tankSeit = ( art ) => FILLS . filter ( ( f ) => f . liters != null && new Date ( f . ts ) >= periodStart ( art ) ) ;
@@ -3797,6 +3826,12 @@ function vStat() {
const nachtKm = kmJahr - tagKm ;
const arbeitFahrten = fJahr . filter ( ( t ) => t . art === "arbeitsweg" ) , privatFahrten = fJahr . filter ( ( t ) => t . art !== "arbeitsweg" ) ;
const arbeitKm = sum ( arbeitFahrten , ( t ) => t . distance _km ) , privatKm = kmJahr - arbeitKm ;
/ * D i e H e r l e i t u n g d e s L a n g z e i t w e r t s - g e t a n k t e L i t e r , B e z u g s s t r e c k e , l e t z t e r
Tankstop , der Unplausibel - Hinweis und der Erklärabsatz - ist am
02.09 . 2026 auf Ansage des Eigentümers aus der ANSICHT genommen worden ,
nicht aus der Rechnung : langzeitverbrauch ( ) rechnet unverändert weiter
und liefert lv . liter / lv . km / lv . basis nach wie vor . In der Kachel bleiben
der Wert selbst und die Näherung je Zeitraum . * /
const lv = langzeitverbrauch ( ) ;
return `
$ { statTile ( "s1" , "Distanz und Fahrzeit" , de ( kmAbs ) , "km" , de ( hAbs ) + " h" ,
@@ -3805,15 +3840,8 @@ function vStat() {
$ { statTile ( "s2" , "Getankte Menge und Kosten" , de ( lAbs ) , "l" , de ( eAbs ) + " €" ,
quad ( "Getankte Liter [l]" , [ [ de ( lJahr ) , "Jahr" ] , [ de ( sum ( tankSeit ( "monat" ) , ( f ) => f . liters ) ) , "Monat" ] , [ de ( sum ( tankSeit ( "woche" ) , ( f ) => f . liters ) ) , "Woche" ] , [ de ( sum ( tankSeit ( "tag" ) , ( f ) => f . liters ) ) , "Tag" ] ] ) +
quad ( "Kraftstoffkosten [€]" , [ [ de ( eJahr ) , "Jahr" ] , [ de ( sum ( tankSeit ( "monat" ) , ( f ) => f . fuel _total _eur || 0 ) ) , "Monat" ] , [ de ( sum ( tankSeit ( "woche" ) , ( f ) => f . fuel _total _eur || 0 ) ) , "Woche" ] , [ de ( sum ( tankSeit ( "tag" ) , ( f ) => f . fuel _total _eur || 0 ) ) , "Tag" ] ] ) ) }
$ { statTile ( "s3" , "Langzeitverbrauch" , lv . wert , "l/100 km" , lv . bis ? "bis " + dedat ( lv . bis ) : "– ",
` <dl class="rows">
< div class = "row" > < dt > Getankt insgesamt < / d t > < d d > $ { d e ( l v . l i t e r , 1 ) } l < / d d > < / d i v >
< div class = "row" > < dt > Strecke bis zum letzten Tankstop < / d t > < d d > $ { d e ( l v . k m ) } k m < s m a l l > $ { l v . b a s i s } < / s m a l l > < / d d > < / d i v >
< div class = "row" style = "border-bottom:0" > < dt > Letzter Tankstop < / d t > < d d > $ { l v . b i s ? d e d a t ( l v . b i s ) : " – " } < / d d > < / d i v >
< / d l >
$ { lv . unplausibel ? ` <span class="label" style="margin-top:16px;color:var(--warn)">Aus Litern und Strecke ergibt sich derzeit kein plausibler Wert. Sobald Tankvorgänge und Kilometerstände vollständig vorliegen, erscheint er hier.</span> ` : "" }
$ { quad ( "Näherung je Fahrt, je Zeitraum [l/100 km]" , [ [ schnittFahrtVerbrauch ( fJahr ) , "Jahr" ] , [ schnittFahrtVerbrauch ( fMonat ) , "Monat" ] , [ schnittFahrtVerbrauch ( fWoche ) , "Woche" ] , [ schnittFahrtVerbrauch ( fTag ) , "Tag" ] ] ) }
< span class = "label" style = "margin-top:16px" > Der Langzeitwert rechnet alle je getankten Liter gegen die Strecke bis zum letzten Tankstop . Die Werte je Zeitraum sind eine Näherung aus der Tankfüllstand - Differenz der einzelnen Fahrten , keine Meldung des Fahrzeugs . < / s p a n > ` ) }
$ { statTile ( "s3" , "Langzeitverbrauch" , lv . wert , "l/100 km" , " ",
quad ( "Näherung je Fahrt, je Zeitraum [l/100 km]" , [ [ schnittFahrtVerbrauch ( fJahr ) , "Jahr" ] , [ schnittFahrtVerbrauch ( fMonat ) , "Monat" ] , [ schnittFahrtVerbrauch ( fWoche ) , "Woche" ] , [ schnittFahrtVerbrauch ( fTag ) , "Tag" ] ] ) ) }
$ { statTile ( "s4" , "Tag und Nacht" , kmJahr > 0 ? de ( Math . round ( ( tagKm / kmJahr ) * 100 ) ) : "– " , "% bei Tag" , de ( tagKm ) + " km" ,
` <div class="bar"><i style="flex: ${ tagKm } ;background:var(--fg)"></i><i style="flex: ${ nachtKm } ;background:var(--fg3)"></i></div>
< div class = "legend" > < span > < i style = "background:var(--fg)" > < / i > T a g · $ { d e ( t a g K m ) } k m < / s p a n >
@@ -3891,6 +3919,7 @@ const LOESCH_TEXT = {
sbuch : "Wartungsplan-Eintrag löschen?" ,
bild : "Foto löschen?" ,
batt : "Messwert löschen?" ,
rfarch : "Archivierten Radsatz löschen?" ,
} ;
const LOESCH _HINWEIS = {
trip : "Die Fahrt wird aus dem Fahrtenbuch entfernt. Das lässt sich nicht widerrufen." ,
@@ -3898,6 +3927,7 @@ const LOESCH_HINWEIS = {
sbuch : "Der Eintrag wird aus dem Wartungsplan entfernt. Das lässt sich nicht widerrufen." ,
bild : "Das Foto wird vom Server gelöscht. Der Platz bleibt bestehen und kann neu belegt werden." ,
batt : "Der Tageseintrag wird aus der Messwertliste entfernt. Das lässt sich nicht widerrufen." ,
rfarch : "Der archivierte Radsatz wird mit seiner Laufleistung entfernt. Das lässt sich nicht widerrufen." ,
} ;
function eintragLoeschen ( art , id ) {
if ( art === "trip" ) {
@@ -3912,6 +3942,11 @@ function eintragLoeschen(art, id) {
} else if ( art === "batt" ) {
serviceRufen ( "batterieverlauf_loeschen" , { datum : id } ) ;
BATTERIEVERLAUF = BATTERIEVERLAUF . filter ( ( e ) => e . datum !== id ) ;
} else if ( art === "rfarch" ) {
// Eigener Dienst statt profilSpeichern - wie schon beim Löschknopf in der
// aufgeklappten Zeile (siehe data-reifenarchivloeschen).
serviceRufen ( "reifen_archiv_loeschen" , { id } ) ;
CAR . reifen . archiv = ( CAR . reifen . archiv || [ ] ) . filter ( ( a ) => a . id !== id ) ;
}
}
@@ -4221,7 +4256,15 @@ const ICONS = {
( . tab svg 26 px / 22 px ) automatisch im richtigen Verhältnis , ohne zwei
Stellen pflegen zu müssen . * /
stat : ` <g transform="translate(2.76,2.76) scale(0.77)"> ${ CI . pollsS } </g> ` ,
fuel : '<path d="M4.5 20V6.2c0-.9.8-1.7 1.7-1.7h5.6c1 0 1.7.8 1.7 1.7V20"/><path d="M3 20h12.5"/><path d="M4.5 11h10.5"/><path d="M17 20v-8.5a2 2 0 0 0-2-2"/><path d="M17 11.5V7.8l-2-2.3"/>' ,
/ * D i e s e l b e B e h a n d l u n g w i e " s t a t " o b e n , a u s d e m s e l b e n G r u n d : d a s C I - S y m b o l
ist randlos gezeichnet und stuende ungeskaliert mit 22 von 24 Einheiten
Hoehe als hoechstes Symbol der Leiste da - hoeher als "Fahrten" ( 21 , 44 )
und deutlich hoeher als die gezeichnete Saeule davor ( 15 , 50 ) .
Faktor 0 , 84 um die Rastermitte bringt es auf 15 , 96 x 18 , 48 und damit auf
exakt dieselbe senkrechte Spanne wie "stat" ( y 2 , 76 bis 21 , 24 ) . Live
gemessen per getBBox ( ) , Raender eingeschlossen - nicht geschaetzt . * /
fuel : ` <g transform="translate(1.5,1.92) scale(0.84)"> ${ CI . fuelStationS } </g> ` ,
} ;
const TABS = [
{ id : "home" , label : "Übersicht" , eyebrow : "" , title : "Übersicht" } ,
@@ -4231,7 +4274,7 @@ const TABS = [
{ id : "fuel" , label : "Tanken" , eyebrow : "" , title : "Tanken" } ,
] ;
/* Symbole, die als Flaeche gezeichnet sind statt als Kontur */
const ICONS _VOLL = new Set ( [ "audi" , "stat" , "trips" ] ) ;
const ICONS _VOLL = new Set ( [ "audi" , "stat" , "trips" , "fuel" ] ) ;
let route = { name : "home" } ;
const ZURUECK = {
trip : "trips" , fill : "fuel" , service : "audi" , reifen : "audi" , ident : "audi" ,
@@ -4895,8 +4938,22 @@ function zurueck() {
route = ziel ; render ( ) ;
}
/* B3: Randwischen zurück - dieselbe Bewegung wie ein Tipp auf den Pfeil. */
/ * B 3 : R a n d w i s c h e n z u r ü c k - d i e s e l b e B e w e g u n g w i e e i n T i p p a u f d e n P f e i l .
Seit dem 02.09 . 2026 folgt die Seite dabei dem Finger ( randZeigen ) : ohne
diese Rückmeldung passierte bis zum Loslassen nichts sichtbares , und wer
die Geste zu kurz zog , sah nicht , dass er sie überhaupt begonnen hatte .
Unter der Auslöseschwelle federt sie zurück - die Geste ist damit
widerrufbar , indem man den Finger zurückführt . Gleichlautend in der App
( useWischZurueck in Shell . tsx ) . * /
let randX0 = null , randY0 = null ;
function randZeigen ( dx ) {
const ansicht = $ ( "#view" ) ;
if ( ! ansicht ) return ;
if ( dx === null ) { ansicht . style . transition = "" ; ansicht . style . transform = "" ; return ; }
ansicht . style . transition = "none" ;
ansicht . style . transform = ` translateX( ${ Math . min ( 140 , dx ) } px) ` ;
}
function randwischenVerdrahten ( ) {
const phone = ROOT . querySelector ( ".phone" ) ;
phone . addEventListener ( "pointerdown" , ( e ) => {
@@ -4905,11 +4962,19 @@ function randwischenVerdrahten() {
const links = phone . getBoundingClientRect ( ) . left ;
if ( e . clientX - links <= 26 && ! istTab ( route . name ) ) { randX0 = e . clientX ; randY0 = e . clientY ; }
} ) ;
phone . addEventListener ( "pointerup " , ( e ) => {
if ( randX0 ! == null && e . clientX - randX0 > 62 && Math . abs ( e . clientY - randY0 ) < 60 ) zurueck ( ) ;
randX0 = null ;
phone . addEventListener ( "pointermove " , ( e ) => {
if ( randX0 = == null || ! e . isPrimary ) return ;
const dx = e . clientX - randX0 ;
// Senkrecht gemeint: die Geste gehört dem Scrollen, nicht uns.
if ( Math . abs ( e . clientY - randY0 ) > 60 ) { randX0 = null ; randZeigen ( null ) ; return ; }
if ( dx > 0 ) randZeigen ( dx ) ;
} ) ;
phone . addEventListener ( "pointercancel " , ( ) => { randX0 = null ; } ) ;
phone . addEventListener ( "pointerup " , ( e ) => {
const ausloesen = randX0 !== null && e . clientX - randX0 > 62 && Math . abs ( e . clientY - randY0 ) < 60 ;
randX0 = null ; randZeigen ( null ) ;
if ( ausloesen ) zurueck ( ) ;
} ) ;
phone . addEventListener ( "pointercancel" , ( ) => { randX0 = null ; randZeigen ( null ) ; } ) ;
}
/ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - A k t i o n e n
@@ -6273,7 +6338,7 @@ class AudiDashboardPanel extends HTMLElement {
< div class = "sync" id = "sync" > < svg viewBox = "0 0 24 24" width = "14" height = "14" fill = "currentColor" > < path d = "m18.65 4.95 2.56 2.55-2.56 2.55-.7-.7L19.29 8H7.2A5.24 5.24 0 0 0 2 13.38V14H1v-.6A6.24 6.24 0 0 1 7.2 7h12.1l-1.34-1.35.7-.7ZM23 11.59A6.24 6.24 0 0 1 16.8 18H4.7l1.35 1.35-.7.7-2.56-2.55 2.56-2.55.7.7L4.71 17H16.8a5.24 5.24 0 0 0 5.2-5.38V11h1v.6Z" / > < / s v g > < s p a n > < / s p a n > < / d i v > < / d i v >
< span class = "kopfgegengewicht" aria - hidden = "true" > < / s p a n >
< button class = "themebtn" id = "theme" hidden aria - hidden = "true" > < svg id = "themeicon" viewBox = "0 0 20 20" width = "15" height = "15" > < / s v g > < / b u t t o n >
< button class = "profilbtn" id = "ringsbtn" aria - label = "Einstellungen" > < svg viewBox = "0 0 24 24" aria - hidden = "true" > < circle cx = "12" cy = "12" r = "3" / > < path d = "M19.4 15a1.6 1.6 0 0 0 .33 1.76l.06.06a2 2 0 1 1-2.83 2.83l-.06-.06a1.6 1.6 0 0 0-1.76-.33 1.6 1.6 0 0 0-1 1.47V21a2 2 0 1 1-4 0v-.1a1.6 1.6 0 0 0-1-1.47 1.6 1.6 0 0 0-1.77.33l-.06.06a2 2 0 1 1-2.83-2.83l.06-.06A1.6 1.6 0 0 0 4.6 15a1.6 1.6 0 0 0-1.47-1H3a2 2 0 1 1 0-4h.1a1.6 1.6 0 0 0 1.47-1 1.6 1.6 0 0 0-.33-1.77l-.06-.06a2 2 0 1 1 2.83-2.83l.06.06A1.6 1.6 0 0 0 9 4.6 1.6 1.6 0 0 0 10 3.13V3a2 2 0 1 1 4 0v.1a1.6 1.6 0 0 0 1 1.47 1.6 1.6 0 0 0 1.77-.33l.06-.06a2 2 0 1 1 2.83 2.83l-.06.06A1.6 1.6 0 0 0 19.4 9v.04a1.6 1.6 0 0 0 1.47 1H21a2 2 0 1 1 0 4h-.1a1.6 1.6 0 0 0-1.5 1Z" / > < / s v g > < / b u t t o n >
< button class = "profilbtn" id = "ringsbtn" aria - label = "Einstellungen" > $ { ciSVG ( CI . settingsS , 19 ) } < / b u t t o n >
< / d i v >
< div class = "ptr" id = "ptr" > < svg viewBox = "0 0 24 24" width = "20" height = "20" fill = "currentColor" > < path d = "M20.06 8.36c-1.21-3.33-4.3-6.46-8.5-6.46-3.69 0-6.97 2-8.55 5.28a9.47 9.47 0 0 0 4.23 12.77A9.56 9.56 0 0 0 20 15.72l-.89-.44a8.56 8.56 0 0 1-11.43 3.77A8.47 8.47 0 0 1 3.9 7.62a8.38 8.38 0 0 1 7.65-4.72c3.8 0 6.64 2.94 7.66 6.1h-5.66v1h7.5V2.5h-1v5.86Z" / > < / s v g > < s p a n > Z i e h e n z u m A k t u a l i s i e r e n < / s p a n > < / d i v >
< main id = "view" > < div class = "tile" style = "margin-top:20px;display:flex;align-items:center;gap:10px" > < span class = "lade-spinner" aria - hidden = "true" > < / s p a n > < s p a n c l a s s = " l a b e l " s t y l e = " m a r g i n : 0 " > L ä d t … < / s p a n > < / d i v > < / m a i n >