/* WAMMES Struktur: Lueftungsanlage (Szene Teil a bis d, Website-Fassung), Stand 10.11.2026 (Runde 14). Erzeugt mit build.py aus src. Regel: keine Zeichen Kleiner, Groesser, Kaufmanns-Und. (c) 2026 Wammes Machinery LW GmbH, Wiebelsheim. Alle Rechte vorbehalten. Nutzung nur auf wammesmachinery.com. */
(function () {
'use strict';
var DATA = {"bauteile":[{"id":"ahu","t":"RLT-Zentralgerät","te":"Air handling unit","grp":"Gerät","klick":"kontext","status":"ok","bereiche":["Außenluft","Zuluft","Abluft","Fortluft"],"schritte":[]},{"id":"absperr","t":"Außenluft- und Fortluftklappe","te":"Shut-off damper","grp":"Gerät","klick":"kontext","status":"ok","bereiche":[],"schritte":[]},{"id":"wetter","t":"Wetterschutzgitter","te":"Weather louvre","grp":"Dach","klick":"kontext","status":"ok","bereiche":[],"schritte":[]},{"id":"bsk","t":"Brandschutzklappe","te":"Fire damper","grp":"Wand","klick":"kontext","status":"ok","bereiche":["Einbau in der Wandebene","Antrieb außen sichtbar"],"schritte":[]},{"id":"entrauch","t":"Entrauchungsklappe","te":"Smoke control damper","grp":"Anlage","klick":"kontext","status":"ok","bereiche":[],"schritte":[]},{"id":"vvs","t":"Volumenstromregler","te":"VAV/CAV terminal unit","grp":"Verteilung","klick":"kontext","status":"ok","bereiche":[],"schritte":[]},{"id":"auslass","t":"Luftdurchlass","te":"Air terminal","grp":"Raum","klick":"kontext","status":"ok","bereiche":[],"schritte":[]},{"id":"abhaeng","t":"Abhängung","te":"Hanger","grp":"Anlage","klick":"kontext","status":"ok","bereiche":[],"schritte":[]},{"id":"kompens","t":"Kompensator","te":"Flexible connector","grp":"Gerät","klick":"kontext","status":"ok","bereiche":[],"schritte":[]},{"id":"daemm","t":"Dämmung","te":"Insulation","grp":"Anlage","klick":"kontext","status":"ok","bereiche":[],"schritte":[]},{"id":"rohrschall","t":"Rohr- und Telefonieschalldämpfer","te":"Circular and crosstalk silencer","grp":"Rundnetz","klick":"kontext","status":"ok","bereiche":["Gehäuse","gelochtes Innenrohr","Dämmstoff"],"schritte":[]},{"id":"rk","t":"Rechteckkanal, gerade","te":"Straight rectangular duct","grp":"Rechteckig","klick":"ja","status":"ok","bereiche":["Mantel mit Versteifung","Längsfalz","Rahmenverbindung (Steckrahmen oder PDF-Flansch)","Dichtung","Biegekanten"],"schritte":[{"t":"Abwicklung mit Falzzugaben","p":["P01"],"M":["z:Zuschnittliste von Hand"],"T":["cutx","sync"],"V":[],"m":""},{"t":"Blech bereitstellen: Tafel vom Stapel oder vom Coil (Selektiereinheit, Vorschub, Richten)","p":["P52","P02","P03"],"M":["z:Tafel"],"T":["has","richt","mcl","cleco","odin","m3z"],"V":["pdfa"],"m":""},{"t":"Versteifungssicke (Z Standard; V und Trapez als Option)","p":["P04","P04b","P04c"],"M":["szp"],"T":["mcl","cleco","odin","m3z"],"V":["pdfa"],"m":""},{"t":"Kreuzbruch (bei geschweißten Kanälen)","p":["P04d"],"M":["mab"],"T":[],"V":[],"m":""},{"t":"Ausklinken, Lochen, Ausschnitte (bei PDF: Ecken für den Flansch)","p":["P05","P07L","P07"],"M":["lc","leco","pc"],"T":["mcl","odin","m3z"],"V":["pdfa"],"m":""},{"t":"Ablängen, Kurzkanäle; bei PDF Zuschnitt mit Laser oder Plasma","p":["P06","P07L","P07"],"M":["msb","lc","leco","pc"],"T":["mcl","cleco","odin","m3z"],"V":["pdfa"],"m":""},{"t":"Längsfalz profilieren","p":["P09","P61"],"M":["rfp5","rfp7","rfs9"],"T":["ds","mcl","m3z"],"V":["pdfa"],"m":""},{"t":"nur PDF: Flansch anformen","p":["P17"],"M":["pdfp"],"T":["pdfp"],"V":["pdfa"],"m":""},{"t":"Kanten zu L, U oder Box (bei PDF mit der PDF-Abkantmaschine)","p":["P11"],"M":["mab","pdfk"],"T":["mcl","cleco","odin","m3b"],"V":["pdfa"],"m":""},{"t":"Längsfalz schließen","p":["P13","P42"],"M":["trf140","trf300","z:Hammer"],"T":["ds","pfs","pfsw","m3b","trf140","trf300"],"V":["pdfa"],"m":""},{"t":"Steckrahmen: Profil zukaufen oder auf der Profilieranlage herstellen","p":["P14"],"M":["z:Profile zukaufen"],"T":["rf"],"V":[],"m":""},{"t":"Steckrahmen: Profile ablängen (Säge auch in der Profilieranlage) und mit Eckwinkeln zum Rahmen verbinden","p":["P15","P16"],"M":["saege","z:Eckwinkel von Hand einlegen, mit dem Hammer einklopfen"],"T":["rf","saege"],"V":[],"m":""},{"t":"Steckrahmen: Rahmen aufsetzen, punktschweißen oder clinchen","p":["P21","P29"],"M":["psm","trtf350"],"T":["psm","trtf350"],"V":[],"m":""},{"t":"nur PDF: Eckwinkel einlegen und einklopfen","p":["P16"],"M":[],"T":["z:Eckwinkel von Hand einlegen, mit dem Hammer einklopfen"],"V":[],"m":""},{"t":"Falzabdichtung: Dichtmasse in den Längsfalz (von Hand mit der Kartusche; automatisch im Falzprofilierer zwischen den Profilierrollen eingespritzt)","p":["P27"],"M":["z:Dichtmasse mit der Kartusche von Hand"],"T":["ds","m3z"],"V":["pdfa"],"m":""},{"t":"Ecken abdichten: Kartusche schmiert die Ecken der Rahmenverbindung ab (letzter Schritt)","p":["P51"],"M":["z:Ecken von Hand mit der Kartusche abdichten"],"T":[],"V":[],"m":""},{"t":"Innenversteifung: Rohrstützen setzen (große Kanäle)","p":["P34"],"M":["z:Rohrstütze setzen"],"T":[],"V":[],"m":"h"}]},{"id":"kurzkanal","t":"Kurzkanal bis 900 mm","te":"Short duct section up to 900 mm","grp":"Rechteckig","klick":"ja","status":"ok","bereiche":["Mantel mit Versteifung","Längsfalz","Rahmenverbindung (Steckrahmen oder PDF-Flansch)","Dichtung","Biegekanten"],"schritte":[{"t":"Abwicklung mit Falzzugaben","p":["P01"],"M":["z:Zuschnittliste von Hand"],"T":["cutx","sync"],"V":[],"m":""},{"t":"Blech bereitstellen: Tafel vom Stapel oder vom Coil (Selektiereinheit, Vorschub, Richten)","p":["P52","P02","P03"],"M":["z:Tafel"],"T":["has","richt","mcl","cleco","odin","m3z"],"V":["pdfa"],"m":""},{"t":"Versteifungssicke (Z Standard; V und Trapez als Option)","p":["P04","P04b","P04c"],"M":["szp"],"T":["mcl","cleco","odin","m3z"],"V":["pdfa"],"m":""},{"t":"Kreuzbruch (bei geschweißten Kanälen)","p":["P04d"],"M":["mab"],"T":[],"V":[],"m":""},{"t":"Ausklinken, Lochen, Ausschnitte (bei PDF: Ecken für den Flansch)","p":["P05","P07L","P07"],"M":["lc","leco","pc"],"T":["mcl","odin","m3z"],"V":["pdfa"],"m":""},{"t":"Ablängen, Kurzkanäle; bei PDF Zuschnitt mit Laser oder Plasma","p":["P06","P07L","P07"],"M":["msb","lc","leco","pc"],"T":["mcl","cleco","odin","m3z"],"V":["pdfa"],"m":""},{"t":"Längsfalz profilieren","p":["P09","P61"],"M":["rfp5","rfp7","rfs9"],"T":["ds","mcl","m3z"],"V":["pdfa"],"m":""},{"t":"nur PDF: Flansch anformen","p":["P17"],"M":["pdfp"],"T":["pdfp"],"V":["pdfa"],"m":""},{"t":"Kanten zu L, U oder Box (bei PDF mit der PDF-Abkantmaschine)","p":["P11"],"M":["mab","pdfk"],"T":["mcl","cleco","odin","m3b"],"V":["pdfa"],"m":""},{"t":"Längsfalz schließen","p":["P13","P42"],"M":["trf140","trf300","z:Hammer"],"T":["ds","pfs","pfsw","m3b","trf140","trf300"],"V":["pdfa"],"m":""},{"t":"Steckrahmen: Profil zukaufen oder auf der Profilieranlage herstellen","p":["P14"],"M":["z:Profile zukaufen"],"T":["rf"],"V":[],"m":""},{"t":"Steckrahmen: Profile ablängen (Säge auch in der Profilieranlage) und mit Eckwinkeln zum Rahmen verbinden","p":["P15","P16"],"M":["saege","z:Eckwinkel von Hand einlegen, mit dem Hammer einklopfen"],"T":["rf","saege"],"V":[],"m":""},{"t":"Steckrahmen: Rahmen aufsetzen, punktschweißen oder clinchen","p":["P21","P29"],"M":["psm","trtf350"],"T":["psm","trtf350"],"V":[],"m":""},{"t":"nur PDF: Eckwinkel einlegen und einklopfen","p":["P16"],"M":[],"T":["z:Eckwinkel von Hand einlegen, mit dem Hammer einklopfen"],"V":[],"m":""},{"t":"Falzabdichtung: Dichtmasse in den Längsfalz (von Hand mit der Kartusche; automatisch im Falzprofilierer zwischen den Profilierrollen eingespritzt)","p":["P27"],"M":["z:Dichtmasse mit der Kartusche von Hand"],"T":["ds","m3z"],"V":["pdfa"],"m":""},{"t":"Ecken abdichten: Kartusche schmiert die Ecken der Rahmenverbindung ab (letzter Schritt)","p":["P51"],"M":["z:Ecken von Hand mit der Kartusche abdichten"],"T":[],"V":[],"m":""},{"t":"Innenversteifung: Rohrstützen setzen (große Kanäle)","p":["P34"],"M":["z:Rohrstütze setzen"],"T":[],"V":[],"m":"h"}]},{"id":"passlaenge","t":"Kanal auf Passlänge","te":"Duct with make-up length","grp":"Rechteckig","klick":"ja","status":"herleitung","bereiche":["Mantel mit Versteifung","Längsfalz","Rahmenverbindung","loser Rahmen","Dichtung","Biegekanten"],"schritte":[{"t":"Abwicklung mit Falzzugaben","p":["P01"],"M":["z:Zuschnittliste von Hand"],"T":["cutx","sync"],"V":[],"m":""},{"t":"Blech bereitstellen: Tafel vom Stapel oder vom Coil (Selektiereinheit, Vorschub, Richten)","p":["P52","P02","P03"],"M":["z:Tafel"],"T":["has","richt","mcl","cleco","odin","m3z"],"V":[],"m":""},{"t":"Versteifungssicke (Z Standard; V und Trapez als Option)","p":["P04","P04b","P04c"],"M":["szp"],"T":["mcl","cleco","odin","m3z"],"V":[],"m":""},{"t":"Kreuzbruch (bei geschweißten Kanälen)","p":["P04d"],"M":["mab"],"T":[],"V":[],"m":""},{"t":"Ausklinken, Lochen, Ausschnitte (bei PDF: Ecken für den Flansch)","p":["P05","P07L","P07"],"M":["lc","leco","pc"],"T":["mcl","odin","m3z"],"V":[],"m":""},{"t":"Ablängen (Länge mit Zugabe für das Kürzen auf der Baustelle); bei PDF Zuschnitt mit Laser oder Plasma","p":["P06","P07L","P07"],"M":["msb","lc","leco","pc"],"T":["mcl","cleco","odin","m3z"],"V":[],"m":"h"},{"t":"Längsfalz profilieren","p":["P09","P61"],"M":["rfp5","rfp7","rfs9"],"T":["ds","mcl","m3z"],"V":[],"m":""},{"t":"nur PDF: Flansch an einem Ende anformen","p":["P17"],"M":["pdfp"],"T":["pdfp"],"V":[],"m":""},{"t":"Kanten zu L, U oder Box (bei PDF mit der PDF-Abkantmaschine)","p":["P11"],"M":["mab","pdfk"],"T":["mcl","cleco","odin","m3b"],"V":[],"m":""},{"t":"Längsfalz schließen","p":["P13","P42"],"M":["trf140","trf300","z:Hammer"],"T":["ds","pfs","pfsw","m3b","trf140","trf300"],"V":[],"m":""},{"t":"Steckrahmen: Profil zukaufen oder auf der Profilieranlage herstellen","p":["P14"],"M":["z:Profile zukaufen"],"T":["rf"],"V":[],"m":""},{"t":"Steckrahmen: Profile ablängen (Säge auch in der Profilieranlage) und mit Eckwinkeln zum Rahmen verbinden","p":["P15","P16"],"M":["saege","z:Eckwinkel von Hand einlegen, mit dem Hammer einklopfen"],"T":["rf","saege"],"V":[],"m":""},{"t":"Einen Rahmen aufsetzen, punktschweißen oder clinchen; den zweiten lose beilegen, ohne Dichtmittel","p":["P21","P29"],"M":["psm","trtf350"],"T":["psm","trtf350"],"V":[],"m":""},{"t":"nur PDF: Eckwinkel am angeformten Flansch einlegen; für das andere Ende einen losen Steckrahmen beilegen","p":["P16"],"M":[],"T":["z:Eckwinkel von Hand einlegen, mit dem Hammer einklopfen"],"V":[],"m":""},{"t":"Falzabdichtung: Dichtmasse in den Längsfalz (von Hand mit der Kartusche; automatisch im Falzprofilierer zwischen den Profilierrollen eingespritzt)","p":["P27"],"M":["z:Dichtmasse mit der Kartusche von Hand"],"T":["ds","m3z"],"V":[],"m":""},{"t":"Ecken am festen Rahmen abdichten: Kartusche schmiert die Ecken ab","p":["P51"],"M":["z:Ecken von Hand mit der Kartusche abdichten"],"T":[],"V":[],"m":""},{"t":"Innenversteifung: Rohrstützen setzen (große Kanäle)","p":["P34"],"M":["z:Rohrstütze setzen"],"T":[],"V":[],"m":"h"},{"t":"Auf der Baustelle: auf Maß kürzen, losen Rahmen bis zum Anschlag aufschieben, dicht nieten, innen abdichten","p":["P16","P27"],"M":["z:Montagebetrieb auf der Baustelle"],"T":[],"V":[],"m":""}]},{"id":"rbogen","t":"Rechteckbogen und Etage mit Radien","te":"Rectangular elbow and radius offset","grp":"Rechteckig","klick":"ja","status":"ok","bereiche":["Seitenblech (2x)","Mantelblech innen und außen","Längsfalz","Rahmenverbindung","Leitblech"],"schritte":[{"t":"Abwicklung mit Zugaben","p":["P01"],"M":["z:Anreißen"],"T":["cutx"],"V":[],"m":""},{"t":"Zuschnitt; große Mantelbleche mit Versteifungssicke","p":["P06","P07L","P07","P04"],"M":["msb","trs160","trs250","szp","trc160","trc250"],"T":["lc","leco","pc"],"V":[],"m":""},{"t":"Tasche am noch geraden Mantel","p":["P09","P61"],"M":["rfp5","rfp7","rfs9"],"T":["rfp5","rfp7","rfs9"],"V":[],"m":""},{"t":"Bord am Seitenblech","p":["P10"],"M":["fpfs","mab"],"T":["fpfs","mab"],"V":[],"m":""},{"t":"Mantel runden (Einlegebleche, Falz wird etwas gepresst)","p":["P12"],"M":["rme"],"T":["rme"],"V":[],"m":""},{"t":"Zusammenstecken, Falz schließen","p":["P13","P42"],"M":["trf140","trf300","z:Hammer"],"T":["trf140","trf300"],"V":[],"m":""},{"t":"Leitbleche einsetzen (Bogen über 45°)","p":["P64","P28"],"M":["z:Leitblechdübel einschlagen"],"T":["llb"],"V":[],"m":""},{"t":"Rahmen: Steckrahmen aufsetzen oder PDF-Flansch anprofilieren","p":["P14","P15","P16","P17"],"M":["saege","psm","trtf350","pdfp"],"T":["rf","saege","psm","trtf350","pdfp"],"V":[],"m":""},{"t":"Abdichten","p":["P27"],"M":["z:Dichtstoff in Ecken und Stöße"],"T":[],"V":[],"m":""}]},{"id":"rwinkel","t":"Rechteckwinkel und T-Stück","te":"Rectangular mitre and tee","grp":"Rechteckig","klick":"ja","status":"ok","bereiche":["Seitenblech (2x)","Mantel (gekantet)","Längsfalz","Rahmenverbindung","Leitbleche"],"schritte":[{"t":"Abwicklung, Zuschnitt; große Mantelbleche mit Versteifungssicke","p":["P01","P06","P07L","P07","P04"],"M":["msb","trs160","trs250","szp","trc160","trc250"],"T":["cutx","lc","leco","pc"],"V":[],"m":""},{"t":"Mantel kanten (Winkel in der Mitte, T-Stück an den Innenecken), Bord an geraden Kanten","p":["P10","P11"],"M":["mab"],"T":["mab"],"V":[],"m":""},{"t":"Falz profilieren und schließen","p":["P09","P61","P13","P42"],"M":["rfp5","rfp7","rfs9","trf140","trf300","z:Hammer"],"T":["rfp5","rfp7","rfs9","trf140","trf300"],"V":[],"m":""},{"t":"Leitbleche (Winkel über 45°, T-Stück nach Bedarf)","p":["P64","P28"],"M":["z:Leitblechdübel"],"T":["llb"],"V":[],"m":""},{"t":"Rahmen: Steckrahmen aufsetzen oder PDF-Flansch anprofilieren","p":["P14","P15","P16","P17"],"M":["saege","psm","trtf350","pdfp"],"T":["rf","saege","psm","trtf350","pdfp"],"V":[],"m":""}]},{"id":"retage","t":"Etagenstück und Übergang eckig","te":"Rectangular offset and transition","grp":"Rechteckig","klick":"ja","status":"herleitung","bereiche":["Seitenbleche","Mantelbleche","Längsfalz (Pittsburgh)","Rahmenverbindung"],"schritte":[{"t":"Abwicklung mit Zugaben (Z-Kontur oder Trapezbleche, wahre Längen)","p":["P01"],"M":["z:Anreißen"],"T":["cutx"],"V":[],"m":"h"},{"t":"Zuschnitt, Ausklinkung an den Knickstellen; große Mantelbleche mit Versteifungssicke","p":["P06","P07L","P07","P04"],"M":["msb","trs160","trs250","szp","trc160","trc250"],"T":["lc","leco","pc"],"V":[],"m":"h"},{"t":"Tasche am Mantelblech","p":["P09","P61"],"M":["rfp5","rfp7","rfs9"],"T":["rfp5","rfp7","rfs9"],"V":[],"m":"h"},{"t":"Bord am Seitenblech (Innenecken an der Bördelmaschine)","p":["P10"],"M":["fpfs","mab"],"T":["fpfs","mab"],"V":[],"m":"h"},{"t":"Kanten: Knicke zwischen Ansatz und Schräge","p":["P11"],"M":["mab"],"T":["mab"],"V":[],"m":"h"},{"t":"Zusammenstecken, 4 Längsfalze schließen","p":["P13","P42"],"M":["trf140","trf300","z:Hammer"],"T":["trf140","trf300"],"V":[],"m":"h"},{"t":"Rahmen an beiden Enden: Steckrahmen aufsetzen oder PDF-Flansch anprofilieren","p":["P14","P15","P16","P17"],"M":["saege","psm","trtf350","pdfp"],"T":["rf","saege","psm","trtf350","pdfp"],"V":[],"m":"h"},{"t":"Abdichten","p":["P27"],"M":["z:Dichtstoff in Ecken und Stöße"],"T":[],"V":[],"m":"h"}]},{"id":"ruebergang","t":"Rohrübergang eckig–rund","te":"Square-to-round transition","grp":"Übergang","klick":"ja","status":"ok","bereiche":["Mantel aus Dreiecken und Eckflächen","Längsnaht (gefalzt)","Rahmen","Steckende (eigener Ring)"],"schritte":[{"t":"Abwicklung, Zuschnitt (Teilung größenabhängig)","p":["P01","P07L","P07"],"M":["msb","trs160","trs250","trc160","trc250"],"T":["cutx","lc","leco","pc"],"V":[],"m":""},{"t":"Eckflächen kanten: viele fächerförmige Kantungen","p":["P31"],"M":["mab"],"T":["mab"],"V":[],"m":""},{"t":"Längsnaht: Hakenfalz profilieren und zudrücken oder punktschweißen","p":["P62","P30","P21"],"M":["hfp","hfz","psm"],"T":["psm"],"V":[],"m":""},{"t":"Steckende als eigener Ring: runden, anfügen (punkten)","p":["P12","P21"],"M":["rme","psm"],"T":["psm","rme"],"V":[],"m":"h"},{"t":"Rahmen auf der Rechteckseite: Steckrahmen aufsetzen oder PDF-Flansch anprofilieren","p":["P14","P16","P17"],"M":["saege","psm","trtf350","pdfp"],"T":["rf","saege","psm","trtf350","pdfp"],"V":[],"m":""}]},{"id":"hose","t":"Rohrgabelung","te":"Duct fork (Y-branch with bends)","grp":"Rechteckig","klick":"ja","status":"herleitung","bereiche":["Seitenbleche","Mäntel","Längsfalz","Spitze","Rahmen (3)"],"schritte":[{"t":"Abwicklung mit Zugaben (Seitenbleche in Gabelform, Mäntel je Abgang)","p":["P01"],"M":["z:Anreißen"],"T":["cutx"],"V":[],"m":"h"},{"t":"Zuschnitt; große Mantelbleche mit Versteifungssicke","p":["P06","P07L","P07","P04"],"M":["msb","trs160","trs250","szp","trc160","trc250"],"T":["lc","leco","pc"],"V":[],"m":"h"},{"t":"Tasche an den noch geraden Mänteln","p":["P09","P61"],"M":["rfp5","rfp7","rfs9"],"T":["rfp5","rfp7","rfs9"],"V":[],"m":"h"},{"t":"Bord an den Seitenblechen","p":["P10"],"M":["fpfs","mab"],"T":["fpfs","mab"],"V":[],"m":"h"},{"t":"Mäntel runden (innen und außen je Abgang)","p":["P12"],"M":["rme"],"T":["rme"],"V":[],"m":"h"},{"t":"Spitze: die inneren Mäntel der Abgänge verbinden","p":["P13","P42"],"M":["trf140","trf300","z:Hammer"],"T":["trf140","trf300"],"V":[],"m":"h"},{"t":"Zusammenstecken, Längsfalze schließen","p":["P13","P42"],"M":["trf140","trf300","z:Hammer"],"T":["trf140","trf300"],"V":[],"m":"h"},{"t":"Rahmen an allen drei Enden: Steckrahmen aufsetzen oder PDF-Flansch anprofilieren","p":["P14","P15","P16","P17"],"M":["saege","psm","trtf350","pdfp"],"T":["rf","saege","psm","trtf350","pdfp"],"V":[],"m":"h"},{"t":"Abdichten","p":["P27"],"M":["z:Dichtstoff in Ecken und Stöße"],"T":[],"V":[],"m":""}]},{"id":"hosenstueck","t":"Hosenstück","te":"Trouser piece","grp":"Rechteckig","klick":"ja","status":"ok","bereiche":["Seitenbleche","Mantelbleche","Längsfalz (Pittsburgh)","Rahmen (3)"],"schritte":[{"t":"Abwicklung mit Zugaben (Seitenbleche in Hosenform, Mantelbleche je Abgang)","p":["P01"],"M":["z:Anreißen"],"T":["cutx"],"V":[],"m":""},{"t":"Zuschnitt, Ausklinkung an den Knickstellen; große Mantelbleche mit Versteifungssicke","p":["P06","P07L","P07","P04"],"M":["msb","trs160","trs250","szp","trc160","trc250"],"T":["lc","leco","pc"],"V":[],"m":""},{"t":"Tasche an den Mantelblechen","p":["P09","P61"],"M":["rfp5","rfp7","rfs9"],"T":["rfp5","rfp7","rfs9"],"V":[],"m":""},{"t":"Bord an den Seitenblechen","p":["P10"],"M":["fpfs","mab"],"T":["fpfs","mab"],"V":[],"m":""},{"t":"Mantelbleche kanten (Knicke zwischen Ansatz und Schräge)","p":["P11"],"M":["mab"],"T":["mab"],"V":[],"m":""},{"t":"Zusammenstecken, Längsfalze schließen","p":["P13","P42"],"M":["trf140","trf300","z:Hammer"],"T":["trf140","trf300"],"V":[],"m":""},{"t":"Rahmen an allen drei Enden: Steckrahmen aufsetzen oder PDF-Flansch anprofilieren","p":["P14","P15","P16","P17"],"M":["saege","psm","trtf350","pdfp"],"T":["rf","saege","psm","trtf350","pdfp"],"V":[],"m":""},{"t":"Abdichten","p":["P27"],"M":["z:Dichtstoff in Ecken und Stöße"],"T":[],"V":[],"m":""}]},{"id":"rboden","t":"Endkappe eckig (Boden)","te":"Rectangular end cap","grp":"Rechteckig","klick":"ja","status":"ok","bereiche":["Platte mit Bord","Befestigung"],"schritte":[{"t":"Zuschnitt der Platte","p":["P06","P07L","P07"],"M":["msb","trs160","trs250","trc160","trc250"],"T":["lc","leco","pc"],"V":[],"m":""},{"t":"Bord kanten","p":["P10","P11"],"M":["mab"],"T":["mab"],"V":[],"m":""},{"t":"Einsteck-Deckel einsetzen, nieten oder punkten","p":["P21"],"M":["z:von Hand","psm"],"T":["psm"],"V":[],"m":"h"}]},{"id":"rstutzen","t":"Stutzen auf Rechteckkanal","te":"Branch collar on rectangular duct","grp":"Rechteckig","klick":"ja","status":"ok","bereiche":["Ausschnitt","Stutzen mit Laschen und Sicke","Befestigungspunkte"],"schritte":[{"t":"Ausschnitt in den Kanal","p":["P07L","P07","P41"],"M":["trc160","trc250","trs160","trs250"],"T":["lc","leco","pc"],"V":[],"m":"h"},{"t":"Stutzen einsetzen","p":["P32"],"M":["z:von Hand"],"T":[],"V":[],"m":""},{"t":"Stutzen punkten oder clinchen","p":["P21","P29"],"M":["trtf350"],"T":["psm"],"V":[],"m":""},{"t":"Abdichten","p":["P27"],"M":["z:Dichtstoff"],"T":[],"V":[],"m":""}]},{"id":"kd","t":"Kanal mit Drosselklappe","te":"Duct with regulating damper","grp":"Verteilung","klick":"kontext","status":"ok","bereiche":["Kanal","Drosselklappe"],"schritte":[]},{"id":"anschlusskasten","t":"Anschlusskasten (Plenum)","te":"Plenum box","grp":"Raum","klick":"bald","status":"herleitung","bereiche":["Gehäuse","Stutzen","Anschlussflansch"],"schritte":[{"t":"Abwicklung, Zuschnitt","p":["P01","P06","P07L","P07"],"M":["msb"],"T":["cutx","lc","leco","pc"],"V":[],"m":""},{"t":"Kanten, Falz schließen","p":["P11","P13","P42"],"M":["mab","trf140","trf300","z:Hammer"],"T":["mab","trf140","trf300"],"V":[],"m":""},{"t":"Stutzen einsetzen, punkten","p":["P32","P21"],"M":["psm"],"T":["psm"],"V":[],"m":""}]},{"id":"revision","t":"Revisions- und Reinigungsöffnung","te":"Access door","grp":"Anlage","klick":"bald","status":"herleitung","bereiche":["Ausschnitt","Rahmen","Deckel"],"schritte":[{"t":"Ausschnitt","p":["P07L","P07","P41"],"M":["trc160","trc250","trs160","trs250"],"T":["lc","leco","pc","odin"],"V":[],"m":"h"},{"t":"Rahmen und Deckel fertigen","p":["P11"],"M":["mab"],"T":["mab"],"V":[],"m":"h"},{"t":"Dichtung, Verschluss","p":["P27"],"M":["z:von Hand"],"T":[],"V":[],"m":"h"}]},{"id":"dachhaube","t":"Dachhaube","te":"Roof cowl","grp":"Dach","klick":"bald","status":"herleitung","bereiche":["Haube","Sockel","Gitter"],"schritte":[{"t":"Abwicklung, Zuschnitt","p":["P01","P06","P07L","P07"],"M":["msb"],"T":["cutx","lc","leco","pc"],"V":[],"m":""},{"t":"Kanten, Runden, Fügen","p":["P11","P12"],"M":["mab","rme"],"T":["mab","rme"],"V":[],"m":"h"}]},{"id":"wfr","t":"Wickelfalzrohr","te":"Spiral duct","grp":"Rund","klick":"ja","status":"ok","bereiche":["Mantel mit Versteifungssicke","Wickelfalz","Rohrende (Muffenseite)"],"schritte":[{"t":"Coil auf die Haspel, Band einziehen","p":["P02"],"M":[],"T":[],"V":["tf14","tf16"],"m":""},{"t":"Bandkanten profilieren, wickeln, Falz schließen, bis zu zwei Sicken","p":["P18"],"M":[],"T":[],"V":["tf14","tf16"],"m":""},{"t":"Fliegend trennen, Rohr abwerfen","p":["P19"],"M":[],"T":[],"V":["tf14","tf16"],"m":""}]},{"id":"lnr","t":"Rundrohr mit Längsnaht","te":"Longitudinal seam pipe","grp":"Rund","klick":"ja","status":"ok","bereiche":["Mantel","Längsnaht","Rohrenden (Sicke und Lippe oder Bördel)"],"schritte":[{"t":"Zuschnitt","p":["P06","P07"],"M":["zus","msb"],"T":["pr"],"V":["swa"],"m":""},{"t":"nur bei Falz: Hakenfalz anformen","p":["P62"],"M":["hfp"],"T":[],"V":[],"m":"h"},{"t":"Runden","p":["P12"],"M":["rme","hyl"],"T":["pr"],"V":["swa"],"m":""},{"t":"Längsnaht gefalzt (Hakenfalz zudrücken) oder geschweißt: punktschweißen oder rollnahtschweißen (Drahtelektrode)","p":["P30","P21","P20"],"M":["hfz","psm"],"T":["sw","hfz"],"V":["swa"],"m":""},{"t":"Rohrenden: Sicke, Lippendichtung oder Bördelrand","p":["P25","P33"],"M":["sick"],"T":["gs","gsa"],"V":["gsa"],"m":""}]},{"id":"segbogen","t":"Segmentbogen","te":"Segmented elbow","grp":"Rund","klick":"ja","status":"ok","bereiche":["Segmente","Längsnaht je Segment","Stehfalz zwischen den Segmenten","Anschlussenden"],"schritte":[{"t":"Segmente flach zuschneiden (abgewickelte Form, Kanten gerade oder wellig)","p":["P54","P07","P53"],"M":["trs160","trs250","trc160","trc250"],"T":["lc","leco","pc","cutx"],"V":[],"m":""},{"t":"Segmente runden","p":["P12","P55"],"M":["rme"],"T":["roll"],"V":[],"m":""},{"t":"Längsnaht je Segment: punktschweißen oder rollnahtschweißen (Drahtelektrode)","p":["P21","P20"],"M":["psm"],"T":["sw"],"V":[],"m":""},{"t":"Anschlussenden vor dem Fügen: Stoppsicke und Gummidichtlippe","p":["P25","P26"],"M":["sick"],"T":["gs","gsa","sick"],"V":["gs","gsa"],"m":""},{"t":"Umfangsnaht der Segmente: Stehfalz und Doppelstehfalz bördeln, ineinanderlegen und verpressen","p":["P22","P23","P50","P24"],"M":["sick"],"T":["cem","cemeco"],"V":["bogen"],"m":""}]},{"id":"tstueck","t":"Sattelstutzen (rund)","te":"Round saddle branch","grp":"Rund","klick":"ja","status":"ok","bereiche":["Grundrohr (nur Träger)","Abzweig (Sattel)","Sattelrand mit Fügepunkten","Enden","Längsnaht"],"schritte":[{"t":"Grundrohr (nur Träger, nicht Teil des Formstücks)","p":[],"M":[],"T":[],"V":[],"m":""},{"t":"Öffnung ins Grundrohr schneiden","p":["P08","P41"],"M":["trc160","trc250","trs160","trs250"],"T":["lc","leco","prot"],"V":[],"m":"h"},{"t":"Abzweig mit Sattelkontur abwickeln und schneiden","p":["P01","P40","P07L","P07"],"M":["trs160","trs250","trc160","trc250"],"T":["cutx","lc","leco","pc"],"V":[],"m":""},{"t":"Abzweig runden","p":["P12","P55"],"M":["rme"],"T":["roll"],"V":[],"m":""},{"t":"Längsnaht am Abzweig punktschweißen oder rollnahtschweißen (Drahtelektrode)","p":["P21","P20"],"M":["psm"],"T":["sw"],"V":[],"m":""},{"t":"Sattel mit dem Grundrohr fügen: mit der Sickenmaschine formen, punktschweißen","p":["P25","P21"],"M":["sick","psm"],"T":["sick","psm"],"V":[],"m":""},{"t":"Abdichten","p":["P27"],"M":["z:Dichtstoff"],"T":[],"V":[],"m":""},{"t":"Enden: Sicke, Lippendichtung","p":["P25","P26"],"M":["sick"],"T":["gs","gsa","sick"],"V":[],"m":""}]},{"id":"tstueck90","t":"T-Stück, Abzweig 45° und Kreuzstück (rund)","te":"Round tee, 45° branch and cross","grp":"Rund","klick":"ja","status":"ok","bereiche":["Grundkörper","Abzweig","Fügenaht","Steckenden","Längsnähte"],"schritte":[{"t":"Grundkörper zuschneiden","p":["P06","P07L","P07"],"M":["trs160","trs250","trc160","trc250"],"T":["lc","leco","pc"],"V":[],"m":""},{"t":"Grundkörper aus dem Zuschnitt runden","p":["P12","P55"],"M":["rme"],"T":["roll"],"V":[],"m":"h"},{"t":"Längsnaht am Grundkörper punktschweißen oder rollnahtschweißen (Drahtelektrode)","p":["P21","P20"],"M":["psm"],"T":["sw"],"V":[],"m":"h"},{"t":"Öffnung in den Grundkörper schneiden","p":["P08","P41"],"M":["trc160","trc250","trs160","trs250"],"T":["lc","leco","prot"],"V":[],"m":""},{"t":"Abzweig mit Sattelkontur abwickeln und schneiden","p":["P01","P40","P07L","P07"],"M":["trs160","trs250","trc160","trc250"],"T":["cutx","lc","leco","pc"],"V":[],"m":""},{"t":"Abzweig runden","p":["P12","P55"],"M":["rme"],"T":["roll"],"V":[],"m":""},{"t":"Längsnaht am Abzweig punktschweißen oder rollnahtschweißen (Drahtelektrode)","p":["P21","P20"],"M":["psm"],"T":["sw"],"V":[],"m":""},{"t":"Abzweig mit dem Grundkörper fügen: mit der Sickenmaschine formen, punktschweißen","p":["P25","P21"],"M":["sick","psm"],"T":["sick","psm"],"V":[],"m":""},{"t":"Abdichten","p":["P27"],"M":["z:Dichtstoff"],"T":[],"V":[],"m":""},{"t":"Steckenden: Sicke, Lippendichtung","p":["P25","P26"],"M":["sick"],"T":["gs","gsa","sick"],"V":[],"m":""}]},{"id":"reduz","t":"Reduzierung","te":"Reducer","grp":"Rund","klick":"ja","status":"ok","bereiche":["Konus","Anschlussstücke","Umfangsnähte","Enden","Längsnähte"],"schritte":[{"t":"Abwicklung des Kegelmantels","p":["P01"],"M":[],"T":["cutx"],"V":[],"m":""},{"t":"Zuschnitt","p":["P06","P40","P07L","P07"],"M":["trs160","trs250","trc160","trc250"],"T":["lc","leco","pc"],"V":[],"m":""},{"t":"Konus und Anschlussstücke runden (Seitenanschlag)","p":["P12","P55"],"M":["rme"],"T":["roll"],"V":[],"m":""},{"t":"Längsnaht punktschweißen oder rollnahtschweißen (Drahtelektrode)","p":["P21","P20"],"M":["psm"],"T":["sw"],"V":[],"m":""},{"t":"Umfangsnähte: mit der Sickenmaschine formen, punktschweißen","p":["P25","P21"],"M":["sick","psm"],"T":["sick","psm"],"V":[],"m":""},{"t":"Enden","p":["P25","P26"],"M":["sick"],"T":["gs","gsa","sick"],"V":[],"m":""}]},{"id":"enddeckel","t":"Enddeckel (rund)","te":"Round end cap","grp":"Rund","klick":"ja","status":"herleitung","bereiche":["Ronde","Ring","Bördelrand","Sicke und Dichtung","Längsnaht am Ring"],"schritte":[{"t":"Ronde schneiden","p":["P40","P07L","P07"],"M":["trs160","trs250","trc160","trc250"],"T":["lc","leco","pc"],"V":[],"m":""},{"t":"Ring zuschneiden","p":["P06","P07L","P07"],"M":["trs160","trs250","trc160","trc250"],"T":["lc","leco","pc"],"V":[],"m":"h"},{"t":"Ring runden","p":["P12","P55"],"M":["rme"],"T":["roll"],"V":[],"m":"h"},{"t":"Längsnaht am Ring: punktschweißen oder rollnahtschweißen (Drahtelektrode)","p":["P21","P20"],"M":["psm"],"T":["sw"],"V":[],"m":"h"},{"t":"Ronde und Ring fügen: Rand mit der Sickenmaschine formen, punktschweißen","p":["P25","P21"],"M":["sick","psm"],"T":["sick","psm"],"V":[],"m":""},{"t":"Sicke und Dichtung","p":["P25","P26"],"M":["sick"],"T":["gs","gsa","sick"],"V":[],"m":"h"}]},{"id":"nippel","t":"Nippel und Muffe","te":"Nipple and coupling","grp":"Rund","klick":"ja","status":"herleitung","bereiche":["Rohrstück","Längsnaht","Sicke","Dichtung"],"schritte":[{"t":"Rohrstück zuschneiden","p":["P06","P07L","P07"],"M":["trs160","trs250","trc160","trc250"],"T":["lc","leco","pc"],"V":[],"m":"h"},{"t":"Rohrstück runden","p":["P12","P55"],"M":["rme"],"T":["roll"],"V":[],"m":"h"},{"t":"Längsnaht punktschweißen oder rollnahtschweißen (Drahtelektrode)","p":["P21","P20"],"M":["psm"],"T":["sw"],"V":[],"m":"h"},{"t":"Sicke rollen (Nippel: Mittelsicke als Anschlag)","p":["P25"],"M":["sick"],"T":["gs","gsa","sick"],"V":[],"m":"h"},{"t":"Dichtung an den Enden","p":["P26"],"M":["z:Dichtung von Hand"],"T":["gs","gsa"],"V":[],"m":""}]},{"id":"lippe","t":"Steckverbindung mit Lippendichtung","te":"Spigot joint with lip seal","grp":"Rund","klick":"ja","status":"ok","bereiche":["Rohrende mit Bord","Stoppsicke","Dichtungssitz","Lippendichtung (EPDM)","Rohrstück","Längsnaht"],"schritte":[{"t":"Rohrstück zuschneiden","p":["P06","P07L","P07"],"M":["trs160","trs250","trc160","trc250"],"T":["lc","leco","pc"],"V":[],"m":""},{"t":"Rohrstück runden","p":["P12","P55"],"M":["rme"],"T":["roll"],"V":[],"m":""},{"t":"Längsnaht punktschweißen oder rollnahtschweißen (Drahtelektrode)","p":["P21","P20"],"M":["psm"],"T":["sw"],"V":[],"m":""},{"t":"Stoppsicke und Dichtungssitz rollen: am Universal nacheinander, am Automaten in einem Schritt mit einem Werkzeug","p":["P25"],"M":["sick"],"T":["gs","gsa","sick"],"V":[],"m":""},{"t":"Rohrkante 90° umbördeln","p":["P26"],"M":[],"T":["gs","gsa"],"V":[],"m":"h"},{"t":"Dichtung auflegen: am Universal von Hand, am Automaten vorher auf den Rohrmantel gesetzt und von einer Vorrichtung zum Rohrende geschoben","p":["P26"],"M":["z:Dichtung von Hand"],"T":["z:Dichtung von Hand auflegen","gsa"],"V":[],"m":""},{"t":"Bord um die Dichtung legen und zudrücken","p":["P26"],"M":[],"T":["gs","gsa"],"V":[],"m":"h"}]},{"id":"pbogen","t":"Gepresste Formteile","te":"Pressed fittings","grp":"Rund","klick":"ja","status":"herleitung","bereiche":["Pressteile (Halbschalen)","Naht der Halbschalen","Steckenden"],"schritte":[{"t":"Halbschalen in einer Presse mit Matrize und Stempel formen (Werkzeug je Bogengröße)","p":["P56"],"M":[],"T":["presse"],"V":[],"m":""},{"t":"Halbschalen fügen: Rollennahtschweißen mit Drahtelektrode, eine Elektrodenrolle außen über dem Falz, eine innen im Bogen","p":["P57"],"M":[],"T":["varb"],"V":[],"m":""},{"t":"Steckenden: Sicke und Lippendichtung mit dem Gasket Shaper Automatic","p":["P25","P26"],"M":[],"T":["gsa"],"V":[],"m":""}]},{"id":"flex","t":"Flexible Lüftungsrohre","te":"Flexible ventilation pipes","grp":"Rund","klick":"ja","status":"ok","bereiche":["Wickelrohr","Muffe"],"schritte":[{"t":"Rohr wickeln","p":[],"M":[],"T":[],"V":["spf250","spf450","sr300","sr450"],"m":""}]},{"id":"kulisse","t":"Kulissenschalldämpfer","te":"Splitter silencer","grp":"Schalldämpfer","klick":"ja","status":"herleitung","bereiche":["Gehäuse (Rechteckkanal)","Schalldämpferkulissen"],"schritte":[{"t":"Gehäuse wie einen Rechteckkanal fertigen","p":[],"M":["k:rk"],"T":["k:rk"],"V":["k:rk"],"m":""},{"t":"Schalldämpferkulissen fertigen und montieren","p":["B:skulisse","P60"],"M":["k:skulisse"],"T":["k:skulisse"],"V":["k:skulisse"],"m":""},{"t":"Kulissen ins Gehäuse einsetzen und befestigen","p":["B:skulisse"],"M":[],"T":[],"V":[],"m":""}]},{"id":"skulisse","t":"Schalldämpferkulisse","te":"Splitter (baffle)","grp":"Schalldämpfer","klick":"ja","status":"ok","bereiche":["Kulissenrahmen","An- und Abströmprofil","T-Bügelprofil","Mineralwolle","Glasseide","Abdeckung (Kammerblech oder Lochblech)","Rundung oder Kante des Rahmenprofils"],"schritte":[{"t":"Rahmenbleche zuschneiden","p":["P06","P07L","P07"],"M":["msb"],"T":["cutx","lc","leco","pc"],"V":["pod"],"m":""},{"t":"Ausklinken; vollautomatisch alternativ an den Biegelinien perforieren","p":["P05","P41"],"M":["trc160","trc250","trs160","trs250"],"T":["lc","leco","pc"],"V":["pod"],"m":""},{"t":"Längssicken","p":["P04"],"M":[],"T":[],"V":["pod"],"m":""},{"t":"Kulissenrahmen mit An- und Abströmprofil formen: von Hand an den Langseiten 90° gekantet (ohne Radius), automatisiert profiliert (Radius beidseitig umlaufend), vollautomatisch in einer Maschine","p":["P11","P58","P35"],"M":["mab"],"T":["podr"],"V":["pod"],"m":""},{"t":"Rahmen auf Länge schneiden und an den Ecken kanten: vier Einzelteile, 2 × L (üblich), U und Deckel oder einteilig; vollautomatisch alternativ perforiert und von Hand geklappt","p":["P06","P11"],"M":["msb","mab"],"T":["mab"],"V":["pod"],"m":""},{"t":"T-Bügelprofil (Mittelsteg) kanten oder profilieren und einsetzen","p":["P11","P59"],"M":["mab"],"T":["mab","tbp"],"V":[],"m":""},{"t":"Mineralwolle mit Glasseide zuschneiden","p":[],"M":[],"T":[],"V":[],"m":""},{"t":"Abdeckung zuschneiden: Kammerblech oder Lochblech","p":["P06","P07L","P07"],"M":["msb"],"T":["lc","leco","pc"],"V":[],"m":""},{"t":"Kulisse montieren: Kammerbleche und T-Bügelprofil in eine Rahmenhälfte einsetzen, Dämmung einlegen, zweite Rahmenhälfte aufschieben; T-Bügelprofil mittig an den Rahmen nieten, Rahmenteile an den Laschen und jede Ecke nieten","p":["P60"],"M":["z:Montage und Nieten von Hand"],"T":["z:Montage und Nieten von Hand"],"V":["z:Montage und Nieten von Hand"],"m":""}]}],"stufen":{"M":"manuell","T":"automatisiert","V":"vollautomatisiert"},"zusatz":{"pdfk":{"mb":"PDF-Abkantmaschine","ty":"[Name folgt]","b":"WAMMES","i":"/media/54749a7c-4d68-42f9-90d5-9da9de2fa6c7/pdf-abkantmaschine.jpg"},"hfp":{"mb":"Hakenfalz-Profilierer","ty":"[Name folgt]","b":"WAMMES","i":"/media/dc5e28ae-2c8b-4f9a-9c3e-0a4945945d2c/rfs-9_2.jpg"},"tbp":{"mb":"T-Bügel-Profilierer","ty":"[Name folgt]","b":"WAMMES","i":"/media/27c9d0c0-32c6-4123-b277-c268c55825bb/img_62901-jpg.jpg"},"hfz":{"mb":"Falzschließer für Hakenfalz","ty":"[Name folgt]","b":"WAMMES"},"gsa":{"mb":"Gasket Shaper","ty":"Automatic","b":"WAMMES","u":"/maschinen/luftkanalbau-rund/formstueckbau-rund/gasket-shaper","i":"/media/ce836192-caac-456c-ba6d-085667e3c37f/gasket_shaper_gs-u_2_format_website-jpg.jpg"},"presse":{"mb":"Presse mit Matrize und Stempel","ty":"","b":"","platz":1,"erkl":"formt die Halbschalen vor, Werkzeug je Bogengröße · nicht Teil unseres Maschinenprogramms"},"vstw":{"mb":"Rollennahtschweißmaschine für Bogenhalbschalen","ty":"","b":"WAMMES"},"varb":{"mb":"Halbschalen-Schweißautomat","ty":"","b":"WAMMES","i":"/media/f629106e-3fc4-40e1-b883-411a2c121054/halbschalen-schweissautomat.jpg"},"m3z":{"mb":"Zuschnittanlage mit querfahrender Pittsburgh-Kassette","ty":"3-Maschinen-System, Stufe 1","b":"WAMMES","u":"/maschinen/luftkanalbau-eckig/kanalfertigung-mit-integriertem-pdf-flansch/3-maschinen-system","i":"/media/dc8e3c95-a6b8-421c-9d74-93a51d79dbd5/drei-maschinen-system-stufe-1.jpg"},"m3b":{"mb":"Automatische Kant- und Schließeinheit","ty":"3-Maschinen-System, Stufe 3","b":"WAMMES","u":"/maschinen/luftkanalbau-eckig/kanalfertigung-mit-integriertem-pdf-flansch/3-maschinen-system","i":"/media/d4f8d5d8-8215-4526-9a81-814a16ffd3a8/drei-maschinen-system-stufe-3.jpg"},"pfs":{"mb":"Pittsburgh-Falzschließmaschine","ty":"senkrecht","b":"WAMMES","zk":1,"i":"/media/699037b9-f4d1-489a-8241-ed636aed6daf/pittsburgh-falzschliessmaschine-senkrecht.jpg"},"pfsw":{"mb":"Pittsburgh-Falzschließmaschine","ty":"waagerecht","b":"WAMMES","zk":1,"i":"/media/c887c388-8cf8-4574-ac0a-cdb0c5f56b3e/pittsburgh-falzschliessmaschine-waagerecht.jpg"},"sr300":{"mb":"Hüll- und Flexrohrmaschine","ty":"SR 300","b":"DROSSBACH","u":"/maschinen/metallrohrmaschinen","i":"/media/912b7f08-621b-4e95-b3a8-1ab5aa1d7415/drossbach-sr-300.jpg"},"sr300xl":{"mb":"Hüll- und Flexrohrmaschine","ty":"SR 300 XL","b":"DROSSBACH","u":"/maschinen/metallrohrmaschinen","i":"/media/c3575a65-d7ee-4b66-a5d6-2f9852bb0b54/drossbach-sr-300-xl.jpg"},"sr450":{"mb":"Hüll- und Flexrohrmaschine","ty":"SR 450","b":"DROSSBACH","u":"/maschinen/metallrohrmaschinen","i":"/media/0a993f53-9a8d-441b-9267-44d844688f08/drossbach-sr-450.jpg"},"spfc":{"mb":"Flexrohrmaschine","ty":"SPF Compact","b":"DROSSBACH","u":"/maschinen/metallrohrmaschinen","i":"/media/1c7d6119-8a1b-4866-939e-1525791185a7/drossbach-spf-compact.jpg"},"spf250":{"mb":"Flexrohrmaschine","ty":"SPF 250","b":"DROSSBACH","u":"/maschinen/metallrohrmaschinen","i":"/media/f1ca1647-7803-4a89-9c96-d9df4281a0c6/drossbach-spf-250.jpg"},"spf450":{"mb":"Flexrohrmaschine","ty":"SPF 450 S","b":"DROSSBACH","u":"/maschinen/metallrohrmaschinen","i":"/media/c29ad8d0-db28-49a4-b353-116abcc4dbbe/drossbach-spf-450-s.jpg"},"hpt":{"mb":"Hole-Punching TubeFormer","ty":"Hole-Punching TubeFormer","b":"WAMMES"},"trs160":{"mb":"Schere","ty":"TruTool S 160","b":"TRUMPF","u":"/zubehoer/trumpf-elektrowerkzeuge/schere-trutool-s160","i":"/media/98e5c4fd-1753-40a2-be44-7923be207f7e/s160_1web2.jpg"},"trs250":{"mb":"Schere","ty":"TruTool S 250","b":"TRUMPF","u":"/zubehoer/trumpf-elektrowerkzeuge/schere-trutool-s250","i":"/media/cea00811-521f-4146-9ddd-5d576643f436/s250_web1.jpg"},"trc160":{"mb":"Schlitzschere","ty":"TruTool C 160","b":"TRUMPF","u":"/zubehoer/trumpf-elektrowerkzeuge/schlitzschere-trutool-c160","i":"/media/630cbe8d-32ae-4631-b1dd-3edc0391c69c/c160_web1.jpg"},"trc250":{"mb":"Schlitzschere","ty":"TruTool C 250","b":"TRUMPF","u":"/zubehoer/trumpf-elektrowerkzeuge/schlitzschere-trutool-c250","i":"/media/fa0e429e-281c-4608-852d-f8aab57de6ae/c250_web1.jpg"},"trf140":{"mb":"Falzschließer","ty":"TruTool F 140","b":"TRUMPF","u":"/zubehoer/trumpf-elektrowerkzeuge/falzschliesser-trutool-f140","i":"/media/0bc8442d-e621-4f83-9375-ed397d7b68bf/f140_web2.jpg"},"trf300":{"mb":"Falzschließer","ty":"TruTool F 300","b":"TRUMPF","u":"/zubehoer/trumpf-elektrowerkzeuge/falzschliesser-trutool-f300","i":"/media/722e0978-6b77-4d59-a852-cf57f5562396/oragetblobweb-3.jpg"},"trtf350":{"mb":"Fügepresse","ty":"TruTool TF 350","b":"TRUMPF","u":"/zubehoer/trumpf-elektrowerkzeuge/fuegepresse-trutool-tf-350","i":"/media/7fb194b9-3da0-4163-b0f9-e335768501a9/tf350_web2.jpg"},"trdd1010":{"mb":"Akku-Bohrschrauber","ty":"TruTool DD 1010","b":"TRUMPF","u":"/zubehoer/trumpf-elektrowerkzeuge/akku-bohrschrauber-trutool-dd-1010","i":"/media/2db634d3-4323-4ed8-9222-6b31bb66769b/dd1010-700-456web2.jpg"},"trtpc165":{"mb":"Panel Cutter","ty":"TruTool TPC 165","b":"TRUMPF","u":"/zubehoer/trumpf-elektrowerkzeuge/panel-cutter-trutool-tpc-165","i":"/media/1105b545-9437-4541-b1af-0ff9875a339f/oragetblob_web1.jpg"},"trtsc100":{"mb":"Auflageleistenreiniger","ty":"TruTool TSC 100","b":"TRUMPF","u":"/zubehoer/trumpf-elektrowerkzeuge/auflageleistenreiniger-trutool-tsc-100","i":"/media/e74b2a26-e91a-4399-b0a9-57fab0b5f7ce/oragetblob_web2.jpg"}},"prozesse":[{"id":"P01","t":"Abwicklung, CAD"},{"id":"P02","t":"Abwickeln"},{"id":"P03","t":"Richten"},{"id":"P04","t":"Z-Sicke"},{"id":"P04b","t":"V-Sicke"},{"id":"P04c","t":"Trapezsicke"},{"id":"P04d","t":"Kreuzbruch"},{"id":"P05","t":"Ausklinken, Lochen"},{"id":"P06","t":"Scheren"},{"id":"P07","t":"Plasmaschneiden"},{"id":"P07L","t":"Laserschneiden"},{"id":"P08","t":"Rotationsschneiden"},{"id":"P09","t":"Falz profilieren (Tasche)"},{"id":"P10","t":"Bord stellen, Gegenfalz"},{"id":"P11","t":"Kanten"},{"id":"P12","t":"Runden"},{"id":"P13","t":"Falz schließen"},{"id":"P14","t":"Rahmenprofil profilieren"},{"id":"P15","t":"Ablängen, Sägen"},{"id":"P16","t":"Eckwinkel, Rahmen aufstecken"},{"id":"P17","t":"Flansch anformen (PDF)"},{"id":"P18","t":"Wickeln"},{"id":"P19","t":"Fliegend trennen"},{"id":"P20","t":"Rollennahtschweißen"},{"id":"P21","t":"Punktschweißen"},{"id":"P22","t":"Segment bördeln"},{"id":"P23","t":"Segmente schließen"},{"id":"P24","t":"Bogen formen"},{"id":"P25","t":"Sicken rund"},{"id":"P26","t":"Lippendichtung"},{"id":"P27","t":"Abdichten"},{"id":"P28","t":"Leitblech"},{"id":"P29","t":"Clinchen"},{"id":"P30","t":"Falz zudrücken"},{"id":"P31","t":"Rohrübergang kanten"},{"id":"P32","t":"Stutzen einsetzen"},{"id":"P33","t":"Bördelrand"},{"id":"P34","t":"Rohrstütze setzen"},{"id":"P35","t":"Kulissenrahmen fertigen"},{"id":"P36","t":"Selektieren"},{"id":"P37","t":"Vorschub"},{"id":"P38","t":"Kanalanlage"},{"id":"P39","t":"Selektier-, Vorschub- und Richteinheit"},{"id":"P40","t":"Schneiden mit der Handschere"},{"id":"P41","t":"Schlitzen und Ausklinken mit der Schlitzschere"},{"id":"P42","t":"Falz schließen von Hand"},{"id":"P43","t":"Rohranlage"},{"id":"P44","t":"Rohrschweißanlage"},{"id":"P45","t":"PDF-Kanalanlage (3-Maschinen-System)"},{"id":"P46","t":"Schrauben mit dem Bohrschrauber"},{"id":"P47","t":"PDF-Zuschnitt (Stufe 1)"},{"id":"P48","t":"Kanten und Falz schließen (PDF Stufe 3)"},{"id":"P49","t":"Falz schließen, freistehende Maschine"},{"id":"P51","t":"Ecken abdichten"},{"id":"P50","t":"Segmentbogen bördeln und schließen"},{"id":"P52","t":"Blech vom Stapel"},{"id":"P53","t":"Segment schneiden (Schere)"},{"id":"P54","t":"Segment schneiden (Laser)"},{"id":"P55","t":"Runden mit dem Rundautomaten"},{"id":"P56","t":"Halbschalen pressen"},{"id":"P57","t":"Halbschalen schweißen"},{"id":"P58","t":"Rahmenprofil mit Radius rollen"},{"id":"P59","t":"T-Bügel-Profil rollen"},{"id":"P60","t":"Kulisse montieren"},{"id":"P61","t":"Schnappfalz profilieren"},{"id":"P62","t":"Hakenfalz profilieren"},{"id":"P63","t":"S-Cleat profilieren"},{"id":"P64","t":"Rundfalz am Luftleitblech profilieren"},{"id":"P65","t":"Auflageleisten reinigen"},{"id":"P66","t":"Sandwichpaneel trennen"},{"id":"P67","t":"Absaugen und Filtern"}],"bj":{"rk":[[0],[0],[0],[0],[0],[0],[1],[2],[0],[1],[2],[2],[2],[2],[1],[2],[0]],"kurzkanal":[[0],[0],[0],[0],[0],[0],[1],[2],[0],[1],[2],[2],[2],[2],[1],[2],[0]],"passlaenge":[[0],[0],[0],[0],[0],[0],[1],[2],[0],[1],[2,3],[2,3],[2],[2,3],[1],[2],[0],[3]],"rbogen":[[0,1],[0,1],[2],[2],[1],[2],[4],[3],[-1]],"rwinkel":[[0,1],[1,2],[2],[4],[3]],"retage":[[0,1],[0,1],[2],[2],[1],[2],[3],[-1]],"hose":[[0,1],[0,1],[2],[2],[1],[3],[2],[4],[-1]],"hosenstueck":[[0,1],[0,1],[2],[2],[1],[2],[3],[-1]],"ruebergang":[[0],[0],[1],[3],[2]],"rboden":[[0],[0],[1]],"rstutzen":[[0],[1],[2],[-1]],"anschlusskasten":[[0],[0],[1]],"revision":[[0],[1,2],[2]],"dachhaube":[[0,1],[0,1]],"wfr":[[0],[0,1],[2]],"lnr":[[0],[1],[0],[1],[2]],"segbogen":[[0],[0],[1],[3],[2]],"tstueck":[[0],[0],[1],[1],[4],[2],[2],[3]],"tstueck90":[[0],[0],[4],[0],[1],[1],[4],[2],[2],[3]],"reduz":[[0],[0,1],[0,1],[4],[2],[3]],"enddeckel":[[0],[1],[1],[4],[2],[3]],"nippel":[[0],[0],[1],[2],[3]],"lippe":[[4],[4],[5],[1,2],[0],[3],[0,3]],"flex":[[0]],"kulisse":[[0],[1],[1]],"pbogen":[[0],[1],[2]],"skulisse":[[0],[0],[0],[6],[0],[2],[3,4],[5],[0]]},"wege":{"rk":{"M":[{"t":"Kanäle mit Steckrahmenprofil","st":[{"t":"Mantel: Tafel zuschneiden, versteifen, kanten","s":[1,2,3,4,5,8],"m":["msb","szp","mab"]},{"t":"Längsfalz profilieren und schließen","s":[6,9],"m":["rfp5","rfp7","rfs9","trf140","trf300"]},{"t":"Rahmen: ablängen, aufsetzen, fügen","s":[10,11,12],"m":["saege","psm","trtf350"]}],"rv":"sr"},{"t":"Kanäle mit PDF-Flansch","st":[{"t":"Mantel: zuschneiden (Ecken mit Laser oder Plasma), versteifen, kanten mit der PDF-Abkantmaschine","s":[1,2,4,5,8],"m":["lc","leco","pc","szp","pdfk"]},{"t":"Längsfalz profilieren und schließen","s":[6,9],"m":["rfp5","rfp7","rfs9","trf140","trf300"]},{"t":"Flansch anprofilieren (Stufe 2 des 3-Maschinen-Systems)","s":[7],"m":["pdfp"]}],"rv":"pdf"}],"T":[{"t":"Kanäle mit Steckrahmenprofil","st":[{"t":"Kanal formen","s":[1,2,4,5,8],"m":["mcl","cleco","odin"],"dazu":"Kurzkanäle: ODIN mit Plasma oder Längsschneideinrichtung (Spaltmesser) in der MCL Ultra"},{"t":"Längsfalz profilieren","s":[6],"m":["ds","mcl"],"dazu":"Pittsburgh-Kassette als Option in der MCL Ultra"},{"t":"Längsfalz schließen","s":[9],"m":["ds","trf140","trf300"]},{"t":"Falzabdichtung","s":[14],"m":["ds"],"dazu":"Einspritzung im Falzprofilierer zwischen den Profilierrollen: Option an der DS"},{"t":"Rahmen: Profil profilieren","s":[10,11],"m":["rf"],"dazu":"eine Säge kann in die Profilieranlage eingebaut werden"},{"t":"Rahmen ablängen mit eigener Säge","s":[11],"m":["saege"],"alt":1},{"t":"Rahmen aufsetzen und fügen","s":[12],"m":["psm","trtf350"]},{"t":"Ecken abdichten","s":[15],"m":[],"dazu":"von Hand"}],"rv":"sr"},{"t":"Kanäle mit PDF-Flansch (3-Maschinen-System)","st":[{"t":"Stufe 1: Zuschnitt mit Pittsburgh-Kassette","s":[1,2,4,5,6,14],"m":["m3z"],"dazu":"Dichtmitteleinspritzung als Option","zt":"Stufe 1","zs":"Mantel am flachen Blech","bild":{"pid":"rkflach1","ks":[0,1]}},{"t":"Stufe 2: Rahmenprofil","s":[7],"m":["pdfp"],"zt":"Stufe 2","zs":"Rahmenverbindung am flachen Blech","bild":{"pid":"rkflach2","ks":[2]}},{"t":"Stufe 3: Kanten und Falz schließen","s":[8,9],"m":["m3b"],"zt":"Stufe 3","zs":"Kanten und Längsfalz schließen","bild":{"pid":"rk","ks":[1,4]}},{"t":"Längsfalz alternativ freistehend schließen","s":[9],"m":["pfs","pfsw"],"alt":1,"dazu":"für große Querschnitte"},{"t":"Eckwinkel einlegen und einklopfen","s":[13],"m":[],"dazu":"von Hand mit dem Hammer"},{"t":"Ecken abdichten","s":[15],"m":[],"dazu":"von Hand"}],"rv":"pdf","zeilen":"stationen"}],"V":[{"t":"Kanäle mit PDF-Flansch","m":["pdfa"],"s":[1,2,4,5,6,7,8,9,14],"dazu":"Eckwinkel von Hand einlegen und einklopfen oder mit einer Eckeneinsetzmaschine (nicht im Programm); Ecken von Hand abdichten","rv":"pdf"}]},"kurzkanal":{"M":[{"t":"Kanäle mit Steckrahmenprofil","st":[{"t":"Mantel: Tafel zuschneiden, versteifen, kanten","s":[1,2,3,4,5,8],"m":["msb","szp","mab"]},{"t":"Längsfalz profilieren und schließen","s":[6,9],"m":["rfp5","rfp7","rfs9","trf140","trf300"]},{"t":"Rahmen: ablängen, aufsetzen, fügen","s":[10,11,12],"m":["saege","psm","trtf350"]}],"rv":"sr"},{"t":"Kanäle mit PDF-Flansch","st":[{"t":"Mantel: zuschneiden (Ecken mit Laser oder Plasma), versteifen, kanten mit der PDF-Abkantmaschine","s":[1,2,4,5,8],"m":["lc","leco","pc","szp","pdfk"]},{"t":"Längsfalz profilieren und schließen","s":[6,9],"m":["rfp5","rfp7","rfs9","trf140","trf300"]},{"t":"Flansch anprofilieren (Stufe 2 des 3-Maschinen-Systems)","s":[7],"m":["pdfp"]}],"rv":"pdf"}],"T":[{"t":"Kanäle mit Steckrahmenprofil","st":[{"t":"Kanal formen","s":[1,2,4,5,8],"m":["mcl","cleco","odin"],"dazu":"Kurzkanäle: ODIN mit Plasma oder Längsschneideinrichtung (Spaltmesser) in der MCL Ultra"},{"t":"Längsfalz profilieren","s":[6],"m":["ds","mcl"],"dazu":"Pittsburgh-Kassette als Option in der MCL Ultra"},{"t":"Längsfalz schließen","s":[9],"m":["ds","trf140","trf300"]},{"t":"Falzabdichtung","s":[14],"m":["ds"],"dazu":"Einspritzung im Falzprofilierer zwischen den Profilierrollen: Option an der DS"},{"t":"Rahmen: Profil profilieren","s":[10,11],"m":["rf"],"dazu":"eine Säge kann in die Profilieranlage eingebaut werden"},{"t":"Rahmen ablängen mit eigener Säge","s":[11],"m":["saege"],"alt":1},{"t":"Rahmen aufsetzen und fügen","s":[12],"m":["psm","trtf350"]},{"t":"Ecken abdichten","s":[15],"m":[],"dazu":"von Hand"}],"rv":"sr"},{"t":"Kanäle mit PDF-Flansch (3-Maschinen-System)","st":[{"t":"Stufe 1: Zuschnitt mit Pittsburgh-Kassette","s":[1,2,4,5,6,14],"m":["m3z"],"dazu":"Dichtmitteleinspritzung als Option","zt":"Stufe 1","zs":"Mantel am flachen Blech","bild":{"pid":"rkflach1","ks":[0,1]}},{"t":"Stufe 2: Rahmenprofil","s":[7],"m":["pdfp"],"zt":"Stufe 2","zs":"Rahmenverbindung am flachen Blech","bild":{"pid":"rkflach2","ks":[2]}},{"t":"Stufe 3: Kanten und Falz schließen","s":[8,9],"m":["m3b"],"zt":"Stufe 3","zs":"Kanten und Längsfalz schließen","bild":{"pid":"rk","ks":[1,4]}},{"t":"Längsfalz alternativ freistehend schließen","s":[9],"m":["pfs","pfsw"],"alt":1,"dazu":"für große Querschnitte"},{"t":"Eckwinkel einlegen und einklopfen","s":[13],"m":[],"dazu":"von Hand mit dem Hammer"},{"t":"Ecken abdichten","s":[15],"m":[],"dazu":"von Hand"}],"rv":"pdf","zeilen":"stationen"}],"V":[{"t":"Kanäle mit PDF-Flansch","m":["pdfa"],"s":[1,2,4,5,6,7,8,9,14],"dazu":"Eckwinkel von Hand einlegen und einklopfen oder mit einer Eckeneinsetzmaschine (nicht im Programm); Ecken von Hand abdichten","rv":"pdf"}]},"passlaenge":{"M":[{"t":"Kanäle mit Steckrahmenprofil","st":[{"t":"Mantel: Tafel zuschneiden, versteifen, kanten","s":[1,2,3,4,5,8],"m":["msb","szp","mab"]},{"t":"Längsfalz profilieren und schließen","s":[6,9],"m":["rfp5","rfp7","rfs9","trf140","trf300"]},{"t":"Rahmen: ablängen, aufsetzen, fügen","s":[10,11,12],"m":["saege","psm","trtf350"]}],"rv":"sr"},{"t":"Kanäle mit PDF-Flansch","st":[{"t":"Mantel: zuschneiden (Ecken mit Laser oder Plasma), versteifen, kanten mit der PDF-Abkantmaschine","s":[1,2,4,5,8],"m":["lc","leco","pc","szp","pdfk"]},{"t":"Längsfalz profilieren und schließen","s":[6,9],"m":["rfp5","rfp7","rfs9","trf140","trf300"]},{"t":"Flansch anprofilieren (Stufe 2 des 3-Maschinen-Systems)","s":[7],"m":["pdfp"]}],"rv":"pdf"}],"T":[{"t":"Kanäle mit Steckrahmenprofil","st":[{"t":"Kanal formen","s":[1,2,4,5,8],"m":["mcl","cleco","odin"],"dazu":"Kurzkanäle: ODIN mit Plasma oder Längsschneideinrichtung (Spaltmesser) in der MCL Ultra"},{"t":"Längsfalz profilieren","s":[6],"m":["ds","mcl"],"dazu":"Pittsburgh-Kassette als Option in der MCL Ultra"},{"t":"Längsfalz schließen","s":[9],"m":["ds","trf140","trf300"]},{"t":"Falzabdichtung","s":[14],"m":["ds"],"dazu":"Einspritzung im Falzprofilierer zwischen den Profilierrollen: Option an der DS"},{"t":"Rahmen: Profil profilieren","s":[10,11],"m":["rf"],"dazu":"eine Säge kann in die Profilieranlage eingebaut werden"},{"t":"Rahmen ablängen mit eigener Säge","s":[11],"m":["saege"],"alt":1},{"t":"Einen Rahmen aufsetzen und fügen, den zweiten lose beilegen","s":[12],"m":["psm","trtf350"]},{"t":"Ecken am festen Rahmen abdichten","s":[15],"m":[],"dazu":"von Hand"},{"t":"Auf der Baustelle","s":[17],"m":[],"dazu":"Montagebetrieb: kürzen, Rahmen aufschieben, nieten, abdichten"}],"rv":"sr"},{"t":"Kanäle mit PDF-Flansch (3-Maschinen-System)","st":[{"t":"Stufe 1: Zuschnitt mit Pittsburgh-Kassette","s":[1,2,4,5,6,14],"m":["m3z"],"dazu":"Dichtmitteleinspritzung als Option","zt":"Stufe 1","zs":"Mantel am flachen Blech","bild":{"pid":"rkflach1","ks":[0,1]}},{"t":"Stufe 2: Flansch an einem Ende","s":[7],"m":["pdfp"],"zt":"Stufe 2","zs":"Rahmenverbindung am flachen Blech","bild":{"pid":"rkflach2","ks":[2]}},{"t":"Stufe 3: Kanten und Falz schließen","s":[8,9],"m":["m3b"],"zt":"Stufe 3","zs":"Kanten und Längsfalz schließen","bild":{"pid":"rk","ks":[1,4]}},{"t":"Längsfalz alternativ freistehend schließen","s":[9],"m":["pfs","pfsw"],"alt":1,"dazu":"für große Querschnitte"},{"t":"Eckwinkel einlegen, losen Steckrahmen beilegen","s":[13],"m":[],"dazu":"von Hand mit dem Hammer"},{"t":"Ecken am festen Ende abdichten","s":[15],"m":[],"dazu":"von Hand"},{"t":"Auf der Baustelle","s":[17],"m":[],"dazu":"Montagebetrieb: kürzen, Rahmen aufschieben, nieten, abdichten"}],"rv":"pdf","zeilen":"stationen"}]},"rbogen":{"M":[{"t":"Formstücke mit Steckrahmenprofil","rv":"sr","jeSchritt":1,"st":[{"t":"Zuschnitt; große Mantelbleche mit Versteifungssicke","s":[1],"m":["msb","trs160","trs250","szp","trc160","trc250"]},{"t":"Tasche am noch geraden Mantel","s":[2],"m":["rfp5","rfp7","rfs9"]},{"t":"Bord am Seitenblech","s":[3],"m":["fpfs","mab"]},{"t":"Mantel runden (Einlegebleche, Falz wird etwas gepresst)","s":[4],"m":["rme"]},{"t":"Zusammenstecken, Falz schließen","s":[5],"m":["trf140","trf300"]},{"t":"Rahmen: Steckrahmen aufsetzen oder PDF-Flansch anprofilieren","s":[7],"m":["saege","psm","trtf350"]}]},{"t":"Formstücke mit PDF-Flansch","rv":"pdf","jeSchritt":1,"st":[{"t":"Zuschnitt; große Mantelbleche mit Versteifungssicke","s":[1],"m":["msb","trs160","trs250","szp","trc160","trc250"]},{"t":"Tasche am noch geraden Mantel","s":[2],"m":["rfp5","rfp7","rfs9"]},{"t":"Bord am Seitenblech","s":[3],"m":["fpfs","mab"]},{"t":"Mantel runden (Einlegebleche, Falz wird etwas gepresst)","s":[4],"m":["rme"]},{"t":"Zusammenstecken, Falz schließen","s":[5],"m":["trf140","trf300"]},{"t":"Rahmen: Steckrahmen aufsetzen oder PDF-Flansch anprofilieren","s":[7],"m":["pdfp"]}]}],"T":[{"t":"Formstücke mit Steckrahmenprofil","rv":"sr","jeSchritt":1,"st":[{"t":"Abwicklung mit Zugaben","s":[0],"m":["cutx"]},{"t":"Zuschnitt; große Mantelbleche mit Versteifungssicke","s":[1],"m":["lc","leco","pc"]},{"t":"Tasche am noch geraden Mantel","s":[2],"m":["rfp5","rfp7","rfs9"]},{"t":"Bord am Seitenblech","s":[3],"m":["fpfs","mab"]},{"t":"Mantel runden (Einlegebleche, Falz wird etwas gepresst)","s":[4],"m":["rme"]},{"t":"Zusammenstecken, Falz schließen","s":[5],"m":["trf140","trf300"]},{"t":"Leitbleche einsetzen (Bogen über 45°)","s":[6],"m":["llb"]},{"t":"Rahmen: Steckrahmen aufsetzen oder PDF-Flansch anprofilieren","s":[7],"m":["rf","saege","psm","trtf350"]}]},{"t":"Formstücke mit PDF-Flansch","rv":"pdf","jeSchritt":1,"st":[{"t":"Abwicklung mit Zugaben","s":[0],"m":["cutx"]},{"t":"Zuschnitt; große Mantelbleche mit Versteifungssicke","s":[1],"m":["lc","leco","pc"]},{"t":"Tasche am noch geraden Mantel","s":[2],"m":["rfp5","rfp7","rfs9"]},{"t":"Bord am Seitenblech","s":[3],"m":["fpfs","mab"]},{"t":"Mantel runden (Einlegebleche, Falz wird etwas gepresst)","s":[4],"m":["rme"]},{"t":"Zusammenstecken, Falz schließen","s":[5],"m":["trf140","trf300"]},{"t":"Leitbleche einsetzen (Bogen über 45°)","s":[6],"m":["llb"]},{"t":"Rahmen: Steckrahmen aufsetzen oder PDF-Flansch anprofilieren","s":[7],"m":["pdfp"]}]}]},"rwinkel":{"M":[{"t":"Formstücke mit Steckrahmenprofil","rv":"sr","jeSchritt":1,"st":[{"t":"Abwicklung, Zuschnitt; große Mantelbleche mit Versteifungssicke","s":[0],"m":["msb","trs160","trs250","szp","trc160","trc250"]},{"t":"Mantel kanten (Winkel in der Mitte, T-Stück an den Innenecken), Bord an geraden Kanten","s":[1],"m":["mab"]},{"t":"Falz profilieren und schließen","s":[2],"m":["rfp5","rfp7","rfs9","trf140","trf300"]},{"t":"Rahmen: Steckrahmen aufsetzen oder PDF-Flansch anprofilieren","s":[4],"m":["saege","psm","trtf350"]}]},{"t":"Formstücke mit PDF-Flansch","rv":"pdf","jeSchritt":1,"st":[{"t":"Abwicklung, Zuschnitt; große Mantelbleche mit Versteifungssicke","s":[0],"m":["msb","trs160","trs250","szp","trc160","trc250"]},{"t":"Mantel kanten (Winkel in der Mitte, T-Stück an den Innenecken), Bord an geraden Kanten","s":[1],"m":["mab"]},{"t":"Falz profilieren und schließen","s":[2],"m":["rfp5","rfp7","rfs9","trf140","trf300"]},{"t":"Rahmen: Steckrahmen aufsetzen oder PDF-Flansch anprofilieren","s":[4],"m":["pdfp"]}]}],"T":[{"t":"Formstücke mit Steckrahmenprofil","rv":"sr","jeSchritt":1,"st":[{"t":"Abwicklung, Zuschnitt; große Mantelbleche mit Versteifungssicke","s":[0],"m":["cutx","lc","leco","pc"]},{"t":"Mantel kanten (Winkel in der Mitte, T-Stück an den Innenecken), Bord an geraden Kanten","s":[1],"m":["mab"]},{"t":"Falz profilieren und schließen","s":[2],"m":["rfp5","rfp7","rfs9","trf140","trf300"]},{"t":"Leitbleche (Winkel über 45°, T-Stück nach Bedarf)","s":[3],"m":["llb"]},{"t":"Rahmen: Steckrahmen aufsetzen oder PDF-Flansch anprofilieren","s":[4],"m":["rf","saege","psm","trtf350"]}]},{"t":"Formstücke mit PDF-Flansch","rv":"pdf","jeSchritt":1,"st":[{"t":"Abwicklung, Zuschnitt; große Mantelbleche mit Versteifungssicke","s":[0],"m":["cutx","lc","leco","pc"]},{"t":"Mantel kanten (Winkel in der Mitte, T-Stück an den Innenecken), Bord an geraden Kanten","s":[1],"m":["mab"]},{"t":"Falz profilieren und schließen","s":[2],"m":["rfp5","rfp7","rfs9","trf140","trf300"]},{"t":"Leitbleche (Winkel über 45°, T-Stück nach Bedarf)","s":[3],"m":["llb"]},{"t":"Rahmen: Steckrahmen aufsetzen oder PDF-Flansch anprofilieren","s":[4],"m":["pdfp"]}]}]},"retage":{"M":[{"t":"Formstücke mit Steckrahmenprofil","rv":"sr","jeSchritt":1,"st":[{"t":"Zuschnitt, Ausklinkung an den Knickstellen; große Mantelbleche mit Versteifungssicke","s":[1],"m":["msb","trs160","trs250","szp","trc160","trc250"]},{"t":"Tasche am Mantelblech","s":[2],"m":["rfp5","rfp7","rfs9"]},{"t":"Bord am Seitenblech (Innenecken an der Bördelmaschine)","s":[3],"m":["fpfs","mab"]},{"t":"Kanten: Knicke zwischen Ansatz und Schräge","s":[4],"m":["mab"]},{"t":"Zusammenstecken, 4 Längsfalze schließen","s":[5],"m":["trf140","trf300"]},{"t":"Rahmen an beiden Enden: Steckrahmen aufsetzen oder PDF-Flansch anprofilieren","s":[6],"m":["saege","psm","trtf350"]}]},{"t":"Formstücke mit PDF-Flansch","rv":"pdf","jeSchritt":1,"st":[{"t":"Zuschnitt, Ausklinkung an den Knickstellen; große Mantelbleche mit Versteifungssicke","s":[1],"m":["msb","trs160","trs250","szp","trc160","trc250"]},{"t":"Tasche am Mantelblech","s":[2],"m":["rfp5","rfp7","rfs9"]},{"t":"Bord am Seitenblech (Innenecken an der Bördelmaschine)","s":[3],"m":["fpfs","mab"]},{"t":"Kanten: Knicke zwischen Ansatz und Schräge","s":[4],"m":["mab"]},{"t":"Zusammenstecken, 4 Längsfalze schließen","s":[5],"m":["trf140","trf300"]},{"t":"Rahmen an beiden Enden: Steckrahmen aufsetzen oder PDF-Flansch anprofilieren","s":[6],"m":["pdfp"]}]}],"T":[{"t":"Formstücke mit Steckrahmenprofil","rv":"sr","jeSchritt":1,"st":[{"t":"Abwicklung mit Zugaben (Z-Kontur oder Trapezbleche, wahre Längen)","s":[0],"m":["cutx"]},{"t":"Zuschnitt, Ausklinkung an den Knickstellen; große Mantelbleche mit Versteifungssicke","s":[1],"m":["lc","leco","pc"]},{"t":"Tasche am Mantelblech","s":[2],"m":["rfp5","rfp7","rfs9"]},{"t":"Bord am Seitenblech (Innenecken an der Bördelmaschine)","s":[3],"m":["fpfs","mab"]},{"t":"Kanten: Knicke zwischen Ansatz und Schräge","s":[4],"m":["mab"]},{"t":"Zusammenstecken, 4 Längsfalze schließen","s":[5],"m":["trf140","trf300"]},{"t":"Rahmen an beiden Enden: Steckrahmen aufsetzen oder PDF-Flansch anprofilieren","s":[6],"m":["rf","saege","psm","trtf350"]}]},{"t":"Formstücke mit PDF-Flansch","rv":"pdf","jeSchritt":1,"st":[{"t":"Abwicklung mit Zugaben (Z-Kontur oder Trapezbleche, wahre Längen)","s":[0],"m":["cutx"]},{"t":"Zuschnitt, Ausklinkung an den Knickstellen; große Mantelbleche mit Versteifungssicke","s":[1],"m":["lc","leco","pc"]},{"t":"Tasche am Mantelblech","s":[2],"m":["rfp5","rfp7","rfs9"]},{"t":"Bord am Seitenblech (Innenecken an der Bördelmaschine)","s":[3],"m":["fpfs","mab"]},{"t":"Kanten: Knicke zwischen Ansatz und Schräge","s":[4],"m":["mab"]},{"t":"Zusammenstecken, 4 Längsfalze schließen","s":[5],"m":["trf140","trf300"]},{"t":"Rahmen an beiden Enden: Steckrahmen aufsetzen oder PDF-Flansch anprofilieren","s":[6],"m":["pdfp"]}]}]},"ruebergang":{"M":[{"t":"Formstücke mit Steckrahmenprofil","rv":"sr","jeSchritt":1,"st":[{"t":"Abwicklung, Zuschnitt (Teilung größenabhängig)","s":[0],"m":["msb","trs160","trs250","trc160","trc250"]},{"t":"Eckflächen kanten: viele fächerförmige Kantungen","s":[1],"m":["mab"]},{"t":"Längsnaht: Hakenfalz profilieren und zudrücken oder punktschweißen","s":[2],"m":["hfp","hfz","psm"]},{"t":"Steckende als eigener Ring: runden, anfügen (punkten)","s":[3],"m":["rme","psm"]},{"t":"Rahmen auf der Rechteckseite: Steckrahmen aufsetzen oder PDF-Flansch anprofilieren","s":[4],"m":["saege","psm","trtf350"]}]},{"t":"Formstücke mit PDF-Flansch","rv":"pdf","jeSchritt":1,"st":[{"t":"Abwicklung, Zuschnitt (Teilung größenabhängig)","s":[0],"m":["msb","trs160","trs250","trc160","trc250"]},{"t":"Eckflächen kanten: viele fächerförmige Kantungen","s":[1],"m":["mab"]},{"t":"Längsnaht: Hakenfalz profilieren und zudrücken oder punktschweißen","s":[2],"m":["hfp","hfz","psm"]},{"t":"Steckende als eigener Ring: runden, anfügen (punkten)","s":[3],"m":["rme","psm"]},{"t":"Rahmen auf der Rechteckseite: Steckrahmen aufsetzen oder PDF-Flansch anprofilieren","s":[4],"m":["pdfp"]}]}],"T":[{"t":"Formstücke mit Steckrahmenprofil","rv":"sr","jeSchritt":1,"st":[{"t":"Abwicklung, Zuschnitt (Teilung größenabhängig)","s":[0],"m":["cutx","lc","leco","pc"]},{"t":"Eckflächen kanten: viele fächerförmige Kantungen","s":[1],"m":["mab"]},{"t":"Längsnaht: Hakenfalz profilieren und zudrücken oder punktschweißen","s":[2],"m":["psm"]},{"t":"Steckende als eigener Ring: runden, anfügen (punkten)","s":[3],"m":["psm","rme"]},{"t":"Rahmen auf der Rechteckseite: Steckrahmen aufsetzen oder PDF-Flansch anprofilieren","s":[4],"m":["rf","saege","psm","trtf350"]}]},{"t":"Formstücke mit PDF-Flansch","rv":"pdf","jeSchritt":1,"st":[{"t":"Abwicklung, Zuschnitt (Teilung größenabhängig)","s":[0],"m":["cutx","lc","leco","pc"]},{"t":"Eckflächen kanten: viele fächerförmige Kantungen","s":[1],"m":["mab"]},{"t":"Längsnaht: Hakenfalz profilieren und zudrücken oder punktschweißen","s":[2],"m":["psm"]},{"t":"Steckende als eigener Ring: runden, anfügen (punkten)","s":[3],"m":["psm","rme"]},{"t":"Rahmen auf der Rechteckseite: Steckrahmen aufsetzen oder PDF-Flansch anprofilieren","s":[4],"m":["pdfp"]}]}]}},"fam":[{"t":"Faserlaser","m":["lc","leco"]},{"t":"TruTool S 160 · 250","m":["trs160","trs250"]},{"t":"TruTool C 160 · 250","m":["trc160","trc250"]},{"t":"TruTool F 140 · 300","m":["trf140","trf300"]},{"t":"RFP-5 · RFP-7","m":["rfp5","rfp7"]}],"mkat":[{"id":"elektro","t":"Elektrowerkzeuge","u":"/zubehoer/trumpf-elektrowerkzeuge","m":["trs160","trs250","trc160","trc250","trf140","trf300","trtf350","trdd1010","trtpc165","trtsc100"],"bild":"kat_elektro","i":"/media/46c02022-df60-46b5-986c-591ad9c55fe0/b01a_trumpf_neue-akku-ew_5998-1430x580.jpg","jz":1,"ruhe":["trf300","trf140","trtf350","trc160","trc250","trs160","trs250"],"b":"TRUMPF","paar":[["trf300","trf140"],["trc160","trs160"]]},{"id":"schneiden","t":"CNC-Schneiden","u":"/maschinen/schneiden","m":["lc","leco","pc","prot","hyp","abs","cutx","sync","asb","rev"],"ruhe":["lc","pc"],"txt":"Faserlaser · Plasmaschneidanlagen · CAD/CAM","b":"WAMMES"}],"gat":{"cutx":{"t":"CAD/CAM-|Software"},"sync":{"t":"Fertigungs|software"},"has":{"t":"Abwickel|haspeln"},"richt":{"t":"Richt- und Vorschub|einheiten"},"zus":{"t":"Zuschnitt|anlagen"},"m3z":{"t":"Stufe 1: Zu|schnitt"},"pdfp":{"t":"Stufe 2: Rahmen|profil"},"m3b":{"t":"Stufe 3: Kanten, Falz|schließen"},"szp":{"t":"Versteifungs|maschinen"},"mab":{"t":"Schwenk|biege|maschinen"},"msb":{"t":"Tafel|scheren"},"trs160":{"t":"Hand- und Schlitz|scheren"},"trs250":{"t":"Hand- und Schlitz|scheren"},"trc160":{"t":"Hand- und Schlitz|scheren"},"trc250":{"t":"Hand- und Schlitz|scheren"},"rfp5":{"t":"Falz|profilier|anlagen"},"rfp7":{"t":"Falz|profilier|anlagen"},"rfs9":{"t":"Falz|profilier|anlagen"},"fpfs":{"t":"Bördel|maschinen"},"ds":{"t":"Falz|schließ|maschinen"},"trf140":{"t":"Hand|falz|schließer"},"trf300":{"t":"Hand|falz|schließer"},"rf":{"t":"Rahmen|profilier|anlagen"},"saege":{"t":"Ab|läng|sägen"},"llb":{"t":"Leitblech|profilier|anlagen"},"podr":{"t":"Kulissen|profilier|anlagen"},"pod":{"t":"Kulissen|anlagen"},"psm":{"t":"Punkt|schweiß|maschinen"},"trtf350":{"t":"Füge|pressen"},"trdd1010":{"t":"Bohr|schrauber"},"pc":{"t":"Plasma|schneid|anlagen"},"prot":{"t":"Plasma|schneid|anlagen"},"lc":{"t":"Faser|laser"},"leco":{"t":"Faser|laser"},"abs":{"t":"Absaug|anlagen"},"rme":{"t":"Rund|maschinen"},"hyl":{"t":"Rund|maschinen"},"roll":{"t":"Rund|automaten"},"sw":{"t":"Rollennaht|schweiß|maschinen"},"pr":{"t":"Rohr|anlagen"},"swa":{"t":"Rohr|schweiß|anlagen"},"sick":{"t":"Sicken|maschinen"},"gs":{"t":"Dichtungs|maschinen"},"cem":{"t":"Segment|bogen|maschinen"},"cemeco":{"t":"Segment|bogen|maschinen"},"bogen":{"t":"Bogen|automaten"},"spf250":{"t":"Flexrohr|maschinen"},"spf450":{"t":"Flexrohr|maschinen"},"spfc":{"t":"Flexrohr|maschinen"},"sr300":{"t":"Hüll- und Flex|rohr|maschinen"},"sr300xl":{"t":"Hüll- und Flex|rohr|maschinen"},"sr450":{"t":"Hüll- und Flex|rohr|maschinen"},"sr200":{"t":"Hüll|rohr|maschinen"}},"alt":{"segbogen":{"T":["sick"]},"tstueck":{"T":["sick"]},"tstueck90":{"T":["sick"]},"reduz":{"T":["sick"]},"enddeckel":{"T":["sick"]},"nippel":{"T":["sick"]},"lippe":{"T":["sick"]}},"stb":{"rk":{"sr":{"M":{"ruhe":"mab","folge":["P52","P06","P11","P42","P16"]},"T":{"ruhe":"mcl","folge":["P38","P13","P16"]}},"pdf":{"T":{"ruhe":"m3","folge":["P47","P17","P48"]},"M":{"ruhe":"pdfk","folge":["P52","P07L","P04","P17","P11","P42"]}}},"kurzkanal":{"sr":{"M":{"ruhe":"mab","folge":["P52","P06","P11","P42","P16"]},"T":{"ruhe":"mcl","folge":["P38","P13","P16"]}},"pdf":{"T":{"ruhe":"m3","folge":["P47","P17","P48"]},"M":{"ruhe":"pdfk","folge":["P52","P07L","P04","P17","P11","P42"]}}},"passlaenge":{"sr":{"M":{"ruhe":"mab","folge":["P52","P06","P11","P42","P16"]},"T":{"ruhe":"mcl","folge":["P38","P13","P16"]}},"pdf":{"T":{"ruhe":"m3","folge":["P47","P17","P48"]},"M":{"ruhe":"pdfk","folge":["P52","P07L","P04","P17","P11","P42"]}}},"segbogen":{"*":{"M":{"ruhe":"rme","folge":["P52","P53","P12","P21","P25"]},"T":{"ruhe":"cem","folge":["P54","P55","P20","P50"]},"V":{"ruhe":"bogen","folge":["P24"]}}}},"reihe":["has","richt","zus","lc","leco","pc","prot","hyp","abs","cutx","asb","sync","rev","msb","szp","mcl","cleco","odin","kan","m3z","pdfp","m3b","m3","pdfa","podr","tbp","mab","pdfk","rme","hyl","roll","pr","swa","rfp5","rfp7","rfs9","rfsc","hfp","fpfs","ds","pfs","pfsw","sw","hfz","rf","saege","cem","cemeco","bogen","psm","psz","varb","presse","gs","gsa","sick","llb","pod","tf14","tf16","spf250","spf450","spfc","sr300","sr300xl","sr450","sr200","trs160","trs250","trc160","trc250","trf140","trf300","trtf350","trdd1010","trtpc165","trtsc100"],"verfahren":[{"id":"coil","t":"Coil-Handling","te":"Coil handling","m":["has","besch","richt"],"sym":["P02","P36","P37","P03"]},{"id":"zuschnitt","t":"Zuschnitt","te":"Cut-to-length","m":["zus","msb"],"sym":["P06"]},{"id":"scheren","t":"Sägen und Scheren","te":"Shearing and sawing","m":["saege","trs160","trs250"],"sym":["P06","P15"]},{"id":"laser","t":"Laserschneiden","te":"Laser cutting","m":["lc","leco","trtsc100"],"sym":["P07L"]},{"id":"plasma","t":"Plasmaschneiden","te":"Plasma cutting","m":["pc","prot","hyp"],"sym":["P07","P08"]},{"id":"absaug","t":"Absaugen und Filtern","te":"Extraction and filtering","m":["abs"],"sym":["P67"]},{"id":"kanten","t":"Kanten und Biegen","te":"Folding and bending","m":["mab"],"sym":["P11","P04d","P31"]},{"id":"runden","t":"Runden","te":"Rolling","m":["rme","hyl","roll"],"sym":["P12"]},{"id":"profilieren","t":"Profilieren","te":"Roll forming","m":["rf","pdfp","szp","llb"],"sym":["P14","P04","P17","P64"]},{"id":"falzen","t":"Falzen, Bördeln, Falzschließen","te":"Seaming, flanging, seam closing","m":["rfp5","rfp7","rfs9","rfsc","fpfs","ds","trf140","trf300"],"sym":["P09","P10","P13"],"erg":"E13"},{"id":"sicken","t":"Sicken und Dichten","te":"Beading and sealing","m":["sick","gs"],"sym":["P25","P26","P33"],"erg":"E25"},{"id":"schweissen","t":"Schweißen","te":"Welding","m":["sw","psm","swa"],"sym":["P20","P21"],"erg":"E20"},{"id":"fuegen","t":"Fügen","te":"Joining","m":["trtf350"],"sym":["P29"]},{"id":"wickeln","t":"Rohre wickeln","te":"Pipe forming","m":["tf14","tf16","sr200","sr300","sr300xl","sr450","spfc","spf250","spf450"],"sym":["P18","P19"]},{"id":"rohranlagen","t":"Rohranlagen","te":"Pipe lines","m":["pr","swa"],"sym":["P43","P44"]},{"id":"bogen","t":"Segmentbögen formen","te":"Elbow forming","m":["bogen","cem","cemeco"],"sym":["P50","P24"]},{"id":"anlagen","t":"Komplette Kanalanlagen","te":"Complete duct lines","m":["mcl","cleco","odin","m3","pdfa","kan"],"sym":["P38","P45"]},{"id":"kulissen","t":"Schalldämpferkulissen","te":"Splitter silencers","m":["pod","podr"],"sym":["P35","P58"]},{"id":"hand","t":"Handgeführte Elektrowerkzeuge","te":"Hand-held power tools","m":["trs160","trs250","trc160","trc250","trf140","trf300","trtf350","trdd1010","trtpc165"],"sym":["P40","P41","P42","P29","P46","P66"]},{"id":"software","t":"Software","te":"Software","m":["cutx","asb","sync","rev"],"sym":["P01"]}],"msym":{"mcl":"P38","cleco":"P38","odin":"P38","m3":"P45","m3z":"P47","m3b":"P48","pdfa":"P45","kan":"P38","rf":"P14","saege":"P15","ds":"P13","pdfp":"P17","rfp5":"P09","rfp7":"P09","rfs9":"P61","rfsc":"P63","fpfs":"P10","mab":"P11","szp":"P04","llb":"P64","tf14":"P18","tf16":"P18","sr200":"P18","pr":"P43","swa":"P44","sw":"P20","bogen":"P24","cem":"P50","cemeco":"P50","roll":"P55","rme":"P12","hyl":"P12","sick":"P25","gs":"P26","msb":"P06","zus":"P06","pc":"P07","prot":"P08","hyp":"P07","lc":"P07L","leco":"P07L","abs":"P67","psm":"P21","has":"P02","besch":"P02","richt":"P39","podr":"P58","cutx":"P01","asb":"P01","sync":"P01","rev":"P01","pfs":"P49","trs160":"P40","trs250":"P40","trc160":"P41","trc250":"P41","trf140":"P42","trf300":"P42","trtf350":"P29","trdd1010":"P46","trtpc165":"P66","trtsc100":"P65","vstw":"P57","varb":"P57","pdfk":"P11","hfp":"P62","hfz":"P30","gsa":"P26","presse":"P56","pfsw":"P49","tbp":"P59","pod":"P35"},"btx":{"rk":"Ein gerader Rechteckkanal entsteht aus Blech vom Coil oder von der Tafel. Das Blech wird versteift, ausgeklinkt, abgelängt, mit Längsfalz versehen und zu L, U oder Box gekantet; der Falz wird geschlossen und abgedichtet, Steckrahmen oder PDF-Flansch bilden die Rahmenverbindung.","kurzkanal":"Kurzkanäle bis 900 mm Länge entstehen auf demselben Weg wie der gerade Kanal, nur der Mantel ist kürzer. Auf der Kanalanlage trennt die ODIN sie mit Plasma ab, die MCL Ultra mit einer Längsschneideinrichtung.","passlaenge":"Die Passlänge entsteht wie der gerade Kanal, erhält aber nur an einem Ende einen festen Rahmen oder angeformten Flansch. Der zweite Rahmen liegt lose bei, ohne Dichtmittel: Auf der Baustelle wird das Teil auf Maß gekürzt, der Rahmen bis zum Anschlag aufgeschoben, dicht genietet und innen abgedichtet.","rbogen":"Ein Rechteckbogen besteht aus zwei Seitenblechen und einem gerundeten Mantel. Der Mantel bekommt die Falztasche, die Seitenbleche den Bord; beide werden zusammengesteckt und gefalzt. Bögen über 45° erhalten Leitbleche. Die Etage mit Radien entsteht genauso, mit S-förmigen Seitenblechen.","rwinkel":"Rechteckwinkel und T-Stück entstehen wie der Bogen aus Seitenblechen und Mantel; der Mantel wird gekantet statt gerundet, beim Winkel in der Mitte, beim T-Stück an den Innenecken. Winkel über 45° erhalten Leitbleche.","ruebergang":"Der Übergang von eckig auf rund wird abgewickelt und zugeschnitten. Viele fächerförmige Kantungen formen die Eckflächen, die Naht wird geschweißt; das runde Steckende ist ein eigener Ring.","rboden":"Die Endkappe ist eine zugeschnittene Platte mit gekantetem Bord. Sie wird in den Kanal gesteckt und genietet oder gepunktet.","rstutzen":"In den Kanal wird ein Ausschnitt geschnitten. Der Stutzen wird eingesetzt, gepunktet oder geclincht und abgedichtet.","kd":"Der Kanal entsteht wie ein Standardkanal; die Drosselklappe wird danach eingebaut.","anschlusskasten":"Das Gehäuse wird abgewickelt, zugeschnitten, gekantet und gefalzt. Die Stutzen werden eingesetzt und gepunktet.","revision":"In den Kanal wird ein Ausschnitt geschnitten. Rahmen und Deckel werden gekantet, Dichtung und Verschluss kommen von Hand dazu.","dachhaube":"Haube, Sockel und Gitter werden zugeschnitten, gekantet, gerundet und gefügt.","wfr":"Das Wickelfalzrohr entsteht in einem Durchlauf: Das Band läuft vom Coil in die Maschine, die Bandkanten werden profiliert und die Sicken gerollt. Im Formkopf wird das Band gewickelt und der Falz geschlossen; das Rohr wird fliegend abgetrennt.","lnr":"Ein Zuschnitt wird gerundet und an der Längsnaht gefalzt oder geschweißt. Die Rohrenden erhalten Sicke, Lippendichtung oder Bördelrand.","segbogen":"Der Segmentbogen (90°, 45° oder als Etagenbogen) besteht aus flach zugeschnittenen, gerundeten Segmenten mit Längsnaht. Die Segmente werden gebördelt und über einen Umfangsfalz verbunden; die Enden erhalten Sicke und Lippendichtung.","pbogen":"Gepresste Formteile (Bogen 90° und 45°, T-Stück, Abzweig 45°) entstehen aus Halbschalen, die eine Presse mit Stempelform (Matrize) formt. Die Halbschalen werden durch Rollennahtschweißen gefügt, die Enden erhalten Sicke und Lippendichtung. Presse und Stempelform führen wir derzeit nicht im Programm.","tstueck":"Der Sattelstutzen (90° oder 45°) sitzt auf einem Grundrohr: In das Rohr wird eine Öffnung geschnitten, der Abzweig mit Sattelkontur zugeschnitten, gerundet und an der Längsnaht gefügt, aufgesetzt, gepunktet oder geclincht und abgedichtet. Die Enden erhalten Sicke und Lippendichtung.","reduz":"Die Reduzierung gibt es zentrisch und exzentrisch. Der Kegelmantel wird abgewickelt, zugeschnitten und gerundet, die Längsnaht geschweißt. Die Anschlussstücke werden über Umfangsfalze angefügt, die Enden erhalten Sicke und Dichtung.","enddeckel":"Eine Ronde und ein Ring werden zugeschnitten, der Ring gerundet und an der Längsnaht gefügt. Ronde und Ring werden gebördelt und geschlossen; Sicke und Dichtung schließen das Steckende ab.","nippel":"Nippel und Muffe sind kurze Rohrstücke: zuschneiden, runden, Längsnaht fügen, Sicke rollen und die Enden mit Dichtung versehen. Der Nippel verbindet zwei Rohre, die Muffe zwei Formstücke.","lippe":"Am Rohrende werden Stoppsicke und Dichtungssitz gerollt und die Rohrkante 90° umgebördelt. Die Dichtung wird aufgelegt, der Bord um sie gelegt und zugedrückt.","flex":"Das flexible Rohr wird gewickelt; Aluminiumrohre werden anschließend gestaucht.","kulisse":"Der Kulissenschalldämpfer besteht aus einem Gehäuse, das wie ein Rechteckkanal gefertigt wird, und den Schalldämpferkulissen darin.","tstueck90":"T-Stück, Abzweig 45°, Kreuzstück und T-Stück mit kleinerem Abgang haben drei oder vier Steckenden. Grundkörper und Abzweige werden zugeschnitten, gerundet und an der Längsnaht gefügt, dann miteinander gefügt und abgedichtet; die Enden erhalten Sicke und Lippendichtung.","retage":"Etagenstück und Übergang eckig entstehen auf demselben Weg: Seitenbleche und Mantelbleche werden abgewickelt, zugeschnitten und gekantet, über Pittsburgh-Falz verbunden und an beiden Enden mit Rahmen versehen. Das Etagenstück versetzt den Kanal, der Übergang verbindet zwei Querschnitte, einseitig oder symmetrisch.","hose":"Die Rohrgabelung teilt den Luftstrom auf zwei Abgänge mit Radien. Gefertigt wird sie wie der Rechteckbogen: Die Mäntel bekommen die Falztasche, die Seitenbleche den Bord, beide werden zusammengesteckt und über Längsfalze geschlossen. An der Spitze treffen die inneren Mäntel der Abgänge zusammen; alle drei Enden erhalten einen Rahmen.","hosenstueck":"Das Hosenstück teilt einen Querschnitt gerade auf zwei Abgänge nebeneinander, mit Abstand für die Rahmen. Seitenbleche und Mantelbleche werden zugeschnitten und gekantet, über Pittsburgh-Falz verbunden und an allen drei Enden mit Rahmen versehen.","skulisse":"Schalldämpferkulissen dämpfen den Schall in Lüftungsanlagen. Ein Rahmen aus verzinktem Stahlblech mit An- und Abströmprofil hält die Füllung aus Mineralwolle, Glasseide schützt sie vor Abrieb. Unsere Maschinen profilieren den Rahmen mit Radius statt Kante – das senkt den Druckverlust."},"kat":[{"id":"wfr","t":"Wickelfalzrohr","te":"Spiral duct","sym":"wfr","teile":["wfr"],"sp":1,"leit":{"m":"tf14","q":"V"}},{"id":"formrund","t":"Runde Formstücke","te":"Round fittings","sym":"segbogen","teile":["segbogen","tstueck90","reduz","enddeckel","lippe","pbogen"],"sp":1,"leit":{"m":"bogen","q":"V"},"alle":{"t":"Alle runden Formstücke","te":"All round fittings","txt":"Runde Formstücke entstehen aus Zuschnitten oder Rohrstücken: Mantel runden, Längsnaht schließen, Teile über Umfangsnähte fügen, die Enden mit Sicke und Lippendichtung versehen. Nähte sind entweder gefalzt – Wickelfalz am Rohr, Stehfalz zwischen den Segmenten eines Bogens – oder geschweißt: punktgeschweißt oder rollnahtgeschweißt. Gepresste Formteile bestehen aus zwei gepressten, rollnahtgeschweißten Halbschalen."},"alleOhne":["presse","varb"],"abgesetzt":["pbogen"],"hinweis":"Runde 17 (Dimi 11.11.2026, 16:23): Sattelstutzen beim T-Stück (gleiche Maschinen), Nippel und Muffe bei der Steckverbindung (Bauformen); gepresste Formteile abgesetzt wie „Alle …“. Text „Alle runden Formstücke“ ergänzt nach Prüfliste 19.9 b (freigegeben)."},{"id":"lnr","t":"Rundrohr mit Längsnaht","te":"Longitudinal seam pipe","sym":"lnr","teile":["lnr"],"sp":1,"leit":{"m":"pr","q":"V"}},{"id":"flex","t":"Flexible Lüftungsrohre","te":"Flexible ducts","sym":"flex","teile":["flex"],"sp":1,"leit":{"m":"spf250","q":"V"}},{"id":"kanal","t":"Rechteckkanal","te":"Rectangular duct","sym":"rk","teile":["rk","kurzkanal","passlaenge"],"sp":2,"leit":{"m":"mcl","q":"T"},"alleHinweis":"Dimi 11.11.2026 (Prüfliste 18.6): Kachel „Alle geraden Kanäle“ entfällt, die drei Bauteile haben dieselben Maschinen."},{"id":"formeckig","t":"Rechteckige Formstücke","te":"Rectangular fittings","sym":"rbogen","teile":["rbogen","rwinkel","retage","ruebergang","rboden"],"sp":2,"leit":{"m":"lc","q":"T"},"alle":{"t":"Alle rechteckigen Formstücke","te":"All rectangular fittings","txt":"Rechteckige Formstücke bestehen aus Mantel- und Seitenblechen, die über Längsfalze verbunden werden. An den Enden sitzen Rahmen, in Bögen und Winkeln Leitbleche."},"hinweis":"Runde 17 (Dimi 11.11.2026, 16:23): Rohrgabelung als Bauform des Rechteckbogens, Hosenstück als Bauform von Rechteckwinkel und T-Stück; „Stutzen auf Rechteckkanal“ entfällt."},{"id":"zubehoer","t":"Zubehör und Einbauteile","te":"Accessories and built-in parts","sym":"anschlusskasten","teile":["anschlusskasten","revision","dachhaube"],"sp":2,"leit":{"m":"mab","q":"M"},"alle":{"t":"Alles Zubehör","te":"All accessories","txt":"Zubehör und Einbauteile werden aus Blechen gekantet und mit Stutzen, Rahmen, Deckeln oder Gittern ergänzt."},"inaktiv":"In Arbeit"},{"id":"schall","t":"Kulissenschalldämpfer","te":"Splitter silencers","sym":"kulisse","teile":["kulisse","skulisse"],"sp":3,"gross":3,"leit":{"m":"pod","q":"V"},"folge":["pod","podr"],"prodVon":{"pod":"kulisse","podr":"skulisse"},"folgeHinweis":"Runde 18 (Dimi 11.11.2026, 22:43): in der großen Kachel nur die Kulissenmaschine und der Kulissenrollformer; oben wechselt das Produkt mit (Kulissenschalldämpfer, Schalldämpferkulisse)"}],"katsp":[{"sp":1,"t":"Rund","te":"Round"},{"sp":2,"t":"Eckig","te":"Rectangular"},{"sp":3,"t":"Schalldämpfer","te":"Silencers"}],"anw":[{"id":"anlagen","t":"Komplette Kanalanlagen","te":"Complete duct lines","v":["anlagen"],"leit":"mcl","paar":{"P38":"mcl","P45":"m3"},"prod":{"*":"b:rk"}},{"id":"kulissen","t":"Schalldämpferkulissen","te":"Splitter silencers","v":["kulissen"],"leit":"pod","paar":{"P35":"pod","P58":"podr"},"prod":{"pod":"b:kulisse","podr":"b:skulisse","*":"b:skulisse"}},{"id":"falzen","t":"Längsfalz und Rahmen","te":"Seams and frames","v":["falzen","profilieren"],"leit":"rfp5","paar":{"P09":"rfp5","P10":"fpfs","P13":"ds","P14":"rf","P04":"szp","P17":"pdfp","P64":"llb"},"prod":{"rfp5":"f:pittsburgh","rfp7":"f:pittsburgh","ds":"f:kanalfalz","rf":"f:steckrahmen","pdfp":"f:pdf3","rfs9":"f:schnappfalz","fpfs":"f:schnappfalz"}},{"id":"coil","t":"Coil-Handling","te":"Coil handling","v":["coil"],"leit":"has","paar":{"P02":"has","P36":"richt","P37":"richt","P03":"richt"}},{"id":"zuschnitt","t":"Zuschnitt","te":"Cut-to-length","v":["zuschnitt","scheren"],"leit":"zus","paar":{"P06":"zus","P15":"saege"}},{"id":"kanten","t":"Kanten","te":"Folding","v":["kanten"],"leit":"mab","paar":{"P11":"mab","P04d":"mab","P31":"mab"}},{"id":"wickeln","t":"Rohre wickeln","te":"Spiral tube forming","v":["wickeln"],"leit":"tf14","paar":{"P18":"tf14","P19":"tf16"},"prod":{"tf14":"b:wfr","tf16":"b:wfr","*":"b:flex"},"teile":[{"t":"Lüftung: Wickelfalzrohre","m":["tf14","tf16"]},{"t":"Andere Branchen: Hüll-, Flex- und Kaminrohre","m":["sr200","sr300","sr300xl","sr450","spfc","spf250","spf450"]}]},{"id":"rohranlagen","t":"Rohranlagen","te":"Pipe lines","v":["rohranlagen"],"leit":"pr","paar":{"P43":"pr","P44":"swa"},"prod":{"*":"b:lnr","pr":"f:hakenfalz"}},{"id":"bogen","t":"Segmentbögen","te":"Segmented elbows","v":["bogen"],"leit":"bogen","paar":{"P50":"cem","P24":"bogen"},"ruhe":"P24","prod":{"*":"b:segbogen"}},{"id":"runden","t":"Runden und Sicken","te":"Rolling and beading","v":["runden","sicken"],"leit":"gs","paar":{"P12":"rme","P25":"sick","P26":"gs","P33":"sick"}},{"id":"schneiden","t":"Laser und Plasma","te":"Laser and plasma cutting","v":["laser","plasma"],"leit":"lc","paar":{"P07L":"lc","P07":"pc","P08":"prot"},"ruhe":"P07L"},{"id":"absaugung","t":"Absauganlagen","te":"Extraction systems","v":["absaug"],"leit":"abs","paar":{"P67":"abs"}},{"id":"software","t":"CAD/CAM und Vernetzung","te":"CAD/CAM and connectivity","v":["software"],"paar":{"P01":"cutx"}},{"id":"schweissen","t":"Schweißen und Fügen","te":"Welding and joining","v":["schweissen","fuegen"],"leit":"sw","paar":{"P20":"sw","P21":"psm","P29":"trtf350"},"prod":{"*":"p:E20"}},{"id":"hand","t":"Handgeführte Werkzeuge","te":"Hand-held tools","v":["hand"],"paar":{"P40":"trs160","P41":"trc160","P42":"trf140","P29":"trtf350","P46":"trdd1010","P66":"trtpc165"},"leit":"trs160"}],"anwg":[{"id":"eckig","t":"Kanalbau eckig","te":"Rectangular ductwork","sp":1,"k":["anlagen","falzen","kulissen"],"u":"/maschinen/luftkanalbau-eckig","lt":"Vom Coil zum Rechteckkanal: Kanalanlagen, Profilierer für Längsfalz und Rahmen, Falzschließer und Maschinen für Schalldämpferkulissen.","le":"From coil to rectangular duct: duct lines, rollformers for seams and flanges, duct seamers and machines for attenuator pods."},{"id":"rund","t":"Kanalbau rund","te":"Round ductwork","sp":2,"k":["wickeln","rohranlagen","bogen","runden"],"u":"/maschinen/luftkanalbau-rund","lt":"Wickelfalzrohrmaschinen bis Ø 1.600 mm, Bogenautomaten für Segmentbögen und Maschinen zum Runden und Sicken.","le":"Tubeformers for round ducts up to Ø 1,600 mm, elbow makers for segmented elbows and machines for rolling and beading."},{"id":"blech","t":"Blechbearbeitung","te":"Sheet metal working","sp":3,"k":["coil","zuschnitt","kanten"],"u":"/maschinen/2mm-anlagen-coilhandling-blechzuschnitt","lt":"Coil abwickeln, richten, zuschneiden und kanten: Haspeln, Zuschnittanlagen, Tafelscheren und Schwenkbiegemaschinen.","le":"Decoiling, straightening, cutting to length and folding: decoilers, cut-to-length lines, guillotine shears and folding machines."},{"id":"cnc","t":"Schneiden und CNC","te":"Cutting and CNC","sp":4,"k":["schneiden","absaugung","software"],"u":"/maschinen/schneiden","lt":"Faserlaser und Plasmaschneidanlagen mit Absaugung, dazu CAD/CAM-Software und die Anbindung der Maschinen.","le":"Fibre lasers and plasma cutting systems with extraction, plus CAD/CAM software and machine connectivity."},{"id":"fuegen","t":"Fügen und Werkzeuge","te":"Joining and tools","sp":5,"k":["schweissen","hand"],"u":"/maschinen/luftkanalbau-eckig/formstueckbau-eckig/draht--und-punktschweissen","lt":"Draht- und Punktschweißmaschinen, Rohrschweißanlagen und handgeführte Werkzeuge zum Schneiden, Falzschließen und Fügen.","le":"Stitch and spot welders, pipe welding lines and hand-held tools for cutting, seam closing and joining."}],"stg":[{"id":"andere","t":"Andere Branchen","te":"Other industries","ks":"Andere","u":"/maschinen/metallrohrmaschinen","txt":"Hüll-, Flex- und Kaminrohre","m":["sr200","sr300","sr450","spf250","spf450","spfc","sr300xl"],"prod":{"*":"b:flex"},"lt":"Rohrmaschinen von DROSSBACH für Hüllrohre im Spannbetonbau sowie flexible Kamin- und Lüftungsrohre.","le":"Tube machines by DROSSBACH for post-tensioning ducts in prestressed concrete and for flexible chimney and ventilation pipes.","kurz":"Hüllrohre und flexible Rohre (DROSSBACH)","kurzE":"Post-tensioning ducts and flexible pipes (DROSSBACH)"}],"mbr":{"bogen":[0.154,0.087,0.852,0.922,1.667],"cem":[0.083,0.149,0.87,0.934,2.273],"cleco":[0,0.09,0.991,0.969,1.333],"ds":[0.037,0.29,0.946,0.862,1.333],"fpfs":[0.248,0.074,0.721,0.915,0.973],"gs":[0.113,0.125,0.84,0.875,1.442],"has":[0.083,0.08,0.863,0.9,1.5],"kan":[0,0,0.993,1,2.169],"lc":[0.07,0.061,0.93,0.939,1.775],"llb":[0.076,0.061,0.941,0.964,1.5],"m3":[0.027,0.085,0.92,0.945,1.5],"mab":[0.013,0.201,0.976,0.812,1.5],"mcl":[0.047,0.248,0.937,0.903,1.333],"msb":[0.069,0.17,0.931,0.98,1.8],"odin":[0,0,1,1,2.459],"pc":[0.02,0.212,0.993,0.846,1.333],"pdfa":[0,0.098,0.971,1,1.5],"pdfp":[0.018,0.094,0.999,0.964,1.5],"pod":[0,0.159,1,0.841,1.333],"podr":[0.104,0.212,0.885,0.782,1.0],"pr":[0,0,0.947,1,1.422],"prot":[0.015,0.02,0.996,0.956,2.169],"psm":[0.043,0.077,0.966,0.922,1.5],"rf":[0.026,0.19,0.988,0.897,1.5],"rfp5":[0.123,0.128,0.88,0.877,1.333],"rfp7":[0.198,0.166,0.802,0.812,1.295],"rfs9":[0.19,0.184,0.81,0.816,1.224],"richt":[0.037,0.138,0.785,0.99,1.773],"rme":[0,0.005,1,1,1.485],"sick":[0.307,0,0.693,1,1.629],"spf250":[0.017,0.065,0.98,0.942,1.863],"spf450":[0,0.064,0.99,0.93,1.852],"spfc":[0.12,0.027,0.89,1,1.017],"sr200":[0,0.061,0.968,0.904,1.417],"sr300":[0.087,0.08,0.85,0.982,1.415],"sr300xl":[0.037,0.065,0.983,0.941,1.887],"sr450":[0.067,0.058,0.957,0.929,1.863],"sw":[0.244,0.047,0.737,0.945,1.5],"swa":[0.013,0.011,0.993,0.993,1.049],"szp":[0.041,0.238,0.956,0.82,1.5],"tf14":[0.105,0.188,0.876,0.77,1.5],"tf16":[0.041,0.234,0.978,0.787,1.5],"trc160":[0.068,0.19,0.568,0.772,1.5],"trdd1010":[0.018,0.023,0.499,0.973,1.5],"trf140":[0.057,0.073,0.549,0.877,1.5],"trf300":[0.045,0.07,0.37,0.9,1.5],"trs160":[0.04,0.165,0.557,0.818,1.5],"trtf350":[0.046,0.044,0.485,0.927,1.5],"zus":[0,0,1,1,1.216],"pdfk":[0.042,0.047,0.975,0.992,1.417],"varb":[0.028,0.009,0.978,0.987,1.614],"gsa":[0.139,0.037,0.803,0.971,1.5],"m3z":[0.011,0.054,0.978,0.922,1.756],"m3b":[0.05,0.043,0.95,0.978,1.304],"pfs":[0.406,0.028,0.647,0.995,1.667],"pfsw":[0.131,0.093,0.922,0.949,1.667],"hfp":[0.19,0.184,0.81,0.816,1.224],"tbp":[0.123,0.128,0.88,0.877,1.333],"trc250":[0.063,0.185,0.55,0.78,1.5],"trs250":[0.07,0.155,0.567,0.825,1.5],"trtpc165":[0.047,0.14,0.49,0.88,1.5]},"elem":{"formrund":[{"id":"mantel","t":"Mantel","te":"Body"},{"id":"laengs","t":"Längsnaht","te":"Longitudinal seam"},{"id":"umfang","t":"Umfangsnaht","te":"Circumferential seam"},{"id":"enden","t":"Enden und Verbinder","te":"Ends and connectors"}],"formeckig":[{"id":"bleche","t":"Mantel- und Seitenbleche","te":"Wrapper and cheek sheets"},{"id":"falz","t":"Längsfalz","te":"Longitudinal seam"},{"id":"rahmen","t":"Rahmen und Anschlüsse","te":"Frames and connections"},{"id":"leit","t":"Leitbleche","te":"Turning vanes"},{"id":"dicht","t":"Abdichtung","te":"Sealing"}],"kanal":[{"id":"mantel","t":"Mantel mit Versteifung","te":"Duct wall with stiffening"},{"id":"falz","t":"Längsfalz","te":"Longitudinal seam"},{"id":"rahmen","t":"Rahmenverbindung","te":"Flange connection"},{"id":"dicht","t":"Dichtung","te":"Sealing"}],"zubehoer":[{"id":"gehaeuse","t":"Gehäuse und Bleche","te":"Casing and sheets"},{"id":"oeffnung","t":"Ausschnitte und Stutzen","te":"Cut-outs and collars"},{"id":"rahmen","t":"Rahmen, Deckel und Gitter","te":"Frames, covers and grilles"},{"id":"dicht","t":"Dichtung und Verschluss","te":"Seal and lock"}]},"bel":{"segbogen":["mantel","laengs","umfang","enden"],"tstueck90":["mantel","mantel","umfang","enden","laengs"],"tstueck":["mantel","mantel","umfang","enden","laengs"],"reduz":["mantel","mantel","umfang","enden","laengs"],"enddeckel":["mantel","mantel","umfang","enden","laengs"],"nippel":["mantel","laengs","enden","enden"],"lippe":["enden","enden","enden","enden","mantel","laengs"],"pbogen":["mantel","laengs","enden"],"rbogen":["bleche","bleche","falz","rahmen","leit"],"hose":["bleche","bleche","falz","falz","rahmen"],"hosenstueck":["bleche","bleche","falz","rahmen"],"rwinkel":["bleche","bleche","falz","rahmen","leit"],"retage":["bleche","bleche","falz","rahmen"],"ruebergang":["bleche","falz","rahmen","rahmen"],"rboden":["bleche","rahmen"],"rstutzen":["bleche","rahmen","rahmen"],"rk":["mantel","falz","rahmen","dicht","mantel"],"kurzkanal":["mantel","falz","rahmen","dicht","mantel"],"passlaenge":["mantel","falz","rahmen","rahmen","dicht","mantel"],"anschlusskasten":["gehaeuse","oeffnung","rahmen"],"revision":["oeffnung","rahmen","rahmen"],"dachhaube":["gehaeuse","gehaeuse","rahmen"]},"rel":{"rbogen":"dicht","hose":"dicht","hosenstueck":"dicht","retage":"dicht","rstutzen":"dicht"},"sel":{"tstueck90":{"2":"laengs","6":"laengs"},"tstueck":{"4":"laengs"},"reduz":{"3":"laengs"},"enddeckel":{"3":"laengs"},"revision":{"2":"dicht"}},"mel":{"formeckig":{"mab":"bleche"},"formrund":{"sick":"enden"},"zubehoer":{"mab":"gehaeuse"}},"prof":{"pdf1":{"t":"PDF 1","teile":[{"p":[[31.18,87.41],[31.29,36.73],[30.95,35.26],[29.25,34.47],[28.8,33.56],[28.8,24.04],[29.02,23.24],[30.05,22.79],[76.98,22.9],[77.55,23.24],[77.78,24.49],[77.66,30.39],[77.44,31.29],[75.17,35.15],[74.94,36.85],[75.28,37.87],[75.85,38.44],[77.32,39.0],[78.91,38.66],[79.93,37.3],[80.27,24.72]],"d":2.268,"r":"blech"}],"raupe":null,"box":[28.8,22.8,80.3,87.4]},"pdf1s":{"t":"PDF 1 Super","teile":[{"p":[[34.4,20.34],[23.44,20.34],[21.3,20.82],[20.22,21.89],[19.63,24.51],[19.63,35.59],[20.1,37.85],[21.77,38.92],[23.8,38.57],[24.51,37.73],[24.87,36.42],[24.51,34.99],[22.61,31.78],[22.13,30.23],[22.01,24.63],[22.25,23.32],[22.73,22.84],[24.04,22.61],[69.18,22.61],[70.84,23.2],[71.08,24.27],[70.96,33.92],[70.61,34.4],[68.94,35.11],[68.58,36.66],[68.46,87.52]],"d":2.144,"r":"blech"}],"raupe":null,"box":[19.6,20.3,71.1,87.5]},"pdf2":{"t":"PDF 2","teile":[{"p":[[67.41,66.3],[67.53,51.73],[67.28,50.37],[53.95,33.21],[51.85,31.11],[50.37,30.25],[48.52,29.75],[33.46,29.88],[32.72,30.25],[26.3,36.67],[24.81,37.28],[23.21,37.16],[22.22,36.42],[21.6,33.95],[21.6,23.09],[22.1,20.99],[22.96,20.49],[68.15,20.37],[69.51,21.11],[69.88,22.47],[69.75,85.43]],"d":2.222,"r":"blech"}],"raupe":null,"box":[21.6,20.4,69.9,85.4]},"pdf3":{"t":"PDF 3","teile":[{"p":[[29.8,85.01],[29.92,76.57],[30.41,74.24],[31.15,73.63],[34.21,72.89],[35.68,71.91],[36.9,69.59],[37.02,68.24],[37.02,55.39],[36.78,54.04],[35.8,53.67],[34.94,54.04],[34.7,54.9],[34.7,67.87],[34.45,69.47],[33.96,70.32],[32.74,70.81],[31.88,70.81],[30.41,69.96],[30.04,68.73],[29.92,22.82],[30.41,20.86],[31.02,20.37],[32.13,20.13],[76.81,20.25],[77.79,20.98],[78.16,22.7],[78.04,34.94],[77.79,35.8],[77.06,36.66],[75.95,37.02],[74.24,36.9],[67.14,30.04],[65.67,29.55],[51.35,29.55],[49.51,30.04],[47.92,30.9],[45.96,32.86],[32.62,50.0],[32.37,50.98],[32.25,65.92]],"d":2.204,"r":"blech"}],"raupe":null,"box":[29.8,20.1,78.2,85.0]},"kanalfalz":{"t":"Kanalfalz (DS)","teile":[{"p":[[67.27,14.86],[67.15,55.12],[66.67,57.03],[66.08,57.5],[64.41,57.86],[39.16,57.74],[38.21,57.5],[37.49,56.67],[37.14,54.76],[37.26,51.91],[37.97,50.24],[40.59,49.64],[59.05,49.64]],"d":2.859,"r":"blech"},{"p":[[41.07,53.93],[60.24,53.81],[62.03,53.45],[62.86,52.38],[63.1,50.71],[62.74,46.67],[61.91,45.95],[59.89,45.59],[35.23,45.71],[34.28,45.95],[33.33,46.78],[32.97,49.05],[32.97,55.48],[32.73,56.55],[32.02,57.5],[30.23,57.86],[9.15,57.98]],"d":2.859,"r":"blech2"}],"raupe":null,"box":[9.2,14.9,67.3,58.0]},"kanalfalz_lock":{"t":"Kanalfalz (Poster Lock seam)","teile":[{"p":[[43.99,19.68],[43.92,48.93],[43.69,49.08],[27.28,49.08],[26.9,48.55],[26.9,45.06],[27.36,44.45],[39.36,44.45]],"d":1.368,"r":"blech"},{"p":[[9.27,49.16],[24.39,49.08],[24.62,48.86],[24.62,42.7],[25.08,42.09],[41.33,42.09],[41.64,42.4],[41.64,46.5],[41.41,46.73],[29.18,46.8]],"d":1.368,"r":"blech2"}],"raupe":null,"box":[9.3,19.7,44.0,49.2]},"pittsburgh":{"t":"Pittsburghfalz","teile":[{"p":[[56.0,14.51],[56.0,27.28],[56.15,27.43],[62.53,27.43],[62.91,27.96],[62.91,43.99],[62.61,44.45],[60.78,44.45],[60.56,44.14],[60.56,30.24],[60.18,29.71],[56.3,29.71],[56.0,29.86],[55.92,48.78],[56.23,49.08],[64.74,49.08]],"d":1.368,"r":"blech"},{"p":[[58.35,32.06],[58.28,46.5],[58.51,46.73],[85.4,46.73]],"d":1.368,"r":"blech2"}],"raupe":null,"box":[55.9,14.5,85.4,49.1]},"wickelfalz":{"t":"Wickelfalz","teile":[{"p":[[43.61,65.65],[59.04,65.57],[59.26,65.19],[59.26,61.39],[58.89,60.94],[39.51,60.94],[39.06,61.54],[39.06,64.2],[38.83,64.43],[19.61,64.51]],"d":1.368,"r":"blech"},{"p":[[80.23,64.43],[61.92,64.43],[61.62,64.73],[61.62,67.39],[61.24,67.93],[41.79,67.93],[41.33,67.39],[41.33,63.9],[41.79,63.29],[57.06,63.29]],"d":1.368,"r":"blech2"}],"raupe":null,"box":[19.6,60.9,80.2,67.9]},"steckrahmen":{"t":"Steckrahmenprofil (eigenes Modell)","teile":[{"p":[[25.6,64.0],[25.6,22.6],[26.1,20.9],[27.6,20.2],[76.6,20.2],[77.8,20.9],[78.2,22.6],[78.2,33.6],[77.6,35.6],[75.9,36.7],[74.3,36.5],[67.2,29.9],[65.6,29.4],[51.3,29.4],[49.4,29.9],[47.8,30.9],[45.9,32.9],[35.9,46.0],[35.2,47.8],[35.2,61.2],[36.9,64.6]],"d":2.2,"r":"profil"},{"p":[[30.4,92.0],[30.4,43.0]],"d":2.2,"r":"wand"}],"raupe":[30.4,41.2,1.7],"box":[25.6,20.2,78.2,92.0]},"schnappfalz":{"t":"Schnappfalz","teile":[{"p":[[50,14],[50,47.2],[50.4,48.4],[51.15,48.8],[51.9,48.4],[52.3,47.2],[52.3,32.2],[52.9,30.6],[54.2,29.8],[56.4,29.8],[57.7,30.6],[58.3,32.2],[58.3,47.4],[57.9,48.5],[57.2,48.9],[56.5,48.4],[56.2,47.2],[55.5,42.2]],"d":1.368,"r":"blech"},{"p":[[80,51.2],[55.2,51.2],[54.4,50.4],[54.2,49.2],[54.2,34.5]],"d":1.368,"r":"blech2"},{"p":[[54.2,37.2],[55.9,41.2]],"d":1.368,"r":"blech2"}],"raupe":null,"box":[50,14,80,51.2]},"hakenfalz":{"t":"Hakenfalz","teile":[{"p":[[36,51.8],[55,51.8],[56.8,51.1],[57.6,49.2],[56.8,47.3],[55,46.6],[44.5,46.6]],"d":1.368,"r":"blech"},{"p":[[64,44],[45,44],[43.2,44.7],[42.4,46.6],[43.2,48.5],[45,49.2],[55.5,49.2]],"d":1.368,"r":"blech2"}],"raupe":null,"box":[36,44,64,51.8]},"segfalz":{"t":"Stehfalz am Segmentbogen","teile":[{"p":[[36,58],[49.2,58],[50,57.2],[50,44.8],[50.8,44],[52.8,44],[53.6,44.8],[53.6,53.4]],"d":1.368,"r":"blech"},{"p":[[66,58],[52.6,58],[51.8,57.2],[51.8,46.4]],"d":1.368,"r":"blech2"}],"raupe":null,"box":[36,44,66,58]},"rollnaht":{"t":"Rollnaht","teile":[{"p":[[36,51],[53.5,51]],"d":1.368,"r":"blech"},{"p":[[46.5,49.4],[64,49.4]],"d":1.368,"r":"blech2"}],"raupe":[50,50.2,1.25],"box":[36,47,64,54]},"umfangsnaht":{"t":"Umfangsnaht, punktgeschweißt","teile":[{"p":[[35,52],[56,52]],"d":1.368,"r":"blech"},{"p":[[67,52],[61.5,52],[60.6,51.6],[59.4,50.8],[58.4,50.4],[43,50.4]],"d":1.368,"r":"blech2"}],"raupe":[50.5,51.2,1.2],"box":[35,47,67,55]}},"klay":{"_alle":{"stufeMin":{"k:schneiden":"T","pdfp":"T","zus":"T","gsa":"V"},"tagText":{"k:schneiden":"CNC"}},"formrund":{"zeilen":[{"el":"mantel","g":[["k:schneiden","k:elektro"],["rme","roll"],["presse"]]},{"el":"laengs","g":[["psm","sw"],["varb"]]},{"el":"umfang","i":"Segmentbogen: gefalzt (Stehfalz und Doppelstehfalz, verpresst). Übrige Formstücke: mit der Sickenmaschine geformt und punktgeschweißt.","g":[["sick","psm"],["=cemeco","=cem"],["bogen"]]},{"el":"enden","g":[["sick","=gs","=gsa"]]}]},"lnr":{"zeilen":[{"k":0,"g":[["msb","zus"],["rme","pr"]]},{"k":1,"g":[["hfp","hfz"],["psm","sw"],[{"m":"swa","hoch":1}]]},{"k":2,"g":[["sick","=gs","=gsa"]]}]},"kanal":{"sr":{"zeilen":[{"el":"mantel","g":[["msb","szp","mab"],["mcl","cleco",{"m":"odin","zusatz":"SPEZIAL"}]]},{"el":"falz","g":[[{"m":["rfp5","rfp7","rfs9","rfsc","hfp"],"t":"Falzprofilieranlagen"},"k:elektro"],["ds"]]},{"el":"rahmen","g":[["saege","k:elektro","psm"],["rf"]]}]},"pdf":{"reihe":["mantel","rahmen","falz","dicht"],"zeilen":[{"el":"mantel","g":[["k:schneiden","szp","pdfk"],[{"m":"m3z","zeig":{"pid":"rkflach1","ks":[0,1],"t":"Stufe 1: Mantelzuschnitt"}}],[{"m":"pdfa","zeig":{"pid":"rk","ks":"alle","t":"Alle Elemente in einer Anlage"}}]]},{"el":"rahmen","g":[[{"m":"pdfp","zeig":{"pid":"rkflach2","ks":[2],"t":"Stufe 2: Rahmenverbindung am flachen Blech"}}]]},{"el":"falz","g":[[{"m":["rfp5","rfp7","rfs9","rfsc","hfp"],"t":"Falzprofilieranlagen"},"k:elektro"],[{"m":"m3b","zeig":{"pid":"rk","ks":[1,4],"t":"Stufe 3: Kanten und Längsfalz schließen"}}],[{"m":["pfs","pfsw"]}]]}]}},"formeckig":{"sr":{"zeilen":[{"el":"bleche","g":[["k:schneiden","msb","k:elektro"],["szp"],["mab","rme"]]},{"el":"falz","g":[[{"m":["rfp5","rfp7","rfs9","rfsc","hfp"],"t":"Falzprofilieranlagen"},"fpfs"],["psm","hfz","k:elektro"]],"ohne":["mab"]},{"el":"rahmen","g":[["saege","k:elektro","psm"],["rf"]],"ohne":["rme"]},{"el":"leit","g":[["llb"]]}]},"pdf":{"reihe":["bleche","rahmen","falz","leit","dicht"],"zeilen":[{"el":"bleche","g":[["k:schneiden","msb","k:elektro"],["szp"],["mab","rme"]]},{"el":"rahmen","g":[["pdfp"]],"ohne":["rme"]},{"el":"falz","g":[[{"m":["rfp5","rfp7","rfs9","rfsc","hfp"],"t":"Falzprofilieranlagen"},"fpfs"],["psm","hfz","k:elektro"]],"ohne":["mab"]},{"el":"leit","g":[["llb"]]}]}},"skulisse":{"zeilen":[{"k":[0,1,5],"t":"Kulissenrahmen und Kammerblech","g":[["k:schneiden","msb","k:elektro"]],"bild":{"pid":"skulisse","ks":[0,1,5,6]}},{"k":[6],"t":"Rahmenprofil","g":[["mab","podr"],[{"m":"pod","hoch":1}]],"bild":{"pid":"skulisse","ks":[6]}},{"k":2,"t":"T-Bügel-Profil","g":[["mab","tbp"]]}]},"kulisse":{"wie":"skulisse"},"schall":{"wie":"skulisse"}},"kziel":{"hose":{"p":"rbogen","v":2},"hosenstueck":{"p":"rwinkel","v":2},"nippel":{"p":"lippe","v":1},"tstueck":{"p":"tstueck90","v":0},"rstutzen":{"p":"rk","v":0}},"bfn":{"segbogen":["Segmentbogen 90°","Segmentbogen 45°","Etagenbogen"],"tstueck90":["T-Stück 90°","Abzweig 45°","Kreuzstück","T-Stück reduziert"],"reduz":["Reduzierung zentrisch","Reduzierung exzentrisch","Gerades Rohrstück"],"lippe":["Steckverbindung","Nippel","Muffe"],"pbogen":["Gepresster Bogen 90°","Gepresster Bogen 45°","Gepresstes T-Stück","Gepresster Abzweig 45°"],"rbogen":["Rechteckbogen","Etagenstück mit Radien","Rohrgabelung"],"rwinkel":["Rechteckwinkel","T-Stück","Hosenstück"],"retage":["Etagenstück gekantet","Übergang einseitig","Übergang symmetrisch"]},"kna":{"pbogen":"Gepresst"},"mm":{"trc160":[357,88],"trc250":[398,119],"trs160":[295,156],"trs250":[325,188],"trf140":[321,257],"trf300":[285,406],"trtf350":[454,358],"trtpc165":[493,231],"trdd1010":[295,156]}};
var KAT = {"mcl":{"mb":"Modulare Kanalanlage","ty":"MCL Ultra","b":"WAMMES","u":"/maschinen/luftkanalbau-eckig/kanalfertigung-mit-steckrahmenprofil/modulare-kanalanlage-mcl-ultra","i":"/media/2f4bf186-3c92-4237-b6a8-80256dbd0c83/kanalstrasse.png","be":"Rechteckig"},"cleco":{"mb":"Kanalanlage","ty":"CL Eco","b":"WAMMES","u":"/maschinen/luftkanalbau-eckig/kanalfertigung-mit-steckrahmenprofil/kanalanlage-eco","i":"/media/a05277a3-bf01-48ba-8713-34a1fea956c8/kanalstrasse-eco.png","be":"Rechteckig"},"odin":{"mb":"Erweiterung der MCL Ultra mit Plasma","ty":"ODIN","b":"WAMMES","u":"/maschinen/luftkanalbau-eckig/kanalfertigung-mit-steckrahmenprofil/vollautomatische-kanalanlage-odin","i":"/media/a6c5f994-8335-4384-8fd7-a56d1e4c50ca/dsc_01421-1430x580.jpg","be":"Rechteckig"},"rf":{"mb":"Profilieranlage für Steckrahmenprofile","ty":"[Name folgt]","b":"WAMMES","u":"/maschinen/luftkanalbau-eckig/kanalfertigung-mit-steckrahmenprofil/profilierer-fuer-rahmenprofile-rf-2030","i":"/media/beeadc2d-388c-4f30-b6e7-8f4085f602b0/profilierer-rahmenprofile-rf-20-30.jpg","be":"Rechteckig"},"saege":{"mb":"Säge für Steckrahmenzuschnitt","ty":"[Name folgt]","b":"WAMMES","u":"","i":"","be":"Rechteckig"},"ds":{"mb":"Falzschließer","ty":"DS","b":"WAMMES","u":"/maschinen/luftkanalbau-eckig/kanalfertigung-mit-steckrahmenprofil/falzschliesser-ds","i":"/media/90e5985a-c620-473c-9a2d-bb2efbded211/ds-neu.png","be":"Rechteckig"},"m3":{"mb":"Maschinenverbund","ty":"3-Maschinen-System","b":"WAMMES","u":"/maschinen/luftkanalbau-eckig/kanalfertigung-mit-integriertem-pdf-flansch/3-maschinen-system","i":"/media/1e5f3ac7-085a-41e2-8831-2b613e9fb2b7/3-maschinen-system.jpg","be":"Rechteckig"},"pdfa":{"mb":"Automatische Kanalanlage","ty":"PDF [Name folgt]","b":"WAMMES","u":"/maschinen/luftkanalbau-eckig/kanalfertigung-mit-integriertem-pdf-flansch/vollautomatisches-maschinensystem","i":"/media/85249b69-4599-4154-84ca-8a5c24caacfb/vollautomatisches-maschinensystem-pdf.jpg","be":"Rechteckig"},"pdfp":{"mb":"PDF-Flansch-Profilierer","ty":"[Name folgt]","b":"WAMMES","u":"/maschinen/luftkanalbau-eckig/kanalfertigung-mit-integriertem-pdf-flansch/profilierer","i":"/media/f43aa6ea-baf4-48bd-b56d-8fd462013b7f/profilierer-pdf-bearbeitet.jpg","be":"Rechteckig"},"rfp5":{"mb":"Pittsburgh Profilierer","ty":"","b":"WAMMES","u":"/maschinen/luftkanalbau-eckig/formstueckbau-eckig/pittsburgh-schnappfalz/pittsburgh-profilierer-rfp-5","i":"/media/27c9d0c0-32c6-4123-b277-c268c55825bb/img_62901-jpg.jpg","be":"Rechteckig"},"rfp7":{"mb":"Pittsburgh Profilierer","ty":"","b":"WAMMES","u":"/maschinen/luftkanalbau-eckig/formstueckbau-eckig/pittsburgh-schnappfalz/pittsburgh-profilierer-rfp-7","i":"/media/57c58b06-fc0b-4cc7-b224-3e5301575655/rfp-7_2.jpg","be":"Rechteckig"},"rfs9":{"mb":"Schnappfalz Profilierer","ty":"","b":"WAMMES","u":"/maschinen/luftkanalbau-eckig/formstueckbau-eckig/pittsburgh-schnappfalz/schnappfalz-profilierer-rfs-9","i":"/media/dc5e28ae-2c8b-4f9a-9c3e-0a4945945d2c/rfs-9_2.jpg","be":"Rechteckig"},"rfsc":{"mb":"S-Cleat Profilierer","ty":"","b":"WAMMES","u":"/maschinen/luftkanalbau-eckig/formstueckbau-eckig/pittsburgh-schnappfalz/s-cleat-profilierer-rfsc-9-rfssc-12","i":"/media/dc5e28ae-2c8b-4f9a-9c3e-0a4945945d2c/rfs-9_2.jpg","be":"Rechteckig"},"fpfs":{"mb":"Pittsburgh und Schnappfalz Bördler","ty":"","b":"WAMMES","u":"/maschinen/luftkanalbau-eckig/formstueckbau-eckig/pittsburgh-schnappfalz/pittsburgh-und-schnappfalz-boerdler-fpfs","i":"/media/47d41f56-237b-47f2-bec8-0a4f7469ed45/boerdlerfsfp.jpg","be":"Rechteckig"},"mab":{"mb":"Schwenkbiegemaschinen","ty":"MAB","b":"Schechtl","u":"/maschinen/luftkanalbau-eckig/formstueckbau-eckig/kanten--schneiden--versteifen/schwenkbiegemaschinen","i":"/media/d25dacf9-f731-4ac5-958c-d19d1fa538b0/schechtl-mab.jpg","be":"Rechteckig"},"szp":{"mb":"Z-Profiliermaschinen","ty":"SZP","b":"Schechtl","u":"/maschinen/luftkanalbau-eckig/formstueckbau-eckig/kanten--schneiden--versteifen/z-profiiliermaschinen","i":"/media/0f3ecc6c-6773-4c50-920d-7fcc2b177ffc/szp-310.jpg","be":"Rechteckig"},"llb":{"mb":"Profilierer für Luftleitbleche","ty":"[Name folgt]","b":"WAMMES","u":"/maschinen/luftkanalbau-eckig/formstueckbau-eckig/sonderanwendungen/profilierer-fuer-luftleitbleche","i":"/media/476c674d-bc1f-451a-b48c-21519bbf2f95/leitblech-rf.jpg","be":"Rechteckig"},"tf14":{"mb":"Wickelfalzrohrmaschine","ty":"TF 1401 Ultra","b":"WAMMES","u":"/maschinen/luftkanalbau-rund/rohrfertigung-mit-wickelfalz/tubeformer-tf-1401-ultra","i":"/media/9bcfdadd-d3b7-4580-b7ca-d63b44f05998/wickelfalzrohrmaschine-wickelfalz-rohr-tf-1401-1112.jpg","be":"Rund"},"tf16":{"mb":"Wickelfalzrohrmaschine","ty":"TF 1600 Ultra","b":"WAMMES","u":"/maschinen/luftkanalbau-rund/rohrfertigung-mit-wickelfalz/tubeformer-tf-1600-ultra","i":"/media/642a2ecd-73fc-4644-b884-0a827b655186/wickelfalzrohrmaschine-tf-1600-ultra.jpg","be":"Rund"},"pr":{"mb":"Automatische Rohranlage","ty":"PR 300/1000","b":"WAMMES","u":"/maschinen/luftkanalbau-rund/rundrohrfertigung/automatische-rohranlage-pr-300-1000","i":"/media/b187b384-9adb-440f-8345-ae6c487a5017/pr300-1000-1.jpg","be":"Rund"},"swa":{"mb":"Automatische Rohrschweißanlage","ty":"","b":"WAMMES","u":"/maschinen/luftkanalbau-rund/rundrohrfertigung/automatische-rohrschweissanlage-swa-400","i":"/media/8d65715b-7fc8-4983-8d84-45f1830814c1/ng_titelbild.jpg","be":"Rund"},"bogen":{"mb":"Bogenautomat","ty":"","b":"WAMMES","u":"/maschinen/luftkanalbau-rund/formstueckbau-rund/segmentbogenmaschinen/bogenautomat-a100-a350","i":"/media/a573e02a-8316-4193-a8c9-50952d5b0bcb/bogenautomat-a100-a350-karte.jpg","be":"Rund"},"cem":{"mb":"Segmentbogenmaschine, hydraulisch","ty":"CEM Ultra","b":"WAMMES","u":"/maschinen/luftkanalbau-rund/formstueckbau-rund/segmentbogenmaschinen/cem-ultra-hydraulik","i":"/media/6bf88abb-d717-4470-920b-cfc2b831729b/cem-h-2025.jpg","be":"Rund"},"cemeco":{"mb":"Segmentbogenmaschine, pneumatisch","ty":"CEM Eco","b":"WAMMES","u":"/maschinen/luftkanalbau-rund/formstueckbau-rund/segmentbogenmaschinen/cem-ultra-pneumatik","i":"/media/af454641-78f0-41ae-a6d7-cf4546e578e1/cem-pneu.png","be":"Rund"},"roll":{"mb":"Rollformer","ty":"[Name folgt]","b":"WAMMES","u":"","i":"","be":"Rund"},"rme":{"mb":"Rundbiegemaschinen","ty":"","b":"WAMMES","u":"/maschinen/luftkanalbau-rund/formstueckbau-rund/3-walzen-rundmaschine","i":"/media/ad8e1347-35da-48d5-9cb0-36f9f81bc452/rundbiegemaschine-rme.jpg","be":"Rund"},"hyl":{"mb":"Rundbiegemaschinen","ty":"[Modelle folgen]","b":"WAMMES","u":"","i":"","be":"Rund"},"sick":{"mb":"Sickenmaschinen","ty":"[Modelle folgen]","b":"WAMMES","u":"/maschinen/luftkanalbau-rund/formstueckbau-rund/sickenmaschinen","i":"/media/4fbb1709-26a7-4377-a1b3-76c51e292c8d/sickenmaschine.jpg","be":"Rund"},"gs":{"mb":"Gasket Shaper","ty":"Universal","b":"WAMMES","u":"/maschinen/luftkanalbau-rund/formstueckbau-rund/gasket-shaper","i":"/media/ce836192-caac-456c-ba6d-085667e3c37f/gasket_shaper_gs-u_2_format_website-jpg.jpg","be":"Rund"},"msb":{"mb":"Tafelscheren","ty":"MSB","b":"Schechtl","u":"/maschinen/luftkanalbau-eckig/formstueckbau-eckig/kanten--schneiden--versteifen/tafelscheren","i":"/media/7d40d85f-bd6a-4490-9afb-980813a234ca/msb_310_gesamtansicht.jpg","be":"Schneiden"},"pc":{"mb":"Plasmaschneidanlage","ty":"PC 1500","b":"WAMMES","u":"/maschinen/schneiden/plasmaschneidanlage-pc-1500","i":"/media/75bb6859-9f4d-4f5a-9880-9c5eb681cafe/pc1500hs.jpg","be":"Schneiden"},"prot":{"mb":"Plasma mit Rotationsschneiden","ty":"[Name folgt]","b":"WAMMES","u":"/maschinen/schneiden/plasma-mit-rotationsschneiden","i":"/media/c7122595-3c91-4910-ac6c-c1400b330d60/plasma-3-clean-png.png","be":"Schneiden"},"hyp":{"mb":"Plasmaquellen","ty":"Powermax","b":"Hypertherm","u":"","i":"/media/376c2596-16e0-4710-8dcd-311781ea8fc3/hypertherm-powermax.jpg","be":"Schneiden"},"lc":{"mb":"Faserlaser","ty":"Laser Compact","b":"WAMMES","u":"/maschinen/schneiden/laser/laser-compact","i":"/media/a39370a9-65d0-4db9-b524-170d42f02f18/vanad-kompakt.jpg","be":"Schneiden"},"leco":{"mb":"Faserlaser","ty":"Laser ECO","b":"WAMMES","u":"/maschinen/schneiden/laser/laser-eco","i":"","be":"Schneiden"},"abs":{"mb":"Absaug- und Filteranlagen","ty":"[Modelle folgen]","b":"Sideros","u":"","i":"/media/f7442ad6-91d9-482d-aaa2-78e0d9c3ae14/sideros-absauganlage.jpg","be":"Schneiden"},"sw":{"mb":"Drahtschweißmaschine","ty":"","b":"WAMMES","u":"/maschinen/luftkanalbau-eckig/formstueckbau-eckig/draht--und-punktschweissen/drahtschweissmaschine-sw-1000","i":"/media/0b2e3b38-f9da-408b-972d-2e24d21bd026/drahtschweissmaschine-sw-1000.jpg","be":"Schweißen"},"psm":{"mb":"Punktschweißmaschinen","ty":"[Modelle folgen]","b":"WAMMES","u":"/maschinen/luftkanalbau-eckig/formstueckbau-eckig/draht--und-punktschweissen/punktschweissmaschinen","i":"/media/a01aefd0-f1f5-452c-b603-899cdad8a1ee/punktschweissmaschine-pbp.jpg","be":"Schweißen"},"psz":{"mb":"Punktschweißzangen","ty":"[offen]","b":"WAMMES","u":"","i":"","be":"Schweißen"},"has":{"mb":"Abwickelhaspel auf Schienen","ty":"[Typ folgt]","b":"WAMMES","u":"/maschinen/2mm-anlagen-coilhandling-blechzuschnitt/abwickelhaspel-auf-schienen","i":"/media/b5620ba6-6666-4feb-9632-09e2171050c1/haspel5t.jpg","be":"Coil-Handling"},"besch":{"mb":"Beschickungsanlagen","ty":"[offen]","b":"WAMMES","u":"","i":"","be":"Coil-Handling"},"richt":{"mb":"Richt-, Vorschub- und Selektiereinheiten","ty":"[Typ folgt]","b":"WAMMES","u":"/maschinen/2mm-anlagen-coilhandling-blechzuschnitt/richt--vorschub--und-selektiereinheiten","i":"/media/f405e72e-d2e5-4593-9b8a-6429d08ced25/pf-coil-2.jpg","be":"Coil-Handling"},"zus":{"mb":"Zuschnittanlage","ty":"2 mm","b":"WAMMES","u":"/maschinen/2mm-anlagen-coilhandling-blechzuschnitt/2mm-zuschnittanlage","i":"/media/a9f9d669-21f1-4803-ae02-521cd51ccc6a/saf.png","be":"Coil-Handling"},"kan":{"mb":"Kanalbau geschweißte Kanäle","ty":"2 mm","b":"WAMMES","u":"/maschinen/2mm-anlagen-coilhandling-blechzuschnitt/2mm-kanalbau-geschweisste-kanaele","i":"/media/29f09526-73bd-4130-91ed-e58bbcb6ca3f/2mm-odin.png","be":"Coil-Handling"},"pod":{"mb":"Schalldämpferkulissenmaschine","ty":"[Typ folgt]","b":"WAMMES","u":"/maschinen/schalldaempferkulissen/schalldaempferkulissen-maschine","i":"/media/84209cc4-ac40-4edd-86a1-23500d1fd7b7/pod.jpg","be":"Schalldämpfer"},"podr":{"mb":"Schalldämpferkulissenrollformer","ty":"[Typ folgt]","b":"WAMMES","u":"/maschinen/schalldaempferkulissen/schalldaempferkulissenrollformer","i":"/media/8afaa246-2972-455c-81c4-c97c0fe9dd33/aps-rf.jpg","be":"Schalldämpfer"},"sr200":{"mb":"Hüllrohrmaschine","ty":"SR 200-T2","b":"DROSSBACH","u":"/maschinen/metallrohrmaschinen/huellrohrmaschine-drossbach-sr-200-t2","i":"/media/9d028c1b-c6d1-4c23-8168-8beadf5efb97/drossbach-sr-200-t2-karte.jpg","be":"Metallrohre"},"cutx":{"mb":"CAD/CAM","ty":"","b":"WAMMES","u":"","i":"","be":"Software"},"asb":{"mb":"3D-Kanalnetz","ty":"","b":"WAMMES","u":"","i":"","be":"Software"},"sync":{"mb":"Auftragsverwaltung","ty":"","b":"WAMMES","u":"","i":"","be":"Software"},"rev":{"mb":"Maschinenanbindung","ty":"","b":"WAMMES","u":"","i":"","be":"Software"}};
/* ---------- Grundfunktionen (Vergleiche ohne Vergleichszeichen) ---------- */
function lt(a, b) { return Math.max(a, b) !== a; }
function gt(a, b) { return Math.max(a, b) !== b; }
function pos(a) { return Math.max(0, a); }
function neg(a) { return Math.max(0, -a); }
function each(a, f) { for (var i = 0; i !== a.length; i++) { f(a[i], i); } }
function ad(a, b) { return [a[0] + b[0], a[1] + b[1], a[2] + b[2]]; }
function sb(a, b) { return [a[0] - b[0], a[1] - b[1], a[2] - b[2]]; }
function mu(a, k) { return [a[0] * k, a[1] * k, a[2] * k]; }
function dt(a, b) { return a[0] * b[0] + a[1] * b[1] + a[2] * b[2]; }
function cr(a, b) { return [a[1] * b[2] - a[2] * b[1], a[2] * b[0] - a[0] * b[2], a[0] * b[1] - a[1] * b[0]]; }
function len(a) { return Math.sqrt(dt(a, a)); }
function nz(a) { var l = len(a); if (gt(l, 1e-9)) { return mu(a, 1 / l); } return [0, 0, 1]; }
function lp(a, b, t) { return [a[0] + (b[0] - a[0]) * t, a[1] + (b[1] - a[1]) * t, a[2] + (b[2] - a[2]) * t]; }
function rng(n) { var r = []; for (var i = 0; i !== n; i++) { r.push(i); } return r; }
var C30 = Math.cos(Math.PI / 6), KS = 0.1, VV = [1, 1, 1];
function PX(p) { return [(p[0] - p[1]) * C30 * KS, ((p[0] + p[1]) * 0.5 - p[2]) * KS]; }
function DE(p) { return p[0] + p[1] + p[2]; }
/* D3: Erfassung fuer die drehbare 3D-Ansicht. Dann werden alle Seiten erzeugt (keine Auswahl nach Blickrichtung),
   Flaechen und Linien behalten ihre 3D-Punkte (p3), Umrisse gekruemmter Flaechen werden je Ansicht im Shader bestimmt. */
var D3 = false;
function sicht(n) { if (D3) { return true; } return gt(n[0] + n[1] + n[2], 1e-6); }
/* INS: Bauteil-Symbole mit Innenansicht. Rueckseiten werden als Innenflaechen gezeichnet (Innenfarbe),
   Oeffnungen bleiben offen, damit man durch sie ins Bauteil sieht. Nur beim Bau der Symbole an. */
var INS = false;

/* ---------- Farben ---------- */
var NAVY = '#1F3855';
var MAT = {
  m: ['#EEF2F7', '#DCE4EE', '#C3D1E1', '#AFC1D6'],   /* verzinktes Blech */
  a: ['#F5F5F3', '#E6E7E4', '#D2D4D1', '#BDC0BC'],   /* Geraet RAL 7035 */
  w: ['#F1EFEB', '#E4E1DC', '#D6D2CC', '#C4C0B9'],   /* Beton, Mauerwerk */
  f: ['#A9AFB6', '#959CA4', '#838A93', '#737A83'],   /* Gewebe Kompensator */
  k: ['#F7E7A8', '#EED682', '#E2C566', '#CDAE4E'],   /* Mineralwolle */
  x: ['#FBFCFD', '#ECEFF2', '#DADFE4', '#C7CDD3'],   /* Aluminium flexibel */
  h: ['#FFFFFF', '#F4F6F8', '#E5E9ED', '#D4D9DF'],   /* weiss Durchlass */
  d: ['#77808C', '#636C78', '#525A66', '#434A55'],   /* dunkel Antrieb */
  r: ['#E9EDF1', '#D9DFE6', '#C9D1DA', '#B6C0CB'],   /* Rahmenprofil */
  g: ['#3A4048', '#2F343B', '#272B31', '#202328'],   /* Gummi, schwarz */
  i: ['#D6DDE5', '#C9D2DC', '#BAC5D1', '#A9B5C3'],   /* Innenseite */
  y: ['#FFE27E', '#F9C83A', '#EDB20E', '#C99400'],   /* Hervorhebung Bereich */
  z: ['#FFF1BF', '#FDE28E', '#F7D26B', '#E2B94A']    /* Hervorhebung hell (Puls) */
};
var MC = {};
function rgb(h) { return [parseInt(h.substr(1, 2), 16), parseInt(h.substr(3, 2), 16), parseInt(h.substr(5, 2), 16)]; }
function hx2(v) { var s = Math.round(Math.max(0, Math.min(255, v))).toString(16); return s.length === 1 ? '0' + s : s; }
function shade(m, n) {
  var P = MC[m];
  if (!P) { P = []; each(MAT[m] || MAT.m, function (c) { P.push(rgb(c)); }); MC[m] = P; }
  var wR = pos(n[0]) * pos(n[0]), wL = pos(n[1]) * pos(n[1]), wT = pos(n[2]) * pos(n[2]);
  var wI = neg(n[0]) * neg(n[0]) + neg(n[1]) * neg(n[1]) + neg(n[2]) * neg(n[2]) * 1.4;
  var s = wR + wL + wT + wI; if (!gt(s, 0)) { s = 1; wT = 1; }
  var c = [0, 0, 0];
  for (var k = 0; k !== 3; k++) { c[k] = (P[0][k] * wT + P[1][k] * wL + P[2][k] * wR + P[3][k] * wI) / s; }
  return '#' + hx2(c[0]) + hx2(c[1]) + hx2(c[2]);
}

/* ---------- Zeichenliste (Maleralgorithmus) ---------- */
var IT = [], SEQ = 0, PIDNOW = null;
/* Bereiche fuer die Bauteil-Symbole: AREA Nummer des Bereichs, FXL Bereiche, bei denen das Teil ausgeblendet wird,
   INNENT Innenteil (wird vor allen Aussenflaechen gezeichnet) */
var AREA = null, FXL = null, INNENT = false;
function item(o) { o.q = SEQ++; if (AREA !== null) { o.a = AREA; } if (FXL !== null) { o.fx = FXL; } if (INNENT) { o.inn = 1; } IT.push(o); return o; }
function bereich(k, f) { var alt = AREA; AREA = k; var r = f(); AREA = alt; return r; }
function mitA(o, key, f) {
  var k; if (o) { if (o.A) { k = o.A[key]; } }
  var r = (k === undefined) ? f() : bereich(k, f);
  return r;
}
function verdeckt(ks, f) { var alt = FXL; FXL = ks; var r = f(); FXL = alt; return r; }
function mitFX(o, key, f) {
  var k; if (o) { if (o.FX) { k = o.FX[key]; } }
  return (k === undefined) ? f() : verdeckt(k, f);
}
function mitAF(o, key, f) { return mitA(o, key, function () { return mitFX(o, key, f); }); }
function innenTeil(f) { var alt = INNENT; INNENT = true; var r = f(); INNENT = alt; return r; }
function newell(p) {
  var n = [0, 0, 0];
  for (var i = 0; i !== p.length; i++) {
    var a = p[i], b = p[(i + 1) % p.length];
    n[0] += (a[1] - b[1]) * (a[2] + b[2]); n[1] += (a[2] - b[2]) * (a[0] + b[0]); n[2] += (a[0] - b[0]) * (a[1] + b[1]);
  }
  return nz(n);
}
function mitte(p) { var c = [0, 0, 0]; each(p, function (q) { c = ad(c, q); }); return mu(c, 1 / p.length); }
/* Flaeche; o.n Normale, o.two beidseitig, o.b Tiefenzuschlag, o.c feste Farbe, o.s Umriss */
function face(p3, m, pid, o) {
  o = o || {};
  var n = o.n || newell(p3);
  if (D3) {
    var f3 = item({ t: 'f', d: 0, p3: p3, n: n, m: m, c: o.c, pid: pid || PIDNOW, cls: o.cls, op: o.op, two: o.two ? 1 : 0, cull: o.cull ? 1 : 0, k: o.k });
    if (o.s) { if (o.s !== o.c) { line(p3.concat([p3[0]]), pid, { s: o.s, w: o.w || 0.8, cls: o.cls, op: o.op }); } }
    return f3;
  }
  if (!sicht(n)) {
    if (!o.two) {
      if (!INS) { return null; }
      n = mu(n, -1);
      return item({ t: 'f', d: (o.d === undefined ? DE(mitte(p3)) : o.d) + (o.b || 0), p: p3.map(PX), f: shade(m === 'm' ? 'i' : m, n),
        pid: pid || PIDNOW, cls: o.cls, op: o.op, n: n, m: m, k: o.k, inn2: 1 });
    }
    n = mu(n, -1);
  }
  var it = { t: 'f', d: (o.d === undefined ? DE(mitte(p3)) : o.d) + (o.b || 0), p: p3.map(PX), f: o.c || shade(m, n),
    pid: pid || PIDNOW, cls: o.cls, op: o.op, s: o.s, w: o.w, n: n, m: m, k: o.k };
  return item(it);
}
function line(p3, pid, o) {
  o = o || {};
  if (D3) { return item({ t: 'l', d: 0, p3: p3, s: o.s || NAVY, w: o.w || 1, pid: pid || PIDNOW, cls: o.cls, op: o.op, lc: o.lc, nA: o.nA, nB: o.nB }); }
  var d = o.d; if (d === undefined) { d = DE(mitte(p3)); }
  return item({ t: 'l', d: d + (o.b || 0), p: p3.map(PX), s: o.s || NAVY, w: o.w || 1, pid: pid || PIDNOW, cls: o.cls, op: o.op, da: o.da, lc: o.lc });
}
/* WAMMES-Logo auf einer Flaeche (33_logo.js): p3 Mitte, b Breite in mm, o.m Ebene wie bei text ('y' Vorderseite, 'x' Stirnseite, 't' oben);
   o.sym: nur die Bildmarke (rundes Symbol) ohne Schriftzug */
function logo(p3, b, pid, o) {
  o = o || {};
  var sy = o.sym ? 1 : 0;
  /* weisser Rand (halo) wie bei den Beschriftungen, damit Linien der Flaeche das Logo nicht stoeren; in 3D als eigenes Viereck davor */
  if (D3) {
    if (o.halo) { item({ t: 't', lg: 1, sy: sy, lgh: 1, d: 0, p3: p3, s: '', lb: b, pid: pid || PIDNOW, cls: o.cls, fs: 9, fc: '#FFFFFF', m: o.m || 'y', fw: 400, an: 'middle' }); }
    return item({ t: 't', lg: 1, sy: sy, d: 0, p3: p3, s: '', lb: b, pid: pid || PIDNOW, cls: o.cls, fs: 9, fc: o.fc || NAVY, m: o.m || 'y', fw: 400, an: 'middle' });
  }
  return item({ t: 't', lg: 1, sy: sy, d: (o.d === undefined ? DE(p3) : o.d) + (o.b || 0), p: [PX(p3)], s: '', lb: b, pid: pid || PIDNOW, cls: o.cls, fs: 9, fc: o.fc || NAVY, m: o.m || 'y', fw: 400, an: 'middle', halo: o.halo });
}
function text(p3, s, pid, o) {
  o = o || {};
  if (D3) { return item({ t: 't', d: 0, p3: p3, s: s, pid: pid || PIDNOW, cls: o.cls, fs: o.fs || 9, fc: o.fc || NAVY, m: o.m || 'y', fw: o.fw || 600, an: o.an || 'start' }); }
  return item({ t: 't', d: (o.d === undefined ? DE(p3) : o.d) + (o.b || 0), p: [PX(p3)], s: s, pid: pid || PIDNOW, cls: o.cls,
    fs: o.fs || 9, fc: o.fc || NAVY, m: o.m || 'y', fw: o.fw || 600, an: o.an || 'start', halo: o.halo });
}

/* Gitterflaeche G[i][j]; o.wrap periodisch in j; o.out Aussenrichtung (Vektor) oder o.NG Normalen je Punkt.
   Kanten: e0/e1 an i=0/i=nu, f0/f1 an j=0/j=nv, dazu Umrisse, wo Sichtbarkeit wechselt. */
function patch(G, m, pid, o) {
  o = o || {};
  var nu = G.length - 1, nv = o.wrap ? G[0].length : G[0].length - 1;
  function P(i, j) { return G[i][o.wrap ? (j % nv) : j]; }
  var Q = [], i, j;
  if (D3) { return patch3(G, m, pid, o, nu, nv, P); }
  for (i = 0; i !== nu; i++) {
    Q.push([]);
    for (j = 0; j !== nv; j++) {
      var poly = [P(i, j), P(i + 1, j), P(i + 1, j + 1), P(i, j + 1)];
      var n = newell(poly), ref = o.out;
      if (o.NG) { var jj = o.wrap ? (j + 1) % nv : j + 1; ref = ad(ad(o.NG[i][j], o.NG[i + 1][j]), ad(o.NG[i][jj], o.NG[i + 1][jj])); }
      if (ref) { if (lt(dt(n, ref), 0)) { n = mu(n, -1); } }
      var vis = sicht(n), it = null, inn = 0;
      if (vis || o.two) { it = face(poly, m, pid, { n: vis ? n : mu(n, -1), b: o.b, cls: o.cls, c: o.c, op: o.op, d: o.d }); }
      else if (INS) { it = face(poly, m, pid, { n: n, b: o.b, cls: o.cls, op: o.op, d: o.d }); inn = 1; }
      Q[i].push({ it: it, vis: vis, n: n, inn: inn });
    }
  }
  var ew = o.ew || 1, es = o.es || NAVY;
  var ecl = (o.ecls !== undefined) ? o.ecls : o.cls;
  function aussen(a) { return a.it ? !a.inn : false; }
  function eL(a, b, q, rim) {
    if (!q.it) { return; }
    var alt = AREA; if (rim) { if (o.eaR !== undefined) { AREA = o.eaR; } }
    line([a, b], pid, { d: q.it.d + 0.5, w: rim ? (o.ewR || ew) : ew, s: es, cls: ecl, op: o.eop });
    AREA = alt;
  }
  if (!o.noedge) {
    for (i = 0; i !== nu; i++) {
      for (j = 0; j !== nv; j++) {
        var q = Q[i][j]; if (!q.it) { continue; }
        if (q.inn) {
          /* Innenflaeche (INS): nur die Randkanten, sie umreissen die Oeffnung von innen */
          if (i === 0) { if (o.e0) { eL(P(0, j), P(0, j + 1), q, 1); } }
          if (i === nu - 1) { if (o.e1) { eL(P(nu, j), P(nu, j + 1), q, 1); } }
          if (!o.wrap) { if (j === 0) { if (o.f0) { eL(P(i, 0), P(i + 1, 0), q); } } if (j === nv - 1) { if (o.f1) { eL(P(i, nv), P(i + 1, nv), q); } } }
          continue;
        }
        if (i === 0) { if (o.e0) { eL(P(0, j), P(0, j + 1), q, 1); } } else if (!aussen(Q[i - 1][j])) { eL(P(i, j), P(i, j + 1), q); }
        if (i === nu - 1) { if (o.e1) { eL(P(nu, j), P(nu, j + 1), q, 1); } } else if (!aussen(Q[i + 1][j])) { eL(P(i + 1, j), P(i + 1, j + 1), q); }
        if (o.wrap) {
          if (!aussen(Q[i][(j + nv - 1) % nv])) { eL(P(i, j), P(i + 1, j), q); }
          if (!aussen(Q[i][(j + 1) % nv])) { eL(P(i, j + 1), P(i + 1, j + 1), q); }
        } else {
          if (j === 0) { if (o.f0) { eL(P(i, 0), P(i + 1, 0), q); } } else if (!aussen(Q[i][j - 1])) { eL(P(i, j), P(i + 1, j), q); }
          if (j === nv - 1) { if (o.f1) { eL(P(i, nv), P(i + 1, nv), q); } } else if (!aussen(Q[i][j + 1])) { eL(P(i, j + 1), P(i + 1, j + 1), q); }
        }
      }
    }
  }
  return { Q: Q, G: G, nu: nu, nv: nv };
}
/* 3D-Erfassung einer Gitterflaeche: alle Zellen, Randkanten fest, innere Kanten zwischen verschieden geneigten Zellen
   als Umriss-Kandidaten (Normalen nA, nB; gezeichnet nur, wo eine Zelle zum Betrachter zeigt und die andere nicht) */
function patch3(G, m, pid, o, nu, nv, P) {
  var Q = [], i, j;
  for (i = 0; i !== nu; i++) {
    Q.push([]);
    for (j = 0; j !== nv; j++) {
      var poly = [P(i, j), P(i + 1, j), P(i + 1, j + 1), P(i, j + 1)];
      var n = newell(poly), ref = o.out;
      if (o.NG) { var jj = o.wrap ? (j + 1) % nv : j + 1; ref = ad(ad(o.NG[i][j], o.NG[i + 1][j]), ad(o.NG[i][jj], o.NG[i + 1][jj])); }
      if (ref) { if (lt(dt(n, ref), 0)) { n = mu(n, -1); } }
      var it = face(poly, m, pid, { n: n, cls: o.cls, c: o.c, op: o.op, two: o.two, cull: o.cull });
      Q[i].push({ it: it, vis: true, n: n });
    }
  }
  if (o.noedge) { return { Q: Q, G: G, nu: nu, nv: nv }; }
  var ew = o.ew || 1, es = o.es || NAVY, ecl = (o.ecls !== undefined) ? o.ecls : o.cls;
  function eL(a, b, rim, nA, nB) {
    if (!gt(len(sb(b, a)), 0.01)) { return; }
    var alt = AREA; if (rim) { if (o.eaR !== undefined) { AREA = o.eaR; } }
    line([a, b], pid, { w: rim ? (o.ewR || ew) : ew, s: es, cls: ecl, op: o.eop, nA: nA, nB: nB });
    AREA = alt;
  }
  function kand(a, b, qa, qb) { if (lt(dt(qa.n, qb.n), 0.99995)) { eL(a, b, 0, qa.n, qb.n); } }
  for (j = 0; j !== nv; j++) {
    if (o.e0) { eL(P(0, j), P(0, j + 1), 1); }
    if (o.e1) { eL(P(nu, j), P(nu, j + 1), 1); }
    for (i = 1; i !== nu; i++) { kand(P(i, j), P(i, j + 1), Q[i - 1][j], Q[i][j]); }
  }
  for (i = 0; i !== nu; i++) {
    if (o.wrap) {
      for (j = 0; j !== nv; j++) { kand(P(i, j), P(i + 1, j), Q[i][(j + nv - 1) % nv], Q[i][j]); }
    } else {
      if (o.f0) { eL(P(i, 0), P(i + 1, 0)); }
      if (o.f1) { eL(P(i, nv), P(i + 1, nv)); }
      for (j = 1; j !== nv; j++) { kand(P(i, j), P(i + 1, j), Q[i][j - 1], Q[i][j]); }
    }
  }
  return { Q: Q, G: G, nu: nu, nv: nv };
}
/* Ebene Flaeche als Raster: Ursprung O, Achsen U und W, Teilung ch */
function plane(O, U, W, m, pid, o) {
  o = o || {};
  var ch = o.ch || 300, nu = Math.max(1, Math.ceil(len(U) / ch)), nv = Math.max(1, Math.ceil(len(W) / (o.chv || ch))), G = [];
  for (var i = 0; i !== nu + 1; i++) {
    var row = [];
    for (var j = 0; j !== nv + 1; j++) { row.push(ad(ad(O, mu(U, i / nu)), mu(W, j / nv))); }
    G.push(row);
  }
  var r = patch(G, m, pid, { out: o.out || cr(U, W), e0: o.e0 !== false, e1: o.e1 !== false, f0: o.f0 !== false, f1: o.f1 !== false,
    b: o.b, cls: o.cls, ecls: o.ecls, c: o.c, ew: o.ew, es: o.es, op: o.op, two: o.two, noedge: o.noedge, d: o.d, cull: o.cull });
  r.O = O; r.U = U; r.W = W; r.n = nz(o.out || cr(U, W));
  return r;
}
/* Tiefe der Rasterzelle i,j (null, wenn unsichtbar) */
function zelleIJ(r, i, j) { var q = r.Q[Math.min(r.nu - 1, Math.max(0, i))][Math.min(r.nv - 1, Math.max(0, j))]; return q.it ? (q.inn ? null : q.it.d) : null; }
function zelleD(r, u, v) { return zelleIJ(r, Math.floor(u * r.nu), Math.floor(v * r.nv)); }
function uvP(r, p, h) { return ad(ad(ad(r.O, mu(r.U, p[0])), mu(r.W, p[1])), mu(r.n, h)); }
/* Strecke in u,v an den Zellgrenzen teilen und je Stueck zeichnen */
function aufStrecke(r, a, b, pid, o, db) {
  var ts = [0, 1], k;
  for (k = 1; k !== r.nu; k++) { var t = (k / r.nu - a[0]) / ((b[0] - a[0]) || 1e-12); if (gt(t, 1e-6)) { if (lt(t, 1 - 1e-6)) { ts.push(t); } } }
  for (k = 1; k !== r.nv; k++) { var t2 = (k / r.nv - a[1]) / ((b[1] - a[1]) || 1e-12); if (gt(t2, 1e-6)) { if (lt(t2, 1 - 1e-6)) { ts.push(t2); } } }
  ts.sort(function (x, y) { return x - y; });
  for (k = 0; k !== ts.length - 1; k++) {
    var p = [a[0] + (b[0] - a[0]) * ts[k], a[1] + (b[1] - a[1]) * ts[k]], q = [a[0] + (b[0] - a[0]) * ts[k + 1], a[1] + (b[1] - a[1]) * ts[k + 1]];
    var d = zelleD(r, (p[0] + q[0]) / 2, (p[1] + q[1]) / 2); if (d === null) { continue; }
    line([uvP(r, p, o.h || 0.5), uvP(r, q, o.h || 0.5)], pid, { d: d + db, s: o.s, w: o.w, op: o.op, cls: o.cls, da: o.da, lc: 'butt' });
  }
}
/* Linie oder achsparalleles Rechteck auf einer ebenen Flaeche (u,v in 0..1), je Zelle gezeichnet */
function auf(r, pts, pid, o) {
  o = o || {};
  var b = o.b || 0.3, k;
  if (o.fill) {
    var u0 = 1, u1 = 0, v0 = 1, v1 = 0;
    each(pts, function (p) { u0 = Math.min(u0, p[0]); u1 = Math.max(u1, p[0]); v0 = Math.min(v0, p[1]); v1 = Math.max(v1, p[1]); });
    for (var i = Math.floor(u0 * r.nu); lt(i, u1 * r.nu); i++) {
      for (var j = Math.floor(v0 * r.nv); lt(j, v1 * r.nv); j++) {
        var a0 = Math.max(u0, i / r.nu), a1 = Math.min(u1, (i + 1) / r.nu), c0 = Math.max(v0, j / r.nv), c1 = Math.min(v1, (j + 1) / r.nv);
        if (!gt(a1 - a0, 1e-6)) { continue; } if (!gt(c1 - c0, 1e-6)) { continue; }
        var d = zelleIJ(r, i, j); if (d === null) { continue; }
        var q = [[a0, c0], [a1, c0], [a1, c1], [a0, c1]].map(function (p) { return uvP(r, p, o.h || 0.5); });
        face(q, o.m || 'm', pid, { d: d + b, c: o.c, cls: o.cls, op: o.op, two: 1, s: o.c, w: 0.4 });
      }
    }
    if (o.s) { var R = [[u0, v0], [u1, v0], [u1, v1], [u0, v1], [u0, v0]]; for (k = 0; k !== 4; k++) { aufStrecke(r, R[k], R[k + 1], pid, o, b + 0.05); } }
    return;
  }
  for (k = 0; k !== pts.length - 1; k++) { aufStrecke(r, pts[k], pts[k + 1], pid, o, b); }
}
/* Quader; f = Liste der Flaechen (Standard alle), o wie plane */
function box(x0, y0, z0, x1, y1, z1, m, pid, o) {
  o = o || {};
  var dx = x1 - x0, dy = y1 - y0, dz = z1 - z0, r = {};
  var oh = o.ohne || '';
  if (oh.indexOf('t') === -1) { r.t = plane([x0, y0, z1], [dx, 0, 0], [0, dy, 0], m, pid, ext(o, { out: [0, 0, 1] })); }
  if (oh.indexOf('y') === -1) { r.y = plane([x0, y1, z0], [dx, 0, 0], [0, 0, dz], m, pid, ext(o, { out: [0, 1, 0] })); }
  if (oh.indexOf('x') === -1) { r.x = plane([x1, y0, z0], [0, dy, 0], [0, 0, dz], m, pid, ext(o, { out: [1, 0, 0] })); }
  if (o.alle) {
    r.u = plane([x0, y0, z0], [dx, 0, 0], [0, dy, 0], m, pid, { out: [0, 0, -1], two: 0, b: o.b, cls: o.cls });
    r.ny = plane([x0, y0, z0], [dx, 0, 0], [0, 0, dz], m, pid, { out: [0, -1, 0], b: o.b, cls: o.cls });
    r.nx = plane([x0, y0, z0], [0, dy, 0], [0, 0, dz], m, pid, { out: [-1, 0, 0], b: o.b, cls: o.cls });
  } else if (D3) {
    /* 3D: auch Rueckseiten (-y, -x) und Unterseite, die Anlage laesst sich von allen Seiten ansehen */
    if (oh.indexOf('Y') === -1) { r.ny = plane([x0, y0, z0], [dx, 0, 0], [0, 0, dz], m, pid, ext(o, { out: [0, -1, 0] })); }
    if (oh.indexOf('X') === -1) { r.nx = plane([x0, y0, z0], [0, dy, 0], [0, 0, dz], m, pid, ext(o, { out: [-1, 0, 0] })); }
    if (oh.indexOf('u') === -1) { r.u = plane([x0, y0, z0], [dx, 0, 0], [0, dy, 0], m, pid, ext(o, { out: [0, 0, -1] })); }
  }
  return r;
}

/* ---------- Rohre ---------- */
function rahmen(C) {
  var n = C.length, T = [], N = [], B = [], i;
  for (i = 0; i !== n; i++) { T.push(nz(sb(C[Math.min(n - 1, i + 1)], C[Math.max(0, i - 1)]))); }
  var up = gt(Math.abs(T[0][2]), 0.9) ? [0, 1, 0] : [0, 0, 1];
  var n0 = nz(sb(up, mu(T[0], dt(up, T[0])))); N.push(n0); B.push(cr(T[0], n0));
  for (i = 1; i !== n; i++) { var p = N[i - 1]; var q = nz(sb(p, mu(T[i], dt(p, T[i])))); N.push(q); B.push(cr(T[i], q)); }
  return { T: T, N: N, B: B };
}
/* Schlauch entlang Mittellinie C mit Radius R (Zahl oder Liste) */
function schlauch(C, R, m, pid, o) {
  o = o || {};
  var F = o.F || rahmen(C), nr = o.nr || 28, ph = o.ph || 0, G = [], NG = [], i, j;
  for (i = 0; i !== C.length; i++) {
    var r = (typeof R === 'number') ? R : R[i], row = [], nrow = [];
    for (j = 0; j !== nr; j++) {
      var a = ph + 2 * Math.PI * j / nr, v = ad(mu(F.N[i], Math.cos(a)), mu(F.B[i], Math.sin(a)));
      row.push(ad(C[i], mu(v, r))); nrow.push(v);
    }
    G.push(row); NG.push(nrow);
  }
  var res = patch(G, m, pid, { wrap: 1, NG: NG, e0: o.rim0 !== false, e1: o.rim1 !== false, b: o.b, cls: o.cls, c: o.c, ew: o.ew, d: o.d });
  res.C = C; res.F = F; res.R = R; res.NG = NG;
  if (o.cap0) { deckel(G[0], mu(F.T[0], -1), o.cm || m, pid, o); } else if (o.innen !== false) { oeffnung(G[0], mu(F.T[0], -1), pid, o); }
  if (o.cap1) { deckel(G[C.length - 1], F.T[C.length - 1], o.cm || m, pid, o); } else if (o.innen !== false) { oeffnung(G[C.length - 1], F.T[C.length - 1], pid, o); }
  return res;
}
/* Blick in ein offenes Ende: dunkle Innenflaeche, nur wenn das Ende zum Betrachter zeigt */
var INNEN = '#97A5B5';
function oeffnung(ring, n, pid, o) {
  /* 3D: keine Ersatzflaeche, die Innenseite des Rohrs ist selbst zu sehen */
  if (D3) { return null; }
  if (INS) { return null; }
  if (!gt(dt(n, VV), 0.02)) { return null; }
  /* Klasse wsz-oe: in der Hervorhebung nicht mitkopieren (an Stoessen sonst dunkle Scheibe) */
  var ck = o.cls ? o.cls + ' wsz-oe' : 'wsz-oe';
  var it = face(ring, 'm', pid, { n: n, c: INNEN, b: 0.2, cls: ck });
  if (it) { line(ring.concat([ring[0]]), pid, { d: it.d + 0.3, w: o.ew || 1, cls: ck }); }
  return it;
}
function deckel(ring, n, m, pid, o) {
  var it = face(ring, m, pid, { n: n, b: (o.capb || 0) + (o.b || 0), cls: o.cls });
  if (it) { line(ring.concat([ring[0]]), pid, { d: it.d + 0.5, w: o.ew || 1, cls: o.cls }); }
  return it;
}
function teile(p0, p1, ch) {
  var L = len(sb(p1, p0)), n = Math.max(1, Math.ceil(L / (ch || 250))), C = [];
  for (var i = 0; i !== n + 1; i++) { C.push(lp(p0, p1, i / n)); }
  return C;
}
function rohr(p0, p1, r, pid, o) { o = o || {}; return schlauch(teile(p0, p1, o.ch), r, o.m || 'm', pid, o); }
/* Ring (Fuge, Sicke) als sichtbare Halblinie an Stelle p mit Achse t */
function ring(p, t, r, pid, o) {
  o = o || {};
  var F = rahmen([sb(p, t), ad(p, t)]), N = F.N[0], B = F.B[0], n = 36, prev = null, pv = false;
  if (D3) {
    var R3 = [];
    for (var k3 = 0; k3 !== n + 1; k3++) { var a3 = 2 * Math.PI * k3 / n; R3.push(ad(p, mu(ad(mu(N, Math.cos(a3)), mu(B, Math.sin(a3))), r + (o.h || 1)))); }
    line(R3, pid, { w: o.w || 0.9, s: o.s, op: o.op, cls: o.cls });
    return;
  }
  for (var k = 0; k !== n + 1; k++) {
    var a = 2 * Math.PI * k / n, v = ad(mu(N, Math.cos(a)), mu(B, Math.sin(a))), q = ad(p, mu(v, r + (o.h || 1))), vis = gt(dt(v, VV), -0.02);
    if (prev) { if (vis) { if (pv) { line([prev, q], pid, { w: o.w || 0.9, s: o.s, op: o.op, b: o.b || 2, cls: o.cls }); } } }
    prev = q; pv = vis;
  }
}
/* Wickelfalz: Schraubenlinie auf der sichtbaren Seite. Winkel negativ: in Weltkoordinaten linksgaengig,
   in der gespiegelten Iso-Abbildung (und in 3D, gleiche Spiegelung) rechtsgaengig wie das echte Wickelfalzrohr. */
function wickel(p0, p1, r, pid, steig, o) {
  o = o || {};
  var t = nz(sb(p1, p0)), L = len(sb(p1, p0)), F = rahmen([p0, p1]), N = F.N[0], B = F.B[0];
  var st = Math.ceil(L / steig * (o.nk || 14)), prev = null, pv = false;
  if (D3) {
    var W3 = [];
    for (var k3 = 0; k3 !== st + 1; k3++) {
      var s3 = L * k3 / st, a3 = -(2 * Math.PI * s3 / steig + (o.ph || 0));
      W3.push(ad(ad(p0, mu(t, s3)), mu(ad(mu(N, Math.cos(a3)), mu(B, Math.sin(a3))), r + 1.5)));
    }
    line(W3, pid, { w: o.w || 0.85, s: o.s || '#56697F', op: o.op || 1, cls: o.cls });
    return;
  }
  for (var k = 0; k !== st + 1; k++) {
    var s = L * k / st, a = -(2 * Math.PI * s / steig + (o.ph || 0)), v = ad(mu(N, Math.cos(a)), mu(B, Math.sin(a)));
    var q = ad(ad(p0, mu(t, s)), mu(v, r + 1.5)), vis = gt(dt(v, VV), 0.04);
    if (prev) { if (vis) { if (pv) { line([prev, q], pid, { w: o.w || 0.85, s: o.s || '#56697F', op: o.op || 1, b: o.b || 1, cls: o.cls }); } } }
    prev = q; pv = vis;
  }
}

/* ---------- Rechteckige Teile ---------- */
var AX = { x: [1, 0, 0], y: [0, 1, 0], z: [0, 0, 1] };
/* Kanal: p0 Mitte Anfang, A Achse, L Laenge, Wd/w Breite, Hd/h Hoehe */
/* Runde 19 (Dimi 11.11.2026): Leitbleche tragen an der Kante, auf die die Luft trifft, eine runde Wulst (Rundfalz), Durchmesser etwa 10 mm */
var LEIT_WULST = 5;
function kanalL(p0, A, L, Wd, w, Hd, h, m, pid, o) {
  o = o || {};
  var U = mu(A, L), r = {}, ch = o.ch || 300;
  var cW = mu(Wd, w / 2), cH = mu(Hd, h / 2);
  var po = { ch: ch, chv: o.chv || 700, cls: o.cls, b: o.b, c: o.c, ew: o.ew };
  mitAF(o, 'mantel', function () {
    r.pw = plane(ad(sb(p0, cH), cW), U, mu(Hd, h), m, pid, ext(po, { out: Wd }));
    r.nw = plane(sb(sb(p0, cH), cW), U, mu(Hd, h), m, pid, ext(po, { out: mu(Wd, -1) }));
    r.ph = plane(ad(sb(p0, cW), cH), U, mu(Wd, w), m, pid, ext(po, { out: Hd }));
    r.nh = plane(sb(sb(p0, cW), cH), U, mu(Wd, w), m, pid, ext(po, { out: mu(Hd, -1) }));
  });
  mitAF(o, 'innen', function () {
    if (o.cap0) { endrechteck(p0, mu(A, -1), Wd, w, Hd, h, m, pid, o); } else if (o.innen !== false) { innenRechteck(p0, mu(A, -1), Wd, w, Hd, h, pid, o); }
    if (o.cap1) { endrechteck(ad(p0, U), A, Wd, w, Hd, h, m, pid, o); } else if (o.innen !== false) { innenRechteck(ad(p0, U), A, Wd, w, Hd, h, pid, o); }
  });
  mitAF(o, 'rahmen', function () {
    if (o.fr0 !== false) { profil(p0, A, Wd, w, Hd, h, pid, o); }
    if (o.fr1 !== false) { profil(ad(p0, U), mu(A, -1), Wd, w, Hd, h, pid, o); }
  });
  if (o.sicke !== false) {
    mitAF(o, 'sicke', function () {
      each(['pw', 'nw', 'ph', 'nh'], function (k) {
        var f = r[k], breite = (k === 'pw' || k === 'nw') ? h : w;
        if (lt(breite, 399)) { return; }
        var a0 = 110 + (o.sv || 0), s = a0;
        while (lt(s, L - 100)) {
          var u = s / L, rand = 30 / breite;
          auf(f, [[u, rand], [u, 1 - rand]], pid, { s: '#FFFFFF', w: 1, op: 0.95, cls: o.cls });
          auf(f, [[u + 9 / L, rand], [u + 9 / L, 1 - rand]], pid, { s: '#5E7189', w: 0.75, op: 0.7, cls: o.cls });
          s += 160;
        }
      });
    });
  }
  /* Laengsfalz. Bauteilbilder (o.falzB, Fable Runde 17): Pittsburgh-Verbindung wie am fertigen Kanal von aussen zu sehen:
     auf dem Blech mit dem Pittsburghfalz liegt die Tasche als Streifen an der Ecke (Breite o.falzB), auf dem Nachbarblech
     (Stehfalz) die umgelegte Lippe (Breite o.falzL). o.falz Flaeche mit der Tasche an der Kante v = 1; o.falz2 = 1: zweite
     Naht an der gegenueberliegenden Ecke (Kanal aus zwei L-Teilen). Ecken: [Flaeche, Kante v, Nachbarflaeche, Kante v] */
  var ECK = { ph: ['ph', 1, 'pw', 1], pw: ['pw', 1, 'ph', 1], nh: ['nh', 0, 'nw', 0], nw: ['nw', 0, 'nh', 0] };
  var GEG = { ph: 'nh', pw: 'nw', nh: 'ph', nw: 'pw' };
  function brt(k) { return (k === 'pw' || k === 'nw') ? h : w; }
  function rand(k, v1, br, col, lw, bz) {
    var f = r[k]; if (!f) { return; }
    var ue = 32 / L, d = br / brt(k), va = v1 ? 1 - d : 0, vb = v1 ? 1 : d, vi = v1 ? va : vb, i0 = IT.length;
    auf(f, [[ue, va], [1 - ue, va], [1 - ue, vb], [ue, vb]], pid, { fill: 1, c: col, b: bz || 0.32, cls: o.cls });
    /* Zeichnung (Runde 18): Die Hervorhebung nimmt das Gelb nach der Flaechenrichtung, oben ist es sehr hell. Die Streifen bekommen
       deshalb fuer die Hervorhebung die Richtung der dunkleren Seite; ihre Farbe im Ruhebild ist schon gesetzt und bleibt */
    if (!D3) { if (o.A) { for (var ii = i0; ii !== IT.length; ii++) { if (IT[ii].t === 'f') { IT[ii].n = [1, 0, 0]; } } } }
    if (lw) { auf(f, [[ue, vi], [1 - ue, vi]], pid, { s: '#5E7189', w: lw, b: 0.4, cls: o.cls }); }
    else { auf(f, [[ue, v1 ? 1 : 0], [1 - ue, v1 ? 1 : 0]], pid, { s: NAVY, w: 1, b: 0.45, cls: o.cls }); }
  }
  if (o.falz) {
    mitAF(o, 'falz', function () {
      if (o.falzB) {
        each(o.falz2 ? [o.falz, GEG[o.falz]] : [o.falz], function (k) {
          var e = ECK[k];
          rand(e[0], e[1], o.falzB, '#D1DAE4', 0.8);
          if (o.falzL) { rand(e[2], e[3], o.falzL, '#DDE4EC', 0.7); }
        });
      } else {
        var f2 = r[o.falz], bb = brt(o.falz);
        auf(f2, [[0.02, 1 - 14 / bb], [0.98, 1 - 14 / bb]], pid, { s: '#5E7189', w: 0.7, op: 0.8, cls: o.cls });
      }
    });
  }
  /* Biegekanten des Mantels (Fable Runde 17, Dimi 11.11.2026: eigener Bereich fuer „Kanten“): beim Kanal aus zwei L-Teilen
     die beiden Ecken ohne Laengsfalz. Runde 18 (Dimi: im kleinen Elementbild kaum zu sehen): je Ecke ein kraeftiger Streifen
     (o.kantB) auf beiden angrenzenden Flaechen. Er hat die Farbe des Blechs, ist also im Ruhebild unsichtbar, und leuchtet
     erst gelb, wenn der Bereich hervorgehoben wird; unter den Sicken (Tiefe 0,25) */
  if (o.kant) {
    mitAF(o, 'kant', function () {
      each(o.falz === 'ph' || o.falz === 'nh' ? [['ph', 0], ['nw', 1], ['pw', 0], ['nh', 1]] : [['pw', 0], ['nh', 1], ['ph', 0], ['nw', 1]], function (q) {
        rand(q[0], q[1], o.kantB || 40, undefined, 0, 0.25);
      });
    });
  }
  return r;
}
function ext(a, b) { var r = {}, k; for (k in a) { r[k] = a[k]; } for (k in b) { r[k] = b[k]; } return r; }
/* Pittsburgh-Verbindung an Formstuecken (Fable Runde 17): Der Pittsburghfalz (Tasche) sitzt am Mantelblech, der Stehfalz (Bord) am
   Seitenblech; nach dem Schliessen liegt die Lippe der Tasche auf dem Seitenblech. Von aussen sieht man deshalb auf dem
   Seitenblech die umgelegte Lippe (o.falzB) und auf dem Mantel die Tasche als Streifen entlang beider Kanten (o.falzT).
   taschenRand: gekruemmter Mantel als Raster res (patch: i entlang der Kante, j quer). PK(i, q) Punkt bei Abschnitt i im Abstand q mm
   von der Kante j = 0, knapp ueber der Flaeche; NK(i) Aussennormale; br Breite des Mantels, tb Breite der Tasche */
function taschenRand(res, n, PK, NK, br, tb, m, pid, o) {
  if (!res) { return; }
  var nj = res.nv;
  for (var i = 0; i !== n; i++) {
    each([[0, 0, tb, tb], [nj - 1, br - tb, br, br - tb]], function (e) {
      var q = res.Q[i][e[0]]; if (!q.it) { return; } if (q.inn) { return; }
      face([PK(i, e[1]), PK(i + 1, e[1]), PK(i + 1, e[2]), PK(i, e[2])], m, pid, { n: NK(i), d: q.it.d + 0.35, c: '#D1DAE4', cls: o.cls });
      line([PK(i, e[3]), PK(i + 1, e[3])], pid, { d: q.it.d + 0.45, w: 0.75, s: '#5E7189', cls: o.cls });
    });
  }
}
/* dasselbe auf einer ebenen Mantelflaeche (plane): Tasche an den Kanten v = 0 und v = 1 */
function taschenRandE(pr, tb, pid, o) {
  if (!pr) { return; }
  var d = tb / len(pr.W);
  each([[0, d, d], [1 - d, 1, 1 - d]], function (e) {
    auf(pr, [[0, e[0]], [1, e[0]], [1, e[1]], [0, e[1]]], pid, { fill: 1, c: '#D1DAE4', b: 0.32, cls: o.cls });
    auf(pr, [[0, e[2]], [1, e[2]]], pid, { s: '#5E7189', w: 0.75, b: 0.4, cls: o.cls });
  });
}
function innenRechteck(c, n, Wd, w, Hd, h, pid, o) {
  if (D3) { return null; }
  if (INS) { return null; }
  if (!gt(dt(n, VV), 0.02)) { return null; }
  var a = mu(Wd, w / 2), b = mu(Hd, h / 2);
  var p = [ad(sb(c, a), mu(b, -1)), ad(c, sb(a, b)), ad(ad(c, a), b), ad(sb(c, a), b)];
  /* wsz-oe: in der Hervorhebung nicht mitkopieren (an Stoessen sonst dunkle Flaeche) */
  return face(p, 'm', pid, { n: n, c: INNEN, b: 0.2, cls: o.cls ? o.cls + ' wsz-oe' : 'wsz-oe' });
}
function endrechteck(c, n, Wd, w, Hd, h, m, pid, o) {
  var a = mu(Wd, w / 2), b = mu(Hd, h / 2);
  var p = [ad(sb(c, a), mu(b, -1)), ad(c, sb(a, b)), ad(ad(c, a), b), ad(sb(c, a), b)];
  var it = face(p, m, pid, { n: n, cls: o.cls });
  if (it) { line(p.concat([p[0]]), pid, { d: it.d + 0.5, cls: o.cls }); }
  return it;
}
/* Steckrahmen (Profil 25 mm hoch, 30 mm breit) am Kanalende c, A zeigt in den Kanal.
   Bauteilbilder (INS, Dimi 09.11.2026: Fehler an Rahmen): Leisten, Stirnseite und Dichtband in kurzen Stuecken mit
   Tiefenzuschlag (Leisten RB, sichtbare Stirnseite des vorderen Rahmens RR), sonst ueberdecken angrenzende grosse Flaechen
   (Mantelzellen, Seiten- und Mantelbleche) den Rahmen stellenweise. */
function profil(c, A, Wd, w, Hd, h, pid, o) {
  o = o || {};
  var f = o.prof || 25, t = 30, W2 = w + 2 * f, H2 = h + 2 * f;
  var c0 = c, U = mu(A, t), cW = mu(Wd, W2 / 2), cH = mu(Hd, H2 / 2), RB = INS ? 45 : 0, RR = INS ? 300 : 0, ST = INS ? 70 : 0;
  var po = { ch: 400, chv: INS ? ST : 900, cls: o.cls, ew: 0.9 };
  function pb(out) { return ext(po, { out: out, b: sicht(out) ? RB : 0 }); }
  plane(ad(sb(c0, cH), cW), U, mu(Hd, H2), 'r', pid, pb(Wd));
  plane(sb(sb(c0, cH), cW), U, mu(Hd, H2), 'r', pid, pb(mu(Wd, -1)));
  plane(ad(sb(c0, cW), cH), U, mu(Wd, W2), 'r', pid, pb(Hd));
  plane(sb(sb(c0, cW), cH), U, mu(Wd, W2), 'r', pid, pb(mu(Hd, -1)));
  /* Stirnseite als Ring */
  var n = mu(A, -1);
  if (sicht(n)) {
    var aO = mu(Wd, W2 / 2), bO = mu(Hd, H2 / 2), aI = mu(Wd, w / 2), bI = mu(Hd, h / 2);
    var O = [ad(sb(c0, aO), mu(bO, -1)), sb(ad(c0, aO), bO), ad(ad(c0, aO), bO), ad(sb(c0, aO), bO)];
    var I = [ad(sb(c0, aI), mu(bI, -1)), sb(ad(c0, aI), bI), ad(ad(c0, aI), bI), ad(sb(c0, aI), bI)];
    var RD = [], k, j;
    function teile(k) { return ST ? Math.max(1, Math.ceil(len(sb(O[(k + 1) % 4], O[k])) / ST)) : 1; }
    function auf(P, Q, s) { return ad(P, mu(sb(Q, P), s)); }
    for (k = 0; k !== 4; k++) {
      var nt = teile(k), dk = [];
      for (j = 0; j !== nt; j++) {
        var s0 = j / nt, s1 = (j + 1) / nt, k1 = (k + 1) % 4;
        var oa = auf(O[k], O[k1], s0), ob = auf(O[k], O[k1], s1), ia = auf(I[k], I[k1], s0), ib = auf(I[k], I[k1], s1);
        var it = face([oa, ob, ib, ia], 'r', pid, { n: n, cls: o.cls, b: 1 + RR });
        dk.push(it ? it.d : null);
        if (it) { line([oa, ob], pid, { d: it.d + 0.5, w: 0.9, cls: o.cls }); line([ia, ib], pid, { d: it.d + 0.5, w: 0.7, cls: o.cls, op: 0.8 }); }
      }
      RD.push(dk);
    }
    /* Dichtband auf der Stirnseite (nur Symbol), Stuecke wie der Ring, knapp darueber */
    if (o.dicht) {
      mitA(o, 'dicht', function () {
        var aA = mu(Wd, w / 2 + 5), bA = mu(Hd, h / 2 + 5), aB = mu(Wd, w / 2 + 18), bB = mu(Hd, h / 2 + 18);
        var IA = [ad(sb(c0, aA), mu(bA, -1)), sb(ad(c0, aA), bA), ad(ad(c0, aA), bA), ad(sb(c0, aA), bA)];
        var IB = [ad(sb(c0, aB), mu(bB, -1)), sb(ad(c0, aB), bB), ad(ad(c0, aB), bB), ad(sb(c0, aB), bB)];
        /* je Seite ein Band ohne Stoesse (sonst helle Haarlinien), knapp ueber dem hoechsten Ringstueck dieser Seite */
        for (var k2 = 0; k2 !== 4; k2++) {
          var kk = (k2 + 1) % 4, dd = null;
          each(RD[k2], function (x) { if (x !== null) { dd = dd === null ? x : Math.max(dd, x); } });
          var q = [IB[k2], IB[kk], IA[kk], IA[k2]];
          face(q, 'g', pid, (dd === null || !INS) ? { n: n, cls: o.cls, b: 2.5 + RR } : { n: n, cls: o.cls, d: dd + 0.6 });
        }
      });
    }
    /* Eckwinkel: ueber den angrenzenden Ringstuecken */
    for (k = 0; k !== 4; k++) {
      var e = O[k], s1v = mu(Wd, (dt(sb(I[k], O[k]), Wd) * 0.9)), s2v = mu(Hd, (dt(sb(I[k], O[k]), Hd) * 0.9));
      var q2 = [e, ad(e, s1v), ad(ad(e, s1v), s2v), ad(e, s2v)], km = (k + 3) % 4, dmax = null;
      each([RD[k][0], RD[km][RD[km].length - 1]], function (x) { if (x !== null) { dmax = dmax === null ? x : Math.max(dmax, x); } });
      face(q2, 'd', pid, (dmax === null || !INS) ? { n: n, cls: o.cls, b: 1.5 + RR, c: '#5A6472' } : { n: n, cls: o.cls, d: dmax + 0.8, c: '#5A6472' });
    }
  }
  /* 3D: Rueckseite des Rahmens, Stufe vom Rahmen auf den Kanalmantel (Normale A) */
  if (D3) {
    var c1 = ad(c0, U), aO1 = mu(Wd, W2 / 2), bO1 = mu(Hd, H2 / 2), aI1 = mu(Wd, w / 2), bI1 = mu(Hd, h / 2);
    var O1 = [ad(sb(c1, aO1), mu(bO1, -1)), sb(ad(c1, aO1), bO1), ad(ad(c1, aO1), bO1), ad(sb(c1, aO1), bO1)];
    var I1 = [ad(sb(c1, aI1), mu(bI1, -1)), sb(ad(c1, aI1), bI1), ad(ad(c1, aI1), bI1), ad(sb(c1, aI1), bI1)];
    for (var k1 = 0; k1 !== 4; k1++) {
      face([O1[k1], O1[(k1 + 1) % 4], I1[(k1 + 1) % 4], I1[k1]], 'r', pid, { n: A, cls: o.cls });
      line([I1[k1], I1[(k1 + 1) % 4]], pid, { w: 0.7, cls: o.cls, op: 0.8 });
    }
  }
}
/* Kreisscheibe (n Ecken) in der Ebene mit Normale nn, Radius r; o wie face */
function scheibe(c, nn, r, m, pid, o) {
  o = o || {};
  var u1 = nz(cr(nn, gt(Math.abs(nn[2]), 0.9) ? [1, 0, 0] : [0, 0, 1])), u2 = cr(nn, u1), q = [], k, n = o.nk || 12;
  for (k = 0; k !== n; k++) { var aa = 2 * Math.PI * k / n; q.push(ad(c, ad(mu(u1, r * Math.cos(aa)), mu(u2, r * Math.sin(aa))))); }
  return face(q, m, pid, ext(o, { n: nn }));
}
/* Rechteckbogen: p0 Mitte Anfang, A Richtung hinein, Tn Biegerichtung, a Breite in der Biegeebene, h Hoehe, ri Innenradius
   Symbol: o.falzB Falzband auf den Seitenblechen, o.leit Leitblech, o.innenFl Innenflaechen */
function bogenR(p0, A, Tn, a, h, ri, m, pid, o) {
  o = o || {};
  var Bn = nz(cr(A, Tn)), C = ad(p0, mu(Tn, a / 2 + ri)), ro = ri + a, n = o.n || 14, nh = 3, i, j;
  function rho(f) { return ad(mu(Tn, -Math.cos(f)), mu(A, Math.sin(f))); }
  function P(r, f, s) { return ad(ad(C, mu(rho(f), r)), mu(Bn, s)); }
  var po = { cls: o.cls, b: o.b }, wa = {};
  each([1, -1], function (sg) {
    var G = [];
    for (i = 0; i !== n + 1; i++) { var f = Math.PI / 2 * i / n; G.push([P(ri, f, sg * h / 2), P(ro, f, sg * h / 2)]); }
    wa[sg] = mitAF(o, 'seite', function () { return patch(G, m, pid, ext(po, { out: mu(Bn, sg), e0: 1, e1: 1, f0: 1, f1: 1 })); });
  });
  var MR = [];
  mitAF(o, 'mantel', function () {
    each([[ro, 1], [ri, -1]], function (rr) {
      var G = [], NG = [];
      for (i = 0; i !== n + 1; i++) {
        var f = Math.PI / 2 * i / n, row = [], nr = [];
        for (j = 0; j !== nh + 1; j++) { row.push(P(rr[0], f, -h / 2 + h * j / nh)); nr.push(mu(rho(f), rr[1])); }
        G.push(row); NG.push(nr);
      }
      MR.push([patch(G, m, pid, ext(po, { NG: NG, e0: 1, e1: 1, f0: 1, f1: 1 })), rr[0], rr[1]]);
    });
  });
  var pe = ad(C, mu(A, ri + a / 2));
  mitAF(o, 'innen', function () { innenRechteck(p0, mu(A, -1), Tn, a, Bn, h, pid, o); innenRechteck(pe, Tn, A, a, Bn, h, pid, o); });
  mitAF(o, 'rahmen', function () {
    if (o.fr0 !== false) { profil(p0, A, Tn, a, Bn, h, pid, o); }
    if (o.fr1 !== false) { profil(pe, mu(Tn, -1), A, a, Bn, h, pid, o); }
  });
  /* Falzband: umgelegter Rand der Tasche auf dem Seitenblech, aussen und innen; Tasche auf dem Mantel (o.falzT) */
  if (o.falzB) {
    mitAF(o, 'falz', function () {
      if (o.falzT) {
        each(MR, function (mr) {
          taschenRand(mr[0], n, function (k, q) { return P(mr[1] + mr[2] * 0.6, Math.PI / 2 * k / n, -h / 2 + q); },
            function (k) { return mu(rho(Math.PI / 2 * (k + 0.5) / n), mr[2]); }, h, o.falzT, m, pid, o);
        });
      }
      each([1, -1], function (sg) {
        var Q = wa[sg].Q, z = sg * (h / 2 + 0.5), fb = o.falzB;
        for (i = 0; i !== n; i++) {
          var q = Q[i][0]; if (!q.it) { continue; }
          var f0 = Math.PI / 2 * i / n, f1 = Math.PI / 2 * (i + 1) / n;
          each([[ro - fb, ro], [ri, ri + fb]], function (rr) {
            face([P(rr[0], f0, z), P(rr[1], f0, z), P(rr[1], f1, z), P(rr[0], f1, z)], m, pid, { n: mu(Bn, sg), d: q.it.d + 0.35, c: '#D1DAE4' });
          });
          line([P(ro - fb, f0, z), P(ro - fb, f1, z)], pid, { d: q.it.d + 0.45, w: 0.75, s: '#5E7189' });
          line([P(ri + fb, f0, z), P(ri + fb, f1, z)], pid, { d: q.it.d + 0.45, w: 0.75, s: '#5E7189' });
        }
      });
    });
  }
  /* Innenflaechen (sichtbar, wenn das Seitenblech ausgeblendet wird) */
  if (o.innenFl) {
    innenTeil(function () {
      each([1, -1], function (sg) {
        var G = [];
        for (i = 0; i !== n + 1; i++) { var f = Math.PI / 2 * i / n; G.push([P(ri, f, sg * h / 2), P(ro, f, sg * h / 2)]); }
        patch(G, 'i', pid, { out: mu(Bn, -sg), noedge: 1 });
      });
      each([[ro, -1], [ri, 1]], function (rr) {
        var G = [], NG = [];
        for (i = 0; i !== n + 1; i++) {
          var f = Math.PI / 2 * i / n, row = [], nr = [];
          for (j = 0; j !== nh + 1; j++) { row.push(P(rr[0], f, -h / 2 + h * j / nh)); nr.push(mu(rho(f), rr[1])); }
          G.push(row); NG.push(nr);
        }
        patch(G, 'i', pid, { NG: NG, noedge: 1 });
      });
    });
  }
  /* Leitblech auf mittlerem Radius, Leitblechduebel auf den Seitenblechen; LEIT_WULST: Radius der Wulst an der Anstroemkante in mm */
  if (o.leit) {
    var rv = Math.sqrt(ri * ro);
    mitA(o, 'leit', function () {
      innenTeil(function () {
        var G = [];
        for (i = 0; i !== n + 1; i++) { var f = Math.PI / 2 * i / n; G.push([P(rv, f, -h / 2 + 3), P(rv, f, 0), P(rv, f, h / 2 - 3)]); }
        patch(G, 'r', pid, { two: 1, e0: 1, e1: 1, f0: 1, f1: 1, ew: 0.8 });
        /* Runde 19 (Dimi 11.11.2026): runde Wulst (Rundfalz, Durchmesser etwa 10 mm) an der Kante, auf die die Luft trifft */
        rohr(P(rv, Math.PI / 2, -h / 2 + 3), P(rv, Math.PI / 2, h / 2 - 3), LEIT_WULST, pid, { m: 'r', nr: 8, ch: 400 });
      });
      each([1, -1], function (sg) {
        each([0.12, 0.5, 0.88], function (t) {
          var ii = Math.min(n - 1, Math.floor(t * n)), q = wa[sg].Q[ii][0]; if (!q.it) { return; }
          scheibe(P(rv, Math.PI / 2 * t, sg * (h / 2 + 1)), mu(Bn, sg), 10, 'd', pid, { d: q.it.d + 0.6, c: '#4B5666', k: 1 });
        });
      });
    });
  }
  return { pe: pe, C: C, Bn: Bn };
}
/* Rechteckwinkel mit scharfer Ecke: Schenkel l1 vor und l2 nach dem Eckfeld
   Symbol: o.falzB Falzband, o.leit Leitschaufeln auf der Diagonale, o.innenFl Innenflaechen */
function winkelR(p0, A, Tn, a, h, l1, l2, m, pid, o) {
  o = o || {};
  var Bn = nz(cr(A, Tn));
  function L2(s, t, z) { return ad(ad(ad(p0, mu(A, s)), mu(Tn, t)), mu(Bn, z)); }
  var poly = [[0, -a / 2], [0, a / 2], [l1, a / 2], [l1, a / 2 + l2], [l1 + a, a / 2 + l2], [l1 + a, -a / 2]], wg = {};
  mitAF(o, 'seite', function () {
    each([1, -1], function (sg) {
      var p3 = poly.map(function (q) { return L2(q[0], q[1], sg * h / 2); });
      var it = face(p3, m, pid, { n: mu(Bn, sg), cls: o.cls });
      wg[sg] = it;
      if (it) { line(p3.concat([p3[0]]), pid, { d: it.d + 0.5, cls: o.cls }); }
    });
  });
  var W = [[[0, -a / 2], [l1 + a, -a / 2], mu(Tn, -1)], [[l1 + a, -a / 2], [l1 + a, a / 2 + l2], A], [[0, a / 2], [l1, a / 2], Tn], [[l1, a / 2], [l1, a / 2 + l2], mu(A, -1)]];
  var MR = [];
  mitAF(o, 'mantel', function () {
    each(W, function (wd) {
      var O = L2(wd[0][0], wd[0][1], -h / 2), U = sb(L2(wd[1][0], wd[1][1], -h / 2), O);
      MR.push(plane(O, U, mu(Bn, h), m, pid, { out: wd[2], ch: 250, cls: o.cls }));
    });
  });
  var pe = L2(l1 + a / 2, a / 2 + l2, 0);
  mitAF(o, 'innen', function () { innenRechteck(p0, mu(A, -1), Tn, a, Bn, h, pid, o); innenRechteck(pe, Tn, A, a, Bn, h, pid, o); });
  mitAF(o, 'rahmen', function () {
    if (o.fr0 !== false) { profil(p0, A, Tn, a, Bn, h, pid, o); }
    if (o.fr1 !== false) { profil(pe, mu(Tn, -1), A, a, Bn, h, pid, o); }
  });
  /* Diagonale: Leitschaufelschiene */
  mitAF(o, 'leitL', function () {
    each([1, -1], function (sg) {
      var it = wg[sg]; if (!it) { return; }
      line([L2(l1, a / 2, sg * h / 2), L2(l1 + a, -a / 2, sg * h / 2)], pid, { d: it.d + 0.6, w: 0.8, s: '#5E7189', cls: o.cls });
    });
  });
  if (o.falzB) {
    mitAF(o, 'falz', function () {
      if (o.falzT) { each(MR, function (pr) { taschenRandE(pr, o.falzT, pid, o); }); }
      var fb = o.falzB, e = 30;
      var R = [[e, l1 + a, -a / 2, -a / 2 + fb], [l1 + a - fb, l1 + a, -a / 2, a / 2 + l2 - e], [e, l1 + fb, a / 2 - fb, a / 2], [l1, l1 + fb, a / 2 - fb, a / 2 + l2 - e]];
      each([1, -1], function (sg) {
        var it = wg[sg]; if (!it) { return; }
        var z = sg * (h / 2 + 0.5);
        each(R, function (q) {
          var p3 = [L2(q[0], q[2], z), L2(q[1], q[2], z), L2(q[1], q[3], z), L2(q[0], q[3], z)];
          face(p3, m, pid, { n: mu(Bn, sg), d: it.d + 0.35, c: '#D1DAE4' });
        });
        var Ln = [[[e, -a / 2 + fb], [l1 + a - fb, -a / 2 + fb]], [[l1 + a - fb, -a / 2 + fb], [l1 + a - fb, a / 2 + l2 - e]], [[e, a / 2 - fb], [l1 + fb, a / 2 - fb]], [[l1 + fb, a / 2 - fb], [l1 + fb, a / 2 + l2 - e]]];
        each(Ln, function (q) { line([L2(q[0][0], q[0][1], z), L2(q[1][0], q[1][1], z)], pid, { d: it.d + 0.45, w: 0.75, s: '#5E7189' }); });
      });
    });
  }
  if (o.innenFl) {
    innenTeil(function () {
      each([1, -1], function (sg) {
        var p3 = poly.map(function (q) { return L2(q[0], q[1], sg * h / 2); });
        face(p3, 'i', pid, { n: mu(Bn, -sg) });
      });
      each(W, function (wd) {
        var O = L2(wd[0][0], wd[0][1], -h / 2), U = sb(L2(wd[1][0], wd[1][1], -h / 2), O);
        plane(O, U, mu(Bn, h), 'i', pid, { out: mu(wd[2], -1), ch: 250, noedge: 1 });
      });
    });
  }
  if (o.leit) {
    mitA(o, 'leit', function () {
      var Pi = [l1, a / 2], Po = [l1 + a, -a / 2], diag = a * Math.SQRT2, N = Math.max(3, Math.round(diag / 115)), sp = diag / N, rr = sp * 0.95;
      innenTeil(function () {
        for (var k = 0; k !== N; k++) {
          var t = (k + 0.5) / N, sk = Pi[0] + (Po[0] - Pi[0]) * t, tk = Pi[1] + (Po[1] - Pi[1]) * t;
          var cs = sk - rr / Math.SQRT2, ct = tk + rr / Math.SQRT2, G = [];
          for (var i = 0; i !== 7; i++) {
            var f = Math.PI / 2 * i / 6, ps = cs + rr * Math.sin(f), pt = ct - rr * Math.cos(f);
            G.push([L2(ps, pt, -h / 2 + 3), L2(ps, pt, 0), L2(ps, pt, h / 2 - 3)]);
          }
          patch(G, 'r', pid, { two: 1, e0: 1, e1: 1, f0: 1, f1: 1, ew: 0.75 });
          /* Wulst an der Anstroemkante jeder Schaufel (Runde 19) */
          rohr(L2(cs, ct - rr, -h / 2 + 3), L2(cs, ct - rr, h / 2 - 3), LEIT_WULST, pid, { m: 'r', nr: 8, ch: 400 });
        }
      });
      each([1, -1], function (sg) {
        var it = wg[sg]; if (!it) { return; }
        for (var k = 0; k !== N; k++) {
          var t = (k + 0.5) / N, sk = Pi[0] + (Po[0] - Pi[0]) * t, tk = Pi[1] + (Po[1] - Pi[1]) * t;
          scheibe(L2(sk, tk, sg * (h / 2 + 1)), mu(Bn, sg), 9, 'd', pid, { d: it.d + 0.7, c: '#4B5666', k: 1 });
        }
      });
    });
  }
  return { pe: pe };
}
/* Hosenstueck: Eintritt p0, A Richtung, Abgaenge nach +Tn und -Tn, je halbe Breite.
   Symbol: Bereich 'spitze' = Zwickelbleche an der Spitze (erste Teilung) und Spitzenkante */
function hose(p0, A, Tn, a, h, ri, m, pid, o) {
  o = o || {};
  var Bn = nz(cr(A, Tn)), n = 14, i, j, w2 = a / 2, ns = (o.A ? (o.A.spitze !== undefined ? 2 : 0) : 0);
  /* o.A.spitzeK: nur die Kante an der Spitze gehoert zu diesem Bereich (Bauform von rbogen: Laengsfalz), die Bleche bleiben Mantel */
  var sk = (o.A ? o.A.spitzeK !== undefined : false);
  each([1, -1], function (sg) {
    var T = mu(Tn, sg), C = ad(p0, mu(T, a / 2 + ri)), ro = ri + w2, wa = {};
    function rho(f) { return ad(mu(T, -Math.cos(f)), mu(A, Math.sin(f))); }
    function P(r, f, s) { return ad(ad(C, mu(rho(f), r)), mu(Bn, s)); }
    mitAF(o, 'seite', function () {
      each([1, -1], function (sh) {
        var G = [];
        for (i = 0; i !== n + 1; i++) { var f = Math.PI / 2 * i / n; G.push([P(ri, f, sh * h / 2), P(ro, f, sh * h / 2)]); }
        wa[sh] = patch(G, m, pid, { out: mu(Bn, sh), e0: 1, e1: 1, f0: 1, f1: 1, cls: o.cls });
      });
    });
    /* Laengsfalz (Runde 11, Punkt 18: fehlte): umgelegter Rand der Tasche auf dem Seitenblech, aussen und innen */
    if (o.falzB) {
      mitAF(o, 'falz', function () {
        each([1, -1], function (sh) {
          if (!wa[sh]) { return; }
          var Q = wa[sh].Q, z = sh * (h / 2 + 0.5), fb = o.falzB;
          for (i = 0; i !== n; i++) {
            var q = Q[i][0]; if (!q.it) { continue; }
            var f0 = Math.PI / 2 * i / n, f1 = Math.PI / 2 * (i + 1) / n;
            each([[ro - fb, ro], [ri, ri + fb]], function (rr) {
              face([P(rr[0], f0, z), P(rr[1], f0, z), P(rr[1], f1, z), P(rr[0], f1, z)], m, pid, { n: mu(Bn, sh), d: q.it.d + 0.35, c: '#D1DAE4' });
            });
            line([P(ro - fb, f0, z), P(ro - fb, f1, z)], pid, { d: q.it.d + 0.45, w: 0.75, s: '#5E7189' });
            line([P(ri + fb, f0, z), P(ri + fb, f1, z)], pid, { d: q.it.d + 0.45, w: 0.75, s: '#5E7189' });
          }
        });
      });
    }
    function mantel(r, sgn, i0, i1, ea, eb) {
      var G = [], NG = [];
      for (i = i0; i !== i1 + 1; i++) {
        var f = Math.PI / 2 * i / n, row = [], nr = [];
        for (j = 0; j !== 4; j++) { row.push(P(r, f, -h / 2 + h * j / 3)); nr.push(mu(rho(f), sgn)); }
        G.push(row); NG.push(nr);
      }
      var res = patch(G, m, pid, { NG: NG, e0: ea, e1: eb, f0: 1, f1: 1, cls: o.cls });
      if (o.falzT) {
        mitAF(o, 'falz', function () {
          taschenRand(res, i1 - i0, function (k, q) { return P(r + sgn * 0.6, Math.PI / 2 * (i0 + k) / n, -h / 2 + q); },
            function (k) { return mu(rho(Math.PI / 2 * (i0 + k + 0.5) / n), sgn); }, h, o.falzT, m, pid, o);
        });
      }
    }
    mitAF(o, 'mantel', function () { mantel(ri, -1, 0, n, 1, 1); mantel(ro, 1, ns, n, ns ? 0 : 1, 1); });
    if (ns) { mitAF(o, 'spitze', function () { mantel(ro, 1, 0, ns, 1, 0); }); }
    var pe = ad(C, mu(A, ri + w2 / 2));
    mitAF(o, 'innen', function () { innenRechteck(pe, T, A, w2, Bn, h, pid, o); });
    mitAF(o, 'rahmen', function () { profil(pe, mu(T, -1), A, w2, Bn, h, pid, o); });
  });
  mitAF(o, 'innen', function () { innenRechteck(p0, mu(A, -1), Tn, a, Bn, h, pid, o); });
  mitAF(o, 'rahmen', function () { profil(p0, A, Tn, a, Bn, h, pid, o); });
  if (ns || sk) {
    mitA(o, sk ? 'spitzeK' : 'spitze', function () { line([ad(p0, mu(Bn, -h / 2)), ad(p0, mu(Bn, h / 2))], pid, { w: 1.4, b: 3, cls: o.cls }); });
  }
}
/* Hosenstueck nach DIN 18379, Tabelle 2, Nr. 18 (HS): Eintritt a (entlang Wd) mal b (entlang Hd) bei p0, Achse A, Laenge L;
   zwei Abgaenge a mal d (oben) und a mal hh (unten) mit Abstand m dazwischen; gerade Enden l0 (Eintritt) und l1 (Abgaenge),
   dazwischen schraeg; die inneren Mantelbleche treffen sich am Zwickel bei xc. Seitenbleche in Hosenform (drei Felder),
   Mantelbleche gekantet. o.A Bereiche: seite, mantel, falz, rahmen; o.falzB Falzband. Rueckgabe: Kenngroessen fuer Masse */
function hosenR(p0, A, Wd, a, Hd, b, d, hh, mg, L, pid, o) {
  o = o || {};
  var l0 = o.l0 || 120, l1 = o.l1 || 150, zT1 = (d + mg + hh) / 2, zB1 = -zT1, zIu = zT1 - d, zIl = zB1 + hh, zc = (zIu + zIl) / 2;
  var xc = l0 + (L - l1 - l0) * 0.42, xk = L - l1, i;
  function P(x, y, z) { return ad(ad(ad(p0, mu(A, x)), mu(Wd, y)), mu(Hd, z)); }
  function lin(x, xa, za, xb, zb) { return za + (zb - za) * Math.max(0, Math.min(1, (x - xa) / (xb - xa))); }
  function zT(x) { return lin(x, l0, b / 2, xk, zT1); }
  function zB(x) { return lin(x, l0, -b / 2, xk, zB1); }
  function zU(x) { return lin(x, xc, zc, xk, zIu); }
  function zL(x) { return lin(x, xc, zc, xk, zIl); }
  var xsA = [0, l0, xc], xsB = [xc, xk, L], po = { cls: o.cls };
  /* Seitenbleche: Feld vor dem Zwickel, unterer und oberer Abgang */
  mitAF(o, 'seite', function () {
    each([1, -1], function (sg) {
      var y = sg * a / 2, out = mu(Wd, sg);
      patch(xsA.map(function (x) { return [P(x, y, zB(x)), P(x, y, zT(x))]; }), 'm', pid, ext(po, { out: out, e0: 1, e1: 0, f0: 1, f1: 1 }));
      patch(xsB.map(function (x) { return [P(x, y, zB(x)), P(x, y, zL(x))]; }), 'm', pid, ext(po, { out: out, e0: 0, e1: 1, f0: 1, f1: 1 }));
      patch(xsB.map(function (x) { return [P(x, y, zU(x)), P(x, y, zT(x))]; }), 'm', pid, ext(po, { out: out, e0: 0, e1: 1, f0: 1, f1: 1 }));
    });
  });
  /* Mantelbleche: oben, unten, die beiden inneren am Zwickel; je Knick ein eigenes Feld */
  function wand(xs, zf, out) {
    for (i = 0; i !== xs.length - 1; i++) {
      var xa = xs[i], xb = xs[i + 1];
      if (!gt(xb - xa, 0.5)) { continue; }
      var O = P(xa, -a / 2, zf(xa));
      MR.push(plane(O, sb(P(xb, -a / 2, zf(xb)), O), mu(Wd, a), 'm', pid, ext(po, { out: out, ch: 250 })));
    }
  }
  var MR = [];
  mitAF(o, 'mantel', function () {
    wand([0, l0, xk, L], zT, Hd);
    wand([0, l0, xk, L], zB, mu(Hd, -1));
    wand([xc, xk, L], zU, mu(Hd, -1));
    wand([xc, xk, L], zL, Hd);
  });
  /* Laengsfalz: Band auf den Seitenblechen entlang aller Mantelkanten */
  if (o.falzB) {
    mitAF(o, 'falz', function () {
      if (o.falzT) { each(MR, function (pr) { taschenRandE(pr, o.falzT, pid, o); }); }
      var fb = o.falzB;
      each([1, -1], function (sg) {
        var y = sg * (a / 2 + 0.6), n = mu(Wd, sg);
        each([[[0, l0, xk, L], zT, -1], [[0, l0, xk, L], zB, 1], [[xc, xk, L], zU, 1], [[xc, xk, L], zL, -1]], function (K) {
          var xs = K[0], zf = K[1], ri2 = K[2];
          for (i = 0; i !== xs.length - 1; i++) {
            var xa = xs[i], xb = xs[i + 1]; if (!gt(xb - xa, 0.5)) { continue; }
            face([P(xa, y, zf(xa)), P(xb, y, zf(xb)), P(xb, y, zf(xb) + ri2 * fb), P(xa, y, zf(xa) + ri2 * fb)], 'm', pid, { n: n, c: '#D1DAE4', b: 25, cls: o.cls });
            line([P(xa, y, zf(xa) + ri2 * fb), P(xb, y, zf(xb) + ri2 * fb)], pid, { w: 0.75, s: '#5E7189', b: 25.2, cls: o.cls });
          }
        });
      });
    });
  }
  var cU = P(L, 0, zT1 - d / 2), cL = P(L, 0, zB1 + hh / 2);
  mitAF(o, 'innen', function () {
    innenRechteck(p0, mu(A, -1), Wd, a, Hd, b, pid, o);
    innenRechteck(cU, A, Wd, a, Hd, d, pid, o); innenRechteck(cL, A, Wd, a, Hd, hh, pid, o);
  });
  mitAF(o, 'rahmen', function () {
    profil(p0, A, Wd, a, Hd, b, pid, o);
    profil(cU, mu(A, -1), Wd, a, Hd, d, pid, o); profil(cL, mu(A, -1), Wd, a, Hd, hh, pid, o);
  });
  return { zT1: zT1, zB1: zB1, zIu: zIu, zIl: zIl, P: P, l0: l0, l1: l1, xc: xc };
}
/* Uebergang eckig-rund: Rechteck (w entlang Wd, h entlang Hd) bei p0, Kreis r bei p0+A*L.
   Symbol: o.naht Schweissnaht in der Mitte des Dreiecks an der Seite +Wd */
function uebergang(p0, A, L, Wd, w, Hd, h, r, m, pid, o) {
  o = o || {};
  var pc = ad(p0, mu(A, L)), K = [], k, j, triIt = [];
  var sgn = [[1, -1], [1, 1], [-1, 1], [-1, -1]];
  for (k = 0; k !== 4; k++) { K.push(ad(ad(p0, mu(Wd, sgn[k][0] * w / 2)), mu(Hd, sgn[k][1] * h / 2))); }
  function KP(a) { return ad(ad(pc, mu(Wd, r * Math.cos(a))), mu(Hd, r * Math.sin(a))); }
  function RD(a) { return ad(mu(Wd, Math.cos(a)), mu(Hd, Math.sin(a))); }
  /* Ecke k gehoert zum Viertelbogen von a0 bis a1 */
  var bog = [[-Math.PI / 2, 0], [0, Math.PI / 2], [Math.PI / 2, Math.PI], [Math.PI, 1.5 * Math.PI]], nb = 8;
  mitAF(o, 'ecke', function () {
    for (k = 0; k !== 4; k++) {
      var G = [[], []], NG = [[], []];
      for (j = 0; j !== nb + 1; j++) {
        var a = bog[k][0] + (bog[k][1] - bog[k][0]) * j / nb;
        G[0].push(K[k]); G[1].push(KP(a));
        var rk = nz(sb(K[k], p0)); NG[0].push(rk); NG[1].push(RD(a));
      }
      var res = patch(G, m, pid, { NG: NG, e0: 1, e1: 1, noedge: 0, cls: o.cls });
      /* Faecherlinien */
      for (j = 1; j !== nb; j++) {
        if (j % 2 === 1) { continue; }
        var q = res.Q[0][Math.min(nb - 1, j)];
        if (q.it) { line([K[k], KP(bog[k][0] + (bog[k][1] - bog[k][0]) * j / nb)], pid, { d: q.it.d + 0.3, w: 0.6, s: '#6F829A', op: 0.9, cls: o.cls }); }
      }
    }
  });
  /* Dreiecke an den Seiten */
  mitAF(o, 'drei', function () {
    for (k = 0; k !== 4; k++) {
      var aM = bog[k][1], tri = [K[k], K[(k + 1) % 4], KP(aM)];
      var nn = newell(tri), mid = mitte(tri);
      if (lt(dt(nn, sb(mid, ad(p0, mu(A, L / 2)))), 0)) { nn = mu(nn, -1); }
      var it = face(tri, m, pid, { n: nn, cls: o.cls });
      triIt.push(it);
      if (it) { line(tri.concat([tri[0]]), pid, { d: it.d + 0.5, w: 0.9, cls: o.cls }); }
    }
  });
  if (o.naht) {
    mitAF(o, 'naht', function () {
      var it = triIt[0]; if (!it) { if (!D3) { return; } }
      var a1 = ad(p0, mu(Wd, w / 2)), b1 = KP(0), dd = it ? it.d : 0;
      if (o.haken) {
        /* Hakenfalz (Fable Runde 17): zwei umgelegte Kanten eingehakt und flach zugedrueckt; aussen liegt ein flaches Band
           (Breite o.haken) auf dem Blech, eine Kante ist die Falzkante, an der anderen laeuft das zweite Blech unter das Band */
        var tr = [K[0], K[1], KP(bog[0][1])], nn = newell(tr); if (lt(dt(nn, Wd), 0)) { nn = mu(nn, -1); }
        var q = nz(cr(nn, sb(b1, a1))), hb = o.haken / 2, e0 = lp(a1, b1, 0.03), e1 = lp(a1, b1, 0.97), up = mu(nn, 0.8);
        var B = [ad(ad(e0, mu(q, -hb)), up), ad(ad(e1, mu(q, -hb)), up), ad(ad(e1, mu(q, hb)), up), ad(ad(e0, mu(q, hb)), up)];
        face(B, m, pid, { n: nn, d: dd + 0.6, c: '#D1DAE4', two: 1 });
        line([B[0], B[1]], pid, { d: dd + 0.7, w: 1, s: '#3E4B5C' });
        line([B[3], B[2]], pid, { d: dd + 0.7, w: 0.7, s: '#5E7189' });
        line([ad(B[3], mu(q, -2.5)), ad(B[2], mu(q, -2.5))], pid, { d: dd + 0.72, w: 0.6, s: '#FFFFFF', op: 0.9 });
        return;
      }
      line([lp(a1, b1, 0.03), lp(a1, b1, 0.97)], pid, { d: dd + 0.6, w: 2.6, s: '#6C7887' });
      line([lp(a1, b1, 0.03), lp(a1, b1, 0.97)], pid, { d: dd + 0.7, w: 0.8, s: '#E9EEF3' });
    });
  }
  mitAF(o, 'rahmen', function () { profil(p0, A, Wd, w, Hd, h, pid, o); });
  return { pc: pc };
}

/* Viereck als Gitterflaeche (fuer Trapeze): Ecken a, b, c, d im Umlauf, Normale nach out */
function viereck(a, b, c, d, out, m, pid, o) {
  o = o || {};
  var nu = Math.max(1, Math.ceil(Math.max(len(sb(d, a)), len(sb(c, b))) / (o.ch || 250))), nv = Math.max(1, Math.ceil(Math.max(len(sb(b, a)), len(sb(c, d))) / (o.chv || 300))), G = [];
  for (var i = 0; i !== nu + 1; i++) {
    var ea = lp(a, d, i / nu), eb = lp(b, c, i / nu), row = [];
    for (var j = 0; j !== nv + 1; j++) { row.push(lp(ea, eb, j / nv)); }
    G.push(row);
  }
  return patch(G, m, pid, { out: out, e0: o.e0 !== false, e1: o.e1 !== false, f0: o.f0 !== false, f1: o.f1 !== false, cls: o.cls, b: o.b, noedge: o.noedge });
}
/* Etagenstueck eckig (Versatz in einer Ebene): Anfang p0, Richtung A, Laenge L, Versatz off in Richtung Od (senkrecht zu A),
   Querschnitt w (entlang Od) mal h; gerade Enden l0, dazwischen schraeg. Die Mantelbleche (senkrecht zur Versatzebene)
   sind zweimal gekantet, die Seitenbleche (in der Versatzebene) Z-foermig. Die Knicke sind je Wand versetzt,
   damit der Querschnitt im schraegen Teil gleich bleibt.
   Symbol: o.A Bereiche seite, mantel, falz, rahmen; o.falzB Falzband auf den Seitenblechen; o.innenFl Innenflaechen */
function etageR(p0, A, L, Od, off, w, h, l0, m, pid, o) {
  o = o || {};
  var Bn = nz(cr(A, Od)), al = Math.atan2(off, L - 2 * l0), t = w / 2 * Math.tan(al / 2);
  function P3(s, y, z) { return ad(ad(ad(p0, mu(A, s)), mu(Od, y)), mu(Bn, z)); }
  var poly = [[0, -w / 2], [l0 + t, -w / 2], [L - l0 - t, off - w / 2], [L, off - w / 2], [L, off + w / 2], [L - l0 + t, off + w / 2], [l0 - t, w / 2], [0, w / 2]];
  var wg = {};
  mitAF(o, 'seite', function () {
    each([1, -1], function (sg) {
      var p3 = poly.map(function (q) { return P3(q[0], q[1], sg * h / 2); });
      var it = face(p3, m, pid, { n: mu(Bn, sg), cls: o.cls });
      wg[sg] = it;
      if (it) { line(p3.concat([p3[0]]), pid, { d: it.d + 0.5, cls: o.cls }); }
    });
  });
  /* Mantel: je Seite drei ebene Stuecke, an den Knicken gekantet */
  var MW = [[0, 1, -1], [1, 2, -1], [2, 3, -1], [7, 6, 1], [6, 5, 1], [5, 4, 1]];
  var MR = [];
  function mantel(mm, noedge) {
    each(MW, function (mw) {
      var a = poly[mw[0]], b = poly[mw[1]], O = P3(a[0], a[1], -h / 2), U = sb(P3(b[0], b[1], -h / 2), O);
      var out = nz(cr(U, Bn)); if (lt(dt(out, mu(Od, mw[2])), 0)) { out = mu(out, -1); }
      var pr = plane(O, U, mu(Bn, h), mm, pid, { out: mm === 'i' ? mu(out, -1) : out, ch: 250, cls: o.cls, noedge: noedge });
      if (mm !== 'i') { MR.push(pr); }
    });
  }
  mitAF(o, 'mantel', function () { mantel(m, 0); });
  var pe = P3(L, off, 0);
  mitAF(o, 'innen', function () { innenRechteck(p0, mu(A, -1), Od, w, Bn, h, pid, o); innenRechteck(pe, A, Od, w, Bn, h, pid, o); });
  mitAF(o, 'rahmen', function () {
    if (o.fr0 !== false) { profil(p0, A, Od, w, Bn, h, pid, o); }
    if (o.fr1 !== false) { profil(pe, mu(A, -1), Od, w, Bn, h, pid, o); }
  });
  if (o.falzB) {
    /* Falzband entlang der Mantelkanten auf beiden Seitenblechen (Bord der Seitenbleche, Tasche am Mantel) */
    mitAF(o, 'falz', function () {
      if (o.falzT) { each(MR, function (pr) { taschenRandE(pr, o.falzT, pid, o); }); }
      var fb = o.falzB;
      each([1, -1], function (sg) {
        var it = wg[sg]; if (!it) { return; }
        var z = sg * (h / 2 + 0.5);
        each([[0, 1, 2, 3, 1], [7, 6, 5, 4, -1]], function (kz) {
          for (var k = 0; k !== 3; k++) {
            var a = poly[kz[k]], b = poly[kz[k + 1]], d = nz(sb([b[0], b[1], 0], [a[0], a[1], 0])), nn = [-d[1] * kz[4], d[0] * kz[4]];
            var a2 = [a[0] + nn[0] * fb, a[1] + nn[1] * fb], b2 = [b[0] + nn[0] * fb, b[1] + nn[1] * fb];
            face([P3(a[0], a[1], z), P3(b[0], b[1], z), P3(b2[0], b2[1], z), P3(a2[0], a2[1], z)], m, pid, { n: mu(Bn, sg), d: it.d + 0.35, c: '#D1DAE4' });
            line([P3(a2[0], a2[1], z), P3(b2[0], b2[1], z)], pid, { d: it.d + 0.45, w: 0.75, s: '#5E7189' });
          }
        });
      });
    });
  }
  if (o.innenFl) {
    innenTeil(function () {
      each([1, -1], function (sg) { face(poly.map(function (q) { return P3(q[0], q[1], sg * h / 2); }), 'i', pid, { n: mu(Bn, -sg) }); });
      mantel('i', 1);
    });
  }
  return { pe: pe, Bn: Bn };
}
/* Uebergang eckig-eckig: Anfang p0 (Mitte), Richtung A, Laenge L, Querschnitt w0 x h0 (entlang Wd, Hd) auf w1 x h1.
   Die Mitte am Ende ist um ew (entlang Wd) und eh (entlang Hd) versetzt; einseitig z. B. ew = (w1 - w0) / 2.
   Kurze gerade Ansaetze (o.st, 30 mm, ueblicher Standard) fuer die Rahmen, dazwischen vier ebene Trapezbleche (vierteilig).
   Symbol: o.A Bereiche bleche, falz, rahmen; Eckfalz (Pittsburgh) an allen vier Ecken, o.falz = false ohne; o.innenFl Innenflaechen.
   Familie Etagenstueck und Uebergang (Dimi 09.11.2026): o.A mit seite und mantel teilt die Bleche auf, die zwei seitlichen
   (quer zu Wd) sind Seitenbleche, oben und unten (quer zu Hd) Mantelbleche; o.falzB Falzband auf den Seitenblechen
   entlang der vier Eckfalze (wie beim Etagenstueck). */
function reduzR(p0, A, L, Wd, w0, w1, Hd, h0, h1, ew, eh, m, pid, o) {
  o = o || {};
  var st = o.st === undefined ? 30 : o.st, sg = [[1, -1], [1, 1], [-1, 1], [-1, -1]];
  var pa = ad(p0, mu(A, st)), pz = ad(ad(ad(p0, mu(A, L)), mu(Wd, ew)), mu(Hd, eh)), pb = sb(pz, mu(A, st));
  function K(c, w, h, k) { return ad(ad(c, mu(Wd, sg[k][0] * w / 2)), mu(Hd, sg[k][1] * h / 2)); }
  var R0 = [], Ra = [], Rb = [], R1 = [], k, seiten = [], WS = [];
  for (k = 0; k !== 4; k++) { R0.push(K(p0, w0, h0, k)); Ra.push(K(pa, w0, h0, k)); Rb.push(K(pb, w1, h1, k)); R1.push(K(pz, w1, h1, k)); }
  function aussen(Pa, Pb, k) {
    var mid = mitte([Pa[k], Pa[(k + 1) % 4], Pb[(k + 1) % 4], Pb[k]]), ax = lp(lp(Pa[0], Pa[2], 0.5), lp(Pb[0], Pb[2], 0.5), 0.5);
    return sb(mid, ax);
  }
  function wand(Pa, Pb, k, mm, noedge) {
    var a = Pa[k], b = Pa[(k + 1) % 4], c = Pb[(k + 1) % 4], d = Pb[k], out = aussen(Pa, Pb, k);
    return viereck(a, b, c, d, mm === 'i' ? mu(out, -1) : out, mm, pid, { cls: o.cls, noedge: noedge, ch: 200 });
  }
  var geteilt = o.A ? (o.A.seite !== undefined || o.A.mantel !== undefined) : false;
  function wkey(k) { return geteilt ? (k % 2 === 0 ? 'seite' : 'mantel') : 'bleche'; }
  each([0, 1, 2, 3], function (k) {
    mitAF(o, wkey(k), function () {
      var w = {};
      if (st) { w.s0 = wand(R0, Ra, k, m, 0); w.s1 = wand(Rb, R1, k, m, 0); }
      w.t = wand(Ra, Rb, k, m, 0);
      WS[k] = w; seiten[k] = w.t;
    });
  });
  mitAF(o, 'innen', function () { innenRechteck(p0, mu(A, -1), Wd, w0, Hd, h0, pid, o); innenRechteck(pz, A, Wd, w1, Hd, h1, pid, o); });
  mitAF(o, 'rahmen', function () {
    if (o.fr0 !== false) { profil(p0, A, Wd, w0, Hd, h0, pid, o); }
    if (o.fr1 !== false) { profil(pz, mu(A, -1), Wd, w1, Hd, h1, pid, o); }
  });
  /* Falzband: Streifen der Breite o.falzB auf jedem Seitenblech entlang beider Eckkanten (Ansatz, Trapez, Ansatz) */
  if (o.falzB) {
    mitAF(o, 'falz', function () {
      var RR = st ? [R0, Ra, Rb, R1] : [R0, R1];
      each(o.falzT ? [0, 1, 2, 3] : [0, 2], function (k) {
        var w = WS[k], fb = (k % 2 === 0) ? o.falzB : o.falzT; if (!w) { return; }
        var stueck = st ? [w.s0, w.t, w.s1] : [w.t];
        each([[k, (k + 1) % 4], [(k + 1) % 4, k]], function (ck) {
          for (var j = 0; j !== RR.length - 1; j++) {
            var q = stueck[j]; if (!q) { continue; }
            var dd = null; each(q.Q, function (row) { each(row, function (c) { if (c.it) { if (!c.inn) { dd = dd === null ? c.it.d : Math.max(dd, c.it.d); } } }); });
            if (!D3) { if (dd === null) { continue; } }
            var out = nz(aussen(RR[j], RR[j + 1], k)), h = mu(out, 0.5);
            var a0 = RR[j][ck[0]], a1 = RR[j + 1][ck[0]];
            var i0 = ad(a0, mu(nz(sb(RR[j][ck[1]], a0)), fb)), i1 = ad(a1, mu(nz(sb(RR[j + 1][ck[1]], a1)), fb));
            face([ad(a0, h), ad(a1, h), ad(i1, h), ad(i0, h)], m, pid, { n: out, d: (dd || 0) + 0.35, c: '#D1DAE4', cls: o.cls });
            line([ad(i0, h), ad(i1, h)], pid, { d: (dd || 0) + 0.45, w: 0.75, s: '#5E7189', cls: o.cls });
          }
        });
      });
    });
  } else if (o.falz !== false) {
    /* Eckfalz (Pittsburgh) an jeder Ecke: Linie dicht neben der Ecke auf dem anschliessenden Blech */
    mitAF(o, 'falz', function () {
      each([0, 1, 2, 3], function (k) {
        var q = seiten[k]; if (!q) { return; }
        var a0 = R0[(k + 1) % 4], a1 = R1[(k + 1) % 4], b0 = R0[k], b1 = R1[k];
        var e0 = lp(a0, b0, 14 / len(sb(a0, b0))), e1 = lp(a1, b1, 14 / len(sb(a1, b1)));
        var dd = null; each(q.Q, function (row) { each(row, function (c) { if (c.it) { dd = dd === null ? c.it.d : Math.max(dd, c.it.d); } }); });
        if (dd !== null) { line([e0, e1], pid, { d: dd + 0.4, w: 0.8, s: '#5E7189', cls: o.cls }); }
      });
    });
  }
  if (o.innenFl) {
    innenTeil(function () { for (k = 0; k !== 4; k++) { if (st) { wand(R0, Ra, k, 'i', 1); wand(Rb, R1, k, 'i', 1); } wand(Ra, Rb, k, 'i', 1); } });
  }
  return { pe: pz };
}

/* ---------- Runde Teile ---------- */
/* Segmentbogen: Anfang p0 (Mittellinie), Richtung A, Biegerichtung Tn, Radius R, Rohrradius r.
   o.g Stosswinkel in Grad (Standard 90 Grad aus fuenf Segmenten; 45 Grad: [0, 11.25, 33.75, 45], halbe Endsegmente 11,25 Grad).
   o.nw Winkel der Laengsnaehte (gerade und ungerade Segmente) in der Basis aussen/Bn, Standard 0,36 und 0,64 pi.
   Symbol: o.naht Laengsnaht je Segment (versetzt), o.enden ohne Randlinie an den Enden (Anschlussenden folgen) */
function segBogen(p0, A, Tn, R, r, m, pid, o) {
  o = o || {};
  var Bn = nz(cr(A, Tn)), C = ad(p0, mu(Tn, R)), g = o.g || [0, 11.25, 33.75, 56.25, 78.75, 90], k, i, nS = g.length - 1;
  function rho(f) { return ad(mu(Tn, -Math.cos(f)), mu(A, Math.sin(f))); }
  function tang(f) { return ad(mu(Tn, Math.sin(f)), mu(A, Math.cos(f))); }
  var J = []; /* Knoten der Mittellinie in den Stossebenen */
  for (k = 0; k !== g.length; k++) {
    var f = g[k] * Math.PI / 180, Rk = (k === 0 || k === g.length - 1) ? R : R / Math.cos(11.25 * Math.PI / 180);
    J.push(ad(C, mu(rho(f), Rk)));
  }
  function SP(k0, kk, a) {
    var ax = nz(sb(J[k0 + 1], J[k0])), nn = nz(cr(ax, Bn)), mj = tang(g[kk] * Math.PI / 180);
    var v = ad(mu(nn, Math.cos(a)), mu(Bn, Math.sin(a))), q0 = ad(J[k0], mu(v, r)), s = -dt(sb(q0, C), mj) / dt(ax, mj);
    return { p: ad(q0, mu(ax, s)), v: v };
  }
  for (k = 0; k !== nS; k++) {
    var G = [], NG = [];
    each([k, k + 1], function (kk) {
      var row = [], nr = [];
      for (i = 0; i !== 28; i++) { var q = SP(k, kk, 2 * Math.PI * i / 28); row.push(q.p); nr.push(q.v); }
      G.push(row); NG.push(nr);
    });
    var e0 = (k === 0 ? (o.enden ? 0 : 1) : 1), e1 = (k === nS - 1 ? (o.enden ? 0 : 1) : 1);
    var res = mitAF(o, 'seg', function () {
      return patch(G, m, pid, { wrap: 1, NG: NG, e0: e0, e1: e1, ew: (k === 0 ? 1 : 1.25), cls: o.cls, eaR: (o.A ? o.A.umf : undefined), ewR: (o.A ? 1.9 : undefined) });
    });
    if (!o.enden) {
      mitAF(o, 'innen', function () {
        if (k === 0) { oeffnung(G[0], mu(A, -1), pid, o); }
        if (k === nS - 1) { oeffnung(G[1], tang(g[nS] * Math.PI / 180), pid, o); }
      });
    }
    if (o.naht) {
      mitAF(o, 'naht', function () {
        var NW = o.nw || [0.36 * Math.PI, 0.64 * Math.PI], an = NW[k % 2], ia = (Math.round(an / (2 * Math.PI) * 28) % 28 + 28) % 28, q = res.Q[0][ia];
        if (!q.it) { return; }
        var pa = SP(k, k, an).p, pb = SP(k, k + 1, an).p;
        line([lp(pa, pb, 0.06), lp(pa, pb, 0.94)], pid, { d: q.it.d + 0.4, w: 1.1, s: '#5E7189' });
        line([lp(pa, pb, 0.06), lp(pa, pb, 0.94)], pid, { d: q.it.d + 0.45, w: 0.6, s: '#FFFFFF', op: 0.9 });
      });
    }
  }
  /* Stehfalz zwischen den Segmenten (o.rippe, Hoehe in mm; Fable Runde 17, nach der Betriebsanleitung der Segmentbogenmaschine):
     einfacher Bord und doppelter Bord liegen ineinander und sind verpresst, der Falz steht als Rippe rund um das Rohr */
  if (o.rippe) {
    for (k = 1; k !== nS; k++) {
      (function (kk) {
        var mj = tang(g[kk] * Math.PI / 180);
        mitAF(o, 'umf', function () { falzRippe(function (a) { return SP(kk - 1, kk, a); }, J[kk], mj, r, o.rippe, pid, o); });
      })(k);
    }
  }
  /* Ende und Richtung am Ende (auch fuer Boegen unter 90 Grad, o.g) */
  return { pe: J[g.length - 1], te: tang(g[nS] * Math.PI / 180), C: C };
}
/* Stehender Falz als Rippe in einer Stossebene: SPf(a) liefert { p, v } auf dem Rohrumfang (Winkel a), c Mitte des Stosses,
   mj Normale der Stossebene, r Rohrradius, hr Hoehe. Zwei Ringflaechen (Vorder- und Rueckseite, 2,4 mm auseinander) und die
   Aussenkante. Zeichnung: Stuecke auf der zugewandten Seite liegen ueber den Segmentflaechen (Zuschlag), die anderen dahinter */
function falzRippe(SPf, c, mj, r, hr, pid, o) {
  var n = 36, i, f = (r + hr) / r, dk = 1.2;
  function Q(a, s) { var q = SPf(a); return { i: ad(q.p, mu(mj, s)), o: ad(ad(c, mu(sb(q.p, c), f)), mu(mj, s)), v: q.v }; }
  for (i = 0; i !== n; i++) {
    var a0 = 2 * Math.PI * i / n, a1 = 2 * Math.PI * (i + 1) / n, vm = SPf((a0 + a1) / 2).v, vorn = gt(dt(vm, VV), 0);
    var bz = D3 ? 0 : (vorn ? 110 : -110);
    each([1, -1], function (sg) {
      var A0 = Q(a0, sg * dk), A1 = Q(a1, sg * dk), nn = mu(mj, sg);
      var it = face([A0.i, A1.i, A1.o, A0.o], 'm', pid, { n: nn, b: bz + (sicht(nn) ? 0.2 : 0), cls: o.cls, c: sicht(nn) || D3 ? undefined : '#C9D3DF' });
      if (it) { if (!D3) { line([A0.o, A1.o], pid, { d: it.d + 0.3, w: 0.9, cls: o.cls }); } }
    });
    var B0 = Q(a0, -dk), B1 = Q(a1, -dk), C0 = Q(a0, dk), C1 = Q(a1, dk);
    if (D3) { face([B0.o, B1.o, C1.o, C0.o], 'm', pid, { n: vm, cls: o.cls }); line([B0.o, B1.o], pid, { w: 0.9, cls: o.cls }); line([C0.o, C1.o], pid, { w: 0.9, cls: o.cls }); }
    else if (vorn) { face([B0.o, B1.o, C1.o, C0.o], 'm', pid, { n: vm, b: bz + 0.25, cls: o.cls }); }
  }
}
/* Umfangsnaht runder Formstuecke (Fable Runde 17, Dimi 11.11.2026: mit der Sickenmaschine geformt und punktgeschweisst):
   Die Sickenmaschine weitet oder zieht ein Ende so, dass die Teile ueberlappen; in der Ueberlappung sitzen die Schweisspunkte.
   Gezeichnet: Band der Breite bw um das Rohr (c Mitte, A Achse, r Radius an der Naht) und Schweisspunkte im Abstand ab */
function umfangsNaht(c, A, r, pid, o) {
  o = o || {};
  var F = o.F || rahmen([sb(c, A), ad(c, A)]), bw = o.bw || 14, n = 36, np = Math.max(8, Math.round(2 * Math.PI * r / (o.ab || 42))), i, k;
  var G = [], NG = [];
  each([-bw / 2, bw / 2], function (s) {
    var row = [], nr = [];
    for (i = 0; i !== n; i++) { var a = 2 * Math.PI * i / n, v = ad(mu(F.N[0], Math.cos(a)), mu(F.B[0], Math.sin(a))); row.push(ad(ad(c, mu(A, s)), mu(v, r + 1.6))); nr.push(v); }
    G.push(row); NG.push(nr);
  });
  patch(G, 'm', pid, { wrap: 1, NG: NG, e0: 1, e1: 1, b: o.b, ew: 0.8 });
  for (i = 0; i !== np; i++) {
    var ap = 2 * Math.PI * (i + 0.5) / np, vp = ad(mu(F.N[0], Math.cos(ap)), mu(F.B[0], Math.sin(ap)));
    if (!D3) { if (!gt(dt(vp, VV), 0.12)) { continue; } }
    var cp = ad(c, mu(vp, r + 2.4)), t = nz(cr(A, vp)), pts = [];
    for (k = 0; k !== 8; k++) { var w = 2 * Math.PI * k / 8; pts.push(ad(cp, ad(mu(A, 4.2 * Math.cos(w)), mu(t, 4.2 * Math.sin(w))))); }
    face(pts, 'd', pid, { n: vp, c: '#4B5666', b: (o.b || 0) + 0.6, k: 1 });
  }
}
/* Fuegebord eines Abzweigs (Fable Runde 17, Dimi 11.11.2026: Abzweig mit der Sickenmaschine geformt und punktgeschweisst): schmaler
   Bord (Breite bw) rund um den Abzweig, er liegt auf dem Grundkoerper; darin die Schweisspunkte. pm Punkt auf der Achse Am des
   Grundkoerpers, Ab Achse des Abzweigs mit den Querrichtungen e1, e2; sF(t, rr) Abstand der Verschneidung entlang Ab */
function fuegeBord(pm, Am, Ab, e1, e2, sF, r, bw, pid, o) {
  var rs = r + bw, G = [], NG = [], i, k, n = 48;
  function pk(t, rr, hh) {
    var v = ad(mu(e1, Math.cos(t)), mu(e2, Math.sin(t))), p = ad(ad(pm, mu(Ab, sF(t, rr))), mu(v, rr)), d = sb(p, pm), nn = nz(sb(d, mu(Am, dt(d, Am))));
    return { p: ad(p, mu(nn, hh)), n: nn };
  }
  for (i = 0; i !== n + 1; i++) { var t = 2 * Math.PI * (i % n) / n, a = pk(t, r, 1.6), b = pk(t, rs, 1.6); G.push([a.p, b.p]); NG.push([a.n, b.n]); }
  patch(G, 'm', pid, { NG: NG, e0: 0, e1: 0, f0: 0, f1: 1, cls: o.cls, b: o.bN || 1.5 });
  var np = o.np || 10;
  for (i = 0; i !== np; i++) {
    var c3 = pk(2 * Math.PI * (i + 0.5) / np, (r + rs) / 2, 2.6);
    if (!D3) { if (!gt(dt(c3.n, VV), 0.05)) { continue; } }
    var u1 = nz(cr(c3.n, Am)), u2 = nz(cr(c3.n, u1)), q3 = [];
    for (k = 0; k !== 8; k++) { var w3 = 2 * Math.PI * k / 8; q3.push(ad(c3.p, ad(mu(u1, 5 * Math.cos(w3)), mu(u2, 5 * Math.sin(w3))))); }
    face(q3, 'd', pid, { n: c3.n, c: '#4B5666', b: (o.bN || 1.5) + 1.5, cls: o.cls, k: 1 });
  }
}
/* Sattelstutzen auf Rohr: pm Mitte Hauptrohr, Am Achse Hauptrohr, R Radius; Ab Abzweigrichtung, r Radius, Lb Laenge ab Achse */
function sattel(pm, Am, R, Ab, r, Lb, m, pid, o) {
  o = o || {};
  var e1 = nz(Am), e2 = nz(cr(Ab, Am)), nr = 28, G = [], NG = [], i, k;
  function sF(t, rr) { var q = R * R - rr * rr * Math.sin(t) * Math.sin(t); return Math.sqrt(Math.max(q, 1)); }
  var nL = Math.max(2, Math.ceil((Lb - R) / 120));
  for (k = 0; k !== nL + 1; k++) {
    var row = [], nrow = [], tt = k / nL;
    for (i = 0; i !== nr; i++) {
      var t = 2 * Math.PI * i / nr, v = ad(mu(e1, Math.cos(t)), mu(e2, Math.sin(t)));
      row.push(ad(ad(pm, mu(Ab, sF(t, r) * (1 - tt) + Lb * tt)), mu(v, r))); nrow.push(v);
    }
    G.push(row); NG.push(nrow);
  }
  mitAF(o, 'abzweig', function () { patch(G, m, pid, { wrap: 1, NG: NG, e0: 1, e1: 1, cls: o.cls, b: o.bA || 2 }); });
  /* Sattelblech */
  var rs = r + (o.breit || 38), G2 = [], N2 = [];
  for (i = 0; i !== 48; i++) {
    var t2 = 2 * Math.PI * i / 48, v2 = ad(mu(e1, Math.cos(t2)), mu(e2, Math.sin(t2)));
    var a1 = ad(ad(pm, mu(Ab, sF(t2, r) + 2)), mu(v2, r)), a2 = ad(ad(pm, mu(Ab, sF(t2, rs) + 2)), mu(v2, rs));
    G2.push([a1, a2]);
    var nrm = nz(sb(ad(pm, mu(Ab, sF(t2, rs))), ad(pm, mu(e1, dt(sb(a2, pm), e1)))));
    N2.push([nrm, nrm]);
  }
  /* Ring als Gitter i=Umfang, j=innen/aussen */
  var G3 = [], N3 = [];
  for (i = 0; i !== 49; i++) { G3.push(G2[i % 48]); N3.push(N2[i % 48]); }
  mitAF(o, 'rand', function () {
    patch(G3, 'm', pid, { NG: N3, e0: 0, e1: 0, f0: 0, f1: 1, cls: o.cls, b: o.bR || 1.5 });
    /* Fuegepunkte */
    for (i = 0; i !== 8; i++) {
      var t3 = Math.PI / 8 + i * Math.PI / 4, rm = (r + rs) / 2, v3 = ad(mu(e1, Math.cos(t3)), mu(e2, Math.sin(t3)));
      var c3 = ad(ad(pm, mu(Ab, sF(t3, rm) + 3)), mu(v3, rm)), nn3 = nz(sb(c3, ad(pm, mu(e1, dt(sb(c3, pm), e1)))));
      if (!D3) { if (!gt(dt(nn3, VV), 0.05)) { continue; } }
      var q3 = [], u1 = nz(cr(nn3, e1)), u2 = nz(cr(nn3, u1));
      for (k = 0; k !== 8; k++) { var aa = 2 * Math.PI * k / 8; q3.push(ad(c3, ad(mu(u1, 9 * Math.cos(aa)), mu(u2, 9 * Math.sin(aa))))); }
      face(q3, 'd', pid, { n: nn3, c: '#4B5666', b: o.bP || 3, cls: o.cls, k: 1 });
    }
  });
  var pe = ad(pm, mu(Ab, Lb));
  mitAF(o, 'ende', function () {
    if (o.sickeB) { sicke(ad(pm, mu(Ab, Lb - 45)), Ab, r, pid, 10, o.sickeB); } else { ring(ad(pm, mu(Ab, Lb - 45)), Ab, r, pid, { w: 1, cls: o.cls }); }
    lippe(pe, Ab, r, pid, { cls: o.cls, b: o.lipB });
  });
  return { pe: pe };
}
/* T-Stueck 90 Grad (klassisch): Abzweig mit Sattelkontur direkt am Grundkoerper gefuegt, ohne Sattelblech.
   pm Mitte auf der Achse, Am Achse Grundkoerper, R Radius; Ab Richtung Abzweig, r Radius, Lb Laenge ab Achse.
   o.A Bereiche: abzweig, naht, ende */
function tStueck90(pm, Am, R, Ab, r, Lb, m, pid, o) {
  o = o || {};
  var e1 = nz(Am), e2 = nz(cr(Ab, Am)), nr = 28, G = [], NG = [], i, k;
  function sF(t, rr) { var q = R * R - rr * rr * Math.sin(t) * Math.sin(t); return Math.sqrt(Math.max(q, 1)); }
  var nL = Math.max(2, Math.ceil((Lb - R) / 120));
  for (k = 0; k !== nL + 1; k++) {
    var row = [], nrow = [], tt = k / nL;
    for (i = 0; i !== nr; i++) {
      var t = 2 * Math.PI * i / nr, v = ad(mu(e1, Math.cos(t)), mu(e2, Math.sin(t)));
      row.push(ad(ad(pm, mu(Ab, sF(t, r) * (1 - tt) + Lb * tt)), mu(v, r))); nrow.push(v);
    }
    G.push(row); NG.push(nrow);
  }
  mitAF(o, 'abzweig', function () { patch(G, m, pid, { wrap: 1, NG: NG, e0: 0, e1: 1, cls: o.cls, b: o.bA || 2 }); });
  /* Fuegenaht entlang der Verschneidung: dunkle Linie mit heller Kante, nur auf der sichtbaren Seite (nicht bei gepressten Teilen) */
  if (!o.ohneNaht) mitAF(o, 'naht', function () {
    var n = 72, Pn = [];
    if (o.bord) { fuegeBord(pm, e1, Ab, e1, e2, sF, r, o.bord, pid, o); }
    for (i = 0; i !== n + 1; i++) {
      var t2 = 2 * Math.PI * i / n, v2 = ad(mu(e1, Math.cos(t2)), mu(e2, Math.sin(t2)));
      Pn.push({ p: ad(ad(pm, mu(Ab, sF(t2, r) + 1)), mu(v2, r + 1.5)), v: v2 });
    }
    for (i = 0; i !== n; i++) {
      var sv = D3 ? true : gt(dt(ad(Pn[i].v, Pn[i + 1].v), VV), 0.05);
      if (sv) {
        line([Pn[i].p, Pn[i + 1].p], pid, { w: o.bord ? 1.1 : (o.nw || 2.2), s: '#3E4B5C', b: (o.bN || 4) + (o.bord ? 2 : 0), cls: o.cls });
        if (!o.bord) { line([ad(Pn[i].p, mu(Ab, 4)), ad(Pn[i + 1].p, mu(Ab, 4))], pid, { w: 0.9, s: '#FFFFFF', b: (o.bN || 4) + 0.1, cls: o.cls, op: 0.9 }); }
      }
    }
  });
  var pe = ad(pm, mu(Ab, Lb));
  mitAF(o, 'ende', function () {
    if (o.sickeB) { sicke(ad(pm, mu(Ab, Lb - 45)), Ab, r, pid, 10, o.sickeB); } else { ring(ad(pm, mu(Ab, Lb - 45)), Ab, r, pid, { w: 1, cls: o.cls }); }
    lippe(pe, Ab, r, pid, { cls: o.cls, b: o.lipB });
  });
  return { pe: pe };
}
/* Lippendichtung am Steckende (schwarzer Ring) */
function lippe(p, A, r, pid, o) {
  o = o || {};
  schlauch(teile(sb(p, mu(A, 14)), p, 50), r + 4, 'g', pid, { cls: o.cls, ew: 0.6, b: o.b || 3, innen: false });
}
/* Reduzierung rund: Anschluss r0 (Laenge 0,2 L), Konus, Anschluss r1 (0,2 L). o.ex Richtung (Einheitsvektor quer zu A):
   exzentrisch, die Seite in Richtung o.ex laeuft gerade durch; die Querschnitte bleiben senkrecht zu A */
function reduz(p0, A, L, r0, r1, m, pid, o) {
  o = o || {};
  var a0 = 0.2, a1 = 0.8, res = null, E = o.ex || null, F0 = rahmen([p0, ad(p0, A)]);
  function mit(t, r) { var c = ad(p0, mu(A, L * t)); return E ? ad(c, mu(E, r0 - r)) : c; }
  function sch(t0, t1, ra, rb, key, n) {
    var C = [], R = [], F = { T: [], N: [], B: [] };
    for (var i = 0; i !== n + 1; i++) {
      var t = t0 + (t1 - t0) * i / n, rr = ra + (rb - ra) * i / n;
      C.push(mit(t, rr)); R.push(rr); F.T.push(A); F.N.push(F0.N[0]); F.B.push(F0.B[0]);
    }
    return mitAF(o, key, function () { return schlauch(C, R, m, pid, { cls: o.cls, innen: false, F: E ? F : undefined }); });
  }
  if (o.fein) {
    var nA = Math.max(2, Math.round(L * a0 / 30)), nK = Math.max(6, Math.round(L * (a1 - a0) / 30));
    sch(0, a0, r0, r0, 'ansch', nA); res = sch(a0, a1, r0, r1, 'konus', nK); sch(a1, 1, r1, r1, 'ansch', nA);
  } else {
    sch(0, a0, r0, r0, 'ansch', 2); res = sch(a0, a1, r0, r1, 'konus', 6); sch(a1, 1, r1, r1, 'ansch', 2);
  }
  mitAF(o, 'innen', function () {
    var q0 = [], q1 = [], p1 = mit(1, r1);
    for (var k = 0; k !== 28; k++) { var aa = 2 * Math.PI * k / 28, v = ad(mu(F0.N[0], Math.cos(aa)), mu(F0.B[0], Math.sin(aa))); q0.push(ad(p0, mu(v, r0))); q1.push(ad(p1, mu(v, r1))); }
    oeffnung(q0, mu(A, -1), pid, o); oeffnung(q1, A, pid, o);
  });
  mitAF(o, 'umf', function () {
    var wq = o.A ? 1.6 : 0.7, cq = o.A ? '#5E7189' : '#6F829A';
    if (o.umfB) {
      /* Bauteilbilder: Ueberlappung mit Schweisspunkten (umfangsNaht) statt der einfachen Linie */
      umfangsNaht(mit(a0, r0), A, r0, pid, { F: F0, b: o.rb, bw: o.umfB }); umfangsNaht(mit(a1, r1), A, r1, pid, { F: F0, b: o.rb, bw: o.umfB });
      return;
    }
    ring(mit(a0, r0), A, r0, pid, { w: wq, s: cq, b: o.rb }); ring(mit(a1, r1), A, r1, pid, { w: wq, s: cq, b: o.rb });
  });
  /* Laengsnaehte von Konus und Anschlussstuecken als eigener Bereich (Dimi 11.11.2026, 07:54: Elementbild „Längsnaht“);
     nur in den Symbolen (o.A.laengs), Achse EX wie bei naht() */
  if (o.A ? o.A.laengs !== undefined : false) {
    mitAF(o, 'laengs', function () {
      var an = 64 * Math.PI / 180, n = 18;
      function rad(t) { return lt(t, a0) ? r0 : (gt(t, a1) ? r1 : r0 + (r1 - r0) * (t - a0) / (a1 - a0)); }
      function pkt(t, d) { var r = rad(t), c = mit(t, r), w = an + d / r; return ad(c, [0, r * Math.cos(w), r * Math.sin(w)]); }
      each([0, 10], function (d) {
        for (var i = 0; i !== n; i++) {
          var t0 = 0.02 + 0.96 * i / n, t1 = 0.02 + 0.96 * (i + 1) / n;
          line([pkt(t0, d), pkt(t1, d)], pid, { s: d ? '#FFFFFF' : '#5E7189', w: d ? 1 : 1.1, b: o.rb, lc: 'butt' });
        }
      });
      /* Runde 18 (Dimi 11.11.2026): Laengsnaht punktgeschweisst wie bei T-Stueck und Steckverbindung (Rollnaht nur beim
         Rundrohr mit Laengsnaht): Schweisspunkte zwischen Blechkante und heller Kante, je Abschnitt (Anschluss, Konus, Anschluss) */
      each([[0.03, a0 - 0.03, 2], [a0 + 0.05, a1 - 0.05, Math.max(3, Math.round(L * (a1 - a0) / 46))], [a1 + 0.03, 0.97, 2]], function (ab) {
        for (var j = 0; j !== ab[2]; j++) {
          var tp = ab[0] + (ab[1] - ab[0]) * (j + 0.5) / ab[2], c = pkt(tp, 5), ax = nz(sb(pkt(tp + 0.01, 5), pkt(tp - 0.01, 5)));
          var nn = nz(sb(c, mit(tp, rad(tp)))), e = nz(cr(ax, nn)), pts = [];
          for (var k = 0; k !== 8; k++) { var w = 2 * Math.PI * k / 8; pts.push(ad(ad(c, mu(nn, 0.6)), ad(mu(ax, 5.5 * Math.cos(w)), mu(e, 5.5 * Math.sin(w))))); }
          face(pts, 'd', pid, { n: nn, c: '#4B5666', b: (o.rb || 0) + 0.5, k: 1 });
        }
      });
    });
  }
  return res;
}
function enddeckelR(p, A, r, pid, o) {
  o = o || {};
  return schlauch(teile(sb(p, mu(A, 50)), p, 60), r + 5, 'm', pid, { cap1: 1, cls: o.cls, rim0: true, b: 4 });
}
/* Flexibles Rohr entlang Kurve */
function flexR(C, r, pid, o) {
  o = o || {};
  var res = schlauch(C, r, 'x', pid, { cls: o.cls, nr: 24, innen: false });
  /* Rillen */
  var L = 0, i;
  for (i = 1; i !== C.length; i++) { L += len(sb(C[i], C[i - 1])); }
  var s = 0, next = 30;
  for (i = 1; i !== C.length; i++) {
    var d = len(sb(C[i], C[i - 1]));
    while (lt(next, s + d)) {
      var t = (next - s) / d, p = lp(C[i - 1], C[i], t), A = nz(sb(C[i], C[i - 1]));
      ring(p, A, r, pid, { w: 0.55, s: '#8E9AA8', h: 0.5, b: o.rb || 1, cls: o.cls });
      next += 32;
    }
    s += d;
  }
  ring(C[0], nz(sb(C[1], C[0])), r + 2, pid, { w: 1.6, s: '#3E4652', b: o.rb || 3, cls: o.cls });
  ring(C[C.length - 1], nz(sb(C[C.length - 1], C[C.length - 2])), r + 2, pid, { w: 1.6, s: '#3E4652', b: o.rb || 3, cls: o.cls });
  return res;
}
function bezier(p0, p1, p2, p3, n) {
  var r = [];
  for (var i = 0; i !== n + 1; i++) {
    var t = i / n, a = (1 - t) * (1 - t) * (1 - t), b = 3 * t * (1 - t) * (1 - t), c = 3 * t * t * (1 - t), d = t * t * t;
    r.push(ad(ad(mu(p0, a), mu(p1, b)), ad(mu(p2, c), mu(p3, d))));
  }
  return r;
}

/* ---------- Bauteile der Anlage (Zubehoer, Geraet, Bau) ---------- */
var FLOWS = [], MARKEN = [], ZONEN = [];
function zone(p, s, an) { ZONEN.push({ p: p, s: s, an: an || 'start' }); }
/* Beschriftung im Overlay: Ankerpunkt, Text, Versatz in Bildeinheiten */
function marke(p, s, dx, dy, cls) { MARKEN.push({ p: p, s: s, dx: dx, dy: dy, cls: cls || 'wsz-of' }); }
/* Luftweg: art ODA SUP ETA EHA, Punkte, Bauteil, Optionen (g Geschwindigkeit, nurOffen, nurZu, pfeil) */
function luft(art, pts, pid, o) { o = o || {}; FLOWS.push({ a: art, p: pts, pid: pid, o: o }); }
function bogenPunkte(C, A, Tn, rm, f0, f1, n) {
  var r = [];
  for (var i = 0; i !== n + 1; i++) { var f = (f0 + (f1 - f0) * i / n) * Math.PI / 180; r.push(ad(C, ad(mu(Tn, -Math.cos(f) * rm), mu(A, Math.sin(f) * rm)))); }
  return r;
}
function schraffur(r, pid, n, o) {
  o = o || {};
  /* Schnittflaeche: Linien unter 45 Grad in u,v */
  var Lu = len(r.U), Lw = len(r.W), d = o.d || 60, k;
  var tot = Lu + Lw;
  for (k = d; lt(k, tot); k += d) {
    var a = [k / Lu, 0], b = [0, k / Lw];
    if (gt(k, Lu)) { a = [1, (k - Lu) / Lw]; }
    if (gt(k, Lw)) { b = [(k - Lw) / Lu, 1]; }
    auf(r, [a, b], pid, { s: '#B5AEA4', w: 0.6, op: 0.9 });
  }
}
function geraet() {
  PIDNOW = 'ahu';
  box(500, 500, -150, 3700, 3100, 0, 'w', 'ahu', { ch: 400, es: '#8C857B', ohne: D3 ? '' : 't' });
  if (!D3) {
    box(500, 3000, -1, 3700, 3100, 0, 'w', 'ahu', { ch: 400, es: '#8C857B', ohne: 'xy' });
    box(3600, 500, -1, 3700, 3000, 0, 'w', 'ahu', { ch: 400, es: '#8C857B', ohne: 'xy' });
  }
  box(600, 600, 0, 3600, 3000, 90, 'd', 'ahu', { ch: 400, ohne: 't' });
  var g = box(600, 600, 90, 3600, 3000, 1600, 'a', 'ahu', { ch: 400 });
  /* Abschnitte auf der Vorderseite (Zuluftseite): u entlang x, v entlang z */
  var tr = [600, 1400, 2200, 2900, 3600], nm = ['Filter', 'WRG', 'Register', 'Ventilator'], Lx = 3000;
  for (var k = 0; k !== 4; k++) {
    var u0 = (tr[k] - 600) / Lx, u1 = (tr[k + 1] - 600) / Lx;
    if (k) { auf(g.y, [[u0, 0], [u0, 1]], 'ahu', { s: '#9AA1A8', w: 1 }); }
    var a0 = u0 + 0.018, a1 = u1 - 0.018, m0 = 0.08, m1 = 0.9;
    auf(g.y, [[a0, m0], [a1, m0], [a1, m1], [a0, m1], [a0, m0]], 'ahu', { s: '#A8AFB6', w: 0.8 });
    auf(g.y, [[a1 - 0.025, 0.42], [a1 - 0.025, 0.58]], 'ahu', { s: '#59616B', w: 2.4 });
    auf(g.y, [[a0 + 0.008, 0.2], [a0 + 0.008, 0.28]], 'ahu', { s: '#8D949B', w: 1.8 });
    auf(g.y, [[a0 + 0.008, 0.7], [a0 + 0.008, 0.78]], 'ahu', { s: '#8D949B', w: 1.8 });
    var uc = (u0 + u1) / 2;
    text([600 + uc * Lx, 3001, 90 + 0.64 * 1510], nm[k], 'ahu', { d: zelleD(g.y, uc, 0.64) + 0.6, fs: 105, fc: '#5C6670', m: 'y', an: 'middle' });
  }
  for (k = 1; k !== 4; k++) { var uu = (tr[k] - 600) / Lx; auf(g.t, [[uu, 0], [uu, 1]], 'ahu', { s: '#A8AFB6', w: 0.8 }); }
  /* Stutzenrahmen oben */
  var st = [[900, 1700, 2300, 2700], [900, 1700, 800, 1200], [2950, 3450, 1900, 2900], [3000, 3400, 800, 1600]];
  each(st, function (s) { box(s[0] - 30, s[2] - 30, 1600, s[1] + 30, s[3] + 30, 1660, 'r', 'ahu', { ch: 400 }); });
  /* Stirnseite (Dimi 11.11.2026, Runde 18: Logo in die obere linke Ecke, in der Standardansicht ganz sichtbar, nicht vom
     Zuluftkanal verdeckt; Schaltkasten und Schild entfallen): das ganze WAMMES-Logo mit Schriftzug, LOGO_B mm lang, Abstand
     LOGO_R zur linken Kante (Ecke zur Tuerseite, y = 3000) und zur Oberkante (z = 1600), ohne Linien oder Schrift darunter.
     Zeichnung: Tiefe nach den Rasterzellen, die das Logo bedeckt; 3D: Viereck im Textatlas (70_drei.js) */
  var lb = LOGO_B, lh = lb * WM_LOGO_H / WM_LOGO_W, ly0 = 3000 - LOGO_R - lb / 2, lz0 = 1600 - LOGO_R - lh / 2, ld = -1e9;
  each([[-1, -1], [1, -1], [-1, 1], [1, 1], [0, 0], [0, -1], [0, 1]], function (q) {
    var dd = g.x ? zelleD(g.x, (ly0 + q[0] * lb / 2 - 600) / 2400, (lz0 + q[1] * lh / 2 - 90) / 1510) : null; if (dd !== null) { if (gt(dd, ld)) { ld = dd; } }
  });
  logo([3601, ly0, lz0], lb, 'ahu', { m: 'x', d: gt(ld, -1e8) ? ld + 0.7 : undefined });
}
var LOGO_B = 800, LOGO_R = 140;
function kompensator(x0, x1, y0, y1, z0, z1, pid) {
  var r = box(x0 - 10, y0 - 10, z0, x1 + 10, y1 + 10, z1, 'f', pid, { ch: 300 });
  each([0.33, 0.66], function (v) {
    each([r.y, r.x, r.ny, r.nx], function (f) { if (f) { auf(f, [[v, 0], [v, 1]], pid, { s: '#4A5058', w: 0.8 }); } });
  });
}
function klappe(x0, x1, y0, y1, z0, z1, pid, seite) {
  var r = box(x0, y0, z0, x1, y1, z1, 'm', pid, { ch: 300 });
  box(x0 - 25, y0 - 25, z0, x1 + 25, y1 + 25, z0 + 25, 'r', pid, {});
  box(x0 - 25, y0 - 25, z1 - 25, x1 + 25, y1 + 25, z1, 'r', pid, {});
  /* Antrieb seitlich */
  if (seite === 'x') { box(x1, (y0 + y1) / 2 - 110, z0 + 40, x1 + 110, (y0 + y1) / 2 + 110, z1 - 40, 'd', pid, {}); }
  else { box((x0 + x1) / 2 - 110, y1, z0 + 40, (x0 + x1) / 2 + 110, y1 + 110, z1 - 40, 'd', pid, {}); }
  return r;
}
function wetter(x0, x1, z0, z1, y, pid) {
  box(x0 - 40, y, z0 - 40, x1 + 40, y + 60, z1 + 40, 'r', pid, { ch: 400 });
  var n = 8;
  for (var k = 0; k !== n; k++) {
    var z = z0 + (z1 - z0) * (k + 0.5) / n;
    face([[x0, y + 61, z + 22], [x1, y + 61, z + 22], [x1, y + 100, z - 18], [x0, y + 100, z - 18]], 'm', pid, { n: nz([0, 1, 1.2]), b: 2, two: D3 ? 1 : 0 });
    line([[x0, y + 100, z - 18], [x1, y + 100, z - 18]], pid, { w: 0.8, b: 3 });
    line([[x0, y + 61, z - 30], [x1, y + 61, z - 30]], pid, { w: 0.6, s: '#59616B', b: 1 });
  }
}
function wandStueck(x0, y0, z0, x1, y1, z1, pid) {
  var r = box(x0, y0, z0, x1, y1, z1, 'w', pid, { ch: 400, es: '#8C857B', ew: 0.9 });
  schraffur(r.t, pid);
  if (r.u) { schraffur(r.u, pid); }
  return r;
}
function dachhaube(xc, yc, z0, o) {
  o = o || {};
  var pid = 'dachhaube';
  /* Aufsetzkranz (Sockel) */
  mitAF(o, 'sockel', function () { kanalL([xc, yc, z0], [0, 0, 1], 300, [1, 0, 0], 900, [0, 1, 0], 500, 'm', pid, { fr0: false, fr1: false, sicke: false }); });
  /* Haube mit Gitter */
  var hx = 560, hy = 360, z1 = z0 + 300, z2 = z1 + 380;
  mitAF(o, 'gitter', function () {
    var r = box(xc - hx, yc - hy, z1, xc + hx, yc + hy, z2, 'i', pid, { ch: 300, ohne: D3 ? '' : 't' });
    for (var k = 1; k !== 12; k++) {
      each([r.y, r.ny], function (f) { if (f) { auf(f, [[0.08, k / 12], [0.92, k / 12]], pid, { s: '#7B8796', w: 0.6 }); } });
      each([r.x, r.nx], function (f) { if (f) { auf(f, [[k / 12, 0.08], [k / 12, 0.92]], pid, { s: '#7B8796', w: 0.6 }); } });
    }
    for (k = 1; k !== 6; k++) {
      each([r.y, r.ny], function (f) { if (f) { auf(f, [[k / 6, 0.05], [k / 6, 0.95]], pid, { s: '#7B8796', w: 0.6 }); } });
      each([r.x, r.nx], function (f) { if (f) { auf(f, [[0.05, k / 6], [0.95, k / 6]], pid, { s: '#7B8796', w: 0.6 }); } });
    }
  });
  /* Pultdach der Haube: hinten hoeher */
  mitAF(o, 'haube', function () {
    var e = 70, x0 = xc - hx - e, x1 = xc + hx + e, y0 = yc - hy - e, y1 = yc + hy + e, zv = z2 + 10, zh = z2 + 120;
    var GD = [], ni = 5, nj = 4;
    for (var gi = 0; gi !== ni + 1; gi++) { var rowD = []; for (var gj = 0; gj !== nj + 1; gj++) { var tj = gj / nj; rowD.push([x0 + (x1 - x0) * gi / ni, y0 + (y1 - y0) * tj, zh + (zv - zh) * tj]); } GD.push(rowD); }
    patch(GD, 'm', pid, { out: [0, zh - zv, y1 - y0], e0: 1, e1: 1, f0: 1, f1: 1, b: 200 });
    /* 3D: Unterseite des Pultdachs (Blech 30 mm darunter) */
    if (D3) { patch(GD.map(function (row) { return row.map(function (q) { return [q[0], q[1], q[2] - 30]; }); }), 'm', pid, { out: [0, zv - zh, y0 - y1] }); }
    plane([x0, y1, zv - 30], [x1 - x0, 0, 0], [0, 0, 30], 'm', pid, { out: [0, 1, 0], b: 220 });
    var R = [[x1, y0, zh - 30], [x1, y1, zv - 30], [x1, y1, zv], [x1, y0, zh]];
    var it2 = face(R, 'm', pid, { n: [1, 0, 0], b: 220 });
    if (it2) { line(R.concat([R[0]]), pid, { d: it2.d + 0.5 }); }
    /* 3D: Rueckkante und linke Stirnseite des Pultdachs */
    if (D3) {
      plane([x0, y0, zh - 30], [x1 - x0, 0, 0], [0, 0, 30], 'm', pid, { out: [0, -1, 0] });
      var R0 = [[x0, y0, zh - 30], [x0, y1, zv - 30], [x0, y1, zv], [x0, y0, zh]];
      face(R0, 'm', pid, { n: [-1, 0, 0] });
      line(R0.concat([R0[0]]), pid, {});
    }
  });
}
function revisionsTuer(r, u0, u1, v0, v1, pid) {
  auf(r, [[u0, v0], [u1, v0], [u1, v1], [u0, v1]], pid, { fill: 1, c: '#E7ECF2', s: NAVY, w: 0.9, b: 0.4 });
  auf(r, [[u0 + 0.012, v0 + 0.08], [u1 - 0.012, v0 + 0.08], [u1 - 0.012, v1 - 0.08], [u0 + 0.012, v1 - 0.08], [u0 + 0.012, v0 + 0.08]], pid, { s: '#7B8796', w: 0.6, b: 0.5 });
  each([0.3, 0.7], function (vv) {
    var v = v0 + (v1 - v0) * vv;
    auf(r, [[u1 - 0.02, v - 0.04], [u1 - 0.02, v + 0.04], [u1 - 0.006, v + 0.04], [u1 - 0.006, v - 0.04]], pid, { fill: 1, c: '#3E4652', s: '#3E4652', w: 0.5, b: 0.6 });
  });
}
function gitterAuf(r, u0, u1, v0, v1, pid) {
  auf(r, [[u0, v0], [u1, v0], [u1, v1], [u0, v1]], pid, { fill: 1, c: '#F7F8FA', s: NAVY, w: 0.9, b: 0.4 });
  for (var k = 1; k !== 6; k++) { var v = v0 + (v1 - v0) * k / 6; auf(r, [[u0 + 0.01, v], [u1 - 0.01, v]], pid, { s: '#8A96A6', w: 0.7, b: 0.5 }); }
}
function abhaengung(xa, ya, za, xb, yb, zb, pid, tief) {
  /* Traverse unter dem Kanal von a nach b auf Hoehe zb, Stangen nach oben bis za.
     tief: Traverse unter einem geoeffneten Schalldaempfer tiefer legen (unter dessen Innenteile) */
  var dx = xb - xa, dy = yb - ya, L = Math.sqrt(dx * dx + dy * dy), t = [dx / L, dy / L, 0];
  var n = [-t[1], t[0], 0], w = 21, m0 = IT.length;
  box(Math.min(xa, xb) - Math.abs(n[0]) * w, Math.min(ya, yb) - Math.abs(n[1]) * w, zb - 41, Math.max(xa, xb) + Math.abs(n[0]) * w, Math.max(ya, yb) + Math.abs(n[1]) * w, zb, 'd', pid, { ch: 300, ew: 0.7 });
  if (tief !== undefined) { for (var i = m0; i !== IT.length; i++) { IT[i].d = tief + (IT[i].d - tief) * 0.001; } }
  each([[xa, ya], [xb, yb]], function (p) { stange(p[0], p[1], zb, za, pid); });
}
function stange(x, y, z0, z1, pid) {
  var L = z1 - z0, t = [0, 0.55, 0.8, 1], o = [1, 0.55, 0.22];
  for (var k = 0; k !== 3; k++) { line([[x, y, z0 + L * t[k]], [x, y, z0 + L * t[k + 1]]], pid, { s: '#56606C', w: 1.1, op: o[k], lc: 'butt' }); }
}
function rohrSchelle(p, A, r, ztop, pid) {
  ring(p, A, r + 4, pid, { w: 1.6, s: '#56606C', b: 3 });
  stange(p[0], p[1], p[2] + r + 6, ztop, pid);
}
/* Brandschutzklappe eckig: Gehaeuse x0..x1, Antriebsseite bei x1 */
function bsk(x0, x1, yc, zc, w, h, pid, wa, wb) {
  var r = box(x0, yc - w / 2 - 25, zc - h / 2 - 25, wa, yc + w / 2 + 25, zc + h / 2 + 25, 'm', pid, { ch: 300 });
  r = box(wb, yc - w / 2 - 25, zc - h / 2 - 25, x1, yc + w / 2 + 25, zc + h / 2 + 25, 'm', pid, { ch: 300 });
  box(x1 - 30, yc - w / 2 - 50, zc - h / 2 - 50, x1, yc + w / 2 + 50, zc + h / 2 + 50, 'r', pid, {});
  /* Ausloeseeinrichtung und Antrieb auf der Bedienseite */
  box(x1 - 170, yc + w / 2 + 25, zc - 90, x1 - 40, yc + w / 2 + 130, zc + 110, 'd', pid, {});
  box(x1 - 150, yc + w / 2 + 130, zc + 20, x1 - 60, yc + w / 2 + 150, zc + 90, 'h', pid, { c: '#FFFFFF' });
  return r;
}
/* Kanal mit Drosselklappe: Verstellsegment auf der Seite +Wd */
function drossel(p0, A, L, Wd, w, Hd, h) {
  var pid = 'kd', r = kanalL(p0, A, L, Wd, w, Hd, h, 'm', pid, { falz: 'ph' });
  var c = ad(ad(ad(p0, mu(A, L / 2)), mu(Wd, w / 2)), mu(Hd, -60));
  function Q(rad, an, off) { return ad(ad(ad(c, mu(A, rad * Math.cos(an))), mu(Hd, rad * Math.sin(an))), mu(Wd, off)); }
  var pts = [], k;
  for (k = 0; k !== 10; k++) { pts.push(Q(150, Math.PI * (0.25 + 0.5 * k / 9), 3)); }
  var sec = [ad(c, mu(Wd, 3))].concat(pts);
  face(sec, 'r', pid, { n: Wd, b: 2 });
  line(sec.concat([sec[0]]), pid, { b: 2.5, w: 0.9 });
  for (k = 1; k !== 9; k++) { var a2 = Math.PI * (0.25 + 0.5 * k / 9); line([Q(120, a2, 4), Q(145, a2, 4)], pid, { b: 3, w: 0.6 }); }
  line([ad(c, mu(Wd, 12)), Q(170, Math.PI * 0.62, 12)], pid, { b: 4, w: 3.2, s: '#3E4652' });
  rohr(c, ad(c, mu(Wd, 45)), 14, pid, { m: 'd', b: 5 });
  return r;
}
/* unsichtbare Trefferflaeche fuer kleine Teile */
function treffer(p, A, r, L, pid) {
  schlauch(teile(sb(p, mu(A, L / 2)), ad(p, mu(A, L / 2)), L), r, 'm', pid, { c: 'transparent', b: 6, innen: false, rim0: false, rim1: false, ew: 0.01 });
}
/* Anschlusskasten mit seitlichem Stutzen (Richtung sx: -1 Stutzen an x0, +1 an x1, 0 an y1) und Durchlass darunter */
function kasten(x0, x1, y0, y1, z0, z1, rs, seite, pidK, pidD) {
  box(x0, y0, z0, x1, y1, z1, 'm', pidK, { ch: 300 });
  var zc = (z0 + z1) / 2, p, A;
  if (seite === 'nx') { p = [x0, (y0 + y1) / 2, zc]; A = [-1, 0, 0]; }
  else if (seite === 'px') { p = [x1, (y0 + y1) / 2, zc]; A = [1, 0, 0]; }
  else { p = [(x0 + x1) / 2, y1, zc]; A = [0, 1, 0]; }
  rohr(p, ad(p, mu(A, 70)), rs, pidK, { rim0: true, b: 2 });
  ring(ad(p, mu(A, 28)), A, rs, pidK, { w: 0.9 });
  /* Durchlass: quadratische Frontplatte, je Seite zwei Schlitzreihen (4 Ausblasrichtungen), Mitte geschlossen.
     Die Schlitze liegen auf der Unterseite; sichtbar beim Blick von unten (3D). */
  var e = 50, dz = 45;
  var d = box(x0 - e, y0 - e, z0 - dz, x1 + e, y1 + e, z0, 'h', pidD, { ch: 300 });
  plane([x1 + e + 0.5, y0 - e + 30, z0 - dz + 8], [0, y1 - y0 + 2 * e - 60, 0], [0, 0, dz - 16], 'h', pidD, { out: [1, 0, 0], c: '#E3E8EE', b: 1 });
  durchlassSchlitze((x0 + x1) / 2, (y0 + y1) / 2, z0 - dz - 1.5, (x1 - x0) / 2 + e, pidD);
  return { p: p, A: A };
}
/* Schlitze der Frontplatte (Unterseite bei z): je Seite zwei Reihen parallel zur Kante, Ecken frei */
function durchlassSchlitze(xc, yc, z, hb, pid) {
  var reihen = [hb * 0.62, hb * 0.78], bs = hb * 0.05;
  each([[1, 0], [-1, 0], [0, 1], [0, -1]], function (q) {
    each(reihen, function (dd) {
      var l = dd - hb * 0.12, a, b, c, d2;
      if (q[0]) { a = [xc + q[0] * (dd - bs), yc - l, z]; b = [xc + q[0] * (dd + bs), yc - l, z]; c = [xc + q[0] * (dd + bs), yc + l, z]; d2 = [xc + q[0] * (dd - bs), yc + l, z]; }
      else { a = [xc - l, yc + q[1] * (dd - bs), z]; b = [xc + l, yc + q[1] * (dd - bs), z]; c = [xc + l, yc + q[1] * (dd + bs), z]; d2 = [xc - l, yc + q[1] * (dd + bs), z]; }
      face([a, b, c, d2], 'd', pid, { n: [0, 0, -1], c: '#4A5361', k: 1 });
    });
  });
}
/* Volumenstromregler rund (Kontext) */
function vvs(p0, A, L, r) {
  var pid = 'vvs';
  rohr(p0, ad(p0, mu(A, L)), r + 3, pid, { m: 'm' });
  var pm = ad(p0, mu(A, L * 0.55));
  box(pm[0] + r - 10, pm[1] - 90, pm[2] - 70, pm[0] + r + 120, pm[1] + 90, pm[2] + 70, 'd', pid, {});
  box(pm[0] + r + 120, pm[1] - 60, pm[2] - 40, pm[0] + r + 150, pm[1] + 60, pm[2] + 40, 'h', pid, { c: '#E9EDF1' });
  ring(ad(p0, mu(A, 60)), A, r + 3, pid, { w: 0.8 });
  ring(ad(p0, mu(A, L - 60)), A, r + 3, pid, { w: 0.8 });
}
function rohrSD(p0, A, L, r, rg) {
  var pid = 'rohrschall';
  var C = [], R = [], n = 24;
  for (var i = 0; i !== n + 1; i++) {
    var t = i / n, s = L * t, q = 0;
    if (lt(s, 80)) { q = 0; } else if (lt(s, 150)) { q = (s - 80) / 70; } else if (lt(s, L - 150)) { q = 1; } else if (lt(s, L - 80)) { q = (L - 80 - s) / 70; } else { q = 0; }
    C.push(ad(p0, mu(A, s))); R.push(r + (rg - r) * q);
  }
  schlauch(C, R, 'm', pid, {});
  ring(ad(p0, mu(A, 150)), A, rg, pid, { w: 0.8 });
  ring(ad(p0, mu(A, L - 150)), A, rg, pid, { w: 0.8 });
}
/* Kulissenschalldaempfer: Gehaeuse x0..x1, y0..y1, z0..z1, Kulissen in y, n Stueck, Dicke T.
   An- und Abstroemprofil halbrund an beiden Enden; Stirnseiten offen. haupt: vordere Kulisse aufgeschnitten.
   o.A Bereiche: geh, krahmen, wolle, abdeck, profil; o.FX ausblenden je Bereich.
   Runde 10 der Szene (Dimi 09.11.2026, Runde 11 Punkt 13, nach Herstellerunterlagen): o.abd Abdeckung 'kammer' (Standard: wechselseitige
   Kammerbleche, je Seite eine Haelfte, sonst Glasseide), 'loch' (Lochblech ganz) oder 'ohne' (nur Glasseide).
   Das Gehaeuse ist ein Rechteckkanal: Steckrahmen, Versteifungssicken, Laengsfalz. */
function kulisse(x0, x1, y0, y1, z0, z1, n, T, haupt, einX1, o) {
  o = o || {};
  var pid = 'kulisse', B = y1 - y0, S = (B - n * T) / n;
  /* Innenteile: Tiefe wird spaeter unter die Gehaeusetiefe gelegt */
  var dmin = x0 + y0 + z0, mark = IT.length;
  mitAF(o, 'innen', function () {
    plane([x0, y0 + 1, z0], [x1 - x0, 0, 0], [0, 0, z1 - z0], 'i', pid, { out: [0, 1, 0], ch: 400, cls: 'sdi', noedge: 1, cull: 1 });
    plane([x0, y0, z0 + 1], [x1 - x0, 0, 0], [0, B, 0], 'i', pid, { out: [0, 0, 1], ch: 400, cls: 'sdi', noedge: 1, cull: 1 });
  });
  /* Kulissen (Runde 11 der Szene, Dimi 10.11.2026, Runde 12 der Antworten): stehend, je Kulisse Rahmen mit An- und Abstroemprofil (Radius), T-Buegelprofil,
     Mineralwolle hinter Glasseide und Abdeckung (31_kulisse.js); vorn sichtbar die Abdeckung */
  for (var k = 0; k !== n; k++) {
    var ya = y0 + S / 2 + k * (S + T), za = z0 + 4, zb = z1 - 4, xa = x0 + 80, xb = x1 - 80;
    /* Runde 12 der Szene: die einzelnen Kulissen sind ein eigenes Bauteil (Schalldämpferkulisse), das Gehaeuse bleibt 'kulisse' */
    kulisseEinzeln([xa, ya, za], xb - xa, zb - za, T, o.pidK || 'skulisse', { steh: 1, abd: o.abd || 'kammer', A: o.A, FX: o.FX, cls: 'sdi' });
    if (haupt ? k === n - 1 : false) {
      var zm = (za + zb) / 2, abd = o.abd || 'kammer';
      marke([xb + KUL_D, ya + T / 2, zm], 'An- und Abströmprofil', -33, 71);
      marke([xa + (xb - xa) * 0.75, ya + T, zm], abd === 'loch' ? 'Lochblech' : (abd === 'ohne' ? 'Glasseide' : 'Kammerblech'), -9, 72);
      marke([xa + (xb - xa) * 0.3, ya + T / 2, zb], 'Kulissenrahmen', 28, 26);
    }
  }
  /* Innenteile in der Tiefe vor das Gehaeuse legen */
  for (var ii = mark; ii !== IT.length; ii++) { IT[ii].d = dmin - 50 + (IT[ii].d - dmin) * 0.001; }
  /* Gehaeuse: Wand +y und Deckel werden beim Oeffnen durchsichtig; Stirnseiten offen */
  mitAF(o, 'geh', function () {
    var oc = { ch: 300, cls: 'sdw', ecls: 'sde' };
    var dk = plane([x0, y0, z1], [x1 - x0, 0, 0], [0, B, 0], 'm', pid, oc);
    var vy = plane([x0, y1, z0], [x1 - x0, 0, 0], [0, 0, z1 - z0], 'm', pid, ext(oc, { out: [0, 1, 0] }));
    /* wie ein Rechteckkanal: Versteifungssicken quer, Laengsfalz an der Kante oben vorn */
    each([[dk, B], [vy, z1 - z0]], function (fb) {
      var f = fb[0], br = fb[1], Lg = x1 - x0, s0 = 110; if (lt(br, 399)) { return; }
      while (lt(s0, Lg - 100)) { var u = s0 / Lg, ra = 30 / br; auf(f, [[u, ra], [u, 1 - ra]], pid, { s: '#FFFFFF', w: 1, op: 0.95, cls: 'sdw' }); auf(f, [[u + 9 / Lg, ra], [u + 9 / Lg, 1 - ra]], pid, { s: '#5E7189', w: 0.75, op: 0.7, cls: 'sdw' }); s0 += 160; }
    });
    auf(dk, [[32 / (x1 - x0), 1 - 20 / B], [1 - 32 / (x1 - x0), 1 - 20 / B], [1 - 32 / (x1 - x0), 1], [32 / (x1 - x0), 1]], pid, { fill: 1, c: '#D1DAE4', b: 0.32, cls: 'sdw' });
    if (D3) {
      plane([x0, y0, z0], [x1 - x0, 0, 0], [0, 0, z1 - z0], 'm', pid, ext(oc, { out: [0, -1, 0] }));
      plane([x0, y0, z0], [x1 - x0, 0, 0], [0, B, 0], 'm', pid, ext(oc, { out: [0, 0, -1] }));
    }
    profil([x0, (y0 + y1) / 2, (z0 + z1) / 2], [1, 0, 0], [0, 1, 0], B, [0, 0, 1], z1 - z0, pid, {});
    profil([x1, (y0 + y1) / 2, (z0 + z1) / 2], [-1, 0, 0], [0, 1, 0], B, [0, 0, 1], z1 - z0, pid, {});
  });
  return { S: S };
}

/* ---------- Schalldaempferkulisse (Runde 11 der Szene, Dimi 10.11.2026, Runde 12 der Antworten, nach Herstellerunterlagen) ----------
   Eine Kulisse: umlaufender Kulissenrahmen (Rahmenprofile an den Laengsseiten mit Laengssicken, An- und Abstroemprofil an
   den Enden; aus der Maschine mit Radius, von Hand 90° gekantet ohne Radius), T-Buegelprofil in der Mitte, Mineralwolle,
   Glasseide und Abdeckung (Kammerblech wechselseitig je eine Haelfte, Lochblech oder ohne, dann nur Glasseide).
   Lage liegend: Laenge x (0..L), Hoehe der Kulisse y (0..H), Dicke z (0..T); o.steh: stehend wie im Gehaeuse (y und z getauscht).
   o.ex: Abstand der Explosionsdarstellung (0 = zusammengebaut), o.abd 'kammer' | 'loch' | 'ohne', o.hand: Profil ohne Radius,
   o.A Bereiche (krahmen, profil, tbuegel, wolle, seide, abdeck, rund), o.FX ausblenden je Bereich, o.cls Klasse aller Teile.
   Runde 19 (Montage in Schritten, Dimi 11.11.2026): o.nur Teile, die gezeichnet werden (rahmenH Langseite hinten y = 0, rahmenV
   Langseite vorn y = H, endeL Profil bei x = 0, endeR Profil bei x = L, abdO, abdU, seideO, seideU, wolle, tbuegel; ohne o.nur alle),
   o.ver Versatz je Teil [x, y, z], o.clsT Klasse je Teil, o.offen: Wolle und T-Buegelprofil nach Tiefe einordnen (Rahmen noch offen; die Wolle liegt dann knapp hinter den Lagen),
   o.ch Teilung der Flaechen, o.nL Teilung der Langseiten. */
var KUL_R = 22, KUL_D = 40, KUL_FL = 30, KUL_K = 16;
/* Runde 18 (Dimi 11.11.2026): Querschnitt des Rahmenprofils, an allen vier Seiten gleich: Steg (Dicke T) und zwei Flansche;
   aus der Maschine mit Radius R (beidseitig umlaufend), von Hand 90° gekantet (R = 0). d: Abstand der Stegflaeche vom Bezug.
   Rueckgabe: Punkte [u, z], Normalen, st Reihe des Stegs, K Gruppen von Reihen der Rundung bzw. Kante (Bereich „rund“) */
function kulProfil(T, R, d, fl) {
  var P = [], N = [], K, j, w = KUL_K, st;
  P.push([-fl, T]); N.push([0, 1]);
  if (R) {
    for (j = 0; j !== 7; j++) { var a = Math.PI / 2 * (1 - j / 6); P.push([d - R + Math.cos(a) * R, T - R + Math.sin(a) * R]); N.push([Math.cos(a), Math.sin(a)]); }
    for (j = 0; j !== 7; j++) { var a2 = -Math.PI / 2 * j / 6; P.push([d - R + Math.cos(a2) * R, R + Math.sin(a2) * R]); N.push([Math.cos(a2), Math.sin(a2)]); }
    K = [[1, 7], [8, 14]]; st = 7;
  } else {
    P.push([d - w, T]); N.push([0, 1]); P.push([d, T]); N.push([0.7, 0.7]); P.push([d, T - w]); N.push([1, 0]);
    P.push([d, w]); N.push([1, 0]); P.push([d, 0]); N.push([0.7, -0.7]); P.push([d - w, 0]); N.push([0, -1]);
    K = [[1, 3], [4, 6]]; st = 3;
  }
  P.push([-fl, 0]); N.push([0, -1]);
  return { P: P, N: N, K: K, st: st };
}
function kulisseEinzeln(P0, L, H, T, pid, o) {
  o = o || {};
  var E = o.ex || 0, S = E ? E * 1.6 : 0, R = o.hand ? 0 : KUL_R, d = KUL_D, fl = KUL_FL, abd = o.abd || 'kammer', cls = o.cls;
  var OFF = [0, 0, 0], CH = o.ch || 260;
  function Q(x, y, z) { x += OFF[0]; y += OFF[1]; z += OFF[2]; return o.steh ? [P0[0] + x, P0[1] + z, P0[2] + y] : [P0[0] + x, P0[1] + y, P0[2] + z]; }
  /* ein Teil der Kulisse: nur zeichnen, wenn es in o.nur steht; Versatz und Klasse des Teils gelten fuer alles in f */
  function teil(key, f) {
    if (o.nur) { if (!o.nur[key]) { return; } }
    OFF = (o.ver || {})[key] || [0, 0, 0]; cls = ((o.clsT || {})[key]) || o.cls;
    f();
    OFF = [0, 0, 0]; cls = o.cls;
  }
  function V(v) { return o.steh ? [v[0], v[2], v[1]] : [v[0], v[1], v[2]]; }
  function pl(x, y, z, U, W, n, m, oo) {
    return plane(Q(x, y, z), V(U), V(W), m || 'm', pid, ext({ out: V(n), ch: CH, cls: cls, ew: 0.7 }, oo || {}));
  }
  function fl1(r, pts, c, s, oo) { auf(r, pts, pid, ext({ fill: 1, c: c, s: s, w: 0.5, b: 0.4, cls: cls }, oo || {})); }
  function rechteck(u0, v0, u1, v1) { return [[u0, v0], [u1, v0], [u1, v1], [u0, v1]]; }
  /* Glasseide: helles Gewebe mit feinen Linien */
  function seide(r, u0, u1) {
    fl1(r, rechteck(u0, 0, u1, 1), '#F6F3EA', '#BDB49E');
    for (var q = 1; q !== 7; q++) { auf(r, [[u0 + 0.004, q / 7], [u1 - 0.004, q / 7]], pid, { s: '#DDD5C2', w: 0.5, b: 0.43, cls: cls }); }
  }
  /* Kammerblech: Blech mit Kammern (Resonatorblech), je Kammer ein Rechteck */
  function kammer(r, u0, u1, nk) {
    fl1(r, rechteck(u0, 0, u1, 1), '#D3DAE2', '#8C9AAB');
    var nx = nk || Math.max(1, Math.round((u1 - u0) * 6)), ny = 3;
    for (var i = 0; i !== nx; i++) {
      for (var j = 0; j !== ny; j++) {
        var a = u0 + (u1 - u0) * (i + 0.16) / nx, b = u0 + (u1 - u0) * (i + 0.84) / nx;
        fl1(r, rechteck(a, (j + 0.18) / ny, b, (j + 0.82) / ny), '#E6EBF1', '#9AA7B6', { b: 0.45, w: 0.45 });
      }
    }
  }
  /* Abdeckung einer Seite (oben sg 1, unten -1): Kammerblech wechselseitig je eine Haelfte, sonst Glasseide */
  function decke(r, sg) {
    if (abd === 'loch') { fl1(r, rechteck(0, 0, 1, 1), 'url(#wsz-loch)', '#8C9AAB'); return; }
    if (abd === 'ohne') { seide(r, 0, 1); return; }
    if (sg === 1) { kammer(r, 0.5, 1); seide(r, 0, 0.5); } else { kammer(r, 0, 0.5); seide(r, 0.5, 1); }
  }
  /* Lagen: Abdeckung und Glasseide oben und unten; zusammengebaut liegen sie auf dem Kern */
  var lagen = [
    { k: 'seide', z: E ? T + E : T - 1, x: S, sg: 1 },
    { k: 'abdeck', z: E ? T + 2 * E : T, x: 2 * S, sg: 1 },
    { k: 'seide', z: E ? -E : 1, x: -S, sg: -1 },
    { k: 'abdeck', z: E ? -2 * E : 0, x: -2 * S, sg: -1 }
  ];
  /* Runde 18 (Dimi 11.11.2026): zusammengebaut mit Kammerblech gehoert nur die Haelfte mit dem Kammerblech zur Abdeckung; die Haelfte
     daneben ist Glasseide (Bereich Glasseide). So leuchten in der Zeile „Kulissenrahmen und Kammerblech“ nur Rahmen und Kammerbleche. */
  /* Lagen innerhalb der Rundung des Rahmens: sonst staende ihre Kante ueber die Rundung hinaus */
  var yi = R ? R + 1 : 2;
  var halb = (!E) ? abd === 'kammer' : false;
  each(lagen, function (g) {
    if (g.k === 'abdeck') { if (abd === 'ohne') { return; } }
    if (g.k === 'seide') { if (!E) { if (abd !== 'ohne') { return; } } }
    if (halb) {
      var xk = g.sg === 1 ? L / 2 : 0, xs = g.sg === 1 ? 0 : L / 2;
      /* die Glasseide liegt auch unter dem Kammerblech (1 mm tiefer): sie erscheint, wenn die Abdeckung ausgeblendet ist.
         Die Unterseite wird wie bisher mit der Abdeckung ausgeblendet, sonst laege sie im Bild ueber der Wolle. */
      var fxS = g.sg === 1 ? ((o.FX || {}).seide || []) : ((o.FX || {}).abdeck || []);
      teil(g.sg === 1 ? 'seideO' : 'seideU', function () { mitA(o, 'seide', function () { verdeckt(fxS, function () {
        var r = pl(xs, yi, g.z, [L / 2, 0, 0], [0, H - 2 * yi, 0], [0, 0, g.sg], 'm', { two: 1 });
        seide(r, 0, 1);
        if (D3) { pl(xs, yi, g.z, [L / 2, 0, 0], [0, H - 2 * yi, 0], [0, 0, -g.sg], 'm', { two: 1 }); }
        if (g.sg === 1) { var r2 = pl(xk, yi, g.z - 1, [L / 2, 0, 0], [0, H - 2 * yi, 0], [0, 0, 1], 'm', { two: 1, noedge: 1 }); seide(r2, 0, 1); }
      }); }); });
      teil(g.sg === 1 ? 'abdO' : 'abdU', function () { mitAF(o, 'abdeck', function () {
        var r = pl(xk, yi, g.z, [L / 2, 0, 0], [0, H - 2 * yi, 0], [0, 0, g.sg], 'm', { two: 1 });
        kammer(r, 0, 1, 3);
        if (D3) { pl(xk, yi, g.z, [L / 2, 0, 0], [0, H - 2 * yi, 0], [0, 0, -g.sg], 'm', { two: 1 }); }
      }); });
      return;
    }
    teil((g.k === 'seide' ? 'seide' : 'abd') + (g.sg === 1 ? 'O' : 'U'), function () { mitAF(o, g.k, function () {
      var r = pl(g.x, yi, g.z, [L, 0, 0], [0, H - 2 * yi, 0], [0, 0, g.sg], 'm', { two: 1 });
      if (g.k === 'seide') { seide(r, 0, 1); } else { decke(r, g.sg); }
      if (D3) { pl(g.x, yi, g.z, [L, 0, 0], [0, H - 2 * yi, 0], [0, 0, -g.sg], 'm', { two: 1 }); }
    }); });
  });
  /* Mineralwolle in zwei Haelften links und rechts des T-Buegelprofils */
  var eW = E ? E * 0.35 : 0, y0w = R ? 16 : fl * 0.4, y1w = H - y0w;
  /* zusammengebaut liegen Wolle und T-Buegelprofil innen: vor allen Aussenflaechen zeichnen (Maleralgorithmus) */
  function innen(f) { return (E || o.offen) ? f() : innenTeil(f); }
  teil('wolle', function () { innen(function () { mitAF(o, 'wolle', function () {
    each([[fl * 0.3 - eW, L / 2 - 5 - eW], [L / 2 + 5 + eW, L - fl * 0.3 + eW]], function (h) {
      var a = Q(h[0], y0w, 2), b = Q(h[1], y1w, T - 2);
      var kb = box(Math.min(a[0], b[0]), Math.min(a[1], b[1]), Math.min(a[2], b[2]), Math.max(a[0], b[0]), Math.max(a[1], b[1]), Math.max(a[2], b[2]), 'k', pid, { ch: CH, cls: cls, ew: 0.6, b: o.offen ? -60 : 0 });
      each([kb.t, kb.y, kb.x], function (f) { if (f) { fl1(f, rechteck(0, 0, 1, 1), 'url(#wsz-wolle)', '#B89A3A', { b: 0.42, w: 0.5 }); } });
    });
  }); }); });
  /* T-Buegelprofil (Mittelsteg): drei gleich lange Schenkel, zwei bilden oben den Flansch, der dritte steht als kurzer Steg zwischen
     den Wollhaelften; kein Trennblech durch die ganze Dicke (Runde 12 der Szene, Dimi 10.11.2026, Prüfliste Punkt 6).
     In der Explosion ueber alle Lagen gehoben */
  var zT = E ? T + 2 * E + 150 : 0, xm = L / 2, sT = 26;
  /* Runde 13 der Szene (Dimi 10.11.2026): bei wechselseitigem Kammerblech liegt der Flansch des T-Buegelprofils zusammengebaut sichtbar
     in der Mitte auf der Abdeckung (zwischen Kammerblech und Glasseide); der Steg bleibt innen */
  var tOben = (!E) ? abd === 'kammer' : false;
  teil('tbuegel', function () { innen(function () { mitAF(o, 'tbuegel', function () {
    pl(xm, fl, zT + T - sT, [0, H - 2 * fl, 0], [0, 0, sT], [1, 0, 0], 'm', { two: 1 });
    if (D3) { pl(xm, fl, zT + T - sT, [0, H - 2 * fl, 0], [0, 0, sT], [-1, 0, 0], 'm', { two: 1 }); }
    if (tOben) { return; }
    pl(xm - sT, fl, zT + T, [2 * sT, 0, 0], [0, H - 2 * fl, 0], [0, 0, 1], 'm', { two: 1 });
    if (D3) { pl(xm - sT, fl, zT + T, [2 * sT, 0, 0], [0, H - 2 * fl, 0], [0, 0, -1], 'm', { two: 1 }); }
  }); }); });
  if (tOben) {
    teil('tbuegel', function () { mitAF(o, 'tbuegel', function () {
      pl(xm - sT, fl, T + 1.5, [2 * sT, 0, 0], [0, H - 2 * fl, 0], [0, 0, 1], 'm', { two: 1, b: 400 });
      if (D3) { pl(xm - sT, fl, T + 1.5, [2 * sT, 0, 0], [0, H - 2 * fl, 0], [0, 0, -1], 'm', { two: 1 }); }
    }); });
  }
  /* Rundung bzw. Kante des Rahmenprofils als eigener Bereich („rund“, Runde 18): Baender auf den Reihen K des Querschnitts, 0,6 mm
     ueber der Flaeche und in Blechfarbe (in Ruhe nicht zu sehen). Sie gehoeren weiter zum Rahmen: o.FX.rund blendet sie aus,
     wenn der Rahmen selbst hervorgehoben ist, dann leuchtet die Flaeche darunter. */
  var mitRund = o.A ? o.A.rund !== undefined : false;
  function rundBand(G, NG, Kg) {
    if (!mitRund) { return; }
    mitAF(o, 'rund', function () {
      each(Kg, function (kg) {
        var GG = [], NN = [];
        for (var i = kg[0]; i !== kg[1] + 1; i++) {
          GG.push(G[i].map(function (p, j) { return ad(p, mu(nz(NG[i][j]), 0.6)); }));
          NN.push(NG[i]);
        }
        var i0 = IT.length;
        patch(GG, 'm', pid, { NG: NN, noedge: 1, cls: cls, two: 1, b: 0.35 });
        /* in der Zeichnung ein kraeftiges Gelb, unabhaengig von der Lage der Flaeche (wie die Biegekanten am Rechteckkanal) */
        if (!D3) { for (var ii = i0; ii !== IT.length; ii++) { if (IT[ii].t === 'f') { IT[ii].n = [1, 0, 0]; } } }
      });
    });
  }
  /* Rahmenprofile an den Laengsseiten (y = 0 und y = H): Steg mit Laengssicken, Flansche oben und unten; aus der Maschine mit Radius */
  var eY = E ? E * 0.9 : 0, nL = o.nL || Math.max(1, Math.ceil(L / 260));
  each([[H + eY, 1], [-eY, -1]], function (c) { teil(c[1] === 1 ? 'rahmenV' : 'rahmenH', function () {
    var y = c[0], sg = c[1], pr = kulProfil(T, R, 0, fl), G = [], NG = [], r = null;
    each(pr.P, function (p, i) {
      var row = [], nr = [], nn = V([0, sg * pr.N[i][0], pr.N[i][1]]);
      for (var j = 0; j !== nL + 1; j++) { row.push(Q(L * j / nL, y + sg * p[0], p[1])); nr.push(nn); }
      G.push(row); NG.push(nr);
    });
    mitAF(o, 'krahmen', function () {
      r = patch(G, 'm', pid, { NG: NG, e0: 1, e1: 1, f0: 1, f1: 1, cls: cls, ew: 0.7, two: 1 });
      /* Laengssicken auf dem Steg */
      var z0s = pr.P[pr.st + 1][1], z1s = pr.P[pr.st][1];
      for (var j = 0; j !== nL; j++) {
        var q = r.Q[pr.st][j]; if (!q.it) { continue; } if (q.inn) { continue; }
        var xa = L * (j ? j / nL : 0.01), xb = L * (j === nL - 1 ? 0.99 : (j + 1) / nL), dd = D3 ? undefined : q.it.d + 0.4;
        each([0.36, 0.64], function (v) {
          var za = z0s + (z1s - z0s) * v, zb = z0s + (z1s - z0s) * (v + 0.05);
          line([Q(xa, y + sg * 0.5, za), Q(xb, y + sg * 0.5, za)], pid, { s: '#FFFFFF', w: 1.1, d: dd, cls: cls, lc: 'butt' });
          line([Q(xa, y + sg * 0.5, zb), Q(xb, y + sg * 0.5, zb)], pid, { s: '#5E7189', w: 0.7, op: 0.75, d: dd, cls: cls, lc: 'butt' });
        });
      }
    });
    rundBand(G, NG, pr.K);
  }); });
  /* An- und Abstroemprofil: dasselbe Profil um das Ende der Kulisse, Flansche greifen oben und unten in den Rahmen */
  var eX = E ? E * 0.8 : 0;
  each([[L + eX, 1], [-eX, -1]], function (en) { teil(en[1] === 1 ? 'endeR' : 'endeL', function () {
    var xb = en[0], sx = en[1], pr = kulProfil(T, R, d, fl), P = pr.P, G = [], NG = [];
    each(P, function (p, i) {
      var x = xb + sx * p[0];
      G.push([Q(x, 0, p[1]), Q(x, H, p[1])]);
      var nn = V([sx * pr.N[i][0], 0, pr.N[i][1]]); NG.push([nn, nn]);
    });
    mitAF(o, 'profil', function () {
      patch(G, 'm', pid, { NG: NG, e0: 1, e1: 1, f0: 1, f1: 1, cls: cls, ew: 0.7, two: 1 });
      line(P.map(function (p) { return Q(xb + sx * p[0], H, p[1]); }), pid, { w: 0.8, cls: cls });
      if (D3) { line(P.map(function (p) { return Q(xb + sx * p[0], 0, p[1]); }), pid, { w: 0.8, cls: cls }); }
    });
    rundBand(G, NG, pr.K);
  }); });
  return { L: L, H: H, T: T, d: d };
}

/* ---------- WAMMES-Logo (Dimi 11.11.2026, 07:54: Logo auf dem Zentralgeraet, Corporate Identity) ----------
   Pfad wie im Kopf der Website (wm-layout, viewBox 0 0 253 80, evenodd); Bildmarke rechts, Wortmarke links. */
var WM_LOGO = 'M215.8,72.5 L214.3,72.5 L208.1,71.8 L206.2,71.1 L204.4,70.7 L203.4,70.1 L201.9,69.7 L201.0,69.1 L199.9,68.7 L195.4,65.8 L194.0,64.6 L191.3,62.0 L189.1,59.4 L188.3,58.3 L188.5,57.6 L189.7,55.6 L190.1,54.6 L190.8,53.8 L191.2,52.7 L192.7,50.4 L194.1,47.6 L196.7,43.3 L197.0,42.4 L197.8,41.5 L198.2,40.6 L199.7,38.1 L200.1,37.1 L201.7,34.6 L202.1,33.6 L202.7,32.8 L203.2,31.7 L204.7,29.4 L206.1,26.6 L206.7,25.9 L206.8,25.5 L206.8,25.1 L206.5,24.8 L206.1,24.7 L186.7,24.8 L186.1,24.6 L185.8,24.2 L186.1,23.2 L187.0,21.5 L187.7,20.7 L188.2,19.7 L189.1,18.4 L192.0,15.1 L195.2,12.2 L196.8,11.0 L199.9,9.1 L201.0,8.7 L202.0,8.1 L203.4,7.7 L204.5,7.1 L205.8,6.8 L208.4,6.0 L210.6,5.8 L215.0,5.3 L221.8,6.0 L223.8,6.8 L225.4,7.1 L226.6,7.7 L228.0,8.2 L229.0,8.7 L230.1,9.2 L234.5,12.1 L237.9,15.1 L240.8,18.4 L242.1,20.6 L242.8,21.4 L244.7,24.9 L245.1,26.5 L245.7,27.6 L246.1,29.4 L246.8,31.1 L247.0,33.3 L247.4,35.5 L247.6,38.8 L247.4,42.3 L247.0,44.5 L246.8,46.6 L246.1,48.5 L245.7,50.4 L245.1,51.4 L244.7,52.8 L244.1,53.8 L243.8,54.8 L243.2,55.6 L242.7,56.6 L242.1,57.4 L240.7,59.6 L237.9,62.7 L234.5,65.8 L230.1,68.7 L229.0,69.1 L228.1,69.6 L226.6,70.1 L225.4,70.7 L223.7,71.1 L221.8,71.8 L215.8,72.5Z M209.8,57.8 L210.7,56.6 L211.1,55.6 L211.7,54.7 L214.7,49.4 L215.1,48.5 L215.8,47.6 L217.1,45.0 L217.7,44.2 L218.2,43.1 L219.7,40.8 L220.1,39.7 L220.7,38.9 L222.1,36.3 L222.7,35.5 L223.1,34.5 L223.7,33.7 L224.1,32.7 L226.7,28.4 L227.0,27.5 L227.8,26.5 L228.2,25.5 L228.1,25.1 L227.9,24.9 L227.1,24.7 L214.1,24.7 L213.2,24.9 L212.2,26.2 L211.7,27.2 L211.1,28.1 L210.7,29.1 L209.2,31.4 L208.8,32.4 L208.1,33.4 L207.7,34.3 L206.2,36.7 L204.7,39.5 L204.1,40.4 L203.7,41.3 L203.1,42.1 L202.6,43.2 L202.1,43.9 L201.9,44.7 L202.1,45.5 L202.7,46.3 L203.1,47.4 L204.6,49.7 L205.1,50.7 L205.7,51.6 L206.1,52.6 L207.6,55.0 L209.0,57.6 L209.4,57.8 L209.8,57.8Z M43.4,43.4 L42.4,43.3 L39.4,42.8 L38.8,42.6 L37.2,41.6 L36.2,40.3 L36.0,39.7 L35.9,37.7 L36.1,36.5 L37.4,35.1 L38.9,34.2 L39.5,34.0 L43.4,33.0 L49.1,32.8 L49.7,32.7 L50.0,32.4 L50.2,32.0 L50.3,31.2 L50.2,30.5 L49.7,29.6 L49.0,29.0 L48.2,28.8 L46.0,28.4 L40.9,28.9 L39.1,29.5 L38.6,29.5 L38.3,29.4 L38.1,29.1 L37.6,27.6 L37.7,27.0 L38.1,26.5 L38.8,26.1 L43.8,25.0 L48.3,25.1 L51.4,26.1 L52.9,27.1 L53.6,28.0 L53.9,28.6 L54.3,30.3 L54.5,42.0 L54.4,42.5 L54.1,42.8 L53.5,43.0 L51.5,42.9 L51.0,42.5 L50.8,41.2 L50.4,40.9 L50.0,41.1 L49.3,41.8 L47.4,42.7 L43.4,43.4Z M88.7,43.0 L86.1,43.0 L85.6,42.8 L85.2,42.5 L85.1,42.0 L85.2,32.8 L85.0,30.6 L84.7,30.0 L83.6,29.0 L83.0,28.8 L81.5,28.7 L79.4,28.8 L78.5,29.0 L76.9,30.2 L76.2,31.0 L75.9,31.7 L75.8,32.8 L75.8,42.5 L75.5,42.8 L75.0,43.0 L72.7,43.0 L72.0,42.9 L71.8,42.6 L71.6,42.1 L71.7,32.7 L71.5,31.0 L70.9,29.9 L70.1,29.1 L69.3,28.8 L67.6,28.6 L65.5,28.9 L64.7,29.2 L63.2,30.3 L62.2,32.0 L62.1,32.9 L62.2,42.0 L62.0,42.6 L61.7,42.9 L61.2,43.0 L58.9,43.0 L58.4,42.9 L58.0,42.6 L57.9,42.0 L57.9,26.8 L58.2,25.8 L58.4,25.6 L58.8,25.4 L60.1,25.4 L60.6,25.6 L61.2,26.2 L61.4,27.7 L61.7,27.9 L62.1,28.0 L62.6,27.8 L63.2,27.1 L64.5,26.1 L66.7,25.2 L67.7,25.0 L70.2,25.1 L71.0,25.3 L72.9,26.2 L73.8,26.9 L74.8,28.0 L75.4,28.2 L75.8,28.0 L76.4,27.1 L78.0,26.1 L81.0,25.1 L84.4,25.1 L87.0,26.1 L88.6,27.6 L89.3,29.5 L89.4,30.4 L89.5,42.2 L89.3,42.7 L88.7,43.0Z M96.1,43.1 L93.6,43.0 L93.1,42.8 L92.9,42.3 L92.9,26.8 L93.0,26.0 L93.4,25.5 L93.8,25.4 L95.1,25.4 L95.7,25.6 L96.2,26.3 L96.5,27.6 L97.0,27.9 L97.5,27.7 L98.1,27.1 L99.5,26.1 L100.7,25.7 L101.8,25.2 L102.8,25.0 L105.0,25.1 L105.7,25.3 L107.7,26.1 L108.7,26.9 L109.6,27.9 L110.3,28.2 L110.7,28.0 L111.4,27.1 L112.8,26.2 L115.4,25.2 L116.5,25.0 L119.2,25.0 L119.9,25.2 L122.1,26.2 L123.3,27.2 L123.6,27.7 L124.0,28.6 L124.5,31.2 L124.4,36.4 L124.5,42.1 L124.4,42.6 L124.1,42.8 L123.3,43.0 L121.3,43.0 L120.6,42.9 L120.2,42.6 L120.1,42.0 L120.2,32.6 L119.9,30.5 L119.6,30.0 L118.5,28.9 L116.0,28.7 L114.4,28.8 L113.4,29.1 L111.9,30.2 L111.0,31.3 L110.8,32.6 L110.9,42.1 L110.7,42.7 L110.5,42.9 L110.0,43.0 L107.7,43.0 L107.1,42.8 L106.7,42.5 L106.6,42.0 L106.7,32.0 L106.6,31.3 L105.9,30.1 L105.1,29.1 L104.3,28.8 L102.4,28.6 L100.6,28.8 L99.6,29.2 L98.2,30.3 L97.2,32.1 L97.0,33.0 L97.1,42.2 L97.0,42.6 L96.8,42.8 L96.1,43.1Z M138.5,43.3 L135.9,43.2 L132.4,42.6 L130.2,41.6 L128.4,39.9 L127.9,39.3 L127.3,37.7 L127.2,37.0 L127.1,31.9 L127.3,30.8 L128.1,29.0 L129.2,27.8 L129.8,27.2 L130.8,26.7 L131.7,26.1 L133.4,25.7 L134.7,25.2 L135.5,25.1 L137.5,25.0 L139.2,25.2 L140.5,25.7 L142.1,26.1 L143.8,27.1 L145.4,28.8 L145.9,29.5 L146.3,31.3 L146.4,34.1 L146.3,34.7 L145.8,35.1 L145.0,35.2 L132.8,35.1 L132.1,35.3 L131.6,35.8 L131.5,36.3 L131.5,36.8 L132.2,38.4 L132.6,38.7 L134.6,39.7 L136.2,40.0 L139.8,39.9 L142.2,39.6 L143.5,39.0 L144.3,38.9 L144.9,39.3 L145.8,41.0 L145.8,41.5 L145.6,41.8 L144.3,42.2 L143.3,42.6 L138.5,43.3Z M158.4,43.6 L156.6,43.5 L152.1,42.7 L150.8,42.1 L149.6,41.8 L149.3,41.6 L149.2,41.3 L149.3,40.8 L150.0,39.3 L150.6,38.8 L151.6,38.9 L152.9,39.6 L154.3,39.9 L157.8,40.2 L160.2,40.0 L160.8,39.9 L161.5,39.4 L162.1,38.6 L162.2,38.1 L162.1,37.6 L161.9,37.2 L161.5,36.8 L159.4,36.0 L155.7,35.8 L151.9,34.7 L150.3,33.6 L149.2,32.1 L149.0,31.0 L149.1,29.6 L149.4,28.8 L150.3,27.4 L152.3,26.1 L155.6,25.1 L157.8,25.0 L160.0,25.3 L161.4,25.7 L164.1,26.2 L164.6,26.6 L164.8,27.2 L164.6,28.0 L163.8,29.2 L163.5,29.4 L163.1,29.4 L161.9,28.9 L158.4,28.4 L157.5,28.3 L154.4,28.9 L153.4,29.7 L153.0,30.2 L153.0,30.7 L153.2,31.2 L153.6,31.6 L154.3,32.0 L156.7,32.7 L158.3,32.9 L160.4,32.9 L161.5,33.2 L164.3,34.2 L165.5,35.3 L165.8,35.9 L166.1,37.6 L166.0,39.3 L165.6,40.3 L164.6,41.6 L162.4,42.8 L158.4,43.6Z M28.0,43.1 L25.7,43.0 L25.1,42.7 L24.1,40.3 L23.7,38.9 L23.2,37.8 L22.7,36.0 L22.1,34.7 L21.7,33.1 L20.9,31.2 L20.5,30.8 L20.2,30.9 L19.9,31.3 L19.6,32.7 L19.0,34.0 L18.7,35.4 L18.0,36.8 L17.7,38.4 L17.1,39.5 L16.7,41.3 L16.0,42.6 L15.6,42.9 L15.1,43.1 L12.7,43.0 L12.1,42.8 L11.2,41.3 L10.8,39.5 L10.0,37.8 L9.8,36.2 L9.2,35.0 L8.7,32.9 L8.2,31.8 L7.7,29.8 L7.1,28.4 L6.6,26.4 L6.7,25.8 L7.4,25.5 L9.4,25.5 L10.1,25.7 L10.5,26.1 L10.7,26.7 L11.1,28.6 L11.7,30.1 L12.1,32.2 L12.8,34.0 L13.1,35.9 L13.7,37.5 L14.0,37.7 L14.3,37.8 L14.6,37.7 L14.8,37.4 L15.1,35.8 L15.7,34.5 L16.0,33.0 L16.7,31.6 L17.2,29.8 L17.8,28.7 L18.2,27.0 L18.7,26.1 L19.3,25.5 L19.8,25.4 L21.4,25.4 L22.0,25.7 L22.5,26.4 L23.1,28.3 L23.7,29.5 L24.1,31.1 L24.7,32.3 L25.1,33.7 L25.6,34.8 L26.2,36.6 L26.7,37.4 L27.3,37.7 L27.6,37.5 L27.7,37.1 L28.0,35.0 L28.7,33.2 L29.2,30.6 L29.7,29.4 L30.1,27.4 L30.5,26.3 L30.9,25.8 L31.5,25.4 L33.7,25.4 L34.2,25.6 L34.4,25.9 L34.4,26.4 L34.0,27.5 L33.7,28.9 L33.1,30.3 L32.7,32.2 L32.0,33.5 L31.7,35.4 L31.1,36.7 L30.7,38.4 L30.1,39.9 L29.7,41.8 L29.5,42.3 L29.1,42.7 L28.6,43.0 L28.0,43.1Z M141.5,32.7 L142.1,32.4 L142.4,31.8 L142.2,31.0 L141.8,30.1 L140.2,29.0 L137.4,28.4 L136.7,28.4 L134.7,28.8 L133.8,29.1 L132.2,30.2 L131.9,30.7 L131.6,31.6 L131.6,32.0 L131.8,32.3 L132.1,32.5 L132.6,32.7 L141.5,32.7Z M46.9,40.0 L48.1,39.6 L49.6,38.7 L49.9,38.4 L50.2,37.3 L50.3,36.3 L50.1,35.5 L49.8,35.1 L49.0,34.9 L45.8,35.2 L43.6,35.8 L42.1,36.0 L41.6,36.2 L40.4,37.0 L40.0,37.5 L39.9,38.2 L40.1,38.8 L41.0,39.6 L41.5,39.9 L42.8,40.0 L46.9,40.0Z M128.9,66.5 L128.3,66.3 L127.9,65.6 L127.9,61.2 L127.8,60.3 L127.3,59.4 L126.8,59.1 L126.3,59.0 L125.6,59.0 L125.2,59.2 L124.1,60.7 L124.1,65.2 L123.9,66.1 L123.6,66.4 L123.3,66.4 L122.9,66.3 L122.7,65.9 L122.4,65.0 L122.5,59.0 L122.4,55.1 L122.5,54.5 L123.0,54.1 L123.7,54.1 L124.0,54.6 L124.0,58.0 L124.3,58.5 L124.7,58.5 L125.3,58.0 L125.9,57.8 L126.8,57.7 L127.6,57.8 L128.2,58.0 L128.6,58.3 L129.3,59.7 L129.7,60.9 L129.7,65.3 L129.5,66.1 L128.9,66.5Z M132.6,56.0 L132.0,55.9 L131.6,55.5 L131.7,54.9 L132.3,54.5 L132.8,54.6 L133.1,55.2 L133.0,55.7 L132.6,56.0Z M104.2,66.5 L103.8,66.4 L103.5,66.3 L103.1,65.6 L103.1,60.9 L103.0,60.1 L102.4,59.3 L101.6,59.0 L101.1,59.1 L100.7,59.3 L100.1,60.0 L99.8,60.6 L99.7,61.6 L99.8,65.3 L99.7,65.8 L99.4,66.2 L99.1,66.4 L98.7,66.3 L98.4,66.1 L98.1,65.7 L98.0,64.9 L98.1,60.8 L97.9,59.9 L97.3,59.2 L96.4,59.0 L95.7,59.3 L95.1,60.0 L94.8,60.5 L94.7,61.9 L94.7,65.2 L94.6,65.9 L94.3,66.3 L94.0,66.5 L93.7,66.5 L93.3,66.4 L93.0,65.9 L92.9,65.0 L92.9,58.9 L93.1,58.2 L93.4,58.0 L93.7,57.9 L94.5,58.4 L94.9,58.5 L96.4,57.8 L97.4,57.7 L98.3,58.0 L99.2,58.8 L99.7,58.9 L100.1,58.8 L100.8,58.1 L101.6,57.8 L102.7,57.8 L103.6,58.2 L104.6,59.4 L104.9,60.5 L104.8,65.5 L104.6,66.2 L104.2,66.5Z M109.3,66.7 L108.4,66.6 L106.9,65.7 L106.3,64.9 L106.1,63.9 L106.5,63.0 L107.0,62.3 L107.4,62.0 L109.2,61.1 L111.1,61.0 L111.6,60.7 L111.7,60.4 L111.5,59.9 L110.5,59.0 L109.7,58.9 L107.8,59.1 L107.5,59.0 L107.3,58.8 L107.3,58.4 L107.7,58.0 L110.3,57.7 L111.3,57.9 L111.9,58.2 L112.5,58.8 L112.9,59.5 L113.2,60.6 L113.2,65.5 L113.0,66.1 L112.7,66.3 L112.4,66.3 L111.6,65.9 L111.2,65.8 L109.3,66.7Z M120.1,66.7 L118.2,66.6 L116.6,65.9 L115.9,65.4 L115.0,64.0 L114.8,62.1 L115.1,60.3 L116.1,58.9 L117.0,58.2 L117.6,57.9 L118.7,57.7 L120.0,57.7 L120.6,57.9 L120.9,58.3 L120.8,58.7 L120.5,59.0 L118.8,58.9 L117.7,59.5 L116.9,60.5 L116.4,62.0 L116.6,63.2 L117.1,64.2 L117.5,64.6 L118.7,65.2 L119.2,65.2 L120.2,65.1 L120.7,65.4 L120.8,65.8 L120.7,66.2 L120.5,66.5 L120.1,66.7Z M136.3,66.5 L135.9,66.5 L135.5,66.3 L135.3,65.9 L135.1,65.4 L135.1,58.8 L135.2,58.4 L135.5,58.1 L136.0,58.0 L137.5,58.6 L138.4,57.9 L139.2,57.7 L140.2,57.8 L141.1,58.2 L141.8,58.9 L142.1,60.2 L142.3,65.1 L142.0,66.1 L141.7,66.4 L141.3,66.4 L141.0,66.1 L140.7,65.7 L140.7,60.9 L140.6,60.3 L140.2,59.6 L139.7,59.2 L139.3,59.0 L138.7,59.0 L137.9,59.2 L137.0,60.5 L136.9,65.5 L136.7,66.2 L136.3,66.5Z M148.7,66.7 L147.2,66.6 L145.5,65.9 L145.0,65.3 L144.2,64.3 L144.0,63.8 L143.9,61.0 L144.1,60.3 L145.4,58.6 L146.0,58.1 L146.7,57.9 L148.1,57.7 L149.4,58.0 L150.6,59.3 L150.9,60.0 L151.1,61.5 L150.9,62.1 L150.6,62.4 L150.0,62.5 L146.6,62.5 L146.1,62.8 L145.8,63.2 L145.8,63.9 L146.2,64.4 L147.6,65.3 L148.4,65.5 L150.0,65.1 L150.5,65.3 L150.6,65.7 L150.3,66.1 L149.6,66.5 L148.7,66.7Z M153.7,66.4 L153.4,66.4 L153.1,66.2 L152.7,65.4 L152.8,61.4 L152.7,58.5 L153.0,58.1 L153.4,58.0 L153.7,58.1 L154.3,58.6 L154.6,58.6 L155.6,57.9 L156.1,57.8 L156.5,57.8 L156.9,58.3 L156.8,58.8 L156.5,59.2 L155.1,60.0 L154.8,60.5 L154.4,61.5 L154.2,62.7 L154.2,65.5 L154.0,66.1 L153.7,66.4Z M160.1,70.2 L159.5,70.2 L158.9,70.1 L158.5,69.9 L158.3,69.6 L158.3,69.3 L158.5,69.1 L159.7,68.7 L160.3,68.3 L160.8,67.5 L160.9,66.7 L160.8,66.0 L159.1,61.6 L158.6,59.9 L158.1,58.8 L158.0,58.4 L158.3,58.1 L158.8,57.9 L159.4,58.0 L159.7,58.4 L160.8,61.4 L161.1,63.4 L161.4,63.7 L161.6,63.7 L162.1,63.4 L162.5,62.7 L163.2,59.9 L163.8,58.4 L164.2,58.0 L164.8,57.9 L165.1,58.4 L165.1,59.0 L164.1,62.0 L163.8,63.4 L163.0,64.9 L162.6,66.7 L161.7,68.9 L160.8,69.8 L160.1,70.2Z M132.6,66.4 L132.2,66.4 L131.9,66.2 L131.6,65.2 L131.5,58.8 L131.8,58.2 L132.4,58.0 L132.9,58.3 L133.2,59.1 L133.2,65.4 L133.0,66.1 L132.6,66.4Z M148.5,61.7 L149.2,61.4 L149.6,60.7 L149.5,60.2 L148.9,59.4 L148.5,59.0 L147.9,58.8 L147.2,59.0 L146.5,59.4 L146.1,59.9 L145.8,60.5 L145.8,61.0 L146.1,61.4 L146.7,61.7 L148.5,61.7Z M109.6,65.3 L110.8,64.8 L111.4,63.9 L111.6,63.0 L111.5,62.5 L111.2,62.3 L110.5,62.1 L109.7,62.2 L108.5,62.9 L108.0,63.4 L107.9,64.1 L108.2,64.8 L108.8,65.2 L109.6,65.3Z', WM_LOGO_W = 253, WM_LOGO_H = 80;
/* Bildmarke allein (rundes Symbol, Dimi 11.11.2026, 10:32): die ersten beiden Teilpfade des Logos; Rahmen x, y, Breite, Hoehe = Quadrat um den Kreis (Mitte 214,0 / 38,9, Durchmesser 67,2) */
var WM_SYM = 'M215.8,72.5 L214.3,72.5 L208.1,71.8 L206.2,71.1 L204.4,70.7 L203.4,70.1 L201.9,69.7 L201.0,69.1 L199.9,68.7 L195.4,65.8 L194.0,64.6 L191.3,62.0 L189.1,59.4 L188.3,58.3 L188.5,57.6 L189.7,55.6 L190.1,54.6 L190.8,53.8 L191.2,52.7 L192.7,50.4 L194.1,47.6 L196.7,43.3 L197.0,42.4 L197.8,41.5 L198.2,40.6 L199.7,38.1 L200.1,37.1 L201.7,34.6 L202.1,33.6 L202.7,32.8 L203.2,31.7 L204.7,29.4 L206.1,26.6 L206.7,25.9 L206.8,25.5 L206.8,25.1 L206.5,24.8 L206.1,24.7 L186.7,24.8 L186.1,24.6 L185.8,24.2 L186.1,23.2 L187.0,21.5 L187.7,20.7 L188.2,19.7 L189.1,18.4 L192.0,15.1 L195.2,12.2 L196.8,11.0 L199.9,9.1 L201.0,8.7 L202.0,8.1 L203.4,7.7 L204.5,7.1 L205.8,6.8 L208.4,6.0 L210.6,5.8 L215.0,5.3 L221.8,6.0 L223.8,6.8 L225.4,7.1 L226.6,7.7 L228.0,8.2 L229.0,8.7 L230.1,9.2 L234.5,12.1 L237.9,15.1 L240.8,18.4 L242.1,20.6 L242.8,21.4 L244.7,24.9 L245.1,26.5 L245.7,27.6 L246.1,29.4 L246.8,31.1 L247.0,33.3 L247.4,35.5 L247.6,38.8 L247.4,42.3 L247.0,44.5 L246.8,46.6 L246.1,48.5 L245.7,50.4 L245.1,51.4 L244.7,52.8 L244.1,53.8 L243.8,54.8 L243.2,55.6 L242.7,56.6 L242.1,57.4 L240.7,59.6 L237.9,62.7 L234.5,65.8 L230.1,68.7 L229.0,69.1 L228.1,69.6 L226.6,70.1 L225.4,70.7 L223.7,71.1 L221.8,71.8 L215.8,72.5Z M209.8,57.8 L210.7,56.6 L211.1,55.6 L211.7,54.7 L214.7,49.4 L215.1,48.5 L215.8,47.6 L217.1,45.0 L217.7,44.2 L218.2,43.1 L219.7,40.8 L220.1,39.7 L220.7,38.9 L222.1,36.3 L222.7,35.5 L223.1,34.5 L223.7,33.7 L224.1,32.7 L226.7,28.4 L227.0,27.5 L227.8,26.5 L228.2,25.5 L228.1,25.1 L227.9,24.9 L227.1,24.7 L214.1,24.7 L213.2,24.9 L212.2,26.2 L211.7,27.2 L211.1,28.1 L210.7,29.1 L209.2,31.4 L208.8,32.4 L208.1,33.4 L207.7,34.3 L206.2,36.7 L204.7,39.5 L204.1,40.4 L203.7,41.3 L203.1,42.1 L202.6,43.2 L202.1,43.9 L201.9,44.7 L202.1,45.5 L202.7,46.3 L203.1,47.4 L204.6,49.7 L205.1,50.7 L205.7,51.6 L206.1,52.6 L207.6,55.0 L209.0,57.6 L209.4,57.8 L209.8,57.8Z', WM_SYM_X = 180.4, WM_SYM_Y = 5.3, WM_SYM_W = 67.2, WM_SYM_H = 67.2;
function logoForm(sym) { return sym ? { d: WM_SYM, x: WM_SYM_X, y: WM_SYM_Y, w: WM_SYM_W, h: WM_SYM_H } : { d: WM_LOGO, x: 0, y: 0, w: WM_LOGO_W, h: WM_LOGO_H }; }

/* ---------- Aufbau der Szene (Masse in mm) ---------- */
var ZR = 3450; /* Unterkante Decke */
function ringFlansch(p, A, r0, r1, pid) {
  var F = rahmen([sb(p, A), ad(p, A)]), G = [], NG = [];
  for (var i = 0; i !== 37; i++) {
    var a = 2 * Math.PI * i / 36, v = ad(mu(F.N[0], Math.cos(a)), mu(F.B[0], Math.sin(a)));
    G.push([ad(p, mu(v, r0)), ad(p, mu(v, r1))]); NG.push([A, A]);
  }
  patch(G, 'r', pid, { NG: NG, f1: 1, e0: 0, e1: 0, b: 1 });
}
function endkappeR(c, A, Wd, w, Hd, h, pid) {
  endrechteck(c, A, Wd, w, Hd, h, 'm', pid, {});
  var a = mu(Wd, w / 2 - 28), b = mu(Hd, h / 2 - 28), q = ad(c, mu(A, 1));
  var p = [ad(sb(q, a), mu(b, -1)), ad(q, sb(a, b)), ad(ad(q, a), b), ad(sb(q, a), b)];
  line(p.concat([p[0]]), pid, { w: 0.7, s: '#6F829A', b: 2 });
  /* Nieten am Bord */
  /* 3D: Nieten ringsum (in der Isometrie nur die sichtbaren Seiten) */
  var NI = [[1, 0.3], [1, -0.3], [0.3, 1], [-0.3, 1]];
  if (D3) { NI = NI.concat([[-1, 0.3], [-1, -0.3], [0.3, -1], [-0.3, -1]]); }
  each(NI, function (s) {
    var se = Math.abs(s[0]) === 1, n = se ? mu(Wd, s[0]) : mu(Hd, s[1]), t = se ? Hd : Wd, m = se ? w : h;
    var pp = ad(ad(sb(c, mu(A, 25)), mu(n, m / 2 + 1)), mu(t, (se ? s[1] * h : s[0] * w)));
    if (!sicht(n)) { return; }
    var u = nz(cr(n, A)), ci = [];
    for (var k = 0; k !== 8; k++) { var aa = 2 * Math.PI * k / 8; ci.push(ad(pp, ad(mu(A, 8 * Math.cos(aa)), mu(u, 8 * Math.sin(aa))))); }
    face(ci, 'd', pid, { n: n, c: '#4B5666', b: 3 });
  });
}
/* Nippel: steckt in beiden Rohren, sichtbar ist nur die Mittelsicke zwischen den Rohrenden */
function nippelR(p, A, r, pid) {
  schlauch(teile(sb(p, mu(A, 8)), ad(p, mu(A, 8)), 20), r + 4, 'm', pid, { b: 3, innen: false });
  ring(sb(p, mu(A, 10)), A, r, pid, { w: 1, b: 5 }); ring(ad(p, mu(A, 10)), A, r, pid, { w: 1, b: 5 });
  treffer(p, A, r + 8, 120, pid);
}
/* Steckverbindung: Rohrende, davor die Anschlagsicke des Formteils; Dichtung liegt innen */
function lippeStoss(p, A, r, pid) {
  ring(sb(p, mu(A, 2)), A, r, pid, { w: 1.1, b: 5 });
  schlauch(teile(ad(p, mu(A, 4)), ad(p, mu(A, 16)), 20), r + 3, 'm', pid, { b: 3, innen: false });
  treffer(p, A, r + 8, 120, pid);
}
function lnrNaht(p0, p1, r, pid) {
  var a = 64 * Math.PI / 180;
  each([0, 10], function (d) {
    var off = [0, r * Math.cos(a + d / r), r * Math.sin(a + d / r)];
    line([ad(p0, off), ad(p1, off)], pid, { s: d ? '#FFFFFF' : '#5E7189', w: d ? 0.9 : 0.9, b: 2 });
  });
}
function auslassPfeile(xc, yc, pidD) {
  luft('SUP', bezier([xc + 300, yc, 2345], [xc + 380, yc, 2330], [xc + 450, yc, 2290], [xc + 500, yc, 2210], 6), pidD, { g: 40, aus: 1 });
  luft('SUP', bezier([xc, yc + 300, 2345], [xc, yc + 380, 2330], [xc, yc + 450, 2290], [xc, yc + 500, 2210], 6), pidD, { g: 40, aus: 1 });
}

/* Luftauslassrohr (Runde 12 der Szene, Dimi 10.11.2026): Wickelfalzrohr, am Ende mit Deckel geschlossen; auf der ganzen Laenge Loecher
   in zwei Reihen, 60 Grad zueinander, je 30 Grad aus der Senkrechten nach unten gedreht; jedes Loch mittig in seiner Wicklung, also
   zwischen zwei Falzen. Achse entlang +Y (rahmen: N = Z, B = X), Steigung st und Phase ph wie wickel(). */
function lochRohr(p0, p1, r, st, ph, pid, pidL) {
  var t = nz(sb(p1, p0)), L = len(sb(p1, p0)), F = rahmen([p0, p1]), N = F.N[0], B = F.B[0], aus = [];
  rohr(p0, p1, r, pid, {}); wickel(p0, p1, r, pid, st, { ph: ph });
  each([150, 210], function (g) {
    var a = g * Math.PI / 180, v = ad(mu(N, Math.cos(a)), mu(B, Math.sin(a))), w = ad(mu(N, -Math.sin(a)), mu(B, Math.cos(a)));
    /* Falz bei diesem Winkel: -(2 pi s / st + ph) = a (mod 2 pi); Loch eine halbe Steigung weiter */
    var s0 = ((-a - ph) / (2 * Math.PI)) * st; s0 = s0 - Math.floor(s0 / st) * st + st / 2;
    for (var q = s0; lt(q, L - 45); q += st) {
      if (lt(q, 45)) { continue; }
      var c = ad(ad(p0, mu(t, q)), mu(v, r + 2));
      /* in der Isometrie nur sichtbare Loecher; in 3D alle */
      if (!D3) { if (!gt(dt(v, VV), 0.02)) { aus.push({ c: c, v: v }); continue; } }
      var ci = [];
      for (var k = 0; k !== 12; k++) { var b2 = 2 * Math.PI * k / 12; ci.push(ad(c, ad(mu(t, 15 * Math.cos(b2)), mu(w, 15 * Math.sin(b2))))); }
      face(ci, 'd', pid, { n: v, c: '#3B4654', s: '#2A323C', w: 0.6, b: 3 });
      aus.push({ c: c, v: v });
    }
  });
  /* Luft tritt schraeg nach unten aus (jedes zweite Loch, sonst wird es unruhig) */
  each(aus, function (x, i) {
    if (i % 2) { return; }
    var e = ad(x.c, mu(x.v, 260)), f = ad(ad(x.c, mu(x.v, 430)), [0, 0, -90]);
    luft('SUP', [x.c, e, f], pidL, { g: 34, aus: 1 });
  });
}

function szene() {
  var X = AX.x, Y = AX.y, Z = AX.z, mX = [-1, 0, 0], mY = [0, -1, 0];
  /* ===== Technikzentrale ===== */
  zone([500, 3250, -150], 'Technikzentrale', 'end');
  zone([12000, 3300, 2350], 'Halle', 'end');
  geraet();
  /* Fortluft: Kompensator, Klappe, Steigkanal, Decke, Dachhaube */
  kompensator(900, 1700, 800, 1200, 1660, 1810, 'kompens');
  klappe(900, 1700, 800, 1200, 1810, 2010, 'absperr', 'x');
  kanalL([1300, 1000, 2010], Z, ZR - 2010 + 200, X, 800, Y, 400, 'm', 'rk', { fr1: false });
  var dk = box(500, 300, ZR, 2100, 1350, ZR + 250, 'w', 'dach', { ch: 400, es: '#8C857B' });
  schraffur(dk.y, 'dach', 0, { d: 70 }); schraffur(dk.x, 'dach', 0, { d: 70 });
  if (D3) { schraffur(dk.ny, 'dach', 0, { d: 70 }); schraffur(dk.nx, 'dach', 0, { d: 70 }); }
  box(500, 300, ZR + 250, 2100, 1350, ZR + 285, 'r', 'dach', { ch: 400 });
  dachhaube(1300, 1000, ZR + 285);
  luft('EHA', [[1300, 1000, 1620], [1300, 1000, ZR + 650]], 'rk', { g: 45 });
  luft('EHA', [[1300, 1000, ZR + 760], [1300, 1600, ZR + 760]], 'dachhaube', { g: 45, aus: 1 });
  luft('EHA', [[1300, 1000, ZR + 760], [2050, 1000, ZR + 760]], 'dachhaube', { g: 45, aus: 1 });
  /* Aussenluft: Kompensator, Klappe, Bogen, gedaemmter Kanal, Wand, Wetterschutzgitter */
  kompensator(900, 1700, 2300, 2700, 1660, 1810, 'kompens');
  klappe(900, 1700, 2300, 2700, 1810, 2010, 'absperr', 'x');
  var bo = bogenR([1300, 2500, 2010], Z, Y, 400, 800, 200, 'm', 'rbogen');
  kanalL([1300, 2900, 2410], Y, 420, X, 800, Z, 400, 'm', 'rk', { fr1: false, sicke: false });
  var dm = box(850, 3300, 2160, 1750, 4800, 2660, 'x', 'daemm', { ch: 300 });
  each([0.2, 0.45, 0.7, 0.95], function (u) {
    auf(dm.t, [[0, u], [1, u]], 'daemm', { s: '#9AA5B1', w: 0.8 }); auf(dm.x, [[u, 0], [u, 1]], 'daemm', { s: '#9AA5B1', w: 0.8 });
    if (dm.nx) { auf(dm.nx, [[u, 0], [u, 1]], 'daemm', { s: '#9AA5B1', w: 0.8 }); }
    if (dm.u) { auf(dm.u, [[0, u], [1, u]], 'daemm', { s: '#9AA5B1', w: 0.8 }); }
  });
  abhaengung(800, 3700, ZR, 1800, 3700, 2155, 'abhaeng');
  wandStueck(700, 4800, 2020, 1900, 5040, 2800, 'wand');
  wetter(900, 1700, 2210, 2610, 5040, 'wetter');
  luft('ODA', [[1300, 5550, 2410], [1300, 4800, 2410]], 'wetter', { g: 45 });
  luft('ODA', [[1300, 4800, 2410], [1300, 2900, 2410]], 'rk', { g: 45 });
  luft('ODA', bogenPunkte(bo.C, Z, Y, 400, 90, 0, 12), 'rbogen', { g: 45 });
  luft('ODA', [[1300, 2500, 2010], [1300, 2500, 1620]], 'absperr', { g: 45 });
  /* Zuluft im Technikraum: Runde 12 der Szene (Dimi 10.11.2026): mit dem vierten Zuluftstrang groesser im Querschnitt (1000 x 500 statt
     800 x 400), drei Kulissen; vor der Brandschutzklappe ein Uebergang auf 800 x 400 (Boden gerade) */
  kompensator(2950, 3450, 1900, 2900, 1660, 1810, 'kompens');
  kanalL([3200, 2400, 1810], Z, 390, X, 500, Y, 1000, 'm', 'rk', {});
  var bs = bogenR([3200, 2400, 2200], Z, X, 500, 1000, 200, 'm', 'rbogen');
  kulisse(3650, 5150, 1900, 2900, 2400, 2900, 3, 200, true, false);
  reduzR([5150, 2400, 2650], X, 750, Y, 1000, 800, Z, 500, 400, 0, -50, 'm', 'retage');
  /* Abluft im Technikraum */
  kompensator(3000, 3400, 800, 1600, 1660, 1810, 'kompens');
  kanalL([3200, 1200, 1810], Z, 890, X, 400, Y, 800, 'm', 'rk', {});
  winkelR([3200, 1200, 2700], Z, X, 400, 800, 200, 200, 'm', 'rwinkel');
  kulisse(3600, 5100, 800, 1600, 2900, 3300, 2, 200, false, true);
  kanalL([5100, 1200, 3100], X, 800, Y, 800, Z, 400, 'm', 'kurzkanal', { falz: 'ph' });
  abhaengung(4400, 1840, ZR, 4400, 2960, 2395, 'abhaeng', 3650 + 1900 + 2400 - 120);
  abhaengung(4350, 740, ZR, 4350, 1660, 2895, 'abhaeng', 3600 + 800 + 2900 - 120);
  /* Wand mit Brandschutzklappen */
  var wa = box(6000, 500, 2150, 6240, 3100, ZR, 'w', 'wand', { ch: 500, es: '#8C857B', ew: 0.9 });
  schraffur(wa.t, 'wand', 0, { d: 70 }); schraffur(wa.y, 'wand', 0, { d: 70 });
  each(wa.x.Q, function (row) { each(row, function (q) { if (q.it) { q.it.op = 0.62; } }); });
  each([[2400, 2600], [1200, 3100]], function (b) {
    face([[6241, b[0] - 470, b[1] - 270], [6241, b[0] + 470, b[1] - 270], [6241, b[0] + 470, b[1] + 270], [6241, b[0] - 470, b[1] + 270]], 'w', 'wand', { n: X, c: '#CFC9C0', s: '#8C857B', w: 0.8, b: 1 });
  });
  /* 3D: Rueckseite der Wand (Technikraum) ebenfalls durchscheinend, mit den Oeffnungen; Stirnseite geschnitten */
  if (D3) {
    each(wa.nx.Q, function (row) { each(row, function (q) { q.it.op = 0.62; }); });
    schraffur(wa.ny, 'wand', 0, { d: 70 }); schraffur(wa.u, 'wand', 0, { d: 70 });
    each([[2400, 2600], [1200, 3100]], function (b) {
      face([[5999, b[0] - 470, b[1] - 270], [5999, b[0] + 470, b[1] - 270], [5999, b[0] + 470, b[1] + 270], [5999, b[0] - 470, b[1] + 270]], 'w', 'wand', { n: mX, c: '#CFC9C0', s: '#8C857B', w: 0.8 });
    });
  }
  bsk(5900, 6400, 2400, 2600, 800, 400, 'bsk', 6000, 6240);
  bsk(5900, 6400, 1200, 3100, 800, 400, 'bsk', 6000, 6240);
  /* Luftwege Technikraum */
  luft('SUP', [[3200, 2400, 1620], [3200, 2400, 2200]], 'rk', { g: 55 });
  luft('SUP', bogenPunkte(bs.C, Z, X, 450, 0, 90, 12), 'rbogen', { g: 55 });
  luft('SUP', [[3650, 2400, 2650], [5150, 2400, 2650]], 'kulisse', { g: 55, zu: 1 });
  each([1933, 2233, 2567, 2867], function (yy) { luft('SUP', [[3650, yy, 2650], [5150, yy, 2650]], 'kulisse', { g: 55, offen: 1 }); });
  luft('SUP', [[5150, 2400, 2650], [5900, 2400, 2600]], 'retage', { g: 55 });
  luft('SUP', [[5900, 2400, 2600], [6400, 2400, 2600]], 'bsk', { g: 55 });

  /* ===== Halle: Zuluft ===== */
  var o1 = kanalL([6400, 2400, 2600], X, 1500, Y, 800, Z, 400, 'm', 'rk', { falz: 'ph' });
  revisionsTuer(o1.pw, 0.1, 0.43, 0.14, 0.86, 'revision');
  var o2 = kanalL([7900, 2400, 2600], X, 1500, Y, 800, Z, 400, 'm', 'rk', { falz: 'ph', sv: 40 });
  kanalL([9400, 2400, 2600], X, 700, Y, 800, Z, 400, 'm', 'kurzkanal', { falz: 'ph', sv: 80 });
  hose([10100, 2400, 2600], X, Y, 800, 400, 200, 'm', 'hose');
  abhaengung(7200, 1940, ZR, 7200, 2860, 2395, 'abhaeng');
  abhaengung(8250, 1940, ZR, 8250, 2860, 2395, 'abhaeng');
  luft('SUP', [[6400, 2400, 2600], [7900, 2400, 2600]], 'rk', { g: 55 });
  luft('SUP', [[7900, 2400, 2600], [9400, 2400, 2600]], 'rk', { g: 55 });
  luft('SUP', [[9400, 2400, 2600], [10100, 2400, 2600]], 'kurzkanal', { g: 55 });
  /* Stutzen mit Rundstrang */
  var pS = [7500, 2800, 2600];
  ringFlansch([7500, 2801, 2600], Y, 125, 168, 'rstutzen');
  rohr(pS, [7500, 2900, 2600], 125, 'rstutzen', { ch: 100 });
  ring([7500, 2850, 2600], Y, 125, 'rstutzen', { w: 0.9 });
  rohr([7500, 2900, 2600], [7500, 3400, 2600], 125, 'wfr', {}); wickel([7500, 2900, 2600], [7500, 3400, 2600], 125, 'wfr', 118);
  vvs([7500, 3400, 2600], Y, 450, 125);
  rohr([7500, 3850, 2600], [7500, 4300, 2600], 125, 'wfr', {}); wickel([7500, 3850, 2600], [7500, 4300, 2600], 125, 'wfr', 118, { ph: 1 });
  nippelR([7500, 4300, 2600], Y, 125, 'nippel');
  rohr([7500, 4300, 2600], [7500, 4600, 2600], 125, 'wfr', {}); wickel([7500, 4300, 2600], [7500, 4600, 2600], 125, 'wfr', 118, { ph: 2 });
  rohrSchelle([7500, 4450, 2600], Y, 125, ZR, 'abhaeng');
  lippeStoss([7500, 4600, 2600], Y, 125, 'lippe');
  var sgb = segBogen([7500, 4600, 2600], Y, X, 250, 125, 'm', 'segbogen');
  rohr([7750, 4850, 2600], [8100, 4850, 2600], 125, 'lnr', {}); lnrNaht([7750, 4850, 2600], [8100, 4850, 2600], 125, 'lnr');
  reduz([8100, 4850, 2600], X, 200, 125, 100, 'm', 'reduz');
  rohr([8300, 4850, 2600], [8450, 4850, 2600], 100, 'wfr', {}); wickel([8300, 4850, 2600], [8450, 4850, 2600], 100, 'wfr', 110);
  /* Gepresster Bogen (Dimi 09.11.2026) vor dem Anschlusskasten, Kasten mit Stutzen auf der Seite zum Bogen */
  var pB = pressBogen([8450, 4850, 2600], X, [0, -1, 0], 200, 100, 'm', 'pbogen', {});
  ring([8452, 4850, 2600], X, 100, 'pbogen', { w: 1.1 }); ring(ad(pB.pe, [0, 2, 0]), [0, -1, 0], 100, 'pbogen', { w: 1.1 });
  var kC = kasten(8400, 8900, 4080, 4580, 2400, 2800, 100, 'py', 'anschlusskasten', 'auslass');
  luft('SUP', [[7500, 2400, 2600], [7500, 2900, 2600]], 'rstutzen', { g: 70 });
  luft('SUP', [[7500, 2900, 2600], [7500, 3400, 2600]], 'wfr', { g: 70 });
  luft('SUP', [[7500, 3400, 2600], [7500, 3850, 2600]], 'vvs', { g: 70 });
  luft('SUP', [[7500, 3850, 2600], [7500, 4300, 2600]], 'wfr', { g: 70 });
  luft('SUP', [[7500, 4300, 2600], [7500, 4600, 2600]], 'wfr', { g: 70 });
  luft('SUP', bogenPunkte(sgb.C, Y, X, 250, 0, 90, 10), 'segbogen', { g: 70 });
  luft('SUP', [[7750, 4850, 2600], [8100, 4850, 2600]], 'lnr', { g: 70 });
  luft('SUP', [[8100, 4850, 2600], [8300, 4850, 2600]], 'reduz', { g: 75 });
  luft('SUP', [[8300, 4850, 2600], [8450, 4850, 2600]], 'wfr', { g: 75 });
  luft('SUP', bogenPunkte(pB.C, X, [0, -1, 0], 200, 0, 90, 10), 'pbogen', { g: 75 });
  luft('SUP', [pB.pe, [8650, 4580, 2600]], 'anschlusskasten', { g: 75 });
  auslassPfeile(8650, 4330, 'auslass');
  /* Vierter Zuluftstrang (Runde 12 der Szene): Stutzen, Luftauslassrohr Ø 250 aus Wickelfalzrohr mit Lochreihen, Enddeckel */
  ringFlansch([9150, 2801, 2600], Y, 125, 168, 'rstutzen');
  rohr([9150, 2800, 2600], [9150, 2900, 2600], 125, 'rstutzen', { ch: 100 });
  ring([9150, 2850, 2600], Y, 125, 'rstutzen', { w: 0.9 });
  lochRohr([9150, 2900, 2600], [9150, 4400, 2600], 125, 118, 0.6, 'wfr', 'auslass');
  enddeckelR([9150, 4400, 2600], Y, 125, 'enddeckel');
  rohrSchelle([9150, 3650, 2600], Y, 125, ZR, 'abhaeng');
  luft('SUP', [[9150, 2400, 2600], [9150, 2900, 2600]], 'rstutzen', { g: 70 });
  luft('SUP', [[9150, 2900, 2600], [9150, 4330, 2600]], 'wfr', { g: 70 });
  /* Abgang A: Kanal, Uebergang, Rundrohr, Rohrschalldaempfer, T-Stueck 90 Grad, Rundrohr mit Sattelstutzen, Enddeckel.
     Beide Abzweige fuehren ueber ein flexibles Rohr zu je einem Anschlusskasten mit Durchlass (genug Abstand fuer das Flexrohr). */
  kanalL([10500, 3000, 2600], Y, 500, X, 400, Z, 400, 'm', 'kurzkanal', {});
  uebergang([10500, 3500, 2600], Y, 400, X, 400, Z, 400, 157.5, 'm', 'ruebergang');
  rohr([10500, 3900, 2600], [10500, 3960, 2600], 157.5, 'ruebergang', { ch: 100 }); ring([10500, 3930, 2600], Y, 157.5, 'ruebergang', { w: 1 });
  rohr([10500, 3950, 2600], [10500, 4150, 2600], 157.5, 'wfr', {}); wickel([10500, 3950, 2600], [10500, 4150, 2600], 157.5, 'wfr', 118);
  rohrSD([10500, 4150, 2600], Y, 520, 157.5, 257.5);
  rohr([10500, 4670, 2600], [10500, 4850, 2600], 157.5, 'wfr', {}); wickel([10500, 4670, 2600], [10500, 4850, 2600], 157.5, 'wfr', 118, { ph: 1 });
  rohr([10500, 4850, 2600], [10500, 5150, 2600], 157.5, 'tstueck90', {});
  ring([10500, 4852, 2600], Y, 157.5, 'tstueck90', { w: 1.1 }); ring([10500, 5148, 2600], Y, 157.5, 'tstueck90', { w: 1.1 });
  var tT = tStueck90([10500, 5000, 2600], Y, 157.5, X, 100, 157.5 + 230, 'm', 'tstueck90');
  rohr([10500, 5150, 2600], [10500, 5950, 2600], 157.5, 'wfr', {}); wickel([10500, 5150, 2600], [10500, 5950, 2600], 157.5, 'wfr', 118, { ph: 2 });
  var tA = sattel([10500, 5800, 2600], Y, 157.5, X, 80, 157.5 + 230, 'm', 'tstueck');
  enddeckelR([10500, 5950, 2600], Y, 157.5, 'enddeckel');
  var kA1 = kasten(11650, 12150, 4750, 5250, 2400, 2800, 100, 'nx', 'anschlusskasten', 'auslass');
  var kA = kasten(11650, 12150, 5550, 6050, 2400, 2800, 80, 'nx', 'anschlusskasten', 'auslass');
  function flexWeg(p0, p1, n) { var m = 210, sg = 110; return bezier(p0, [p0[0] + m, p0[1], p0[2] - sg], [p1[0] - m, p1[1], p1[2] - sg], p1, n); }
  var f1a = tT.pe, f1b = ad(kA1.p, [-70, 0, 0]), f2a = tA.pe, f2b = ad(kA.p, [-70, 0, 0]);
  flexR(flexWeg(f1a, f1b, 16), 102, 'flex');
  flexR(flexWeg(f2a, f2b, 16), 82, 'flex');
  rohrSchelle([10500, 4050, 2600], Y, 157.5, ZR, 'abhaeng');
  rohrSchelle([10500, 5450, 2600], Y, 157.5, ZR, 'abhaeng');
  var CA = [10100, 3000, 2600], CB = [10100, 1800, 2600];
  luft('SUP', bogenPunkte(CA, X, Y, 400, 0, 90, 10), 'hose', { g: 55 });
  luft('SUP', [[10500, 3000, 2600], [10500, 3500, 2600]], 'kurzkanal', { g: 55 });
  luft('SUP', [[10500, 3500, 2600], [10500, 3950, 2600]], 'ruebergang', { g: 65 });
  luft('SUP', [[10500, 3950, 2600], [10500, 4850, 2600]], 'wfr', { g: 70 });
  luft('SUP', [[10500, 4850, 2600], [10500, 5150, 2600]], 'tstueck90', { g: 70 });
  luft('SUP', [[10500, 5000, 2600], tT.pe], 'tstueck90', { g: 70 });
  luft('SUP', flexWeg(f1a, f1b, 12), 'flex', { g: 70 });
  luft('SUP', [[10500, 5150, 2600], [10500, 5800, 2600]], 'wfr', { g: 70 });
  luft('SUP', [[10500, 5800, 2600], tA.pe], 'tstueck', { g: 70 });
  luft('SUP', flexWeg(f2a, f2b, 12), 'flex', { g: 70 });
  auslassPfeile(11900, 5000, 'auslass');
  auslassPfeile(11900, 5800, 'auslass');
  /* Abgang B: Kanal, Bogen, Kanal, Etagenstueck (200 mm seitlicher Versatz), Kanal mit Gittern, Endkappe */
  drossel([10500, 1200, 2600], Y, 600, X, 400, Z, 400);
  var bB = bogenR([10500, 1200, 2600], mY, X, 400, 400, 200, 'm', 'rbogen');
  kanalL([10900, 800, 2600], X, 200, Y, 400, Z, 400, 'm', 'kurzkanal', {});
  etageR([11100, 800, 2600], X, 500, mY, 200, 400, 400, 120, 'm', 'retage');
  var kb = kanalL([11600, 600, 2600], X, 500, Y, 400, Z, 400, 'm', 'kurzkanal', { fr1: false });
  gitterAuf(kb.pw, 0.1, 0.46, 0.18, 0.82, 'auslass'); gitterAuf(kb.pw, 0.56, 0.9, 0.18, 0.82, 'auslass');
  endkappeR([12100, 600, 2600], X, Y, 400, Z, 400, 'rboden');
  abhaengung(11850, 340, ZR, 11850, 860, 2395, 'abhaeng');
  luft('SUP', bogenPunkte(CB, X, mY, 400, 0, 90, 10), 'hose', { g: 55 });
  luft('SUP', [[10500, 1800, 2600], [10500, 1200, 2600]], 'kd', { g: 55 });
  luft('SUP', bogenPunkte(bB.C, mY, X, 400, 0, 90, 10), 'rbogen', { g: 55 });
  luft('SUP', [[10900, 800, 2600], [11100, 800, 2600]], 'kurzkanal', { g: 55 });
  luft('SUP', [[11100, 800, 2600], [11220, 800, 2600], [11480, 600, 2600], [11600, 600, 2600]], 'retage', { g: 55 });
  luft('SUP', [[11600, 600, 2600], [12000, 600, 2600]], 'kurzkanal', { g: 55 });
  luft('SUP', [[11740, 810, 2600], [11740, 1400, 2600]], 'auslass', { g: 50, aus: 1 });
  luft('SUP', [[11965, 810, 2600], [11965, 1400, 2600]], 'auslass', { g: 50, aus: 1 });

  /* ===== Halle: Abluft ===== */
  var e1 = kanalL([6400, 1200, 3100], X, 1500, Y, 800, Z, 400, 'm', 'rk', { falz: 'ph' });
  revisionsTuer(e1.pw, 0.1, 0.43, 0.14, 0.86, 'revision');
  /* Uebergang eckig-eckig: am Strangende genuegen 600 mm Breite, zum Geraet hin 800 mm.
     Bauteil 'retage' (Familie Etagenstueck und Uebergang eckig, Dimi 09.11.2026) */
  reduzR([7900, 1200, 3100], X, 300, Y, 800, 600, Z, 400, 400, 0, 0, 'm', 'retage');
  var e2 = kanalL([8200, 1200, 3100], X, 1200, Y, 600, Z, 400, 'm', 'passlaenge', { falz: 'ph', fr1: false });
  gitterAuf(e2.pw, 0.13, 0.5, 0.2, 0.8, 'auslass'); gitterAuf(e2.pw, 0.6, 0.93, 0.2, 0.8, 'auslass');
  /* Runde 12 der Szene (Dimi 10.11.2026: alle gezeigten Formteile einbauen): Hosenstueck nach DIN 18379 (HS) am Strangende, Abluft aus
     zwei Hoehen; je Abgang ein kurzer Kanal mit Gitter und Endkappe */
  var hs = hosenR([9400, 1200, 3100], X, Y, 600, Z, 400, 200, 200, 80, 500, 'hosenstueck', {});
  each([3100 + hs.zT1 - 100, 3100 + hs.zB1 + 100], function (zz) {
    var kh = kanalL([9900, 1200, zz], X, 350, Y, 600, Z, 200, 'm', 'kurzkanal', { fr1: false });
    gitterAuf(kh.pw, 0.12, 0.88, 0.2, 0.8, 'auslass');
    endkappeR([10250, 1200, zz], X, Y, 600, Z, 200, 'rboden');
    luft('ETA', [[10075, 1960, zz], [10075, 1510, zz]], 'auslass', { g: 40 });
    luft('ETA', [[10180, 1200, zz], [9900, 1200, zz]], 'kurzkanal', { g: 40 });
  });
  luft('ETA', [[9900, 1200, 3240], [9650, 1200, 3240], [9500, 1200, 3100], [9400, 1200, 3100]], 'hosenstueck', { g: 40 });
  luft('ETA', [[9900, 1200, 2960], [9650, 1200, 2960], [9500, 1200, 3100], [9400, 1200, 3100]], 'hosenstueck', { g: 40 });
  abhaengung(7150, 740, ZR, 7150, 1660, 2895, 'abhaeng');
  abhaengung(8720, 840, ZR, 8720, 1560, 2895, 'abhaeng');
  luft('ETA', [[8578, 2050, 3100], [8578, 1510, 3100]], 'auslass', { g: 45 });
  luft('ETA', [[9118, 2050, 3100], [9118, 1510, 3100]], 'auslass', { g: 45 });
  luft('ETA', [[9300, 1200, 3100], [8200, 1200, 3100]], 'passlaenge', { g: 45 });
  luft('ETA', [[8200, 1200, 3100], [7900, 1200, 3100]], 'retage', { g: 45 });
  luft('ETA', [[7900, 1200, 3100], [6400, 1200, 3100]], 'rk', { g: 45 });
  luft('ETA', [[6400, 1200, 3100], [5900, 1200, 3100]], 'bsk', { g: 45 });
  luft('ETA', [[5900, 1200, 3100], [5100, 1200, 3100]], 'kurzkanal', { g: 45 });
  luft('ETA', [[5100, 1200, 3100], [3600, 1200, 3100]], 'kulisse', { g: 45, zu: 1 });
  each([850, 1200, 1550], function (yy) { luft('ETA', [[5100, yy, 3100], [3600, yy, 3100]], 'kulisse', { g: 45, offen: 1 }); });
  luft('ETA', [[3600, 1200, 3100], [3200, 1200, 3100], [3200, 1200, 2700]], 'rwinkel', { g: 45 });
  luft('ETA', [[3200, 1200, 2700], [3200, 1200, 1620]], 'rk', { g: 45 });
}

/* ---------- Darstellung und Bedienung ---------- */
var SVGNS = 'http://www.w3.org/2000/svg';
function sv(tag, at, par) {
  var e = document.createElementNS(SVGNS, tag);
  if (at) { for (var k in at) { if (at[k] !== undefined) { if (at[k] !== null) { e.setAttribute(k, at[k]); } } } }
  if (par) { par.appendChild(e); }
  return e;
}
function ht(tag, cls, txt, par) {
  var e = document.createElement(tag);
  if (cls) { e.className = cls; }
  if (txt !== undefined) { if (txt !== null) { e.textContent = txt; } }
  if (par) { par.appendChild(e); }
  return e;
}
function f1(n) { return Math.round(n * 10) / 10; }
function pfad(pts, zu) {
  var s = '';
  for (var i = 0; i !== pts.length; i++) { s += (i ? 'L' : 'M') + f1(pts[i][0]) + ' ' + f1(pts[i][1]); }
  return s + (zu ? 'Z' : '');
}
var LUFT = {
  ODA: { c: '#2E9E4A', de: 'Außenluft', en: 'Outdoor air' },
  SUP: { c: '#1E6FD9', de: 'Zuluft', en: 'Supply air' },
  ETA: { c: '#E8B400', de: 'Abluft', en: 'Extract air' },
  EHA: { c: '#8A5A2B', de: 'Fortluft', en: 'Exhaust air' }
};
var BT = {}, BAU = ['wand', 'dach'], KATV = {}, KATID = {};
each(DATA.bauteile, function (b) { BT[b.id] = b; });
each(DATA.kat || [], function (k) { KATID[k.id] = k; each(k.teile, function (p) { KATV[p] = k; }); });
/* kurzer Name fuer Filter und Listen: ohne Klammerzusatz */
function kurzName(b) { return b.t.replace(/ *\([^)]*\)/g, '').replace(/, gerade$/, ''); }

var GEB = null; /* einmal berechnete Szene */
function bauen() {
  if (GEB) { return GEB; }
  IT = []; SEQ = 0; FLOWS = []; MARKEN = []; ZONEN = [];
  szene();
  var it = IT.slice().sort(function (a, b) { return (a.d - b.d) || (a.q - b.q); });
  var x0 = 1e9, y0 = 1e9, x1 = -1e9, y1 = -1e9, PB = {};
  function bb(pid, p) {
    x0 = Math.min(x0, p[0]); y0 = Math.min(y0, p[1]); x1 = Math.max(x1, p[0]); y1 = Math.max(y1, p[1]);
    if (pid) {
      var b = PB[pid]; if (!b) { b = PB[pid] = [1e9, 1e9, -1e9, -1e9]; }
      b[0] = Math.min(b[0], p[0]); b[1] = Math.min(b[1], p[1]); b[2] = Math.max(b[2], p[0]); b[3] = Math.max(b[3], p[1]);
    }
  }
  each(it, function (o) { each(o.p, function (p) { bb(o.pid, p); }); });
  gruppen(it);
  var GB = {};
  each(it, function (o) { if (o.gi === undefined) { return; } var b = GB[o.gi]; if (!b) { b = GB[o.gi] = [1e9, 1e9, -1e9, -1e9]; } b[0] = Math.min(b[0], o.bb[0]); b[1] = Math.min(b[1], o.bb[1]); b[2] = Math.max(b[2], o.bb[2]); b[3] = Math.max(b[3], o.bb[3]); });
  each(FLOWS, function (f) { each(f.p, function (p) { bb(null, PX(p)); }); });
  GEB = { it: it, vb: [x0 - 25, y0 - 25, x1 - x0 + 50, y1 - y0 + 50], PB: PB, GB: GB, fl: FLOWS.slice(), mk: MARKEN.slice(), zo: ZONEN.slice() };
  return GEB;
}
/* Zusammenhaengende Stuecke je Bauteil finden (fuer das Vergroessern je Stueck) */
function gruppen(it) {
  var nach = {};
  each(it, function (o) {
    if (!o.pid) { return; }
    var b = [1e9, 1e9, -1e9, -1e9];
    each(o.p, function (p) { b[0] = Math.min(b[0], p[0]); b[1] = Math.min(b[1], p[1]); b[2] = Math.max(b[2], p[0]); b[3] = Math.max(b[3], p[1]); });
    o.bb = b; (nach[o.pid] = nach[o.pid] || []).push(o);
  });
  var nr = 0;
  for (var pid in nach) {
    var L = nach[pid].slice().sort(function (a, b) { return a.bb[0] - b.bb[0]; }), P = [], i, j;
    for (i = 0; i !== L.length; i++) { P.push(i); }
    function wurzel(x) { while (P[x] !== x) { P[x] = P[P[x]]; x = P[x]; } return x; }
    for (i = 0; i !== L.length; i++) {
      for (j = i + 1; j !== L.length; j++) {
        if (gt(L[j].bb[0], L[i].bb[2] + 2)) { break; }
        if (gt(L[j].bb[1], L[i].bb[3] + 2)) { continue; }
        if (gt(L[i].bb[1], L[j].bb[3] + 2)) { continue; }
        var a = wurzel(i), c = wurzel(j); if (a !== c) { P[a] = c; }
      }
    }
    var map = {};
    for (i = 0; i !== L.length; i++) { var w = wurzel(i); if (map[w] === undefined) { map[w] = nr++; } L[i].gi = map[w]; }
  }
}
function element(o) {
  var e;
  if (o.t === 'f') {
    e = sv('path', { d: pfad(o.p, 1), fill: o.f, stroke: o.s || o.f, 'stroke-width': o.s ? (o.w || 0.8) : 0.6, 'stroke-linejoin': 'round' });
  } else if (o.t === 'l') {
    e = sv('path', { d: pfad(o.p, 0), fill: 'none', stroke: o.s, 'stroke-width': o.w, 'stroke-linecap': o.lc || 'round', 'stroke-linejoin': 'round', 'stroke-dasharray': o.da || null });
  } else if (o.lg) {
    /* Logo (33_logo.js): Pfad in der Ebene der Flaeche, Mitte o.p[0], Breite o.lb mm */
    var LF = logoForm(o.sy), pl = o.p[0], ml = o.m === 'y' ? [C30, 0.5, 0, 1] : (o.m === 'x' ? [C30, -0.5, 0, 1] : [C30, 0.5, -C30, 0.5]), sl = o.lb * KS / LF.w;
    var ma = ml[0] * sl, mb = ml[1] * sl, mc = ml[2] * sl, md = ml[3] * sl, lcx = LF.x + LF.w / 2, lcy = LF.y + LF.h / 2;
    var me = pl[0] - lcx * ma - lcy * mc, mf = pl[1] - lcx * mb - lcy * md;
    e = sv('path', { d: LF.d, fill: o.fc, 'fill-rule': 'evenodd', transform: 'matrix(' + [ma, mb, mc, md, me, mf].map(function (v) { return Math.round(v * 10000) / 10000; }).join(' ') + ')' });
    if (o.halo) { e.setAttribute('stroke', '#FFFFFF'); e.setAttribute('stroke-width', '2'); e.setAttribute('paint-order', 'stroke'); e.setAttribute('stroke-linejoin', 'round'); }
  } else {
    var p = o.p[0], mtx = o.m === 'y' ? [C30, 0.5, 0, 1] : (o.m === 'x' ? [C30, -0.5, 0, 1] : [C30, 0.5, -C30, 0.5]);
    e = sv('text', { transform: 'matrix(' + mtx.join(' ') + ' ' + f1(p[0]) + ' ' + f1(p[1]) + ')', 'font-size': f1(o.fs * KS), fill: o.fc, 'font-weight': o.fw, 'text-anchor': o.an, 'font-family': 'Arial, Helvetica, sans-serif' });
    if (o.halo) { e.setAttribute('stroke', '#FFFFFF'); e.setAttribute('stroke-width', '2.5'); e.setAttribute('paint-order', 'stroke'); e.setAttribute('stroke-linejoin', 'round'); }
    e.textContent = o.s;
  }
  e.setAttribute('vector-effect', 'non-scaling-stroke');
  if (o.op !== undefined) { if (o.op !== null) { e.setAttribute('opacity', o.op); } }
  return e;
}
function zeichneBasis(g, it) {
  var frag = document.createDocumentFragment();
  each(it, function (o) {
    var e = element(o);
    if (o.pid) { e.setAttribute('data-p', o.pid); e.setAttribute('data-g', o.gi); }
    if (o.cls) { e.setAttribute('class', o.cls); }
    frag.appendChild(e);
  });
  g.appendChild(frag);
}
/* Symbol: Flaechen eines Bereichs mit data-a und eigener Gelbstufe, Linien mit data-al, Ausblenden mit data-fx */
function zeichneSymbol(g, it) {
  var frag = document.createDocumentFragment();
  each(it, function (o) {
    var e = element(o);
    if (o.a !== undefined) {
      if (o.t === 'f') {
        var n = o.n || [0, 0, 1];
        if (o.f === INNEN) { n = [-0.4, -0.4, -0.8]; }
        e.setAttribute('data-a', o.a); e.style.setProperty('--y', shade('y', n)); e.style.setProperty('--z', shade('z', n));
        if (o.k) { e.setAttribute('data-k', '1'); }
      } else { e.setAttribute('data-al', o.a); }
    }
    if (o.fx) { e.setAttribute('data-fx', o.fx.join(' ')); }
    frag.appendChild(e);
  });
  g.appendChild(frag);
}
/* Luftwege: Strichstaerken und Muster fuer Zeichnung und 3D (Dimi 09.11.2026: duennere Linien, ruhiger fuers Auge).
   Musterlaenge 40 bzw. 15 wie die Keyframes wszF und wszK. */
var LW = { halo: 5.5, linie: 3, kurz: 2.4, strich: '15 25', strichKurz: '6 9', spitze: 0.72 };
function zeichneLuft(g, fl) {
  var lauf = {}, P = 40, unter = sv('g', { 'class': 'wsz-lfg' }, g), dash = sv('g', { 'class': 'wsz-lfg' }, g), pf = sv('g', { 'class': 'wsz-lfg' }, g);
  each(fl, function (f) {
    var pts = f.p.map(PX), L = 0, i;
    for (i = 1; i !== pts.length; i++) { L += Math.sqrt(Math.pow(pts[i][0] - pts[i - 1][0], 2) + Math.pow(pts[i][1] - pts[i - 1][1], 2)); }
    var key = f.a + (f.o.offen ? 'o' : ''), d0 = lauf[key] || 0; lauf[key] = d0 + L;
    var c = LUFT[f.a].c, cls = 'wsz-flg' + (f.o.offen ? ' wsz-of' : '') + (f.o.zu ? ' wsz-zu' : '');
    var dp = pfad(pts, 0), T = P / ((f.o.g || 55) * 0.6), ph = ((P - (d0 % P)) / P) * T;
    sv('path', { d: dp, fill: 'none', stroke: '#FFFFFF', 'stroke-width': LW.halo, 'stroke-linecap': 'round', 'stroke-linejoin': 'round', opacity: 0.6, 'class': cls, 'data-p': f.pid }, unter);
    var e = sv('path', { d: dp, fill: 'none', stroke: c, 'stroke-width': f.o.aus ? LW.kurz : LW.linie, 'stroke-linecap': 'round', 'stroke-linejoin': 'round', 'stroke-dasharray': f.o.aus ? LW.strichKurz : LW.strich, 'class': cls + ' wsz-fl' + (f.o.aus ? ' wsz-fk' : ''), 'data-p': f.pid }, dash);
    if (f.o.aus) { T = 15 / ((f.o.g || 40) * 0.6); ph = 0; }
    e.style.animationDuration = f1(T * 100) / 100 + 's';
    e.style.animationDelay = '-' + f1(ph * 100) / 100 + 's';
    /* Pfeilspitze in der Mitte oder am Ende */
    if (gt(L, 45)) {
      var ziel = f.o.aus ? L : L * 0.55, s = 0, a = pts[0], b = pts[1];
      for (i = 1; i !== pts.length; i++) {
        var l = Math.sqrt(Math.pow(pts[i][0] - pts[i - 1][0], 2) + Math.pow(pts[i][1] - pts[i - 1][1], 2));
        if (!lt(s + l, ziel - 0.001)) { var t = l ? (ziel - s) / l : 0; a = pts[i - 1]; b = pts[i]; var m = [a[0] + (b[0] - a[0]) * t, a[1] + (b[1] - a[1]) * t]; break; }
        s += l;
      }
      if (!m) { m = pts[pts.length - 1]; }
      var dx = b[0] - a[0], dy = b[1] - a[1], dl = Math.sqrt(dx * dx + dy * dy) || 1; dx /= dl; dy /= dl;
      var q = LW.spitze, tip = [m[0] + dx * 6 * q, m[1] + dy * 6 * q], l1 = [m[0] - dx * 5 * q - dy * 5.5 * q, m[1] - dy * 5 * q + dx * 5.5 * q], l2 = [m[0] - dx * 5 * q + dy * 5.5 * q, m[1] - dy * 5 * q - dx * 5.5 * q];
      sv('path', { d: pfad([tip, l1, l2], 1), fill: c, stroke: '#FFFFFF', 'stroke-width': 1, 'vector-effect': 'non-scaling-stroke', 'class': cls, 'data-p': f.pid }, pf);
      m = null;
    }
  });
}
function muster(s) {
  var d = sv('defs', {}, s), m = 'matrix(' + C30 + ' 0.5 0 1 0 0)';
  var p = sv('pattern', { id: 'wsz-loch', patternUnits: 'userSpaceOnUse', width: 2.6, height: 2.6, patternTransform: m }, d);
  sv('rect', { width: 2.6, height: 2.6, fill: '#D3DAE2' }, p);
  sv('circle', { cx: 1.3, cy: 1.3, r: 0.62, fill: '#8795A6' }, p);
  var w = sv('pattern', { id: 'wsz-wolle', patternUnits: 'userSpaceOnUse', width: 6, height: 4, patternTransform: m }, d);
  sv('rect', { width: 6, height: 4, fill: '#EDCB62' }, w);
  sv('path', { d: 'M0 1.2C1.5 0.4 3 2 6 1.1M0 3.1C2 2.4 3.6 3.9 6 2.9', fill: 'none', stroke: '#C9A43A', 'stroke-width': 0.35 }, w);
}
function zeichneMarken(g, mk) {
  each(mk, function (m) {
    var a = PX(m.p), b = [a[0] + m.dx, a[1] + m.dy], gg = sv('g', { 'class': 'wsz-mk' }, g), w = m.s.length * 4.3 + 6;
    sv('path', { d: pfad([a, b], 0), stroke: '#1F3855', 'stroke-width': 1, fill: 'none', 'vector-effect': 'non-scaling-stroke' }, gg);
    sv('circle', { cx: f1(a[0]), cy: f1(a[1]), r: 1.3, fill: '#1F3855' }, gg);
    sv('rect', { x: f1(b[0] - w / 2), y: f1(b[1]), width: f1(w), height: 10, rx: 1.5, fill: '#FFFFFF', stroke: '#1F3855', 'stroke-width': 1, 'vector-effect': 'non-scaling-stroke' }, gg);
    var t = sv('text', { x: f1(b[0]), y: f1(b[1] + 7.3), 'font-size': 7.4, 'text-anchor': 'middle', fill: '#1F3855', 'font-weight': 700, 'font-family': 'Arial, Helvetica, sans-serif' }, gg);
    t.textContent = m.s;
  });
}
var CSS = [
  '.wsz{position:relative;color:#1A1D21;font-family:Arial,Helvetica,sans-serif}',
  /* Im Bild: oben links Schalter Luftströmung und Legende, oben rechts Einklappen (Dimi 09.11.2026) */
  '.wsz-ol{position:absolute;left:8px;top:8px;z-index:5;background:rgba(255,255,255,.9);border:1px solid #d5dde6;padding:6px 9px;font-size:12px;line-height:16px;color:#1A1D21}',
  /* Luftstroemung (Dimi 09.11.2026, Runde 9): nur sichtbar, solange die Maus auf der Anlage ist (am Handy beim Beruehren) */
  '.wsz-lk{display:flex;align-items:baseline;flex-wrap:wrap;gap:0 6px;font-size:12px;line-height:16px;font-weight:700;color:#1F3855}',
  '.wsz-lk small{font-size:11px;font-weight:400;color:#6E737A}',
  '.wsz-lk .wsi-w{margin-left:4px}.wsz-lk .wsi{width:18px;height:18px;font-size:12px;line-height:16px}',
  '.wsz-schem{position:absolute;left:10px;bottom:12px;z-index:4;font-size:11px;line-height:14px;color:#6E737A;background:rgba(255,255,255,.85);padding:1px 5px;pointer-events:none}',
  '.wsi-h1 .wsi{width:22px;height:22px;font-size:14px;line-height:20px}',
  '.wsz-lfg{transition:opacity .35s ease}',
  '.wsz-lf0 .wsz-lfg{opacity:0}',
  '.wsz-lfx .wsz-lfg{display:none}',
  '.wsz-lfx .wsz-fl{animation:none}',
  '.wsz-lgs{transition:opacity .35s ease}',
  '.wsz-lf0 .wsz-lgs{opacity:.7}',
  '.wsz-lgs{display:grid;grid-template-columns:auto auto;gap:3px 12px;margin-top:5px}',
  '.wsz-lg{display:inline-flex;align-items:center;gap:5px;white-space:nowrap}',
  '.wsz-lg i{display:inline-block;width:18px;height:4px;border-radius:2px}',
  '.wsz-lg b{font-weight:700;color:#5C6670;font-size:10px}',
  '.wsz-kn{position:absolute;right:8px;top:8px;z-index:5;display:flex;gap:6px}',
  '.wsz-ek{display:inline-flex;align-items:center;justify-content:center;gap:7px;width:34px;height:30px;font-family:inherit;font-size:13px;line-height:18px;padding:0;border:1px solid #1F3855;background:rgba(255,255,255,.92);color:#1F3855;cursor:pointer}',
  '.wsz-ek:hover,.wsz-zul:hover{background:#EEF2F6}',
  '.wsz-zui{display:inline-block;width:7px;height:7px;border-right:2px solid currentColor;border-bottom:2px solid currentColor;transform:rotate(-135deg);margin-top:4px}',
  '.wsz-zul .wsz-zui{transform:rotate(45deg);margin:0 0 4px 0}',
  '.wsz-zul{display:flex;align-items:center;gap:10px;width:100%;font-family:inherit;font-size:14px;line-height:18px;font-weight:700;color:#1F3855;background:#F3F6F9;border:1px solid #d5dde6;padding:9px 12px;cursor:pointer;text-align:left}',
  '.wsz-zul[hidden]{display:none}',
  '@media (max-width:560px){.wsz-lg b{display:none}.wsz-ol{padding:5px 7px}}',
  '.wsz-buehne{position:relative;width:100%;background:#fff;border:1px solid #d5dde6;overflow:hidden;touch-action:manipulation}',
  /* Handy-Runde (Dimi 12.11.2026, Prüfliste 25): nur am Handy (grober Zeiger), der Rechner bleibt gleich */
  '@media (max-width:699px) and (pointer:coarse){.wsz-rand{margin-left:calc(0px - var(--wszRl,0px));margin-right:calc(0px - var(--wszRr,0px))}}',
  '@media (pointer:coarse){.wsz-ol{padding:5px 8px}.wsz-ol .wsz-lgs{display:none}.wsz-ol.wsz-lgauf .wsz-lgs{display:grid}.wsz-lk{cursor:pointer;align-items:center}.wsz-lk::after{content:"▾";font-size:11px;color:#1F3855}.wsz-lgauf .wsz-lk::after{content:"▴"}',
  ' .wsz-schem{max-width:calc(100% - 170px);white-space:normal}}',
  /* Tippflaechen am Handy mindestens 40 x 40 px (unsichtbar vergroessert, Prüfliste 25.8) */
  '@media (pointer:coarse){.wsi,.wsy-wb,.wsz-ek,.wsy-tour{position:relative}.wsi::after,.wsy-wb::after,.wmk-pl::after,.wsz-ek::after,.wsy-tour::after{content:"";position:absolute;left:50%;top:50%;width:40px;height:40px;transform:translate(-50%,-50%)}}',
  /* Balken ueber der Kartei: am Handy mit Text */
  '@media (max-width:999px){.wkg-zst::after{content:"Schließen";font:700 14px/18px Arial,Helvetica,sans-serif;color:#fff}.wkg-zst svg{width:30px;height:16px}}',
  '.wsz-buehne svg{display:block;width:100%;height:auto}',
  '.wsz-ov{position:absolute;left:0;top:0;width:100%;height:100%;pointer-events:none}',
  '.wsz-base{transition:opacity .25s,filter .25s}',
  '.wsz-h .wsz-base{filter:grayscale(1);opacity:.28}',
  '.wsz-hl{pointer-events:none}',
  '.wsz-hl g{transition:transform .22s ease-out;transform-box:fill-box;transform-origin:50% 50%;filter:drop-shadow(0 6px 8px rgba(31,56,85,.28))}',
  '.wsz-fl{animation:wszF linear infinite}',
  '@keyframes wszF{to{stroke-dashoffset:-40}}','.wsz-fk{animation-name:wszK}','@keyframes wszK{to{stroke-dashoffset:-15}}',
  '.wsz-flg{transition:opacity .25s}',
  '.wsz-h .wsz-flg{opacity:.12}',
  '.wsz-zo{transition:opacity .25s}.wsz-h .wsz-zo{opacity:.25}',
  '.wsz-h .wsz-flg.on{opacity:1}',
  '.wsz .sdw{transition:opacity .6s}',
  '.wsz-offen .sdw{opacity:.08}',
  '.wsz .sdx{opacity:0;transition:opacity .5s ease .55s}',
  '.wsz-offen .sdx{opacity:1}',
  '.wsz .wsz-of{display:none}',
  '.wsz-mk{opacity:0;transition:opacity .4s ease 0s;pointer-events:none}',
  '.wsz-offen .wsz-mk{opacity:1;transition:opacity .5s ease .7s}',
  '.wsz-offen .wsz-of{display:inline}',
  '.wsz-offen .wsz-zu{display:none}',
  /* Runde 14 der Szene (Dimi 10.11.2026): kein blaues Fenster mehr beim Zeigen; nur der Name klein und grau unten rechts */
  '.wsz-tip{position:absolute;right:14px;bottom:12px;pointer-events:none;color:#6E737A;font-size:12px;line-height:15px;white-space:nowrap;display:none;z-index:3;background:rgba(255,255,255,.55);padding:1px 4px}',
  '.wsz-info{grid-column:1/-1;min-width:0;position:relative;margin:0 0 10px 0;border:1px solid #c3ccd6;border-top:0;background:#f7f8fa;padding:16px 18px 18px 18px}',
  /* Rueckweg als dicker Streifen mit Pfeil nach oben (Runde 12 der Szene, Dimi 10.11.2026), auch in den Einzelheiten der Anwendungen */
  '.wkg-zst{display:flex;align-items:center;justify-content:center;gap:10px;box-sizing:border-box;width:calc(100% + 38px);height:32px;margin:-16px -19px 14px -19px;padding:0;background:#1F3855;border:0;color:#fff;cursor:pointer;transition:background .15s}',
  '.wkg-zst svg{display:block;width:44px;height:22px;transition:transform .2s ease}',
  '.wkg-zst:hover{background:#2A4A70}',
  '.wkg-zst:hover svg{transform:scale(1.12)}',
  '.wkg-zst:focus-visible{outline:2px solid #F7BC0C;outline-offset:-4px}',
  '.wkg-zst.kb{margin:-12px -19px 12px -19px}',
  /* Hinweis nach 1 s (hinweisTipp) */
  '.wtp{position:fixed;z-index:2147483000;max-width:300px;padding:6px 10px;background:#1F3855;color:#fff;font:13px/17px Arial,Helvetica,sans-serif;box-shadow:0 4px 14px rgba(0,0,0,.22);pointer-events:none;opacity:0;transition:opacity .2s ease;display:none}',
  '.wtp.auf{opacity:1}',
  '.wsz-info.wsz-ein{animation:wszWeich .6s ease-out}',
  /* weiches Ein- und Ausblenden der Kartei (Runde 11, Punkt 12) */
  '@keyframes wszWeich{from{opacity:0;transform:translateY(6px)}to{opacity:1;transform:none}}',
  '.wsz-info.wsz-aus{opacity:0;transform:translateY(6px);transition:opacity .28s ease,transform .28s ease}',
  '.wsz-info .wsy,.wsz-info .wkp{transition:opacity .2s ease}',
  '.wsz-info.wsz-wechsel .wsy,.wsz-info.wsz-wechsel .wkp{opacity:0}',
  '.wsz-info.wsz-neuein .wsy,.wsz-info.wsz-neuein .wkp{animation:wszEin .5s ease both}',
  '.wsd-pg.wsd-blend .wsd-p{opacity:0;transition:opacity .26s ease}',
  '.wsd-pg .wsd-p.einb{animation:wszEin .5s ease both}',
  '.wsz-info.wsz-morph .wsy-leiste,.wsz-info.wsz-morph .wsy-txt,.wsz-info.wsz-morph .wsy-ber,.wsz-info.wsz-morph .wsy-hi,.wsz-info.wsz-morph .wkp,.wsz-info.wsz-morph .wsz-x{animation:wszEin .42s ease .14s both}',
  '@keyframes wszEin{from{opacity:0}to{opacity:1}}',
  '.wsz-rahmen{position:absolute;z-index:5;pointer-events:none;box-sizing:border-box;border:1px solid #9AA5B1;border-top:4px solid #1F3855}',
  '.wsd-pg .wsd-p{transition:border-color .15s,box-shadow .15s,transform .34s cubic-bezier(.45,0,.55,1),opacity .28s ease}',
  '.wsd-pg .wsd-p.weg{transform:translateX(70%);opacity:0;pointer-events:none}',
  '.wsd-pg .wsd-p.zu{display:none}',
  '.wsd-pg .wsd-p.quelle{border-color:#E0A800;border-top-color:#F7BC0C;background:#FFFBEB}',
  '.wsd-pg.wsd-fahrt{overflow:hidden}',
  '.wsd-sh,.wsd-sk{transition:opacity .3s ease}',
  '.wsd-pg.wsd-fahrt .wsd-sh,.wsd-pg.wsd-fahrt .wsd-sk{opacity:0}',
  '@keyframes wszAuf{from{opacity:0;transform:translateY(-8px)}to{opacity:1;transform:none}}',
  '.wsz-x{position:absolute;top:6px;right:8px;z-index:3;border:0;background:none;font:400 30px/28px Arial,Helvetica,sans-serif;color:#1F3855;cursor:pointer;padding:0 6px}',
  '.wsz-x:hover{color:#E0A800}',
  '.wsz-info h3{margin:0 0 2px 0;padding-right:38px;font-size:20px;line-height:25px;color:#1F3855}',
  '.wsz-mehr{position:absolute;left:50%;bottom:12px;transform:translateX(-50%);z-index:4;max-width:92%;font:700 14px/18px Arial,Helvetica,sans-serif;padding:9px 16px;background:#1F3855;color:#fff;border:0;cursor:pointer;box-shadow:0 3px 10px rgba(16,30,48,.25);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}',
  '.wsz-mehr:hover{background:#2A4A70}',
  '.wsz-mehr[hidden]{display:none}',
  /* Handy-Runde (Prüfliste 25.2): am Handy ueber den Knoepfen unten rechts */
  '@media (pointer:coarse){.wsz-mehr{bottom:58px;font-size:13px;padding:8px 12px}}',
  '.wsz-info .en{font-size:12px;color:#6E737A;margin:0 0 8px 0}',
  '.wsz-info ol{margin:6px 0 0 18px;padding:0}',
  '.wsz-info li{margin:0 0 6px 0;font-size:14px;line-height:19px}',
  '.wsz-st{display:inline-block;font-size:11px;font-weight:700;padding:1px 5px;margin:2px 4px 0 0;color:#fff;background:#1F3855}',
  '.wsz-st.T,.wsz-st.V{background:#1F3855}',
  '.wsz-m{display:inline-flex;flex-direction:column;vertical-align:top;margin:3px 6px 0 0;padding:2px 7px 3px 7px;border:1px solid #c3ccd6;background:#fff;color:#1A1D21;text-decoration:none}',
  'a.wsz-m:hover{border-color:#1F3855}',
  '.wsz-mb{font-size:11px;line-height:14px;color:#6E737A}',
  '.wsz-ty{font-size:13px;line-height:16px;font-weight:700;color:#1F3855;white-space:nowrap}',
  '.wsz-ty.ph{color:#9AA3AD;font-weight:400;font-style:italic}',
  '.wsz-m.g{border-style:dashed;background:#FAFBFC}',
  '.wsz-m.g .wsz-ty{color:#8A9099;font-weight:400;font-size:12px}',
  '.wsz-m.z{display:inline-block;border-color:transparent;background:transparent;color:#4B5563;font-style:italic;font-size:13px;padding-left:0}',
  '.wsz-tag{display:inline-block;font-size:11px;padding:1px 6px;margin-left:6px;background:#F7BC0C;color:#1A1D21;font-weight:700}',
  '.wsz-liste{margin:12px 0 0 0;font-size:13px}',
  '.wsz-liste h4{margin:10px 0 4px 0;font-size:12px;text-transform:uppercase;letter-spacing:.04em;color:#1F3855}',
  '.wsz-liste button{font:inherit;font-size:13px;margin:0 6px 6px 0;padding:4px 9px;background:#fff;border:1px solid #d5dde6;color:#1A1D21;cursor:pointer}',
  '.wsz-liste button.k{border-style:dashed;color:#6E737A}',
  '.wsz-liste button.on{border-color:#1F3855;background:#1F3855;color:#fff}',
  /* Kartei-Kopf (Runde 9 der Szene, Dimi 09.11.2026): Fenster mit dem Bauteil (gleich in 3D), daneben die Bereiche als
     Nummern, rechts der Text. Darueber die Bauteile der Kategorie als kleine Kacheln (wsy-leiste) */
  /* Runde 17: feste Hoehe (Fenster), Text und Kacheln passen sich ein */
  '.wsy{display:grid;grid-template-columns:minmax(0,var(--wsy-w,176px)) 34px minmax(0,1fr);grid-template-rows:var(--wsy-h,200px);gap:10px 16px;align-items:start;margin:0 0 8px 0}',
  '.wsy-bild{position:relative;min-width:0;height:var(--wsy-h,200px);background:#fff;border:1px solid #d5dde6}',
  '.wsy-bild svg{display:block;width:100%;height:100%}',
  '.wsy-bild .wt3{position:absolute;left:0;top:0;width:100%;height:100%!important}',
  '.wsy-bild .wsy-hi{position:absolute;left:8px;bottom:8px;margin:0;z-index:4}',
  '.wsy.wsy-neu .wsy-txt,.wsy.wsy-neu .wsy-ber{animation:wszEin .45s ease both}',
  '.wsy-txt{min-width:0;height:var(--wsy-h,200px);overflow:hidden;box-sizing:border-box}',
  '.wsy-txt .wsy-kk{margin:0 0 4px 0}',
  '.wsy-txt h3{margin:0 0 6px 0;padding-right:38px;font-size:20px;line-height:25px;color:#1F3855}',
  '.wsy-txt .wkp-tx{margin:0}',
  '.wsy-zg{height:14px;right:22px}',
  /* Ecke unten rechts: Fenster in Breite und Hoehe ziehen (Runde 12 der Szene) */
  '.wsy-eg{position:absolute;right:0;bottom:0;z-index:7;width:22px;height:22px;cursor:nwse-resize;touch-action:none;background:linear-gradient(135deg,rgba(255,255,255,0) 45%,#9AA6B2 45%,#9AA6B2 52%,rgba(255,255,255,0) 52%,rgba(255,255,255,0) 64%,#9AA6B2 64%,#9AA6B2 71%,rgba(255,255,255,0) 71%,rgba(255,255,255,0) 82%,#9AA6B2 82%,#9AA6B2 89%,rgba(255,255,255,0) 89%)}',
  '.wsy-eg:hover,.wsy-eg.an{background:linear-gradient(135deg,rgba(255,255,255,0) 45%,#1F3855 45%,#1F3855 52%,rgba(255,255,255,0) 52%,rgba(255,255,255,0) 64%,#1F3855 64%,#1F3855 71%,rgba(255,255,255,0) 71%,rgba(255,255,255,0) 82%,#1F3855 82%,#1F3855 89%,rgba(255,255,255,0) 89%)}',
  '.wsy-kk{font-size:12px;line-height:16px;font-weight:700;color:#1F3855;text-transform:uppercase;letter-spacing:.05em;margin:0 0 8px 0}',
  '.wsy-leiste{margin:0 0 14px 0}',
  /* Runde 16: Kopf (Kategorie und Kacheln) rechts neben dem Fenster ueber dem Text; Fenster und Nummern ueber beide Zeilen */
  '.wsy.mk{grid-template-columns:minmax(0,var(--wsy-w,176px)) 34px minmax(0,1fr) max-content}',
  '.wsy.mk .wsy-bild,.wsy.mk .wsy-ber{grid-row:1}',
  '.wsy.mk .wsy-txt{grid-column:3;grid-row:1}',
  '.wsy.mk .wsy-kopf{grid-column:4;grid-row:1;min-width:0;height:var(--wsy-h,200px);overflow:hidden;box-sizing:border-box}',
  '.wsy-kopf .wsy-kk{margin:0 0 6px 0}',
  '.wsy-kopf .wsy-leiste{display:grid;grid-template-columns:repeat(3,var(--kw,88px));margin:0;gap:4px;align-content:start}',
  '.wsy-kopf .wsy-leiste.einzeln{grid-template-columns:repeat(var(--sp,6),var(--kw,74px))}',
  '.wsy-kopf .wsy-leiste .wkg-alle{grid-column:1/-1;width:auto;min-height:26px;padding:4px 8px;justify-content:center}',
  '.wsy-kopf .wsy-leiste .wkg-alle .wkg-ct{margin:0;font-size:12px;line-height:16px;font-weight:700;letter-spacing:.02em}',
  /* abgesetzte Kachel (gepresste Formteile): Linie im Abstand davor, wie zwischen den Gruppen der Kartei */
  '.wsy-kopf .wkg-c.wkg-ab{position:relative;overflow:visible}',
  '.wsy-kopf .wkg-c.wkg-ab::before{content:"";position:absolute;left:-4px;top:0;bottom:0;width:3px;margin-left:-1px;background:#1F3855}',
  '.wsy-kopf .wkg-c{width:var(--kw,64px);padding:3px 2px 4px 2px;box-sizing:border-box}',
  '.wsy-kopf .wkg-ci{width:100%;height:calc(var(--kw,64px) * 0.62)}',
  '.wsy-kopf .wkg-ct{font-size:10.5px;line-height:12px}',
  '.wsy-kopf .wkg-gap{flex:0 0 8px}',
  /* Bauformen der Kachel uebereinander, eine sichtbar; Beschriftung ohne automatische Trennung (Dimi: „Formstü-cke“) */
  '.wkg-ci.wkg-vs{position:relative}',
  '.wkg-v{position:absolute;left:0;top:0;width:100%;height:100%;display:flex;align-items:center;justify-content:center;opacity:0;transition:opacity .5s ease}',
  '.wkg-v.auf{opacity:1}',
  '.wkg-v img{max-width:100%;max-height:100%}',
  '.wkg-c .wkg-ct{-webkit-hyphens:manual;hyphens:manual;overflow-wrap:normal;word-break:normal}',
  /* Rueckweg links in der Leiste (Runde 11, Punkt 17), „Alle …“ mit einer Kachel Abstand (Punkt 16) */
  '.wkg-zur{flex:0 0 auto;display:flex;align-items:center;justify-content:center;width:40px;align-self:stretch;min-height:68px;padding:0;background:#1F3855;border:1px solid #1F3855;color:#fff;cursor:pointer}',
  '.wkg-zur svg{display:block;width:22px;height:36px}',
  '.wkg-zur:hover{background:#2A4A70}',
  '.wkg-zur:focus-visible{outline:2px solid #F7BC0C;outline-offset:2px}',
  /* Runde 14 (Dimi 10.11.2026): Abstand nach „Alle …“ halbiert (vorher 6 + 74 + 6 px) */
  '.wkg-gap{flex:0 0 31px}',
  '.wkg-alle .wkg-ct{font-weight:700;color:#1F3855}',
  /* Runde 18 (Dimi 11.11.2026, 22:43): Knoepfe im Fenster halb so gross (am Handy groesser zum Antippen) */
  '.wsy-wk{position:absolute;right:4px;top:4px;z-index:5;display:flex;gap:3px}',
  '.wsy-wb{display:inline-flex;align-items:center;justify-content:center;gap:3px;font:10px/12px Arial,Helvetica,sans-serif;width:16px;height:15px;padding:0;border:1px solid #9AA6B2;background:rgba(255,255,255,.94);color:#1F3855;cursor:pointer}',
  '.wsy-wb:hover{border-color:#1F3855}',
  '.wsy-wb.on{background:#1F3855;border-color:#1F3855;color:#fff}',
  '.wsy-wb[hidden]{display:none}',
  '.wdk-ic{display:block;width:16px;height:16px}',
  '.wsy-bild .wsy-wb svg.wdk-ic{display:block;width:9px;height:9px}',
  '.wsz-kn svg.wdk-ic{display:block;width:16px;height:16px}',
  '@media (pointer:coarse){.wsy-wb{width:26px;height:24px}.wsy-bild .wsy-wb svg.wdk-ic{width:13px;height:13px}}',
  /* Szene: Hoehe ziehen (Runde 11, Punkt 9) */
  '.wsz-zg{position:absolute;left:0;right:0;bottom:0;height:16px;z-index:6;cursor:ns-resize;display:flex;align-items:center;justify-content:center;touch-action:none;background:linear-gradient(rgba(255,255,255,0),rgba(238,242,246,.85))}',
  '.wsz-zg span{display:block;width:46px;height:5px;border-radius:3px;background:#9AA6B2}',
  '.wsz-zg:hover span,.wsz-zg.an span{background:#1F3855}',
  '.wsz-zg:focus-visible{outline:2px solid #F7BC0C;outline-offset:-2px}',
  '.wsz-dr .wdk-ic{width:15px;height:15px}',
  /* Runde 18 (Dimi 11.11.2026, 22:43): der Name des Formstuecks steht ganz unten am Rand, nicht ueber dem Bauteil */
  '.wsy-cap{position:absolute;left:26px;right:22px;bottom:1px;z-index:4;font-size:10.5px;line-height:13px;font-weight:700;color:#1F3855;text-align:center;background:rgba(255,255,255,.85);padding:0 2px;pointer-events:none;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;transition:opacity .4s ease}',
  '.wsy-bild .wsy-zg{display:none}',
  '.wsy-cap.aus{opacity:0}',
  /* Runde 18: im schmalen Fenster (Breite der Elementkarten) steht der Name unten statt unter den Knoepfen */
  '.wsy-bild.eng .wsy-cap{font-size:10px;line-height:12px}',
  '.wsy-al{margin:8px 0 0 0;font-size:13px;line-height:21px;color:#4B5563}',
  '.wsy-bild path{transition:fill .25s,stroke .25s,opacity .35s}',
  '.wsy-ber{position:relative;z-index:6;display:flex;flex-direction:column;align-items:center;gap:var(--nrg,7px);min-width:0;padding:2px 0 0 0;box-sizing:border-box}',
  '.wsy-nr{position:relative;width:var(--nr,30px);height:var(--nr,30px);flex:0 0 auto;padding:0;border-radius:50%;border:1px solid #c3ccd6;background:#fff;color:#1F3855;font:700 14px Arial,Helvetica,sans-serif;line-height:calc(var(--nr,30px) - 2px);text-align:center;cursor:pointer;transition:background .2s,border-color .2s}',
  '.wsy-nr:hover{border-color:#1F3855}',
  '.wsy-nr.on{background:#F7BC0C;border-color:#C99400;color:#1A1D21}',
  '.wsy-nr:focus-visible{outline:2px solid #1F3855;outline-offset:2px}',
  '.wsy-nt{display:none;position:absolute;left:38px;top:50%;transform:translateY(-50%);z-index:30;width:max-content;max-width:260px;padding:5px 9px;background:#FFFFFF;color:#1A1D21;border:1px solid #1F3855;border-left:4px solid #F7BC0C;font:400 13px/17px Arial,Helvetica,sans-serif;text-align:left;white-space:normal;box-shadow:0 3px 12px rgba(0,0,0,.22);pointer-events:none}',
  '.wsy-nr:hover .wsy-nt,.wsy-nr:focus-visible .wsy-nt{display:block}',
  '.wsy-tour{width:30px;height:26px;padding:0;border:0;background:none;color:#1F3855;font-size:15px;line-height:26px;cursor:pointer}',
  '.wsy-tour:hover{color:#000}',
  '@media (max-width:900px){.wsy-kopf .wsy-leiste{grid-template-columns:repeat(3,minmax(0,1fr))}.wsy-kopf .wkg-c{width:auto}.wsy,.wsy.mk{grid-template-columns:minmax(0,1fr) 34px;grid-template-rows:auto}.wsy-txt,.wsy.mk .wsy-kopf{height:auto;overflow:visible}.wsy-txt{grid-column:1/-1}.wsy.mk .wsy-kopf{grid-column:1/-1;grid-row:1}.wsy.mk .wsy-bild,.wsy.mk .wsy-ber{grid-row:2}.wsy.mk .wsy-txt{grid-column:1/-1;grid-row:3}}',
  '@media (max-width:560px){.wsy-bild{height:230px}}',
  /* Handy-Runde (Prüfliste 25.9): in der schmalen Kartei ist die Namenszeile der Formstueck-Kacheln immer zwei Zeilen hoch,
     sonst springt alles darunter, wenn eine Kachel die Bauform wechselt (am Rechner hat der Kopf eine feste Hoehe) */
  '@media (max-width:900px){.wsy-kopf .wkg-c .wkg-ct{min-height:26px}}',
  '@keyframes wsyP{0%,100%{fill:var(--y);stroke:var(--y)}50%{fill:var(--z);stroke:var(--z)}}',
  (function () { var r = ''; for (var k = 0; k !== 9; k++) { r += '.wsy-a' + k + ' [data-a="' + k + '"]{fill:var(--y);stroke:var(--y);animation:wsyP 1.5s ease-in-out 1}' + '.wsy-a' + k + ' [data-al="' + k + '"]{stroke:#A97A00;stroke-width:1.9px}' + '.wsy-a' + k + ' [data-fx~="' + k + '"]{opacity:.09}' + '.wsy-a' + k + ' [data-a="' + k + '"][data-k]{stroke:#7A5600;stroke-width:1.5px}'; } return r; })(),
  '.wst-z{margin:3px 0 0 0}',
  /* Ruhe (Dimi 09.11.2026): Bereich leuchtet einmal auf und bleibt dann gelb; der blasse Grundkoerper bleibt blass */
  (function () { var r = ''; for (var k = 0; k !== 4; k++) { r += '.wsy-gh' + k + ':not(.wsy-a' + k + ') [data-a="' + k + '"],.wsy-gh' + k + ':not(.wsy-a' + k + ') [data-al="' + k + '"]{opacity:.22}'; } return r; })(),
  /* Hinweis hinter einem i (infoKnopf) */
  '.wsi-w{position:relative;display:inline-block;vertical-align:middle;margin:0 0 0 8px;line-height:0}',
  '.wsi{width:20px;height:20px;padding:0;border-radius:50%;border:1px solid #9AA6B2;background:#fff;color:#1F3855;font:italic 700 13px/18px Georgia,"Times New Roman",serif;text-align:center;cursor:pointer;text-transform:none;letter-spacing:0}',
  '.wsi:hover,.wsi-w.auf .wsi{border-color:#1F3855;background:#1F3855;color:#fff}',
  '.wsi:focus-visible{outline:2px solid #F7BC0C;outline-offset:2px}',
  '.wsi-b{display:none;position:absolute;z-index:40;left:50%;top:27px;transform:translateX(-50%);width:max-content;max-width:300px;padding:8px 11px;background:#1F3855;color:#fff;font:400 13px/18px Arial,Helvetica,sans-serif;text-transform:none;letter-spacing:0;text-align:left;white-space:normal;box-shadow:0 4px 14px rgba(0,0,0,.18)}',
  '.wsi-w.auf .wsi-b{display:block}',
  '.wsi-w.oben .wsi-b{top:auto;bottom:27px}',
  '.wsi-w.links .wsi-b{left:0;transform:none}',
  '@media (max-width:560px){.wsi-b{max-width:calc(100vw - 32px)}}',
  '@media (prefers-reduced-motion:reduce){.wsz-fl{animation:none}.wsz-hl g{transition:none}.wsy-bild [data-a],.wsy-bild [data-al]{animation:none}}'
].join('');
/* Maschinen eines Schritts nach Stufen (Einzelheiten zu einer Kachel in der kompakten Bauteilansicht) */
var PNAME = {};
each(DATA.prozesse || [], function (p) { PNAME[p.id] = p.t; });
function stufenZeilen(s, par) {
  var gleich = s.M.join('|') === s.T.join('|') ? s.T.join('|') === s.V.join('|') : false;
  each(gleich ? ['M'] : ['M', 'T', 'V'], function (k) {
    if (!s[k].length) { return; }
    var d = ht('div', 'wst-z', null, par); ht('span', 'wsz-st ' + k, gleich ? 'alle Stufen' : DATA.stufen[k], d);
    each(s[k], function (id) { chip(id, d); });
  });
}
/* Symbol mit Bereichen im Infokasten: Rundgang durch alle Bereiche, Zeigen und Antippen */
var TOUR = null, SYMTOK = 0;
function tourAus() { if (TOUR) { window.clearTimeout(TOUR); TOUR = null; } }
function symbolSvg(S, b, nurV) {
  if (!document.getElementById('wsz-loch')) { var hs = sv('svg', { width: 0, height: 0, 'aria-hidden': 'true' }); hs.style.position = 'absolute'; muster(hs); document.body.appendChild(hs); }
  /* Wechselbild (52_varianten.js): mehrere Bauformen; nurV zeigt nur Bauform nurV (Test) */
  var V = symbolVarianten(b.id) || [S];
  if (nurV !== undefined) { S = V[nurV] || S; V = [S]; }
  var svg = sv('svg', { viewBox: S.vb.map(f1).join(' '), role: 'img', 'aria-label': 'Zeichnung ' + b.t + ' mit ' + b.bereiche.length + ' Bereichen' + (gt(V.length, 1) ? ', ' + V.length + ' Bauformen im Wechsel' : '') });
  if (gt(V.length, 1)) { variantenZeichnen(svg, V, true); } else { zeichneSymbol(sv('g', {}, svg), S.it); }
  var gh = (SYM[b.id] || {}).ghost; if (gh !== undefined) { svg.classList.add('wsy-gh' + gh); }
  return svg;
}
function bereichSetzen(svg, k) {
  for (var i = 0; i !== 9; i++) { svg.classList.remove('wsy-a' + i); }
  each(k === null || k === undefined ? [] : (Array.isArray(k) ? k : [k]), function (x) { svg.classList.add('wsy-a' + x); });
}
/* Kartei-Kopf (Runde 9 der Szene, Dimi 09.11.2026): Fenster | Bereiche als Nummern | Text (o.txt).
   Das Bauteil ist gleich in 3D beweglich (teil3d, ohne Knoepfe), start3d(ms) setzt die Flaeche nach dem Einflug des Bildes;
   ohne WebGL 2 bleibt die Zeichnung mit den Bauformen im Wechsel. Eine Nummer zeigen oder antippen hebt den Bereich im Bild
   hervor und meldet ihn an die Tabelle darunter (zeilen(fn)); dort leuchtet die Zeile mit derselben Nummer.
   Rueckgabe: an(k)/ab() (k Zahl oder Feld), zeilen(fn), start3d(ms), zurueck() (Ausgangslage), zu() (3D freigeben). */
function symbolBlock(info, b, o) {
  o = o || {};
  var S = symbolBauen(b.id); if (!S) { return false; }
  var tok = SYMTOK, n = b.bereiche.length, kn = [], fest = null, zFn = null, T = null, T3W = null, akt = [];
  var wrap = ht('div', 'wsy', null, info), bild = ht('div', 'wsy-bild', null, wrap), svg = symbolSvg(S, b);
  bild.appendChild(svg); fensterZiehen(bild);
  /* Erklaerung zum Bild hinter dem i (Dimi 09.11.2026) */
  if (S.hw) { infoKnopf(bild, S.hw, { oben: true, links: true, cls: 'wsy-hi', label: 'Was das Bild zeigt' }); }
  var ber = ht('div', 'wsy-ber', null, wrap); ber.setAttribute('role', 'group'); ber.setAttribute('aria-label', 'Bereiche');
  if (o.txt) { wrap.appendChild(o.txt); }
  /* Masse und Drucken (Runde 11, Punkte 10 und 11) */
  var WK = karteiWerkzeuge(bild, {
    masse: function () { return T; },
    zoom: function () { return T; },
    druck: function () {
      var z = ['Bereiche: ' + b.bereiche.map(function (t, i) { return (i + 1) + ' ' + t.replace(/ *\([^)]*\)/g, ''); }).join(' · ')];
      if (T ? MASSE_AN : false) { var ml = masseLegende(b.id, T); if (ml) { z.push(ml); } }
      function weiter(u) { druckSeite({ titel: b.t, unter: KATV[b.id] ? KATV[b.id].t : '', bild: u, svg: u ? null : svg, text: (DATA.btx || {})[b.id] || '', zeilen: z }); }
      if (T) { T.bild(weiter); } else { weiter(''); }
    }
  });
  /* Bauformen im Wechsel (52_varianten.js wechselSteuern): Zeiger ueber Bild oder Nummern haelt an; ein Bereich wird in der
     gezeigten Bauform hervorgehoben, gewechselt wird nur, wenn sie ihn nicht hat. Nach dem Drehen bleibt die Bauform stehen,
     bis die Bauteil-Kachel die Ansicht zuruecksetzt. */
  var ctl = svg.wsvCtl || null;
  /* Runde 17: Klick auf ein zusammengelegtes Bauteil in der Anlage (z. B. Rohrgabelung): diese Bauform zeigen und stehen lassen */
  if (ctl) { if (o.bauform !== undefined) { if (gt(o.bauform, 0)) { if (lt(o.bauform, ctl.n)) { ctl.zeige(o.bauform); ctl.halt('wahl', true); } } } }
  if (ctl) {
    each([bild, ber], function (el, i) {
      el.addEventListener('mouseenter', function () { ctl.halt('zeiger' + i, true); });
      el.addEventListener('mouseleave', function () { ctl.halt('zeiger' + i, false); });
    });
  }
  function liste(k) { return k === null || k === undefined ? [] : (Array.isArray(k) ? k : [k]); }
  function setA(k) {
    var L = liste(k); akt = L;
    if (ctl) { ctl.bereich(L.length ? L[0] : null); ctl.halt('bereich', L.length !== 0); }
    bereichSetzen(svg, L); each(kn, function (bt, i) { bt.classList.toggle('on', L.indexOf(i) !== -1); });
    if (T) { T.bereich(L); }
    if (zFn) { zFn(L); }
  }
  each(b.bereiche, function (t, k) {
    var bt = ht('button', 'wsy-nr', String(k + 1), ber); bt.type = 'button';
    bt.setAttribute('aria-label', 'Bereich ' + (k + 1) + ': ' + t);
    ht('span', 'wsy-nt', t, bt).setAttribute('aria-hidden', 'true');
    bt.addEventListener('mouseenter', function () { tourAus(); setA(k); });
    bt.addEventListener('mouseleave', function () { if (!TOUR) { setA(fest); } });
    bt.addEventListener('click', function () { tourAus(); fest = (fest === k) ? null : k; setA(fest); });
    kn.push(bt);
  });
  var tb = null;
  if (gt(n, 1)) { tb = ht('button', 'wsy-tour', '▸', ber); tb.type = 'button'; tb.title = 'Bereiche nacheinander zeigen'; tb.setAttribute('aria-label', 'Bereiche nacheinander zeigen'); }
  /* Dimi 11.11.2026, 07:54: die Spalte ist nie hoeher als das Fenster links (unten buendig); bei vielen Bereichen werden die Knoepfe
     kleiner, damit beim Wechsel der Bauteile nichts springt */
  function berPassen() {
    if (!bild.isConnected) { return; }
    var H = bild.getBoundingClientRect().height; if (!H) { return; }
    var d = 30, g = 7, m = kn.length;
    function bedarf() { return m * d + (m - 1) * g + (tb ? g + 26 : 0) + 2; }
    while (gt(bedarf(), H)) { if (!gt(d, 18)) { break; } d -= 1; if (gt(g, 3)) { g -= 0.5; } }
    ber.style.setProperty('--nr', d + 'px'); ber.style.setProperty('--nrg', g + 'px'); ber.style.maxHeight = Math.round(H) + 'px';
  }
  window.requestAnimationFrame(berPassen);
  if (window.ResizeObserver) { new ResizeObserver(berPassen).observe(bild); }
  function schritt(i) {
    if (tok !== SYMTOK) { return; }
    if (i === n) { TOUR = null; setA(fest); return; }
    setA(i); TOUR = window.setTimeout(function () { schritt(i + 1); }, 1700);
  }
  function tour() { tourAus(); fest = null; TOUR = window.setTimeout(function () { schritt(0); }, 450); }
  if (tb) { tb.addEventListener('click', tour); }
  function ziel(ev) {
    var t = ev.target; if (!t || !t.getAttribute) { return null; }
    var a = t.getAttribute('data-a'); if (a === null) { a = t.getAttribute('data-al'); }
    return a === null ? null : parseInt(a, 10);
  }
  svg.addEventListener('mousemove', function (ev) { var k = ziel(ev); if (k !== null) { tourAus(); setA(k); } });
  svg.addEventListener('mouseleave', function () { if (!TOUR) { setA(fest); } });
  svg.addEventListener('click', function (ev) { var k = ziel(ev); tourAus(); fest = (k === null || k === fest) ? null : k; setA(fest); });
  /* Rundgang starten, sobald das Bild sichtbar ist */
  if (window.IntersectionObserver) {
    var io = new IntersectionObserver(function (es) { each(es, function (e) { if (e.isIntersecting) { io.disconnect(); if (tok === SYMTOK) { tour(); } } }); }, { threshold: 0.4 });
    io.observe(bild);
  } else { tour(); }
  function frei() { T = null; svg.wsvNeu = null; WK.zeigeZoom(false); if (ctl) { ctl.halt('3d', false); } }
  function start3d() {
    T3W = null;
    if (T) { return; } if (tok !== SYMTOK) { return; } if (!svg.isConnected) { return; } if (!dreiMoeglich()) { return; }
    T = teil3d(bild, b.id, ctl ? ctl.j() : 0, { svg: svg, weg: frei, beruehrt: function () { if (ctl) { ctl.halt('3d', true); } } });
    if (!T) { return; }
    bild.appendChild(bild.querySelector('.wsy-wk'));
    WK.zeigeMasse(hatMasse(b.id)); WK.zeigeZoom(true);
    if (ctl) { svg.wsvNeu = function (j) { if (T) { T.bauform(j, true); } }; }
    T.bereich(akt);
  }
  return {
    an: function (k) { tourAus(); setA(k); },
    ab: function () { if (!TOUR) { setA(fest); } },
    zeilen: function (fn) { zFn = fn; if (fn) { fn(akt); } },
    start3d: function (ms) { if (T3W) { window.clearTimeout(T3W); T3W = null; } if (lt(ms || 0, 0)) { start3d(); return; } T3W = window.setTimeout(start3d, ms || 0); },
    zurueck: function () { tourAus(); fest = null; setA(null); if (T) { T.zurueck(); } if (ctl) { ctl.halt('3d', false); } },
    zu: function () { if (T3W) { window.clearTimeout(T3W); T3W = null; } if (T) { var t = T; T = null; t.zu(); } frei(); },
    drei: function () { return T; }
  };
}
/* ---------- Drucken und Bildschirmfoto (Dimi 09.11.2026, Runde 11 Punkt 10) ----------
   druckSeite(o): eigene Druckansicht (wie der Katalog der Merkliste): Kopf, Titel, Bild (o.bild data-URL oder o.svg), Text,
   Zeilen. Der Druckdialog bietet auch „Als PDF speichern“. In der Vorschau ist Drucken gesperrt: die Seite erscheint dann
   als Ansicht im Fenster. bildMitSvg legt die Massschicht (SVG) ueber das Bild der 3D-Flaeche. */
function bildMitSvg(url, svgEl, pw, ph, w, h, cb) {
  try {
    var c = document.createElement('canvas'); c.width = pw; c.height = ph;
    var x = c.getContext('2d'), im = new Image();
    im.onload = function () {
      x.drawImage(im, 0, 0, pw, ph);
      var cl = svgEl.cloneNode(true); cl.setAttribute('xmlns', SVGNS); cl.setAttribute('width', String(w)); cl.setAttribute('height', String(h)); cl.removeAttribute('class');
      var st = document.createElementNS(SVGNS, 'style');
      st.textContent = 'text{font:italic 700 15px Georgia,serif;fill:#14304F;paint-order:stroke;stroke:#fff;stroke-width:4px;stroke-linejoin:round}';
      cl.insertBefore(st, cl.firstChild);
      var im2 = new Image();
      im2.onload = function () { x.drawImage(im2, 0, 0, pw, ph); var r = ''; try { r = c.toDataURL('image/png'); } catch (e) { r = url; } cb(r); };
      im2.onerror = function () { cb(url); };
      im2.src = 'data:image/svg+xml;charset=utf-8,' + encodeURIComponent(new XMLSerializer().serializeToString(cl));
    };
    im.onerror = function () { cb(url); };
    im.src = url;
  } catch (e) { cb(url); }
}
function druckSeite(o) {
  var alt = document.getElementById('wmk-druck'); if (alt) { alt.parentNode.removeChild(alt); }
  var d = ht('div', null, null, document.body); d.id = 'wmk-druck';
  ht('div', 'wdk-f', FIRMA.n, d);
  ht('h1', null, o.titel, d);
  if (o.unter) { ht('p', 'wdk-a', o.unter, d); }
  ht('p', 'wdk-a', 'Stand ' + new Date().toLocaleDateString('de-DE') + ' · ' + FIRMA.w, d);
  var bx = ht('div', 'wdk-bild', null, d);
  if (o.bild) { var im = ht('img', null, null, bx); im.alt = o.titel; im.src = o.bild; }
  else if (o.svg) { var c = o.svg.cloneNode(true); c.removeAttribute('style'); c.setAttribute('width', '100%'); bx.appendChild(c); }
  if (o.text) { ht('p', 'wdk-t2', o.text, d); }
  each(o.zeilen || [], function (z) { ht('p', 'wdk-z2', z, d); });
  ht('p', 'wdk-n', 'Schematische Darstellung, nicht maßstäblich. ' + FIRMA.n + ' · ' + FIRMA.a + ' · ' + FIRMA.t + ' · ' + FIRMA.m, d);
  if (VORSCHAU) {
    d.classList.add('wdk-vs');
    var k = ht('div', 'wdk-vk', null, d); d.insertBefore(k, d.firstChild);
    ht('span', null, 'Druckansicht. Auf der Website öffnet sich hier der Druckdialog (auch „Als PDF speichern“); in der Vorschau ist Drucken gesperrt.', k);
    var zu = ht('button', null, 'Schließen', k); zu.type = 'button'; zu.addEventListener('click', function () { if (d.parentNode) { d.parentNode.removeChild(d); } });
    return;
  }
  var h = document.documentElement;
  h.classList.add('wmk-druckt');
  function fertig() { h.classList.remove('wmk-druckt'); window.removeEventListener('afterprint', fertig); }
  window.addEventListener('afterprint', fertig);
  try { window.print(); } catch (e) { fertig(); }
}
/* Drucksymbol fuer Knoepfe */
/* Rueckweg (Runde 11 der Szene, Antwort Punkt 15): ueberall dieselbe schmale Kachel mit grossem Pfeil nach links */
function zurueckKnopf(par, titel, fn) {
  var zr = ht('button', 'wkg-zur', null, par); zr.type = 'button'; zr.title = titel; zr.setAttribute('aria-label', titel);
  var zs = sv('svg', { viewBox: '0 0 24 40', 'aria-hidden': 'true', focusable: 'false' }, zr);
  sv('path', { d: 'M17 6 L5 20 L17 34', fill: 'none', stroke: 'currentColor', 'stroke-width': 3.4, 'stroke-linecap': 'round', 'stroke-linejoin': 'round' }, zs);
  zr.addEventListener('click', function (ev) { ev.stopPropagation(); fn(); });
  return zr;
}
/* Rueckweg (Runde 12 der Szene, Dimi 10.11.2026): der dicke blaue Streifen ueber Kartei und Einzelheiten ist der Rueckweg,
   mit Pfeil nach oben; er ersetzt die schmale Kachel mit dem Pfeil nach links. kl: 'kb' fuer die Einzelheiten der Anwendungen */
function zurueckStreifen(par, titel, fn, kl) {
  var zr = ht('button', 'wkg-zst' + (kl ? ' ' + kl : ''), null, null); zr.type = 'button'; zr.setAttribute('aria-label', titel);
  var zs = sv('svg', { viewBox: '0 0 44 22', 'aria-hidden': 'true', focusable: 'false' }, zr);
  /* Runde 18 (Dimi 11.11.2026, 20:13: der Pfeil nach oben ueber einer nach unten aufgeklappten Kartei ist unlogisch): Kreuz = schliessen, dazu ESC */
  sv('path', { d: 'M15 4 L29 18 M29 4 L15 18', fill: 'none', stroke: 'currentColor', 'stroke-width': 3.2, 'stroke-linecap': 'round', 'stroke-linejoin': 'round' }, zs);
  par.insertBefore(zr, par.firstChild);
  hinweisTipp(zr, titel);
  zr.addEventListener('click', function (ev) { ev.stopPropagation(); tippWeg(); fn(); });
  return zr;
}
/* Hinweis nach 1 s (Runde 12 der Szene, Dimi 10.11.2026): auf jeder Kachel erscheint nach einer Sekunde, was sie zeigt.
   Ersetzt den Hinweis des Browsers (title), der unterschiedlich lange braucht. Am Handy (ohne Maus) entfaellt er. */
var TIPP = null, TIPPT = null, TIPPS = false;
function hinweisTipp(el, txt) {
  if (!el) { return; }
  el.removeAttribute('title'); el.wTipp = txt || '';
  if (el.wTippAn) { return; } el.wTippAn = 1;
  el.addEventListener('mouseenter', function () {
    tippWeg(); if (!el.wTipp) { return; }
    TIPPT = window.setTimeout(function () { TIPPT = null; if (el.isConnected) { if (el.matches(':hover')) { tippZeigen(el); } } }, 1000);
  });
  el.addEventListener('mouseleave', tippWeg);
  el.addEventListener('pointerdown', tippWeg);
  if (!TIPPS) { TIPPS = true; window.addEventListener('scroll', tippWeg, { passive: true }); }
}
function tippZeigen(el) {
  if (!TIPP) { TIPP = ht('div', 'wtp', null, document.body); TIPP.setAttribute('role', 'tooltip'); }
  TIPP.textContent = el.wTipp; TIPP.style.display = 'block';
  var r = el.getBoundingClientRect(), tw = TIPP.offsetWidth, th = TIPP.offsetHeight, vw = window.innerWidth || 1200, vh = window.innerHeight || 800;
  var x = Math.max(8, Math.min(r.left + r.width / 2 - tw / 2, vw - tw - 8)), y = r.bottom + 8;
  if (gt(y + th, vh - 8)) { y = Math.max(8, r.top - th - 8); }
  TIPP.style.left = Math.round(x) + 'px'; TIPP.style.top = Math.round(y) + 'px';
  TIPP.getBoundingClientRect(); TIPP.classList.add('auf');
}
function tippWeg() { if (TIPPT) { window.clearTimeout(TIPPT); TIPPT = null; } if (TIPP) { TIPP.classList.remove('auf'); TIPP.style.display = 'none'; } }
/* Symbol „Ansicht zuruecksetzen“ (Pfeil im Kreis gegen den Uhrzeigersinn) */
function resetIcon(par) {
  var s = sv('svg', { viewBox: '0 0 20 20', 'aria-hidden': 'true', focusable: 'false', 'class': 'wdk-ic' }, par);
  sv('path', { d: 'M4.6 7.2 A6.2 6.2 0 1 1 3.9 12.4 M4.6 2.8 V7.2 H9', fill: 'none', stroke: 'currentColor', 'stroke-width': 1.7, 'stroke-linecap': 'round', 'stroke-linejoin': 'round' }, s);
  return s;
}
/* Lupe plus und minus fuer die 3D-Ansicht (Dimi 11.11.2026, 07:54: Mausrad scrollt die Seite, Zoomen mit Knopf oder Strg + Rad) */
function zoomIcon(par, plus) {
  var s = sv('svg', { viewBox: '0 0 20 20', 'aria-hidden': 'true', focusable: 'false', 'class': 'wdk-ic' }, par);
  sv('path', { d: plus ? 'M4 10 H16 M10 4 V16' : 'M4 10 H16', fill: 'none', stroke: 'currentColor', 'stroke-width': 1.8, 'stroke-linecap': 'round' }, s);
  return s;
}
/* Fenster der Kartei groesser und kleiner ziehen (Runde 11 der Szene, Antwort Punkt 24): Griff am unteren Rand, Doppelklick setzt zurueck.
   Die Hoehe gilt fuer alle Bauteile, bis die Seite neu geladen wird. */
var WSY_H = 0, WSY_W = 0;
/* Runde 18 (Dimi 11.11.2026, 20:13): von Hand gezogene Groesse gilt fuer alle danach geoeffneten Fenster, auch nach dem Neuladen */
try { var wsyM = (window.localStorage.getItem('wmsFenster') || '').split('x'); WSY_W = parseInt(wsyM[0], 10) || 0; WSY_H = parseInt(wsyM[1], 10) || 0; } catch (e) { WSY_W = 0; WSY_H = 0; }
function wsyMerken() { try { if (WSY_W + WSY_H) { window.localStorage.setItem('wmsFenster', WSY_W + 'x' + WSY_H); } else { window.localStorage.removeItem('wmsFenster'); } } catch (e) { } }
function fensterZiehen(bild) {
  /* Ecke unten rechts (Runde 12 der Szene, Dimi 10.11.2026): Breite und Hoehe zugleich; Doppelklick setzt beides zurueck */
  var wrap = bild.parentNode, eg = ht('div', 'wsy-eg', null, bild);
  eg.setAttribute('aria-hidden', 'true');
  hinweisTipp(eg, 'Ziehen: Fenster breiter, schmaler, höher oder niedriger · Doppelklick: zurücksetzen');
  if (WSY_W) { if (wrap) { wrap.style.setProperty('--wsy-w', WSY_W + 'px'); } }
  function breite(w) {
    if (!wrap) { return; }
    var max = Math.max(176, wrap.clientWidth - 34 - 32 - 220);
    WSY_W = Math.round(Math.max(176, Math.min(w, max))); wrap.style.setProperty('--wsy-w', WSY_W + 'px'); wsyMerken();
  }
  var se = null;
  eg.addEventListener('pointerdown', function (ev) { ev.preventDefault(); ev.stopPropagation(); try { eg.setPointerCapture(ev.pointerId); } catch (e) { } var r = bild.getBoundingClientRect(); se = { x: ev.clientX, y: ev.clientY, w: r.width, h: r.height }; eg.classList.add('an'); tippWeg(); });
  eg.addEventListener('pointermove', function (ev) { if (!se) { return; } setz(se.h + (ev.clientY - se.y)); breite(se.w + (ev.clientX - se.x)); });
  function egLos() { se = null; eg.classList.remove('an'); }
  eg.addEventListener('pointerup', egLos); eg.addEventListener('pointercancel', egLos);
  eg.addEventListener('dblclick', function (ev) { ev.stopPropagation(); WSY_H = 0; WSY_W = 0; wsyMerken(); bild.style.height = ''; if (wrap) { wrap.style.removeProperty('--wsy-w'); wrap.style.removeProperty('--wsy-h'); kopfPassen(wrap); } });
  var zg = ht('div', 'wsz-zg wsy-zg', null, bild); ht('span', null, null, zg);
  zg.setAttribute('role', 'separator'); zg.setAttribute('aria-orientation', 'horizontal'); zg.setAttribute('tabindex', '0');
  zg.setAttribute('aria-label', 'Höhe des Fensters ändern'); zg.title = 'Ziehen: Fenster größer oder kleiner · Doppelklick: zurücksetzen';
  if (WSY_H) { bild.style.height = WSY_H + 'px'; if (wrap) { wrap.style.setProperty('--wsy-h', WSY_H + 'px'); } }
  var st = null;
  function setz(h) { WSY_H = Math.round(Math.max(160, Math.min(h, (window.innerHeight || 900) - 90))); bild.style.height = WSY_H + 'px'; if (wrap) { wrap.style.setProperty('--wsy-h', WSY_H + 'px'); } wsyMerken(); }
  zg.addEventListener('pointerdown', function (ev) { ev.preventDefault(); ev.stopPropagation(); try { zg.setPointerCapture(ev.pointerId); } catch (e) { } st = { y: ev.clientY, h: bild.getBoundingClientRect().height }; zg.classList.add('an'); });
  zg.addEventListener('pointermove', function (ev) { if (!st) { return; } setz(st.h + (ev.clientY - st.y)); });
  function los() { st = null; zg.classList.remove('an'); }
  zg.addEventListener('pointerup', los); zg.addEventListener('pointercancel', los);
  zg.addEventListener('dblclick', function (ev) { ev.stopPropagation(); WSY_H = 0; wsyMerken(); bild.style.height = ''; if (wrap) { wrap.style.removeProperty('--wsy-h'); kopfPassen(wrap); } });
  zg.addEventListener('keydown', function (ev) {
    var h = bild.getBoundingClientRect().height;
    if (ev.key === 'ArrowDown') { ev.preventDefault(); setz(h + 30); } else if (ev.key === 'ArrowUp') { ev.preventDefault(); setz(h - 30); }
  });
  return zg;
}
function druckIcon(par) {
  var s = sv('svg', { viewBox: '0 0 20 20', 'aria-hidden': 'true', focusable: 'false', 'class': 'wdk-ic' }, par);
  sv('path', { d: 'M5 7 V2.5 H15 V7 M5 14.5 H3 V8 H17 V14.5 H15 M5 11.5 H15 V17.5 H5 Z', fill: 'none', stroke: 'currentColor', 'stroke-width': 1.6, 'stroke-linejoin': 'round' }, s);
  return s;
}
/* Hat ein Bauteil Masse (in irgendeiner Bauform)? Legende der Buchstaben fuer den Druck */
function hatMasse(pid) {
  var S = SYM[pid]; if (!S) { return false; }
  var n = 1 + (S.v || []).length, ja = false;
  for (var v = 0; v !== n; v++) { var E = teilErfassen(pid, v); if (E ? (E.ms || []).length : false) { ja = true; break; } }
  return ja;
}
function masseLegende(pid, T) {
  var vi = T ? (T.info().vi || 0) : 0, E = teilErfassen(T ? T.pid() : pid, vi), L = [];
  each((E ? E.ms : null) || [], function (m) { if (m.n) { var s = m.t + ' ' + m.n; if (L.indexOf(s) === -1) { L.push(s); } } });
  var k = KATV[pid] ? KATV[pid].id : '';
  return L.length ? 'Maße: ' + L.join(', ') + ((k === 'formeckig' || k === 'kanal') ? ' (Buchstaben wie in DIN 18379, Tabelle 2)' : '') : '';
}
/* Werkzeuge im Fenster der Kartei: Masse ein und aus (nur mit Massen), Drucken */
function karteiWerkzeuge(bild, o) {
  var wk = ht('div', 'wsy-wk', null, bild), bM = null, bZ = [];
  /* Lupe minus und plus (Dimi 11.11.2026, 07:54): das Mausrad scrollt die Seite, gezoomt wird mit Strg + Rad oder hier;
     nur sichtbar, solange das 3D-Modell steht */
  if (o.zoom) {
    each([false, true], function (plus) {
      var z = ht('button', 'wsy-wb', null, wk); z.type = 'button'; z.hidden = true; zoomIcon(z, plus);
      z.title = plus ? 'Vergrößern' : 'Verkleinern'; z.setAttribute('aria-label', z.title);
      z.addEventListener('click', function (ev) { ev.stopPropagation(); var T = o.zoom(); if (T) { T.zoom(plus ? 1.3 : 1 / 1.3); } });
      bZ.push(z);
    });
  }
  if (o.masse) {
    bM = ht('button', 'wsy-wb', null, wk); bM.type = 'button'; bM.hidden = true;
    var ms = sv('svg', { viewBox: '0 0 20 20', 'aria-hidden': 'true', focusable: 'false', 'class': 'wdk-ic' }, bM);
    sv('path', { d: 'M2 14 H18 M2 11 V17 M18 11 V17 M5 14 L2 14 M15 14 L18 14 M6 12 L2 14 L6 16 M14 12 L18 14 L14 16', fill: 'none', stroke: 'currentColor', 'stroke-width': 1.5, 'stroke-linejoin': 'round', 'stroke-linecap': 'round' }, ms);
    bM.title = 'Maße mit Buchstaben ein- und ausblenden'; bM.setAttribute('aria-label', 'Maße');
    bM.addEventListener('click', function (ev) { ev.stopPropagation(); var T = o.masse(); if (!T) { return; } T.masse(!MASSE_AN); mStand(); });
  }
  function mStand() { if (!bM) { return; } bM.classList.toggle('on', MASSE_AN); bM.setAttribute('aria-pressed', MASSE_AN ? 'true' : 'false'); }
  var bD = ht('button', 'wsy-wb', null, wk); bD.type = 'button'; druckIcon(bD);
  bD.title = 'Ansicht drucken oder als PDF speichern'; bD.setAttribute('aria-label', 'Drucken');
  bD.addEventListener('click', function (ev) { ev.stopPropagation(); o.druck(); });
  mStand();
  return {
    zeigeMasse: function (ja) { if (bM) { bM.hidden = !ja; mStand(); } },
    zeigeZoom: function (ja) { each(bZ, function (z) { z.hidden = !ja; }); }
  };
}
/* Fenster der Kartei „Alle …“ (Runde 10 der Szene, Dimi 09.11.2026, Runde 11 Punkt 16): die Bauteile der Kategorie im Wechsel
   (4,2 s je Bauteil, weich nacheinander), oben links der Name. Zeigen mit der Maus haelt an, Drehen haelt bis zum Zuruecksetzen.
   element(eid): Bereiche dieses Elements im gezeigten Bauteil hervorheben (Zeile der Tabelle). */
var ALLE_MS = 4200;
function alleSymbol(info, k, o) {
  o = o || {};
  var teile = k.teile.filter(function (p) { return !!symbolBauen(p); });
  if (!teile.length) { return null; }
  var tok = SYMTOK, wrap = ht('div', 'wsy wsy-alle', null, info), bild = ht('div', 'wsy-bild', null, wrap);
  fensterZiehen(bild);
  var cap = ht('div', 'wsy-cap', null, bild);
  ht('div', 'wsy-ber', null, wrap);
  if (o.txt) { wrap.appendChild(o.txt); }
  /* Runde 13 der Szene (Dimi 10.11.2026): einmal durch alle Bauteile, danach bleibt das erste stehen */
  var i = 0, svg = null, T = null, T3W = null, tm = null, halt = {}, eid = null, fertig = false;
  var WKA = karteiWerkzeuge(bild, {
    zoom: function () { return T; },
    druck: function () {
      var p = teile[i];
      function weiter(u) { druckSeite({ titel: k.alle.t, unter: 'Im Bild: ' + kurzName(BT[p]), bild: u, svg: u ? null : svg, text: k.alle.txt || '', zeilen: ['Bauteile: ' + teile.map(function (x) { return kurzName(BT[x]); }).join(', ')] }); }
      if (T) { T.bild(weiter); } else { weiter(''); }
    }
  });
  function zeichne2d(p) { if (svg) { if (svg.parentNode) { svg.parentNode.removeChild(svg); } } svg = symbolSvg(symbolBauen(p), BT[p]); bild.insertBefore(svg, cap); }
  zeichne2d(teile[0]); cap.textContent = kurzName(BT[teile[0]]);
  function ks(p) { var r = []; if (!eid) { return r; } each((DATA.bel || {})[p] || [], function (e, j) { if (e === eid) { r.push(j); } }); return r; }
  function zeig(j) {
    i = j; var p = teile[i];
    cap.classList.add('aus');
    window.setTimeout(function () { cap.textContent = kurzName(BT[p]); cap.classList.remove('aus'); }, 450);
    if (T) { T.teil(p, 0, true, function () { if (T) { T.bereich(ks(p)); } }); }
    else { zeichne2d(p); bereichSetzen(svg, ks(p)); }
  }
  function grund() { for (var g in halt) { if (halt[g]) { return true; } } return false; }
  function plan() {
    if (tm) { window.clearTimeout(tm); tm = null; }
    if (!BEWEGUNG) { return; } if (grund()) { return; } if (lt(teile.length, 2)) { return; } if (fertig) { if (i === 0) { return; } }
    tm = window.setTimeout(function () {
      tm = null; if (tok !== SYMTOK) { return; } if (!wrap.isConnected) { return; }
      if (fertig) { zeig(0); return; }
      zeig((i + 1) % teile.length); if (i === 0) { fertig = true; return; } plan();
    }, ALLE_MS);
  }
  bild.addEventListener('mouseenter', function () { halt.z = true; plan(); });
  bild.addEventListener('mouseleave', function () { halt.z = false; plan(); });
  function start3d() {
    T3W = null;
    if (T) { return; } if (tok !== SYMTOK) { return; } if (!svg.isConnected) { return; } if (!dreiMoeglich()) { return; }
    T = teil3d(bild, teile[i], 0, { svg: svg, weg: function () { T = null; WKA.zeigeZoom(false); }, beruehrt: function () { halt.d = true; plan(); } });
    if (T) { T.bereich(ks(teile[i])); bild.appendChild(cap); bild.appendChild(bild.querySelector('.wsy-wk')); WKA.zeigeZoom(true); }
  }
  plan();
  return {
    an: function () { }, ab: function () { }, zeilen: function () { },
    start3d: function (ms) { if (T3W) { window.clearTimeout(T3W); T3W = null; } if (lt(ms || 0, 0)) { start3d(); return; } T3W = window.setTimeout(start3d, ms || 0); },
    zurueck: function () { halt.d = false; if (T) { T.zurueck(); } plan(); },
    zu: function () { if (tm) { window.clearTimeout(tm); tm = null; } if (T3W) { window.clearTimeout(T3W); T3W = null; } if (T) { var t = T; T = null; t.zu(); } },
    drei: function () { return T; },
    element: function (e) { eid = e; halt.e = !!e; plan(); if (T) { T.bereich(ks(teile[i])); } else if (svg) { bereichSetzen(svg, ks(teile[i])); } },
    teil: function () { return teile[i]; }
  };
}
/* ---------- Schutz gegen die Seitenvorlage (Dimi 12.11.2026) ----------
   Die Vorlage der Website (Composite, reset.less und global.less) gestaltet Elemente direkt, z. B.
   button{float:left;height:34px;text-transform:uppercase}, button:hover{background:#777}, *{box-sizing:border-box},
   div{font:inherit} und h3{margin-bottom:30px}. Ohne Schutz rutscht die Kartei aus dem Bild (schwebender Balken),
   Texte stehen in Grossbuchstaben und Knoepfe werden beim Zeigen grau.
   1. VORLAGE_ZURUECK setzt die Elemente der Szene auf die Werte des Browsers zurueck, wie in der Vorschau ohne Vorlage.
   2. regelnStaerken gibt jeder Regel der Szene dieselbe Zusatz-Gewichtung (:not(#wsz-v) davor). So gilt die Szene stets
      vor der Vorlage, auch vor deren :hover-Regeln; die Reihenfolge der Regeln der Szene untereinander bleibt gleich. */
/* Der Rohr-Rechner (.wmr) in der Szene ist fuer die Vorlage gebaut und bleibt davon ausgenommen. */
var VORLAGE_ZURUECK = '.wsz{line-height:normal}' +
  ':where(.wsz),:where(.wsz) :where(:not(.wmr,.wmr *)),:where(.wsz) :where(:not(.wmr,.wmr *))::before,:where(.wsz) :where(:not(.wmr,.wmr *))::after{box-sizing:content-box}' +
  ':where(.wsz) :is(button,input,textarea,select,h1,h2,h3,h4,h5,h6,b,strong,small,a):where(:not(.wmr *)){all:revert}';
function selTeilen(s) {
  var t = [], d = 0, a = 0, i, c;
  for (i = 0; i !== s.length; i++) {
    c = s.charAt(i);
    if (c === '(' || c === '[') { d++; } else if (c === ')' || c === ']') { d--; } else if (c === ',') { if (d === 0) { t.push(s.slice(a, i)); a = i + 1; } }
  }
  t.push(s.slice(a));
  return t;
}
function regelnStaerken(liste) {
  var i, j, r, t;
  for (i = 0; i !== liste.length; i++) {
    r = liste[i];
    if (typeof r.selectorText === 'string') {
      t = selTeilen(r.selectorText);
      for (j = 0; j !== t.length; j++) { t[j] = ':not(#wsz-v) ' + t[j].replace(/^\s+|\s+$/g, ''); }
      try { r.selectorText = t.join(','); } catch (e) { }
    }
    if (r.cssRules) { if (r.type !== 7) { regelnStaerken(r.cssRules); } }
  }
}
function stilEinsetzen(id, text) {
  var st = document.createElement('style'); st.id = id; st.textContent = text; document.head.appendChild(st);
  try { if (st.sheet) { regelnStaerken(st.sheet.cssRules); } } catch (e) { }
  return st;
}
function cssEinmal() {
  if (document.getElementById('wsz-css')) { return; }
  stilEinsetzen('wsz-css', VORLAGE_ZURUECK + CSS + CSSD + CSS3 + CSSK + CSSM + CSSV + CSSW + CSSE + CSSRR + CSSVB + CSSST + pcssAlle());
}
/* ---------- Kartei-Kopf in fester Hoehe (Runde 17, Dimi 11.11.2026, 16:23) ----------
   Drei Spalten: 3D mit Nummern, Text, Formstueck-Kacheln. Langer Text wird kleiner, bis er passt; die Kacheln schrumpfen bis zu einer
   kleinsten Groesse, damit alle in die Spalte passen. Am Handy untereinander, ohne Einpassen. */
function kopfMobil() { try { return window.matchMedia ? window.matchMedia('(max-width:900px)').matches : false; } catch (e) { return false; } }
function txtPassen(t) {
  var h3 = t.querySelector('h3'), ps = [];
  each(t.querySelectorAll('.wkp-tx'), function (x) { ps.push(x); });
  if (h3) { h3.style.fontSize = ''; h3.style.lineHeight = ''; }
  each(ps, function (x) { x.style.fontSize = ''; x.style.lineHeight = ''; });
  t.style.overflowY = '';
  if (kopfMobil()) { return; }
  var f = 14, fh = 20, n = 0;
  function zuViel() { return gt(t.scrollHeight, t.clientHeight + 1); }
  function setz() { each(ps, function (x) { x.style.fontSize = f + 'px'; x.style.lineHeight = Math.round(f * 1.42) + 'px'; }); if (h3) { h3.style.fontSize = fh + 'px'; h3.style.lineHeight = Math.round(fh * 1.25) + 'px'; } }
  setz();
  while (zuViel()) { n++; if (gt(n, 24)) { break; } if (gt(f, 11)) { f -= 0.5; } else if (gt(fh, 16)) { fh -= 1; } else { break; } setz(); }
  t.style.overflowY = zuViel() ? 'auto' : 'hidden';
}
function labelPassen(el) {
  el.style.fontSize = ''; el.style.lineHeight = '';
  var f = parseFloat(window.getComputedStyle(el).fontSize) || 10.5, i = 0;
  function zuViel() { return gt(el.scrollWidth, el.clientWidth + 1) ? true : gt(el.scrollHeight, Math.ceil(f * 1.16 * 2) + 2); }
  while (zuViel()) { if (lt(f, 8.6)) { break; } f -= 0.5; el.style.fontSize = f + 'px'; el.style.lineHeight = (f * 1.16).toFixed(1) + 'px'; i++; if (gt(i, 10)) { break; } }
}
/* Runde 18 (Dimi 11.11.2026, 20:13): drei Kacheln je Reihe; ihre Groesse folgt der Breite (64 bis 96 px), der Text bekommt den Rest */
function kachelnPassen(k) {
  var L = k.querySelector('.wsy-leiste'); if (!L) { return; }
  if (kopfMobil()) { k.style.removeProperty('--kw'); each(L.querySelectorAll('.wkg-ct'), labelPassen); return; }
  var g = k.parentNode, W = g ? g.clientWidth : 0, bb = g ? g.querySelector('.wsy-bild') : null, bw = bb ? bb.offsetWidth : 176;
  var sp = L.classList.contains('einzeln') ? (parseInt(L.style.getPropertyValue('--sp'), 10) || 6) : 3;
  var w = Math.max(64, Math.min(96, Math.floor((W - bw - 34 - 48 - 300 - 8) / sp)));
  k.style.setProperty('--kw', w + 'px');
  each(L.querySelectorAll('.wkg-ct'), labelPassen);
}
/* Hoehe des Fensters beim Oeffnen: so hoch wie die Kacheln rechts (zwei Reihen), ohne Kacheln 200 px; von Hand gezogen gilt die eigene Hoehe */
function kopfHoehe0(g, k, t) {
  if (WSY_H) { return; }
  if (kopfMobil()) { g.style.removeProperty('--wsy-h'); return; }
  var h = 200;
  if (k) { var h0 = k.style.height; k.style.height = 'auto'; h = Math.ceil(k.scrollHeight); k.style.height = h0; }
  /* langer Text (z. B. Schalldaempferkulisse): so hoch, dass er in 13 px passt, hoechstens 340 px */
  if (t) {
    var ht0 = t.style.height, ps = t.querySelectorAll('.wkp-tx');
    each(ps, function (x) { x.style.fontSize = '13px'; x.style.lineHeight = '18px'; });
    t.style.height = 'auto'; var hT = Math.ceil(t.scrollHeight); t.style.height = ht0;
    if (gt(hT, h)) { h = Math.min(340, hT); }
  }
  h = Math.max(200, h);
  if (g.style.getPropertyValue('--wsy-h') !== h + 'px') { g.style.setProperty('--wsy-h', h + 'px'); }
}
function kopfPassen(g) {
  function fit() {
    if (!g.isConnected) { return; }
    var t = g.querySelector('.wsy-txt'), k = g.querySelector('.wsy-kopf');
    if (k) { kachelnPassen(k); }
    kopfHoehe0(g, k, t);
    var bb = g.querySelector('.wsy-bild'); if (bb) { bb.classList.toggle('eng', lt(bb.clientWidth, 300)); }
    if (t) { txtPassen(t); }
  }
  window.requestAnimationFrame(fit);
  if (window.ResizeObserver) {
    var bw = -1, bh = -1;
    new ResizeObserver(function () { var r = g.getBoundingClientRect(); if (Math.round(r.width) === bw) { if (Math.round(r.height) === bh) { return; } } bw = Math.round(r.width); bh = Math.round(r.height); window.requestAnimationFrame(fit); }).observe(g);
  }
}
/* Kachel eines Bauteils: Bauformen laufen einmal durch (beim ersten Sehen und beim Zeigen) und enden in der ersten; die Beschriftung nennt
   nur die gerade gezeigte Bauform (DATA.bfn, Dimi 11.11.2026, 16:23; fehlt dort ein Eintrag: SYM[id].vn aus der Zeichnung) */
function kachelBild(b, ib, ct, knopf) {
  var V = symbolVarianten(b.id), N = V ? V.length : 1, namen = (DATA.bfn || {})[b.id] || (SYM[b.id] || {}).vn || [];
  /* Runde 18 (Dimi 11.11.2026, Prüfliste 21.4): feste Beschriftung statt der wechselnden Bauform (z. B. „Gepresst“, DATA.kna) */
  var fest = (DATA.kna || {})[b.id] || '';
  function name(i) { return fest || namen[i] || kurzName(b); }
  ct.textContent = trennen(name(0));
  if (lt(N, 2)) { symbolBild(b, ib, true); return; }
  ib.classList.add('wkg-vs');
  var bs = [];
  for (var i = 0; i !== N; i++) { var sp = ht('span', 'wkg-v' + (i === 0 ? ' auf' : ''), null, ib); bs.push(sp); }
  /* Bilder erst bauen, wenn die Flaeche ihre Groesse hat (Seitenverhaeltnis) */
  var gebaut = false;
  function bauen() { if (gebaut) { return; } gebaut = true; each(bs, function (sp, j) { symbolBild(b, sp, true, j); }); }
  var j = 0, lauf = false, tm = null;
  function setz(i) { bs[j].classList.remove('auf'); j = i; bs[j].classList.add('auf'); ct.textContent = trennen(name(j)); labelPassen(ct); }
  function einmal() {
    bauen(); if (lauf) { return; } if (!BEWEGUNG) { return; } lauf = true;
    var i = 0;
    function weiter() { tm = null; if (!ib.isConnected) { lauf = false; return; } i++; if (i === N) { setz(0); lauf = false; return; } setz(i); tm = window.setTimeout(weiter, 2600); }
    tm = window.setTimeout(weiter, 2200);
  }
  window.requestAnimationFrame(bauen);
  if (window.IntersectionObserver) {
    var io = new IntersectionObserver(function (es) { each(es, function (e) { if (e.isIntersecting) { io.disconnect(); einmal(); } }); }, { threshold: 0.6 });
    io.observe(ib);
  }
  if (knopf) { knopf.addEventListener('mouseenter', einmal); }
}
/* Runde 18 (Dimi 11.11.2026, 22:43): Produkt der Kategorie-Kachel wechselt mit der gezeigten Maschine (k.prodVon), Ruhe: k.sym */
function kachelProdukt(k, pb) {
  var ids = [k.sym]; for (var m in k.prodVon) { if (ids.indexOf(k.prodVon[m]) === -1) { ids.push(k.prodVon[m]); } }
  var L = {};
  each(ids, function (p) { var sp = ht('span', 'wsd-pbv' + (p === k.sym ? ' auf' : ''), null, pb); symbolBild(BT[p], sp); L[p] = sp; });
  pb.wProd = function (p) { if (!L[p]) { p = k.sym; } for (var q in L) { L[q].classList.toggle('auf', q === p); } };
  var el = pb.closest ? pb.closest('.wsd-p') : null; if (el ? el.wProdZeig : false) { pb.wProd(el.wProdZeig); }
}
/* Bauteil-Symbol als Bild (ein Element statt vieler Pfade) */
function symbolBild(b, el, ruhig, nurV) {
  if (!b) { return; }
  var S = symbolBauen(b.id); if (!S) { return; }
  try {
    /* Runde 11 der Szene (Dimi 10.11.2026, Antworten Runde 12, Punkt 2): jede Bauform fuellt die Flaeche fuer sich (eigene viewBox in einem Rahmen mit dem
       Seitenverhaeltnis der Flaeche), damit z. B. Etagenstueck oder 45°-Bogen nicht klein in der Ecke stehen */
    var A = 1.43; try { var rr = el.getBoundingClientRect(); if (gt(rr.width, 20)) { if (gt(rr.height, 20)) { A = rr.width / rr.height; } } } catch (e0) { }
    var box = [0, 0, Math.round(1000 * A), 1000];
    var s = sv('svg', { viewBox: box.join(' ') }), V = symbolVarianten(b.id) || [S];
    /* ruhig: kleine Symbole ohne Wechselbild, nur die erste Bauform; nurV: nur diese Bauform (Kachel der Leiste, Runde 17) */
    if (nurV !== undefined) { V = [V[nurV] || V[0]]; S = V[0]; } else if (ruhig) { V = [V[0]]; }
    muster(s);
    if (gt(V.length, 1)) { variantenZeichnen(s, V, false, box); } else {
      var s2 = sv('svg', { x: 0, y: 0, width: box[2], height: box[3], viewBox: S.vb.map(f1).join(' '), overflow: 'visible' }, s);
      zeichneSymbol(sv('g', {}, s2), S.it);
    }
    var gh = (SYM[b.id] || {}).ghost; if (gh !== undefined) { sv('style', {}, s).textContent = '[data-a="' + gh + '"],[data-al="' + gh + '"]{opacity:.3}'; }
    var txt = new XMLSerializer().serializeToString(s);
    var url = URL.createObjectURL(new Blob([txt], { type: 'image/svg+xml' }));
    var im = ht('img', null, null, el); im.alt = ''; im.src = url;
  } catch (e) { }
}
/* Hinweis hinter einem i (Dimi 09.11.2026): Bedienhinweise und Erklaerungen stehen nicht mehr im Text, sondern
   erscheinen beim Zeigen, beim Fokus oder beim Antippen. o.oben: Blase oeffnet nach oben; o.links: am linken Rand */
var WSI_N = 0;
function infoKnopf(par, text, o) {
  o = o || {};
  var w = ht('span', 'wsi-w' + (o.oben ? ' oben' : '') + (o.links ? ' links' : '') + (o.cls ? ' ' + o.cls : ''), null, par);
  var k = ht('button', 'wsi', 'i', w); k.type = 'button';
  var bl = ht('span', 'wsi-b', text, w); bl.id = 'wsi' + (++WSI_N); bl.setAttribute('role', 'tooltip');
  k.setAttribute('aria-label', o.label || 'Hinweis'); k.setAttribute('aria-describedby', bl.id); k.setAttribute('aria-expanded', 'false');
  var fest = false;
  function lage() {
    bl.style.marginLeft = '';
    var r = bl.getBoundingClientRect(), vw = document.documentElement.clientWidth || window.innerWidth;
    if (lt(r.left, 8)) { bl.style.marginLeft = Math.round(8 - r.left) + 'px'; } else if (gt(r.right, vw - 8)) { bl.style.marginLeft = Math.round(vw - 8 - r.right) + 'px'; }
  }
  function an(x) { w.classList.toggle('auf', x); k.setAttribute('aria-expanded', x ? 'true' : 'false'); if (x) { lage(); } }
  w.addEventListener('mouseenter', function () { an(true); });
  w.addEventListener('mouseleave', function () { if (!fest) { an(false); } });
  k.addEventListener('focus', function () { an(true); });
  k.addEventListener('blur', function () { fest = false; an(false); });
  k.addEventListener('click', function (ev) { ev.stopPropagation(); ev.preventDefault(); fest = !fest; an(fest); });
  k.addEventListener('keydown', function (ev) { if (ev.key === 'Escape') { fest = false; an(false); } });
  w.addEventListener('click', function (ev) { ev.stopPropagation(); });
  return w;
}
/* Runde 13 der Szene (Dimi 10.11.2026): reine Anleitungstexte stehen hinter einem i. Der Absatz unter der Ueberschrift der Seite
   (Absatz mit Klasse e oder wms-info vor dem Platzhalter) wandert in den Hinweis an der Ueberschrift (h1 oder h2 davor);
   der Text bleibt im Quelltext der Seite. */
function seitenInfo(box) {
  var p = box.previousElementSibling, h = null;
  while (p) { if (p.tagName === 'P') { if (p.classList.contains('e') || p.classList.contains('wms-info')) { break; } } p = p.previousElementSibling; }
  if (!p) { return; }
  h = p.previousElementSibling;
  while (h) { if (/^H[12]$/.test(h.tagName)) { break; } h = h.previousElementSibling; }
  if (!h) { return; }
  if (h.querySelector('.wsi-w')) { return; }
  var t = (p.textContent || '').replace(/\s+/g, ' ').trim(); if (!t) { return; }
  p.style.display = 'none'; p.setAttribute('data-wms-i', '1');
  infoKnopf(h, t, { label: 'Bedienung', cls: 'wsi-h1' });
}
/* Hoehe der Szene (Dimi 09.11.2026): am Rechner passen Szene und Kachel-Uebersicht zusammen auf einen Bildschirm.
   ah = Hoehe/Breite der Zeichnung; root.wszUeb() misst Ueberschrift und Kachelraster (ohne aufgeklappte Kartei). */
/* Handy-Runde (Dimi 12.11.2026, Prüfliste 25): Handy = grober Zeiger (Finger). Am Rechner aendert sich nichts. */
function handyGrob() { try { return window.matchMedia('(pointer: coarse)').matches; } catch (e) { return false; } }
/* Handy in der schmalen Startseiten-Ansicht (Anlage, Balken und Gruppen untereinander) */
function handySpalte() { try { return handyGrob() ? window.matchMedia('(max-width:999px)').matches : false; } catch (e) { return false; } }
/* Handy-Runde 2 (Dimi 12.11.2026, 09:23): Aufgeklapptes kommt am Handy ins Bild – weich scrollen, bis es oben unter dem Kopf steht */
function handyFokus(el, ms) {
  if (!el) { return; } if (!handyGrob()) { return; }
  window.setTimeout(function () {
    if (!el.isConnected) { return; }
    /* Am Handy faehrt der Kopf beim Scrollen nach unten weg und kommt beim Scrollen nach oben zurueck (Layout 1.37): nach oben den
       ganzen Kopf frei lassen, nach unten nur einen kleinen Rand */
    var r = el.getBoundingClientRect(), hd = document.getElementById('wmlHdr'), hh = hd ? hd.offsetHeight : 0;
    var off = lt(r.top, kopfHoehe() + 10) ? hh + 10 : 10;
    if (!gt(Math.abs(r.top - off), 24)) { return; }
    var y = Math.max(0, r.top + (window.pageYOffset || 0) - off);
    try { window.scrollTo({ top: y, behavior: 'smooth' }); } catch (e) { window.scrollTo(0, y); }
  }, ms === undefined ? 520 : ms);
}
function handyQuer() { var vh = window.innerHeight || 900, vw = window.innerWidth || 1440; return handyGrob() ? (lt(vh, 500) ? gt(vw, vh) : false) : false; }
function szeneHoehe(w, ah, root) {
  var h = w * ah, vh = window.innerHeight || 900;
  /* gezogene Hoehe (Dimi 09.11.2026, Runde 11 Punkt 9): von schmal bis ganzer Bildschirm */
  if (root ? root.wszHU : 0) { return Math.round(Math.max(150, Math.min(root.wszHU, vh - 8))); }
  /* Handy quer (Prüfliste 25.2): die Anlage fuellt die Bildschirmhoehe */
  if (handyQuer()) { return Math.round(Math.max(200, vh - 16)); }
  /* Handy hoch (Prüfliste 25.2): etwa 60 % des Bildschirms */
  if (lt(w, 700) ? handyGrob() : false) { return Math.round(Math.max(200, Math.min(Math.max(w * 1.25, h), vh * 0.62))); }
  /* Startseite (11.11.2026): am Rechner so hoch wie die Gruppenleiste daneben */
  if (root ? root.wszStartH : 0) { return root.wszStartH; }
  if (lt(w, 700)) { return Math.round(Math.max(h, Math.min(w * 0.95, vh * 0.62))); }
  var ueb = (root ? (root.wszUeb ? root.wszUeb() : 0) : 0) || 300;
  return Math.round(Math.min(h, Math.max(400, vh - ueb - 40)));
}
function init(box) {
  if (box.getAttribute('data-wsz-ok')) { return; }
  box.setAttribute('data-wsz-ok', '1');
  cssEinmal();
  VORSCHAU = box.getAttribute('data-vorschau') === '1'; basisSetzen();
  seitenInfo(box);
  var G = bauen(), root = ht('div', 'wsz', null, box);
  if (!root.closest('[lang]')) { root.setAttribute('lang', 'de'); }
  /* Teil d: Suche, Reiter Nach Bauteil und Nach Anwendung */
  /* Runde 12 der Szene (Dimi 10.11.2026): die Suche steht dezent rechts neben den Reitern */
  /* Runde 14 der Szene (Dimi 10.11.2026, Pruefliste 15.7): Reiter „Lüftungsanlage“ und „Fertigungsverfahren“. Strukturvorschau:
     data-variante="B" laesst den zweiten Reiter weg; die Maschinengruppen stehen dann unter der Anlage (variantB) */
  var VAR = box.getAttribute('data-variante') === 'B' ? 'B' : 'A';
  /* Startseite (Dimi 11.11.2026, Abwandlung Vorschlag 1, 4a_start.js): data-modus="start" – Frage als Reiter, daneben das Antwortfeld,
     Ideen und Rohr-Rechner; links die Anlage, rechts die Maschinengruppen, die beim Bedienen der Anlage nach rechts wegfahren */
  var START = box.getAttribute('data-modus') === 'start';
  var rl = ht('div', 'wsd-r', null, root), rlk = ht('div', 'wsd-rk', null, rl), r1 = ht('button', 'on', 'Lüftungsanlage', rlk), r2 = ht('button', null, 'Fertigungsverfahren', rlk);
  if (VAR === 'B') { r2.hidden = true; root.classList.add('wsz-vb'); }
  if (START) { r1.textContent = 'Was möchten Sie fertigen?'; r2.hidden = true; root.classList.add('wsz-start'); }
  /* Runde 13 der Szene (Dimi 10.11.2026): Suche und das Feld „Ideen und Verbesserungen“ stehen wie die Reiter auf der blauen Linie */
  var rf = ht('div', 'wsd-rf', null, rl);
  var SU = sucheBauen(rf, function (pid) { zuBauteil(pid); }, function (vid) { zuVerfahren(vid); });
  feedbackBauen(rf, function () { return root.wszStand ? root.wszStand() : ''; });
  /* Runde 14: Rohr-Rechner (Variante C) neben Suche und Ideen; klappt unter der Leiste auf */
  var rrPlatz = ht('div', 'wsd-rrp', null, root);
  rechnerBauen(rf, rrPlatz, box);
  if (START) { var qi = rf.querySelector('input.wsd-q'); if (qi) { qi.placeholder = 'Ihre Antwort, z. B. Wickelfalzrohr'; qi.setAttribute('aria-label', 'Was möchten Sie fertigen? Ihre Antwort'); } }
  r1.type = 'button'; r2.type = 'button'; rlk.setAttribute('role', 'tablist'); r1.setAttribute('role', 'tab'); r2.setAttribute('role', 'tab');
  if (START) { r1.title = 'Ansicht zurücksetzen'; }
  var t1 = ht('div', 'wsd-t1', null, root), t2 = ht('div', 'wsd-t2', null, root), ANW = null;
  t1.setAttribute('role', 'tabpanel'); t2.setAttribute('role', 'tabpanel'); t2.hidden = true;
  function reiter(i) {
    t1.hidden = i !== 0; t2.hidden = i !== 1;
    r1.classList.toggle('on', i === 0); r2.classList.toggle('on', i === 1);
    r1.setAttribute('aria-selected', i === 0 ? 'true' : 'false'); r2.setAttribute('aria-selected', i === 1 ? 'true' : 'false');
    /* Startseite: „Fertigungsverfahren“ erscheint nur, solange es gezeigt wird (Treffer der Suche) */
    if (START) { r2.hidden = i !== 1; }
    if (i === 1) { if (!ANW) { ANW = anwendungen(t2, function (pid) { zuBauteil(pid); }); } }
  }
  /* Hinweis auf die Reiter (Dimi 09.11.2026, Runde 9: sie gehen unter): beim ersten Sichtbarwerden blinken beide kurz
     abwechselnd, wie der Umschalter am Handy; nicht mehr, sobald ein Reiter benutzt wurde */
  var rlFertig = START;
  function reiterHinweis() {
    if (rlFertig) { return; } rlFertig = true;
    if (!BEWEGUNG) { return; }
    rlk.classList.add('wsd-blink');
    window.setTimeout(function () { rlk.classList.remove('wsd-blink'); }, 2900);
  }
  if (window.IntersectionObserver) {
    var rio = new IntersectionObserver(function (es) { each(es, function (e) { if (e.isIntersecting) { rio.disconnect(); window.setTimeout(reiterHinweis, 700); } }); }, { threshold: 1 });
    rio.observe(rl);
  } else { window.setTimeout(reiterHinweis, 1200); }
  /* zweites Antippen des aktiven Reiters setzt die Ansicht ganz zurueck (Runde 12 der Szene, Dimi 10.11.2026):
     Nach Bauteil: Kartei zu, Anlage aufgeklappt in Ausgangshoehe und Ausgangsblick; Nach Anwendung: Einzelheiten zu */
  function zuruecksetzen(i) {
    tippWeg();
    if (i === 0) {
      if (START) { startZurueck(); return; }
      if (auswahl()) { waehle(null); }
      if (EIN) { einklappen(false); }
      if (root.wszHU) { root.wszHU = 0; hoeheNeu(); }
      if (DV) { if (dvAn) { DV.zurueck(); } }
      zeige(null);
    } else if (ANW) { ANW.zeige(null, false); }
    hinScrollen(rl);
  }
  r1.addEventListener('click', function () { rlFertig = true; if (!t1.hidden) { zuruecksetzen(0); return; } reiter(0); });
  r2.addEventListener('click', function () { rlFertig = true; if (!t2.hidden) { zuruecksetzen(1); return; } reiter(1); });
  reiter(0);
  function zuBauteil(pid) {
    if (!BT[pid]) { return; }
    reiter(0); waehle(pid, null);
    window.setTimeout(function () { hinScrollen(info.parentNode ? info : lei); }, 60);
  }
  /* Kachel antippen: Kartei auf, gleich mit dem ersten Bauteil der Kategorie (Runde 9 der Szene); nochmals antippen: zu */
  function zuKategorie(kid, el) {
    var k = KATID[kid]; if (!k) { return; }
    reiter(0);
    var t = pg ? pg.querySelector('.wsd-p[data-k="' + kid + '"]') : null;
    if (info.parentNode) { if (t) { if (t.classList.contains('on')) { waehle(null); return; } } }
    QUELLE = el || null;
    /* Kachel wird zur Kartei: Lage der Kachel, ihres Bildes und Namens fuer den Uebergang merken */
    QK = t ? { t: t, r: t.getBoundingClientRect(), rn: (t.querySelector('.wsd-pn') || t).getBoundingClientRect() } : null;
    waehleKat(kid);
    /* Handy (Dimi 12.11.2026, 09:23): die aufgeklappte Kartei kommt ins Bild */
    handyFokus(info, 700);
  }
  function zuVerfahren(vid) {
    reiter(1); ANW.zeige(vid, true);
  }
  /* Eingeklappte Anlage (Dimi 09.11.2026: mehr Platz auf dem Schirm): schmale Leiste an Stelle der Buehne */
  var zuL = ht('button', 'wsz-zul', null, t1); zuL.type = 'button'; zuL.hidden = true; zuL.setAttribute('aria-expanded', 'false');
  ht('span', 'wsz-zui', null, zuL); ht('span', null, 'Lüftungsanlage in 3D zeigen', zuL);
  /* Buehne */
  var sw = START ? ht('div', 'wsz-sw', null, t1) : null;
  /* Startseite: linke Spalte mit Anlage (in einer Huelle zum Zuklappen), blauem Balken und Bauteil-Kacheln */
  var lc = START ? ht('div', 'wsz-stl', null, sw) : null, bw = START ? ht('div', 'wsz-stw', null, lc) : null;
  var bu = ht('div', 'wsz-buehne', null, bw || t1), vb = G.vb.slice();
  /* Startseite: Gruppenleiste rechts neben der Anlage */
  var ST = START ? startGruppen(sw, root, box, function (was) { startZurueck(was); }) : null, STAKTIV = false;
  function startHoehe() {
    var h = ST ? ST.hoehe() : 0;
    /* Hoehe der Gruppenleiste = Hoehe der Anlage mit Rahmen und dem blauen Balken darunter (ST_BALKEN) */
    root.style.setProperty('--sth', h ? (h + 2 + ST_BALKEN) + 'px' : 'auto');
    if (h !== (root.wszStartH || 0)) { root.wszStartH = h; return true; } return false;
  }
  if (ST) { startHoehe(); window.addEventListener('resize', function () { if (startHoehe()) { hoeheNeu(); } }); }
  /* Im Bild oben links: Legende der Luftarten. Die Luftstroemung zeigt sich nur, solange die Maus auf der Anlage ist
     (Dimi 09.11.2026, Runde 9; vorher Schalter mit Dauerbewegung); am Handy beim Beruehren und kurz danach */
  var ol = ht('div', 'wsz-ol', null, bu), maus = true;
  try { maus = window.matchMedia('(hover: hover)').matches; } catch (e) { maus = true; }
  var lk = ht('div', 'wsz-lk', null, ol); ht('span', null, 'Luftströmung', lk);
  /* Handy-Runde (Prüfliste 25.2): am Handy steht nur „Luftströmung“; Antippen zeigt die Farben (am Rechner ohne Wirkung) */
  lk.addEventListener('click', function (ev) { if (ev.target.closest ? ev.target.closest('.wsi-w') : false) { return; } if (handyGrob()) { ol.classList.toggle('wsz-lgauf'); } });
  infoKnopf(lk, (maus ? 'Maus auf die Anlage: ' : 'Anlage berühren: ') + 'die Luft strömt in den Farben der Luftarten. Bauteil anklicken: Fertigungsweg und Maschinen.', { label: 'Luftströmung', links: true, cls: 'wsi-k' });
  root.classList.add('wsz-lf0'); root.classList.add('wsz-lfx');
  var lgs = ht('div', 'wsz-lgs', null, ol);
  each(['ODA', 'SUP', 'ETA', 'EHA'], function (k) { var s = ht('span', 'wsz-lg', null, lgs); var i = ht('i', null, null, s); i.style.background = LUFT[k].c; ht('span', null, LUFT[k].de, s); ht('b', null, k, s); });
  /* Oben rechts: einklappen; der Umschalter Isometrisch | 3D bleibt unsichtbar fuer die Umschaltlogik */
  var kn = ht('div', 'wsz-kn', null, bu);
  var md = ht('div', 'wsz-mod', null, kn), bI = ht('button', 'an', 'Isometrisch', md), b3 = ht('button', null, '3D', md);
  bI.type = 'button'; b3.type = 'button'; md.setAttribute('role', 'group'); md.setAttribute('aria-label', 'Darstellung');
  bI.setAttribute('aria-pressed', 'true'); b3.setAttribute('aria-pressed', 'false'); b3.title = '3D-Ansicht: drehen und zoomen';
  if (!dreiMoeglich()) { b3.disabled = true; b3.title = 'Die 3D-Ansicht wird von diesem Browser nicht unterstützt'; }
  /* Nur noch 3D (Dimi 09.11.2026): kein Umschalter; die isometrische Zeichnung bleibt als Rueckfall ohne WebGL 2 und
     ist bis zum Aufbau der 3D-Ansicht zu sehen (gleiche Ausgangslage). data-ansicht="iso" im Platzhalter behaelt die Zeichnung. */
  md.hidden = true;
  /* Drucken der Szene (Dimi 09.11.2026, Runde 11 Punkt 10): markiertes Bauteil aus der gewaehlten Perspektive */
  var bDr = ht('button', 'wsz-ek wsz-dr', null, kn); bDr.type = 'button'; bDr.title = 'Ansicht drucken oder als PDF speichern';
  druckIcon(bDr); bDr.setAttribute('aria-label', 'Drucken');
  bDr.addEventListener('click', function () {
    var s0 = auswahl(), unter = 'Gesamtansicht';
    if (s0) { if (Array.isArray(s0)) { var kk = KATV[s0[0]]; unter = 'Markiert: ' + (kk ? (kk.alle ? kk.alle.t : kk.t) : ''); } else { unter = 'Markiert: ' + BT[s0].t; } }
    var u = dvAn ? DV.bild() : '';
    druckSeite({ titel: 'Lüftungsanlage', unter: unter, bild: u, svg: u ? null : s1 });
  });
  var bE = ht('button', 'wsz-ek', null, kn); bE.type = 'button'; bE.title = 'Anlage einklappen'; bE.setAttribute('aria-expanded', 'true');
  if (START) { bE.hidden = true; }
  ht('span', 'wsz-zui', null, bE); bE.setAttribute('aria-label', 'Anlage einklappen');
  var s1 = sv('svg', { viewBox: vb.join(' '), role: 'img', 'aria-label': 'Isometrische Darstellung einer Lüftungsanlage mit Zentralgerät, Kanalnetz und Formstücken' }, bu);
  muster(s1);
  var base = sv('g', { 'class': 'wsz-base' }, s1), hl = sv('g', { 'class': 'wsz-hl' }, s1);
  zeichneBasis(base, G.it);
  var s2 = sv('svg', { viewBox: vb.join(' '), 'class': 'wsz-ov', 'aria-hidden': 'true' }, bu);
  zeichneLuft(s2, G.fl);
  zeichneMarken(s2, G.mk);
  each(G.zo, function (z) { var q = PX(z.p), t = sv('text', { x: f1(q[0]), y: f1(q[1] + 12), 'text-anchor': z.an, 'font-size': 9, fill: '#7B8796', 'font-weight': 700, 'letter-spacing': 0.6, 'font-family': 'Arial, Helvetica, sans-serif', 'class': 'wsz-zo' }, s2); t.textContent = z.s.toUpperCase(); });
  /* Startseite (Dimi 11.11.2026, 07:54): blauer Balken unter der Anlage; Pfeil nach oben klappt sie zu, die Bauteil-Kacheln kommen an
     ihre Stelle, der Balken wandert nach oben und sein Pfeil dreht sich; nochmal Antippen zeigt die Anlage wieder */
  var stB = null;
  if (START) {
    stB = ht('button', 'wsz-stb', null, lc); stB.type = 'button'; stB.setAttribute('aria-expanded', 'true');
    var stP = sv('svg', { viewBox: '0 0 28 16', 'aria-hidden': 'true', focusable: 'false', 'class': 'wsz-stbp' }, stB);
    sv('path', { d: 'M4 12 L14 4 L24 12', fill: 'none', stroke: 'currentColor', 'stroke-width': 2.6, 'stroke-linecap': 'round', 'stroke-linejoin': 'round' }, stP);
  }
  var tip = ht('div', 'wsz-tip', null, bu), liste = ht('div', 'wsd-pk', null, lc || t1), pg = null;
  /* Startseite: Bauteil-Kacheln erst, wenn die Anlage bedient wird */
  if (START) { liste.classList.add('wsz-stzu'); }
  function startAktiv() {
    if (!START) { return; } if (STAKTIV) { return; } STAKTIV = true;
    root.classList.add('wsz-stan'); liste.classList.remove('wsz-stzu');
    if (ST) { ST.aus(); }
  }
  /* Anlage zu- und aufklappen (Balken unter der Anlage); die 3D-Ansicht ruht, solange sie zu ist */
  var STZU = false, STZT = null;
  function stBText() { var t = STZU ? 'Anlage zeigen' : 'Anlage zuklappen, Bauteile zeigen'; stB.title = t; stB.setAttribute('aria-label', t); stB.setAttribute('aria-expanded', STZU ? 'false' : 'true'); stB.setAttribute('data-t', STZU ? 'Anlage zeigen' : 'Anlage ausblenden'); }
  function szeneZu(z) {
    if (!START) { return; } z = !!z; if (z === STZU) { return; }
    STZU = z; root.classList.toggle('wsz-stzk', z); stBText();
    if (STZT) { window.clearTimeout(STZT); STZT = null; }
    tip.style.display = 'none'; tippWeg();
    try { bw.inert = z; } catch (e) { }
    bw.setAttribute('aria-hidden', z ? 'true' : 'false');
    var weich = BEWEGUNG, h0 = bw.offsetHeight;
    if (z) {
      /* Dimi 11.11.2026, 10:32: Zuklappen zaehlt als Bedienen – die Gruppenleiste faehrt wie beim Klick in die Anlage weg
         (kleine Kacheln und Streifen bleiben), die beiden Bereiche ueberlappen sich nie */
      startAktiv();
      liste.classList.remove('wsz-stzu');
      if (weich) { liste.classList.remove('wsz-stin'); void liste.offsetWidth; liste.classList.add('wsz-stin'); }
      if (!weich) { bw.style.height = '0px'; if (dvAn) { DV.aus(); } return; }
      bw.style.transition = 'none'; bw.style.height = h0 + 'px'; bw.getBoundingClientRect();
      bw.style.transition = 'height .45s cubic-bezier(.4,0,.2,1)'; bw.style.height = '0px';
      STZT = window.setTimeout(function () {
        STZT = null; if (!STZU) { return; } if (dvAn) { DV.aus(); }
        /* der Balken wandert nach oben: ist er dabei aus dem Bild geraten, dorthin blaettern */
        var rb = stB.getBoundingClientRect(); if (lt(rb.top, kopfHoehe())) { hinScrollen(stB); }
      }, 480);
      return;
    }
    liste.classList.remove('wsz-stin');
    if (dvAn) { DV.an(null); }
    bw.style.transition = 'none'; bw.style.height = ''; var h1 = bw.offsetHeight;
    if (!weich) { if (!STAKTIV) { liste.classList.add('wsz-stzu'); } return; }
    bw.style.height = '0px'; bw.getBoundingClientRect();
    bw.style.transition = 'height .45s cubic-bezier(.4,0,.2,1)'; bw.style.height = h1 + 'px';
    STZT = window.setTimeout(function () { STZT = null; if (!STZU) { bw.style.height = ''; bw.style.transition = ''; if (!STAKTIV) { liste.classList.add('wsz-stzu'); } } }, 480);
  }
  if (stB) {
    stBText();
    stB.addEventListener('click', function () {
      var zu = !STZU; szeneZu(zu);
      /* Handy (Dimi 12.11.2026, 09:23): Anlage auf heisst Gruppen zu; das Aufgeklappte kommt ins Bild */
      if (handySpalte()) { if (zu) { handyFokus(stB); } else { startAktiv(); handyFokus(bw); } }
    });
  }
  root.wszSzeneZu = function (z) { if (z !== undefined) { szeneZu(z); } return STZU; };
  /* Balken oder Frage-Reiter: Leiste zurueck, Kartei zu, Anlage in der Ausgangslage */
  function startZurueck(was) {
    if (!START) { return; }
    tippWeg();
    /* Handy (Dimi 12.11.2026, 09:23): „Produktgruppen zeigen“ klappt die Anlage zu und die Bauteil-Kacheln weg, damit es uebersichtlich
       bleibt; die Gruppen kommen ins Bild. Der Frage-Reiter setzt weiter alles zurueck. */
    if (was === 'gruppen' ? handySpalte() : false) {
      if (auswahl()) { waehle(null); } zeige(null); tip.style.display = 'none';
      if (!STZU) { szeneZu(true); }
      STAKTIV = false; root.classList.remove('wsz-stan'); liste.classList.add('wsz-stzu');
      if (ST) { ST.ein(); }
      handyFokus(stB);
      return;
    }
    if (STZU) { szeneZu(false); }
    if (auswahl()) { waehle(null); }
    /* Ausgangsansicht erst, wenn die Leiste wieder steht (die Breite der Anlage aendert sich bis dahin) */
    if (DV) { if (dvAn) { if (ST ? ST.istAus() : false) { window.setTimeout(function () { if (!STAKTIV) { if (dvAn) { DV.zurueck(); } } }, BEWEGUNG ? 600 : 0); } else { DV.zurueck(); } } }
    zeige(null); tip.style.display = 'none';
    STAKTIV = false; root.classList.remove('wsz-stan'); liste.classList.add('wsz-stzu');
    if (ST) { ST.ein(); }
    var rr = rl.getBoundingClientRect(); if (lt(rr.top, kopfHoehe())) { hinScrollen(rl); }
  }
  if (START) {
    /* Bedienen der Anlage: Klick oder Ziehen in der Zeichnung bzw. 3D-Ansicht, Zoomen mit Strg und Rad, Pfeiltasten */
    var stFrei = function (t) { return t ? (t.closest ? !t.closest('.wsz-ol, .wsz-dr, .wsz-zg, .wsz-mehr, .wsz-schem') : true) : false; };
    /* erst nach dem Loslassen (Blase): das angeklickte Bauteil ist dann schon gewaehlt, die Buehne waechst erst danach */
    bu.addEventListener('pointerup', function (ev) { if (stFrei(ev.target)) { startAktiv(); } });
    /* Zoomen mit dem Rad (70_drei.js meldet wszzoom) zaehlt als Bedienen (Dimi 11.11.2026, 10:32: ohne Zusatztaste) */
    bu.addEventListener('wszzoom', function () { startAktiv(); });
    bu.addEventListener('keydown', function (ev) { if (ev.target ? ev.target.tagName === 'CANVAS' : false) { startAktiv(); } }, true);
  }
  /* Runde 13 der Szene (Dimi 10.11.2026): Hinweis zur Darstellung */
  ht('div', 'wsz-schem', 'Schematische Darstellung, Maße beispielhaft', bu);
  /* Hoehe der Szene ziehen (Dimi 09.11.2026, Runde 11 Punkt 9): von schmal bis ganzer Bildschirm; Doppelklick setzt zurueck */
  var zg = ht('div', 'wsz-zg', null, bu); ht('span', null, null, zg);
  zg.setAttribute('role', 'separator'); zg.setAttribute('aria-orientation', 'horizontal'); zg.setAttribute('tabindex', '0');
  zg.setAttribute('aria-label', 'Höhe der Anlage ändern'); zg.title = 'Ziehen: Höhe der Anlage ändern · Doppelklick: zurücksetzen';
  var zgS = null;
  function hoeheNeu() { isoGroesse(); if (DV) { if (dvAn) { DV.neu(); } } }
  /* Handy-Runde (Prüfliste 25.2): am Handy hoch steht die Anlage fast randlos (8 px zum Bildschirmrand) */
  var randEl = bw || bu;
  function randHandy() {
    if (lt(window.innerWidth || 1440, 700) ? !handyGrob() : true) { if (randEl.classList.contains('wsz-rand')) { randEl.classList.remove('wsz-rand'); randEl.style.removeProperty('--wszRl'); randEl.style.removeProperty('--wszRr'); } return; }
    randEl.classList.remove('wsz-rand');
    var r = randEl.getBoundingClientRect(), vw = document.documentElement.clientWidth || window.innerWidth;
    randEl.style.setProperty('--wszRl', Math.max(0, Math.round(r.left) - 8) + 'px');
    randEl.style.setProperty('--wszRr', Math.max(0, Math.round(vw - r.right) - 8) + 'px');
    randEl.classList.add('wsz-rand');
  }
  function randNeu() { var v = randEl.getBoundingClientRect().width; randHandy(); if (Math.round(randEl.getBoundingClientRect().width) !== Math.round(v)) { hoeheNeu(); } }
  /* erst messen, wenn die Seite steht (beim Aufbau liegt die Anlage noch nicht an ihrem Platz) */
  window.requestAnimationFrame(randNeu); window.setTimeout(randNeu, 400); window.setTimeout(randNeu, 1500);
  window.addEventListener('resize', randNeu);
  function hoeheSetzen(h) { root.wszHU = Math.max(150, Math.min(h, (window.innerHeight || 900) - 8)); hoeheNeu(); }
  zg.addEventListener('pointerdown', function (ev) { ev.preventDefault(); ev.stopPropagation(); try { zg.setPointerCapture(ev.pointerId); } catch (e) { } zgS = { y: ev.clientY, h: bu.getBoundingClientRect().height }; zg.classList.add('an'); });
  zg.addEventListener('pointermove', function (ev) { if (!zgS) { return; } hoeheSetzen(zgS.h + (ev.clientY - zgS.y)); });
  function zgEnde() { zgS = null; zg.classList.remove('an'); }
  zg.addEventListener('pointerup', zgEnde); zg.addEventListener('pointercancel', zgEnde);
  zg.addEventListener('dblclick', function () { root.wszHU = 0; hoeheNeu(); });
  zg.addEventListener('keydown', function (ev) { if (ev.key === 'ArrowUp' || ev.key === 'ArrowDown') { ev.preventDefault(); hoeheSetzen(bu.getBoundingClientRect().height + (ev.key === 'ArrowDown' ? 40 : -40)); } });
  /* Kartei (Dimi 09.11.2026): klappt im Kachelraster unter der Zeile der gewaehlten Gruppe auf */
  var info = document.createElement('div'); info.className = 'wsz-info';
  /* Hinweis in der Zeichnung: fuehrt zur aufgeklappten Kartei */
  var mehr = ht('button', 'wsz-mehr', null, bu); mehr.type = 'button'; mehr.hidden = true;
  mehr.addEventListener('click', function () { if (info.parentNode) { hinScrollen(info); } });
  var QUELLE = null, QK = null;
  bewegungPruefen();
  var aktiv = null, sel = null, selS = null, offen = false, DV = null, dvAn = false;
  function ovs() { return DV ? [s2, DV.ov] : [s2]; }
  /* Hervorheben: ein Bauteil (pid) oder eine Gruppe (Liste von pids) */
  function zeige(pid) {
    var key = pid ? (Array.isArray(pid) ? pid.join(',') : pid) : pid;
    if (key === aktiv) { return; }
    aktiv = key; while (hl.firstChild) { hl.removeChild(hl.firstChild); }
    each(ovs(), function (o) { each(o.querySelectorAll('.wsz-flg.on'), function (e) { e.classList.remove('on'); }); });
    if (dvAn) { DV.zeige(pid); }
    if (!pid) { root.classList.remove('wsz-h'); return; }
    var ps = Array.isArray(pid) ? pid : [pid];
    if (dvAn) { root.classList.add('wsz-h'); each(ps, function (x) { each(DV.ov.querySelectorAll('[data-p="' + x + '"]'), function (e) { e.classList.add('on'); }); }); return; }
    var gs = {}, liste2 = [];
    each(ps, function (x) {
      var q = base.querySelectorAll('[data-p="' + x + '"]');
      for (var i = 0; i !== q.length; i++) {
        if (q[i].classList.contains('wsz-oe')) { continue; }
        var gi = q[i].getAttribute('data-g'), g = gs[gi];
        if (!g) { g = gs[gi] = sv('g', {}, hl); liste2.push(g); }
        g.appendChild(q[i].cloneNode(true));
      }
      each(s2.querySelectorAll('[data-p="' + x + '"]'), function (e) { e.classList.add('on'); });
    });
    root.classList.add('wsz-h');
    var kl = ps.length === 1 ? (BT[ps[0]] ? BT[ps[0]].klick === 'ja' : false) : true;
    window.requestAnimationFrame(function () { each(liste2, function (g) { g.style.transform = 'scale(' + (kl ? (ps.length === 1 ? 1.07 : 1.04) : 1.03) + ')'; }); });
  }
  /* aktuelle Auswahl: Bauteil oder alle Bauteile der gewaehlten Gruppe */
  function auswahl() { return sel; }
  /* Hinweis beim Zeigen: Inhalt nur neu, wenn das Bauteil wechselt (sonst nur die Lage) */
  var tipPid = null;
  function tipp(pid, ev) {
    if (!pid) { tip.style.display = 'none'; return; }
    var b = BT[pid]; if (!b) { tip.style.display = 'none'; return; }
    /* Runde 14: nur der Name, fest unten rechts (keine Bedientexte, kein Fenster am Zeiger) */
    if (pid !== tipPid) { tipPid = pid; tip.textContent = b.t + (b.klick === 'bald' ? ' · in Arbeit' : (b.klick !== 'ja' ? ' · Zukauf' : '')); }
    tip.style.display = 'block';
  }
  function pidAus(ev) {
    var t = ev.target; if (!t || !t.getAttribute) { return null; }
    var p = t.getAttribute('data-p');
    if (!p) { return null; }
    if (BAU.indexOf(p) !== -1) { return null; }
    if (!BT[p]) { return null; }
    return p;
  }
  /* Zeigen hebt nicht mehr hervor (Dimi 09.11.2026, Runde 11 Punkt 8), nur der Hinweis erscheint; hervorgehoben wird beim Anklicken */
  s1.addEventListener('mousemove', function (ev) { var p = pidAus(ev); s1.style.cursor = p ? (BT[p].klick === 'ja' ? 'pointer' : 'default') : ''; tipp(p, ev); });
  s1.addEventListener('mouseleave', function () { zeige(szene(auswahl())); tip.style.display = 'none'; });
  s1.addEventListener('click', function (ev) {
    var p = pidAus(ev); if (p) { if (BT[p].klick !== 'ja') { return; } }
    var gi = ev.target.getAttribute ? ev.target.getAttribute('data-g') : null;
    if (!p) { if (!auswahl()) { return; } }
    waehle(p === gewaehlt() ? null : p, gi);
  });
  function kulisseAuf(a) { offen = a; root.classList.toggle('wsz-offen', a); if (DV) { DV.offen(a); } }
  /* Luftstroemung ein- und ausblenden; ausgeblendet ruhen die Animationen (display:none) */
  var LFA = false, LFT = null, LFB = null;
  function luft(an) {
    an = !!an; if (an === LFA) { return; } LFA = an;
    if (LFT) { window.clearTimeout(LFT); LFT = null; }
    if (an) { root.classList.remove('wsz-lfx'); root.getBoundingClientRect(); root.classList.remove('wsz-lf0'); return; }
    root.classList.add('wsz-lf0');
    LFT = window.setTimeout(function () { LFT = null; if (!LFA) { root.classList.add('wsz-lfx'); } }, 380);
  }
  /* Ruht die Maus 20 s auf der Anlage, hoert die Bewegung auf; die naechste Mausbewegung zeigt sie wieder */
  var LFR = null;
  function luftRuhe() { if (LFR) { window.clearTimeout(LFR); } LFR = window.setTimeout(function () { LFR = null; luft(false); }, 20000); }
  bu.addEventListener('pointerenter', function (ev) { if (ev.pointerType === 'mouse') { luft(true); luftRuhe(); } });
  bu.addEventListener('pointermove', function (ev) { if (ev.pointerType === 'mouse') { if (!LFA) { luft(true); } luftRuhe(); } });
  bu.addEventListener('pointerleave', function (ev) { if (ev.pointerType === 'mouse') { if (LFR) { window.clearTimeout(LFR); LFR = null; } luft(false); } });
  bu.addEventListener('touchstart', function () { if (LFB) { window.clearTimeout(LFB); LFB = null; } luft(true); }, { passive: true });
  bu.addEventListener('touchend', function () { if (LFB) { window.clearTimeout(LFB); } LFB = window.setTimeout(function () { LFB = null; luft(false); }, 4000); }, { passive: true });
  root.wszLuft = luft;
  /* Einklappen: Buehne faehrt zu einer schmalen Leiste zusammen; die 3D-Ansicht ruht solange */
  var EIN = false, EINT = null;
  function einklappen(z) {
    z = !!z; if (z === EIN) { return; }
    EIN = z; root.classList.toggle('wsz-ein', z);
    bE.setAttribute('aria-expanded', z ? 'false' : 'true'); zuL.setAttribute('aria-expanded', z ? 'false' : 'true');
    if (EINT) { window.clearTimeout(EINT); EINT = null; }
    function zu() { if (!EIN) { return; } if (dvAn) { DV.aus(); } bu.hidden = true; bu.style.height = ''; bu.style.transition = ''; zuL.hidden = false; }
    if (z) {
      if (!BEWEGUNG) { zu(); return; }
      bu.style.transition = 'none'; bu.style.height = bu.offsetHeight + 'px'; bu.getBoundingClientRect();
      bu.style.transition = 'height .35s ease'; bu.style.height = '0px';
      EINT = window.setTimeout(zu, 380);
      return;
    }
    zuL.hidden = true; bu.hidden = false;
    if (dvAn) { DV.an(null); }
    if (!BEWEGUNG) { bu.style.height = ''; return; }
    bu.style.transition = 'none'; bu.style.height = ''; var h1 = bu.offsetHeight; bu.style.height = '0px'; bu.getBoundingClientRect();
    bu.style.transition = 'height .35s ease'; bu.style.height = h1 + 'px';
    EINT = window.setTimeout(function () { EINT = null; if (!EIN) { bu.style.height = ''; bu.style.transition = ''; } }, 380);
  }
  bE.addEventListener('click', function () { einklappen(true); });
  zuL.addEventListener('click', function () { einklappen(false); });
  root.wszEinklappen = einklappen;
  /* Zoom */
  var anim = null;
  function zoom(ziel) {
    var von = vb.slice(), t0 = null;
    if (anim) { window.cancelAnimationFrame(anim); }
    function schritt(ts) {
      if (t0 === null) { t0 = ts; }
      var t = Math.min(1, (ts - t0) / 1100), e = lt(t, 0.5) ? 4 * t * t * t : 1 - Math.pow(-2 * t + 2, 3) / 2;
      for (var k = 0; k !== 4; k++) { vb[k] = von[k] + (ziel[k] - von[k]) * e; }
      var s = vb.map(f1).join(' '); s1.setAttribute('viewBox', s); s2.setAttribute('viewBox', s);
      if (lt(t, 1)) { anim = window.requestAnimationFrame(schritt); } else { anim = null; }
    }
    anim = window.requestAnimationFrame(schritt);
  }
  function zielFuer(pid, gi) {
    var b = (gi !== null ? (gi !== undefined ? G.GB[gi] : null) : null), F = G.vb;
    if (!b) {
      each(Array.isArray(pid) ? pid : [pid], function (x) { var q = G.PB[x]; if (!q) { return; } if (!b) { b = q.slice(); return; } b = [Math.min(b[0], q[0]), Math.min(b[1], q[1]), Math.max(b[2], q[2]), Math.max(b[3], q[3])]; });
    }
    if (!b) { return F.slice(); }
    /* Gruppe: knapper Rahmen um alle Teile, nie weiter als die Gesamtansicht */
    var gr = Array.isArray(pid) ? gt(pid.length, 1) : false, fw = gr ? 1.35 : 3, fh = gr ? 1.35 : 2.2;
    var w = Math.max((b[2] - b[0]) * fw, F[2] * 0.2), h = w * F[3] / F[2];
    if (lt(w * F[3] / F[2], (b[3] - b[1]) * fh)) { h = (b[3] - b[1]) * fh; w = h * F[2] / F[3]; }
    if (gt(w, F[2])) { return F.slice(); }
    return [(b[0] + b[2]) / 2 - w / 2, (b[1] + b[3]) / 2 - h / 2, w, h];
  }
  function selEins(x) { return Array.isArray(x) ? x[0] : x; }
  function kachelnMarkieren() {
    var s0 = selEins(sel), kid = s0 ? (KATV[s0] ? KATV[s0].id : null) : null;
    each(liste.querySelectorAll('.wsd-p'), function (b) { b.classList.toggle('on', b.getAttribute('data-k') === kid); });
  }
  /* Kulissenschalldaempfer: das Gehaeuse ('kulisse') hebt die Kulissen darin ('skulisse', Runde 12 der Szene) mit hervor */
  function mitInnen(pid) { return pid === 'kulisse' ? ['kulisse', 'skulisse'] : pid; }
  /* Runde 17 (Dimi 11.11.2026, 16:23): zusammengelegte Bauteile (z. B. Rohrgabelung als Bauform des Rechteckbogens) haben keine eigene
     Kartei. Die Anlage hebt das angeklickte Teil hervor (selS), die Kartei zeigt das Ziel-Bauteil mit dieser Bauform (DATA.kziel). */
  function szene(x) { return mitInnen(x ? (x === sel ? (selS || sel) : x) : x); }
  function gewaehlt() { return selS || sel; }
  function waehle(pid, gi, g3) {
    var zz = pid ? ((DATA.kziel || {})[pid] || null) : null, ps = pid;
    if (zz) { if (BT[zz.p]) { pid = zz.p; } else { zz = null; } }
    if (pid) { startAktiv(); }
    sel = pid; selS = zz ? ps : null; aktiv = undefined; zeige(szene(pid));
    kachelnMarkieren();
    if (!pid) { SYMTOK++; tourAus(); if (API) { API.zu(); API = null; } schliessen(); mehr.hidden = true; if (!dvAn) { zoom(G.vb); } kulisseAuf(false); return; }
    if (dvAn) { DV.fokus(szene(pid), g3 === undefined ? null : g3); } else { zoom(zielFuer(szene(pid), gi)); }
    if (pid === 'kulisse' || pid === 'skulisse') { kulisseAuf(true); } else { kulisseAuf(false); }
    infoZeigen(pid, null, zz ? zz.v : undefined);
  }
  /* „Alle …“ einer Kategorie (Dimi 09.11.2026, Runde 11 Punkt 16): alle Bauteile hervorgehoben, Kartei mit allen Maschinen */
  function waehleAlle(kid) {
    var k = KATID[kid]; if (!k) { return; }
    startAktiv();
    sel = k.teile.slice(); selS = null; aktiv = undefined; zeige(sel);
    kachelnMarkieren();
    if (dvAn) { DV.fokus(sel, null); } else { zoom(zielFuer(sel, null)); }
    kulisseAuf(false);
    infoZeigen(null, k);
  }
  /* Kategorie waehlen: mit mehreren Bauteilen gleich „Alle …“, sonst das Bauteil */
  function waehleKat(kid) {
    var k = KATID[kid]; if (!k) { return; }
    if (k.alle) { if (gt(k.teile.length, 1)) { waehleAlle(kid); return; } }
    waehle(k.teile[0], null);
  }
  /* Kachel der Kategorie eines Bauteils */
  function kachelVon(x) {
    if (!pg) { return null; }
    x = selEins(x);
    var kid = x ? (KATV[x] ? KATV[x].id : null) : null;
    return kid ? pg.querySelector('.wsd-p[data-k="' + kid + '"]') : null;
  }
  /* Kachel wird Kartei (Dimi 09.11.2026): Die uebrigen Kacheln fahren nach rechts weg, die Kartei steht an der Stelle der
     Kachel und waechst aus ihr heraus (Rahmen und Bild). Antippen des Bildes, x oder Esc: die Kartei schrumpft zur Kachel,
     die anderen Kacheln kommen von rechts zurueck. KZU: Kacheln eingefahren; KT: Kachel, an deren Stelle die Kartei steht. */
  var KZU = false, KT = null, KR = null, FAHRT = 0;
  function kachelListe() { var a = []; if (pg) { each(pg.querySelectorAll('.wsd-p'), function (e) { a.push(e); }); } return a; }
  function sichtbar(r) { return gt(r.bottom, 40) ? gt(window.innerHeight - 40, r.top) : false; }
  function scrollSofort(dy) {
    var y = Math.max(0, (window.pageYOffset || 0) + dy);
    try { window.scrollTo({ top: y, left: window.pageXOffset || 0, behavior: 'instant' }); } catch (e) { window.scrollTo(window.pageXOffset || 0, y); }
  }
  function karteiSetzen(qk, nachher) {
    var t = kachelVon(auswahl());
    if (!t) { schliessen(); return; }
    if (KZU) {
      if (info.parentNode !== pg) { pg.insertBefore(info, t); } else if (info.nextElementSibling !== t) { pg.insertBefore(info, t); }
      KT = t; if (nachher) { nachher(); } return;
    }
    oeffnen(t, qk, nachher);
  }
  /* Weiches Einblenden (Dimi 09.11.2026, Runde 11 Punkt 12): die Kacheln blenden aus, die Kartei blendet an ihrer Stelle ein */
  function oeffnen(t, qk, nachher) {
    var tok = ++FAHRT, ks = kachelListe(), r = t.getBoundingClientRect(), pb = t.querySelector('.wsd-pb'), ri = pb ? pb.getBoundingClientRect() : r;
    KR = { w: r.width, h: r.height, ix: ri.left - r.left, iy: ri.top - r.top, iw: ri.width, ih: ri.height };
    KT = t; KZU = true;
    var anim = BEWEGUNG ? (qk ? (qk.t === t ? sichtbar(qk.r) : false) : false) : false;
    if (anim) {
      pg.classList.add('wsd-blend');
      window.setTimeout(function () {
        if (tok !== FAHRT) { return; }
        each(ks, function (e) { e.classList.add('zu'); });
        pg.classList.add('wsd-kauf'); pg.classList.remove('wsd-blend');
        pg.insertBefore(info, t);
        var rK = info.getBoundingClientRect(), dy = rK.top - qk.r.top;
        if (dy) { scrollSofort(dy); }
        info.classList.remove('wsz-ein'); info.getBoundingClientRect(); info.classList.add('wsz-ein');
        if (nachher) { nachher(); }
      }, 260);
      return;
    }
    if (!anim) {
      each(ks, function (e) { e.classList.remove('weg'); e.classList.add('zu'); });
      pg.classList.add('wsd-kauf'); pg.insertBefore(info, t);
      info.classList.remove('wsz-ein'); info.getBoundingClientRect(); info.classList.add('wsz-ein');
      if (nachher) { nachher(); }
      return;
    }
    pg.classList.add('wsd-fahrt'); t.classList.add('quelle');
    var i = 0;
    each(ks, function (e) { if (e !== t) { e.style.transitionDelay = Math.min(i * 16, 160) + 'ms'; i++; e.classList.add('weg'); } });
    window.setTimeout(function () {
      if (tok !== FAHRT) { return; }
      each(ks, function (e) { e.style.transitionDelay = ''; e.classList.add('zu'); });
      t.classList.remove('quelle'); pg.classList.add('wsd-kauf');
      pg.insertBefore(info, t);
      var rK = info.getBoundingClientRect(), dy = rK.top - qk.r.top;
      if (dy) { scrollSofort(dy); rK = info.getBoundingClientRect(); }
      info.classList.add('wsz-morph'); window.setTimeout(function () { info.classList.remove('wsz-morph'); }, 700);
      aufziehen(qk.r, rK);
      if (nachher) { nachher(); }
      window.setTimeout(function () { if (tok === FAHRT) { pg.classList.remove('wsd-fahrt'); } }, 600);
    }, 330);
  }
  /* Rahmen und sichtbarer Ausschnitt der Kartei wachsen von der Kachel (r0) auf die volle Kartei (rK) */
  function rahmen(o, r, u, l, rK, g) {
    var c = 'inset(' + o + 'px ' + r + 'px ' + u + 'px ' + l + 'px)';
    info.style.clipPath = c; info.style.webkitClipPath = c;
    g.style.left = (l - 1) + 'px'; g.style.top = (o - 4) + 'px'; g.style.width = Math.max(0, rK.width - l - r) + 'px'; g.style.height = Math.max(0, rK.height - o - u) + 'px';
  }
  function aufziehen(r0, rK) {
    var o = Math.max(0, Math.round(r0.top - rK.top)), l = Math.max(0, Math.round(r0.left - rK.left)), r = Math.max(0, Math.round(rK.right - r0.right)), u = Math.max(0, Math.round(rK.bottom - r0.bottom));
    var g = ht('div', 'wsz-rahmen', null, info), ez = ' .5s cubic-bezier(.2,.75,.25,1)';
    info.style.transition = 'none'; g.style.transition = 'none';
    rahmen(o, r, u, l, rK, g);
    info.getBoundingClientRect();
    window.requestAnimationFrame(function () {
      info.style.transition = 'clip-path' + ez + ',-webkit-clip-path' + ez;
      g.style.transition = 'left' + ez + ',top' + ez + ',width' + ez + ',height' + ez;
      rahmen(0, 0, 0, 0, rK, g);
    });
    window.setTimeout(function () { info.style.clipPath = ''; info.style.webkitClipPath = ''; info.style.transition = ''; if (g.parentNode) { g.parentNode.removeChild(g); } }, 560);
  }
  function schliessen() {
    var tok = ++FAHRT, t = KT;
    if (!info.parentNode) { kachelnZurueck(t, null, tok); return; }
    var rK = info.getBoundingClientRect();
    /* weich ausblenden, dann blenden die Kacheln wieder ein (Punkt 12) */
    if (BEWEGUNG ? sichtbar(rK) : false) {
      info.classList.remove('wsz-ein'); info.classList.add('wsz-aus');
      window.setTimeout(function () {
        if (tok !== FAHRT) { return; }
        info.classList.remove('wsz-aus');
        if (info.parentNode) { info.parentNode.removeChild(info); }
        KZU = false; KT = null; pg.classList.remove('wsd-kauf');
        var ks = kachelListe();
        each(ks, function (e) { e.classList.remove('weg'); e.style.transform = ''; e.style.transitionDelay = ''; e.classList.add('einb'); e.classList.remove('zu'); });
        if (t) { var rt = t.getBoundingClientRect(); if (lt(rt.top, kopfHoehe())) { scrollSofort(rt.top - kopfHoehe() - 20); } }
        window.setTimeout(function () { each(ks, function (e) { e.classList.remove('einb'); }); }, 520);
      }, 280);
      return;
    }
    if (!(BEWEGUNG ? (t ? (KR ? sichtbar(rK) : false) : false) : false)) { info.parentNode.removeChild(info); kachelnZurueck(t, null, tok); return; }
    var w = Math.min(KR.w, rK.width), h = Math.min(KR.h, rK.height), g = ht('div', 'wsz-rahmen', null, info), ez = ' .36s cubic-bezier(.4,0,.2,1)';
    info.style.transition = 'none'; g.style.transition = 'none';
    rahmen(0, 0, 0, 0, rK, g);
    info.getBoundingClientRect();
    var svg = info.querySelector('.wsy-bild svg');
    window.requestAnimationFrame(function () {
      info.style.transition = 'clip-path' + ez + ',-webkit-clip-path' + ez;
      g.style.transition = 'width' + ez + ',height' + ez;
      rahmen(0, Math.round(rK.width - w), Math.round(rK.height - h), 0, rK, g);
      if (svg) { flipNach(svg, { left: rK.left + KR.ix, top: rK.top + KR.iy, width: KR.iw, height: KR.ih }, ez); }
    });
    window.setTimeout(function () {
      if (tok !== FAHRT) { return; }
      var r1 = info.getBoundingClientRect();
      if (info.parentNode) { info.parentNode.removeChild(info); }
      info.style.clipPath = ''; info.style.webkitClipPath = ''; info.style.transition = ''; if (g.parentNode) { g.parentNode.removeChild(g); }
      kachelnZurueck(t, { left: r1.left, top: r1.top }, tok);
    }, 380);
  }
  function kachelnZurueck(t, r, tok) {
    var ks = kachelListe();
    KZU = false; KT = null; if (pg) { pg.classList.remove('wsd-kauf'); }
    if (!r || !t || !BEWEGUNG) {
      each(ks, function (e) { e.classList.remove('zu'); e.classList.remove('weg'); e.style.transitionDelay = ''; e.style.transform = ''; });
      if (pg) { pg.classList.remove('wsd-fahrt'); }
      return;
    }
    pg.classList.add('wsd-fahrt');
    each(ks, function (e) { e.style.transition = 'none'; e.classList.add('weg'); e.classList.remove('zu'); });
    t.classList.remove('weg');
    var rt = t.getBoundingClientRect(), dy = rt.top - r.top;
    if (dy) { scrollSofort(dy); rt = t.getBoundingClientRect(); }
    var dx = Math.round(r.left - rt.left);
    if (dx) { t.style.transform = 'translateX(' + dx + 'px)'; }
    pg.getBoundingClientRect();
    /* setTimeout statt requestAnimationFrame: laeuft auch, wenn die 3D-Ansicht Bilder verzoegert */
    window.setTimeout(function () {
      var i = 0;
      each(ks, function (e) {
        e.style.transition = '';
        if (e === t) { e.style.transform = ''; return; }
        e.style.transitionDelay = Math.min(i * 20, 220) + 'ms'; i++; e.classList.remove('weg');
      });
    }, 30);
    window.setTimeout(function () { if (tok !== FAHRT) { return; } each(ks, function (e) { e.style.transitionDelay = ''; }); pg.classList.remove('wsd-fahrt'); }, 760);
  }
  var rzT = 0;
  window.addEventListener('resize', function () { if (rzT) { return; } rzT = window.requestAnimationFrame(function () { rzT = 0; if (info.parentNode) { karteiSetzen(null, null); } }); });
  /* Bauteilbild waechst aus dem angetippten Symbol (Kachel oder Filter) in die Kartei */
  function flip(r0, el) {
    if (!el) { return; }
    var r1 = el.getBoundingClientRect(); if (!r1.width) { return; }
    if (!BEWEGUNG) { return; }
    var s = 0.6, dx = 0, dy = 0;
    if (r0) { s = Math.max(0.12, Math.min(r0.width / r1.width, r0.height / r1.height)); dx = r0.left + r0.width / 2 - (r1.left + r1.width / 2); dy = r0.top + r0.height / 2 - (r1.top + r1.height / 2); }
    el.style.transition = 'none'; el.style.position = 'relative'; el.style.zIndex = '2';
    el.style.transform = 'translate(' + Math.round(dx) + 'px,' + Math.round(dy) + 'px) scale(' + s.toFixed(3) + ')'; el.style.opacity = r0 ? '1' : '0';
    el.getBoundingClientRect();
    window.requestAnimationFrame(function () {
      /* Flug des Symbols in die Kartei (Dimi 09.11.2026: etwas langsamer) */
      el.style.transition = 'transform .8s cubic-bezier(.2,.75,.25,1),opacity .45s ease';
      el.style.transform = 'none'; el.style.opacity = '1';
      window.setTimeout(function () { el.style.zIndex = ''; }, 860);
    });
  }
  /* Bild beim Schliessen zurueck an die Stelle des Kachelbildes */
  function flipNach(el, z, ez) {
    var r1 = el.getBoundingClientRect(); if (!r1.width) { return; }
    var s = Math.max(0.12, Math.min(z.width / r1.width, z.height / r1.height));
    var dx = z.left + z.width / 2 - (r1.left + r1.width / 2), dy = z.top + z.height / 2 - (r1.top + r1.height / 2);
    el.style.position = 'relative'; el.style.zIndex = '6'; el.style.transition = 'transform' + ez;
    el.style.transform = 'translate(' + Math.round(dx) + 'px,' + Math.round(dy) + 'px) scale(' + s.toFixed(3) + ')';
  }
  /* Name der Kachel gleitet in die Ueberschrift der Kartei */
  function flipText(r0, el) {
    if (!r0 || !el || !BEWEGUNG) { return; }
    var r1 = el.getBoundingClientRect(); if (!r1.width) { return; }
    el.style.transformOrigin = '0 0'; el.style.transition = 'none';
    el.style.transform = 'translate(' + Math.round(r0.left - r1.left) + 'px,' + Math.round(r0.top - r1.top) + 'px) scale(.8)';
    el.getBoundingClientRect();
    window.requestAnimationFrame(function () { el.style.transition = 'transform .8s cubic-bezier(.2,.75,.25,1)'; el.style.transform = 'none'; });
  }
  /* Bauteile der Kategorie als kleine Kacheln ganz oben in der Kartei (Dimi 09.11.2026, Runde 9). Antippen waehlt das
     Bauteil; die Kachel des gezeigten Bauteils setzt die Ansicht zurueck (3D in die Ausgangslage, Bereiche aus). */
  /* Dimi 11.11.2026, 07:54: kein Flackern beim Wechsel in der Leiste. Die Leiste derselben Kategorie bleibt stehen (alt), nur die
     Markierung wechselt; die Kacheln lesen die Auswahl aus fz.wPid */
  function leisteSetzen(fz, pid) {
    fz.wPid = pid;
    each(fz.querySelectorAll('.wkg-c'), function (c) { var on = c.wP === pid; c.classList.toggle('on', on); c.setAttribute('aria-pressed', on ? 'true' : 'false'); });
  }
  function bauteilLeiste(k, pid, par, alt) {
    /* Rueckweg: Streifen ueber der Kartei (zurueckStreifen in infoZeigen); die Leiste nur bei mehreren Bauteilen */
    if (!k) { return null; }
    var mehr = gt(k.teile.length, 1);
    if (!mehr) { return null; }
    if (alt) { if (alt.wKat === k.id) { par.appendChild(alt); leisteSetzen(alt, pid); return alt; } }
    var fz = ht('div', 'wkg-f wsy-leiste', null, par); fz.wKat = k.id; fz.wPid = pid;
    /* Runde 18 (Dimi 11.11.2026, 20:13): Vergleich nur fuer die Vorschau – jede Bauform als eigene Kachel (window.WMS_EINZELN = Spalten) */
    var EINZ = { formrund: ['segbogen', 'tstueck90', 'tstueck', 'reduz', 'enddeckel', 'lippe', 'pbogen'], formeckig: ['rbogen', 'rwinkel', 'retage', 'ruebergang', 'rboden', 'rstutzen'] };
    if (window.WMS_EINZELN ? !!EINZ[k.id] : false) {
      fz.classList.add('einzeln'); fz.style.setProperty('--sp', String(window.WMS_EINZELN));
      var nE = 0;
      each(EINZ[k.id], function (p) {
        var b = BT[p]; if (!b) { return; }
        var V = symbolVarianten(p) || [null], nm = (DATA.bfn || {})[p] || (SYM[p] || {}).vn || [];
        each(V, function (v, j) {
          var c = ht('button', 'wkg-c', null, fz); c.type = 'button'; c.wP = p; nE++;
          var ib = ht('span', 'wkg-ci', null, c); symbolBild(b, ib, true, j);
          ht('span', 'wkg-ct', nm[j] || kurzName(b), c);
          c.addEventListener('click', function () { waehle(p, null); });
        });
      });
      fz.setAttribute('data-n', String(nE));
      return fz;
    }
    /* Runde 18 (Dimi 11.11.2026, 20:13): „Alle …“ als Leiste ueber den Kacheln, so breit wie alle Kacheln, ohne Bild */
    if (mehr ? !!k.alle : false) {
      fz.classList.add('mit-alle');
      var al = ht('button', 'wkg-c wkg-alle' + (pid === null ? ' on' : ''), null, fz); al.type = 'button'; al.setAttribute('aria-pressed', pid === null ? 'true' : 'false'); al.wP = null;
      ht('span', 'wkg-ct', k.alle.t, al);
      al.addEventListener('click', function () { if (fz.wPid === null) { if (API) { API.zurueck(); } return; } waehleAlle(k.id); });
    }
    /* Runde 17 (Dimi 11.11.2026, 16:23): abgesetzte Bauteile (gepresste Formteile) mit Abstand wie „Alle …“ am Ende */
    var ab = k.abgesetzt || [], reihe = k.teile.filter(function (p) { return ab.indexOf(p) === -1; }).concat(k.teile.filter(function (p) { return ab.indexOf(p) !== -1; }));
    each(reihe, function (p, i) {
      var b = BT[p]; if (!b) { return; }
      var c = ht('button', 'wkg-c' + (p === pid ? ' on' : '') + (ab.indexOf(p) !== -1 ? ' wkg-ab' : ''), null, fz); c.type = 'button'; c.setAttribute('aria-pressed', p === pid ? 'true' : 'false'); c.wP = p;
      var ib = ht('span', 'wkg-ci', null, c), ct = ht('span', 'wkg-ct', null, c);
      kachelBild(b, ib, ct, c);
      c.addEventListener('click', function () { if (p === fz.wPid) { if (API) { API.zurueck(); } return; } waehle(p, null); });
    });
    return fz;
  }
  /* Bild neu einblenden statt einfliegen (Dimi 09.11.2026, Runde 9: Wechsel innerhalb der offenen Kartei) */
  var WEICH = false;
  function einblenden(el) {
    if (!el) { return; } if (!BEWEGUNG) { return; }
    el.style.transition = 'none'; el.style.opacity = '0'; el.getBoundingClientRect();
    window.requestAnimationFrame(function () { el.style.transition = 'opacity .55s ease'; el.style.opacity = '1'; });
  }
  var API = null, WT = null;
  function infoZeigen(pid, kAlle, bf) {
    /* Wechsel in der offenen Kartei (Dimi 11.11.2026, 07:54: kein Flackern): kein Aus- und Einblenden mehr. Alles wird im selben
       Bild neu gesetzt; unveraenderte Kaesten, Linien und Texte stehen danach an derselben Stelle (Leiste, Stufenkacheln und Karten
       werden wiederverwendet), die Hoehe bleibt bis zum naechsten Blaettern nach oben (emHalten), die 3D-Ansicht kommt sofort. */
    if (WT) { window.clearTimeout(WT); WT = null; }
    var r0 = null;
    if (QUELLE) { if (QUELLE.getBoundingClientRect) { r0 = QUELLE.getBoundingClientRect(); if (!r0.width) { r0 = null; } } }
    QUELLE = null;
    var qk = QK; QK = null;
    /* Kartei schon offen: das neue Bild blendet im Fenster ein, die Auswahl bleibt an ihrer Stelle */
    WEICH = KZU ? (info.parentNode ? !qk : false) : false;
    var weich = WEICH;
    var altL = weich ? info.querySelector('.wsy-leiste') : null;
    if (weich) { emHalten(info); }
    if (API) { API.zu(); API = null; }
    while (info.firstChild) { info.removeChild(info.firstChild); }
    SYMTOK++; tourAus();
    var kz = kAlle || KATV[pid], b = kAlle ? null : BT[pid];
    zurueckStreifen(info, 'Zurück zu allen Bauteilen', function () { var t = kachelVon(auswahl()); waehle(null); if (t) { window.setTimeout(function () { t.focus(); }, 600); } });
    mehr.textContent = (kAlle ? kAlle.alle.t : b.t) + ' – Maschinen dafür ↓'; mehr.hidden = false;
    /* Runde 9 (Dimi 09.11.2026): ganz oben die Kategorie und ihre Bauteile als kleine Kacheln, darunter das Fenster mit dem
       gewaehlten Bauteil, daneben die Bereiche als Nummern, rechts Name und Text. Runde 10: links der Rueckweg, „Alle …“ */
    /* Runde 16 (Dimi 11.11.2026, 10:32: Kartei kompakter): Kategorie und Bauteil-Kacheln stehen rechts neben dem Fenster ueber dem
       Text (wsy-kopf, eigene Zeile im Raster); am Handy oben ueber dem Fenster. Die Kacheln bleiben beim Wechsel stehen. */
    var kopfK = ht('div', 'wsy-kopf', null, info);
    if (kz) { if (!(kz.alle ? gt(kz.teile.length, 1) : false)) { ht('div', 'wsy-kk', kz.t, kopfK); } }
    if (!bauteilLeiste(kz || null, kAlle ? null : pid, kopfK, altL)) { if (!kz) { info.removeChild(kopfK); kopfK = null; } }
    /* Runde 17 (Dimi 11.11.2026, 16:23): Maske mit drei Spalten in fester Hoehe: 3D mit Nummern, Text, Formstueck-Kacheln.
       Ohne Kacheln (ein Bauteil in der Kategorie) steht die Kategorie ueber dem Titel. */
    function kopfSetzen() {
      if (!kopfK) { var g0 = info.querySelector('.wsy'); if (g0) { kopfPassen(g0); } return; }
      var g = info.querySelector('.wsy'); if (!g) { return; }
      var t = g.querySelector('.wsy-txt');
      if (!kopfK.querySelector('.wsy-leiste')) {
        var kk = kopfK.querySelector('.wsy-kk'); if (kk) { if (t) { t.insertBefore(kk, t.firstChild); } }
        if (kopfK.parentNode) { kopfK.parentNode.removeChild(kopfK); }
        kopfK = null; kopfPassen(g); return;
      }
      g.insertBefore(kopfK, t ? t.nextSibling : null); g.classList.add('mk');
      kopfPassen(g);
    }
    if (kAlle) { alleZeigen(kAlle, r0, qk, weich, kopfSetzen); return; }
    var txt = ht('div', 'wsy-txt');
    var h = ht('h3', 'wsy-n', b.t, txt);
    if (VORSCHAU) { if (b.status === 'offen') { ht('span', 'wsz-tag', 'Fertigungsweg offen', h); } if (b.status === 'herleitung') { ht('span', 'wsz-tag', 'zu prüfen', h); } }
    var btx = (DATA.btx || {})[b.id];
    if (btx) { var tp = ht('p', 'wkp-tx', btx, txt); if (VORSCHAU) { ht('span', 'wsz-tag', 'Text-Entwurf', tp); } }
    /* Runde 14: Karte Rohr-Rechner in der Kartei Wickelfalzrohr */
    if (b.id === 'wfr') { rechnerKarte(txt); }
    var api = symbolBlock(info, b, { txt: txt, bauform: bf });
    if (api) { API = api; }
    if (!api) { info.appendChild(txt); if (b.bereiche.length) { ht('div', null, 'Bereiche: ' + b.bereiche.join(' · '), info); } }
    kopfSetzen();
    if (b.schritte.length) { kompaktBlock(info, b, api || null); }
    else { ht('p', 'wmk-e', 'Der Fertigungsweg für dieses Bauteil wird noch beschrieben. Fragen Sie uns gern direkt.', info); }
    if (VORSCHAU) { if (b.hinweis) { ht('p', null, 'Interner Hinweis (wird nicht veröffentlicht): ' + b.hinweis, info).style.cssText = 'margin:8px 0 0 0;font-size:13px;color:#4B5563'; } }
    function danach() {
      if (weich) {
        /* Zeile der Tabelle angetippt: die Kartei steht weiter oben, dorthin zurueck */
        var rb = info.querySelector('.wsy-bild'); if (rb) { var rr = rb.getBoundingClientRect(); if (lt(rr.bottom, kopfHoehe() + 40)) { hinScrollen(info); } }
        if (api) { api.start3d(-1); }
        return;
      }
      /* Runde 10 (Dimi 09.11.2026, Runde 11 Punkt 12): kein Einflug des Bildes mehr, die Kartei blendet weich ein; 3D danach */
      if (api) { api.start3d(BEWEGUNG ? 520 : 0); }
    }
    karteiSetzen(qk, danach);
  }
  function neuEin() {
    if (!BEWEGUNG) { return; }
    info.classList.remove('wsz-neuein'); info.getBoundingClientRect(); info.classList.add('wsz-neuein');
    window.setTimeout(function () { info.classList.remove('wsz-neuein'); }, 700);
  }
  /* Kartei „Alle …“: Fenster mit den Bauteilen im Wechsel, Text der Kategorie, Tabelle mit allen Maschinen */
  function alleZeigen(k, r0, qk, weich, kopfSetzen) {
    var txt = ht('div', 'wsy-txt');
    ht('h3', 'wsy-n', k.alle.t, txt);
    if (k.alle.txt) { ht('p', 'wkp-tx', k.alle.txt, txt); }
    /* Dimi 11.11.2026, 07:54: die Liste „Einzeln: …“ entfaellt, die Formstuecke stehen in der Leiste darueber */
    var api = alleSymbol(info, k, { txt: txt });
    if (api) { API = api; } else { info.appendChild(txt); }
    if (kopfSetzen) { kopfSetzen(); }
    alleBlock(info, k, { element: function (eid) { if (API) { if (API.element) { API.element(eid); } } } });
    function danach() {
      if (weich) {
        var rb = info.querySelector('.wsy-bild'); if (rb) { var rr = rb.getBoundingClientRect(); if (lt(rr.bottom, kopfHoehe() + 40)) { hinScrollen(info); } }
        if (api) { api.start3d(-1); }
        return;
      }
      if (api) { api.start3d(BEWEGUNG ? 520 : 0); }
    }
    karteiSetzen(qk, danach);
  }
  /* 3D-Ansicht: wird erst beim ersten Umschalten aufgebaut */
  var H3 = {
    /* Ist ein Bauteil gewaehlt, bleibt es hervorgehoben: Zeigen auf andere Teile aendert nichts, damit man ueberall
       anfassen und drehen kann. Ein kurzer Klick auf ein anderes Teil waehlt dieses. */
    hover: function (pid, ev) { if (auswahl()) { tip.style.display = 'none'; return; } tipp(pid, ev); },
    gewaehlt: function () { return !!auswahl(); },
    weg: function () { zeige(szene(auswahl())); tip.style.display = 'none'; },
    klick: function (pid, g3, ev) {
      if (pid) { if (BT[pid].klick !== 'ja') { return; } } else if (!auswahl()) { return; }
      /* Handy-Runde (Prüfliste 25.3): Finger auf das gewaehlte Bauteil: bleibt gewaehlt; abwaehlen mit Tippen ins Leere oder Zuruecksetzen */
      if (pid) { if (ev ? ev.pointerType === 'touch' : false) { if (pid === gewaehlt()) { return; } } }
      tip.style.display = 'none'; waehle(pid === gewaehlt() ? null : pid, null, g3);
    },
    verloren: function () { modus(false); b3.disabled = true; b3.title = 'Die 3D-Ansicht ist nicht mehr verfügbar. Bitte Seite neu laden.'; }
  };
  /* Leistung (Runde 8, Messung 09.11.2026): Steht die 3D-Ansicht, wird die versteckte Zeichnung (etwa 10.400 Elemente)
     freigegeben; zurueck zur Zeichnung (ohne WebGL oder nach Verlust) wird sie neu gezeichnet */
  var BLEER = false;
  function basisFrei() { if (BLEER) { return; } if (!dvAn) { return; } while (base.firstChild) { base.removeChild(base.firstChild); } while (hl.firstChild) { hl.removeChild(hl.firstChild); } BLEER = true; }
  function basisNeu() { if (!BLEER) { return; } zeichneBasis(base, G.it); BLEER = false; }
  function modus(d3) {
    if (d3) {
      if (!dreiMoeglich()) { return; }
      if (!DV) {
        try { DV = drei3(bu, root, G, H3); } catch (e) { DV = null; if (window.console) { window.console.error(e); } }
        if (!DV) { b3.disabled = true; b3.title = 'Die 3D-Ansicht konnte nicht gestartet werden'; return; }
      }
      dvAn = true; s1.style.display = 'none'; s2.style.display = 'none'; tip.style.display = 'none';
      DV.offen(offen); DV.an(szene(auswahl())); aktiv = undefined; zeige(szene(auswahl()));
      if (EIN) { DV.aus(); }
      window.setTimeout(basisFrei, 600);
    } else {
      if (!dvAn) { return; }
      dvAn = false; DV.aus(); basisNeu(); s1.style.display = ''; s2.style.display = '';
      aktiv = undefined; zeige(szene(auswahl())); zoom(auswahl() ? zielFuer(szene(auswahl()), null) : G.vb);
    }
    bI.classList.toggle('an', !d3); b3.classList.toggle('an', d3);
    bI.setAttribute('aria-pressed', d3 ? 'false' : 'true'); b3.setAttribute('aria-pressed', d3 ? 'true' : 'false');
  }
  bI.addEventListener('click', function () { modus(false); });
  b3.addEventListener('click', function () {
    if (dvAn) { return; }
    if (DV) { modus(true); return; }
    var alt = b3.textContent; b3.textContent = '3D wird geladen …'; b3.disabled = true;
    window.setTimeout(function () { b3.textContent = alt; b3.disabled = false; modus(true); }, 30);
  });
  /* Teil d: Bauteile in Gruppen (gerade Teile je eigene Gruppe, Formstuecke als Gruppe) */
  /* Ueberschrift bleibt, die Bedienung steht hinter dem i (Dimi 09.11.2026) */
  var hU = ht('h3', 'wsd-h', 'Diese Bauteile fertigen unsere Maschinen', liste);
  infoKnopf(hU, 'Bauteil antippen: Sie sehen, mit welchen WAMMES-Maschinen es entsteht – manuell, automatisiert oder vollautomatisch.', { label: 'Bedienung' });
  var SQ = [], SQL = false;
  function symQueue() {
    if (SQL) { return; }
    SQL = true;
    window.requestAnimationFrame(function weiter() {
      var x = SQ.shift();
      if (!x) { SQL = false; return; }
      if (x.k ? !!x.k.prodVon : false) { kachelProdukt(x.k, x.el); } else { symbolBild(x.b, x.el); }
      window.requestAnimationFrame(weiter);
    });
  }
  var pio = window.IntersectionObserver ? new IntersectionObserver(function (es) {
    each(es, function (e) { if (e.isIntersecting) { pio.unobserve(e.target); var kid = e.target.getAttribute('data-k'); SQ.push({ b: BT[KATID[kid].sym], el: e.target.querySelector('.wsd-pb'), k: KATID[kid] }); symQueue(); } });
  }, { rootMargin: '250px 0px' }) : null;
  /* Runde 12 der Szene (Dimi 10.11.2026): Nach Bauteil breit, Gruppen als Spalten; die Spalten brechen nicht um, die Kacheln werden kleiner */
  pg = ht('div', 'wsd-pg', null, liste);
  /* Kacheln senkrecht in Spalten (Dimi 09.11.2026): sp = Spalte, Reihenfolge der Daten = Zeile in der Spalte.
     Runde 9: Jede Spalte ist als Gruppe erkennbar (Kopf mit Namen, hinterlegte Flaeche: wsd-sk, wsd-sh); am Handy und bei
     zwei Spalten steht der Kopf als Zwischenueberschrift vor den Kacheln seiner Gruppe. */
  /* gross: Kachel ueber mehrere Zeilen (Kulissen, Dimi 09.11.2026: eigener Bereich, stark beworben); die Flaechen aller
     Spalten reichen gleich weit nach unten */
  var zr = {}, SPN = {}, SPK = {}, ZE = 0;
  function kSpan(k) { return k.gross ? (gt(k.gross, 1) ? k.gross : 2) : 1; }
  each(DATA.katsp || [], function (x) { SPN[x.sp] = x.t; });
  each(DATA.kat || [], function (k) { if (k.sp) { SPK[k.sp] = (SPK[k.sp] || 0) + kSpan(k); if (gt(SPK[k.sp], ZE)) { ZE = SPK[k.sp]; } } });
  each(DATA.kat || [], function (k) {
    if (k.sp) {
      if (!zr[k.sp]) {
        zr[k.sp] = 1;
        var sh = ht('div', 'wsd-sh', null, pg); sh.style.setProperty('--sp', String(k.sp)); sh.style.setProperty('--ze', String(ZE + 2)); sh.setAttribute('aria-hidden', 'true');
        if (SPN[k.sp]) { var sk = ht('div', 'wsd-sk', SPN[k.sp], pg); sk.style.setProperty('--sp', String(k.sp)); }
      }
      zr[k.sp]++;
    }
    var el = kategorieKachel(k, pg);
    if (k.sp) { el.style.setProperty('--sp', String(k.sp)); el.style.setProperty('--zr', String(zr[k.sp]) + (k.gross ? ' / span ' + kSpan(k) : '')); zr[k.sp] += kSpan(k) - 1; pg.classList.add('wsd-spx'); }
    var pb = el.querySelector('.wsd-pb');
    if (pio) { pio.observe(el); } else { SQ.push({ b: BT[k.sym], el: pb, k: k }); symQueue(); }
    /* inaktive Kategorie (Runde 13): nicht anwaehlbar */
    if (k.inaktiv) { return; }
    el.addEventListener('click', function () { zuKategorie(k.id, pb); });
    el.addEventListener('keydown', function (ev) { if (ev.key === 'Enter' || ev.key === ' ') { ev.preventDefault(); zuKategorie(k.id, pb); } });
  });
  /* Strukturvorschau Variante B (Runde 14): kein zweiter Reiter; unter den Bauteilen die Maschinengruppen mit Link zur Kategorieseite */
  if (VAR === 'B') { gruppenDirekt(liste); }
  /* Dimi 11.11.2026, 07:54: der Abschnitt „In der Zeichnung, nicht im Maschinenprogramm: Zukauf und andere Gewerke“ mit den
     gestrichelten Kaestchen entfaellt ueberall; Zukaufteile bleiben in der Anlage als Kontext (Hinweis beim Zeigen) */
  /* Uebersicht messen: Ueberschrift plus Kachelzeilen, ohne aufgeklappte Kartei */
  var UEB = 0;
  root.wszUeb = function () {
    if (!pg) { return 0; }
    if (KZU) { return UEB; }
    var ks = pg.querySelectorAll('.wsd-p'), unten = 0; if (!ks.length) { return UEB; }
    each(ks, function (e) { var r = e.getBoundingClientRect(); if (r.height) { if (gt(r.bottom, unten)) { unten = r.bottom; } } });
    if (!unten) { return UEB; }
    UEB = Math.round(unten - liste.getBoundingClientRect().top);
    return UEB;
  };
  function isoGroesse() {
    var w = bu.clientWidth; if (!w) { return; }
    if (lt(w, 700)) { if (!root.wszHU) { s1.style.height = ''; s2.style.height = ''; return; } }
    var h = szeneHoehe(w, G.vb[3] / G.vb[2], root) + 'px';
    if (s1.style.height !== h) { s1.style.height = h; s2.style.height = h; }
  }
  isoGroesse();
  window.addEventListener('resize', isoGroesse);
  merklisteStart();
  /* Runde 18 (Dimi 11.11.2026, 20:13): ESC klappt Schritt fuer Schritt zu – erst die Kartei, dann die grosse Gruppenleiste, dann die
     Gruppenleiste bis auf die kleinen Kacheln, zuletzt die Anlage. Ein offenes Menue „Produkte“ schliesst zuerst (wm-layout). */
  document.addEventListener('keydown', function (ev) {
    if (ev.key !== 'Escape') { return; }
    if (ev.wmsEsc) { return; }
    var mg = document.getElementById('wmlMega'); if (mg ? mg.classList.contains('open') : false) { return; }
    if (auswahl()) { ev.wmsEsc = 1; waehle(null); return; }
    if (!ST) { return; }
    if (ST.gross()) { ev.wmsEsc = 1; ST.gross(false); return; }
    if (!ST.istAus()) { ev.wmsEsc = 1; startAktiv(); return; }
    /* Runde 18 (Prüfliste 21.3 b): als letzter Schritt klappt die Anlage zu (wie der Balken unter der Anlage) */
    if (root.wszSzeneZu) { if (!root.wszSzeneZu()) { ev.wmsEsc = 1; root.wszSzeneZu(true); } }
  });
  WSZ_NAV = function (pid) { zuBauteil(pid); };
  root.wszWaehle = waehle; root.wszKat = waehleKat; root.wszAlle = waehleAlle; root.wszOffen = kulisseAuf; root.wszZeige = zeige; root.wszReiter = reiter; root.wszSuche = SU; root.wszVerfahren = zuVerfahren;
  /* Stand der Ansicht fuer die Rueckmeldung (Feld „Ideen und Verbesserungen“, Runde 13) */
  root.wszStand = function () {
    var a0 = auswahl(), t = t1.hidden ? 'Fertigungsverfahren' : 'Lüftungsanlage';
    if (a0) { if (Array.isArray(a0)) { var kk = KATV[a0[0]]; t += ', Gruppe: ' + (kk ? kk.t : ''); } else if (BT[a0]) { t += ', Bauteil: ' + BT[a0].t; } }
    return t + (EM_RV === 'pdf' ? ', Rahmenverbindung: PDF-Flansch' : '');
  };
  root.wszModus = modus; root.wszDrei = function () { return DV; };
  /* 3D erst aufbauen, wenn die Szene ins Bild kommt (Runde 8, Ladezeit); bis dahin steht die Zeichnung */
  if (box.getAttribute('data-ansicht') !== 'iso') {
    if (dreiMoeglich()) {
      if (window.IntersectionObserver) {
        var dio = new IntersectionObserver(function (es) { each(es, function (e) { if (e.isIntersecting) { dio.disconnect(); window.setTimeout(function () { if (!DV) { modus(true); } }, 40); } }); }, { rootMargin: '120px 0px' });
        dio.observe(bu);
      } else { window.setTimeout(function () { modus(true); }, 40); }
    }
  }
  root.wszBasisLeer = function () { return BLEER; };
}

/* ---------- Kompakte Bauteilansicht (08.11.2026, von Dimi bestaetigt; Kartei und Stufen untereinander 09.11.2026) ----------
   Oben ein kurzer Text, wie das Bauteil entsteht, und das Bauteilbild. Darunter die Fertigung als Kette nummerierter Kacheln
   (Symbol und Kurztext; unten drei Balken M, T, V: welche Stufe den Schritt mit einer Maschine abdeckt).
   Darunter die Ausbaustufen untereinander: Manuell, Teilautomatisiert, Vollautomatisiert, je Stufe die Maschinen
   mit den Schritten, die sie uebernehmen. Ein Klick auf eine Kachel zeigt den Schritt mit allen Stufen und Maschinen. */
/* Maschinenkarten zeigen das Maschinensymbol (Seite ist auf Symbole ausgelegt). Fotos: auf Wunsch wieder einschalten. */
var KARTE_FOTO = false;
/* Maschinenkarte: Symbol, Bezeichnung, Typ, Marke; o.nr Schrittnummern oder o.teile Bauteile; o.an/o.ab beim Zeigen */
function maschKarte(id, par, o) {
  o = o || {};
  var m = masch(id), link = m.u ? (m.g ? '' : seitenUrl(m.u)) : '';
  var c = ht(link ? 'a' : 'div', 'wkp-mc' + (m.g ? ' g' : ''), null, par);
  if (link) { c.href = link; }
  var bi = ht('span', 'wkp-mb', null, c);
  if (!m.g) {
    var src = KARTE_FOTO ? bildUrl(id, m) : '';
    if (src) {
      var im = ht('img', null, null, bi); im.alt = ''; im.loading = 'lazy'; im.decoding = 'async';
      im.addEventListener('error', function () { if (im.parentNode) { bi.removeChild(im); } platzIcon(bi, id); });
      im.src = src;
    } else { platzIcon(bi, id); }
  }
  var tx = ht('span', 'wkp-mt', null, c), ty = tyZeigen(m);
  ht('span', 'wkp-m1', m.mb, tx);
  if (m.g) { ht('span', 'wkp-m2 ng', 'nicht im Programm', tx); }
  else if (ty) { ht('span', 'wkp-m2' + (platzhalter(ty) ? ' ph' : ''), ty, tx); }
  else if (m.zk) { ht('span', 'wkp-m2 ng', 'auf Anfrage', tx); }
  if (m.b) { ht('span', 'wkp-m3', m.b, tx); }
  if (o.nr) {
    var sl = ht('span', 'wkp-ms', null, tx);
    ht('small', null, gt(o.nr.length, 1) ? 'Schritte' : 'Schritt', sl);
    each(o.nr, function (i) { ht('i', null, String(i + 1), sl); });
  }
  if (o.teile) {
    var tl = ht('span', 'wkp-mf', null, tx);
    ht('small', null, 'für', tl);
    each(o.teile, function (p) { var b = BT[p]; if (b) { ht('i', null, kurzName(b), tl); } });
  }
  if (!m.g) { merkKnopf(c, id); }
  if (o.an) { c.addEventListener('mouseenter', o.an); }
  if (o.ab) { c.addEventListener('mouseleave', o.ab); }
  return c;
}
/* Abschnitt einer Ausbaustufe: farbiger Rand, Name, Zahl der Maschinen */
function stufenAbschnitt(par, q, txt) {
  var sec = ht('div', 'wkp-st ' + q, null, par); sec.setAttribute('data-st', q);
  var hd = ht('div', 'wkp-sth', null, sec);
  ht('b', null, grossAnfang(DATA.stufen[q]), hd);
  ht('small', null, txt, hd);
  return sec;
}
function alleMerkenKnopf(par, ids) {
  if (!gt(ids.length, 1)) { return; }
  var al = ht('button', 'wkp-alle', 'Alle ' + ids.length + ' Maschinen auf die Merkliste', par); al.type = 'button';
  al.addEventListener('click', function () { var a = mkLesen(); each(ids, function (id) { if (a.indexOf(id) === -1) { a.push(id); } }); mkSchreiben(a); });
}
/* Gruppen-Kachel (Runde 9, Dimi 09.11.2026): oben der Name, darunter zweigeteilt das Bauteil und das Maschinenbild (je halbe
   Breite), der Maschinenname unter dem Bild. Keine Zahlen und keine Stufen-Zeichen; die Bauteile nennt der Hinweis beim Zeigen */
function kategorieKachel(k, par) {
  var el = ht('div', 'wsd-p wkg-k' + (k.gross ? ' gross' : ''), null, par);
  el.setAttribute('role', 'button'); el.setAttribute('tabindex', '0'); el.setAttribute('data-k', k.id);
  ht('div', 'wsd-pn', k.t, el);
  var bi = ht('div', 'wsd-pbi', null, el);
  ht('div', 'wsd-pb', null, bi);
  var namen = [];
  each(k.teile, function (p) { var b = BT[p]; if (b) { namen.push(kurzName(b)); } });
  /* Runde 13 der Szene (Dimi 10.11.2026): Zubehoer und Einbauteile bleiben als Kachel, ohne Maschinen und nicht anwaehlbar */
  if (k.inaktiv) {
    el.classList.add('ohne-m'); el.classList.add('inaktiv'); el.removeAttribute('role'); el.setAttribute('tabindex', '-1'); el.setAttribute('aria-disabled', 'true');
    ht('span', 'wsd-bald', k.inaktiv, bi);
    el.setAttribute('aria-label', k.t + ': ' + k.inaktiv);
    return el;
  }
  /* Maschinenbezug (43_maschinenbild.js): Leitbild k.leit, beim Zeigen wechseln die Maschinen */
  /* Runde 18: Produkt oben wechselt mit der Maschine (k.prodVon: Maschine zu Bauteil; Ebenen in kachelProdukt, 40_ui.js) */
  var mo = k.prodVon ? { beiZeig: function (x) { var p = null; each(x.ids, function (id) { if (!p) { p = k.prodVon[id] || null; } }); el.wProdZeig = p || k.sym; var pb = el.querySelector('.wsd-pb'); if (pb ? pb.wProd : false) { pb.wProd(el.wProdZeig); } } } : null;
  if (!mbKachel(el, k, bi, mo)) { el.classList.add('ohne-m'); }
  /* Runde 13 (Dimi 10.11.2026): kein Hinweisfenster mehr auf den Kacheln */
  el.setAttribute('aria-label', k.t + (gt(namen.length, 1) ? ': ' + namen.join(', ') : ''));
  return el;
}
/* Bild eines Ablaufschritts: Ablaufsymbol, oder bei 'B:Bauteil' die Zeichnung des Bauteils (Runde 11 der Szene: Kulissen einsetzen
   zeigt die Schalldaempferkulisse) */
function prozessBild(pid) {
  if (pid.indexOf('B:') === 0) {
    var b = BT[pid.slice(2)]; if (!b) { return null; }
    var s = ht('span', 'wps wps-b'); symbolBild(b, s, true); return s;
  }
  return ikSvg(pid);
}
function prozessName(pid) { if (pid.indexOf('B:') === 0) { var b = BT[pid.slice(2)]; return b ? kurzName(b) : ''; } return PNAME[pid] || pid; }
function stufenDaten(b) {
  var R = {};
  each(['M', 'T', 'V'], function (k) {
    var ms = [], idx = {}, hand = [], frei = [];
    each(b.schritte, function (s, i) {
      var hat = false;
      each(s[k] || [], function (id) {
        var m = masch(id); if (!m) { return; }
        hat = true;
        if (m.z) { hand.push({ i: i, t: m.mb }); return; }
        if (idx[id] === undefined) { idx[id] = ms.length; ms.push({ id: id, s: [] }); }
        ms[idx[id]].s.push(i);
      });
      if (!hat) { frei.push(i); }
    });
    var n = 0; each(ms, function (e) { if (!masch(e.id).g) { n++; } });
    R[k] = { ms: ms, hand: hand, frei: frei, n: n };
  });
  return R;
}
function schrittListe(a) { return a.map(function (i) { return String(i + 1); }).join(', '); }
/* Fertigung eines Bauteils: Schritte (eingeklappt, Dimi 09.11.2026), darunter die Maschinen-Matrix.
   api: an(k)/ab() aus symbolBlock, hebt einen Bereich im Bauteilbild hervor */
/* Dimi 11.11.2026, 07:54: kein Springen beim Wechsel der Bauteile; ob „Fertigung in … Schritten“ offen ist, bleibt erhalten */
var KP_AUF = false;
function kompaktBlock(info, b, api) {
  var D = stufenDaten(b), box = ht('div', 'wkp', null, info), kacheln = [], svgs = [], offenI = null;
  /* nur Stufen, in denen das Bauteil Maschinen oder Handarbeit hat (Dimi 09.11.2026, Runde 11 Punkt 6) */
  var QS = ['M', 'T', 'V'].filter(function (q) { return gt(D[q].ms.length + D[q].hand.length, 0); });
  var kopf = ht('button', 'wkp-k wkp-auf', null, box); kopf.type = 'button'; kopf.setAttribute('aria-expanded', 'false');
  var pfx = ht('span', 'wkp-px', '▸', kopf);
  ht('span', 'wkp-kt', 'Fertigung in ' + b.schritte.length + (b.schritte.length === 1 ? ' Schritt' : ' Schritten'), kopf);
  /* Bedienhinweis entfaellt (Dimi 09.11.2026: weniger Text); der Pfeil zeigt das Aufklappen */
  var reihe = ht('div', 'wkp-r', null, box); reihe.hidden = true;
  each(b.schritte, function (s, i) {
    if (i) { ht('span', 'wkp-pf', '›', reihe).setAttribute('aria-hidden', 'true'); }
    var k = ht('button', 'wkp-s', null, reihe); k.type = 'button'; k.setAttribute('aria-expanded', 'false');
    ht('span', 'wkp-n', String(i + 1), k);
    var ic = ht('span', 'wkp-i', null, k), g = null;
    if (s.p.length) {
      g = prozessBild(s.p[0]);
      if (g) { ic.appendChild(g); svgs.push(g); }
      if (gt(s.p.length, 1)) { ht('span', 'wkp-mehr', '+' + (s.p.length - 1), ic); }
    } else { ic.classList.add('leer'); }
    ht('span', 'wkp-t', s.t, k);
    var bb = ht('span', 'wkp-b', null, k);
    each(QS, function (q) {
      var hat = false, hand = false;
      each(D[q].ms, function (m) { if (m.s.indexOf(i) !== -1) { hat = true; } });
      each(D[q].hand, function (h) { if (h.i === i) { hand = true; } });
      ht('i', q + (hat ? ' ja' : (hand ? ' hand' : '')), null, bb);
    });
    if (VORSCHAU) { if (s.m === 'h') { ht('span', 'wkp-tag', 'prüfen', k); } if (s.m === 'o') { ht('span', 'wkp-tag', 'offen', k); } }
    k.title = s.p.length ? s.p.map(prozessName).join(' · ') : s.t;
    kacheln.push(k);
    k.addEventListener('click', function () { detail(offenI === i ? null : i); });
    k.addEventListener('mouseenter', function () { if (g) { ikNochmal(g); } markM(i, true); });
    k.addEventListener('mouseleave', function () { if (offenI !== i) { markM(i, false); } });
  });
  var det = ht('div', 'wkp-d', null, box); det.hidden = true;
  function aufSetzen(auf) { reihe.hidden = !auf; pfx.textContent = auf ? '▾' : '▸'; kopf.setAttribute('aria-expanded', auf ? 'true' : 'false'); }
  kopf.addEventListener('click', function () {
    var auf = reihe.hidden; KP_AUF = auf;
    aufSetzen(auf);
    if (!auf) { detail(null); }
    /* Handy (Dimi 12.11.2026, 09:23): Aufgeklapptes ins Bild */
    if (auf) { if (handyGrob()) { var rk = reihe.getBoundingClientRect(); if (gt(rk.bottom, window.innerHeight - 20)) { handyFokus(kopf, 80); } } }
  });
  if (KP_AUF) { aufSetzen(true); }
  function detail(i) {
    if (offenI !== null) { markM(offenI, false); }
    offenI = i;
    each(kacheln, function (k, j) { k.classList.toggle('auf', j === i); k.setAttribute('aria-expanded', j === i ? 'true' : 'false'); });
    while (det.firstChild) { det.removeChild(det.firstChild); }
    if (i === null) { det.hidden = true; return; }
    markM(i, true);
    var s = b.schritte[i];
    det.hidden = false;
    var h = ht('div', 'wkp-dh', null, det);
    ht('b', null, 'Schritt ' + (i + 1) + ': ' + s.t, h);
    var x = ht('button', 'wkp-dx', '×', h); x.type = 'button'; x.setAttribute('aria-label', 'Schließen');
    x.addEventListener('click', function () { detail(null); });
    if (s.p.length) {
      var di = ht('div', 'wkp-di', null, det);
      each(s.p, function (pid) {
        var g = prozessBild(pid); if (!g) { return; }
        var hb = ht('span', 'wkp-dim', null, di); hb.appendChild(g); ht('small', null, prozessName(pid), hb);
        window.setTimeout(function () { ikNochmal(g); }, 30);
      });
    }
    stufenZeilen(s, det);
  }
  /* Matrix: Zeilen = Bereiche (wie im Bild), Spalten = Stufen und Fertigungswege */
  var alleK = [];
  function markK(liste, an) { each(liste, function (i) { if (kacheln[i]) { kacheln[i].classList.toggle('hl', an); } }); }
  function markM(i, an) { alleK = alleK.filter(function (e) { return !!e.el.parentNode; }); each(alleK, function (e) { if (e.s.indexOf(i) !== -1) { e.el.classList.toggle('hl', an); } }); }
  var kopf2 = ht('div', 'wkp-k wkp-k2', null, box);
  /* Runde 16 (Dimi 11.11.2026, Pruefliste 18.3): alle Ausbaustufen in einer Tabelle, keine Stufenkacheln */
  ht('h4', null, 'Maschinen', kopf2);
  infoKnopf(kopf2.firstChild || kopf2, 'Je Element alle Maschinen, von manuell bis vollautomatisch: AUTO = automatisiert, VOLLAUTO = vollautomatisch, manuell ohne Vermerk. Die Ausbaustufen lassen sich je Element mischen. Zeigen auf eine Karte: links erscheint, was die Maschine bearbeitet. Element zeigen: Bereich im Bild oben hervorheben. Karte antippen: Seite der Maschine öffnen.', { label: 'Bedienung' });
  var kid = KATV[b.id] ? KATV[b.id].id : '';
  /* Runde 18 (Dimi 11.11.2026, 20:13): „wie“ in der Vorlage – die Kartei zeigt die Zeilen eines anderen Bauteils (Kulissenschalldaempfer: Zeilen der Schalldaempferkulisse) */
  var wie = ((DATA.klay || {})[b.id] || {}).wie || '', tb = wie ? (BT[wie] ? wie : b.id) : b.id;
  var zeilen = mtZeilen(kid, [tb]), sp = mtSpalten([tb]);
  /* Zeilenkoepfe (Tabelle und Regler am Handy): leuchten, wenn ihr Bereich oben gezeigt wird (Dimi 09.11.2026, Runde 9) */
  var koepfe = [];
  function koepfeMarkieren(L) {
    koepfe = koepfe.filter(function (e) { return box.contains(e.el); });
    each(koepfe, function (e) { var an = false; each(e.z.ks || [], function (k) { if (L.indexOf(k) !== -1) { an = true; } }); e.el.classList.toggle('hl', an); });
  }
  var mo = {
    ecke: (zeilen.length ? zeilen[0].nr : 0) ? (zeilen[0].id ? 'Element' : 'Bereich') : 'Schritt',
    zeile: function (z, an) { if (!api) { return; } if (tb !== b.id) { return; } if (an) { if ((z.ks || []).length) { api.an(z.ks.length === 1 ? z.ks[0] : z.ks); } } else { api.ab(); } },
    kopf: function (z, el) { koepfe.push({ z: z, el: el }); },
    mini: function (u, el) { var st = u.st[b.id] || []; alleK.push({ s: st, el: el }); el.addEventListener('mouseenter', function () { markK(st, true); }); el.addEventListener('mouseleave', function () { markK(st, false); }); }
  };
  /* Runde 11 der Szene (Dimi 10.11.2026, Runde 12 der Antworten): Entwuerfe A, B, C (42e_entwuerfe.js); Bild des Elements links in der Zeile */
  mo.bild = { pid: tb }; mo.schluessel = kid || tb; mo.teile = [tb];
  /* Runde 17 (Dimi 11.11.2026, 16:23): Aufbau nach Vorlage (DATA.klay: Bauteil, sonst Kategorie), Frage zur Rahmenverbindung in der Zeile „Maschinen“ */
  mo.vorlage = [tb, kid]; mo.kopfZeile = kopf2;
  emTabelle(box, zeilen, sp, kid, mo);
  /* Dimi 11.11.2026, 07:54: nur eine Ausbaustufe (z. B. Wickelfalzrohr): ohne Stufenkachel und ohne die Ueberschrift */
  if (box.querySelector('.em-eins')) { kopf2.hidden = true; }
  if (api) { if (api.zeilen) { api.zeilen(koepfeMarkieren); } }
  /* Runde 13 (Dimi 10.11.2026): der Satz zum Mischen der Stufen steht hinter dem i der Ueberschrift */
  var w = (DATA.wege || {})[b.id];
  if (w) {
    if (w.TA) {
      var ta = ht('div', 'wmx-ta', null, box), fertigTA = {}; ht('b', null, w.TA.t + ': ', ta);
      each(w.TA.m, function (id) {
        var ga = gatVon(id);
        if (!ga) { mxMini(id, ta); return; }
        if (fertigTA[ga.t]) { return; } fertigTA[ga.t] = 1;
        mxGattung(ga, w.TA.m.filter(function (y) { var g2 = gatVon(y); return g2 ? g2.t === ga.t : false; }), ta);
      });
    }
  }
  /* Symbole bewegen sich einmal, wenn sie sichtbar werden */
  if (window.IntersectionObserver) {
    var io = new IntersectionObserver(function (es) { each(es, function (e) { if (e.isIntersecting) { io.unobserve(e.target); e.target.classList.add('go'); } }); }, { threshold: 0.6 });
    each(svgs, function (g) { io.observe(g); });
  } else { each(svgs, function (g) { g.classList.add('go'); }); }
}
/* „Alle Formstücke“ (Dimi 09.11.2026, Runde 11 Punkt 16): alle Maschinen der Kategorie in einer Tabelle (Zeilen = Oberbegriffe),
   ohne Schrittkette. o.element(eid, an): Zeile gezeigt (3D hebt den Bereich im gerade gezeigten Bauteil hervor) */
function alleBlock(info, k, o) {
  o = o || {};
  var box = ht('div', 'wkp', null, info);
  /* Dimi 11.11.2026, 07:54: kein Springen beim Wechsel zwischen „Alle …“ und einem Bauteil: Platz wie die Zeile „Fertigung in … Schritten“ */
  var pl = ht('div', 'wkp-k wkp-auf wkp-platz', null, box); pl.setAttribute('aria-hidden', 'true'); ht('span', 'wkp-px', '▸', pl); ht('span', 'wkp-kt', 'Fertigung', pl);
  var kopf2 = ht('div', 'wkp-k wkp-k2', null, box);
  ht('h4', null, 'Maschinen', kopf2);
  infoKnopf(kopf2.firstChild || kopf2, 'Alle Maschinen für ' + (k.alle ? k.alle.t : k.t) + ', je Element von manuell bis vollautomatisch: AUTO = automatisiert, VOLLAUTO = vollautomatisch. Zeigen auf eine Karte: links erscheint das Formstück, für das die Maschine gilt, mit dem bearbeiteten Bereich. Einzelne Formstücke zeigen ihre Fertigungsschritte. Karte antippen: Seite der Maschine öffnen.', { label: 'Bedienung' });
  var wie = ((DATA.klay || {})[k.id] || {}).wie || '', TE = wie ? (BT[wie] ? [wie] : k.teile) : k.teile;
  var zeilen = mtZeilen(k.id, TE), sp = mtSpalten(TE);
  var mo = { ecke: 'Element', zeile: function (z, an) { if (wie) { return; } if (o.element) { o.element(an ? z.id : null); } }, bild: { pid: wie ? TE[0] : (k.sym || k.teile[0]) }, schluessel: k.id, teile: TE, ohne: k.alleOhne || [], vorlage: wie ? [wie, k.id] : [k.id], kopfZeile: kopf2 };
  emTabelle(box, zeilen, sp, k.id, mo);
  if (box.querySelector('.em-eins')) { kopf2.hidden = true; }
  return box;
}
/* ---------- Maschinen-Matrix (Dimi 09.11.2026: Vorschlag 2 „Bereichs-Matrix“) ----------
   Zeilen: Bereiche des Bauteils wie im Bild (Zuordnung DATA.bj), ohne Zuordnung die Schritte; in der Gruppe die Bauteile.
   Spalten: Manuell, Teilautomatisiert, Vollautomatisiert; hat das Bauteil Fertigungswege (DATA.wege), je Weg eine Spalte.
   Gleiche Inhalte in benachbarten Zeilen stehen als ein Block (z. B. eine Anlage fuer alle Bereiche). */
var STF = { M: 'Manuell', T: 'Automatisiert', V: 'Vollautomatisch' };
function wegKurz(t) { return t.replace(/^(Kanäle|Formstücke) mit /, ''); }
/* Querschnitt der Kanalverbindung als kleines Bild (Dimi 09.11.2026): Steckrahmen = aufgestecktes Hohlprofil mit Tasche,
   PDF = am Kanalblech angeformter, doppelt gelegter Flansch. Schematisch, ohne Mass. Gelb: das, was die Verbindung bildet. */
/* Blechprofil im Querschnitt in Dimis Stil (DATA.prof aus profile_v1.json): Mittellinie mit Blechdicke, gerundete
   Biegungen, im Lupenkreis. o.sw Strichstaerke (Einheiten der 0..100-Box), o.kreis Kreis zeichnen */
function profilSvg(key, par, o) {
  var P = (DATA.prof || {})[key]; if (!P) { return null; }
  o = o || {};
  var s = sv('svg', { viewBox: '0 0 100 100', 'class': o.klasse || 'wpq', 'aria-hidden': 'true', focusable: 'false' }, par);
  /* ohne Kreis (Dimi 09.11.2026, Runde 11 Punkt 23); o.kreis: true zeichnet ihn wie frueher */
  if (o.kreis === true) { sv('circle', { cx: 50, cy: 50, r: 48.5, fill: '#FFFFFF', stroke: '#B9C3CE', 'stroke-width': 2 }, s); }
  /* Profil mittig in den Kreis setzen */
  var b = P.box, cx = (b[0] + b[2]) / 2, cy = (b[1] + b[3]) / 2, w = Math.max(b[2] - b[0], b[3] - b[1]), k = (o.gross || 62) / w;
  /* Runde 14 (Dimi 10.11.2026): o.spiegel spiegelt das Profil an der senkrechten Achse (PDF 3 und PDF 1 liegen dann wie PDF 2) */
  var g = sv('g', { transform: 'translate(50 50) scale(' + (o.spiegel ? '-' : '') + f1(k * 100) / 100 + ' ' + f1(k * 100) / 100 + ') translate(' + f1(-cx * 10) / 10 + ' ' + f1(-cy * 10) / 10 + ')' }, s);
  each(P.teile, function (t) {
    var d = 'M' + t.p.map(function (q) { return q[0] + ' ' + q[1]; }).join(' L');
    var farbe = t.r === 'wand' ? '#8A96A3' : (t.r === 'blech2' ? '#3D6A99' : '#1F3855');
    var sw = (o.sw || 4) / k;
    /* Lupe (Dimi 09.11.2026, Runde 10 der Antworten: eng liegende Lagen wirkten verschmolzen): Blech etwas duenner als echt,
       davor ein weisser Saum, damit Lagen und Teile sichtbar getrennt bleiben */
    if (o.echt) {
      if (t.d) { sw = Math.max(t.d * 0.62, sw); }
      sv('path', { d: d, fill: 'none', stroke: '#FFFFFF', 'stroke-width': f1((sw + (t.d || sw) * 0.45) * 10) / 10, 'stroke-linejoin': 'round', 'stroke-linecap': 'butt' }, g);
    }
    sv('path', { d: d, fill: 'none', stroke: farbe, 'stroke-width': f1(sw * 10) / 10, 'stroke-linejoin': 'round', 'stroke-linecap': 'butt' }, g);
  });
  if (P.raupe) { sv('circle', { cx: P.raupe[0], cy: P.raupe[1], r: f1(Math.max(P.raupe[2], (o.sw || 4) / k * 0.7) * 10) / 10, fill: '#E0A800' }, g); }
  return s;
}
/* Querschnitt fuer die Kopfzeile der Wege: Steckrahmen = eigenes Profil auf der Kanalwand (grau), PDF = die Kanalwand ist
   selbst zum Flansch profiliert (wie PDF 3). Beim Zeigen zoomt das Profil gross auf (profilZoom). */
/* Reihenfolge in der Lupe: PDF 3, PDF 2, PDF 1 Super, PDF 1 (Dimi 09.11.2026, Runde 10 der Antworten) */
var PZ_PDF = ['pdf3', 'pdf2', 'pdf1s', 'pdf1'];
function profilQuer(t, par) {
  var art = /PDF/.test(t) ? 'pdf3' : (/Steckrahmen/.test(t) ? 'steckrahmen' : ''); if (!art) { return null; }
  var s = profilSvg(art, par, { sw: 3, echt: true });
  if (s) {
    s.setAttribute('role', 'img'); s.removeAttribute('aria-hidden'); s.setAttribute('aria-label', art === 'pdf3' ? 'Querschnitt PDF-Flansch' : 'Querschnitt Steckrahmenprofil');
    profilZoom(s, art === 'pdf3' ? PZ_PDF : ['steckrahmen'], art === 'pdf3' ? 'PDF-Flansch' : 'Steckrahmenprofil');
  }
  return s;
}
/* Grosse Ansicht der Profile (Dimi 09.11.2026, Runde 9: die Symbole sind zu klein): Zeigen mit der Maus zoomt das Profil in
   eine Lupe neben dem Symbol; beim PDF-Flansch wechseln PDF 3, PDF 2, PDF 1 Super und PDF 1 nacheinander (1,6 s je Profil,
   weiche Ueberblendung). Ohne Maus oeffnet und schliesst Antippen des Symbols die Lupe. Ein gemeinsames Feld fuer alle. */
var PZ = null;
function pzFeld() {
  if (PZ) { return PZ; }
  var box = ht('div', 'wpz', null, document.body); box.setAttribute('aria-hidden', 'true');
  PZ = { box: box, bild: ht('div', 'wpz-b', null, box), cap: ht('div', 'wpz-t', null, box), sub: ht('div', 'wpz-s', null, box), dots: ht('div', 'wpz-d', null, box), el: null, tm: null, i: 0, keys: [], svgs: [], pt: 'mouse' };
  document.addEventListener('click', function (ev) { if (PZ.el) { if (!PZ.el.contains(ev.target)) { pzZu(); } } }, true);
  window.addEventListener('scroll', function () { if (PZ.el) { pzLage(); } }, { passive: true });
  return PZ;
}
function pzText() {
  var z = PZ, P = (DATA.prof || {})[z.keys[z.i]];
  z.cap.textContent = P ? P.t.replace(/ *\([^)]*\)/g, '') : z.titel;
  z.sub.textContent = z.titel + (gt(z.keys.length, 1) ? ', Profil ' + (z.i + 1) + ' von ' + z.keys.length : '') + ' im Querschnitt';
  each(z.svgs, function (s, j) { s.classList.toggle('auf', j === z.i); });
  each(z.dots.children, function (d, j) { d.classList.toggle('on', j === z.i); });
}
function pzWeiter() { var z = PZ; if (!z.el) { return; } if (!z.el.isConnected) { pzZu(); return; } z.i = (z.i + 1) % z.svgs.length; pzText(); }
function pzLage() {
  var z = PZ; if (!z.el) { return; }
  var r = z.el.getBoundingClientRect(), vw = document.documentElement.clientWidth || window.innerWidth, vh = window.innerHeight || 800;
  var w = z.box.offsetWidth || 244, h = z.box.offsetHeight || 290;
  var x = Math.round(Math.min(Math.max(8, r.left + r.width / 2 - w / 2), vw - w - 8));
  var y = Math.round(gt(r.bottom + 10 + h, vh - 8) ? r.top - 10 - h : r.bottom + 10);
  if (lt(y, 8)) { y = 8; }
  z.box.style.left = x + 'px'; z.box.style.top = y + 'px';
  z.box.classList.toggle('oben', lt(y, r.top));
}
function pzAuf(el, keys, titel) {
  var z = pzFeld();
  if (z.el === el) { return; }
  pzZu();
  z.el = el; z.keys = keys; z.i = 0; z.titel = titel; z.svgs = [];
  while (z.bild.firstChild) { z.bild.removeChild(z.bild.firstChild); }
  while (z.dots.firstChild) { z.dots.removeChild(z.dots.firstChild); }
  each(keys, function (k) { var s = profilSvg(k, z.bild, { klasse: 'wpz-p', sw: 1.6, gross: 76, echt: true }); if (s) { z.svgs.push(s); if (gt(keys.length, 1)) { ht('i', null, null, z.dots); } } });
  if (!z.svgs.length) { z.el = null; return; }
  z.dots.hidden = !gt(z.svgs.length, 1);
  pzText(); pzLage();
  z.box.classList.add('auf');
  if (gt(z.svgs.length, 1)) { z.tm = window.setInterval(pzWeiter, BEWEGUNG ? 1600 : 2600); }
}
function pzZu() {
  var z = PZ; if (!z) { return; }
  if (z.tm) { window.clearInterval(z.tm); z.tm = null; }
  z.el = null; z.box.classList.remove('auf');
}
function profilZoom(el, keys, titel) {
  el.classList.add('wpz-z');
  el.addEventListener('pointerdown', function (ev) { pzFeld().pt = ev.pointerType || 'mouse'; });
  el.addEventListener('pointerenter', function (ev) { if (ev.pointerType === 'mouse') { pzAuf(el, keys, titel); } });
  el.addEventListener('pointerleave', function (ev) { if (ev.pointerType === 'mouse') { if (PZ) { if (PZ.el === el) { pzZu(); } } } });
  /* ohne Maus: Antippen oeffnet bzw. schliesst die Lupe und schaltet den Weg nicht um */
  el.addEventListener('click', function (ev) {
    if (pzFeld().pt === 'mouse') { return; }
    ev.stopPropagation(); ev.preventDefault();
    if (PZ.el === el) { pzZu(); } else { pzAuf(el, keys, titel); }
  });
}
function mxSpalten(b) {
  /* Runde 13 der Szene (Dimi 10.11.2026): Wege auch in Manuell (Rechteckkanal mit Steckrahmen oder PDF-Flansch) */
  var w = (DATA.wege || {})[b.id] || {}, sp = [];
  each(['M', 'T', 'V'], function (q) {
    if (w[q]) { each(w[q], function (g) { sp.push({ q: q, w: g }); }); return; }
    /* Vollautomatische Anlage, die alle Bereiche vereint (z. B. PR oder SWA): ein Block ohne Weg */
    if (q === 'V') { if (w.VB) { sp.push({ q: q, blk: w.VB }); return; } }
    sp.push({ q: q });
  });
  return sp;
}
function mxZeilen(b) {
  var bj = (DATA.bj || {})[b.id], z = [], rest = [];
  if (!bj) {
    each(b.schritte, function (s, i) { z.push({ t: s.t, nr: 0, sn: i + 1, ks: [], nrs: [], s: [i] }); });
    return z;
  }
  each(b.bereiche, function (t, k) { z.push({ t: t.replace(/ *\([^)]*\)/g, ''), nr: k + 1, k: k, ks: [k], nrs: [k + 1], s: [] }); });
  each(b.schritte, function (s, i) {
    each(bj[i], function (k) {
      if (k === -1) { rest.push({ t: s.t.split(':')[0], nr: 0, k: -1, ks: [], nrs: [], s: [i] }); return; }
      if (z[k]) { z[k].s.push(i); }
    });
  });
  return z.filter(function (x) { return x.s.length !== 0; }).concat(rest);
}
/* Inhalt einer Zelle: Maschinen der Schritte st in der Stufe der Spalte; bei einem Fertigungsweg nur dessen Maschinen */
function mxZelle(b, st, sp) {
  var ms = [], hand = [], wo = {}, ref = [];
  if (sp.blk) {
    each(sp.blk.m || [], function (id) { if (masch(id)) { ms.push(id); wo[id] = (sp.blk.s || []).slice(); } });
    if (sp.blk.dazu) { hand.push(sp.blk.dazu); }
    return { ms: ms, hand: hand, wo: wo, block: 1 };
  }
  if (sp.w) {
    if (!sp.w.st) {
      /* Vollautomatischer Weg: eine Anlage fuer alle Zeilen */
      each(sp.w.m || [], function (id) { if (masch(id)) { ms.push(id); wo[id] = (sp.w.s || []).slice(); } });
      if (sp.w.dazu) { hand.push(sp.w.dazu); }
      return { ms: ms, hand: hand, wo: wo, block: 1 };
    }
  }
  var filt = null, fs = null;
  if (sp.w) { filt = {}; each(sp.w.st, function (x) { each(x.m, function (id) { filt[id] = 1; }); }); }
  /* Runde 14: Wege je Schritt (rechteckige Formstuecke): die Maschine gilt nur in den Schritten, fuer die sie genannt ist */
  if (sp.w ? !!sp.w.jeSchritt : false) { fs = {}; each(sp.w.st, function (x) { each(x.s, function (i) { if (!fs[i]) { fs[i] = {}; } each(x.m, function (id) { fs[i][id] = 1; }); }); }); }
  each(st, function (i) {
    each(b.schritte[i][sp.q] || [], function (id) {
      var m = masch(id); if (!m) { return; }
      if (m.k) { if (ref.indexOf(m.k) === -1) { ref.push(m.k); } return; }
      if (m.z) { if (hand.indexOf(m.mb) === -1) { hand.push(m.mb); } return; }
      if (fs) { if (!(fs[i] ? fs[i][id] : false)) { return; } } else if (filt) { if (!filt[id]) { return; } }
      if (!wo[id]) { wo[id] = []; ms.push(id); }
      if (wo[id].indexOf(i) === -1) { wo[id].push(i); }
    });
  });
  if (sp.w) {
    each(sp.w.st, function (x) {
      if (!x.dazu) { return; }
      var hit = false; each(x.s, function (i) { if (st.indexOf(i) !== -1) { hit = true; } });
      if (hit) { if (hand.indexOf(x.dazu) === -1) { hand.push(x.dazu); } }
    });
  }
  return { ms: ms, hand: hand, wo: wo, ref: ref };
}
/* Leere Spalten fallen weg (Dimi 09.11.2026, Runde 9: bei Formteilen gibt es keine vollautomatisierte Stufe) */
function mxFrei(b, zeilen, sp) {
  var r = sp.filter(function (c) {
    var voll = false;
    each(zeilen, function (z) { var x = mxZelle(b, z.s, c); if (x.ms.length + x.hand.length + (x.ref ? x.ref.length : 0)) { voll = true; } });
    return voll;
  });
  return r.length ? r : sp;
}
/* Bereiche zusammenlegen (Dimi 09.11.2026, Runde 9): damit dieselbe Maschine nicht mehrfach erscheint, stehen zwei Bereiche
   in einer Zeile, wenn in jeder Spalte die Maschinen des einen in denen des anderen enthalten sind (z. B. Seitenblech und
   Mantelblech: Tafelscheren). Leere Zellen passen nur zu leeren; Zeilen ohne Maschine oder ohne Nummer bleiben fuer sich,
   Bloecke (eine Anlage fuer alle Bereiche) zaehlen nicht. */
function mxMengen(b, z, sp) {
  var r = [], ok = false;
  each(sp, function (c) {
    if (c.blk) { r.push(null); return; }
    if (c.w) { if (!c.w.st) { r.push(null); return; } }
    var x = mxZelle(b, z.s, c); r.push(x.ms.slice()); if (x.ms.length) { ok = true; }
  });
  return ok ? r : null;
}
function mxTeil(a, c) { var ok = true; each(a, function (x) { if (c.indexOf(x) === -1) { ok = false; } }); return ok; }
function mxPasst(A, C) {
  var ok = true;
  each(A, function (a, j) {
    var c = C[j]; if (a === null || c === null) { return; }
    if (!a.length || !c.length) { if (a.length !== c.length) { ok = false; } return; }
    if (!mxTeil(a, c)) { if (!mxTeil(c, a)) { ok = false; } }
  });
  return ok;
}
function mxZusammen(b, zeilen, sp) {
  var r = [];
  each(zeilen, function (z) {
    var A = z.nr ? mxMengen(b, z, sp) : null;
    if (A) {
      for (var i = 0; i !== r.length; i++) {
        var g = r[i];
        if (g.M) {
          if (mxPasst(A, g.M)) {
            g.t = g.t + ', ' + z.t; g.ks = g.ks.concat(z.ks); g.nrs = g.nrs.concat(z.nrs);
            each(z.s, function (x) { if (g.s.indexOf(x) === -1) { g.s.push(x); } });
            g.M = mxMengen(b, g, sp); return;
          }
        }
      }
    }
    r.push({ t: z.t, nr: z.nr, sn: z.sn, k: z.k, ks: z.ks || [], nrs: z.nrs || [], s: z.s.slice(), M: A });
  });
  return r;
}
/* Kleine Maschinenkarte in der Matrix: Symbol, Typ; Link zur Maschinenseite; Merkliste */
function mxMini(id, par) {
  var m = masch(id); if (!m) { return null; }
  var link = m.u ? (m.g ? '' : seitenUrl(m.u)) : '';
  var c = ht(link ? 'a' : 'span', 'wmx-m' + (m.g ? ' g' : ''), null, par);
  if (link) { c.href = link; }
  var s = ht('span', 'wmx-s', null, c);
  if (!m.g) { platzIcon(s, id); }
  var ty = tyZeigen(m), te = tyEcht(m);
  ht('small', null, m.g ? m.mb : (te || m.mb), c);
  c.title = m.mb + (ty ? ' ' + ty : '') + (m.b ? ' (' + m.b + ')' : '') + (m.g ? ': nicht im Programm' : (m.zk ? ': auf Anfrage' : ''));
  if (!m.g) { merkKnopf(c, id); }
  return c;
}
function mxSchluessel(c) { return c.block ? 'B' : c.ms.join(',') + '|' + c.hand.join(','); }
/* Zellen berechnen und gleiche Inhalte benachbarter Zeilen je Spalte zusammenfassen */
function mxModell(zeilen, sp, zelleFn) {
  var nz = zeilen.length, C = [], span = [], deckt = [];
  each(zeilen, function (z, r) { C.push([]); span.push([]); deckt.push([]); each(sp, function (c) { C[r].push(zelleFn(z, c)); }); });
  each(sp, function (c, j) {
    var r0 = 0;
    for (var r = 0; r !== nz; r++) {
      span[r][j] = 1; deckt[r][j] = false;
      if (r !== 0) { if (mxSchluessel(C[r][j]) === mxSchluessel(C[r0][j])) { span[r0][j]++; deckt[r][j] = true; continue; } }
      r0 = r;
    }
  });
  return { C: C, span: span, deckt: deckt, nz: nz };
}
/* Maschinenfamilien (verfahren_v1.json maschinenFamilien, z. B. Faserlaser): stehen mehrere Mitglieder in einer Zelle,
   zeigt die Tabelle eine Karte fuer alle (ruhiger) */
var FAM = null;
function famVon(id) {
  if (!FAM) { FAM = {}; each(DATA.fam || [], function (f, i) { each(f.m, function (x) { FAM[x] = i; }); }); }
  return FAM[id];
}
function mxFamilie(f, mem, par) {
  var m0 = masch(mem[0]), link = m0.u ? seitenUrl(m0.u) : '';
  var c = ht(link ? 'a' : 'span', 'wmx-m wmx-f', null, par);
  if (link) { c.href = link; }
  var s = ht('span', 'wmx-s', null, c); platzIcon(s, mem[0]);
  ht('small', null, f.t, c);
  c.title = m0.mb + ': ' + mem.map(function (y) { var m = masch(y); return tyEcht(m) || m.mb; }).join(', ') + (m0.b ? ' (' + m0.b + ')' : '');
  return c;
}
/* Maschinengattungen (Dimi 09.11.2026): unter den Symbolen steht der Fachbegriff der Familie statt des Modellnamens
   (verfahren_v1.json maschinenGattung, „|“ = moegliche Trennstelle). Mehrere Maschinen derselben Gattung in einer Zelle
   stehen als eine Karte; die Modelle nennt der Hinweis beim Zeigen. */
function gatVon(id) { var g = (DATA.gat || {})[id]; return g ? g : null; }
/* Trennstellen: weiches Trennzeichen; endet das Stueck schon mit Bindestrich (CAD/CAM-|Software), nur ein Umbruchpunkt */
function gatText(t, trenn) {
  var a = t.split('|'), r = a[0];
  for (var i = 1; i !== a.length; i++) { r += (trenn ? (/-$/.test(a[i - 1]) ? '\u200b' : '\u00ad') : '') + a[i]; }
  return r;
}
function gatEltern(mem) {
  var u = null, ok = true;
  each(mem, function (y) { var m = masch(y); if (!m.u) { ok = false; return; } var e = m.u.replace(/\/[^\/]*$/, ''); if (u === null) { u = e; } else if (u !== e) { ok = false; } });
  return ok ? u : '';
}
function mxGattung(ga, mem, par) {
  var m0 = masch(mem[0]), eins = mem.length === 1;
  var url = ga.u || (eins ? (m0.u || '') : (gatEltern(mem) || m0.u || ''));
  var link = url ? (m0.g ? '' : seitenUrl(url)) : '';
  var c = ht(link ? 'a' : 'span', 'wmx-m wmx-f' + (m0.g ? ' g' : ''), null, par);
  if (link) { c.href = link; }
  var s = ht('span', 'wmx-s', null, c); if (!m0.g) { platzIcon(s, mem[0]); }
  ht('small', null, gatText(ga.t, true), c);
  c.title = gatText(ga.t, false) + ': ' + mem.map(function (y) { var m = masch(y), te = tyEcht(m); return (te ? m.mb + ' ' + te : m.mb) + (m.b ? ' (' + m.b + ')' : ''); }).join(', ');
  if (eins) { if (!m0.g) { merkKnopf(c, mem[0]); } }
  return c;
}
function mxInhalt(td, x, ganz, o) {
  if (!(x.ms.length + x.hand.length)) {
    td.classList.add('leer');
    ht('span', 'wmx-l', ganz ? 'nicht vorgesehen' : '–', td).title = 'In dieser Stufe keine Maschine';
    return;
  }
  if (x.ms.length) {
    var g = ht('div', 'wmx-g', null, td), fertig = {}, fertigG = {};
    each(x.ms, function (id) {
      var fi = famVon(id), el = null, st = x.wo[id] || [], ga = gatVon(id);
      if (ga) {
        if (fertigG[ga.t]) { return; }
        fertigG[ga.t] = 1;
        var memG = x.ms.filter(function (y) { var g2 = gatVon(y); return g2 ? g2.t === ga.t : false; });
        st = []; each(memG, function (y) { each(x.wo[y] || [], function (i) { if (st.indexOf(i) === -1) { st.push(i); } }); });
        el = mxGattung(ga, memG, g);
      } else if (fi !== undefined) {
        if (fertig[fi]) { return; }
        var mem = x.ms.filter(function (y) { return famVon(y) === fi; });
        if (gt(mem.length, 1)) {
          fertig[fi] = 1; st = [];
          each(mem, function (y) { each(x.wo[y] || [], function (i) { if (st.indexOf(i) === -1) { st.push(i); } }); });
          el = mxFamilie(DATA.fam[fi], mem, g);
        }
      }
      if (!el) { el = mxMini(id, g); }
      if (el) { if (o.mini) { o.mini(id, st, el); } }
    });
  }
  if (x.hand.length) { ht('div', 'wmx-h', x.hand.join(' · '), td); }
}
function mxZeilenkopf(el, z, o) {
  if ((z.nrs || []).length) { var nb = ht('span', 'wmx-nr', null, el); each(z.nrs, function (x) { ht('i', null, String(x), nb); }); } else if (z.sn) { ht('i', 'sn', String(z.sn), el); }
  ht('span', null, z.t, el);
  if (o.kopf) { o.kopf(z, el); }
  if (o.zeile) { el.addEventListener('mouseenter', function () { o.zeile(z, true); }); el.addEventListener('mouseleave', function () { o.zeile(z, false); }); }
  if (o.klick) {
    el.classList.add('kl'); el.setAttribute('tabindex', '0'); el.setAttribute('role', 'button');
    el.addEventListener('click', function () { o.klick(z, el); });
    el.addEventListener('keydown', function (ev) { if (ev.key === 'Enter' || ev.key === ' ') { ev.preventDefault(); o.klick(z, el); } });
  }
}
function mxTabelle(par, zeilen, sp, zelleFn, o) {
  o = o || {};
  var M = mxModell(zeilen, sp, zelleFn), nz = M.nz;
  var wrap = ht('div', 'wmx-w', null, par), tb = ht('table', 'wmx', null, wrap);
  var wege = false; each(sp, function (c) { if (c.w) { wege = true; } });
  /* Kopf: Stufen, darunter die Wege */
  var h1 = ht('tr', null, null, tb), ec = ht('th', 'wmx-ec', o.ecke || '', h1);
  if (wege) { ec.rowSpan = 2; }
  each(['M', 'T', 'V'], function (q) {
    var idx = []; each(sp, function (c, j) { if (c.q === q) { idx.push(j); } });
    if (!idx.length) { return; }
    var th = ht('th', 'wmx-q ' + q, null, h1);
    ht('b', null, STF[q], th);
    var mitWeg = false; each(idx, function (j) { if (sp[j].w) { mitWeg = true; } });
    if (idx.length !== 1) { th.colSpan = idx.length; } else if (wege) { if (!mitWeg) { th.rowSpan = 2; } }
  });
  if (wege) {
    var h2 = ht('tr', null, null, tb);
    each(sp, function (c) { if (c.w) { var t = ht('th', 'wmx-w2 ' + c.q, null, h2); profilQuer(c.w.t, t); ht('span', null, wegKurz(c.w.t), t).title = c.w.t; } });
  }
  each(zeilen, function (z, r) {
    var tr = ht('tr', null, null, tb);
    var th = ht('th', 'wmx-z', null, tr); th.scope = 'row';
    mxZeilenkopf(th, z, o);
    each(sp, function (c, j) {
      if (M.deckt[r][j]) { return; }
      var td = ht('td', c.q, null, tr);
      if (gt(M.span[r][j], 1)) { td.rowSpan = M.span[r][j]; td.classList.add('blk'); }
      mxInhalt(td, M.C[r][j], M.span[r][j] === nz, o);
    });
  });
  return M;
}
/* Handy (Dimi 09.11.2026, Idee A): Stufen-Regler statt Tabelle. Dieselben Zeilen; der Regler waehlt die Spalte,
   bei Fertigungswegen ein Umschalter. Zusammengefasste Bereiche stehen als ein Block, bei Voll meist eine Anlage. */
function mxRegler(par, zeilen, sp, M, o) {
  o = o || {};
  var stufen = ['M', 'T', 'V'].filter(function (q) { var da = false; each(sp, function (c) { if (c.q === q) { da = true; } }); return da; }), wsel = { T: 0, V: 0 }, wort = o.wort || 'Bereiche';
  var box = ht('div', 'wrg', null, par);
  ht('div', 'wrg-f', 'Wie automatisiert wollen Sie fertigen?', box);
  var bahn = ht('div', 'wrg-b', null, box);
  var inp = ht('input', 'wrg-i', null, bahn);
  inp.type = 'range'; inp.min = '0'; inp.max = String(stufen.length - 1); inp.step = '1'; inp.value = '0'; inp.setAttribute('aria-label', 'Ausbaustufe: ' + stufen.map(function (q) { return STF[q]; }).join(' oder '));
  if (lt(stufen.length, 2)) { bahn.hidden = true; }
  var lab = ht('div', 'wrg-l', null, box), lb = [];
  each(stufen, function (q, i) { var x = ht('button', null, STF[q], lab); x.type = 'button'; x.addEventListener('click', function () { inp.value = String(i); setz(); }); lb.push(x); });
  var wg = ht('div', 'wrg-w', null, box), satz = ht('div', 'wrg-s', null, box), gitter = ht('div', 'wrg-g', null, box);
  function setz() {
    var i = parseInt(inp.value, 10) || 0, q = stufen[i], idx = [];
    each(sp, function (c, j) { if (c.q === q) { idx.push(j); } });
    inp.setAttribute('aria-valuetext', STF[q]);
    each(lb, function (x, k) { x.classList.toggle('on', k === i); });
    while (wg.firstChild) { wg.removeChild(wg.firstChild); }
    var wi = wsel[q] || 0; if (!gt(idx.length, wi)) { wi = 0; }
    var einzeln = idx.length === 1 ? !!sp[idx[0]].w : false;
    wg.hidden = !(gt(idx.length, 1) || einzeln);
    if (gt(idx.length, 1)) {
      each(idx, function (j, k) {
        var b = ht('button', k === wi ? 'on' : null, null, wg); b.type = 'button'; b.title = sp[j].w.t;
        profilQuer(sp[j].w.t, b); ht('span', null, wegKurz(sp[j].w.t), b);
        b.setAttribute('aria-pressed', k === wi ? 'true' : 'false');
        b.addEventListener('click', function () { wsel[q] = k; hinweisFertig = true; setz(); });
      });
    } else if (einzeln) { var w1 = ht('span', 'wrg-w1', null, wg); profilQuer(sp[idx[0]].w.t, w1); ht('span', null, 'nur mit ' + wegKurz(sp[idx[0]].w.t), w1); }
    zeichne(idx[wi], q);
    if (gt(idx.length, 1)) { window.setTimeout(hinweis, 250); }
  }
  function zeichne(j, q) {
    var neu = ht('div', 'wrg-g ' + q + (BEWEGUNG ? ' wrg-neu' : ''));
    gitter.parentNode.replaceChild(neu, gitter); gitter = neu;
    var bloecke = 0, voll = false, leer = true;
    each(zeilen, function (z, r) { var th = ht('div', 'wrg-z', null, gitter); th.style.gridRow = String(r + 1); mxZeilenkopf(th, z, o); });
    each(zeilen, function (z, r) {
      if (M.deckt[r][j]) { return; }
      var x = M.C[r][j], n = M.span[r][j], td = ht('div', 'wrg-c', null, gitter);
      td.style.gridRow = (r + 1) + ' / span ' + n; td.style.gridColumn = '2';
      if (x.ms.length + x.hand.length) { leer = false; }
      if (gt(n, 1)) { td.classList.add('blk'); if (x.ms.length) { bloecke++; if (n === M.nz) { voll = true; td.classList.add('ganz'); } } }
      mxInhalt(td, x, n === M.nz, o);
    });
    satz.textContent = leer ? 'In dieser Stufe nicht vorgesehen.' : (voll ? 'Eine Anlage fertigt alle ' + wort + '.' : (bloecke ? (wort === 'Bauteile' ? 'Gleiche Maschinen für mehrere Bauteile.' : 'Eine Maschine fertigt mehrere Bereiche zusammen.') : 'Je ' + (wort === 'Bauteile' ? 'Bauteil' : 'Bereich') + ' eigene Maschinen.'));
  }
  /* Hinweis (Dimi 09.11.2026): Beim ersten Sichtbarwerden des Umschalters leuchten die beiden Felder kurz abwechselnd auf */
  var hinweisFertig = false;
  function hinweis() {
    if (hinweisFertig) { return; } if (!BEWEGUNG) { return; } if (wg.hidden) { return; }
    var r = wg.getBoundingClientRect(); if (!r.height) { return; }
    if (!(gt(window.innerHeight - 30, r.top) ? gt(r.bottom, 30) : false)) { return; }
    hinweisFertig = true; wg.classList.add('wrg-blink');
    window.setTimeout(function () { wg.classList.remove('wrg-blink'); }, 2700);
  }
  if (window.IntersectionObserver) {
    var io = new IntersectionObserver(function (es) { each(es, function (e) { if (e.isIntersecting) { hinweis(); } }); }, { threshold: 1 });
    io.observe(wg);
  }
  inp.addEventListener('input', setz); inp.addEventListener('change', setz);
  setz();
  return box;
}
var CSSK = [
  '.wkp{margin:8px 0 0 0}',
  /* Bauteile der Kategorie als kleine Kacheln oben in der Kartei (Runde 9 der Szene) */
  '.wkg-f{display:flex;flex-wrap:wrap;gap:6px}',
  '.wps-b{display:flex;align-items:center;justify-content:center}.wps-b img{display:block;max-width:100%;max-height:100%}',
  '.wkg-c{display:flex;flex-direction:column;align-items:center;width:86px;padding:4px 4px 5px 4px;font:inherit;background:#fff;border:1px solid #d5dde6;color:#1A1D21;cursor:pointer;text-align:center}',
  '.wkg-c:hover{border-color:#1F3855}',
  '.wkg-c.on{border-color:#E0A800;background:#FFF5D1;box-shadow:inset 0 0 0 1px #E0A800}',
  '.wkg-ci{display:flex;align-items:center;justify-content:center;width:68px;height:46px}',
  '.wkg-ci img{max-width:100%;max-height:100%}',
  '.wkg-ct{font-size:11px;line-height:13px;margin-top:2px;max-width:100%;-webkit-hyphens:auto;hyphens:auto;overflow-wrap:anywhere}',
  '.wkp-mf{display:flex;flex-wrap:wrap;align-items:center;gap:3px;margin-top:5px}',
  '.wkp-mf small{font-size:11px;color:#5C6670;margin-right:2px}',
  '.wkp-mf i{font-style:normal;font-size:11px;line-height:15px;padding:0 5px;border:1px solid #d5dde6;background:#F3F5F8;color:#1F3855}',
  '.wkp-tx{font-size:15px;line-height:22px;color:#1A1D21;margin:4px 0 10px 0;max-width:860px}',
  '.wkp-tx .wsz-tag{margin-left:6px}',
  '.wkp-k{display:flex;align-items:baseline;justify-content:space-between;gap:4px 12px;flex-wrap:wrap;margin:0 0 7px 0}',
  '.wkp-k h4{margin:0;font-size:12px;text-transform:uppercase;letter-spacing:.04em;color:#1F3855}',
  '.wkp-hw{font-size:12px;color:#6E737A}',
  '.wkp-r{display:flex;flex-wrap:wrap;align-items:center;gap:6px 3px}',
  '.wkp-pf{color:#9AA5B1;font-size:18px;line-height:18px}',
  '.wkp-s{position:relative;display:flex;flex-direction:column;align-items:center;width:94px;min-height:122px;padding:6px 5px 10px 5px;background:#fff;border:1px solid #d5dde6;cursor:pointer;font:inherit;color:#1A1D21;text-align:center;transition:opacity .2s,border-color .15s}',
  '.wkp-s:hover{border-color:#1F3855}',
  '.wkp-s.auf{border-color:#1F3855;box-shadow:inset 0 0 0 2px #1F3855}',
  '.wkp-s.hl{border-color:#E0A800;box-shadow:inset 0 0 0 2px #F7BC0C}',
  '.wkp-n{position:absolute;top:3px;left:5px;font-size:11px;font-weight:700;color:#1F3855}',
  '.wkp-i{position:relative;display:block;width:74px;height:54px}',
  '.wkp-i .wps{width:100%;height:100%}',
  '.wkp-i.leer{background:repeating-linear-gradient(45deg,#f3f5f8 0 4px,#fff 4px 8px)}',
  '.wkp-mehr{position:absolute;right:-6px;bottom:-3px;font-size:10px;font-weight:700;background:#E9EDF2;color:#1F3855;padding:0 3px}',
  '.wkp-t{display:-webkit-box;-webkit-line-clamp:3;-webkit-box-orient:vertical;overflow:hidden;font-size:11px;line-height:13px;margin:5px 0 0 0}',
  '.wkp-tag{position:absolute;top:2px;right:2px;font-size:9px;font-weight:700;background:#F7BC0C;color:#1A1D21;padding:0 3px}',
  '.wkp-b{position:absolute;left:-1px;right:-1px;bottom:-1px;height:6px;display:flex;gap:1px}',
  '.wkp-b i{flex:1 1 0;background:#E6EAEF}',
  '.wkp-b i.M.ja,.wkp-b i.T.ja,.wkp-b i.V.ja{background:#1F3855}',
  '.wkp-b i.hand{background:repeating-linear-gradient(90deg,#9AA5B1 0 3px,#E6EAEF 3px 6px)}',
  '.wkp-k2{margin:12px 0 2px 0}',
  '.wkp-st{margin:12px 0 0 0;padding:2px 0 4px 12px;border-left:5px solid #1F3855}',
  '.wkp-st.T,.wkp-st.V{border-left-color:#1F3855}',
  '.wkp-sth{display:flex;align-items:baseline;flex-wrap:wrap;gap:2px 10px;margin:0 0 8px 0}',
  '.wkp-sth b{font-size:16px;line-height:21px;color:#1A1D21}',
  '.wkp-sth small{font-size:12px;color:#6E737A}',
  '.wkp-st .wkp-no:first-of-type{margin-top:4px}',
  '.wkp-d{margin:8px 0 0 0;background:#fff;border:1px solid #1F3855;padding:10px 12px 12px 12px}',
  '.wkp-dh{display:flex;justify-content:space-between;align-items:flex-start;gap:10px;font-size:14px;line-height:19px;color:#1F3855}',
  '.wkp-dx{border:0;background:none;font-size:24px;line-height:18px;color:#1F3855;cursor:pointer;padding:0 2px}',
  '.wkp-di{display:flex;flex-wrap:wrap;gap:10px;margin:8px 0 4px 0}',
  '.wkp-dim{display:flex;flex-direction:column;align-items:center;width:120px}',
  '.wkp-dim .wps{width:120px;height:86px}',
  '.wkp-dim small{font-size:11px;line-height:14px;color:#5C6670;text-align:center;margin-top:2px}',
  '.wkp-mg{display:grid;grid-template-columns:repeat(auto-fill,minmax(255px,1fr));gap:8px}',
  '.wkp-mc{position:relative;display:flex;gap:10px;align-items:flex-start;padding:7px 40px 8px 7px;background:#fff;border:1px solid #d5dde6;color:#1A1D21;text-decoration:none;transition:border-color .15s}',
  'a.wkp-mc:hover{border-color:#1F3855}',
  '.wkp-mc.hl{border-color:#E0A800;box-shadow:inset 0 0 0 2px #F7BC0C}',
  '.wkp-mc.g{border-style:dashed;background:#FAFBFC}',
  '.wkp-mb{flex:0 0 78px;height:58px;display:flex;align-items:center;justify-content:center;background:#f3f5f8;overflow:hidden}',
  '.wkp-mb img{width:100%;height:100%;object-fit:cover}',
  '.wkp-mb .wps{width:100%;height:100%}',
  '.wkp-mc.g .wkp-mb{background:transparent}',
  '.wkp-mt{display:flex;flex-direction:column;min-width:0}',
  '.wkp-m1{font-size:11px;line-height:14px;color:#6E737A}',
  '.wkp-m2{font-size:14px;line-height:18px;font-weight:700;color:#1F3855}',
  '.wkp-m2.ph{color:#9AA3AD;font-weight:400;font-style:italic;font-size:12px}',
  '.wkp-m2.ng{color:#8A9099;font-weight:400;font-size:12px}',
  '.wkp-m3{font-size:11px;line-height:14px;color:#8A9099}',
  '.wkp-ms{display:flex;flex-wrap:wrap;align-items:center;gap:3px;margin-top:5px}',
  '.wkp-ms small{font-size:11px;color:#5C6670;margin-right:2px}',
  '.wkp-ms i{font-style:normal;font-size:11px;font-weight:700;min-width:17px;height:17px;line-height:17px;text-align:center;color:#fff;background:#1F3855;border-radius:9px;padding:0 3px;box-sizing:border-box}',
  '[data-st=T] .wkp-ms i,[data-st=V] .wkp-ms i{background:#1F3855}',
  '.wkp-mc .wmk-pl{top:7px;right:7px;width:27px;height:27px;font-size:17px;line-height:24px}',
  '.wkp-no{font-size:13px;line-height:19px;color:#4B5563;margin:9px 0 0 0}',
  '.wkp-alle{font:inherit;font-size:13px;margin:10px 0 0 0;padding:6px 12px;border:1px solid #1F3855;background:#fff;color:#1F3855;cursor:pointer}',
  '.wkp-alle:hover{background:#1F3855;color:#fff}',
  '.wkp-auf{width:100%;justify-content:flex-start;align-items:center;font:inherit;text-align:left;background:#fff;border:1px solid #c3ccd6;padding:8px 10px;cursor:pointer;color:#1F3855;margin:0 0 8px 0}',
  '.wkp-auf:hover{border-color:#1F3855}',
  '.wkp-platz{visibility:hidden;pointer-events:none}',
  '.wkp-px{flex:0 0 auto;font-size:13px;color:#1F3855}',
  '.wkp-kt{font-size:12px;font-weight:700;text-transform:uppercase;letter-spacing:.04em;color:#1F3855}',
  '.wkp-auf .wkp-hw{margin-left:auto}',
  '.wkp-r{margin:0 0 8px 0}',
  '.wmx-w{overflow-x:auto;-webkit-overflow-scrolling:touch;margin:2px -4px 0 -4px}',
  '.wmx{border-collapse:separate;border-spacing:4px;width:100%;min-width:660px;table-layout:fixed}',
  '.wmx th,.wmx td{vertical-align:top;text-align:left}',
  '.wmx-ec{width:150px;font-size:12px;font-weight:700;color:#6E737A;text-transform:uppercase;letter-spacing:.04em;padding:6px 4px;vertical-align:bottom!important}',
  '.wmx-q{padding:6px 8px;color:#fff;background:#1F3855}',
  '.wmx-q b{display:block;font-size:13px;line-height:17px}',
  '.wmx-q small{display:block;font-size:11px;line-height:14px;font-weight:400;opacity:.92}',
  '.wmx-q.T,.wmx-q.V{background:#1F3855}',
  '.wmx-w2{font-size:12px;line-height:15px;font-weight:700;color:#1F3855;background:#E9EDF2;padding:4px 8px}',
  '.wmx-w2 .wpq{display:inline-block;vertical-align:middle;width:40px;height:40px;margin:-7px 8px -7px -2px}',
  /* Lupe der Profile (Runde 9) */
  '.wpz-z{cursor:zoom-in;transition:transform .15s}',
  '.wpz-z:hover{transform:scale(1.12)}',
  '.wpz{position:fixed;left:0;top:0;z-index:2147483000;width:244px;box-sizing:border-box;padding:10px 12px 9px;background:#fff;border:1px solid #c3ccd6;border-top:3px solid #1F3855;box-shadow:0 10px 28px rgba(31,56,85,.25);opacity:0;visibility:hidden;transform:translateY(-6px) scale(.94);transform-origin:50% 0;transition:opacity .18s ease,transform .2s ease,visibility 0s linear .2s;pointer-events:none;font-family:Arial,Helvetica,sans-serif}',
  '.wpz.oben{transform-origin:50% 100%;transform:translateY(6px) scale(.94)}',
  '.wpz.auf{opacity:1;visibility:visible;transform:none;transition:opacity .18s ease,transform .2s ease}',
  '.wpz-b{position:relative;width:218px;height:218px;margin:0 auto}',
  '.wpz-p{position:absolute;left:0;top:0;width:100%;height:100%;opacity:0;transition:opacity .5s ease}',
  '.wpz-p.auf{opacity:1}',
  '.wpz-t{margin:6px 0 0 0;font-size:15px;line-height:19px;font-weight:700;color:#1F3855;text-align:center}',
  '.wpz-s{font-size:11px;line-height:14px;color:#6E737A;text-align:center;margin:1px 0 0 0}',
  '.wpz-d{display:flex;justify-content:center;gap:5px;margin:6px 0 0 0}',
  '.wpz-d[hidden]{display:none}',
  '.wpz-d i{width:7px;height:7px;border-radius:50%;background:#C9D2DC;transition:background .3s}',
  '.wpz-d i.on{background:#1F3855}',
  '@media (prefers-reduced-motion:reduce){.wpz,.wpz-p,.wpz-z{transition:none}}',
  '.wmx-w2 span{vertical-align:middle}',
  '.wrg-w button .wpq,.wrg-w1 .wpq{display:inline-block;vertical-align:middle;width:28px;height:28px;margin:-3px 6px -3px 0}',
  '.wrg-w button span,.wrg-w1 span{vertical-align:middle}',
  '.wmx-z{font-size:13px;line-height:17px;font-weight:400;color:#1A1D21;background:#f3f5f8;padding:7px 8px;position:sticky;left:0;z-index:2;transition:background .15s;-webkit-hyphens:auto;hyphens:auto;overflow-wrap:break-word}',
  '.wmx-z i{display:inline-block;width:20px;height:20px;line-height:20px;text-align:center;font-style:normal;font-size:11px;background:#fff;color:#1F3855;border-radius:50%;margin:0 6px 2px 0}',
  '.wmx-z i.sn{border-radius:3px}',
  '.wmx-z:hover{background:#FFF5D1}',
  /* Zeile des oben gezeigten Bereichs leuchtet gelb (Runde 9); zusammengelegte Bereiche tragen mehrere Nummern */
  '.wmx-z.hl,.wrg-z.hl{background:#FFF5D1;box-shadow:inset 3px 0 0 #F7BC0C}',
  '.wmx-z.hl i,.wrg-z.hl i{background:#F7BC0C;color:#1A1D21}',
  '.wmx-nr{display:inline-flex;gap:3px;margin:0 6px 2px 0;vertical-align:top}',
  '.wmx-z .wmx-nr i,.wrg-z .wmx-nr i{margin:0}',
  '.wmx-z.kl{cursor:pointer}',
  '.wmx td{background:#fff;border:1px solid #e3e8ee;padding:4px}',
  '.wmx td.blk.M{background:#F4F5F6;border-color:#C5C9CE}.wmx td.blk.T{background:#EEF2F7;border-color:#9DB0C6}.wmx td.blk.V{background:#EEF4F1;border-color:#9CC3B2}',
  '.wmx td.leer{background:transparent;border-style:dashed}',
  '.wmx-l{display:block;font-size:12px;color:#9AA5B1;padding:2px 2px}',
  '.wmx-g{display:flex;flex-wrap:wrap;gap:2px}',
  '.wmx-m{position:relative;display:inline-flex;flex-direction:column;align-items:center;width:70px;padding:2px 2px 3px 2px;color:#1F3855;text-decoration:none;border:1px solid transparent;box-sizing:border-box}',
  'a.wmx-m:hover{border-color:#1F3855;background:#fff}',
  '.wmx-m.hl{border-color:#E0A800;background:#FFF5D1;box-shadow:inset 0 0 0 1px #F7BC0C}',
  '.wmx-s{width:62px;height:42px;display:flex;align-items:center;justify-content:center;background:#f3f5f8}',
  '.wmx-m small{display:-webkit-box;-webkit-line-clamp:3;-webkit-box-orient:vertical;overflow:hidden;font-size:11px;line-height:13px;text-align:center;margin-top:2px;-webkit-hyphens:auto;hyphens:auto;overflow-wrap:break-word}',
  '.wmx-m.g .wmx-s{background:transparent;border:1px dashed #c3ccd6;box-sizing:border-box}',
  '.wmx-m.g small{color:#8A9099}',
  '.wmx-m .wmk-pl{top:-3px;right:-3px;width:19px;height:19px;border-radius:10px;font-size:13px;line-height:17px;opacity:0;transition:opacity .15s}',
  '.wmx-m:hover .wmk-pl,.wmx-m:focus-within .wmk-pl,.wmx-m .wmk-pl.on{opacity:1}',
  '.wmx-h{font-size:12px;line-height:16px;color:#6E737A;margin:3px 2px 0 2px}',
  '.wmx-ta{display:flex;flex-wrap:wrap;align-items:center;gap:4px 8px;margin:6px 0 0 0;font-size:13px;color:#1F3855}',
  '@media (hover:none){.wmx-m .wmk-pl{opacity:.85;width:17px;height:17px;font-size:12px;line-height:15px}}',
  '.wrg{display:none;margin:2px 0 0 0;background:#fff;border:1px solid #d5dde6;padding:10px 10px 8px 10px}',
  '.wrg-f{font-size:13px;font-weight:700;color:#1F3855;margin:0 0 4px 0}',
  '.wrg-b{padding:0 10px}',
  '.wrg-i{-webkit-appearance:none;appearance:none;display:block;width:100%;height:34px;background:transparent;margin:0;cursor:pointer;touch-action:pan-y}',
  '.wrg-i:focus{outline:none}',
  '.wrg-i::-webkit-slider-runnable-track{height:5px;border-radius:3px;background:#1F3855}',
  '.wrg-i::-moz-range-track{height:5px;border-radius:3px;background:#1F3855}',
  '.wrg-i::-webkit-slider-thumb{-webkit-appearance:none;width:30px;height:30px;margin-top:-13px;border-radius:50%;background:#F7BC0C;border:3px solid #fff;box-shadow:0 1px 5px rgba(0,0,0,.35)}',
  '.wrg-i::-moz-range-thumb{width:24px;height:24px;border-radius:50%;background:#F7BC0C;border:3px solid #fff;box-shadow:0 1px 5px rgba(0,0,0,.35)}',
  '.wrg-i:focus-visible::-webkit-slider-thumb{box-shadow:0 0 0 3px #1F3855}',
  '.wrg-l{display:flex;justify-content:space-between;margin:0 0 2px 0}',
  '.wrg-l button{font:inherit;font-size:12px;font-weight:700;color:#9AA5B1;background:none;border:0;padding:4px 0;cursor:pointer}',
  '.wrg-l button.on{color:#1A1D21}',
  '.wrg-w{display:flex;margin:8px 0 2px 0;border:1px solid #1F3855}',
  '.wrg-w[hidden]{display:none}',
  '.wrg-w button{flex:1 1 0;font:inherit;font-size:13px;line-height:17px;padding:6px 4px;background:#fff;color:#1F3855;border:0;cursor:pointer}',
  '.wrg-w button.on{background:#1F3855;color:#fff;font-weight:700}',
  '.wrg-s{font-size:14px;line-height:19px;font-weight:700;color:#1A1D21;margin:9px 0 6px 0}',
  '.wrg-w1{flex:1 1 auto;font-size:13px;line-height:17px;padding:6px 8px;color:#1F3855;background:#F3F5F8}',
  '.wrg-w.wrg-blink button{animation:wrgBl .9s ease-in-out 0s 3}',
  '.wrg-w.wrg-blink button + button{animation-delay:.45s}',
  '@keyframes wrgBl{0%,100%{box-shadow:inset 0 0 0 0 rgba(247,188,12,0)}50%{box-shadow:inset 0 0 0 4px #F7BC0C}}',
  '.wmx-mix{font-size:12px;line-height:16px;color:#6E737A;margin:6px 0 0 0}',
  '.wrg-g{display:grid;grid-template-columns:112px minmax(0,1fr);gap:3px}',
  '.wrg-g.wrg-neu{animation:wszEin .3s ease both}',
  '.wrg-z{grid-column:1;font-size:12px;line-height:15px;font-weight:400;color:#1A1D21;background:#f3f5f8;padding:7px 5px;-webkit-hyphens:auto;hyphens:auto;overflow-wrap:break-word}',
  '.wrg-z i{display:inline-block;width:18px;height:18px;line-height:18px;text-align:center;font-style:normal;font-size:10px;background:#fff;border-radius:50%;margin:0 4px 2px 0}',
  '.wrg-z i.sn{border-radius:3px}',
  '.wrg-c{border:1px solid #e3e8ee;padding:3px;min-height:44px;background:#fff;min-width:0}',
  '.wrg-c.blk{display:flex;flex-direction:column;justify-content:center}',
  '.wrg-g.M .wrg-c.blk{background:#F4F5F6;border-color:#C5C9CE}.wrg-g.T .wrg-c.blk{background:#EEF2F7;border-color:#9DB0C6}.wrg-g.V .wrg-c.blk{background:#EEF4F1;border-color:#9CC3B2}',
  '.wrg-c.ganz .wmx-g{justify-content:center}',
  '.wrg-c.ganz .wmx-m{width:96px}.wrg-c.ganz .wmx-s{width:88px;height:60px}.wrg-c.ganz .wmx-m small{font-size:12px;line-height:14px;font-weight:700}',
  '.wrg-c.ganz .wmx-h{text-align:center}',
  '.wrg-c.leer{background:transparent;border-style:dashed}',
  '@media (max-width:700px){.wmx-w{display:none}.wrg{display:block}}',
  '@media (max-width:700px){.wmx{min-width:780px}.wmx-ec{width:104px}.wmx-z{font-size:12px;padding:6px 5px}.wmx-m{width:62px}.wmx-s{width:56px;height:38px}}',
  '@media (max-width:560px){.wkg-f{flex-wrap:nowrap;overflow-x:auto;padding:0 0 6px 0}.wkg-c{flex:0 0 78px;width:78px}.wkp-r{flex-wrap:nowrap;overflow-x:auto;scroll-snap-type:x proximity;padding:0 0 8px 0}.wkp-s{flex:0 0 94px;scroll-snap-align:start}.wkp-pf{flex:0 0 auto}.wkp-mg{grid-template-columns:1fr}}'
].join('');

/* ---------- Tabelle „Maschinen nach Ausbaustufe“, Runde 10 der Szene (Dimi 09.11.2026, Runde 11 der Antworten) ----------
   Zeilen: Oberbegriffe der Kategorie (DATA.elem, z. B. Mantel, Längsnaht, Umfangsnaht, Enden und Verbinder); bei einem
   einzelnen Bauteil darunter dessen Bereichsnamen (Unterbegriff, Punkt 18). Ohne Oberbegriffe (Wickelfalzrohr, Kulisse ...)
   die Bereiche des Bauteils. Spalten: Stufen mit Maschinen (Punkt 6), beim Kanal je Fertigungsweg.
   Jede Maschine (Gattung, Familie) steht nur einmal: in der ersten Zeile, in der sie arbeitet (Punkt 18). Arbeitet sie in
   mehreren Stufen, reicht ihre Karte über diese Spalten (Punkt 19). Gleicher Inhalt einer Spalte in mehreren Zeilen (eine
   Anlage fuer alles) steht als ein Block. Karten zeigen Symbol und Foto nebeneinander (Punkte 5 und 21).
   Darstellung als Raster (CSS grid): Kopfspalte, je Stufe eine Spalte mit eigener Tönung; Zeilen durch Linien getrennt. */
var MT_Q = { M: 'Manuell', T: 'Automatisiert', V: 'Vollautomatisch' };
/* Element eines Schritts i von Bauteil p: Liste der Element-IDs (leer: keine Zuordnung) */
function mtSchrittElemente(p, i) {
  var sel = (DATA.sel || {})[p]; if (sel) { if (sel[String(i)]) { return [sel[String(i)]]; } }
  var bj = (DATA.bj || {})[p], bel = (DATA.bel || {})[p], rel = (DATA.rel || {})[p], r = [];
  if (!bj || !bel) { return r; }
  each(bj[i] || [], function (k) { var e = k === -1 ? rel : bel[k]; if (e) { if (r.indexOf(e) === -1) { r.push(e); } } });
  return r;
}
/* Zeilen fuer eine Kategorie kid und Bauteile teile (eines oder alle). z.s[p] = Schritte von p in der Zeile */
function mtZeilen(kid, teile) {
  var EL = (DATA.elem || {})[kid];
  var einzeln = teile.length === 1, b0 = BT[teile[0]];
  if (!EL || !(DATA.bel || {})[teile[0]]) {
    /* ohne Oberbegriffe: Bereiche (wie Runde 9) */
    var z0 = mxZeilen(b0);
    each(z0, function (z) { var s = {}; s[b0.id] = z.s; z.s = s; z.sub = ''; });
    return z0;
  }
  var Z = [];
  each(EL, function (e) { Z.push({ id: e.id, t: e.t, sub: '', ks: [], nrs: [], s: {}, nr: 1 }); });
  each(teile, function (p) {
    var b = BT[p]; if (!b) { return; }
    each(b.schritte, function (st, i) {
      each(mtSchrittElemente(p, i), function (eid) {
        each(Z, function (z) { if (z.id !== eid) { return; } if (!z.s[p]) { z.s[p] = []; } if (z.s[p].indexOf(i) === -1) { z.s[p].push(i); } });
      });
    });
  });
  /* Unterbegriffe und Bereichsnummern nur bei einem Bauteil */
  if (einzeln) {
    var bel = DATA.bel[b0.id] || [];
    each(Z, function (z) {
      var namen = [];
      each(bel, function (e, k) { if (e !== z.id) { return; } z.ks.push(k); z.nrs.push(k + 1); var n = (b0.bereiche[k] || '').replace(/ *\([^)]*\)/g, ''); if (namen.indexOf(n) === -1) { namen.push(n); } });
      z.sub = namen.join(', ');
    });
  }
  return Z.filter(function (z) { for (var p in z.s) { if (z.s[p].length) { return true; } } return false; });
}
/* Spalten: Vereinigung der Spalten der Bauteile (Schluessel Stufe und Weg); c.per[p] = Spalte des Bauteils p */
function mtSpalten(teile) {
  var R = [], idx = {}, mehr = gt(teile.length, 1);
  each(teile, function (p) {
    var b = BT[p]; if (!b) { return; }
    var Z = mxZeilen(b), sp = mxFrei(b, Z, mxSpalten(b));
    each(sp, function (c) {
      /* mehrere Bauteile: eine Anlage fuer alles (VB) nach ihren Schritten verteilen, damit jede Maschine bei ihrem Element steht */
      if (mehr) { if (c.blk) { c = { q: c.q }; } }
      var key = c.q + '|' + (c.w ? c.w.t : '');
      if (idx[key] === undefined) { idx[key] = R.length; R.push({ q: c.q, w: c.w || null, blk: c.blk || null, key: key, per: {} }); }
      R[idx[key]].per[p] = c;
    });
  });
  var ord = { M: 0, T: 1, V: 2 };
  R.sort(function (a, b2) { return (ord[a.q] - ord[b2.q]) || 0; });
  return R;
}
/* Einheit einer Maschine: Gattung, sonst Familie, sonst die Maschine; „nicht im Programm“ fuer sich */
function mtEinheit(id) {
  var m = masch(id); if (!m) { return null; }
  if (m.g) { return { key: 'n:' + id, g: 1 }; }
  var ga = gatVon(id); if (ga) { return { key: 'g:' + ga.t, ga: ga }; }
  var fi = famVon(id); if (fi !== undefined) { return { key: 'f:' + fi, fi: fi }; }
  return { key: 'm:' + id };
}
/* Modell (je Maschine): Zellen, Bloecke, Platzierung jeder Maschine (Zeile, Spaltenbereich). Maschinen derselben Gattung in
   derselben Gruppe stehen als eine Karte (mtKarten). kid: Kategorie fuer feste Zeilen (DATA.mel, z. B. Schwenkbiegemaschine
   immer bei Mantel- und Seitenblechen, Runde 11 Punkt 18) */
function mtModell(zeilen, sp, kid) {
  var nz = zeilen.length, nc = sp.length, C = [], OCC = {}, ST = {}, ord = [];
  each(zeilen, function (z, r) {
    C.push([]);
    each(sp, function (c, j) {
      var cell = { ids: [], hand: [], ref: [] };
      for (var p in z.s) {
        var cp = c.per[p]; if (!cp) { continue; }
        var x = mxZelle(BT[p], z.s[p], cp);
        each(x.ms, function (id) {
          if (!masch(id)) { return; }
          if (!OCC[id]) { OCC[id] = []; ST[id] = {}; ord.push(id); }
          if (!ST[id][p]) { ST[id][p] = []; } each(x.wo[id] || [], function (i) { if (ST[id][p].indexOf(i) === -1) { ST[id][p].push(i); } });
          if (cell.ids.indexOf(id) === -1) { cell.ids.push(id); OCC[id].push([r, j]); }
        });
        each(x.hand, function (h) { if (cell.hand.indexOf(h) === -1) { cell.hand.push(h); } });
        each(x.ref || [], function (k) { if (cell.ref.indexOf(k) === -1) { cell.ref.push(k); } });
      }
      C[r].push(cell);
    });
  });
  function sig(cl) { return cl.ids.slice().sort().join(',') + '|' + cl.hand.join(',') + '|' + cl.ref.join(','); }
  function leer(cl) { return !(cl.ids.length + cl.hand.length + cl.ref.length); }
  /* senkrechte Bloecke: gleicher, nicht leerer Inhalt in benachbarten Zeilen einer Spalte (eine Anlage fuer mehrere Zeilen) */
  var B = [], inB = [];
  for (var r0 = 0; r0 !== nz; r0++) { inB.push([]); for (var j0 = 0; j0 !== nc; j0++) { inB[r0].push(-1); } }
  for (var j = 0; j !== nc; j++) {
    var r = 0;
    while (lt(r, nz)) {
      var r2 = r;
      if (!leer(C[r][j])) { while (lt(r2 + 1, nz)) { if (sig(C[r2 + 1][j]) === sig(C[r][j])) { r2++; } else { break; } } }
      if (gt(r2, r)) { B.push({ r0: r, r1: r2, c: j, cell: C[r][j] }); for (var q = r; q !== r2 + 1; q++) { inB[q][j] = B.length - 1; } }
      r = r2 + 1;
    }
  }
  var fest = {};
  each(B, function (bl) { each(bl.cell.ids, function (id) { fest[id] = 1; }); });
  /* feste Zeile je Maschine fuer diese Kategorie */
  var MEL = ((DATA.mel || {})[kid]) || {}, zeileVon = {};
  each(zeilen, function (z, rr) { if (z.id) { zeileVon[z.id] = rr; } });
  var G = [];
  for (var rr = 0; rr !== nz; rr++) { G.push([]); }
  function gruppe(r, c0, c1) {
    var g = null; each(G[r], function (x) { if (x.c0 === c0) { if (x.c1 === c1) { g = x; } } });
    if (!g) { g = { c0: c0, c1: c1, ids: [], hand: [], ref: [] }; G[r].push(g); }
    return g;
  }
  each(ord, function (id) {
    if (fest[id]) { return; }
    var rmin = 1e9, cols = [];
    each(OCC[id], function (o) { if (inB[o[0]][o[1]] !== -1) { return; } if (lt(o[0], rmin)) { rmin = o[0]; } if (cols.indexOf(o[1]) === -1) { cols.push(o[1]); } });
    if (rmin === 1e9) { return; }
    var ziel = MEL[id]; if (ziel !== undefined) { if (zeileVon[ziel] !== undefined) { rmin = zeileVon[ziel]; } }
    cols.sort(function (a, b) { return a - b; });
    var c0 = cols[0], c1 = cols[cols.length - 1], a0 = c0;
    for (var c = c0; c !== c1 + 2; c++) {
      var frei = c === c1 + 1 ? false : inB[rmin][c] === -1;
      if (!frei) { if (lt(a0, c)) { gruppe(rmin, a0, c - 1).ids.push(id); } a0 = c + 1; }
    }
  });
  /* Handarbeit und Verweise bleiben in ihrer Zelle (je Zeile eigene Arbeit, z. B. „von Hand“) */
  each(C, function (row, r) {
    each(row, function (cl, j) {
      if (inB[r][j] !== -1) { return; }
      if (!(cl.hand.length + cl.ref.length)) { return; }
      var g = gruppe(r, j, j);
      each(cl.hand, function (h) { if (g.hand.indexOf(h) === -1) { g.hand.push(h); } });
      each(cl.ref, function (h) { if (g.ref.indexOf(h) === -1) { g.ref.push(h); } });
    });
  });
  /* Unterzeilen je Zeile: Gruppen ueber mehrere Spalten zuerst, dann je Spalte; ohne Ueberschneidung packen */
  var S = [];
  each(G, function (gs) {
    gs.sort(function (a, b) { return ((b.c1 - b.c0) - (a.c1 - a.c0)) || (a.c0 - b.c0); });
    var lagen = [];
    each(gs, function (g) {
      var L = -1;
      for (var i = 0; i !== lagen.length; i++) { var ok = true; each(lagen[i], function (x) { if (!(lt(g.c1, x.c0) || gt(g.c0, x.c1))) { ok = false; } }); if (ok) { L = i; break; } }
      if (L === -1) { lagen.push([]); L = lagen.length - 1; }
      lagen[L].push(g); g.L = L;
    });
    S.push(Math.max(1, lagen.length));
  });
  return { C: C, ST: ST, B: B, inB: inB, G: G, S: S, nz: nz, nc: nc };
}
/* Karten einer Gruppe: Maschinen gleicher Gattung oder Familie zusammen, Reihenfolge wie in den Schritten */
function mtKarten(ids, M) {
  var R = [], idx = {};
  each(ids, function (id) {
    var e = mtEinheit(id); if (!e) { return; }
    if (idx[e.key] === undefined) { idx[e.key] = R.length; R.push({ key: e.key, e: e, ids: [], st: {} }); }
    var u = R[idx[e.key]]; u.ids.push(id);
    var st = M.ST[id] || {};
    for (var p in st) { if (!u.st[p]) { u.st[p] = []; } each(st[p], function (i) { if (u.st[p].indexOf(i) === -1) { u.st[p].push(i); } }); }
  });
  return R;
}
/* Karte einer Einheit: Symbol und Foto nebeneinander, darunter der Name; Link zur Maschinenseite, Plus fuer die Merkliste
   (ausserhalb des Links, Punkt 3) */
function mtKarte(u, par, o) {
  var id0 = u.ids[0], m0 = masch(id0), eins = u.ids.length === 1, e = u.e;
  var foto = '', fid = id0;
  each(u.ids, function (y) { if (foto) { return; } var my = masch(y); if (my.g) { return; } var f = bildUrl(y, my); if (f) { foto = f; fid = y; } });
  var name, url;
  if (e.ga) { name = gatText(e.ga.t, true); url = e.ga.u || (eins ? (m0.u || '') : (gatEltern(u.ids) || m0.u || '')); }
  else if (e.fi !== undefined) { name = DATA.fam[e.fi].t; url = m0.u || ''; }
  else { name = m0.g ? trennen(m0.mb) : trennen(tyEcht(m0) || m0.mb); url = m0.u || ''; }
  var link = (url ? (m0.g ? '' : seitenUrl(url)) : '');
  var c = ht('div', 'wmt-m' + (m0.g ? ' g' : '') + (link ? ' lk' : '') + (foto ? ' ft' : ''), null, par);
  var a = ht(link ? 'a' : 'div', 'wmt-a', null, c); if (link) { a.href = link; }
  var bl = ht('span', 'wmt-b', null, a);
  if (!m0.g) { var s = ht('span', 'wmt-s', null, bl); platzIcon(s, id0); }
  if (foto) { var f = ht('span', 'wmt-f', null, bl), im = ht('img', null, null, f); im.alt = ''; im.loading = 'lazy'; im.decoding = 'async'; im.src = foto; fotoRahmen(im, fid, true); }
  ht('span', 'wmt-n', name, a);
  if (m0.g) { ht('span', 'wmt-ng', 'nicht im Programm', a); }
  c.title = (e.ga ? gatText(e.ga.t, false) + ': ' : '') + u.ids.map(function (y) { var m = masch(y), te = tyEcht(m); return (te ? m.mb + ' ' + te : m.mb) + (m.b ? ' (' + m.b + ')' : ''); }).join(', ') + (m0.g ? ': nicht im Programm' : '');
  if (eins) { if (!m0.g) { merkKnopf(c, id0); } }
  if (o) { if (o.mini) { o.mini(u, c); } }
  return c;
}
/* Verweis auf ein anderes Bauteil (k:), z. B. Gehaeuse wie Rechteckkanal */
function mtVerweis(k, par) {
  var b = BT[k]; if (!b) { return null; }
  var x = ht('button', 'wmt-ref', 'wie ' + kurzName(b) + ' ›', par); x.type = 'button';
  x.title = 'Zum Bauteil ' + b.t;
  x.addEventListener('click', function (ev) { ev.stopPropagation(); if (WSZ_NAV) { WSZ_NAV(k); } });
  return x;
}
var WSZ_NAV = null;
function mtGruppe(g, M, par, o) {
  var w = ht('div', 'wmt-g', null, par);
  each(mtKarten(g.ids, M), function (u) { mtKarte(u, w, o); });
  if (g.ref.length) { var rf = ht('div', 'wmt-h', null, par); each(g.ref, function (k) { mtVerweis(k, rf); }); }
  if (g.hand.length) { ht('div', 'wmt-h', g.hand.join(' · '), par); }
}
function mtStufen(sp, c0, c1) { var r = []; for (var j = c0; j !== c1 + 1; j++) { if (r.indexOf(sp[j].q) === -1) { r.push(sp[j].q); } } return r; }
/* Tabelle zeichnen (Rechner und Tablet) */
function mtTabelle(par, zeilen, sp, M, o) {
  o = o || {};
  var wrap = ht('div', 'wmt-w', null, par), gr = ht('div', 'wmt', null, wrap), wege = false;
  each(sp, function (c) { if (c.w) { wege = true; } });
  gr.style.gridTemplateColumns = 'minmax(118px,0.85fr) repeat(' + sp.length + ',minmax(150px,1fr))';
  var zr = 1;
  /* Kopf: Stufen (eine Zelle je Stufe), darunter die Wege */
  var ec = ht('div', 'wmt-ec', o.ecke || '', gr); ec.style.gridRow = '1 / span ' + (wege ? 2 : 1); ec.style.gridColumn = '1';
  each(['M', 'T', 'V'], function (q) {
    var idx = []; each(sp, function (c, j) { if (c.q === q) { idx.push(j); } }); if (!idx.length) { return; }
    var th = ht('div', 'wmt-q ' + q, null, gr); ht('b', null, MT_Q[q], th);
    th.style.gridColumn = (idx[0] + 2) + ' / span ' + idx.length;
    var mitWeg = false; each(idx, function (j) { if (sp[j].w) { mitWeg = true; } });
    th.style.gridRow = (wege ? (mitWeg ? '1' : '1 / span 2') : '1');
  });
  if (wege) {
    each(sp, function (c, j) {
      if (!c.w) { return; }
      var t = ht('div', 'wmt-w2 ' + c.q, null, gr); t.style.gridRow = '2'; t.style.gridColumn = String(j + 2);
      profilQuer(c.w.t, t); ht('span', null, wegKurz(c.w.t), t).title = c.w.t;
    });
  }
  zr = wege ? 3 : 2;
  var Z0 = [];
  each(zeilen, function (z, r) { Z0.push(zr); zr += M.S[r]; });
  each(zeilen, function (z, r) {
    var a = Z0[r], n = M.S[r];
    /* Kopf der Zeile: Oberbegriff, darunter der Unterbegriff des Bauteils */
    var th = ht('div', 'wmt-z' + (r % 2 ? ' ug' : ''), null, gr); th.style.gridRow = a + ' / span ' + n; th.style.gridColumn = '1';
    mtZeilenkopf(th, z, o);
    /* Hintergrund je Spalte (Toenung der Stufe) */
    each(sp, function (c, j) {
      if (M.inB[r][j] !== -1) { return; }
      var bg = ht('div', 'wmt-bg ' + c.q + (r % 2 ? ' ug' : ''), null, gr); bg.style.gridRow = a + ' / span ' + n; bg.style.gridColumn = String(j + 2);
      var hat = false; each(M.G[r], function (g) { if (!(lt(j, g.c0) || gt(j, g.c1))) { hat = true; } });
      if (!hat) { ht('span', 'wmt-l', '–', bg).title = 'In dieser Stufe keine Maschine'; }
    });
    each(M.G[r], function (g) {
      var td = ht('div', 'wmt-c' + (g.c1 !== g.c0 ? ' sp' : ''), null, gr);
      td.style.gridRow = String(a + g.L); td.style.gridColumn = (g.c0 + 2) + ' / ' + (g.c1 + 3);
      if (g.c1 !== g.c0) {
        var qs = mtStufen(sp, g.c0, g.c1); td.classList.add('q' + qs.join(''));
        ht('span', 'wmt-sp', qs.map(function (q) { return MT_Q[q]; }).join(' und '), td);
      }
      mtGruppe(g, M, td, o);
    });
  });
  /* Bloecke: eine Anlage fuer mehrere Zeilen */
  each(M.B, function (bl) {
    var a = Z0[bl.r0], n = 0; for (var r = bl.r0; r !== bl.r1 + 1; r++) { n += M.S[r]; }
    var td = ht('div', 'wmt-c blk ' + sp[bl.c].q, null, gr); td.style.gridRow = a + ' / span ' + n; td.style.gridColumn = String(bl.c + 2);
    mtGruppe({ ids: bl.cell.ids, hand: bl.cell.hand, ref: bl.cell.ref }, M, td, o);
  });
  return wrap;
}
function mtZeilenkopf(el, z, o) {
  if ((z.nrs || []).length) { var nb = ht('span', 'wmx-nr', null, el); each(z.nrs, function (x) { ht('i', null, String(x), nb); }); }
  var tx = ht('span', 'wmt-zt', null, el);
  ht('b', null, z.t, tx);
  if (z.sub) { if (z.sub !== z.t) { ht('small', null, z.sub, tx); } }
  if (o.kopf) { o.kopf(z, el); }
  if (o.zeile) { el.addEventListener('mouseenter', function () { o.zeile(z, true); }); el.addEventListener('mouseleave', function () { o.zeile(z, false); }); }
}
/* Handy: eine Stufe auf einmal (Regler wie Runde 9); Karten ueber mehrere Stufen zeigen ihre Stufen */
function mtRegler(par, zeilen, sp, M, o) {
  o = o || {};
  var stufen = ['M', 'T', 'V'].filter(function (q) { var da = false; each(sp, function (c) { if (c.q === q) { da = true; } }); return da; }), wsel = { T: 0, V: 0 };
  var box = ht('div', 'wrg', null, par);
  ht('div', 'wrg-f', 'Wie automatisiert wollen Sie fertigen?', box);
  var bahn = ht('div', 'wrg-b', null, box), inp = ht('input', 'wrg-i', null, bahn);
  inp.type = 'range'; inp.min = '0'; inp.max = String(Math.max(0, stufen.length - 1)); inp.step = '1'; inp.value = '0';
  inp.setAttribute('aria-label', 'Ausbaustufe: ' + stufen.map(function (q) { return MT_Q[q]; }).join(' oder '));
  if (lt(stufen.length, 2)) { bahn.hidden = true; }
  var lab = ht('div', 'wrg-l', null, box), lb = [];
  each(stufen, function (q, i) { var x = ht('button', null, MT_Q[q], lab); x.type = 'button'; x.addEventListener('click', function () { inp.value = String(i); setz(); }); lb.push(x); });
  var wg = ht('div', 'wrg-w', null, box), liste = ht('div', 'wmt-rl', null, box);
  function setz() {
    var i = parseInt(inp.value, 10) || 0, q = stufen[i], idx = [];
    each(sp, function (c, j) { if (c.q === q) { idx.push(j); } });
    each(lb, function (x, k) { x.classList.toggle('on', k === i); });
    while (wg.firstChild) { wg.removeChild(wg.firstChild); }
    var wi = wsel[q] || 0; if (!gt(idx.length, wi)) { wi = 0; }
    wg.hidden = !gt(idx.length, 1);
    if (gt(idx.length, 1)) {
      each(idx, function (j, k) {
        var b = ht('button', k === wi ? 'on' : null, null, wg); b.type = 'button'; b.title = sp[j].w ? sp[j].w.t : '';
        if (sp[j].w) { profilQuer(sp[j].w.t, b); ht('span', null, wegKurz(sp[j].w.t), b); }
        b.addEventListener('click', function () { wsel[q] = k; setz(); });
      });
    }
    zeichne(idx[wi]);
  }
  function zeichne(j) {
    while (liste.firstChild) { liste.removeChild(liste.firstChild); }
    each(zeilen, function (z, r) {
      var zl = ht('div', 'wmt-rz', null, liste), kopf = ht('div', 'wrg-z', null, zl); mtZeilenkopf(kopf, z, o);
      var inh = ht('div', 'wmt-rc', null, zl), was = false;
      var bi = M.inB[r][j];
      if (bi !== -1) {
        var bl = M.B[bi];
        if (bl.r0 === r) { mtGruppe({ ids: bl.cell.ids, hand: bl.cell.hand, ref: bl.cell.ref }, M, inh, o); if (gt(bl.r1, bl.r0)) { ht('div', 'wmt-h', 'gilt für ' + (bl.r1 - bl.r0 + 1) + ' Zeilen', inh); } }
        else { ht('div', 'wmt-h', 'wie oben', inh); }
        was = true;
      }
      each(M.G[r], function (g) {
        if (lt(j, g.c0) || gt(j, g.c1)) { return; }
        was = true;
        var d = ht('div', 'wmt-rg', null, inh);
        mtGruppe(g, M, d, o);
        if (g.c1 !== g.c0) { ht('div', 'wmt-h', 'auch ' + mtStufen(sp, g.c0, g.c1).filter(function (x) { return x !== sp[j].q; }).map(function (x) { return MT_Q[x]; }).join(' und '), d); }
      });
      if (!was) { ht('span', 'wmt-l', '–', inh); }
    });
  }
  inp.addEventListener('input', setz); inp.addEventListener('change', setz);
  setz();
  return box;
}
var CSSM = [
  '.wmt-w{overflow-x:auto;-webkit-overflow-scrolling:touch;margin:4px 0 0 0}',
  '.wmt{display:grid;gap:0;min-width:640px;border-top:1px solid #C9D2DC}',
  '.wmt-ec{padding:8px 8px 6px 8px;font-size:12px;font-weight:700;color:#6E737A;text-transform:uppercase;letter-spacing:.04em;display:flex;align-items:flex-end;border-bottom:2px solid #1F3855}',
  /* Spaltenkoepfe: farbiges Band je Stufe */
  '.wmt-q{padding:7px 10px;color:#fff;background:#1F3855;border-left:2px solid #fff}',
  '.wmt-q b{display:block;font-size:14px;line-height:18px}',
  '.wmt-q.T,.wmt-q.V{background:#1F3855}',
  '.wmt-w2{font-size:12px;line-height:15px;font-weight:700;color:#1F3855;background:#E9EDF2;padding:4px 8px;border-left:2px solid #fff;border-bottom:2px solid #1F3855}',
  '.wmt-w2 .wpq{display:inline-block;vertical-align:middle;width:40px;height:40px;margin:-7px 8px -7px -2px}',
  '.wmt-w2 span{vertical-align:middle}',
  /* Zeilen: Kopf links, Linie unten; Stufen leicht getoent */
  '.wmt-z{position:sticky;left:0;z-index:3;display:flex;align-items:flex-start;gap:6px;padding:9px 8px;background:#EEF2F6;border-bottom:1px solid #C9D2DC;transition:background .15s}',
  '.wmt-z:hover{background:#FFF5D1}',
  '.wmt-zt{display:flex;flex-direction:column;min-width:0}',
  '.wmt-zt b{font-size:14px;line-height:18px;color:#1F3855;-webkit-hyphens:auto;hyphens:auto;overflow-wrap:break-word}',
  '.wmt-zt small{font-size:12px;line-height:15px;color:#5C6670;margin-top:2px;-webkit-hyphens:auto;hyphens:auto;overflow-wrap:break-word}',
  '.wmt-z .wmx-nr{margin:1px 0 0 0;flex:0 0 auto;display:inline-flex;flex-wrap:wrap;gap:3px;max-width:46px}',
  '.wmt-z .wmx-nr i{display:inline-block;width:20px;height:20px;line-height:20px;text-align:center;font-style:normal;font-size:11px;background:#fff;color:#1F3855;border-radius:50%}',
  '.wmt-z.hl,.wrg-z.hl{background:#FFF5D1;box-shadow:inset 4px 0 0 #F7BC0C}',
  '.wmt-z.hl .wmx-nr i,.wrg-z.hl .wmx-nr i{background:#F7BC0C;color:#1A1D21}',
  '.wmt-bg{border-left:2px solid #fff;border-bottom:1px solid #C9D2DC;background:#F6F7F8;display:flex;align-items:center;justify-content:center}',
  '.wmt-bg.T{background:#F1F5FA}.wmt-bg.V{background:#EFF6F2}',
  '.wmt-l{font-size:13px;color:#A3ADB8}',
  '.wmt-c{position:relative;z-index:1;display:flex;flex-direction:column;justify-content:flex-start;gap:4px;padding:6px;min-width:0;border-left:2px solid transparent}',
  /* Karte ueber mehrere Stufen: Band in den Farben der Stufen (Punkt 19) */
  '.wmt-c.sp{margin:4px 3px;padding:16px 6px 6px 6px;border:1px solid #9DB0C6;background:linear-gradient(90deg,rgba(110,115,122,.10),rgba(31,56,85,.10))}',
  '.wmt-c.sp.qTV{border-color:#9CC3B2;background:linear-gradient(90deg,rgba(31,56,85,.10),rgba(11,110,79,.10))}',
  '.wmt-c.sp.qMTV{background:linear-gradient(90deg,rgba(110,115,122,.10),rgba(31,56,85,.10),rgba(11,110,79,.10))}',
  '.wmt-sp{position:absolute;left:6px;top:2px;font-size:10px;line-height:13px;font-weight:700;color:#41566F;text-transform:uppercase;letter-spacing:.04em}',
  '.wmt-c.sp .wmt-g{justify-content:center}',
  '.wmt-c.blk{margin:4px 3px;border:1px solid #9CC3B2;background:#E6F1EB;justify-content:flex-start;align-items:center}',
  '.wmt-c.blk.T{border-color:#9DB0C6;background:#E8EEF5}.wmt-c.blk.M{border-color:#C5C9CE;background:#EEF0F2}',
  '.wmt-c.blk .wmt-g{justify-content:center}',
  '.wmt-g{display:flex;flex-wrap:wrap;gap:6px}',
  /* Maschinenkarte: Symbol und Foto nebeneinander, Name darunter */
  '.wmt-m{position:relative;display:inline-flex;flex-direction:column;width:156px;background:#fff;border:1px solid #D5DDE6;box-sizing:border-box;transition:border-color .15s,box-shadow .15s}',
  '.wmt-m:not(.ft){width:112px}',
  '.wmt-m.lk:hover{border-color:#1F3855;box-shadow:0 2px 8px rgba(31,56,85,.16)}',
  '.wmt-m.hl{border-color:#E0A800;box-shadow:inset 0 0 0 2px #F7BC0C}',
  '.wmt-a{display:flex;flex-direction:column;align-items:stretch;color:#1F3855;text-decoration:none;padding:4px 4px 5px 4px}',
  '.wmt-b{display:flex;gap:3px;height:58px}',
  '.wmt-s{flex:1 1 0;min-width:0;display:flex;align-items:center;justify-content:center;background:#F3F5F8}',
  '.wmt-s .wps{width:100%;height:100%}',
  '.wmt-f{flex:1 1 0;min-width:0;position:relative;overflow:hidden;background:#fff}',
  '.wmt-f img{position:absolute;display:block}',
  '.wmt-f img:not(.rh){left:0;top:0;width:100%;height:100%;object-fit:contain}',
  '.wmt-n{display:-webkit-box;-webkit-line-clamp:3;-webkit-box-orient:vertical;overflow:hidden;margin:4px 2px 0 2px;font-size:12px;line-height:15px;font-weight:700;color:#1F3855;-webkit-hyphens:manual;hyphens:manual;overflow-wrap:anywhere}',
  '.wmt-ng{font-size:11px;line-height:14px;color:#8A9099;margin:0 2px}',
  '.wmt-m.g{border-style:dashed;background:#FAFBFC;width:112px}',
  '.wmt-m.g .wmt-b{display:none}',
  '.wmt-m.g .wmt-n{color:#8A9099;font-weight:400}',
  '.wmt-m .wmk-pl{top:-6px;right:-6px;width:24px;height:24px;opacity:0;transition:opacity .15s}',
  '.wmt-m:hover .wmk-pl,.wmt-m:focus-within .wmk-pl,.wmt-m .wmk-pl.on{opacity:1}',
  '@media (hover:none){.wmt-m .wmk-pl{opacity:.9}}',
  '.wmt-h{font-size:12px;line-height:16px;color:#5C6670;margin:2px 2px 0 2px}',
  '.wmt-ref{font:700 12px/16px Arial,Helvetica,sans-serif;color:#1F3855;background:#fff;border:1px solid #1F3855;padding:4px 8px;cursor:pointer;margin:2px 4px 2px 0}',
  '.wmt-ref:hover{background:#1F3855;color:#fff}',
  /* Handy */
  '.wmt-rl{display:flex;flex-direction:column;gap:3px;margin:8px 0 0 0}',
  '.wmt-rz{display:grid;grid-template-columns:112px minmax(0,1fr);gap:3px}',
  '.wmt-rz .wrg-z{display:flex;gap:4px;align-items:flex-start}',
  '.wmt-rz .wmt-zt b{font-size:13px;line-height:16px}',
  '.wmt-rc{border:1px solid #e3e8ee;padding:4px;min-width:0;background:#fff;display:flex;flex-direction:column;gap:4px}',
  '.wmt-rc .wmt-m{width:138px}',
  '@media (max-width:700px){.wmt-w{display:none}.wrg{display:block}}',
  '@media (min-width:701px){.wmt-w + .wrg{display:none}}'
].join('');

/* ---------- Tabelle der Maschinen (Kartei) ----------
   Runde 11 bis 16 der Szene: siehe LIES_MICH.md (jede Maschine einmal je Zeile, Kategorien als eine Karte, Rahmenverbindung als
   Weiche, Karten ohne Flackern wiederverwendet, eine Tabelle fuer alle Ausbaustufen).
   Runde 17 der Szene (Dimi 11.11.2026, 16:23):
   - Aufbau je Kategorie nach Vorlage (DATA.klay aus verfahren_v1.json „karteiLayout“): Zeilen, Gruppen von Karten mit einer
     senkrechten Linie dazwischen, Reihenfolge. Eine Karte steht nur, wenn die Maschine laut Strukturdaten in dieser Zeile arbeitet;
     eine nicht eingetragene Maschine steht am Ende der Zeile, wenn sie in keiner anderen Zeile eingetragen ist. Ohne Vorlage je
     Ausbaustufe eine Gruppe.
   - Vermerk der Ausbaustufe als Rechteck auf dem blauen Querstreifen rechts: AUTO (automatisiert), VOLLAUTO (vollautomatisch),
     manuell ohne Vermerk; Hersteller unten rechts. Keine Bloecke (Ketten, Anlagen) und keine Vermerke „nur …“, „außer …“,
     „alternativ“ mehr.
   - Zeigen auf eine Karte: links erscheint das Formstueck mit dem Bereich, den die Maschine bearbeitet (wenn sie nicht fuer alle
     Formstuecke der Zeile gilt), oder das Bild aus der Vorlage (z. B. Stufe 1 des 3-Maschinen-Systems). Am Handy zeigt das erste
     Antippen das Bild, das zweite oeffnet die Seite.
   - Zeilen mit denselben Karten werden eine Zeile (z. B. Wickelfalzrohr); das Elementbild zeigt dann alle ihre Bereiche.
   - Elementkarte links wie eine Maschinenkarte (Bild, blauer Streifen, Text) mit blaeulichem Grund. */
var EM_ALLE = [], EM_RV = 'sr', EM_KLICK = null;
/* Stufennamen (Dimi 11.11.2026, 16:23): Manuell, Automatisiert, Vollautomatisch; Vermerk AUTO und VOLLAUTO */
var EM_Q = { M: 'Manuell', T: 'Automatisiert', V: 'Vollautomatisch' };
var EM_TAG = { M: '', T: 'AUTO', V: 'VOLLAUTO' };
var EM_QN = { M: 0, T: 1, V: 2 };
/* Runde 18 (Dimi 11.11.2026, 20:13): ein Abstand zwischen allen Karten, in den bei Gruppenwechsel die senkrechte Linie passt */
var EM_GAP = 14;
/* Kategorie einer Maschine (DATA.mkat) */
var MKAT = null;
function katVon(id) {
  if (!MKAT) { MKAT = {}; each(DATA.mkat || [], function (k) { each(k.m, function (x) { MKAT[x] = k; }); }); }
  return MKAT[id] || null;
}
/* Runde 18 (Dimi 11.11.2026, 20:13, „merken“): Maschinen derselben Bezeichnung von verschiedenen Herstellern (z. B. später weitere
   Tafelscheren neben der MSB von Schechtl) bilden von selbst eine Gruppenkarte; der vorhandene Eintrag der Vorlage (msb) nimmt sie mit.
   Modelle desselben Herstellers (TF 1401 Ultra, TF 1600 Ultra) bleiben einzelne Karten. */
var EM_MBG = null, EM_MBL = {};
function mbGruppe(id) {
  if (!EM_MBG) {
    EM_MBG = {}; EM_MBL = {};
    var H = {}, rein = function (x, m) {
      if (!m) { return; } if (m.platz || m.g) { return; }
      var n = (m.mb || '').replace(/­|​/g, ''); if (!n) { return; }
      if (!H[n]) { H[n] = []; } H[n].push({ id: x, b: m.b || '' });
    };
    for (var x in KAT) { rein(x, KAT[x]); }
    var Z0 = DATA.zusatz || {}; for (var y in Z0) { if (!KAT[y]) { rein(y, Z0[y]); } }
    for (var n in H) {
      var bs = []; each(H[n], function (e) { if (bs.indexOf(e.b) === -1) { bs.push(e.b); } });
      if (gt(bs.length, 1)) { EM_MBL[n] = []; each(H[n], function (e) { EM_MBG[e.id] = n; EM_MBL[n].push(e.id); }); }
    }
  }
  return EM_MBG[id] || '';
}
function einheitVon(id) {
  var m = masch(id); if (!m) { return null; }
  if (m.g) { return { key: 'n:' + id, g: 1 }; }
  var ka = katVon(id); if (ka) { return { key: 'k:' + ka.id, ka: ka }; }
  var e = mtEinheit(id), n = mbGruppe(id);
  if (!n) { return e; }
  /* gemeinsame Einheit: Gattung oder Familie eines Mitglieds (z. B. „Tafelscheren“ der MSB), sonst die Bezeichnung */
  var g = null;
  each(EM_MBL[n] || [], function (x) { if (g) { return; } if (katVon(x)) { return; } var ex = mtEinheit(x); if (ex) { if (ex.key !== 'm:' + x) { g = ex; } } });
  return g || { key: 'b:' + n, mbg: n };
}
function emNum(a, b) { return a - b; }
/* Runde 14 (Dimi 10.11.2026): Maschinen, die in einer Tabelle „Alle …“ nicht stehen sollen (Presse und Halbschalen-Schweissautomat der
   gepressten Formteile); EM_OHNE gilt nur waehrend des Aufbaus des Modells */
var EM_OHNE = [];
function emZelle(b, st, cp) {
  var x = mxZelle(b, st, cp);
  if (EM_OHNE.length) { x.ms = x.ms.filter(function (id) { return EM_OHNE.indexOf(id) === -1; }); }
  return x;
}
/* Art einer Spalte: Element-Zeilen (spalte), Kette (linie) oder eine Anlage fuer alles (anlage) */
function emArt(c) {
  if (c.blk) { return 'anlage'; }
  if (c.w) { if (c.w.linie) { return 'linie'; } return c.w.st ? 'spalte' : 'anlage'; }
  return 'spalte';
}
/* Rang einer Einheit fuer die Reihenfolge (DATA.reihe; Kategorien mit ihrer ersten Maschine) */
var EM_RANG = null;
function emRang(ids) {
  if (!EM_RANG) { EM_RANG = {}; each(DATA.reihe || [], function (id, i) { EM_RANG[id] = i; }); }
  var r = 9999; each(ids, function (id) { var x = EM_RANG[id]; if (x !== undefined) { if (lt(x, r)) { r = x; } } });
  return r;
}
/* Modell: Einheiten in Element-Spalten; u.rx[Zeile|Spalte][Bauteil][Maschine] = Schritte dieser Zeile; Handarbeit und Verweise je Zelle */
function emModell(zeilen, sp, kid) {
  var U = [], UI = {}, H = [];
  var art = sp.map(emArt);
  each(zeilen, function (z, r) {
    H.push([]);
    each(sp, function (c, j) {
      var cell = { hand: [], ref: [] }; H[r].push(cell);
      if (art[j] !== 'spalte') { return; }
      for (var p in z.s) {
        var cp = c.per[p]; if (!cp) { continue; }
        var x = emZelle(BT[p], z.s[p], cp);
        each(x.ms, function (id) {
          var e = einheitVon(id); if (!e) { return; }
          /* Kategorie mit Karte je Zeile (Elektrowerkzeuge): je Zeile eigene Karte mit den Werkzeugen dieser Zeile */
          if (e.ka) { if (e.ka.jz) { e = { key: e.key + '@' + r, ka: e.ka }; } }
          if (UI[e.key] === undefined) { UI[e.key] = U.length; U.push({ key: e.key, e: e, ids: [], rc: {}, rx: {}, n: U.length }); }
          var u = U[UI[e.key]], rk = r + '|' + j;
          if (u.ids.indexOf(id) === -1) { u.ids.push(id); }
          u.rc[rk] = 1;
          if (!u.rx[rk]) { u.rx[rk] = {}; } if (!u.rx[rk][p]) { u.rx[rk][p] = {}; }
          var L = u.rx[rk][p][id] || (u.rx[rk][p][id] = []);
          each(x.wo[id] || [], function (i) { if (L.indexOf(i) === -1) { L.push(i); } });
        });
        each(x.hand, function (h) { if (cell.hand.indexOf(h) === -1) { cell.hand.push(h); } });
        each(x.ref || [], function (k) { if (cell.ref.indexOf(k) === -1) { cell.ref.push(k); } });
      }
    });
  });
  return { U: U, H: H, art: art };
}
/* Zeilen ohne Maschine und ohne Verweis entfallen (Anlagen-Spalten zaehlen mit, z. B. die Automatische Kanalanlage PDF) */
function emZeilenFiltern(zeilen, sp, kid) {
  var M0 = emModell(zeilen, sp, kid), keep = [];
  each(zeilen, function (z, r) {
    var voll = false;
    each(M0.U, function (u) { for (var rk in u.rc) { if (rk.split('|')[0] === String(r)) { voll = true; } } });
    each(M0.H[r], function (cell) { if (cell.ref.length) { voll = true; } });
    each(sp, function (c, j) { if (M0.art[j] !== 'spalte') { for (var p in z.s) { if (c.per[p]) { if (z.s[p].length) { voll = true; } } } } });
    if (voll) { keep.push(z); }
  });
  return { Z: keep, M: keep.length === zeilen.length ? M0 : emModell(keep, sp, kid) };
}
/* Titel zusammengelegter Zeilen in ihrer Reihenfolge („Mantel mit Versteifungssicke, Wickelfalz, Rohrende“) */
function emTitel(z) {
  if (!(z.mitL || []).length) { return z.t; }
  return [z.t].concat(z.mitL.map(function (x) { return x.t; })).join(', ');
}
/* Name und Link einer Einheit */
function emName(u) {
  var e = u.e, m0 = masch(u.ids[0]);
  if (e.ka) { return { t: e.ka.t, u: e.ka.u }; }
  if (e.ga) { return { t: gatText(e.ga.t, true), u: e.ga.u || (u.ids.length === 1 ? (m0.u || '') : emLink(u.ids)) }; }
  if (e.fi !== undefined) { return { t: DATA.fam[e.fi].t, u: emLink(u.ids) }; }
  if (e.mbg) { return { t: trennen(e.mbg), u: emLink(u.ids) }; }
  return { t: m0.g ? trennen(m0.mb) : trennen(tyEcht(m0) || m0.mb), u: emLink(u.ids) };
}
/* Link einer Karte: die Seite der Maschine, bei mehreren die gemeinsame Uebersicht der Maschinen mit eigener Seite */
function emLink(ids) {
  var L = []; each(ids, function (id) { var m = masch(id); if (m) { if (m.u) { if (L.indexOf(m.u) === -1) { L.push(m.u); } } } });
  if (!L.length) { return ''; }
  if (L.length === 1) { return L[0]; }
  var e = null, ok = true;
  each(L, function (u) { var x = u.replace(/\/[^\/]*$/, ''); if (e === null) { e = x; } else if (e !== x) { ok = false; } });
  return ok ? e : L[0];
}
/* Karten werden nach ihrem Inhalt (Schluessel) aufbewahrt und beim Neuaufbau wiederverwendet (kein Flackern, Runde 14) */
var EM_KC = {}, EM_GEN = 0;
function emNeuerAufbau() {
  EM_GEN++;
  for (var k in EM_KC) { var e = EM_KC[k]; if (!e.isConnected) { if (lt(e.wemGen, EM_GEN - 4)) { delete EM_KC[k]; } } }
}
/* Karte: Titelzeile (Kategorie oder Gruppe), ein Ruhebild, blauer Querstreifen mit dem Vermerk der Stufe rechts, Bezeichnung, Typ,
   Hersteller unten rechts. k: { key, e, ids, q, titel, zusatz, ruhe } */
function emKarte(k, par) {
  var u = { key: k.key, e: k.e, ids: k.ids };
  var nm = emName(u), ng = !!u.e.g, m0 = masch(u.ids[0]), platz = m0 ? !!m0.platz : false;
  var link = nm.u ? (ng || platz ? '' : seitenUrl(nm.u)) : '';
  var mehr = gt(u.ids.length, 1), titel = k.titel || '';
  if (!titel) {
    if (u.e.ka) { titel = u.e.ka.t; }
    else if (mehr) { var mbs = []; each(u.ids, function (id) { var mx = masch(id); var n = mx ? (mx.mb || '').replace(/­|​/g, '') : ''; if (mbs.indexOf(n) === -1) { mbs.push(n); } }); titel = mbs.length === 1 ? '' : nm.t.replace(/­|​/g, ''); }
  }
  /* Runde 18 (Dimi 11.11.2026, 20:13): Vermerk je Kategorie statt AUTO (CNC-Schneiden: CNC) */
  var TT = ((DATA.klay || {})._alle || {}).tagText || {}, tagE = TT[u.key.split('@')[0]] || '';
  var tag = tagE || EM_TAG[k.q] || '';
  var sig = [u.key.split('@')[0], u.ids.join(','), titel, link, tag, k.zusatz || ''].join('|');
  var alt = EM_KC[sig];
  if (alt) { if (alt.wemGen !== EM_GEN) { alt.wemGen = EM_GEN; par.appendChild(alt); return alt; } }
  /* Runde 18 (Dimi 11.11.2026, 20:13, Pruefliste 20.12): Paar im Ruhebild (TruTool F 300 groesser, F 140 kleiner), wenn beide in der Karte stehen */
  var paar = null;
  if (u.e.ka) { each(u.e.ka.paar || [], function (P) { if (paar) { return; } var ja = true; each(P, function (id) { if (u.ids.indexOf(id) === -1) { ja = false; } }); if (ja) { paar = P; } }); }
  var ruhe = k.ruhe || (u.e.ka ? (u.e.ka.ruhe || null) : null);
  if (paar) { ruhe = paar.concat((ruhe || []).filter(function (x) { return paar.indexOf(x) === -1; })); }
  var G = wbGlieder(u.ids, { einzeln: true, ruhe: ruhe });
  var fest = u.e.ka ? (u.e.ka.txt ? { mb: u.e.ka.txt, b: u.e.ka.b || '' } : null) : null;
  /* ein Ruhebild je Karte (Dimi 11.11.2026, 16:23: zwei gleiche Maschinen nebeneinander, die erste abgeschnitten) */
  var c = wkKarte(par, u.ids, { glieder: G, titel: titel, ot: true, link: link, merk: mehr || ng || platz ? '' : u.ids[0], klasse: 'em-k', gruppe: !!u.e.ka || mehr, nebeneinander: paar ? paar.length : 1, gross1: !!paar, fest: fest });
  if (tag || k.zusatz) {
    var tx = c.querySelector('.wmk-tx'), tg = ht('span', 'em-tags', null, tx || c);
    if (k.zusatz) { ht('span', 'em-tag zs', k.zusatz, tg); }
    if (tag) { ht('span', 'em-tag ' + (tagE ? 'cnc' : k.q), tag, tg).title = tagE ? 'CNC-gesteuert' : EM_Q[k.q]; }
  }
  c.wemGen = EM_GEN; EM_KC[sig] = c;
  return c;
}
/* Text kleiner setzen, bis er in hoechstens n Zeilen passt (Dimi 11.11.2026, 16:23: lange Texte kleiner, kompakter) */
function emPassen(el, n, min) {
  function fit() {
    if (!el.isConnected) { return; }
    el.style.fontSize = ''; el.style.lineHeight = '';
    var cs = window.getComputedStyle(el), f = parseFloat(cs.fontSize) || 12, lh = parseFloat(cs.lineHeight) || f * 1.25, r = lh / f;
    var i = 0;
    while (gt(el.scrollHeight, Math.ceil(n * f * r) + 1)) { if (lt(f - 0.5, min)) { break; } f -= 0.5; el.style.fontSize = f + 'px'; el.style.lineHeight = (f * r).toFixed(1) + 'px'; i++; if (gt(i, 12)) { break; } }
  }
  window.requestAnimationFrame(fit);
}
/* Runde 14 (Dimi 10.11.2026): kein Springen. Ein Bereich, der neu aufgebaut wird, behaelt seine Hoehe, bis man so weit nach oben
   geblaettert hat, dass das Kuerzen nichts mehr verschiebt; ein Anker (z. B. die angetippte Kachel) bleibt an seiner Stelle. */
function emHalten(el) {
  if (!el) { return; }
  var h = el.getBoundingClientRect().height; if (!h) { return; }
  var alt0 = parseFloat(el.style.minHeight) || 0;
  el.style.minHeight = Math.max(h, alt0) + 'px';
  if (el.wemLos) { return; }
  el.wemLos = function () {
    if (!el.isConnected) { window.removeEventListener('scroll', el.wemLos); el.wemLos = null; return; }
    var mh = parseFloat(el.style.minHeight) || 0; if (!mh) { return; }
    el.style.minHeight = ''; var ch = el.getBoundingClientRect().height; el.style.minHeight = mh + 'px';
    var de = document.documentElement, rest = de.scrollHeight - ((window.pageYOffset || 0) + (window.innerHeight || de.clientHeight));
    var neu = Math.max(ch, mh - Math.max(0, rest));
    el.style.minHeight = gt(neu, ch + 1) ? neu + 'px' : '';
  };
  window.addEventListener('scroll', el.wemLos, { passive: true });
}
/* fn baut neu; anker() vorher und nachher: das Element, das an seiner Stelle auf dem Bildschirm bleiben soll */
function emOhneSprung(el, anker, fn) {
  var a0 = anker ? anker() : null, y0 = a0 ? a0.getBoundingClientRect().top : null;
  emHalten(el);
  fn();
  var a1 = anker ? anker() : null;
  if (a1) { if (y0 !== null) { var d = a1.getBoundingClientRect().top - y0; if (gt(Math.abs(d), 1)) { window.scrollBy(0, d); } } }
  if (el) { if (el.wemLos) { el.wemLos(); } }
}
/* Einheiten fuer eine Liste von Maschinen (Anlagen) */
function emEinheiten(ids) {
  var R = [], idx = {};
  each(ids, function (id) {
    var e = einheitVon(id); if (!e) { return; }
    if (e.g) { return; }
    if (idx[e.key] === undefined) { idx[e.key] = R.length; R.push({ key: e.key, e: e, ids: [] }); }
    R[idx[e.key]].ids.push(id);
  });
  return R;
}
/* ---------- Elementkarte links in der Zeile ---------- */
/* flache Zuschnitte des 3-Maschinen-Systems (Zeichnungen in 50_symbole.js) */
var EM_FLACH = { rkflach1: ['Blech', 'Längsfalz (Pittsburghfalz und Stehfalz)', 'Flansch'], rkflach2: ['Blech', 'Längsfalz (Pittsburghfalz und Stehfalz)', 'Flansch'] };
function emBauteil(pid) { return BT[pid] || (EM_FLACH[pid] ? { id: pid, t: 'Zuschnitt', bereiche: EM_FLACH[pid] } : null); }
/* Bereiche: Zahlen, Namen (Anfang des Bereichsnamens, z. B. „Kantlinien“) oder „alle“ */
function emBereiche(b, ks) {
  if (!b) { return []; }
  if (ks === 'alle') { return b.bereiche.map(function (t, i) { return i; }); }
  var R = [];
  each(ks || [], function (k) {
    var i = k;
    if (typeof k === 'string') { i = -1; each(b.bereiche, function (t, j) { if (i === -1) { if (t.indexOf(k) === 0) { i = j; } } }); }
    if (gt(i, -1)) { if (R.indexOf(i) === -1) { R.push(i); } }
  });
  return R;
}
/* Bereiche eines Bauteils, die die Schritte st bearbeiten (DATA.bj) */
function emSchrittBereiche(p, st) {
  var bj = (DATA.bj || {})[p], R = []; if (!bj) { return R; }
  each(st || [], function (i) { each(bj[i] || [], function (k) { if (gt(k, -1)) { if (R.indexOf(k) === -1) { R.push(k); } } }); });
  return R;
}
/* Bereiche eines Bauteils in einer Zeile: Element-Zeilen ueber DATA.bel, Bereichs-Zeilen ueber z.ks */
function emZeilenBereiche(z, p) {
  var R = [], ids = z.ids || (z.id ? [z.id] : []);
  if (ids.length) { each((DATA.bel || {})[p] || [], function (e, k) { if (ids.indexOf(e) !== -1) { R.push(k); } }); return R; }
  return (z.ks || []).slice();
}
function emBereichNamen(b, ks) { return ks.map(function (k) { return (b.bereiche[k] || '').replace(/ *\([^)]*\)/g, ''); }).filter(function (t) { return !!t; }).join(', '); }
/* Elementkarte: Bild des Elements (Bauteil mit den Bereichen der Zeile), blauer Streifen, Name; setz(spec) zeigt ein anderes Bild
   (spec: { pid, ks, t }), setz(null) wieder das Elementbild */
function emElement(par, z, o) {
  var c = ht('div', 'em-el wmk-c wk', null, par);
  ht('span', 'wk-ot', '', c);
  var bi = ht('span', 'wmk-bi em-eb', null, c), tx = ht('span', 'wmk-tx em-zt', null, c);
  var tb = ht('b', null, emTitel(z), tx), ts = ht('small', null, '', tx);
  var i0 = (z.tz ? z.tz.i : '') || ''; each(z.mitL || [], function (x) { if (!i0) { i0 = x.tz ? (x.tz.i || '') : ''; } });
  if (i0) { infoKnopf(c, i0, { label: emTitel(z), cls: 'em-eli' }); }
  var pid0 = z.bild ? z.bild.pid : (o.bild ? o.bild.pid : null), b0 = pid0 ? emBauteil(pid0) : null;
  var ks0 = b0 ? (z.bild ? (z.bild.ks || []) : emZeilenBereiche(z, pid0)) : [];
  var sub0 = z.sub ? (z.sub !== z.t ? z.sub : '') : '';
  ts.textContent = sub0;
  var bilder = {}, jetzt = null;
  function bild(pid) {
    if (bilder[pid] !== undefined) { return bilder[pid]; }
    var b = emBauteil(pid), S = b ? symbolBauen(pid) : null;
    if (!S) { bilder[pid] = null; return null; }
    var vEl = (SYM[pid] || {}).vEl, svg = symbolSvg(S, b, vEl === undefined ? 0 : vEl);
    var w = ht('span', 'em-ebi', null, bi); w.appendChild(svg); w.wSvg = svg;
    bilder[pid] = w; return w;
  }
  function zeig(pid, ks) {
    var w = pid ? bild(pid) : null;
    each(Object.keys(bilder), function (k) { if (bilder[k]) { bilder[k].classList.toggle('auf', bilder[k] === w); } });
    if (w) { bereichSetzen(w.wSvg, ks); }
    jetzt = w;
  }
  if (b0) { zeig(pid0, ks0); }
  if (!jetzt) { bi.classList.add('leer'); }
  emPassen(tb, 3, 10.5);
  var api = {
    setz: function (spec) {
      if (!spec) { if (b0) { zeig(pid0, ks0); } tb.textContent = emTitel(z); ts.textContent = sub0; c.classList.remove('zg'); return; }
      var b = emBauteil(spec.pid); if (!b) { return; }
      var ks = emBereiche(b, spec.ks);
      zeig(spec.pid, ks);
      if (spec.t) { tb.textContent = spec.t; }
      ts.textContent = emBereichNamen(b, ks);
      c.classList.add('zg');
    },
    el: c
  };
  if (o.kopf) { o.kopf(z, c); }
  if (o.zeile) { c.addEventListener('mouseenter', function () { o.zeile(z, true); }); c.addEventListener('mouseleave', function () { o.zeile(z, false); }); }
  return api;
}
function emRef(k, par) { return mtVerweis(k, par); }
/* ---------- Rahmenverbindung ---------- */
/* Runde 14 (Dimi 10.11.2026): PDF 3 und PDF 1 gespiegelt, damit alle vier PDF-Profile gleich liegen */
var EM_SPIEGEL = ['pdf3', 'pdf1'];
var EM_RV_TXT = {
  sr: { t: 'Steckrahmen', p: ['steckrahmen'], d: 'Profil zukaufen oder profilieren, ablängen, mit Eckwinkeln zum Rahmen verbinden und auf den Kanal stecken.' },
  pdf: { t: 'PDF-Flansch', p: ['pdf3', 'pdf2', 'pdf1s', 'pdf1'], d: 'Der Flansch wird direkt aus der Kanalwand profiliert: kein Rahmenkauf, kein Rahmenbau. Gezeigt: PDF 3, PDF 2, PDF 1 Super und PDF 1.' }
};
function emAlleNeu(anker) { EM_ALLE = EM_ALLE.filter(function (f) { return f.wemBox ? f.wemBox.isConnected : false; }); each(EM_ALLE, function (f) { emOhneSprung(f.wemZiel, anker || null, f); }); }
function emRvSetzen(rv, box) {
  if (rv === EM_RV) { return; } EM_RV = rv; EM_KLICK = 'rv:' + rv;
  emAlleNeu(box ? function () { return box.querySelector('.em-rvb.' + rv); } : null); EM_KLICK = null;
}
/* nach dem Antippen: dickerer Rahmen fuer etwa 1 s (Dimi 10.11.2026), danach bleibt die Auswahl an der Fuellung erkennbar */
function emKlickRahmen(b) {
  if (!b) { return; }
  b.classList.add('em-kl');
  window.setTimeout(function () { b.classList.remove('em-kl'); }, 1000);
}
/* Runde 17 (Dimi 11.11.2026, 16:23): die Frage zur Rahmenverbindung kurz in der Zeile „Maschinen“, rechtsbuendig */
function emRvFrage(kopf) {
  if (!kopf) { return; } if (kopf.wemRv) { return; } kopf.wemRv = 1;
  var w = ht('span', 'em-rvq', null, kopf);
  ht('span', null, 'Entscheiden Sie selbst: Steckrahmen oder PDF-Flansch (bis Luftdichtheitsklasse D)?', w);
  infoKnopf(w, 'Steckrahmen: ' + EM_RV_TXT.sr.d + ' PDF-Flansch: ' + EM_RV_TXT.pdf.d + ' Die Wahl gilt für Kanäle und Formstücke.', { label: 'Rahmenverbindung' });
}
/* Weiche der Rahmenverbindung: Steckrahmen ein Drittel, PDF-Flansch zwei Drittel mit allen vier Profilen */
function emRvWeiche(par, aktiv) {
  var w = ht('div', 'em-rv', null, par);
  var reihe = ht('div', 'em-rvr', null, w);
  each(['sr', 'pdf'], function (rv) {
    var b = ht('button', 'em-rvb ' + rv + (rv === aktiv ? ' on' : ''), null, reihe); b.type = 'button'; b.wrv = rv;
    b.setAttribute('aria-pressed', rv === aktiv ? 'true' : 'false');
    var bb = ht('span', 'em-rvbb', null, b);
    each(EM_RV_TXT[rv].p, function (key) {
      var f = ht('span', 'em-rvp', null, bb); profilSvg(key, f, { sw: 2.2, gross: 86, echt: true, spiegel: EM_SPIEGEL.indexOf(key) !== -1 });
      if (gt(EM_RV_TXT[rv].p.length, 1)) { var P = (DATA.prof || {})[key]; if (P) { ht('small', null, P.t.replace(/ *\([^)]*\)/g, ''), f); } }
    });
    ht('b', 'em-rvn2', EM_RV_TXT[rv].t, b);
    b.addEventListener('click', function () { emRvSetzen(rv, b.closest ? b.closest('.em-box') : null); });
    if (EM_KLICK === 'rv:' + rv) { emKlickRahmen(b); }
  });
  emHinweisEinmal(w, 'em-rv-puls');
  return w;
}
/* einmal kurz aufmerksam machen, wenn das Element zum ersten Mal sichtbar wird (gelbes Aufleuchten, Dimi 10.11.2026: bleibt) */
var EM_HW = {};
function emHinweisEinmal(el, kl) {
  if (EM_HW[kl]) { return; } if (!BEWEGUNG) { return; } if (!window.IntersectionObserver) { return; }
  var io = new IntersectionObserver(function (es) {
    each(es, function (e) {
      if (!e.isIntersecting) { return; } io.disconnect(); if (EM_HW[kl]) { return; } EM_HW[kl] = 1;
      window.setTimeout(function () { el.classList.add(kl); window.setTimeout(function () { el.classList.remove(kl); }, 2600); }, 400);
    });
  }, { threshold: 0.9 });
  io.observe(el);
}
/* kurzer Name eines Formstuecks: erste Bauform (DATA.bfn), sonst der Name bis zum ersten Komma */
function emTeilKurz(p) { var n = ((DATA.bfn || {})[p] || [])[0]; if (n) { return n; } var b = BT[p]; return b ? kurzName(b).split(',')[0] : p; }
/* ---------- Vorlage (DATA.klay) ---------- */
/* o.vorlage: Schluessel in DATA.klay, der erste gefundene gilt (Bauteil, dann Kategorie); bei sr und pdf die gewaehlte Rahmenverbindung */
function emVorlage(o, mitRv) {
  var K = DATA.klay || {}, T = null;
  each(o.vorlage || [], function (key) { if (!T) { if (K[key]) { T = K[key]; } } });
  if (!T) { return null; }
  /* Bauteil ohne Wahl der Rahmenverbindung (z. B. Endkappe): Vorlage Steckrahmen */
  if (T.sr || T.pdf) { T = (mitRv ? T[EM_RV] : null) || T.sr || T.pdf; }
  return T;
}
/* Zeilen nach der Vorlage: Reihenfolge der Vorlage, mehrere Bereiche einer Vorlagenzeile werden eine Zeile; nicht genannte Zeilen folgen */
function emZeilenVorlage(zeilen, T) {
  if (!T) { return zeilen; }
  var R = [], benutzt = {};
  each(T.zeilen || [], function (tz) {
    var L = [];
    each(zeilen, function (z, i) {
      if (benutzt[i]) { return; }
      if (tz.el !== undefined) { if (z.id === tz.el) { L.push(i); } return; }
      var ks = Array.isArray(tz.k) ? tz.k : [tz.k];
      if (z.k !== undefined) { if (ks.indexOf(z.k) !== -1) { L.push(i); } }
    });
    if (!L.length) { return; }
    var z0 = zeilen[L[0]], z = {}; for (var a in z0) { z[a] = z0[a]; }
    z.s = {}; z.ks = []; z.nrs = []; z.tz = tz;
    each(L, function (i) {
      benutzt[i] = 1; var q = zeilen[i];
      for (var p in q.s) { if (!z.s[p]) { z.s[p] = []; } each(q.s[p], function (st) { if (z.s[p].indexOf(st) === -1) { z.s[p].push(st); } }); }
      each(q.ks || [], function (k) { if (z.ks.indexOf(k) === -1) { z.ks.push(k); } });
      each(q.nrs || [], function (n) { if (z.nrs.indexOf(n) === -1) { z.nrs.push(n); } });
    });
    if (tz.t) { z.t = tz.t; } if (tz.sub !== undefined) { z.sub = tz.sub; }
    /* Runde 18: eigenes Elementbild der Zeile (z. B. Kulissenrahmen und Kammerblech: Rahmen, Profile und Kammerbleche gelb) */
    if (tz.bild) { z.bild = tz.bild; }
    R.push(z);
  });
  each(zeilen, function (z, i) { if (!benutzt[i]) { R.push(z); } });
  return R;
}
/* ---------- Tabelle ---------- */
function emStufen(par, Z, sp, M, o, T) {
  var wrap = ht('div', 'em-w em-s', null, par);
  var EM_TEILE = o.teile || [];
  /* nur Verweise (Kulissenschalldaempfer, Dimi 10.11.2026: keine Stufen, keine Ueberschrift) */
  var nurRef = !M.U.length;
  if (nurRef) { each(sp, function (c, j) { if (M.art[j] !== 'spalte') { nurRef = false; } }); }
  if (nurRef) {
    wrap.classList.add('em-eins');
    each(Z, function (z, r) {
      var refs = []; each(M.H[r], function (cell) { each(cell.ref, function (k) { if (refs.indexOf(k) === -1) { refs.push(k); } }); });
      if (!refs.length) { return; }
      var zl = ht('div', 'em-sz em-nur', null, wrap); emElement(zl, z, o);
      var g = ht('div', 'em-g', null, zl); each(refs, function (k) { emRef(k, g); });
    });
    return wrap;
  }
  var stufen = ['M', 'T', 'V'].filter(function (q) { var da = false; each(sp, function (c) { if (c.q === q) { da = true; } }); return da; });
  var rvs = []; each(sp, function (c) { if (c.w) { if (c.w.rv) { if (rvs.indexOf(c.w.rv) === -1) { rvs.push(c.w.rv); } } } });
  var mitRv = gt(rvs.length, 1) ? true : (rvs.length === 1 ? rvs[0] === 'pdf' : false);
  if (mitRv) { emRvWeiche(wrap, EM_RV); emRvFrage(o.kopfZeile || null); }
  var inhalt = ht('div', 'em-si', null, wrap);
  /* Teile der Tabelle (in „Alle …“ ohne die Bauteile mit eigenem Weg, o.teile) */
  var ALLE = []; each(Z, function (z) { for (var p in z.s) { if (ALLE.indexOf(p) === -1) { if (!EM_TEILE.length) { ALLE.push(p); } else if (EM_TEILE.indexOf(p) !== -1) { ALLE.push(p); } } } });
  /* Spalten einer Stufe: Weg der gewaehlten Rahmenverbindung, Spalten ohne Weg, Anlagen; Wege der anderen Rahmenverbindung entfallen
     (Dimi 11.11.2026, 16:23: kein „auf Anfrage“) */
  function spalten(q) {
    var R = [];
    each(sp, function (c, j) { if (c.q !== q) { return; } if (c.w ? (c.w.rv ? c.w.rv !== EM_RV : false) : false) { return; } R.push(j); });
    return R;
  }
  var STUFEN_SP = stufen.map(function (q) { return { q: q, js: spalten(q) }; });
  var einsQ = 0; each(STUFEN_SP, function (s) { if (s.js.length) { einsQ++; } });
  if (einsQ === 1) { wrap.classList.add('em-eins'); }
  /* Belegung: je Zeile die Maschinen mit niedrigster Stufe, Formstuecken und Schritten */
  var BEL = [], NR = 0; each(Z, function () { BEL.push({}); });
  function eintragen(r, e0, key, id, q, p, steps) {
    if (EM_OHNE.indexOf(id) !== -1) { return; }
    var E = BEL[r][key];
    if (!E) { E = BEL[r][key] = { key: key, e: e0, ids: [], idq: {}, stid: {}, n: NR++ }; }
    if (E.ids.indexOf(id) === -1) { E.ids.push(id); }
    if (E.idq[id] === undefined) { E.idq[id] = q; } else if (lt(EM_QN[q], EM_QN[E.idq[id]])) { E.idq[id] = q; }
    if (!p) { return; }
    if (!E.stid[p]) { E.stid[p] = {}; }
    var L = E.stid[p][id] || (E.stid[p][id] = []);
    each(steps || [], function (i) { if (L.indexOf(i) === -1) { L.push(i); } });
  }
  var ohneT = T ? (T.ohne || []) : [];
  each(STUFEN_SP, function (S) {
    each(S.js, function (j) {
      var c = sp[j];
      if (M.art[j] === 'spalte') {
        each(M.U, function (u) {
          each(Z, function (z, r) {
            var rk = r + '|' + j; if (!u.rc[rk]) { return; }
            var X = u.rx[rk] || {};
            for (var p in X) {
              if (EM_TEILE.length) { if (EM_TEILE.indexOf(p) === -1) { continue; } }
              for (var id in X[p]) { if (ohneT.indexOf(id) === -1) { eintragen(r, u.e, u.key, id, S.q, p, X[p][id]); } }
            }
          });
        });
        return;
      }
      /* Anlage oder Kette: Maschinen der Stationen in den Zeilen ihrer Schritte (ohne Schritte: in allen Zeilen des Bauteils) */
      var sts = c.blk ? [c.blk] : (c.w ? (c.w.st || [c.w]) : []);
      each(sts, function (st) {
        var us = emEinheiten(st.m || []);
        each(Z, function (z, r) {
          for (var p in z.s) {
            if (!c.per[p]) { continue; } if (EM_TEILE.length) { if (EM_TEILE.indexOf(p) === -1) { continue; } }
            var S0 = st.s || [], steps = S0.length ? z.s[p].filter(function (i) { return S0.indexOf(i) !== -1; }) : z.s[p].slice();
            if (!steps.length) { continue; }
            each(us, function (u) { each(u.ids, function (id) { if (ohneT.indexOf(id) === -1) { eintragen(r, u.e, u.key, id, S.q, p, steps); } }); });
          }
        });
      });
    });
  });
  var MIN = ((DATA.klay || {})._alle || {}).stufeMin || {};
  function idE(B, id) { for (var key in B) { if (B[key].ids.indexOf(id) !== -1) { return B[key]; } } return null; }
  /* Karte aus Maschinen der Zeile: niedrigste Stufe (Vorlage: q, stufeMin), Formstuecke und Schritte */
  function karte(B, ids, it) {
    var E0 = idE(B, ids[0]), q = 'V', st = {}, pu = [], ein = true;
    each(ids, function (id) {
      var E = idE(B, id); if (E !== E0) { ein = false; }
      if (lt(EM_QN[E.idq[id]], EM_QN[q])) { q = E.idq[id]; }
      var mq = MIN[id] || MIN[E.key.split('@')[0]]; if (mq) { if (gt(EM_QN[mq], EM_QN[q])) { q = mq; } }
      for (var p in E.stid) { var L = E.stid[p][id]; if (!L) { continue; } if (pu.indexOf(p) === -1) { pu.push(p); } if (!st[p]) { st[p] = []; } each(L, function (i) { if (st[p].indexOf(i) === -1) { st[p].push(i); } }); }
    });
    if (it) { if (it.q) { q = it.q; } }
    var key = ein ? E0.key : 'x:' + ids.join(',');
    return { key: key, e: E0.e, ids: ids, q: q, titel: it ? (it.t || '') : '', zusatz: it ? (it.zusatz || '') : '', zeig: it ? (it.zeig || null) : null, pu: pu, st: st, n: E0.n };
  }
  /* Eintrag der Vorlage einer Zeile zu einer Karte */
  function vorlageKarte(it, B, gen) {
    var o2 = typeof it === 'string' ? { m: it } : it, m = o2.m, nur = false, liste = null, ids = [];
    if (typeof m === 'string') { if (m.charAt(0) === '=') { nur = true; m = m.substr(1); } } else { liste = m || []; }
    for (var key in B) {
      var E = B[key], basis = key.split('@')[0];
      each(E.ids, function (id) {
        if (gen[id]) { return; }
        var ja = liste ? liste.indexOf(id) !== -1 : (m.indexOf('k:') === 0 ? basis === m : (nur ? id === m : E.ids.indexOf(m) !== -1));
        if (ja) { ids.push(id); }
      });
    }
    if (!ids.length) { return null; }
    if (liste) { ids.sort(function (a, b) { return liste.indexOf(a) - liste.indexOf(b); }); }
    each(ids, function (id) { gen[id] = 1; });
    return karte(B, ids, o2);
  }
  /* 1. Karten aus der Vorlage */
  var ROWS = Z.map(function (z, r) {
    var B = BEL[r], gen = {}, G = [];
    if (z.tz) {
      each(z.tz.g || [], function (grp) {
        var K = [], hoch = 0; each(grp, function (it) { if (typeof it !== 'string') { if (it.hoch) { hoch = it.hoch; } } var k = vorlageKarte(it, B, gen); if (k) { K.push(k); } });
        if (K.length) { if (hoch) { K.hoch = hoch; } G.push(K); }
      });
    }
    return { z: z, r: r, G: G, gen: gen };
  });
  /* 2. uebrige Maschinen: am Ende der Zeile, wenn sie in keiner anderen Zeile eingetragen sind; ohne Vorlage je Stufe eine Gruppe */
  each(ROWS, function (R0) {
    var B = BEL[R0.r], rest = [], ohneZ = R0.z.tz ? (R0.z.tz.ohne || []) : [];
    for (var key in B) {
      var E = B[key], offen = E.ids.filter(function (id) {
        if (R0.gen[id]) { return false; }
        if (ohneZ.indexOf(id) !== -1) { return false; }
        var sonst = false; each(ROWS, function (R1) { if (R1 !== R0) { if (R1.gen[id]) { sonst = true; } } });
        return !sonst;
      });
      if (offen.length) { rest.push(karte(B, offen, null)); }
    }
    if (!rest.length) { return; }
    rest.sort(function (a, b) { return (EM_QN[a.q] - EM_QN[b.q]) || (emRang(a.ids) - emRang(b.ids)) || (a.n - b.n); });
    if (R0.z.tz) { R0.G.push(rest); R0.rest = 1; return; }
    each(['M', 'T', 'V'], function (q) { var K = rest.filter(function (k) { return k.q === q; }); if (K.length) { R0.G.push(K); } });
  });
  /* Verweise je Zeile */
  each(ROWS, function (R0) {
    var refs = []; each(STUFEN_SP, function (S) { each(S.js, function (j) { each(M.H[R0.r][j].ref, function (k) { if (refs.indexOf(k) === -1) { refs.push(k); } }); }); });
    R0.refs = refs;
  });
  /* 3. Zeilen mit denselben Karten werden eine Zeile (Dimi 11.11.2026, 16:23, Wickelfalzrohr) */
  function sig(R0) { return R0.G.map(function (K) { return K.map(function (k) { return k.ids.join(',') + ':' + k.q; }).join('+'); }).join('|'); }
  var ZEIG = [];
  each(ROWS, function (R0) {
    if (!(R0.G.length + R0.refs.length)) { return; }
    var s = sig(R0) + '#' + R0.refs.join(','), ziel = null;
    if (R0.G.length) { each(ZEIG, function (Z0) { if (!ziel) { if (Z0.s === s) { ziel = Z0; } } }); }
    if (ziel) {
      var z = ziel.R.z;
      if (!z.wemKopie) {
        var z2 = {}; for (var a in z) { z2[a] = z[a]; }
        z2.wemKopie = 1; z2.mitL = []; z2.ks = (z.ks || []).slice(); z2.ids = z.id ? [z.id] : []; z2.s = {};
        for (var p2 in z.s) { z2.s[p2] = z.s[p2].slice(); }
        ziel.R.z = z = z2;
      }
      z.mitL.push(R0.z); if (R0.z.id) { z.ids.push(R0.z.id); }
      each(R0.G, function (K, gi) { each(K, function (k, ki) { var k0 = ziel.R.G[gi][ki]; each(k.pu, function (p) { if (k0.pu.indexOf(p) === -1) { k0.pu.push(p); } }); for (var p3 in k.st) { if (!k0.st[p3]) { k0.st[p3] = []; } each(k.st[p3], function (i) { if (k0.st[p3].indexOf(i) === -1) { k0.st[p3].push(i); } }); } }); });
      each(R0.z.ks || [], function (k) { if (z.ks.indexOf(k) === -1) { z.ks.push(k); } });
      for (var p in R0.z.s) { if (!z.s[p]) { z.s[p] = []; } each(R0.z.s[p], function (i) { if (z.s[p].indexOf(i) === -1) { z.s[p].push(i); } }); }
      return;
    }
    ZEIG.push({ s: s, R: R0 });
  });
  /* Formstuecke mit eigenem Weg (Maschinen aus o.ohne, z. B. gepresste Formteile): zaehlen nicht mit, wenn eine Maschine fuer alle gilt */
  var OHNE = o.ohne || [], SONDER = [];
  each(ALLE, function (p) { var b = BT[p], ja = false; if (!b) { return; } each(b.schritte || [], function (s) { each(['M', 'T', 'V'], function (q) { each(s[q] || [], function (id) { if (OHNE.indexOf(id) !== -1) { ja = true; } }); }); }); if (ja) { SONDER.push(p); } });
  /* Bild beim Zeigen auf eine Karte: Vorlage, sonst das Formstueck, fuer das die Maschine in dieser Zeile gilt, mit ihrem Bereich */
  function zeigVon(k, z) {
    if (k.zeig) { return k.zeig; }
    var PR = ALLE.filter(function (p) { return z.s[p] ? z.s[p].length !== 0 : false; });
    var PU = PR.filter(function (p) { return k.pu.indexOf(p) !== -1; });
    if (!PU.length) { return null; }
    var PR2 = PR.filter(function (p) { return SONDER.indexOf(p) === -1; }); if (!PR2.length) { PR2 = PR; }
    var PU2 = PU.filter(function (p) { return PR2.indexOf(p) !== -1; }); if (!PU2.length) { PU2 = PU; }
    if (lt(PU2.length, PR2.length)) {
      var p1 = PU2[0], kb = emSchrittBereiche(p1, k.st[p1]), zb = emZeilenBereiche(z, p1);
      if (zb.length) { kb = kb.filter(function (x) { return zb.indexOf(x) !== -1; }); }
      return { pid: p1, ks: kb.length ? kb : zb, t: PU2.map(emTeilKurz).join(', ') };
    }
    var pid = o.bild ? o.bild.pid : PR[0]; if (PU.indexOf(pid) === -1) { return null; }
    var kb2 = emSchrittBereiche(pid, k.st[pid]), zb2 = emZeilenBereiche(z, pid);
    kb2 = kb2.filter(function (x) { return zb2.indexOf(x) !== -1; });
    if (!kb2.length) { return null; }
    /* Bereiche ohne eigenen Schritt im Ablauf des Bauteils (z. B. Biegekanten am Rechteckkanal, Runde 17) zaehlen beim Vergleich nicht */
    var UA = []; each((DATA.bj || {})[pid] || [], function (ks) { each(ks || [], function (x) { if (UA.indexOf(x) === -1) { UA.push(x); } }); });
    var zb3 = zb2.filter(function (x) { return UA.indexOf(x) !== -1; }); if (zb3.length) { zb2 = zb3; }
    if (!lt(kb2.length, zb2.length)) { return null; }
    return { pid: pid, ks: kb2, t: '' };
  }
  /* 4. Zeichnen; Runde 18 (Dimi 11.11.2026, 20:13): eine Gruppe mit „hoch“ steht als Karte fuer zwei Zeilen rechts neben dieser und der
     vorigen Zeile, die Trennlinie laeuft durch beide Zeilen (z. B. Automatische Rohrschweissanlage, Schalldaempferkulissenmaschine) */
  function hochG(R0) { return R0.G.filter(function (K) { return !!K.hoch; }); }
  function zeichne() {
    emNeuerAufbau();
    while (inhalt.firstChild) { inhalt.removeChild(inhalt.firstChild); }
    var dz = null;
    each(ZEIG, function (Z0, zi) {
      var R0 = Z0.R, z = R0.z, HG = hochG(R0), nx = ZEIG[zi + 1], nHoch = nx ? !!hochG(nx.R).length : false;
      if (nHoch) { if (!dz) { dz = ht('div', 'em-dz', null, inhalt); dz.wL = ht('div', 'em-dzl', null, dz); } }
      var zl = ht('div', 'em-sz', null, dz ? dz.wL : inhalt), EL = emElement(zl, z, o);
      var g = ht('div', 'em-g', null, zl), neben = dz ? (HG.length ? true : false) : false;
      each(R0.G, function (K, gi) {
        if (neben) { if (K.hoch) { return; } }
        var gr = ht('div', 'em-gr' + (R0.rest ? (gi === R0.G.length - 1 ? ' rest' : '') : ''), null, g);
        each(K, function (k) { var c = emKarte(k, gr); c.wemZeig = zeigVon(k, z); });
      });
      if (neben) {
        var r = ht('div', 'em-dzr', null, dz), E1 = dz.wEL;
        each(HG, function (K) { var gh = ht('div', 'em-gr em-gh', null, r); each(K, function (k) { emKarte(k, gh); }); });
        /* Zeigen: beide Elementkarten leuchten, die Karte gilt fuer beide Zeilen */
        r.addEventListener('mouseover', function () { if (E1) { E1.el.classList.add('hl'); } EL.el.classList.add('hl'); });
        r.addEventListener('mouseout', function (ev) { if (ev.relatedTarget ? r.contains(ev.relatedTarget) : false) { return; } if (E1) { E1.el.classList.remove('hl'); } EL.el.classList.remove('hl'); });
        dz = null;
      } else if (dz) { dz.wEL = EL; }
      if (R0.refs.length) { var gr2 = ht('div', 'em-gr em-refs', null, g); each(R0.refs, function (k) { emRef(k, gr2); }); }
      var tipp = null, typ = 'mouse';
      g.addEventListener('pointerdown', function (ev) { typ = ev.pointerType || 'mouse'; });
      g.addEventListener('mouseover', function (ev) { var c = ev.target.closest ? ev.target.closest('.em-k') : null; if (c) { EL.setz(c.wemZeig || null); } });
      g.addEventListener('mouseout', function (ev) { var c = ev.target.closest ? ev.target.closest('.em-k') : null; if (!c) { return; } if (ev.relatedTarget ? c.contains(ev.relatedTarget) : false) { return; } if (tipp !== c) { EL.setz(null); } });
      /* Handy: erstes Antippen zeigt das Bild links, zweites oeffnet die Seite */
      g.addEventListener('click', function (ev) {
        if (typ === 'mouse') { return; }
        var c = ev.target.closest ? ev.target.closest('.em-k') : null; if (!c) { return; } if (!c.wemZeig) { return; }
        if (ev.target.closest('.wmk-pl')) { return; }
        if (tipp === c) { return; }
        ev.preventDefault(); tipp = c; EL.setz(c.wemZeig);
        window.setTimeout(function () { if (tipp === c) { tipp = null; } }, 4000);
      });
    });
  }
  zeichne();
  /* Kartenbreite: die laengste Zeile passt in eine Reihe (176 bis 140 px), sonst bricht sie um (Dimi 11.11.2026, 16:23: Platz nutzen) */
  var NR2 = ZEIG.map(function (Z0, zi) { var n = 0, nx = ZEIG[zi + 1]; each(Z0.R.G, function (K) { n += K.length; }); if (nx) { each(hochG(nx.R), function (K) { n += K.length; }); } return { n: n, refs: Z0.R.refs.length ? 1 : 0 }; });
  function breite() {
    if (!wrap.isConnected) { return; }
    var W = inhalt.clientWidth || wrap.clientWidth; if (!W) { return; }
    var lw = gt(W, 700) ? 176 : 132, w = 176, gp = gt(W, 700) ? EM_GAP : 10;
    each(NR2, function (x) { if (!x.n) { return; } var b = (W - lw - gp - (x.n - 1) * gp - (x.refs ? 160 + gp : 0) - 4) / x.n; if (lt(b, w)) { w = b; } });
    w = Math.max(140, Math.min(176, Math.floor(w)));
    if (lt(W, 701)) { w = 150; }
    wrap.style.setProperty('--emk', w + 'px'); wrap.style.setProperty('--emgap', gp + 'px');
  }
  window.requestAnimationFrame(breite);
  if (window.ResizeObserver) { var bw0 = -1; new ResizeObserver(function () { var x = Math.round(inhalt.clientWidth); if (x === bw0) { return; } bw0 = x; breite(); }).observe(inhalt); }
  return wrap;
}
/* Tabelle: alle Tabellen der Seite schalten die Rahmenverbindung gemeinsam; o.vorlage: Schluessel der Vorlage, o.kopfZeile: Zeile „Maschinen“ */
function emTabelle(par, zeilen, sp, kid, o) {
  o = o || {};
  var box = ht('div', 'em-box', null, par), ziel = ht('div', 'em-ziel', null, box);
  function zeichne() {
    emNeuerAufbau();
    while (ziel.firstChild) { ziel.removeChild(ziel.firstChild); }
    var mitRv = false; each(sp, function (c) { if (c.w) { if (c.w.rv) { mitRv = true; } } });
    var T = emVorlage(o, mitRv), Z = emZeilenVorlage(zeilen, T);
    EM_OHNE = o.ohne || [];
    var F = emZeilenFiltern(Z, sp, kid);
    emStufen(ziel, F.Z, sp, F.M, o, T);
    EM_OHNE = [];
  }
  EM_ALLE = EM_ALLE.filter(function (f) { return f.wemBox ? f.wemBox.isConnected : false; });
  zeichne(); zeichne.wemBox = box; zeichne.wemZiel = ziel; EM_ALLE.push(zeichne);
  return box;
}
/* Runde 17 (Dimi 11.11.2026, 16:23): eine Schrift und wenige Groessen in der ganzen Kartei (20 Titel, 14 Text, 12 Ueberschriften und
   Bezeichnungen, 11 Titelzeile der Karten, 10 Hersteller und Vermerke), Farben navy, Text, Grau; Abstaende knapp */
var CSSE = [
  '.em-box{margin:2px 0 0 0}',
  /* knapper Abstand zwischen Kopf, „Fertigung“, „Maschinen“ und Tabelle (Dimi 11.11.2026, 16:23) */
  '.wkp{margin:2px 0 0 0}',
  '.wkp-auf{padding:6px 10px;margin:0 0 4px 0}',
  '.wkp-k2{margin:6px 0 2px 0}',
  '.em-w{overflow-x:auto;-webkit-overflow-scrolling:touch}',
  /* Zeilen: links die Elementkarte, rechts die Gruppen */
  '.em-sz{display:grid;grid-template-columns:176px minmax(0,1fr);gap:0;border-bottom:1px solid #D5DDE6;padding:6px 0}',
  /* Runde 18 (Dimi 11.11.2026, 20:13): ein Abstand zwischen allen Karten (--emgap); die senkrechte Linie zwischen den Gruppen steht in diesem Abstand */
  '.em-g{display:flex;flex-wrap:wrap;gap:6px var(--emgap,14px);align-items:stretch;padding:0 0 0 var(--emgap,14px);min-width:0}',
  '.em-gr{position:relative;display:flex;flex-wrap:wrap;gap:6px var(--emgap,14px);align-items:flex-start;padding:0}',
  '.em-gr+.em-gr::before,.em-dzr::before{content:"";position:absolute;top:0;bottom:0;left:calc(var(--emgap,14px) / -2 - 1.5px);width:3px;background:#1F3855}',
  /* Karte fuer zwei Zeilen: rechts neben beiden Zeilen, die Linie laeuft durch beide */
  '.em-dz{display:flex;align-items:stretch;border-bottom:1px solid #D5DDE6}',
  '.em-dzl{flex:0 1 auto;min-width:0}',
  '.em-dzl .em-sz:last-child{border-bottom:0}',
  '.em-dzr{position:relative;display:flex;align-items:center;margin:6px 0 6px var(--emgap,14px);padding:0}',
  '.em-dzr::before{left:calc(var(--emgap,14px) / -2 - 1.5px)}',
  '.em-gr.em-refs{align-items:center}',
  /* Elementkarte: wie eine Maschinenkarte, blaeulicher Grund */
  '.em-el.wmk-c{position:sticky;left:0;z-index:3;width:176px;background:#EEF3F8;border-color:#C9D4E0;box-sizing:border-box;transition:background .15s}',
  '.em-el.wmk-c .wk-ot{display:block;height:21px;box-sizing:border-box}',
  /* Runde 18 (Dimi 11.11.2026, 20:13): Bild ohne weissen Grund, der Grund der Elementkarte scheint durch */
  /* Runde 18 (Punkt 6): Querstreifen der Elementkarte auf derselben Hoehe wie bei den Karten (gleiche Bildhoehe, Vorrang vor .wmk-c.wk .wmk-bi) */
  '.em-el.wmk-c .em-eb{position:relative;display:block;height:calc(var(--emk,176px) * 0.7);margin:4px 6px;background:transparent;border:0;box-sizing:border-box}',
  '.em-el.wmk-c .em-eb.leer{height:8px;border:0;background:none}',
  '.em-ebi{position:absolute;left:0;top:0;width:100%;height:100%;opacity:0;transition:opacity .25s}',
  '.em-ebi.auf{opacity:1}',
  '.em-ebi svg{display:block;width:100%;height:100%}',
  '.em-el .wmk-tx{position:relative;display:flex;flex-direction:column;gap:1px;height:86px;box-sizing:border-box;overflow:hidden}',
  '.em-zt b{font-size:13px;line-height:16px;font-weight:700;color:#1F3855;-webkit-hyphens:manual;hyphens:manual;overflow-wrap:break-word}',
  '.em-zt small{font-size:11px;line-height:14px;color:#5C6670;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}',
  '.em-el .em-eli{position:absolute;right:4px;top:1px;z-index:5;margin:0}',
  '.em-el:hover,.em-el.hl{background:#FFF5D1;border-color:#E0A800}',
  '.em-el.zg{background:#FFF8DD}',
  /* Karten gleich hoch: Titelzeile immer, Bild 124 px, Text 86 px mit dem Hersteller unten rechts */
  '.em-k.wmk-c{position:relative;display:flex;flex-direction:column;width:var(--emk,176px);flex:0 0 auto;background:#fff;border:1px solid #D5DDE6;box-sizing:border-box}',
  '.em-k.wmk-c.lk:hover{border-color:#1F3855;box-shadow:0 2px 10px rgba(31,56,85,.18)}',
  '.em-k.wmk-c .wk-ot{display:block;height:21px;box-sizing:border-box;padding:5px 8px 0 8px;font-size:11px;line-height:15px;color:#5C6670}',
  '.em-k.wmk-c .wmk-bi{height:calc(var(--emk,176px) * 0.7);margin:4px 6px}',
  '.em-k.wmk-c .wmk-tx{position:relative;display:flex;flex-direction:column;gap:1px;height:86px;box-sizing:border-box;overflow:visible;padding:6px 8px 5px 8px}',
  /* Runde 18 (Dimi 11.11.2026, 20:13): Bezeichnung hoechstens zwei Zeilen, sonst „…“; der Typ steht vollstaendig (Umbruch nur nach dem Komma) */
  '.em-k.wmk-c .wmk-mb{display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;max-height:30px;overflow:hidden;font-size:12px;line-height:15px;color:#5C6670}',
  '.em-k.wmk-c.wk.grp .wmk-mb{font-size:12px;line-height:15px;-webkit-line-clamp:2;min-height:0}',
  '.em-k.wmk-c .wmk-ty{font-size:13px;line-height:16px;color:#1F3855;white-space:normal;overflow:visible;text-overflow:clip}',
  '.em-k.wmk-c .wmk-br{margin-top:auto;text-align:right;font-size:10px;line-height:13px;color:#8A939C}',
  '.em-k .wmk-pl{top:6px;right:6px;width:24px;height:24px;opacity:0;transition:opacity .15s}',
  '.em-k:hover .wmk-pl,.em-k:focus-within .wmk-pl,.em-k .wmk-pl.on{opacity:1}',
  '@media (hover:none){.em-k .wmk-pl{opacity:.9}}',
  /* Vermerk der Stufe: Rechteck auf dem blauen Querstreifen, rechts */
  '.em-tags{position:absolute;right:6px;top:-10px;z-index:3;display:flex;gap:3px}',
  '.em-tag{display:block;height:16px;padding:0 6px;font-size:10px;line-height:16px;font-weight:700;letter-spacing:.06em;color:#fff;background:#1F3855;box-sizing:border-box;white-space:nowrap}',
  '.em-tag.zs{color:#1F3855;background:#fff;border:1px solid #1F3855;line-height:14px}',
  /* in der Vorschau: Maschine, die nicht in der Vorlage steht (gehoert nachgetragen) */
  '[data-vorschau="1"] .em-gr.rest .em-k{outline:2px dashed #E0A800;outline-offset:-2px}',
  /* Weiche der Rahmenverbindung: Steckrahmen ein Drittel, PDF-Flansch zwei Drittel; Frage in der Zeile „Maschinen“ */
  '.em-rv{margin:0 0 6px 0}',
  '.em-rvq{display:inline-flex;align-items:center;gap:6px;font-size:12px;line-height:16px;font-weight:700;letter-spacing:.04em;color:#1F3855;text-align:right}',
  '.em-rvr{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:10px}',
  '.em-rvb.pdf{grid-column:span 2}',
  '.em-rvb{position:relative;display:flex;flex-direction:column;align-items:center;gap:2px;padding:0 0 6px 0;font-family:inherit;text-align:center;background:#fff;color:#1F3855;border:2px solid #C3CCD6;cursor:pointer;overflow:hidden;transition:background .25s,color .25s,border-color .25s,box-shadow .3s}',
  '.em-rvb:hover{border-color:#1F3855}',
  '.em-rvb.on{color:#fff;background:#1F3855;border-color:#1F3855}',
  '.em-rvb.em-kl{box-shadow:0 0 0 4px #1F3855}',
  '.em-rvbb{display:flex;align-items:stretch;justify-content:center;width:100%;height:80px;background:#fff;border-bottom:4px solid #B3B8BE;margin:0 0 4px 0;box-sizing:content-box}',
  '.em-rvb.on .em-rvbb{border-bottom-color:#F7BC0C}',
  '.em-rvp{flex:0 1 110px;display:flex;flex-direction:column;align-items:center;justify-content:center;min-width:0;padding:2px 2px 0 2px}',
  '.em-rvp .wpq{width:62px;height:62px;flex:0 0 auto}',
  '.em-rvp small{font-size:10px;line-height:13px;color:#5C6670;white-space:nowrap}',
  /* eine Schrift fuer „Maschinen“, „Fertigung in … Schritten“ und die Rahmenverbindung */
  '.em-rvn2,.wkp-k h4,.wkp-kt{font-size:12px;line-height:16px;font-weight:700;text-transform:uppercase;letter-spacing:.04em}',
  '@keyframes emPuls{0%{box-shadow:0 0 0 0 rgba(247,188,12,0)}35%{box-shadow:0 0 0 7px rgba(247,188,12,.6)}100%{box-shadow:0 0 0 0 rgba(247,188,12,0)}}',
  '.em-rv-puls .em-rvb{animation:emPuls 1.2s ease 2}',
  '.em-rv-puls .em-rvb+.em-rvb{animation-delay:.3s}',
  '@media (max-width:700px){.em-g,.em-gr{flex-wrap:nowrap}.em-sz{grid-template-columns:132px max-content}.em-el.wmk-c{width:132px}.em-el.wmk-c .em-eb{height:96px}.em-k.wmk-c .wmk-bi{height:96px}.em-rvr{grid-template-columns:minmax(0,1fr)}.em-rvb.pdf{grid-column:auto}.em-rvp{flex-basis:80px}.em-rvp .wpq{width:52px;height:52px}.em-rvq{text-align:left}}',
  /* Handy-Runde (Dimi 12.11.2026, Prüfliste 25.9): Elementspalte bleibt beim waagerechten Wischen stehen (die Zeile ist so breit wie
     ihr Inhalt, sonst endet das Haften am Rand der Zeile) und ist schmaler (96 px) */
  '@media (max-width:700px){.em-sz,.em-dz{width:max-content;min-width:100%}.em-sz{grid-template-columns:96px max-content}.em-el.wmk-c{width:96px}.em-el.wmk-c .em-eb{height:70px}.em-el.wmk-c .wk-ot{font-size:10px}}',
  '@media (prefers-reduced-motion:reduce){.em-rvb{animation:none!important;transition:none}.em-ebi{transition:none}}'
].join('');

/* ---------- Maschinenbezug der Kacheln (Dimi 09.11.2026, Runde 9: Vorschlag 1 fest, auch auf der Website) ----------
   Kategorie-Kachel „Nach Bauteil“ und Anwendungs-Kachel „Nach Anwendung“: neben dem Bild ein Maschinenfeld. In Ruhe steht das
   feste Leitbild der Kachel (verfahren_v1.json: kategorien[].leit = {m, q}, anwendungen[].leit = Maschine); beim Zeigen
   blenden die Maschinen weich nacheinander ein (Bauteil: je Stufe bis drei, Anwendung: bis sechs; 2 s je Bild), beim
   Verlassen steht sofort wieder das Leitbild. Die Vorschlaege 2 (Bilder im Hinweis der Szene) und 3 (Leitmaschine in der
   Kartei) entfallen (Dimi 09.11.2026). Fotos nur ueber bildUrl; fehlt ein Foto, steht das Maschinensymbol. */
/* Runde 12 der Szene (Dimi 10.11.2026): auf der ganzen Seite dieselben, ruhigeren Zeiten wie in 44_wechsel.js (WB_FOTO) */
var MB_STUFEN = ['M', 'T', 'V'], MB_JE = 3, MB_MS = 3200, MB_IO = null;
/* Eintrag fuer eine Maschine: Gattung oder Familie zusammengefasst (ids = alle Mitglieder) */
function mbSchluessel(id) {
  var ga = gatVon(id), fi = famVon(id);
  return { key: ga ? 'g' + ga.t : (fi !== undefined ? 'f' + fi : 'm' + id), name: ga ? gatText(ga.t, true) : (fi !== undefined ? DATA.fam[fi].t : trennen(kurz(masch(id)))) };
}
function mbAufnehmen(liste, gesehen, id, q) {
  var m = masch(id); if (!m) { return; } if (m.g) { return; } if (m.z) { return; }
  var v = verfahrenVon(id); if (v) { if (v.id === 'software') { return; } }
  var s = mbSchluessel(id), foto = bildUrl(id, m), alt = gesehen[q + s.key];
  if (alt !== undefined) { var x = liste[alt]; x.ids.push(id); if (!x.foto) { if (foto) { x.foto = foto; x.id = id; } } return; }
  gesehen[q + s.key] = liste.length;
  liste.push({ id: id, q: q, name: s.name, foto: foto, ids: [id] });
}
function fotoZuerst(a) { return a.filter(function (x) { return !!x.foto; }).concat(a.filter(function (x) { return !x.foto; })); }
/* Maschinen einer Teileliste je Stufe, ohne „nicht im Programm“ und Software; Reihenfolge der Schritte, Fotos vor Symbolen */
function mbMaschinen(teile) {
  var R = { M: [], T: [], V: [] }, gesehen = {};
  each(teile, function (p) {
    var b = BT[p]; if (!b) { return; }
    var D = stufenDaten(b);
    each(MB_STUFEN, function (q) { each(D[q].ms, function (e) { mbAufnehmen(R[q], gesehen, e.id, q); }); });
  });
  each(MB_STUFEN, function (q) { R[q] = fotoZuerst(R[q]); });
  return R;
}
/* Festes Leitbild: Eintrag, der die Maschine enthaelt (in Stufe q, sonst in jeder Stufe); er zeigt das Foto dieser Maschine */
function mbLeitFest(liste, leit) {
  if (!leit) { return null; }
  var m = masch(leit.m); if (!m) { return null; }
  var x = null;
  each(liste, function (e) { if (x) { return; } if (leit.q) { if (e.q !== leit.q) { return; } } if (e.ids.indexOf(leit.m) !== -1) { x = e; } });
  if (!x) { return null; }
  var f = bildUrl(leit.m, m); if (f) { x.foto = f; x.id = leit.m; }
  return x;
}
/* Ersatz ohne festes Leitbild: erste V-Maschine mit Foto, sonst T, sonst M; ohne Fotos die erste Maschine */
function mbLeitAuto(liste) {
  var l = null;
  each(['V', 'T', 'M', ''], function (q) { if (l) { return; } each(liste, function (x) { if (l) { return; } if (q) { if (x.q !== q) { return; } } if (x.foto) { l = x; } }); });
  return l || liste[0] || null;
}
/* Foto einpassen (Runde 10 der Szene, Dimi 09.11.2026, Runde 11 Punkte 4 und 7: Bildhaelfte mit der Maschine fuellen, wenig Weiss):
   Motivrahmen r = [x0, y0, x1, y1, Breite/Hoehe] des Fotos aus DATA.mbr (verfahren_v1.json maschinenBildRahmen, berechnet mit
   werkzeug/bildrahmen.py). Das Motiv wird in die Flaeche eingepasst, rechtsbuendig (mitte: mittig); ohne Rahmen bleibt contain. */
var FR_RO = null;
/* Runde 18 (Dimi 11.11.2026, 22:43): Handwerkzeuge massstaeblich zueinander. DATA.mm[id] = Laenge, Hoehe in mm (TRUMPF);
   die Diagonale des Werkzeugs im Bild entspricht seiner wirklichen Diagonale; die Bildflaeche der Karte steht fuer MM_REF mm */
var MM_REF = 520;
function mmBreite(id) {
  var r = (DATA.mbr || {})[id], mm = (DATA.mm || {})[id]; if (!r || !mm) { return 0; }
  var mw = (r[2] - r[0]) * r[4], mh = r[3] - r[1];
  return Math.sqrt(mm[0] * mm[0] + mm[1] * mm[1]) * mw / Math.sqrt(mw * mw + mh * mh);
}
function fotoSetzen(im) {
  var r = im.wmbR, box = im.parentNode; if (!r || !box) { return; }
  var W = box.clientWidth, H = box.clientHeight; if (!W || !H) { return; }
  var A = r[4], mw = (r[2] - r[0]) * A, mh = r[3] - r[1], p = 2;
  var k = Math.min((W - 2 * p) / mw, (H - 2 * p) / mh);
  var mm = im.wmbMm;
  if (mm) {
    var fl = im.closest ? (im.closest('.wb') || im.closest('.wsd-pmi') || box) : box;
    var FW = fl.clientWidth || W, FH = fl.clientHeight || H;
    var s = Math.min(FW - 2 * p, FH - 2 * p) / MM_REF;
    var kmm = Math.sqrt(mm[0] * mm[0] + mm[1] * mm[1]) * s / Math.sqrt(mw * mw + mh * mh);
    if (lt(kmm, k)) { k = kmm; }
  }
  var x = im.wmbMitte ? (W - mw * k) / 2 - r[0] * A * k : W - p - r[2] * A * k, y = (H - mh * k) / 2 - r[1] * k;
  im.style.width = Math.round(A * k) + 'px'; im.style.height = Math.round(k) + 'px';
  im.style.left = Math.round(x) + 'px'; im.style.top = Math.round(y) + 'px';
}
function fotoRahmen(im, id, mitte) {
  var r = (DATA.mbr || {})[id]; if (!r) { return false; }
  im.classList.add('rh'); im.wmbR = r; im.wmbMitte = !!mitte; im.wmbMm = (DATA.mm || {})[id] || null;
  var box = im.parentNode;
  if (window.ResizeObserver) {
    if (!FR_RO) { FR_RO = new ResizeObserver(function (es) { each(es, function (e) { each(e.target.querySelectorAll('img.rh'), fotoSetzen); }); }); }
    if (!box.wmbRo) { box.wmbRo = 1; FR_RO.observe(box); }
  }
  fotoSetzen(im);
  return true;
}
/* Bild einer Maschine: Foto, sonst das Maschinensymbol im Endzustand */
function mbBild(x, par) {
  if (x.foto) { var im = ht('img', null, null, par); im.alt = ''; im.decoding = 'async'; im.src = x.foto; fotoRahmen(im, x.id, false); return; }
  var sy = maschSym(x.id), g = sy ? ikSvg(sy) : null, s = ht('span', 'wsd-pms', null, par);
  if (g) { g.classList.add('go'); g.classList.add('fix'); s.appendChild(g); }
}
function mbBeobachten(box, f) {
  if (!window.IntersectionObserver) { f(); return; }
  if (!MB_IO) {
    MB_IO = new IntersectionObserver(function (es) {
      each(es, function (e) { if (e.isIntersecting) { MB_IO.unobserve(e.target); if (e.target.wmbLos) { e.target.wmbLos(); } } });
    }, { rootMargin: '200px 0px' });
  }
  box.wmbLos = f; MB_IO.observe(box);
}
/* Maschinenfeld: folge = Bilder beim Zeigen, leit = Ruhebild. el: Kachel (Zeigen startet, Verlassen und Klick stoppen).
   Runde 9 (Dimi 09.11.2026): der Name steht unter dem Bild (verdeckt es nicht), ohne Kuerzel M, T, V.
   o.extern: die Folge steuert die Kachel selbst (Anwendung: Bild passend zum Ablauf), Rueckgabe .zeigeId(id) */
function mbFeld(el, folge, leit, par, o) {
  if (!leit) { return null; }
  o = o || {};
  if (folge.indexOf(leit) === -1) { folge.push(leit); }
  var box = ht('div', 'wsd-pm', null, par || el); box.setAttribute('aria-hidden', 'true');
  var flaeche = ht('div', 'wsd-pmi', null, box), cap = ht('div', 'wsd-pmc', null, box);
  var dias = [], ruhe = folge.indexOf(leit), jetzt = -1, tm = null, an = false, bereit = false, erst = false;
  function dia(i) {
    if (dias[i]) { return dias[i]; }
    var d = ht('div', 'wsd-pmd', null, flaeche);
    mbBild(folge[i], d);
    dias[i] = d; return d;
  }
  function zeig(i) {
    dia(i); jetzt = i;
    each(dias, function (d, j) { if (d) { d.classList.toggle('auf', j === i); } });
    cap.textContent = folge[i].name;
    if (o.beiZeig) { o.beiZeig(folge[i]); }
  }
  function weiter() {
    tm = null;
    if (!an) { return; }
    if (!el.isConnected) { stop(); return; }
    if (el.offsetParent === null) { stop(); return; }
    /* Folge von vorn; das Ruhebild kommt an seiner Stelle wieder */
    var i = erst ? (ruhe === 0 ? 1 : 0) : (jetzt + 1) % folge.length;
    erst = false; zeig(i);
    tm = window.setTimeout(weiter, MB_MS);
  }
  function start() {
    if (o.extern) { return; }
    if (!BEWEGUNG) { return; }
    if (!bereit) { return; }
    if (!gt(folge.length, 1)) { return; }
    if (an) { return; }
    an = true; box.classList.remove('sofort');
    each(folge, function (x, i) { dia(i); });
    erst = true;
    if (tm) { window.clearTimeout(tm); }
    tm = window.setTimeout(weiter, Math.round(MB_MS * 0.6));
  }
  function stop() {
    an = false;
    if (tm) { window.clearTimeout(tm); tm = null; }
    if (!bereit) { return; }
    box.classList.add('sofort'); zeig(ruhe);
  }
  mbBeobachten(box, function () { bereit = true; zeig(ruhe); });
  el.addEventListener('mouseenter', start);
  el.addEventListener('mouseleave', stop);
  el.addEventListener('click', stop);
  /* von aussen: Bild der Maschine id zeigen (Anwendung), null = Ruhebild */
  box.zeigeId = function (id) {
    if (!bereit) { return; }
    box.classList.remove('sofort');
    if (id === null) { box.classList.add('sofort'); zeig(ruhe); return; }
    var j = -1; each(folge, function (x, i) { if (j === -1) { if (x.ids.indexOf(id) !== -1) { j = i; } } });
    if (j !== -1) { zeig(j); }
  };
  box.wmbTest = { folge: folge.map(function (x) { return (x.q ? x.q + ':' : '') + x.id; }), ruhe: ruhe, jetzt: function () { return jetzt; } };
  return box;
}
/* Kategorie-Kachel: Maschinen der Bauteile je Stufe (bis drei je Stufe), Leitbild aus k.leit */
function mbKachel(el, k, par, o) {
  var R = mbMaschinen(k.teile), folge = [], alle = [];
  each(MB_STUFEN, function (q) { each(R[q], function (x) { alle.push(x); }); each(R[q].slice(0, MB_JE), function (x) { folge.push(x); }); });
  /* Runde 18 (Dimi 11.11.2026, 22:43): feste Folge der Kachel (k.folge, z. B. nur Kulissenmaschine und Kulissenrollformer) */
  if (k.folge) { folge = alle.filter(function (x) { var ja = false; each(k.folge, function (id) { if (x.ids.indexOf(id) !== -1) { ja = true; } }); return ja; }); folge.sort(function (a, b) { return mbFolgeRang(k, a) - mbFolgeRang(k, b); }); }
  var leit = mbLeitFest(alle, k.leit) || mbLeitAuto(alle);
  return mbFeld(el, folge, leit, par, o);
}
function mbFolgeRang(k, x) { var r = 99; each(k.folge, function (id, i) { if (x.ids.indexOf(id) !== -1) { if (lt(i, r)) { r = i; } } }); return r; }
/* Anwendungs-Kachel (Runde 9): zu jedem Symbol des Ablaufs die Maschine, die das macht (anwendungen[].paar), sonst
   Maschinen der Verfahren; Leitbild aus a.leit. Die Kachel schaltet das Bild mit dem Ablauf um (zeigeId).
   Ohne Leitbild mit Foto kein Maschinenfeld (z. B. Software, TRUMPF-Werkzeuge) */
function mbAnwendung(el, a, par) {
  if (!a.leit) { return null; }
  var liste = [], gesehen = {};
  each(a.paarIds || [], function (id) { mbAufnehmen(liste, gesehen, id, ''); });
  each(anwMaschinen(a), function (id) { mbAufnehmen(liste, gesehen, id, ''); });
  var leit = mbLeitFest(liste, { m: a.leit });
  if (!leit) { return null; } if (!leit.foto) { return null; }
  return mbFeld(el, liste, leit, par, { extern: true });
}

/* ---------- Wechselbild der Kacheln und Maschinenkarten ----------
   Runde 11 der Szene (Dimi 10.11.2026, Runde 12 der Antworten, Punkte 18 und 23): die ganze Flaeche zeigt die Maschine (Foto).
   Runde 12 der Szene (Dimi 10.11.2026, Auftrag 09:14): ruhiger und auf der ganzen Seite mit denselben Zeiten.
   Ohne Maus steht das Ruhebild (Foto der ersten Maschine, sonst ihr Ablauf im Endbild). Maus darauf: Endprodukt (wenn es eines
   gibt), Ablauf, Maschine, dann die naechste Maschine, im Wechsel, solange die Maus darauf ist. Maus weg: sofort das Ruhebild.
   o.ruhe 'takt' (Anwendungen): die Kachel wird von aussen im Gleichschritt mit allen anderen geschaltet (takt). */
var WB_FOTO = 3200, WB_PROD = 3200, WB_ZEIT = 3200, WB_ABLAUF_PLUS = 1000, WB_TAKT_ABLAUF = 5200, WB_IO = null;
/* Glieder einer Karte: je Maschine Foto, Symbol und Name; Maschinen „nicht im Programm“ und Handarbeit entfallen */
function wbGlieder(ids, o) {
  o = o || {};
  var R = [], gesehen = {};
  each(ids, function (id) {
    var m = masch(id); if (!m) { return; } if (m.g) { return; } if (m.z) { return; }
    var foto = bildUrl(id, m), sy = maschSym(id);
    /* gleiche Gattung oder Familie: ein Glied (Bild der ersten Maschine mit Foto) */
    var ga = gatVon(id), fi = famVon(id), key = o.einzeln ? id : (ga ? 'g' + ga.t : (fi !== undefined ? 'f' + fi : 'm' + id));
    var name = ga ? gatText(ga.t, false) : (fi !== undefined ? DATA.fam[fi].t : vollName(m));
    if (o.einzeln) { name = vollName(m); }
    if (gesehen[key] !== undefined) { var x = R[gesehen[key]]; if (!x.foto) { if (foto) { x.foto = foto; x.id = id; } } x.ids.push(id); return; }
    gesehen[key] = R.length;
    R.push({ id: id, ids: [id], foto: foto, sym: sy, name: name, prod: o.prod ? (o.prod[id] || o.prod['*'] || null) : null });
  });
  /* Vorschau: eine Maschine ohne eigenes Foto zeigt das Foto ihrer Familie (z. B. TruTool S 250 wie S 160); auf der Website hat sie ihr eigenes */
  each(R, function (x) {
    if (x.foto) { return; }
    var fi = famVon(x.id); if (fi === undefined) { return; }
    each(DATA.fam[fi].m, function (y) { if (x.foto) { return; } var my = masch(y); if (my) { var f = bildUrl(y, my); if (f) { x.foto = f; x.fotoVon = y; } } });
  });
  /* Ruhebild nach Wunsch (o.ruhe: Liste bevorzugter Maschinen), sonst Fotos zuerst; die Reihenfolge der Schritte bleibt erhalten */
  var mit = R.filter(function (x) { return !!x.foto; }), ohne = R.filter(function (x) { return !x.foto; });
  R = mit.concat(ohne);
  if (o.ruhe) {
    var rang = function (x) { var r = 99; each(o.ruhe, function (id, i) { if (x.ids.indexOf(id) !== -1) { if (lt(i, r)) { r = i; } } }); return x.foto ? r : 99 + r; };
    R.sort(function (a, b) { return rang(a) - rang(b); });
  }
  if (o.max) { R = R.slice(0, o.max); }
  return R;
}
/* Endprodukt: b:Bauteil (Zeichnung, erste Bauform), f:Falzart (Querschnitt), p:Ablaufsymbol im Endzustand */
function wbProdukt(tok, par) {
  if (!tok) { return null; }
  var art = tok.slice(0, 2), id = tok.slice(2), s = ht('span', 'wb-pr', null, par), name = '';
  if (art === 'b:') { var b = BT[id]; if (b) { symbolBild(b, s, true); name = kurzName(b); } }
  else if (art === 'f:') { profilSvg(id, s, { sw: 2.4, gross: 74, echt: true }); var P = (DATA.prof || {})[id]; name = P ? P.t : ''; }
  else if (art === 'p:') { var g = ikSvg(id); if (g) { g.classList.add('go'); g.classList.add('fix'); s.appendChild(g); } name = PNAME[id] || ''; }
  s.wbName = name;
  return s;
}
function wbDauer(g) {
  var ms = 3200;
  try {
    if (g.getAnimations) {
      var e = 0;
      each(g.getAnimations({ subtree: true }), function (a) { var t = a.effect ? a.effect.getComputedTiming().endTime : 0; if (isFinite(t)) { e = Math.max(e, t); } });
      if (e) { ms = Math.min(e, 12000); }
    }
  } catch (x) { }
  return ms;
}
function wbBeobachten(el, an) {
  if (!window.IntersectionObserver) { an(true); return; }
  if (!WB_IO) {
    WB_IO = new IntersectionObserver(function (es) { each(es, function (e) { if (e.target.wbSicht) { e.target.wbSicht(e.isIntersecting); } }); }, { threshold: 0.4 });
  }
  el.wbSicht = an; WB_IO.observe(el);
}
/* el: Element fuer Zeigen und Verlassen; flaeche: Bildflaeche; G: Glieder; o.ruhe ('takt'), o.cap (Element fuer den Namen des Bildes),
   o.capFn(x): eigene Beschriftung je Glied (Karten mit Bezeichnung, Typ, Hersteller) */
function wechselBild(el, flaeche, G, o) {
  o = o || {};
  flaeche.classList.add('wb');
  if (!G.length) { return null; }
  var dias = {}, jetzt = null, tm = null, modus = '', schritt = 0, folge = [];
  function dia(key, f) {
    if (dias[key]) { return dias[key]; }
    var d = ht('div', 'wb-d', null, flaeche); f(d); dias[key] = d; return d;
  }
  function fotoDia(x) {
    return dia('f' + x.id, function (d) { var im = ht('img', null, null, d); im.alt = ''; im.decoding = 'async'; im.loading = 'lazy'; im.src = x.foto; fotoRahmen(im, x.fotoVon || x.id, true); });
  }
  function symDia(x, still) {
    return dia('s' + x.id, function (d) { var g = x.sym ? ikSvg(x.sym) : null; if (g) { d.appendChild(g); d.wbG = g; if (still) { g.classList.add('go'); g.classList.add('fix'); } } });
  }
  function prodDia(x) { return dia('p' + x.prod, function (d) { var s = wbProdukt(x.prod, d); d.wbName = s ? s.wbName : ''; }); }
  function zeig(d, name, x) {
    if (jetzt === d) { return; }
    each(Object.keys(dias), function (k) { dias[k].classList.toggle('auf', dias[k] === d); });
    jetzt = d;
    if (o.cap) { o.cap.textContent = name || ''; }
    if (o.capFn) { o.capFn(x, d === dias['p' + x.prod] ? 'p' : ''); }
  }
  /* Runde 14 (Dimi 10.11.2026): Gruppenkarte (o.gruppe) zeigt im Ruhebild bis zu o.gruppe Modelle nebeneinander (z. B. TruTool F 140
     und F 300); die Beschriftung nennt dann die ganze Gruppe ohne Typ (capFn(null)) */
  function gruppenDia() {
    var mit = G.filter(function (x) { return !!x.foto; }).slice(0, o.gruppe);
    if (lt(mit.length, 2)) { return null; }
    /* Runde 18 (Dimi 11.11.2026, 22:43): mit Massen (DATA.mm) stehen die Werkzeuge massstaeblich nebeneinander, die Breite der Flaechen
       folgt ihrer Breite in mm; ohne Masse wie bisher (erstes Modell groesser, gross1) */
    var mitMm = true; each(mit, function (x) { if (!mmBreite(x.fotoVon || x.id)) { mitMm = false; } });
    return dia('r', function (d) {
      d.classList.add('wb-nb'); if (o.gross1 ? !mitMm : false) { d.classList.add('wb-nb1'); }
      each(mit, function (x) { var f = ht('span', 'wb-nbf', null, d), im = ht('img', null, null, f); if (mitMm) { f.style.flexGrow = String(Math.round(mmBreite(x.fotoVon || x.id))); } im.alt = ''; im.decoding = 'async'; im.src = x.foto; fotoRahmen(im, x.fotoVon || x.id, true); });
    });
  }
  /* Ruhebild: erste Maschine (Foto, sonst Symbol im Endzustand) */
  function ruheBild() {
    var x = G[0];
    if (o.gruppe) {
      var dg = gruppenDia();
      if (dg) { if (jetzt !== dg) { each(Object.keys(dias), function (k) { dias[k].classList.toggle('auf', dias[k] === dg); }); jetzt = dg; } if (o.capFn) { o.capFn(null, ''); } return; }
      if (x.foto) { zeig(fotoDia(x), x.name, x); if (o.capFn) { o.capFn(null, ''); } return; }
    }
    if (x.foto) { zeig(fotoDia(x), x.name, x); return; }
    var d = symDia(x, true); if (d.wbG) { d.wbG.classList.add('go'); d.wbG.classList.add('fix'); }
    zeig(d, x.name, x);
    if (o.gruppe) { if (o.capFn) { o.capFn(null, ''); } }
  }
  function halt() { if (tm) { window.clearTimeout(tm); tm = null; } }
  /* Folge beim Zeigen: je Maschine Endprodukt, Ablauf, Foto; das Ruhebild (Foto der ersten Maschine) steht schon */
  function folgeZeigen() {
    folge = [];
    each(G, function (x) { if (x.prod) { folge.push({ t: 'p', x: x }); } if (x.sym) { folge.push({ t: 's', x: x }); } if (x.foto) { folge.push({ t: 'f', x: x }); } });
    return folge;
  }
  function eins(e, fest) {
    var ms = WB_ZEIT;
    if (e.t === 'f') { zeig(fotoDia(e.x), e.x.name, e.x); ms = WB_FOTO; }
    else if (e.t === 'p') { var dp = prodDia(e.x); zeig(dp, dp.wbName || e.x.name, e.x); ms = WB_PROD; }
    else {
      var d = symDia(e.x, false); zeig(d, e.x.name, e.x);
      if (d.wbG) { d.wbG.classList.remove('fix'); ikNochmal(d.wbG); ms = fest ? fest : wbDauer(d.wbG) + WB_ABLAUF_PLUS; }
    }
    return ms;
  }
  function spiel(F, i, schleife) {
    halt();
    if (!F.length) { return; }
    if (!(lt(i, F.length))) { if (!schleife) { return; } i = 0; }
    schritt = i;
    var ms = eins(F[i]);
    /* letzte Folge ohne Schleife: Ablauf bleibt im Endbild stehen */
    if (!schleife) { if (i === F.length - 1) { return; } }
    tm = window.setTimeout(function () { tm = null; if (!el.isConnected) { stop(); return; } spiel(F, i + 1, schleife); }, ms);
  }
  function zeigen() {
    if (!BEWEGUNG) { return; }
    modus = 'zeigen'; halt();
    var F = folgeZeigen(), mitFoto = false;
    each(G, function (x) { if (x.foto) { mitFoto = true; } });
    if (!F.length) { return; }
    /* Folge beginnt mit dem, was nach dem Ruhebild kommt; mit Foto als Schleife */
    spiel(F, 0, mitFoto);
  }
  function ruhe() { modus = 'ruhe'; halt(); ruheBild(); }
  function stop() { halt(); modus = ''; }
  /* Gleichschritt von aussen (Anwendungen): 'p' Endprodukt der ersten Maschine, 's' ihr Ablauf, 'f' Ruhebild.
     Waehrend die Maus auf der Kachel ist, gilt das Zeigen. */
  function takt(art) {
    if (modus === 'zeigen') { return; }
    halt(); var x = G[0];
    /* ohne Endprodukt steht im ersten Takt der Ablauf im Endbild (Runde 12 der Szene) */
    if (art === 'p') { if (x.prod) { eins({ t: 'p', x: x }); } else if (x.sym) { var d0 = symDia(x, true); if (d0.wbG) { d0.wbG.classList.add('go'); d0.wbG.classList.add('fix'); } zeig(d0, x.name, x); } else { ruheBild(); } return; }
    if (art === 's') { if (x.sym) { eins({ t: 's', x: x }, WB_TAKT_ABLAUF); } return; }
    ruheBild();
  }
  el.addEventListener('mouseenter', zeigen);
  el.addEventListener('mouseleave', ruhe);
  el.addEventListener('focusin', zeigen);
  el.addEventListener('focusout', ruhe);
  ruheBild();
  return { zeigen: zeigen, ruhe: ruhe, takt: takt, glieder: G, test: function () { return { modus: modus, schritt: schritt, n: folge.length }; } };
}
/* Gleichschritt mehrerer Wechselbilder (Runde 12: alle Anwendungskacheln wechseln zugleich): Endprodukt, Ablauf, Maschine,
   ein Durchlauf, dann das Ruhebild. Laeuft einmal, wenn die Kacheln das erste Mal sichtbar werden. */
function wbTakt(liste, el) {
  var lauf = false, fertig = false;
  function los() {
    if (lauf) { return; } if (fertig) { return; } if (!BEWEGUNG) { return; }
    lauf = true;
    each(liste, function (w) { if (w) { w.takt('p'); } });
    window.setTimeout(function () {
      each(liste, function (w) { if (w) { w.takt('s'); } });
      window.setTimeout(function () { each(liste, function (w) { if (w) { w.takt('f'); } }); lauf = false; fertig = true; }, WB_TAKT_ABLAUF);
    }, WB_PROD);
  }
  if (window.IntersectionObserver) {
    var io = new IntersectionObserver(function (es) { each(es, function (e) { if (e.isIntersecting) { io.disconnect(); window.setTimeout(los, 500); } }); }, { threshold: 0.25 });
    io.observe(el);
  } else { window.setTimeout(los, 800); }
  return { los: los };
}
/* Stufenkachel (Runde 13 der Szene, Dimi 10.11.2026): Ruhebild (Foto der Maschine) und ein Ablauf aus Prozess-Symbolen, der einmal
   laeuft, wenn die Kachel zum ersten Mal sichtbar wird; danach steht dauerhaft das Ruhebild. key: je Bauteil, Rahmenverbindung und
   Stufe nur einmal je Seitenaufruf. Ohne Foto steht das letzte Symbol im Endbild. */
var WB_EINMAL = {};
/* Runde 14 der Szene (Dimi 10.11.2026): beim ersten Sehen einmal der Ablauf, dann das Ruhebild; zeigt man mit der Maus auf die Kachel
   (hover, z. B. der Knopf der Stufe), laeuft der Ablauf wieder, wiederholt, bis die Maus geht; dann sofort das Ruhebild. */
function wbEinmal(fl, foto, fid, folge, key, hover) {
  fl.classList.add('wb');
  var ruhe = ht('div', 'wb-d auf', null, fl);
  if (foto) { var im = ht('img', null, null, ruhe); im.alt = ''; im.decoding = 'async'; im.src = foto; if (fid) { fotoRahmen(im, fid, true); } }
  else if (folge.length) { var g0 = ikSvg(folge[folge.length - 1]); if (g0) { g0.classList.add('go'); g0.classList.add('fix'); ruhe.appendChild(g0); } }
  if (!folge.length) { return; } if (!BEWEGUNG) { return; }
  var dias = null, tm = null, tok = 0;
  function bauen() {
    if (dias) { return; }
    dias = folge.map(function (pid) { var d = ht('div', 'wb-d', null, fl), g = ikSvg(pid); if (g) { d.appendChild(g); d.wbG = g; } return d; });
  }
  function zeig(d) { each(fl.children, function (c) { c.classList.toggle('auf', c === d); }); }
  function halt() { tok++; if (tm) { window.clearTimeout(tm); tm = null; } }
  function lauf(i, schleife, t) {
    if (t !== tok) { return; }
    if (!fl.isConnected) { return; }
    if (i === dias.length) { if (!schleife) { zeig(ruhe); return; } i = 0; }
    var d = dias[i], ms = WB_ZEIT;
    zeig(d);
    if (d.wbG) { ikNochmal(d.wbG); ms = wbDauer(d.wbG) + 600; }
    tm = window.setTimeout(function () { tm = null; lauf(i + 1, schleife, t); }, ms);
  }
  function los() { if (WB_EINMAL[key]) { return; } WB_EINMAL[key] = 1; bauen(); halt(); var t = tok; tm = window.setTimeout(function () { lauf(0, false, t); }, 500); }
  if (hover) {
    hover.addEventListener('mouseenter', function () { bauen(); halt(); lauf(0, true, tok); });
    hover.addEventListener('mouseleave', function () { halt(); zeig(ruhe); });
  }
  if (WB_EINMAL[key]) { return; }
  if (window.IntersectionObserver) {
    var io = new IntersectionObserver(function (es) { each(es, function (e) { if (e.isIntersecting) { io.disconnect(); los(); } }); }, { threshold: 0.6 });
    io.observe(fl);
  } else { los(); }
}
/* Karte im Stil der Einzelheiten (Runde 12, Dimi 10.11.2026): Bild oben, blauer Querstreifen, darunter Bezeichnung, Typ und
   Hersteller. Ohne Maus nur das Maschinenbild, mit Maus Maschine und Ablauf im Wechsel (wechselBild).
   o.titel: feste Oberzeile (Kategorie, Gattung); bei mehreren Maschinen wechselt die Unterzeile mit dem Bild.
   o.link, o.merk (Kennung fuer das Plus der Merkliste), o.glieder (sonst aus ids), o.klasse */
function wkKarte(par, ids, o) {
  o = o || {};
  var G = o.glieder || wbGlieder(ids, { einzeln: true }), m0 = masch(ids[0]);
  var platz = m0 ? !!m0.platz : false;
  var c = ht('div', 'wmk-c wk' + (o.link ? ' lk' : '') + (platz ? ' platz' : '') + (o.klasse ? ' ' + o.klasse : ''), null, par);
  var a = ht(o.link ? 'a' : 'div', 'wmk-ca', null, c); if (o.link) { a.href = o.link; }
  /* Runde 13 (Dimi 10.11.2026): o.ot – Titelzeile immer, damit alle Karten einer Tabelle gleich hoch sind */
  if (o.titel || o.ot) { ht('span', 'wk-ot', o.titel || '', a); }
  var bi = ht('span', 'wmk-bi', null, a);
  var tx = ht('span', 'wmk-tx', null, a), mb = ht('span', 'wmk-mb', null, tx), ty = ht('span', 'wmk-ty', null, tx), br = ht('span', 'wmk-br', null, tx);
  /* Runde 14 (Dimi 10.11.2026): Karten fuer eine Gruppe (o.gruppe) nennen unter dem Bild alle Namen der Gruppe; der Typ wechselt mit
     dem gezeigten Modell, im Ruhebild steht kein Typ */
  var namen = [], marken = [];
  each(G, function (x) { var mx = masch(x.id); if (!mx) { return; } var n = (mx.mb || '').replace(/­|​/g, ''); if (namen.indexOf(n) === -1) { namen.push(n); } var br0 = mx.platz ? '' : (mx.b || ''); if (br0) { if (marken.indexOf(br0) === -1) { marken.push(br0); } } });
  var gruppe = o.gruppe ? gt(G.length, 1) : false;
  if (o.fest) { c.classList.add('grp'); }
  if (gruppe) { c.classList.add('grp'); }
  function text(x) {
    /* Runde 14: feste Beschriftung (Karte „Schneiden und CNC“: Faserlaser · Plasmaschneidanlagen · CAD/CAM, WAMMES), kein Modell */
    if (o.fest) { mb.textContent = o.fest.mb; mb.title = o.fest.mb; ty.textContent = ''; ty.className = 'wmk-ty leer'; br.textContent = o.fest.b || ''; return; }
    if (gruppe) {
      var mg = x ? masch(x.id) : null;
      mb.textContent = namen.join(' · '); mb.title = namen.join(' · ');
      var tg = mg ? tyZeigen(mg) : '';
      tySetzen(ty, tg || ''); ty.title = tg || '';
      ty.className = 'wmk-ty' + (mg ? '' : ' leer'); tyEinpassen(ty);
      br.textContent = mg ? (mg.b || '') : marken.join(' · ');
      return;
    }
    var m = x ? masch(x.id) : m0; if (!m) { return; }
    var mehr = x ? gt(x.ids.length, 1) : false, t = tyZeigen(m), oben = m.mb;
    /* Familie oder Gattung (z. B. Kanalanlagen): oben ihr Name, darunter die Typen der Mitglieder */
    if (mehr) { oben = x.name; t = x.ids.map(function (y) { var my = masch(y); return my ? tyEcht(my) : ''; }).filter(function (q) { return !!q; }).join(' · '); }
    mb.textContent = trennen(oben); mb.title = oben || ''; tySetzen(ty, t || ''); ty.title = t || '';
    ty.className = 'wmk-ty' + (platzhalter(t) ? ' wmk-ph' : ''); tyEinpassen(ty);
    br.textContent = m.platz ? (m.erkl || '') : (m.b || '');
  }
  text(G.length ? G[0] : null);
  var wb = G.length ? wechselBild(c, bi, G, { capFn: function (x) { text(x); }, gruppe: gruppe ? (o.nebeneinander || 2) : 0, gross1: !!o.gross1 }) : null;
  /* zu lange Titel (z. B. FALZPROFILIERANLAGEN) werden kleiner statt abgeschnitten */
  var ot = c.querySelector('.wk-ot'); if (ot) { if (o.titel) { titelEinpassen(ot); } }
  if (!wb) { bi.classList.add('leer'); }
  if (o.merk) { merkKnopf(c, o.merk); }
  /* Runde 13 (Dimi 10.11.2026): kein Hinweisfenster mehr auf Kacheln und Karten */
  c.wkWb = wb;
  return c;
}
/* Runde 18 (Dimi 11.11.2026, 20:13): Typ mit Komma (z. B. „3-Maschinen-System, Stufe 1“) darf nach dem Komma umbrechen, die Teile nicht */
function tySetzen(ty, t) {
  while (ty.firstChild) { ty.removeChild(ty.firstChild); }
  /* Runde 19 (Pruefliste 22.5 a): auch ein Typ ohne Komma steht in einem Teil ohne Umbruch (Kartei: „TruTool DD 1010“ bricht nie um) */
  if (!t) { return; }
  var T = t.split(', ');
  each(T, function (s, i) { if (i) { ty.appendChild(document.createTextNode(' ')); } ht('span', 'tyt', s + (i === T.length - 1 ? '' : ','), ty); });
}
/* Runde 19 (Dimi 12.11.2026, Pruefliste 22.5 a): alle Typen in der Groesse der Karte; kleiner nur, wenn der Name nicht passt.
   Gemessen wie bei titelEinpassen; jeder Teil (zwischen den Kommas) muss in die Breite passen, umgebrochen wird nur nach dem Komma */
function tyZuBreit(el) {
  var cs = window.getComputedStyle(el), innen = el.clientWidth - (parseFloat(cs.paddingLeft) || 0) - (parseFloat(cs.paddingRight) || 0);
  var T = el.querySelectorAll('.tyt'), i, r;
  if (!T.length) { r = document.createRange(); r.selectNodeContents(el); return gt(r.getBoundingClientRect().width, innen + 0.25); }
  for (i = 0; lt(i, T.length); i++) { if (gt(T[i].getBoundingClientRect().width, innen + 0.25)) { return true; } }
  return false;
}
function tyEinpassen(el) {
  function fit() {
    if (!el.isConnected) { return; } if (!el.clientWidth) { return; }
    el.style.fontSize = '';
    if (!tyZuBreit(el)) { return; }
    var f = parseFloat(window.getComputedStyle(el).fontSize) || 14;
    while (tyZuBreit(el)) { if (lt(f, 9.6)) { return; } f -= 0.5; el.style.fontSize = f + 'px'; }
  }
  el.style.fontSize = '';
  window.requestAnimationFrame(fit);
  if (!el.wkTyFit) { el.wkTyFit = 1; if (window.ResizeObserver) { new ResizeObserver(fit).observe(el); } }
}
/* Runde 18: ab der eigenen Schriftgroesse verkleinern; ein einzelnes Wort (z. B. ELEKTROWERKZEUGE) wird nur kleiner, nie zweizeilig;
   „zw“ wird bei jedem Einpassen neu bestimmt (vorher blieb es nach einem fruehen Messen bei schmaler Karte haengen) */
/* genaue Breite des Textes (scrollWidth rundet; 145 statt 144,6 liess die Auslassungspunkte stehen) */
function zuBreit(el) {
  var cs = window.getComputedStyle(el), innen = el.clientWidth - (parseFloat(cs.paddingLeft) || 0) - (parseFloat(cs.paddingRight) || 0);
  var r = document.createRange(); r.selectNodeContents(el);
  return gt(r.getBoundingClientRect().width, innen + 0.25);
}
function titelEinpassen(el) {
  function fit() {
    if (!el.isConnected) { return; } if (!el.clientWidth) { return; }
    el.classList.remove('zw'); el.style.fontSize = ''; el.style.letterSpacing = '';
    if (!zuBreit(el)) { return; }
    var f = parseFloat(window.getComputedStyle(el).fontSize) || 12, ein = (el.textContent || '').indexOf(' ') === -1;
    el.style.letterSpacing = '0';
    while (zuBreit(el)) {
      if (lt(f, ein ? 8.6 : 9.6)) { if (!ein) { el.classList.add('zw'); el.style.fontSize = ''; } return; }
      f -= 0.5; el.style.fontSize = f + 'px';
    }
  }
  window.requestAnimationFrame(fit);
  if (window.ResizeObserver) { new ResizeObserver(fit).observe(el); }
}
var CSSW = [
  '.wb{position:relative;overflow:hidden;background:#fff}',
  /* nacheinander statt ueberblendet, ruhiger (Runde 12): das alte Bild geht, dann kommt das neue */
  '.wb-d{position:absolute;left:0;top:0;right:0;bottom:0;opacity:0;transition:opacity .45s ease;display:flex;align-items:center;justify-content:center}',
  '.wb-d.auf{opacity:1;transition:opacity .6s ease .35s}',
  '.wb-d img{position:absolute;display:block}',
  '.wb-d img:not(.rh){left:0;top:0;width:100%;height:100%;object-fit:contain}',
  '.wb-d .wps{width:92%;height:92%}',
  '.wb-pr{display:flex;align-items:center;justify-content:center;width:100%;height:100%}',
  '.wb-pr img{position:static;display:block;max-width:94%;max-height:94%}',
  '.wb-pr .wpq,.wb-pr svg{width:86%;height:86%}',
  /* Karte im Stil der Einzelheiten */
  '.wmk-c.wk .wk-ot{display:block;padding:6px 8px 0 8px;font-size:12px;line-height:15px;font-weight:700;color:#41566F;text-transform:uppercase;letter-spacing:.03em;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}',
  '.wmk-c.wk .wmk-bi{height:118px;padding:0;margin:4px 6px}',
  '.wmk-c.wk .wmk-bi.leer{height:8px}',
  '.wmk-c.wk .wmk-tx{min-height:46px}',
  /* Platzhalter-Karte (Runde 13): erklaert, was noetig ist (z. B. Presse mit Matrize und Stempel), ohne Link und Merkliste */
  '.wmk-c.wk.platz{border-style:dashed;background:#FAFBFC}',
  '.wmk-c.wk.platz .wmk-tx{border-top-color:#9DB0C6}',
  '.wmk-c.wk.platz .wmk-br{color:#41566F;font-size:12px;line-height:15px}',
  /* Runde 14: Gruppenkarte, Ruhebild mit mehreren Modellen nebeneinander, alle Namen unter dem Bild */
  '.wb-d.wb-nb{display:flex;align-items:stretch;justify-content:center;gap:2px}',
  '.wb-nbf{position:relative;flex:1 1 0;min-width:0;height:100%}',
  /* Runde 18 (Dimi 11.11.2026, 20:13): zwei Modelle, das erste groesser (TruTool F 300 neben F 140) */
  '.wb-nb1 .wb-nbf:first-child{flex-grow:1.55}',
  '.wb-nb1 .wb-nbf+.wb-nbf{height:72%;align-self:center}',
  '.tyt{white-space:nowrap}',
  '.wmk-c.wk.grp .wmk-mb{font-size:11px;line-height:13px;-webkit-line-clamp:3;min-height:26px}',
  '.wmk-c.wk .wmk-ty.leer{display:none}',
  '.wmk-c.wk .wk-ot.zw{white-space:normal;font-size:10px;line-height:11px;letter-spacing:0;padding-top:0}',
  /* Handy-Runde (Dimi 12.11.2026, Prüfliste 25.6): am Handy nie zwei Bilder zugleich – erst aus, dann ein */
  '@media (pointer:coarse){.wb-d{transition:opacity .15s ease}.wb-d.auf{transition:opacity .15s ease .15s}}',
  '@media (prefers-reduced-motion:reduce){.wb-d,.wb-d.auf{transition:none}}'
].join('');

/* ---------- Teil d: Maschinen, Karten, Merkliste, Katalogdruck, Anfrage ---------- */
var VORSCHAU = false, BASIS = '';
var FIRMA = { n: 'Wammes Machinery LW GmbH', a: 'Industriepark 14 a · 56291 Wiebelsheim · Germany', t: '+49 (0) 6766 961-630', m: 'sales@wammesmachinery.com', w: 'wammesmachinery.com' };
function basisSetzen() {
  var h = String(location.hostname || '').toLowerCase();
  BASIS = h.indexOf('wammesmachinery.') !== -1 ? '' : 'https://www.wammesmachinery.com';
}
function seitenUrl(u) { return (BASIS || location.origin) + u; }
/* Hoehe des festen Seitenkopfs der Website (Kopf und klebende Bereichsleiste), damit Ziele nicht darunter verschwinden */
function kopfHoehe() {
  var h = 0, a = document.getElementById('wmlHdr'), n = document.querySelector('.wml[data-wml=nav]');
  /* Handy-Runde (Layout 1.37): am Handy faehrt der Kopf beim Scrollen weg – nur der sichtbare Teil zaehlt (am Rechner gleich) */
  if (a) { h += Math.max(0, a.getBoundingClientRect().bottom); }
  if (n) { if (getComputedStyle(n).position === 'sticky') { h += n.getBoundingClientRect().height; } }
  return h;
}
function hinScrollen(el) {
  var y = el.getBoundingClientRect().top + (window.pageYOffset || 0) - kopfHoehe() - 10;
  try { window.scrollTo({ top: Math.max(0, y), behavior: 'smooth' }); } catch (e) { window.scrollTo(0, Math.max(0, y)); }
}
var TRW = ['schalldämpfer', 'kulissen', 'kulisse', 'maschinen', 'maschine', 'rollformer', 'profilier', 'profilierer', 'anlagen', 'anlage', 'wickelfalz',
  'rohr', 'schweiß', 'punkt', 'zangen', 'zange', 'schwenk', 'biege', 'tafel', 'scheren', 'schere', 'segment', 'bogen', 'automaten', 'automat', 'abwickel',
  'haspeln', 'haspel', 'zuschnitt', 'kanal', 'falz', 'schließ', 'schließer', 'dichtungs', 'sicken', 'plasma', 'schneid', 'faser', 'laser', 'absaug',
  'filter', 'beschickungs', 'selektier', 'vorschub', 'einheiten', 'steckrahmen', 'rahmen', 'leitblech', 'versteifungs', 'ablängs', 'äge', 'sägen', 'rund',
  'flex', 'hüll', 'füge', 'pressen', 'bohr', 'schrauber', 'rollennaht', 'drahts', 'verbund', 'pittsburgh', 'schnapp', 'bördler', 'bördel', 'drossel', 'klappe'];
/* Trennt lange Woerter (ab 13 Zeichen) an bekannten Teilwoertern mit weichem Trennzeichen; unbekannte Reste bleiben ganz */
function trennen(t) {
  if (!t) { return t; }
  return String(t).replace(/[A-Za-zÄÖÜäöüß]{13,}/g, function (w) {
    var l = w.toLowerCase(), r = [], i = 0;
    while (lt(i, l.length)) {
      var best = 0;
      each(TRW, function (m) { if (gt(m.length, best)) { if (l.substr(i, m.length) === m) { best = m.length; } } });
      if (!best) { return w; }
      r.push(w.substr(i, best)); i += best;
    }
    return r.join('\u00ad');
  });
}
function grossAnfang(t) { return t ? t.charAt(0).toUpperCase() + t.substr(1) : ''; }
function platzhalter(t) { return t ? t.indexOf('[') !== -1 : false; }
/* Typ ohne Platzhalter in eckigen Klammern, z. B. PDF [Name folgt] wird PDF */
function tyRein(t) { return t ? t.replace(/\s*\[[^\]]*\]/g, '').trim() : ''; }
/* Maschine zu einer Kennung: Katalog, Zusatz, g: (gehoert zur Kette, nicht im Programm), z: (Handarbeit) */
function masch(id) {
  if (id.indexOf('z:') === 0) { return { z: 1, mb: id.substr(2), ty: '', b: '' }; }
  if (id.indexOf('k:') === 0) { var bk = BT[id.substr(2)]; return { z: 1, k: id.substr(2), mb: 'wie ' + (bk ? kurzName(bk) : id.substr(2)), ty: '', b: '' }; }
  if (id.indexOf('g:') === 0) { return { g: 1, mb: id.substr(2), ty: '', b: '' }; }
  return KAT[id] || DATA.zusatz[id] || null;
}
/* Typ fuer die Anzeige: Platzhalter in eckigen Klammern nur in der Vorschau */
function tyZeigen(m) { if (!m.ty) { return ''; } if (platzhalter(m.ty)) { return VORSCHAU ? m.ty : tyRein(m.ty); } return m.ty; }
function tyEcht(m) { return tyRein(m.ty); }
function kurz(m) { var t = tyEcht(m); if (!t) { return m.mb; } return / mm$/.test(t) ? m.mb + ' ' + t : t; }
function vollName(m) { var t = tyEcht(m); return t ? m.mb + ' ' + t : m.mb; }
function bildUrl(id, m) {
  var vb = window.wmsBilder;
  if (vb) { return vb[id] || ''; }
  return m.i ? BASIS + m.i + '?mw=300' : '';
}
var MV = null;
function verfahrenVon(id) {
  if (!MV) { MV = {}; each(DATA.verfahren || [], function (v) { each(v.m, function (x) { if (MV[x] === undefined) { MV[x] = v; } }); }); MV.pfs = MV.ds || null; }
  return MV[id] || null;
}
/* Symbol einer Maschine: eigenes Symbol aus DATA.msym, sonst das erste Symbol ihres ersten Verfahrens */
function maschSym(id) {
  var s = (DATA.msym || {})[id]; if (s) { return s; }
  var v = verfahrenVon(id); return v ? v.sym[0] : null;
}
/* Ersatz fuer ein fehlendes Foto: Symbol der Maschine im Endzustand.
   Dimi 09.11.2026: Die Bewegung laeuft, solange die Maus auf der Karte ist, und hoert beim Verlassen sofort auf. */
function platzIcon(par, id) {
  var sy = maschSym(id), g = sy ? ikSvg(sy) : null;
  par.classList.add('ic');
  if (!g) { return; }
  g.classList.add('go'); g.classList.add('fix'); par.appendChild(g);
  var ziel = par.parentNode || par;
  if (ziel.getAttribute('data-ikh')) { return; }
  ziel.setAttribute('data-ikh', '1');
  ziel.addEventListener('mouseenter', function () { if (!BEWEGUNG) { return; } each(ziel.querySelectorAll('.wps.fix'), function (x) { x.classList.remove('fix'); ikNochmal(x); x.setAttribute('data-ikl', '1'); }); });
  ziel.addEventListener('mouseleave', function () { each(ziel.querySelectorAll('.wps[data-ikl]'), function (x) { x.removeAttribute('data-ikl'); x.classList.add('fix'); }); });
}
function karte(id, par) {
  var m = masch(id); if (!m) { return null; }
  if (m.z) { return null; }
  var link = m.u ? seitenUrl(m.u) : '';
  var c = ht('div', 'wmk-c' + (m.g ? ' g' : '') + (link ? ' lk' : ''), null, par), ca = ht(link ? 'a' : 'div', 'wmk-ca', null, c);
  if (link) { ca.href = link; }
  var bi = ht('span', 'wmk-bi', null, ca);
  if (!m.g) {
    var src = bildUrl(id, m);
    if (src) {
      var im = ht('img', null, null, bi); im.alt = ''; im.loading = 'lazy'; im.decoding = 'async';
      im.addEventListener('error', function () { if (im.parentNode) { bi.removeChild(im); } platzIcon(bi, id); });
      im.src = src; fotoRahmen(im, id, true);
    } else { platzIcon(bi, id); }
  }
  var tx = ht('span', 'wmk-tx', null, ca), ty = tyZeigen(m);
  ht('span', 'wmk-mb', trennen(m.mb), tx);
  if (m.g) { ht('span', 'wmk-ty wmk-ng', 'nicht im Programm', tx); }
  else if (ty) { var t = ht('span', 'wmk-ty' + (platzhalter(ty) ? ' wmk-ph' : ''), null, tx); tySetzen(t, ty); t.title = ty; tyEinpassen(t); }
  else if (m.zk) { ht('span', 'wmk-ty wmk-ng', 'auf Anfrage', tx); }
  if (m.b) { ht('span', 'wmk-br', m.b, tx); }
  if (!m.g) { merkKnopf(c, id); }
  return c;
}
/* Maschine in einem Fertigungsschritt: Maschinenbezeichnung oben, Typ darunter */
function chip(id, par) {
  var m = masch(id); if (!m) { return null; }
  if (m.z) { return ht('span', 'wsz-m z', m.mb, par); }
  var link = m.u ? seitenUrl(m.u) : '';
  var c = ht(link ? 'a' : 'span', 'wsz-m' + (m.g ? ' g' : ''), null, par);
  if (link) { c.href = link; }
  ht('span', 'wsz-mb', m.mb, c);
  var ty = m.g ? 'nicht im Programm' : (tyZeigen(m) || (m.zk ? 'auf Anfrage' : ''));
  if (ty) { ht('span', 'wsz-ty' + (platzhalter(ty) ? ' ph' : ''), ty, c); }
  return c;
}
/* Maschinen eines Bauteils nach Ausbaustufe, Reihenfolge wie in den Schritten */
function stufenListe(b) {
  var st = { M: [], T: [], V: [] };
  each(b.schritte, function (s) {
    each(['M', 'T', 'V'], function (k) {
      each(s[k], function (id) {
        if (id.indexOf('z:') === 0) { return; }
        if (!masch(id)) { return; }
        if (st[k].indexOf(id) === -1) { st[k].push(id); }
      });
    });
  });
  return st;
}
/* ---------- Merkliste (bleibt im Browser des Besuchers) ---------- */
var MKS = 'wmMerk', MKMEM = null, MKB = null, MKP = null;
function mkLesen() {
  try {
    var r = window.localStorage.getItem(MKS), a = r ? JSON.parse(r) : [];
    if (Array.isArray(a)) { return a.filter(function (x) { return typeof x === 'string' ? !!masch(x) : false; }); }
  } catch (e) { }
  return MKMEM ? MKMEM.slice() : [];
}
function mkSchreiben(a) {
  MKMEM = a.slice();
  try { window.localStorage.setItem(MKS, JSON.stringify(a)); } catch (e) { }
  mkSync();
}
function mkHat(id) { return mkLesen().indexOf(id) !== -1; }
function mkUmschalten(id) { var a = mkLesen(), i = a.indexOf(id); if (i === -1) { a.push(id); } else { a.splice(i, 1); } mkSchreiben(a); }
function mkKnopfSetzen(k, on) {
  while (k.firstChild) { k.removeChild(k.firstChild); }
  var s = sv('svg', { viewBox: '0 0 20 20', 'aria-hidden': 'true', focusable: 'false' }, k);
  if (on) { sv('path', { d: 'M4.5 10.5 L8.5 14.5 L15.5 6', fill: 'none', stroke: 'currentColor', 'stroke-width': 2.6, 'stroke-linecap': 'round', 'stroke-linejoin': 'round' }, s); }
  else { sv('path', { d: 'M10 4 V16 M4 10 H16', fill: 'none', stroke: 'currentColor', 'stroke-width': 2.4, 'stroke-linecap': 'round' }, s); }
  k.classList.toggle('on', on);
  k.setAttribute('aria-pressed', on ? 'true' : 'false');
  k.title = on ? 'Von der Merkliste nehmen' : 'Auf die Merkliste';
  k.setAttribute('aria-label', k.title);
}
function merkKnopf(par, id) {
  var k = ht('span', 'wmk-pl', null, par);
  k.setAttribute('role', 'button'); k.setAttribute('tabindex', '0'); k.setAttribute('data-merk', id);
  mkKnopfSetzen(k, mkHat(id));
  function tun(ev) { ev.preventDefault(); ev.stopPropagation(); if (ev.stopImmediatePropagation) { ev.stopImmediatePropagation(); } mkUmschalten(id); }
  k.addEventListener('click', tun);
  /* auch Druck und Loslassen nicht an einen Link darunter weitergeben */
  each(['pointerdown', 'mousedown', 'pointerup', 'mouseup'], function (t) { k.addEventListener(t, function (ev) { ev.stopPropagation(); }); });
  k.addEventListener('keydown', function (ev) { if (ev.key === 'Enter' || ev.key === ' ') { tun(ev); } });
  return k;
}
function mkSync() {
  var a = mkLesen();
  each(document.querySelectorAll('[data-merk]'), function (k) { mkKnopfSetzen(k, a.indexOf(k.getAttribute('data-merk')) !== -1); });
  mkKnopf();
  if (MKP) { mkPanel(); }
}
function mkKnopf() {
  var n = mkLesen().length;
  if (!MKB) {
    MKB = ht('button', 'wmk-fb', null, document.body); MKB.type = 'button';
    ht('span', null, 'Merkliste', MKB); ht('b', null, '0', MKB);
    MKB.addEventListener('click', function () { if (MKP) { mkZu(); } else { mkPanel(); } });
  }
  MKB.lastChild.textContent = String(n);
  MKB.setAttribute('aria-label', 'Merkliste, ' + n + (n === 1 ? ' Produkt' : ' Produkte'));
  MKB.style.display = n ? '' : 'none';
  if (!n) { mkZu(); }
}
function mkZu() { if (MKP) { if (MKP.parentNode) { MKP.parentNode.removeChild(MKP); } MKP = null; } }
function anfrageUrl(a) {
  var t = [];
  each(a, function (id) { var m = masch(id); if (m) { t.push(vollName(m)); } });
  return BASIS + '/kontakt/online-anfrage?m=' + encodeURIComponent(t.join('; '));
}
function mkPanel() {
  var a = mkLesen();
  if (!a.length) { mkZu(); return; }
  if (!MKP) { MKP = ht('div', 'wmk-pn', null, document.body); MKP.setAttribute('role', 'dialog'); MKP.setAttribute('aria-label', 'Merkliste'); }
  while (MKP.firstChild) { MKP.removeChild(MKP.firstChild); }
  var kopf = ht('div', 'wmk-pk', null, MKP);
  ht('b', null, 'Ihre Merkliste (' + a.length + ')', kopf);
  var zu = ht('button', 'wmk-x', '×', kopf); zu.type = 'button'; zu.setAttribute('aria-label', 'Schließen'); zu.addEventListener('click', mkZu);
  var li = ht('div', null, null, MKP);
  each(a, function (id) {
    var m = masch(id); if (!m) { return; }
    var z = ht('div', 'wmk-pz', null, li), bi = ht('span', 'wmk-pb', null, z), src = bildUrl(id, m);
    if (src) { var im = ht('img', null, null, bi); im.alt = ''; im.src = src; } else { platzIcon(bi, id); }
    var tx = ht(m.u ? 'a' : 'span', 'wmk-pt', null, z); if (m.u) { tx.href = seitenUrl(m.u); }
    ht('span', 'wmk-mb', m.mb, tx); var ty = tyZeigen(m); if (ty) { ht('span', 'wmk-ty', ty, tx); }
    var w = ht('button', 'wmk-weg', '×', z); w.type = 'button'; w.title = 'Entfernen'; w.setAttribute('aria-label', 'Entfernen: ' + vollName(m));
    w.addEventListener('click', function () { var b = mkLesen(), i = b.indexOf(id); if (i !== -1) { b.splice(i, 1); } mkSchreiben(b); });
  });
  var ak = ht('div', 'wmk-ak', null, MKP);
  var dr = ht('button', 'wmk-dr1', 'Als Katalog drucken', ak); dr.type = 'button'; dr.addEventListener('click', mkDruck);
  var an = ht('a', 'wmk-an', 'Anfrage senden', ak); an.href = anfrageUrl(a);
  ht('p', 'wmk-hw', 'Die Liste bleibt in diesem Browser gespeichert. „Anfrage senden“ übernimmt die Maschinen in die Online-Anfrage. Der Katalog lässt sich auch als PDF speichern.', MKP);
  if (VORSCHAU) { ht('p', 'wmk-hw', 'Vorschau: Drucken ist in der Vorschau gesperrt und funktioniert erst auf der Website.', MKP); }
}
/* Katalog drucken: eigene Druckansicht im Dokument, der Rest der Seite wird beim Drucken ausgeblendet */
function mkDruck() {
  var a = mkLesen(); if (!a.length) { return; }
  var alt = document.getElementById('wmk-druck'); if (alt) { alt.parentNode.removeChild(alt); }
  var d = ht('div', null, null, document.body); d.id = 'wmk-druck';
  ht('div', 'wdk-f', FIRMA.n, d);
  ht('h1', null, 'Ihre Maschinenauswahl', d);
  ht('p', 'wdk-a', FIRMA.a + ' · ' + FIRMA.t + ' · ' + FIRMA.m + ' · ' + FIRMA.w, d);
  ht('p', 'wdk-a', 'Stand ' + new Date().toLocaleDateString('de-DE'), d);
  each(a, function (id) {
    var m = masch(id); if (!m) { return; }
    var z = ht('div', 'wdk-z', null, d), bi = ht('div', 'wdk-b', null, z);
    var src = window.wmsBilder ? (window.wmsBilder[id] || '') : (m.i ? BASIS + m.i + '?mw=400' : '');
    if (src) { var im = ht('img', null, null, bi); im.alt = ''; im.src = src; }
    var tx = ht('div', 'wdk-t', null, z), ty = tyEcht(m);
    ht('div', 'wdk-mb', m.mb, tx); if (ty) { ht('div', 'wdk-ty', ty, tx); }
    if (m.b) { ht('div', 'wdk-br', m.b, tx); }
    ht('div', 'wdk-u', m.u ? 'https://www.wammesmachinery.com' + m.u : 'Seite folgt', tx);
  });
  ht('p', 'wdk-n', 'Unverbindliche Zusammenstellung. Technische Daten und Preise auf Anfrage.', d);
  var h = document.documentElement;
  h.classList.add('wmk-druckt');
  function fertig() { h.classList.remove('wmk-druckt'); window.removeEventListener('afterprint', fertig); }
  window.addEventListener('afterprint', fertig);
  try { window.print(); } catch (e) { fertig(); }
}
var MKOK = false;
function merklisteStart() {
  if (MKOK) { return; }
  MKOK = true;
  window.addEventListener('storage', function (ev) { if (ev.key === MKS) { mkSync(); } });
  document.addEventListener('keydown', function (ev) { if (ev.key === 'Escape') { mkZu(); } });
  mkKnopf();
}
var CSSD = [
  '.wsz [hidden]{display:none!important}',
  '.wps.fix *{animation-delay:-60s!important;animation-play-state:paused!important}',
  /* Suche */
  /* Suche (Runde 12 der Szene, Dimi 10.11.2026): dezent rechts neben den Reitern, die Liste klappt unter dem Feld auf */
  /* Runde 13 der Szene (Dimi 10.11.2026): Suche und „Ideen und Verbesserungen“ stehen wie die Reiter auf der blauen Linie */
  '.wsd-rf{display:flex;align-items:flex-end;gap:2px;margin:0 0 0 auto;min-width:0}',
  '.wsd-s{position:relative;flex:0 1 300px;min-width:190px;margin:0;align-self:flex-end}',
  '.wsd-sl{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}',
  '.wsd-sz{display:flex;align-items:center;gap:6px;height:39px;padding:0 10px;background:#f3f5f8;color:#41566F;box-sizing:border-box;transition:background .15s,box-shadow .15s}',
  '.wsd-sz:hover{background:#E8EDF3}',
  '.wsd-s.auf .wsd-sz,.wsd-sz:focus-within{background:#fff;box-shadow:inset 0 0 0 1px #1F3855,inset 0 3px 0 #F7BC0C}',
  '.wsd-slu{flex:0 0 auto;display:block;width:17px;height:17px}',
  '.wsd-q{flex:1 1 auto;min-width:0;height:34px;border:0;padding:0;font:14px Arial,Helvetica,sans-serif;color:#1A1D21;outline:none;background:transparent;-webkit-appearance:none;border-radius:0}',
  '.wsd-q::placeholder{color:#7B8796}',
  '.wsd-erg{position:absolute;right:0;top:calc(100% + 2px);z-index:60;width:640px;max-width:calc(100vw - 24px);max-height:70vh;overflow:auto;box-sizing:border-box;border:1px solid #1F3855;border-top:3px solid #1F3855;background:#fff;padding:12px 16px 14px;box-shadow:0 10px 30px rgba(0,0,0,.18)}',
  '.wsd-ea{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:4px 18px}',
  '.wsd-eac{min-width:0}',
  '.wsd-ek{margin:8px 0 3px 0;font-size:12px;line-height:15px;color:#6E737A}',
  '.wsd-el{flex-direction:column;align-items:stretch;gap:2px}',
  '.wsd-el.e1{margin-top:8px}',
  '.wsd-eb button.kl{padding:3px 8px;border:0;border-left:3px solid transparent;font-size:14px;line-height:19px;background:none}',
  '.wsd-eb button.kl:hover,.wsd-eb button.kl:focus-visible{background:#FFF5D1;border-left-color:#F7BC0C}',
  '.wsd-eb button.kl b{font-weight:400}',
  '.wsd-ems{flex-direction:column;align-items:stretch;gap:2px}',
  '.wsd-em{display:flex;align-items:center;gap:10px;padding:4px 6px;color:#1A1D21;text-decoration:none;border-left:3px solid transparent}',
  '.wsd-em:hover{background:#FFF5D1;border-left-color:#F7BC0C}',
  '.wsd-emb{flex:0 0 52px;height:38px;display:flex;align-items:center;justify-content:center;background:#fff}',
  '.wsd-emb img{display:block;max-width:100%;max-height:100%;object-fit:contain}',
  '.wsd-emb .wps{width:52px;height:38px}',
  '.wsd-emt{display:flex;flex-direction:column;min-width:0;font-size:13px;line-height:16px}',
  '.wsd-emt small{color:#6E737A;font-size:12px}',
  '.wsd-emt b{color:#1F3855}',
  '.wsd-emt i{font-style:normal;font-size:11px;color:#8A9099}',
  /* Ideen und Verbesserungen: Feld wie die Suche, Eingabe klappt unter der Linie auf */
  '.wsd-fb{position:relative;flex:0 0 auto;align-self:flex-end}',
  '.wsd-fbk{display:flex;align-items:center;gap:6px;height:39px;padding:0 12px;border:0;background:#f3f5f8;color:#41566F;font:13px Arial,Helvetica,sans-serif;cursor:pointer;white-space:nowrap;transition:background .15s}',
  '.wsd-fbk:hover,.wsd-fb.auf .wsd-fbk{background:#E8EDF3;color:#1F3855}',
  '.wsd-fbk:focus-visible{outline:2px solid #F7BC0C;outline-offset:-2px}',
  '.wsd-fbi{display:block;width:18px;height:18px;flex:0 0 auto}',
  '.wsd-fbp{position:absolute;right:0;top:calc(100% + 2px);z-index:61;width:380px;max-width:calc(100vw - 24px);box-sizing:border-box;border:1px solid #1F3855;border-top:3px solid #1F3855;background:#fff;padding:12px 14px 14px;box-shadow:0 10px 30px rgba(0,0,0,.18);font-size:13px;line-height:18px;color:#1A1D21}',
  '.wsd-fbh{display:block;margin:0 0 4px 0;font-size:14px;color:#1F3855}',
  '.wsd-fbp p{margin:0 0 8px 0}',
  '.wsd-fbx{display:block;width:100%;box-sizing:border-box;min-height:84px;padding:6px 8px;border:1px solid #C3CCD6;font:13px/18px Arial,Helvetica,sans-serif;color:#1A1D21;resize:vertical}',
  '.wsd-fbx:focus{outline:none;border-color:#1F3855;box-shadow:0 0 0 2px rgba(247,188,12,.55)}',
  '.wsd-fbz{display:flex;align-items:center;gap:10px;margin:8px 0 0 0}',
  '.wsd-fbz small{font-size:11px;color:#6E737A}',
  '.wsd-fbs{font:700 13px Arial,Helvetica,sans-serif;padding:7px 14px;border:0;background:#1F3855;color:#fff;cursor:pointer}',
  '.wsd-fbs:hover{background:#2C4C70}',
  '@media (max-width:700px){.wsd-rf{flex:1 1 100%;margin:6px 0 0 0}.wsd-s{flex:1 1 auto;min-width:0}.wsd-erg{width:auto;left:0;right:auto;max-width:calc(100vw - 24px)}.wsd-fbt{display:none}.wsd-fbk{padding:0 11px}.wsd-ea{grid-template-columns:minmax(0,1fr)}}',
  '.wsd-eh{font-size:12px;font-weight:700;text-transform:uppercase;letter-spacing:.04em;color:#1F3855;margin:8px 0 6px 0}',
  '.wsd-eh:first-child{margin-top:0}',
  '.wsd-eb{display:flex;flex-wrap:wrap;gap:6px}',
  '.wsd-eb button{display:inline-flex;align-items:center;gap:8px;font:inherit;font-size:14px;padding:5px 10px;background:#fff;border:1px solid #d5dde6;color:#1A1D21;cursor:pointer;text-align:left}',
  '.wsd-eb button:hover{border-color:#1F3855}',
  '.wsd-eb button b{color:#1F3855}',
  '.wsd-eb button small{color:#6E737A;font-size:12px}',
  '.wsd-eb .wsd-ei{display:block;width:44px;height:33px;flex:0 0 auto}',
  '.wsd-e0{margin:0;font-size:14px;color:#4B5563}',
  /* Reiter */
  '.wsd-r{display:flex;flex-wrap:wrap;align-items:flex-end;gap:0 12px;margin:14px 0 14px 0;border-bottom:2px solid #1F3855}',
  '.wsd-rk{display:flex}',
  '.wsd-rk button{font:600 16px Arial,Helvetica,sans-serif;padding:10px 20px;background:#f3f5f8;color:#1F3855;border:0;cursor:pointer;margin:0 2px 0 0}',
  '.wsd-rk button.on{background:#1F3855;color:#fff}',
  /* Kopfzeilen der Abschnitte */
  '.wsd-h{margin:22px 0 4px 0;font-size:20px;line-height:26px;color:#1F3855}',
  '.wsd-e{margin:0 0 12px 0;font-size:14px;line-height:20px;color:#4B5563}',
  '.wsd-gh{margin:16px 0 8px 0;font-size:12px;text-transform:uppercase;letter-spacing:.04em;color:#1F3855}',
  /* Produkt-Kacheln (Runde 9 der Szene, Dimi 09.11.2026): Name oben, darunter zweigeteilt Bauteil und Maschinenbild, Maschinenname
     unter dem Bild. Kacheln senkrecht in drei Spalten; jede Spalte als Gruppe mit Kopf und hinterlegter Flaeche */
  '.wsd-pg{display:grid;grid-template-columns:repeat(auto-fill,minmax(300px,1fr));gap:10px}',
  '.wsd-sh{display:none}',
  '.wsd-sk{grid-column:1/-1;margin:8px 0 0 0;padding:0 0 4px 0;font-size:12px;line-height:16px;font-weight:700;text-transform:uppercase;letter-spacing:.05em;color:#1F3855;border-bottom:2px solid #1F3855}',
  '.wsd-pg.wsd-spx{grid-template-columns:repeat(2,minmax(0,1fr))}',
  '@media (min-width:640px){.wsd-pg.wsd-spx{grid-template-columns:repeat(3,minmax(0,1fr));column-gap:14px;row-gap:0}.wsd-pg.wsd-spx .wsd-sh{display:block;grid-column:var(--sp);grid-row:1 / var(--ze);background:#EEF2F6;border-top:3px solid #1F3855}.wsd-pg.wsd-spx .wsd-sk{grid-column:var(--sp);grid-row:1;position:relative;z-index:1;margin:0;padding:9px 12px 8px 12px;border:0}.wsd-pg.wsd-spx .wsd-p{grid-column:var(--sp);grid-row:var(--zr);position:relative;z-index:1;margin:0 10px 10px 10px}.wsd-pg.wsd-spx .wsd-p.gross .wsd-pbi{flex:1 1 0;min-height:0;grid-template-rows:minmax(70px,2fr) minmax(90px,3fr)}.wsd-pg.wsd-spx .wsd-p.gross .wsd-pb{height:auto;min-height:0;aspect-ratio:auto}.wsd-pg.wsd-spx .wsd-p.gross .wsd-pm{display:flex;flex-direction:column;min-height:0}.wsd-pg.wsd-spx .wsd-p.gross .wsd-pmi{flex:1 1 0;height:auto;min-height:0;aspect-ratio:auto}}',
  '@media (max-width:639px){.wsd-pg.wsd-spx{grid-template-columns:minmax(0,1fr)}}',
  '.wsd-pg.wsd-kauf .wsd-sh,.wsd-pg.wsd-kauf .wsd-sk{display:none}',
  '.wsd-p{display:flex;flex-direction:column;gap:6px;min-width:0;border:1px solid #d5dde6;border-top:3px solid #1F3855;background:#fff;padding:8px 10px 6px 10px;cursor:pointer;outline:none;transition:border-color .15s,box-shadow .15s}',
  '.wsd-p:hover,.wsd-p:focus-visible{border-color:#1F3855;box-shadow:0 2px 10px rgba(31,56,85,.12)}',
  '.wsd-p.on{border-color:#E0A800;border-top-color:#F7BC0C;background:#FFFBEB}',
  '.wsd-pn{font-size:15px;line-height:19px;font-weight:700;color:#1F3855;-webkit-hyphens:auto;hyphens:auto;overflow-wrap:break-word}',
  /* Runde 10 der Szene (Dimi, Punkt 7): das Bauteil nutzt die ganze Hoehe neben Maschinenbild und Maschinenname */
  '.wsd-pbi{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:8px;align-items:stretch}',
  '.wsd-p.ohne-m .wsd-pbi{grid-template-columns:minmax(0,1fr)}',
  '.wsd-pb{position:relative;min-width:0;min-height:0}',
  '.wsd-p.ohne-m .wsd-pb{aspect-ratio:2/1}',
  /* Runde 13 der Szene (Dimi 10.11.2026): inaktive Kategorie (Zubehoer und Einbauteile: In Arbeit), nicht anwaehlbar */
  '.wsd-p.inaktiv{cursor:default;border-top-color:#9AA6B2;background:#FAFBFC}',
  '.wsd-p.inaktiv:hover{box-shadow:none;border-color:#d5dde6;border-top-color:#9AA6B2}',
  '.wsd-p.inaktiv .wsd-pn{color:#6E737A}',
  '.wsd-p.inaktiv .wsd-pb{opacity:.55}',
  '.wsd-p.inaktiv .wsd-pbi{position:relative}',
  '.wsd-bald{position:absolute;right:0;bottom:0;z-index:2;font-size:12px;line-height:16px;font-weight:700;color:#41566F;background:#fff;border:1px solid #9AA6B2;padding:2px 8px}',
  '.wsd-pb img{position:absolute;left:0;top:0;display:block;width:100%;height:100%;object-fit:contain}',
  /* Runde 18: Produkt wechselt mit der Maschine (kachelProdukt) */
  '.wsd-pbv{position:absolute;left:0;top:0;right:0;bottom:0;opacity:0;transition:opacity .45s ease}',
  '.wsd-pbv.auf{opacity:1}',
  /* grosse Kachel: Bauteil oben, Maschine darunter, beide ueber die ganze Breite; Foto ganz zeigen */
  '.wsd-p.gross .wsd-pbi{grid-template-columns:minmax(0,1fr);align-items:stretch}',
  '.wsd-p.gross .wsd-pb{height:120px}',
  '.wsd-p.gross .wsd-pmi{height:180px}',
  '.wsd-pc{display:flex;flex-wrap:wrap;gap:3px 4px}',
  '.wsd-c{font-size:12px;line-height:16px;padding:0 5px;border:1px solid #d5dde6;background:#fff;white-space:nowrap;color:#1A1D21}',
  '.wsd-c.g{border-style:dashed;color:#8A9099}',
  '.wsd-c.lg{white-space:normal}',
  '.wsd-kx{display:flex;flex-wrap:wrap;gap:6px}',
  '.wsd-kx span,.wsd-kx button{font:inherit;font-size:13px;padding:3px 9px;border:1px dashed #c3ccd6;color:#6E737A;background:#fff}',
  '.wsd-kx button{cursor:pointer}.wsd-kx button:hover{border-color:#1F3855;color:#1F3855}.wsd-kx button:disabled{cursor:default;opacity:.7}',
  /* Maschinenkarten */
  '.wmk-e{margin:0 0 10px 0;font-size:13px;color:#5C6670}',
  '.wmk-g{display:grid;grid-template-columns:repeat(auto-fill,minmax(150px,1fr));gap:10px}',
  '.wmk-c{position:relative;display:flex;flex-direction:column;min-width:0;border:1px solid #d5dde6;background:#fff;color:#1A1D21;transition:border-color .15s,box-shadow .15s}',
  '.wmk-ca{display:flex;flex-direction:column;flex:1 1 auto;min-width:0;color:inherit;text-decoration:none}',
  '.wmk-c.lk:hover{border-color:#1F3855;box-shadow:0 2px 10px rgba(31,56,85,.14)}',
  '.wmk-bi{position:relative;overflow:hidden;height:96px;display:flex;align-items:center;justify-content:center;padding:6px;background:#fff;box-sizing:border-box}',
  '.wmk-bi img.rh{position:absolute;max-width:none;max-height:none}',
  '.wmk-bi img{display:block;max-width:100%;max-height:84px;object-fit:contain}',
  '.wmk-bi.ic{background:#F5F7FA}',
  '.wmk-bi .wps{width:92px;height:70px}',
  '.wmk-tx{display:flex;flex-direction:column;gap:1px;border-top:3px solid #1F3855;padding:6px 8px 8px 8px}',
  '.wmk-mb{font-size:12px;line-height:15px;color:#6E737A;-webkit-hyphens:manual;hyphens:manual;overflow-wrap:anywhere}',
  '.wmk-ty{font-size:14px;line-height:18px;font-weight:700;color:#1F3855;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}',
  '.wmk-ty.wmk-ph{color:#9AA3AD;font-weight:400;font-style:italic;font-size:12px}',
  '.wmk-ty.wmk-ng{color:#8A9099;font-weight:400;font-size:12px}',
  '.wmk-br{font-size:11px;line-height:14px;color:#8A9099;margin-top:2px}',
  '.wmk-pl{position:absolute;top:6px;right:6px;z-index:2;display:flex;align-items:center;justify-content:center;box-sizing:border-box;width:22px;height:22px;padding:0;border-radius:50%;background:#fff;border:1px solid #1F3855;color:#1F3855;cursor:pointer;box-shadow:0 1px 2px rgba(0,0,0,.12);user-select:none}',
  '.wmk-pl svg{display:block;width:64%;height:64%;pointer-events:none}',
  '.wmk-pl:hover{background:#FFF5D1}',
  '.wmk-pl.on{background:#F7BC0C;border-color:#C99400;color:#1A1D21}',
  '.wmk-c.g{border-style:dashed;background:#FAFBFC}',
  '.wmk-c.g .wmk-bi{height:20px;background:transparent}',
  '.wmk-c.g .wmk-tx{border-top-color:#C3CCD6}',
  /* Anwendungs-Kacheln (Runde 9): Gruppen als Spalten mit hinterlegter Flaeche, Name oben (Zahl der Maschinen rechts, wenn sie
     in die Zeile passt), darunter Ablauf und Maschinenbild, Maschinenname unter dem Bild */
  '.wsd-ag{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:14px;align-items:start}',
  '.wsd-ag[hidden],.wsd-kd[hidden]{display:none}',
  '@media (max-width:1079px){.wsd-ag{grid-template-columns:repeat(2,minmax(0,1fr))}}',
  '@media (max-width:639px){.wsd-ag{grid-template-columns:minmax(0,1fr)}}',
  '.wsd-as{display:flex;flex-direction:column;gap:14px;min-width:0;background:#EEF2F6;border-top:3px solid #1F3855;padding:0 10px 10px 10px}',
  '.wsd-agr{display:flex;flex-direction:column;gap:10px;min-width:0}',
  '.wsd-agh{margin:0;padding:9px 2px 0 2px;font-size:12px;line-height:16px;font-weight:700;text-transform:uppercase;letter-spacing:.05em;color:#1F3855}',
  '.wsd-k{display:flex;flex-direction:column;gap:6px;text-align:left;font:inherit;color:inherit;border:1px solid #d5dde6;border-top:3px solid #1F3855;background:#fff;padding:8px 10px 6px 10px;cursor:pointer;outline:none;transition:border-color .15s,box-shadow .15s}',
  '.wsd-k:hover,.wsd-k:focus-visible{border-color:#1F3855;box-shadow:0 3px 12px rgba(31,56,85,.14)}',
  '.wsd-k.on{border-color:#1F3855;border-top-color:#F7BC0C;background:#F3F5F8}',
  '.wsd-kk{display:flex;align-items:baseline;justify-content:space-between;gap:4px 10px;flex-wrap:wrap}',
  '.wsd-kt{min-width:0;font-size:15px;line-height:19px;font-weight:700;color:#1F3855;-webkit-hyphens:auto;hyphens:auto;overflow-wrap:break-word}',
  '.wsd-kn{flex:0 0 auto;margin-left:auto;font-size:12px;line-height:19px;color:#6E737A;white-space:nowrap}',
  '.wsd-kk.zwei .wsd-kn{display:none}',
  '.wsd-kbi{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:8px;align-items:start}',
  '.wsd-kl{display:flex;flex-direction:column;justify-content:center;gap:3px;min-width:0;align-self:stretch;font-size:12px;line-height:15px;color:#5C6670}',
  '.wsd-ki{display:block;aspect-ratio:16/9;min-width:0}',
  '.wsd-ki .wps{width:100%;height:100%}',
  '.wsd-kbi .wsd-pmi{aspect-ratio:16/9}',
  '.wsd-kd{margin:0 0 4px 0}',
  '.wsd-kb{position:relative;border:1px solid #c3ccd6;border-top:0;background:#f7f8fa;padding:12px 18px 18px;animation:wszAuf .32s ease-out}',
  '.wsd-zur{font:700 12px/16px Arial,Helvetica,sans-serif;padding:3px 8px;margin:0 0 10px 0;border:1px solid #c3ccd6;background:#fff;color:#1F3855;cursor:pointer}',
  '.wsd-zur:hover{border-color:#1F3855}',
  '.wsd-kh{display:flex;gap:16px;align-items:center;margin:0 0 12px 0}',
  /* Runde 11 der Szene (Dimi 10.11.2026, Antworten Runde 12): Rueckweg links ueber die ganze Hoehe, Kachel ganzflaechig mit Wechselbild */
  '.wsd-kr{display:flex;gap:14px;align-items:stretch}',
  '.wsd-kre{flex:1 1 auto;min-width:0}',
  '.wsd-kf{position:relative;display:block;aspect-ratio:16/9;min-width:0}',
  '.wsd-kc{min-height:15px;font-size:12px;line-height:15px;color:#5C6670;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}',
  '.wsd-khi{position:relative;display:block}',
  '.wsd-form{display:flex;flex-wrap:wrap;align-items:center;gap:6px;margin:0 0 10px 0;padding:6px 8px;background:#FFF5D1;border:1px dashed #E0A800;font-size:12px;color:#4B5563}',
  '.wsd-form button{font:700 12px/16px Arial,Helvetica,sans-serif;padding:4px 10px;border:1px solid #1F3855;background:#fff;color:#1F3855;cursor:pointer}',
  '.wsd-form button.on{background:#1F3855;color:#fff}',
  /* hoch (Runde 12 der Szene, Dimi 10.11.2026): Gruppen als Zeilen, feste Spalten (--n: groesste Gruppe); kein Umbruch, die Kacheln werden kleiner */
  '.wsd-ag.hoch{display:flex;flex-direction:column;align-items:stretch;gap:12px}',
  '.wsd-ag.hoch .wsd-agr{display:grid;grid-template-columns:140px repeat(var(--n,5),minmax(0,1fr));gap:10px;align-items:stretch;background:#EEF2F6;border-top:3px solid #1F3855;padding:8px 10px 10px 10px}',
  '.wsd-ag.hoch .wsd-agh{padding:4px 0 0 0;align-self:start}',
  '@media (max-width:900px){.wsd-ag.hoch .wsd-agr{grid-template-columns:repeat(var(--n,5),minmax(0,1fr))}.wsd-ag.hoch .wsd-agh{grid-column:1/-1}}',
  '@media (max-width:639px){.wsd-ag.hoch .wsd-agr{grid-template-columns:repeat(var(--n,5),minmax(136px,1fr));overflow-x:auto;-webkit-overflow-scrolling:touch}.wsd-ag.hoch .wsd-agh{position:sticky;left:0}}',
  /* Kachel der Anwendung wie eine Karte der Einzelheiten: oben Anwendung und Zahl, Bild, blaue Querlinie, Maschine */
  '.wsd-k3{cursor:pointer;outline:none}',
  '.wsd-k3:hover,.wsd-k3:focus-visible{border-color:#1F3855;box-shadow:0 3px 12px rgba(31,56,85,.16)}',
  '.wsd-k3.on{border-color:#E0A800;box-shadow:inset 0 0 0 1px #F7BC0C}',
  '.wmk-c.wk.wsd-k3 .wk-ot{display:flex;padding:7px 8px 0 8px;text-transform:none;letter-spacing:0;white-space:normal;overflow:visible}',
  '.wsd-k3 .wsd-kt{font-size:14px;line-height:18px}',
  '.wmk-c.wk.wsd-k3 .wk-ot{min-height:36px;align-items:flex-start}',
  '.wsd-k3 .wsd-kn{font-size:11px;line-height:18px;font-weight:400}',
  '.wmk-c.wk.wsd-k3 .wmk-bi{height:auto;aspect-ratio:4/3;margin:6px}',
  '.wsd-kg{grid-template-columns:repeat(auto-fill,minmax(170px,1fr))}',
  '.wsd-khi{flex:0 0 150px;height:112px}',
  '.wsd-khi .wps{width:100%;height:100%}',
  '.wsd-kb h3{margin:0 0 4px 0;font-size:20px;line-height:25px;color:#1F3855}',
  '.wsd-kv{margin:16px 0 8px 0;font-size:13px;text-transform:uppercase;letter-spacing:.04em;color:#1F3855}',
  '.wsd-ke{font-size:13px;line-height:21px;color:#4B5563}',
  '.wsd-lk{font:inherit;font-size:13px;background:none;border:0;border-bottom:1px solid #E0A800;color:#1F3855;padding:0;margin:0 9px 2px 0;cursor:pointer}',
  '.wsd-lk:hover{color:#000;border-bottom-color:#1F3855}',
  /* Reiter-Hinweis (Runde 9): beide Reiter leuchten kurz abwechselnd auf (Keyframes wrgBl in 41_kompakt.js) */
  '.wsd-rk.wsd-blink button{animation:wrgBl .9s ease-in-out 0s 3}',
  '.wsd-rk.wsd-blink button + button{animation-delay:.45s}',
  /* Merkliste */
  '.wmk-fb{position:fixed;right:18px;bottom:20px;z-index:99990;display:flex;align-items:center;gap:8px;background:#1F3855;color:#fff;border:0;font:700 15px Arial,Helvetica,sans-serif;padding:12px 16px;cursor:pointer;box-shadow:0 4px 14px rgba(0,0,0,.28)}',
  '.wmk-fb b{display:inline-block;min-width:22px;padding:0 6px;border-radius:11px;background:#F7BC0C;color:#1A1D21;text-align:center;line-height:22px}',
  '.wmk-pn{position:fixed;right:18px;bottom:76px;z-index:99991;width:420px;max-width:calc(100vw - 24px);max-height:70vh;overflow:auto;background:#fff;border:2px solid #1F3855;box-shadow:0 8px 30px rgba(0,0,0,.25);padding:12px 16px 14px;font-family:Arial,Helvetica,sans-serif;color:#1A1D21;box-sizing:border-box}',
  '.wmk-pk{display:flex;align-items:center;justify-content:space-between;margin:0 0 4px 0}',
  '.wmk-pk b{font-size:17px;color:#1F3855}',
  '.wmk-x{border:0;background:none;font-size:26px;line-height:26px;color:#1F3855;cursor:pointer;padding:0 4px}',
  '.wmk-pz{display:flex;gap:10px;align-items:center;border-bottom:1px solid #e3e6ea;padding:6px 0}',
  '.wmk-pb{flex:0 0 60px;height:44px;display:flex;align-items:center;justify-content:center}',
  '.wmk-pb img{max-width:60px;max-height:44px}',
  '.wmk-pb .wps{width:56px;height:42px}',
  '.wmk-pt{flex:1 1 auto;display:flex;flex-direction:column;min-width:0;text-decoration:none;color:inherit}',
  '.wmk-pt .wmk-ty{font-size:14px}',
  '.wmk-weg{flex:0 0 auto;border:0;background:none;font-size:22px;line-height:22px;color:#6E737A;cursor:pointer;padding:0 6px}',
  '.wmk-ak{display:flex;gap:10px;margin:14px 0 0 0;flex-wrap:wrap}',
  '.wmk-dr1{flex:1 1 150px;font:700 14px Arial,Helvetica,sans-serif;border:2px solid #1F3855;color:#1F3855;background:#fff;padding:10px;cursor:pointer}',
  '.wmk-an{flex:1 1 150px;display:block;text-align:center;font:700 14px Arial,Helvetica,sans-serif;background:#F7BC0C;border:2px solid #F7BC0C;color:#1A1D21;padding:10px;text-decoration:none}',
  '.wmk-hw{font-size:12px;line-height:16px;color:#6E737A;margin:10px 0 0 0}',
  /* Druckansicht */
  '#wmk-druck{display:none}',
  '@media print{html.wmk-druckt body *{display:none!important}html.wmk-druckt #wmk-druck,html.wmk-druckt #wmk-druck div,html.wmk-druckt #wmk-druck h1,html.wmk-druckt #wmk-druck p,html.wmk-druckt #wmk-druck img{display:block!important}html.wmk-druckt #wmk-druck .wdk-z{display:flex!important}html.wmk-druckt #wmk-druck svg,html.wmk-druckt #wmk-druck svg *{display:inline!important}html.wmk-druckt #wmk-druck svg{display:block!important}@page{margin:14mm}}',
  '#wmk-druck .wdk-bild{margin:12px 0 8px 0;border:1px solid #d5dde6;text-align:center}',
  '#wmk-druck .wdk-bild img,#wmk-druck .wdk-bild svg{display:block;max-width:100%;height:auto;margin:0 auto}',
  '#wmk-druck .wdk-t2{font-size:13px;line-height:19px;color:#1A1D21;margin:6px 0}',
  '#wmk-druck .wdk-z2{font-size:12px;line-height:17px;color:#4B5563;margin:3px 0}',
  /* Vorschau: Druckansicht im Fenster */
  '#wmk-druck.wdk-vs{display:block;position:fixed;left:24px;right:24px;top:24px;bottom:24px;z-index:2147483600;overflow:auto;background:#fff;padding:18px 24px;border:2px solid #1F3855;box-shadow:0 12px 40px rgba(0,0,0,.3)}',
  '#wmk-druck .wdk-vk{display:flex;gap:12px;align-items:center;justify-content:space-between;background:#FFF5D1;border:1px solid #E0A800;padding:8px 10px;margin:0 0 12px 0;font-size:13px;color:#1A1D21}',
  '#wmk-druck .wdk-vk button{font:700 13px Arial,Helvetica,sans-serif;padding:6px 12px;border:1px solid #1F3855;background:#fff;color:#1F3855;cursor:pointer}',
  '#wmk-druck{font-family:Arial,Helvetica,sans-serif;color:#1A1D21}',
  '#wmk-druck .wdk-f{font-size:13px;font-weight:700;color:#1F3855;letter-spacing:.04em;text-transform:uppercase}',
  '#wmk-druck h1{font-size:24px;color:#1F3855;margin:4px 0 6px 0;border:0;padding:0;background:none}',
  '#wmk-druck .wdk-a{font-size:12px;color:#4B5563;margin:2px 0}',
  '#wmk-druck .wdk-z{gap:18px;border-top:3px solid #1F3855;padding:12px 0;margin:10px 0 0 0;page-break-inside:avoid;break-inside:avoid}',
  '#wmk-druck .wdk-b{flex:0 0 180px;height:110px}',
  '#wmk-druck .wdk-b img{max-width:180px;max-height:110px;object-fit:contain}',
  '#wmk-druck .wdk-mb{font-size:13px;color:#4B5563}',
  '#wmk-druck .wdk-ty{font-size:18px;font-weight:700;color:#1F3855}',
  '#wmk-druck .wdk-br{font-size:12px;color:#6E737A}',
  '#wmk-druck .wdk-u{font-size:11px;color:#6E737A;margin-top:6px;word-break:break-all}',
  '#wmk-druck .wdk-n{font-size:12px;color:#6E737A;margin-top:18px}',
  /* Maschinenfeld der Kacheln (43_maschinenbild.js): Leitbild, beim Zeigen weich wechselnd; Name unter dem Bild (Runde 9) */
  '.wsd-pm{min-width:0}',
  '.wsd-pmi{position:relative;aspect-ratio:2/1;overflow:hidden;background:#fff}',
  '.wsd-pmd{position:absolute;left:0;top:0;width:100%;height:100%;opacity:0;transition:opacity .8s ease}',
  '.wsd-pmd.auf{opacity:1}',
  '.wsd-pm.sofort .wsd-pmd{transition:opacity .15s ease}',
  /* Fotos ganz zeigen (Runde 9 der Szene: hohe Maschinen wurden beschnitten); Produktfotos meist auf Weiss */
  '.wsd-pmd img{display:block;width:100%;height:100%;object-fit:contain;object-position:100% 50%;padding:2px;box-sizing:border-box}',
  /* Foto mit bekanntem Motivrahmen (verfahren_v1.json maschinenBildRahmen): das Motiv fuellt die Flaeche, rechtsbuendig */
  '.wsd-pmd img.rh{position:absolute;max-width:none;max-height:none;width:auto;height:auto;padding:0;object-fit:fill}',
  '.wsd-pms{display:flex;align-items:center;justify-content:center;width:100%;height:100%;padding:4px;box-sizing:border-box;background:#fff}',
  '.wsd-pms svg{display:block;width:100%;height:100%}',
  '.wsd-pmc{margin:3px 0 0 0;min-height:30px;font-size:12px;line-height:15px;color:#5C6670;text-align:right;-webkit-hyphens:manual;hyphens:manual;overflow:hidden;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical}',
  /* Handy-Runde (Prüfliste 25.6): am Handy erst aus, dann ein */
  '@media (pointer:coarse){.wsd-pmd{transition:opacity .15s ease}.wsd-pmd.auf{transition:opacity .15s ease .15s}}',
  /* Prüfliste 25.5: grosse Kachel ohne Raster (unter 640 px) – Bildflaeche so breit wie die Kachel, nicht aus Hoehe mal Seitenverhaeltnis */
  '@media (max-width:639px){.wsd-p.gross .wsd-pmi{aspect-ratio:auto}}',
  '@media (prefers-reduced-motion:reduce){.wsd-pmd{transition:none}}',
  /* Handy */
  '@media (max-width:560px){.wsd-kt{font-size:14px;line-height:18px}.wsd-s{padding:14px 14px 12px}.wsd-sl{font-size:17px;line-height:22px}.wsd-r button{flex:1 1 50%;padding:10px 8px;font-size:15px}.wsd-kt{font-size:14px;line-height:18px}.wsd-khi{flex-basis:84px;height:64px}.wsd-kb{padding:12px}.wmk-g{grid-template-columns:1fr 1fr;gap:8px}.wmk-bi{height:84px}.wmk-fb{right:12px;bottom:14px}.wmk-pn{left:8px;right:8px;width:auto;max-width:none;bottom:68px}}',
  '@media (prefers-reduced-motion:reduce){.wsd-p,.wsd-k,.wmk-c{transition:none}}'
].join('');

/* ---------- Teil d: Anwendungs-Kacheln mit bewegten Prozess-Symbolen ----------
   Runde 9 (Dimi 09.11.2026): Kacheln in 4 Gruppen, die Gruppen stehen als Spalten (verfahren_v1.json anwGruppen, sp).
   Eine Kachel fasst ein oder mehrere Verfahren zusammen (anwendungen, v): sie spielt deren Symbole nacheinander und zeigt
   deren Maschinen; daneben das Maschinenfeld (43_maschinenbild.js). Runde 10 der Antworten: Name oben, rechts daneben die
   Zahl der Maschinen, wenn sie in die Zeile passt; zu jedem Symbol die Maschine, die das macht (anwendungen[].paar).
   Antippen oeffnet an Stelle der Kacheln die Einzelheiten; „‹ Alle Anwendungen“ oder × fuehrt zurueck. */
var VID = {};
each(DATA.verfahren || [], function (v) { VID[v.id] = v; });
/* Kacheln aus den Verfahren zusammensetzen: Symbole, Maschinen und Endbild (erstes Verfahren mit Endbild) */
var AID = {}, ANWL = [];
(function () {
  var liste = (DATA.anw ? DATA.anw.length : 0) ? DATA.anw : (DATA.verfahren || []).map(function (v) { return { id: v.id, t: v.t, te: v.te, v: [v.id] }; });
  each(liste, function (a) {
    /* Zahl als „Produkte“ (Dimi 09.11.2026, Runde 11 Punkt 1: auch Software und Werkzeuge); ruhe: Symbol in Ruhe (Punkt 44) */
    var x = { id: a.id, t: a.t, te: a.te || '', leit: a.leit || null, ruhe: a.ruhe || null, v: [], sym: [], m: [], erg: null, paar: a.paar || {}, paarIds: [], wort: ['Produkt', 'Produkte'], prod: a.prod || null, teile: a.teile || null };
    each(a.v, function (vid) {
      var v = VID[vid]; if (!v) { return; }
      x.v.push(v);
      each(v.sym, function (p) { if (x.sym.indexOf(p) === -1) { x.sym.push(p); } });
      each(v.m, function (id) { if (x.m.indexOf(id) === -1) { x.m.push(id); } });
      if (!x.erg) { if (v.erg) { x.erg = v.erg; } }
    });
    each(x.sym, function (p) { var id = x.paar[p]; if (id) { if (x.paarIds.indexOf(id) === -1) { x.paarIds.push(id); } } });
    if (x.v.length) { AID[x.id] = x; ANWL.push(x); }
  });
})();
/* Kachel zu einer Kachel- oder Verfahrenskennung */
function anwVon(id) {
  if (AID[id]) { return AID[id]; }
  var r = null; each(ANWL, function (a) { if (r) { return; } each(a.v, function (v) { if (v.id === id) { r = a; } }); });
  return r;
}
function anwMaschinen(a) { return a.m; }
var BEWEGUNG = true;
function bewegungPruefen() {
  try { BEWEGUNG = !(window.matchMedia ? window.matchMedia('(prefers-reduced-motion: reduce)').matches : false); } catch (e) { BEWEGUNG = true; }
}
function zahlMaschinen(v) { var n = 0; each(v.m, function (id) { var m = masch(id); if (m) { if (!m.g) { n++; } } }); return n; }
/* Symbole einer Kachel nacheinander abspielen; Dauer aus den laufenden Animationen.
   Ruhe (Dimi 09.11.2026): Die Folge laeuft einmal, danach steht das erste Symbol (Leitsymbol) still im Endbild.
   Erneut nur beim Zeigen mit der Maus. cb(pid): Symbol pid wird gezeigt, cb(null): Endbild oder Ruhe (Maschinenfeld). */
function symZyklus(box, syms, erg, cb, ruhePid) {
  var svgs = [], ids = [], i = 0, tm = null, an = false;
  each(syms, function (pid) { var g = ikSvg(pid); if (g) { g.style.display = 'none'; box.appendChild(g); svgs.push(g); ids.push(pid); } });
  if (!svgs.length) { return null; }
  /* Ruhebild (Runde 11, Punkt 44): ein bestimmtes Symbol der Folge, sonst das erste */
  var r0 = ruhePid ? Math.max(0, ids.indexOf(ruhePid)) : 0;
  /* Ergebnisbild (Dimi 09.11.2026): nach der Folge Zoom auf das Endergebnis; es bleibt stehen, bis die Folge neu startet */
  var gE = erg ? ikSvg(erg) : null;
  if (gE) { gE.style.display = 'none'; box.appendChild(gE); }
  (gE || svgs[r0]).style.display = '';
  function dauer(g) {
    var ms = 3200;
    try {
      if (g.getAnimations) {
        var e = 0;
        each(g.getAnimations({ subtree: true }), function (a) { var t = a.effect ? a.effect.getComputedTiming().endTime : 0; if (isFinite(t)) { e = Math.max(e, t); } });
        if (e) { ms = Math.min(e, 12000); }
      }
    } catch (x) { }
    return ms;
  }
  function ruhe() {
    an = false; i = 0; if (cb) { cb(null); }
    if (tm) { window.clearTimeout(tm); tm = null; }
    each(svgs, function (g, j) { g.style.display = (j === r0 ? !gE : false) ? '' : 'none'; g.classList.remove('go'); });
    if (gE) { gE.style.display = ''; gE.classList.remove('go'); }
  }
  function ergebnis() {
    an = false; i = 0; if (cb) { cb(null); }
    each(svgs, function (g) { g.style.display = 'none'; g.classList.remove('go'); });
    gE.style.display = ''; if (BEWEGUNG) { ikNochmal(gE); }
  }
  function zeig(k) {
    i = k;
    each(svgs, function (g, j) { g.style.display = j === k ? '' : 'none'; });
    if (gE) { gE.style.display = 'none'; }
    var g = svgs[k]; ikNochmal(g); if (cb) { cb(ids[k]); }
    if (tm) { window.clearTimeout(tm); }
    tm = window.setTimeout(function () { tm = null; if (!an) { return; } if (k + 1 === svgs.length) { if (gE) { ergebnis(); } else { ruhe(); } return; } zeig(k + 1); }, dauer(g) + 900);
  }
  return {
    start: function () { if (!BEWEGUNG) { ruhe(); return; } if (an) { return; } an = true; zeig(0); },
    stop: ruhe,
    erstes: function () { return svgs[r0]; }
  };
}
/* Glieder einer Anwendungskachel (Runde 11 der Szene, Antwort Punkt 23): Leitmaschine zuerst, dann die Maschinen der Symbole und der Verfahren;
   je Maschine ihr Endprodukt (a.prod), z. B. Kanalanlage und Rechteckkanal, Wickelfalzrohrmaschine und Wickelfalzrohr */
function anwGlieder(a) {
  var ids = [];
  function auf(id) { if (ids.indexOf(id) === -1) { ids.push(id); } }
  if (a.leit) { auf(a.leit); }
  each(a.paarIds || [], auf); each(anwMaschinen(a), auf);
  return wbGlieder(ids, { prod: a.prod || null, max: 6 });
}
/* Gruppen als Zeilen (Runde 12 der Szene, Dimi 10.11.2026): links der Name der Gruppe, rechts ihre Kacheln in festen Spalten; die Spalten
   brechen nicht um, die Kacheln werden kleiner. Kachel wie die Karten der Einzelheiten: oben Anwendung und Zahl (fest), Bild, blaue
   Querlinie, darunter die Maschine zum Bild (wechselt). Alle Kacheln wechseln einmal im Gleichschritt (Endprodukt, Ablauf, Maschine),
   dann steht das Ruhebild; mit der Maus laeuft die Kachel weiter, Maus weg: sofort das Ruhebild (44_wechsel.js). Antippen oeffnet an
   Stelle der Kacheln die Einzelheiten; der Streifen oben fuehrt zurueck. */
function anwendungen(par, zuBauteil) {
  bewegungPruefen();
  var kopf = ht('div', null, null, par);
  var hk = ht('h3', 'wsd-h', 'Maschinen nach Anwendung', kopf);
  infoKnopf(hk, 'Anwendung antippen: Sie sehen die Maschinen dafür. Maus auf eine Kachel: Endprodukt, Ablauf und Maschine im Wechsel.', { label: 'Bedienung' });
  var det = ht('div', 'wsd-kd', null, par); det.hidden = true;
  var grid = ht('div', 'wsd-ag hoch', null, par), Z = [], offen = null, zuletzt = null, KK = [];
  var G = (DATA.anwg ? DATA.anwg.length : 0) ? DATA.anwg : [{ id: 'alle', t: '', sp: 1, k: ANWL.map(function (a) { return a.id; }) }];
  var nMax = 1; each(G, function (g) { var nn = g.k.filter(function (id) { return !!AID[id]; }).length; if (gt(nn, nMax)) { nMax = nn; } });
  grid.style.setProperty('--n', String(nMax));
  function kachel(a, gb, g) {
    var n = zahlMaschinen(a), nw = n + ' ' + a.wort[n === 1 ? 0 : 1], GL = anwGlieder(a);
    var ids = GL.length ? GL.map(function (x) { return x.id; }) : a.m.slice(0, 1);
    var k = wkKarte(gb, ids, { glieder: GL, titel: a.t, klasse: 'wsd-k3' });
    k.setAttribute('role', 'button'); k.setAttribute('tabindex', '0'); k.setAttribute('data-v', a.id); k.setAttribute('aria-expanded', 'false');
    var ot = k.querySelector('.wk-ot'); if (ot) { ot.textContent = ''; ot.classList.add('wsd-kk'); ht('span', 'wsd-kt', a.t, ot); ht('span', 'wsd-kn', nw, ot); KK.push(ot); }
    /* Runde 13 der Szene (Dimi 10.11.2026): kein blaues Hinweisfenster auf den Kacheln; der Text steht fuer Vorleseprogramme im aria-label */
    k.setAttribute('aria-label', a.t + ', ' + nw + (gt(a.v.length, 1) ? ' (' + a.v.map(function (v) { return v.t; }).join(', ') + ')' : ''));
    var z = { k: k, wb: k.wkWb || null, a: a, g: g };
    Z.push(z);
    function los() { tippWeg(); zeige(offen === a.id ? null : a.id, true); }
    k.addEventListener('click', los);
    k.addEventListener('keydown', function (ev) { if (ev.key === 'Enter' || ev.key === ' ') { ev.preventDefault(); los(); } });
  }
  each(G, function (g) {
    var gb = ht('div', 'wsd-agr', null, grid); gb.setAttribute('data-g', g.id);
    ht('h4', 'wsd-agh', g.t || '', gb);
    each(g.k, function (id) { var a = AID[id]; if (a) { kachel(a, gb, g); } });
  });
  /* einmal im Gleichschritt, wenn die Kacheln das erste Mal sichtbar werden */
  wbTakt(Z.map(function (z) { return z.wb; }), grid);
  /* Zahl der Maschinen nur, wenn sie rechts neben dem Namen in eine Zeile passt (Dimi 09.11.2026, Runde 10 der Antworten) */
  function zeilenPruefen() {
    each(KK, function (kk) {
      kk.classList.remove('zwei');
      var t = kk.firstChild, z = kk.lastChild; if (!t || !z) { return; }
      var rt = t.getBoundingClientRect(), rz = z.getBoundingClientRect(); if (!rt.height) { return; }
      if (gt(rt.height, 26) || gt(Math.abs(rz.top - rt.top), 4)) { kk.classList.add('zwei'); }
    });
  }
  zeilenPruefen();
  var zpT = 0;
  window.addEventListener('resize', function () { if (zpT) { return; } zpT = window.requestAnimationFrame(function () { zpT = 0; if (!grid.hidden) { if (grid.offsetParent !== null) { zeilenPruefen(); } } }); });
  function sichtbarOben(el) { var r = el.getBoundingClientRect(); return gt(r.top, kopfHoehe() - 1) ? lt(r.top, window.innerHeight - 120) : false; }
  /* Einzelheiten: oben der Rueckweg (Streifen), Bild der Anwendung (Ruhebild; mit der Maus Maschinen und Ablaeufe im Wechsel), Gruppe
     und Name; je Verfahren (oder Abschnitt a.teile) die Maschinen als Karten mit Foto, mit der Maus ihr Ablauf; jede Maschine einmal,
     ohne „nicht im Programm“ */
  function zeige(id, scroll) {
    var a = id ? anwVon(id) : null;
    offen = a ? a.id : null;
    each(Z, function (z) { var on = z.a.id === offen; z.k.classList.toggle('on', on); z.k.setAttribute('aria-expanded', on ? 'true' : 'false'); });
    while (det.firstChild) { det.removeChild(det.firstChild); }
    if (!a) {
      det.hidden = true; grid.hidden = false; zeilenPruefen();
      if (zuletzt) { var zk = null; each(Z, function (z) { if (z.a.id === zuletzt) { zk = z.k; } }); if (zk) { if (scroll) { if (!sichtbarOben(zk)) { hinScrollen(zk); } } window.setTimeout(function () { zk.focus(); }, 60); } }
      return;
    }
    zuletzt = a.id;
    det.hidden = false; grid.hidden = true;
    var b = ht('div', 'wsd-kb', null, det);
    zurueckStreifen(b, 'Zurück zu allen Anwendungen', function () { zeige(null, true); }, 'kb');
    var rechts = ht('div', 'wsd-kre', null, b);
    var h = ht('div', 'wsd-kh', null, rechts);
    var ic = ht('span', 'wsd-khi', null, h), cap = null;
    var t = ht('div', null, null, h);
    var gr = null; each(Z, function (z) { if (z.a === a) { gr = z.g; } });
    if (gr) { if (gr.t) { ht('div', 'wsy-kk', gr.t, t); } }
    ht('h3', null, a.t, t);
    cap = ht('div', 'wsd-kc', null, t);
    /* Runde 14: Karte Rohr-Rechner bei „Rohre wickeln“ */
    if (a.id === 'wickeln') { rechnerKarte(t); }
    var wb = wechselBild(ic, ic, anwGlieder(a), { cap: cap });
    if (wb) { window.setTimeout(function () { wb.ruhe(); }, 60); }
    var schon = {};
    var teile = a.teile ? a.teile : a.v.map(function (v) { return { t: gt(a.v.length, 1) ? v.t : '', m: v.m }; });
    each(teile, function (v) {
      var ids = v.m.filter(function (mid) { if (schon[mid]) { return false; } var m = masch(mid); if (!m) { return false; } return m.g ? false : !m.z; });
      if (!ids.length) { return; }
      if (v.t) { ht('h4', 'wsd-kv', v.t, rechts); }
      var mg = ht('div', 'wmk-g wsd-kg', null, rechts);
      each(ids, function (mid) { schon[mid] = 1; var m = masch(mid); wkKarte(mg, [mid], { link: m.u ? seitenUrl(m.u) : '', merk: mid }); });
    });
    if (scroll) { window.requestAnimationFrame(function () { if (!sichtbarOben(det)) { hinScrollen(det); } }); }
  }
  return { zeige: zeige, kacheln: Z };
}

/* ---------- Teil d: Suche nach Bauteil, Verfahren und Maschine ---------- */
function norm(t) {
  return String(t || '').toLowerCase().replace(/ä/g, 'a').replace(/ö/g, 'o').replace(/ü/g, 'u').replace(/ß/g, 'ss').replace(/[^a-z0-9]+/g, ' ').trim();
}
/* Suchwoerter je Bauteil: nur sichere Fachbegriffe, keine Marken von Mitbewerbern */
var SYN = {
  rk: 'kanal luftkanal gerader kanal rechteckkanal rechteckig eckig steckrahmen pdf flansch',
  rbogen: 'bogen eckig kanalbogen leitblech etage etagenstuck radius radien s form versatz',
  rwinkel: 'winkel eckig t stuck t stueck tstueck abzweig eckig',
  ruebergang: 'ubergang eckig rund square to round',
  retage: 'etage etagenstuck versatz versatzstuck sprung eckig gekantet ubergang reduzierung reduzierstuck rechteckig querschnitt einseitig symmetrisch zentrisch',
  hose: 'hosenstuck eckig',
  rboden: 'boden endkappe eckig',
  rstutzen: 'stutzen kragen abzweig',
  kd: 'drosselklappe klappe',
  anschlusskasten: 'plenum anschlusskasten',
  revision: 'revision reinigungsoffnung reinigung',
  dachhaube: 'dachhaube dach',
  wfr: 'spiralrohr wickelfalz rohr rundrohr',
  lnr: 'langsnaht rundrohr rohr geschweisst',
  segbogen: 'bogen segment segmentbogen rundbogen 90 grad 45 grad etagenbogen etage versatz s bogen',
  pbogen: 'bogen gepresst gepresster pressbogen rundbogen halbschale presse 90 grad 45 grad',
  tstueck: 'sattel sattelstutzen abzweig aufsatz 90 grad 45 grad',
  tstueck90: 't stuck t stueck tstueck abzweig 90 grad 45 grad kreuzstuck kreuz kreuzung reduziert reduzierter abgang',
  reduz: 'reduzierung reduzierstuck rund zentrisch konzentrisch exzentrisch',
  enddeckel: 'deckel enddeckel rund',
  nippel: 'nippel muffe verbinder',
  lippe: 'lippendichtung dichtung dichtring steckverbindung',
  flex: 'flexrohr flexibel',
  kulisse: 'schalldampfer kulisse kulissenschalldampfer'
};
var IDX = null;
function sucheIndex() {
  if (IDX) { return IDX; }
  IDX = [];
  var o = 0;
  each(DATA.bauteile, function (b) {
    if (b.klick !== 'ja') { return; }
    var w = [b.te, SYN[b.id] || '', b.bereiche.join(' ')];
    each(b.schritte, function (s) { w.push(s.t); each(s.p, function (p) { w.push(PNAME[p] || ''); }); });
    IDX.push({ k: 'b', id: b.id, o: o++, tn: ' ' + norm(b.t), an: ' ' + norm(w.join(' ')) });
  });
  /* Anwendungen: die Kacheln (Runde 9: zusammengefasste Verfahren), gefunden auch ueber die Namen der Verfahren */
  each(ANWL, function (a) {
    var w = [a.te];
    each(a.v, function (v) { w.push(v.t); w.push(v.te); });
    each(a.sym, function (p) { w.push(PNAME[p] || ''); });
    IDX.push({ k: 'v', id: a.id, o: o++, tn: ' ' + norm(a.t), an: ' ' + norm(w.join(' ')) });
  });
  for (var id in KAT) {
    var m = KAT[id], v = verfahrenVon(id);
    IDX.push({ k: 'm', id: id, o: o++, tn: ' ' + norm(m.mb + ' ' + tyEcht(m)), an: ' ' + norm([m.b, m.be, v ? v.t : ''].join(' ')) });
  }
  /* Zusatz: z. B. handgefuehrte Elektrowerkzeuge, DROSSBACH-Maschinen (nur Eintraege ausserhalb des Katalogs) */
  for (var zid in DATA.zusatz) {
    if (KAT[zid]) { continue; }
    var z = DATA.zusatz[zid], vz = verfahrenVon(zid);
    IDX.push({ k: 'm', id: zid, o: o++, tn: ' ' + norm(z.mb + ' ' + tyEcht(z)), an: ' ' + norm([z.b, vz ? vz.t : ''].join(' ')) });
  }
  return IDX;
}
function suchTreffer(q) {
  var qs = norm(q).split(' ').filter(function (x) { return x.length !== 0; });
  if (!qs.length) { return []; }
  var r = [];
  each(sucheIndex(), function (e) {
    var s = 0, ok = true;
    each(qs, function (w) {
      if (!ok) { return; }
      var wb = ' ' + w;
      if (e.tn.indexOf(wb) !== -1) { s += 6; }
      else if (e.tn.indexOf(w) !== -1) { s += 3; }
      else if (e.an.indexOf(wb) !== -1) { s += 2; }
      else if (e.an.indexOf(w) !== -1) { s += gt(w.length, 3) ? 1 : 0; if (!gt(w.length, 3)) { ok = false; } }
      else { ok = false; }
    });
    if (ok) { r.push({ e: e, s: s }); }
  });
  r.sort(function (a, b) { return (b.s - a.s) || (a.e.o - b.e.o); });
  return r;
}
var SUCHN = 0;
/* Suche (Runde 12 der Szene, Dimi 10.11.2026): dezent rechts neben den Reitern, ohne Vorschlagstexte. Antippen des leeren Feldes
   zeigt alle Bauteile nach Gruppen; Tippen sucht in Bauteilen, Anwendungen und Maschinen. Die Liste klappt unter dem Feld auf. */
function sucheBauen(par, zuBauteil, zuVerfahren) {
  var n = ++SUCHN, band = ht('div', 'wsd-s', null, par);
  var lab = ht('label', 'wsd-sl', 'Was möchten Sie fertigen?', band); lab.htmlFor = 'wsd-q' + n;
  var zl = ht('div', 'wsd-sz', null, band);
  var lu = sv('svg', { viewBox: '0 0 20 20', 'aria-hidden': 'true', focusable: 'false', 'class': 'wsd-slu' }, zl);
  sv('path', { d: 'M8.5 3 A5.5 5.5 0 1 1 8.49 3 Z M12.6 12.6 L17 17', fill: 'none', stroke: 'currentColor', 'stroke-width': 1.8, 'stroke-linecap': 'round' }, lu);
  var inp = ht('input', 'wsd-q', null, zl);
  inp.type = 'search'; inp.id = 'wsd-q' + n; inp.placeholder = 'Was möchten Sie fertigen?';
  inp.setAttribute('autocomplete', 'off'); inp.setAttribute('enterkeyhint', 'search'); inp.setAttribute('aria-controls', 'wsd-erg' + n);
  inp.setAttribute('aria-expanded', 'false');
  var erg = ht('div', 'wsd-erg', null, band); erg.id = 'wsd-erg' + n; erg.hidden = true; erg.setAttribute('aria-live', 'polite');
  function abschnitt(t, par2) { ht('div', 'wsd-eh', t, par2 || erg); return ht('div', 'wsd-eb', null, par2 || erg); }
  function leeren() { while (erg.firstChild) { erg.removeChild(erg.firstChild); } }
  function auf(a) { erg.hidden = !a; inp.setAttribute('aria-expanded', a ? 'true' : 'false'); band.classList.toggle('auf', a); }
  function teilKnopf(id, par2, klein) {
    var b = BT[id]; if (!b) { return null; }
    var k = ht('button', klein ? 'kl' : null, null, par2); k.type = 'button';
    ht('b', null, klein ? kurzName(b) : b.t, k);
    if (!klein) { ht('small', null, 'Fertigungsweg und Maschinen ›', k); }
    k.addEventListener('click', function () { auf(false); inp.blur(); zuBauteil(id); });
    return k;
  }
  /* leeres Feld: alle Bauteile in den Gruppen der Uebersicht (Rund, Eckig, Schalldaempfer) */
  function alle() {
    leeren(); auf(true);
    var gr = ht('div', 'wsd-ea', null, erg), SP = {};
    each(DATA.katsp || [], function (x) { var c = ht('div', 'wsd-eac', null, gr); ht('div', 'wsd-eh', x.t, c); SP[x.sp] = c; });
    each(DATA.kat || [], function (k) {
      var c = SP[k.sp]; if (!c) { c = SP[k.sp] = ht('div', 'wsd-eac', null, gr); }
      var ids = k.teile.filter(function (p) { return BT[p] ? BT[p].klick === 'ja' : false; }); if (!ids.length) { return; }
      if (gt(ids.length, 1)) { ht('div', 'wsd-ek', k.t, c); }
      var eb = ht('div', 'wsd-eb wsd-el' + (gt(ids.length, 1) ? '' : ' e1'), null, c);
      each(ids, function (p) { teilKnopf(p, eb, true); });
    });
  }
  /* Maschine als Zeile: kleines Foto (sonst Ablaufsymbol), Bezeichnung, Typ, Hersteller; fuehrt auf die Maschinenseite */
  function maschZeile(id, par2) {
    var m = masch(id); if (!m) { return; } if (m.g) { return; } if (m.z) { return; }
    var link = m.u ? seitenUrl(m.u) : '';
    var z = ht(link ? 'a' : 'span', 'wsd-em', null, par2); if (link) { z.href = link; }
    var bi = ht('span', 'wsd-emb', null, z), f = bildUrl(id, m);
    if (f) { var im = ht('img', null, null, bi); im.alt = ''; im.loading = 'lazy'; im.src = f; } else { var sy = maschSym(id), g = sy ? ikSvg(sy) : null; if (g) { g.classList.add('go'); g.classList.add('fix'); bi.appendChild(g); } }
    var tx = ht('span', 'wsd-emt', null, z); ht('small', null, m.mb, tx);
    var t = tyZeigen(m); if (t) { ht('b', null, t, tx); }
    if (m.b) { ht('i', null, m.b, tx); }
  }
  function zeigen() {
    var q = inp.value;
    if (lt(norm(q).length, 2)) { if (document.activeElement === inp) { alle(); } else { leeren(); auf(false); } return; }
    leeren(); auf(true);
    var r = suchTreffer(q), B = [], V = [], M = [];
    each(r, function (x) { if (x.e.k === 'b') { B.push(x.e); } else if (x.e.k === 'v') { V.push(x.e); } else { var mm = masch(x.e.id); if (mm) { if (!mm.g) { M.push(x.e); } } } });
    if (!r.length) { ht('p', 'wsd-e0', 'Kein Treffer. Rufen Sie uns an, wir finden die passende Maschine: ' + FIRMA.t, erg); return; }
    if (B.length) { var bb = abschnitt('Bauteile'); each(B.slice(0, 8), function (e) { teilKnopf(e.id, bb, false); }); }
    if (V.length) {
      var vb = abschnitt('Anwendungen');
      each(V.slice(0, 4), function (e) {
        var v = AID[e.id], k = ht('button', null, null, vb); k.type = 'button';
        var ic = ht('span', 'wsd-ei', null, k), g = ikSvg(v.sym[0]); if (g) { g.classList.add('go'); g.classList.add('fix'); ic.appendChild(g); }
        ht('b', null, v.t, k);
        k.addEventListener('click', function () { auf(false); inp.blur(); zuVerfahren(e.id); });
      });
    }
    if (M.length) { var mb = abschnitt('Maschinen'); mb.classList.add('wsd-ems'); each(M.slice(0, 10), function (e) { maschZeile(e.id, mb); }); }
  }
  inp.addEventListener('input', zeigen);
  inp.addEventListener('search', zeigen);
  inp.addEventListener('focus', zeigen);
  inp.addEventListener('click', function () { if (erg.hidden) { zeigen(); } });
  inp.addEventListener('keydown', function (ev) {
    if (ev.key === 'Escape') { if (inp.value) { inp.value = ''; zeigen(); } else { auf(false); inp.blur(); } }
    if (ev.key === 'Enter') { var b1 = erg.querySelector('button,a'); if (b1) { ev.preventDefault(); b1.click(); } }
  });
  /* Antippen ausserhalb schliesst die Liste */
  document.addEventListener('pointerdown', function (ev) { if (erg.hidden) { return; } if (band.contains(ev.target)) { return; } auf(false); });
  return { feld: inp, zeigen: function (t) { inp.value = t; zeigen(); auf(true); } };
}
/* Ideen und Verbesserungen (Runde 13 der Szene, Dimi 10.11.2026): dezent neben der Suche, wie beim Rechner ein Weg fuer Rueckmeldungen
   zu den Funktionen der Seite. Das Feld klappt wie die Suche auf: kurzer Text, Eingabe, „Nachricht senden“ oeffnet das E-Mail-Programm
   (an sales@, Betreff und angefuegter Stand der Ansicht wie beim Rechner). stand(): Reiter, Bauteil oder Gruppe, Rahmenverbindung */
var FB_MAIL = 'sales@wammesmachinery.com';
function feedbackBauen(par, stand) {
  var w = ht('div', 'wsd-fb', null, par);
  var k = ht('button', 'wsd-fbk', null, w); k.type = 'button'; k.setAttribute('aria-expanded', 'false'); k.setAttribute('aria-label', 'Ideen und Verbesserungen');
  var ic = sv('svg', { viewBox: '0 0 20 20', 'aria-hidden': 'true', focusable: 'false', 'class': 'wsd-fbi' }, k);
  sv('path', { d: 'M10 2.4 A5.6 5.6 0 0 0 6.6 12.4 C7.4 13.1 7.6 13.8 7.6 14.6 H12.4 C12.4 13.8 12.6 13.1 13.4 12.4 A5.6 5.6 0 0 0 10 2.4 Z M7.9 16.6 H12.1 M8.6 18.4 H11.4', fill: 'none', stroke: 'currentColor', 'stroke-width': 1.6, 'stroke-linecap': 'round', 'stroke-linejoin': 'round' }, ic);
  ht('span', 'wsd-fbt', 'Ideen und Verbesserungen', k);
  var pn = ht('div', 'wsd-fbp', null, w); pn.hidden = true; pn.setAttribute('role', 'dialog'); pn.setAttribute('aria-label', 'Ideen und Verbesserungen');
  ht('b', 'wsd-fbh', 'Ideen und Verbesserungen', pn);
  ht('p', null, 'Fehlt ein Bauteil, eine Maschine oder eine Funktion? Ist Ihnen ein Fehler aufgefallen? Schreiben Sie uns – wir prüfen jede Nachricht und bauen die Seite weiter aus.', pn);
  var ta = ht('textarea', 'wsd-fbx', null, pn); ta.rows = 4; ta.placeholder = 'Ihre Idee oder Ihr Hinweis …'; ta.setAttribute('aria-label', 'Ihre Nachricht');
  var zl = ht('div', 'wsd-fbz', null, pn);
  var snd = ht('button', 'wsd-fbs', 'Nachricht senden', zl); snd.type = 'button';
  ht('small', null, 'öffnet Ihr E-Mail-Programm', zl);
  function auf(a) { pn.hidden = !a; w.classList.toggle('auf', a); k.setAttribute('aria-expanded', a ? 'true' : 'false'); if (a) { window.setTimeout(function () { try { ta.focus(); } catch (e) { } }, 30); } }
  k.addEventListener('click', function () { auf(pn.hidden); });
  snd.addEventListener('click', function () {
    var NL = String.fromCharCode(10), AMP = String.fromCharCode(38);
    var body = [ta.value || '', '', '--- automatisch angefügt ---', 'Seite: ' + (location.pathname || ''), 'Ansicht: ' + (stand ? stand() : ''), 'Browser: ' + navigator.userAgent].join(NL);
    location.href = 'mailto:' + FB_MAIL + '?subject=' + encodeURIComponent('Idee zur Seite „Maschinen finden“') + AMP + 'body=' + encodeURIComponent(body);
    auf(false);
  });
  w.addEventListener('keydown', function (ev) { if (ev.key === 'Escape') { auf(false); k.focus(); } });
  document.addEventListener('pointerdown', function (ev) { if (pn.hidden) { return; } if (w.contains(ev.target)) { return; } auf(false); });
  return { auf: auf };
}

/* ---------- Vorschau-Umschalter Maschinenbezug: entfallen (Runde 8, Dimi 09.11.2026) ----------
   Vorschlag 1 (Kachel mit Maschinenbild) gilt fest, auch auf der Website (43_maschinenbild.js); die Vorschlaege 2 und 3
   und der Umschalter sind entfernt. Alter Stand: Szene/alt_vor_runde8/48_mbezug.js. */

/* ---------- Rohr-Rechner in der Strukturseite (Runde 14 der Szene, Dimi 10.11.2026, Variante C) ----------
   Knopf „Rohr-Rechner“ neben Suche und „Ideen und Verbesserungen“; der Rechner klappt darunter auf. Dazu eine Karte in der Kartei
   Wickelfalzrohr und bei „Rohre wickeln“, die denselben Rechner oeffnet. Der Rechner selbst ist die zentrale Datei
   wm-rechner-v1-komplett.js (Werkzeuge/Rechner_zentral, Medien › Rechner): sie wird beim ersten Oeffnen nachgeladen, wenn sie noch
   nicht auf der Seite ist, und erkennt den nachtraeglich eingefuegten Platzhalter selbst (MutationObserver im Rechner).
   Platzhalter der Strukturseite: data-rechner = eigene Adresse der Datei (Vorschau), sonst die Datei der Medienbibliothek. */
var RR_URL = '/media/64717d01-32ed-4949-a191-e0991e23b962/wm-rechner-v1-komplett.js', RR = null, RR_QUELLE = '';
function rrLaden() {
  var da = false;
  each(document.querySelectorAll('script'), function (s) { if (/wm-rechner-v1/.test(s.getAttribute('src') || '')) { da = true; } });
  if (da) { return; }
  var s = document.createElement('script'); s.async = true; s.src = RR_QUELLE || ((BASIS || '') + RR_URL);
  (document.head || document.documentElement).appendChild(s);
}
function rrSymbol(par, kl) {
  var ic = sv('svg', { viewBox: '0 0 20 20', 'aria-hidden': 'true', focusable: 'false', 'class': kl }, par);
  sv('rect', { x: 3.5, y: 2.5, width: 13, height: 15, rx: 1.6, fill: 'none', stroke: 'currentColor', 'stroke-width': 1.5 }, ic);
  sv('rect', { x: 6, y: 5, width: 8, height: 3, fill: 'currentColor' }, ic);
  each([[6.8, 11], [10, 11], [13.2, 11], [6.8, 14.2], [10, 14.2], [13.2, 14.2]], function (q) { sv('circle', { cx: q[0], cy: q[1], r: 0.95, fill: 'currentColor' }, ic); });
  return ic;
}
/* knopfPar: Leiste mit Suche und Ideen; panelPar: Platz unter der Leiste */
function rechnerBauen(knopfPar, panelPar, box) {
  RR_QUELLE = box.getAttribute('data-rechner') || '';
  var k = ht('button', 'wsd-fbk wsd-rrk', null, knopfPar); k.type = 'button'; k.setAttribute('aria-expanded', 'false');
  rrSymbol(k, 'wsd-fbi'); ht('span', 'wsd-fbt', 'Rohr-Rechner', k);
  var pn = ht('div', 'wsd-rr', null, panelPar); pn.hidden = true; pn.setAttribute('role', 'region'); pn.setAttribute('aria-label', 'Rohr-Rechner');
  var kopf = ht('div', 'wsd-rrh', null, pn);
  ht('b', null, 'Rohr-Rechner für Wickelfalzrohre', kopf);
  var x = ht('button', 'wsd-rrx', '×', kopf); x.type = 'button'; x.setAttribute('aria-label', 'Rohr-Rechner schließen');
  var platz = null;
  function auf(a, hin) {
    pn.hidden = !a; k.classList.toggle('on', a); k.setAttribute('aria-expanded', a ? 'true' : 'false');
    if (!a) { return; }
    if (!platz) { platz = ht('div', 'wmr', null, pn); platz.setAttribute('data-wmr', 'rohr'); platz.setAttribute('data-lang', 'de'); }
    rrLaden();
    if (hin) { window.setTimeout(function () { hinScrollen(pn); }, 40); }
  }
  k.addEventListener('click', function () { auf(pn.hidden, false); });
  x.addEventListener('click', function () { auf(false); k.focus(); });
  RR = { auf: auf };
  return RR;
}
/* Karte in Kartei und Einzelheiten: oeffnet den Rechner oben unter der Leiste */
function rechnerKarte(par) {
  var c = ht('button', 'wsd-rrc', null, par); c.type = 'button';
  var i = ht('span', 'wsd-rrci', null, c); rrSymbol(i, 'wsd-rrcs');
  var t = ht('span', 'wsd-rrct', null, c);
  ht('b', null, 'Rohr-Rechner', t);
  ht('small', null, 'Rohr und Coil, Kosten, Bedarf, Luft und Fläche – direkt hier rechnen', t);
  c.addEventListener('click', function () { if (RR) { RR.auf(true, true); } });
  return c;
}
var CSSRR = [
  '.wsd-rrk.on{background:#1F3855;color:#fff}',
  '.wsd-rrk.on:hover{background:#2A4A70;color:#fff}',
  '.wsd-rr{margin:0 0 14px 0;border:1px solid #1F3855;border-top:3px solid #1F3855;background:#fff;padding:10px 12px 12px}',
  '.wsd-rrh{display:flex;align-items:center;justify-content:space-between;gap:10px;margin:0 0 8px 0}',
  '.wsd-rrh b{font-size:15px;color:#1F3855}',
  '.wsd-rrx{border:0;background:none;font-size:22px;line-height:22px;color:#41566F;cursor:pointer;padding:0 4px}',
  '.wsd-rrx:hover{color:#1F3855}',
  '.wsd-rrc{display:flex;align-items:center;gap:10px;width:100%;max-width:420px;margin:10px 0 0 0;padding:8px 12px;font:inherit;text-align:left;background:#EEF3F9;border:1px solid #9DB0C6;border-left:4px solid #1F3855;color:#1F3855;cursor:pointer}',
  '.wsd-rrc:hover{background:#E2EAF3;border-color:#1F3855}',
  '.wsd-rrc:focus-visible{outline:2px solid #F7BC0C;outline-offset:2px}',
  '.wsd-rrci{flex:0 0 auto;display:flex;align-items:center;justify-content:center;width:38px;height:38px;background:#1F3855;color:#fff}',
  '.wsd-rrcs{display:block;width:24px;height:24px}',
  '.wsd-rrct{display:flex;flex-direction:column;min-width:0}',
  '.wsd-rrct b{font-size:14px;line-height:18px}',
  '.wsd-rrct small{font-size:12px;line-height:16px;color:#41566F}',
  '@media (max-width:560px){.wsd-rrk .wsd-fbt{display:none}}',
  /* Handy-Runde 2 (Dimi 12.11.2026, 09:23): in der schmalen Ansicht Suche ueber die ganze Breite, darunter „Ideen und Verbesserungen“
     und „Rohr-Rechner“ nebeneinander, gleich breit, mit Text */
  '@media (max-width:700px){.wsd-r .wsd-rf{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:6px;align-items:stretch;flex:1 1 100%;margin:8px 0 8px 0}',
  ' .wsd-r .wsd-s{grid-column:1/-1;min-width:0;margin:0;padding:0}.wsd-r .wsd-fb{align-self:stretch;margin:0}.wsd-r .wsd-fbk{width:100%;height:42px;justify-content:center;padding:0 8px;white-space:normal;line-height:15px;text-align:left}',
  ' .wsd-r .wsd-fbt,.wsd-r .wsd-rrk .wsd-fbt{display:inline}.wsd-r .wsd-fbp{right:auto;left:0}}'
].join('');
/* ---------- Strukturvorschau Variante B (Runde 14 der Szene, Dimi 10.11.2026: erst sehen, dann entscheiden) ----------
   Ohne Reiter „Fertigungsverfahren“: unter den Bauteilen „Oder direkt zur Maschinengruppe“ mit den Gruppen aus DATA.anwg; jede Karte
   nennt ihre Anwendungen und fuehrt auf die Kategorieseite der Website (g.u). Die Einzelheiten stehen dann auf den Kategorieseiten. */
function gruppenDirekt(par) {
  var G = DATA.anwg || []; if (!G.length) { return null; }
  var h = ht('h3', 'wsd-h wsd-vbh', 'Oder direkt zur Produktgruppe', par);
  infoKnopf(h, 'Jede Gruppe führt auf ihre Seite mit allen Maschinen, sortiert nach Anwendung.', { label: 'Gruppen' });
  var w = ht('div', 'wsd-vbg', null, par);
  each(G, function (g) {
    var namen = [], ids = [];
    each(g.k, function (id) { var a = AID[id]; if (!a) { return; } namen.push(a.t); var l = a.leit || (a.m.length ? a.m[0] : null); if (l) { if (ids.indexOf(l) === -1) { ids.push(l); } } });
    if (!ids.length) { return; }
    wkKarte(w, ids, { glieder: wbGlieder(ids, { einzeln: true }), titel: g.t, link: g.u ? seitenUrl(g.u) : '', klasse: 'wsd-vbk', gruppe: true, fest: { mb: namen.join(' · '), b: '' } });
  });
  return w;
}
var CSSVB = [
  '.wsd-vbh{margin-top:22px}',
  '.wsd-vbg{display:grid;grid-template-columns:repeat(5,minmax(0,1fr));gap:10px;margin:0 0 18px 0}',
  '.wsd-vbk.wmk-c{display:flex;flex-direction:column;background:#fff;border:1px solid #D5DDE6}',
  '.wsd-vbk.wmk-c.lk:hover{border-color:#1F3855;box-shadow:0 2px 10px rgba(31,56,85,.18)}',
  '.wsd-vbk .wmk-bi{height:120px}',
  '.wsd-vbk .wk-ot{font-size:13px!important;color:#1F3855!important}',
  '.wsd-vbk .wmk-mb{font-size:12px;line-height:16px;color:#41566F}',
  '@media (max-width:900px){.wsd-vbg{grid-template-columns:repeat(2,minmax(0,1fr))}}'
].join('');

/* ---------- Startseite (Dimi 11.11.2026, Abwandlung von Vorschlag 1) ----------
   Platzhalter mit data-modus="start": links die Anlage, rechts die Maschinengruppen (DATA.anwg). Jede Gruppe ist eine Karte mit dem Leitbild
   der ersten Kachel ihrer Gruppe unter „Fertigungsverfahren“ (z. B. Kanalbau eckig: MCL Ultra) und demselben Verhalten: beim ersten Sehen
   einmal Endprodukt und Ablauf im Gleichschritt, dann das Ruhebild; Maus darauf: im Wechsel; Maus weg: sofort das Ruhebild. Die Karte
   fuehrt auf die Kategorieseite der Gruppe (g.u).
   Sobald die Anlage bedient wird (Klick, Ziehen, Zoomen, Bauteil gewaehlt), faehrt die Gruppenleiste nach rechts weg (aus). Rechts bleibt ein
   blauer Balken mit Pfeil nach links; er holt die Leiste zurueck und setzt die Anlage zurueck (zurueck).
   data-gruppen="schmal" (Vorgabe): neben dem Balken bleiben kleine Kacheln (Leitbild und Kurzname); data-gruppen="weg": nur der Balken.
   Am Handy (unter 1.000 px) stehen die Gruppen unter der Anlage; beim Bedienen klappen sie zu einem Balken „Maschinengruppen“ zusammen.
   Pruefliste 17.8 (Dimi 11.11.2026): dazu „Andere Branchen“ (DATA.stg, nur Startseite) mit den Rohrmaschinen fuer Hüll-, Flex- und
   Kaminrohre; ab sechs Karten werden die Karten etwas niedriger, damit Anlage und Leiste auf den Schirm passen. */
var ST_KURZ = { eckig: 'Eckig', rund: 'Rund', blech: 'Blech', cnc: 'Schneiden', fuegen: 'Fügen', andere: 'Andere' }, ST_KH = 92, ST_KH6 = 82, ST_GAP = 8, ST_BALKEN = 32;
/* Dimi 11.11.2026, 07:54: der blaue Streifen links an der Leiste steht immer (auch ganz offen). Antippen: die Leiste waechst nach links
   auf zwei Drittel der Breite (gross) und zeigt grosse Kacheln wie unter „Fertigungsverfahren“ (Leitbild, blaue Linie, Maschine zum
   Bild, dazu ein kurzer Text je Gruppe: g.lt); der Pfeil dreht sich, nochmal Antippen fuehrt zurueck. Im Zustand aus holt der Streifen
   die Leiste zurueck wie bisher.
   Dimi 11.11.2026, 10:32: Leiste und Anlage ueberlappen sich nie. Die grosse Leiste steht im Fluss, die Anlage wird schmaler, bleibt
   mittig und zeigt denselben Ausschnitt kleiner (70_drei.js REF); der Balken unter ihr schrumpft mit, sein Pfeil bleibt in der Mitte.
   Legende und Knoepfe der Anlage ruhen solange. */
function startGruppen(par, root, box, zurueck) {
  var GR = (DATA.anwg || []).filter(function (g) { var ok = false; each(g.k, function (id) { if (AID[id]) { ok = true; } }); return ok; });
  each(DATA.stg || [], function (g) { var ok = false; each(g.m || [], function (id) { if (masch(id)) { ok = true; } }); if (ok) { GR.push(g); } });
  if (!GR.length) { return null; }
  var KH = lt(GR.length, 6) ? ST_KH : ST_KH6;
  var art = box.getAttribute('data-gruppen') === 'weg' ? 'weg' : 'schmal';
  root.classList.add('wsz-gp-' + art);
  var gp = ht('aside', 'wsz-gp', null, par); gp.setAttribute('aria-label', 'Produktgruppen'); gp.style.setProperty('--gkh', KH + 'px');
  /* Ziel des Schnellzugriffs „Maschinen“ der Startseite (wm-layout: #wmlBereiche) */
  if (!document.getElementById('wmlBereiche')) { gp.id = 'wmlBereiche'; }
  var lay = ht('div', 'wsz-gpl', null, gp);
  var bar = ht('button', 'wsz-gpb', null, lay); bar.type = 'button';
  var pf = sv('svg', { viewBox: '0 0 16 28', 'aria-hidden': 'true', focusable: 'false', 'class': 'wsz-gpp' }, bar);
  sv('path', { d: 'M12 3 L4 14 L12 25', fill: 'none', stroke: 'currentColor', 'stroke-width': 2.6, 'stroke-linecap': 'round', 'stroke-linejoin': 'round' }, pf);
  ht('span', 'wsz-gpbt', 'Produktgruppen', bar);
  var fl = ht('div', 'wsz-gpf', null, lay);
  var inn = ht('div', 'wsz-gpi', null, fl), mini = ht('div', 'wsz-gpm', null, fl), gross = null, WB = [], GLS = [], WBG = [];
  each(GR, function (g) {
    var a0 = null, namen = [];
    each(g.k || [], function (id) { var a = AID[id]; if (!a) { return; } if (!a0) { a0 = a; } namen.push(a.t); });
    if (g.txt) { namen = [g.txt]; }
    var link = g.u ? seitenUrl(g.u) : '';
    var k = ht(link ? 'a' : 'div', 'wsz-gk', null, inn); if (link) { k.href = link; }
    k.setAttribute('data-g', g.id);
    var bi = ht('span', 'wsz-gkb', null, k);
    var tx = ht('span', 'wsz-gkt', null, k); ht('b', null, g.t, tx); ht('small', null, namen.join(' · '), tx);
    ht('i', 'wsz-gkp', '›', k).setAttribute('aria-hidden', 'true');
    k.setAttribute('aria-label', g.t + ': ' + namen.join(', '));
    /* Leitbild: erste Kachel der Gruppe unter „Fertigungsverfahren“; weitere Gruppen (DATA.stg): ihre Maschinen mit Endprodukt */
    var GL = a0 ? anwGlieder(a0) : wbGlieder((g.m || []).filter(function (id) { return !!masch(id); }), { prod: g.prod || null, max: 6 });
    GLS.push(GL);
    var wb = GL.length ? wechselBild(k, bi, GL, {}) : null;
    WB.push(wb);
    /* kleine Kachel (data-gruppen="schmal"): Ruhebild und Kurzname */
    var m = ht(link ? 'a' : 'div', 'wsz-gm', null, mini); if (link) { m.href = link; } m.title = g.t; m.setAttribute('aria-label', g.t); m.tabIndex = -1;
    var mb = ht('span', 'wsz-gmb', null, m), f = GL.length ? GL[0] : null;
    if (f ? !!f.foto : false) { var im = ht('img', null, null, mb); im.alt = ''; im.decoding = 'async'; im.loading = 'lazy'; im.src = f.foto; fotoRahmen(im, f.fotoVon || f.id, true); }
    ht('span', 'wsz-gmt', g.ks || ST_KURZ[g.id] || g.t, m);
  });
  /* einmal im Gleichschritt, wenn die Karten das erste Mal sichtbar werden (wie die Kacheln der Fertigungsverfahren) */
  wbTakt(WB, inn);
  var aus = false, gr = false;
  function barText() {
    var t = aus ? 'Produktgruppen wieder zeigen' : (gr ? 'Produktgruppen verkleinern' : 'Produktgruppen vergrößern');
    bar.title = t; bar.setAttribute('aria-label', t); bar.setAttribute('aria-expanded', gr ? 'true' : 'false');
  }
  /* grosse Kacheln erst beim ersten Oeffnen (Bilder und Ablaeufe laden dann) */
  function grossBauen() {
    if (gross) { return; }
    gross = ht('div', 'wsz-gpg', null, fl);
    gross.style.gridTemplateRows = 'repeat(' + Math.max(1, Math.ceil(GR.length / 3)) + ',minmax(0,1fr))';
    each(GR, function (g, i) {
      var link = g.u ? seitenUrl(g.u) : '';
      var k = ht(link ? 'a' : 'div', 'wsz-gg', null, gross); if (link) { k.href = link; }
      k.setAttribute('data-g', g.id);
      ht('b', 'wsz-ggh', g.t, k);
      var bi = ht('span', 'wsz-ggb', null, k), cap = ht('span', 'wsz-ggc', null, k);
      if (g.lt) { ht('span', 'wsz-ggt', g.lt, k); }
      k.setAttribute('aria-label', g.t + (g.lt ? ': ' + g.lt : ''));
      WBG.push(GLS[i].length ? wechselBild(k, bi, GLS[i], { cap: cap }) : null);
    });
    wbTakt(WBG, gross);
  }
  function breite() { var W = par.clientWidth || 0; if (W) { gp.style.setProperty('--gpg', Math.round(W * 2 / 3) + 'px'); } }
  function tabs() {
    each(inn.querySelectorAll('a'), function (x) { x.tabIndex = (aus || gr) ? -1 : 0; });
    inn.setAttribute('aria-hidden', (aus || gr) ? 'true' : 'false');
    each(mini.querySelectorAll('a'), function (x) { x.tabIndex = aus ? (art === 'schmal' ? 0 : -1) : -1; });
    if (gross) { each(gross.querySelectorAll('a'), function (x) { x.tabIndex = gr ? 0 : -1; }); gross.setAttribute('aria-hidden', gr ? 'false' : 'true'); }
  }
  function grossSetz(g) {
    g = !!g; if (g === gr) { return; }
    if (g) { if (aus) { return; } if (lt(window.innerWidth, 1000)) { return; } grossBauen(); breite(); }
    gr = g; root.classList.toggle('wsz-gpgr', gr);
    if (!gr) { each(WBG, function (w) { if (w) { w.ruhe(); } }); }
    tabs(); barText();
  }
  function setz(a) {
    aus = !!a;
    if (aus) { if (gr) { grossSetz(false); } }
    root.classList.toggle('wsz-gpaus', aus);
    if (aus) { each(WB, function (w) { if (w) { w.ruhe(); } }); }
    tabs(); barText();
  }
  bar.addEventListener('click', function () {
    if (aus) { zurueck('gruppen'); window.setTimeout(function () { var k0 = inn.querySelector('a'); if (k0) { k0.focus({ preventScroll: true }); } }, 600); return; }
    grossSetz(!gr);
  });
  window.addEventListener('resize', function () { if (gr) { if (lt(window.innerWidth, 1000)) { grossSetz(false); } else { breite(); } } });
  tabs(); barText();
  return {
    aus: function () { setz(true); },
    ein: function () { setz(false); },
    istAus: function () { return aus; },
    gross: function (g) { if (g !== undefined) { grossSetz(g); } return gr; },
    /* Hoehe der Leiste am Rechner = Hoehe der Anlage; am Handy 0 (dann gilt die normale Hoehe) */
    hoehe: function () { if (lt(window.innerWidth, 1000)) { return 0; } var n = GR.length; return Math.max(420, n * KH + (n - 1) * ST_GAP); },
    el: gp
  };
}
var CSSST = [
  /* Reiter-Zeile der Startseite: Frage links (wie der aktive Reiter), daneben das Antwortfeld, rechts Ideen und Rohr-Rechner */
  '.wsz-start .wsd-rf{flex:1 1 auto;margin:0;min-width:0}',
  '.wsz-start .wsd-s{flex:0 1 440px}',
  '.wsz-start .wsd-fb{margin-left:auto}',
  '.wsz-start .wsd-rk button{cursor:pointer}',
  /* links die Spalte mit Anlage, blauem Balken und Bauteil-Kacheln, rechts die Gruppenleiste (so hoch wie die Anlage: --sth) */
  '.wsz-sw{display:flex;align-items:flex-start;gap:12px}',
  '.wsz-stl{flex:1 1 auto;min-width:0;isolation:isolate}',
  '.wsz-stw{position:relative;overflow:hidden}',
  '.wsz-stw .wsz-buehne{width:auto}',
  '.wsz-start .wsz-zg{display:none}',
  /* Balken unter der Anlage (Dimi 11.11.2026, 07:54): Pfeil nach oben klappt die Anlage zu, die Bauteil-Kacheln kommen an ihre Stelle */
  '.wsz-stb{display:flex;align-items:center;justify-content:center;width:100%;height:' + ST_BALKEN + 'px;margin:0;padding:0;border:0;background:#1F3855;color:#fff;cursor:pointer}',
  '.wsz-stb:hover{background:#2A4A70}',
  '.wsz-stb:focus-visible{outline:2px solid #F7BC0C;outline-offset:-2px}',
  '.wsz-stbp{display:block;width:26px;height:15px;transition:transform .35s ease}',
  '.wsz-stzk .wsz-stbp{transform:rotate(180deg)}',
  '.wsz-start .wsd-pk{margin-top:14px}',
  '.wsz-stin{animation:wszStIn .5s cubic-bezier(.2,.7,.2,1) both}',
  '@keyframes wszStIn{from{opacity:0;transform:translateY(48px)}to{opacity:1;transform:none}}',
  /* Gruppenleiste: Lage (wsz-gpl) mit Streifen und Flaeche; die Lage waechst im Zustand gross nach links ueber die Anlage */
  '.wsz-gp{--gpw:420px;position:relative;z-index:20;flex:0 0 auto;width:var(--gpw);height:var(--sth,auto);transition:width .55s cubic-bezier(.4,0,.2,1)}',
  '.wsz-gpl{position:absolute;right:0;top:0;bottom:0;width:100%;display:flex;gap:6px;background:#fff}',
  '.wsz-gpgr .wsz-gp{width:var(--gpg,840px)}',
  /* schmale Anlage neben der grossen Leiste: Legende, Knoepfe und Hinweis ruhen */
  '.wsz-ol,.wsz-3k,.wsz-kn,.wsz-schem{transition:opacity .25s ease}',
  '.wsz-gpgr .wsz-ol,.wsz-gpgr .wsz-3k,.wsz-gpgr .wsz-kn,.wsz-gpgr .wsz-schem{opacity:0;pointer-events:none}',
  '.wsz-gpb{flex:0 0 32px;display:flex;align-items:center;justify-content:center;gap:8px;padding:0;border:0;background:#1F3855;color:#fff;cursor:pointer}',
  '.wsz-gpb:hover{background:#2A4A70}',
  '.wsz-gpb:focus-visible{outline:2px solid #F7BC0C;outline-offset:-2px}',
  '.wsz-gpp{display:block;width:14px;height:26px;transition:transform .35s ease}',
  '.wsz-gpgr .wsz-gpp{transform:scaleX(-1)}',
  '.wsz-gpbt{display:none;font:600 14px Arial,Helvetica,sans-serif}',
  '.wsz-gpf{position:relative;flex:1 1 auto;min-width:0;overflow:hidden}',
  '.wsz-gpi{position:absolute;left:0;top:0;bottom:0;width:calc(var(--gpw) - 38px);display:flex;flex-direction:column;gap:' + ST_GAP + 'px;transition:transform .5s cubic-bezier(.4,0,.2,1),opacity .4s ease}',
  '.wsz-gpgr .wsz-gpi{opacity:0;pointer-events:none;transition:opacity .2s ease}',
  '.wsz-gk{position:relative;display:grid;grid-template-columns:132px minmax(0,1fr) 16px;align-items:center;gap:12px;height:var(--gkh,' + ST_KH + 'px);box-sizing:border-box;padding:0 10px 0 4px;background:#fff;border:1px solid #D5DDE6;border-left:4px solid #1F3855;color:inherit;text-decoration:none;transition:border-color .2s,box-shadow .2s}',
  'a.wsz-gk:hover{border-color:#1F3855;box-shadow:0 2px 10px rgba(31,56,85,.18)}',
  'a.wsz-gk:focus-visible{outline:2px solid #F7BC0C;outline-offset:2px}',
  '.wsz-gkb{position:relative;display:block;height:calc(var(--gkh,' + ST_KH + 'px) - 10px);background:#fff;overflow:hidden}',
  '.wsz-gkt{display:block;min-width:0}',
  '.wsz-gkt b{display:block;font:700 16px/20px Arial,Helvetica,sans-serif;color:#1F3855}',
  '.wsz-gkt small{display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;margin:3px 0 0 0;font:12px/15px Arial,Helvetica,sans-serif;color:#5C6670}',
  '.wsz-gkp{font-style:normal;font-size:24px;line-height:24px;color:#1F3855}',
  /* grosse Kacheln (gross): wie die Kacheln der Fertigungsverfahren, dazu der kurze Text der Gruppe */
  '.wsz-gpg{position:absolute;right:0;top:0;bottom:0;width:calc(var(--gpg,840px) - 38px);display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:10px;opacity:0;pointer-events:none;transition:opacity .2s ease}',
  '.wsz-gpgr .wsz-gpg{opacity:1;pointer-events:auto;transition:opacity .35s ease .3s}',
  '.wsz-gg{position:relative;display:flex;flex-direction:column;min-width:0;min-height:0;box-sizing:border-box;padding:8px 10px 9px;background:#fff;border:1px solid #D5DDE6;border-top:3px solid #1F3855;color:inherit;text-decoration:none;transition:border-color .2s,box-shadow .2s}',
  'a.wsz-gg:hover{border-color:#1F3855;box-shadow:0 3px 12px rgba(31,56,85,.16)}',
  'a.wsz-gg:focus-visible{outline:2px solid #F7BC0C;outline-offset:2px}',
  '.wsz-ggh{flex:0 0 auto;font:700 15px/19px Arial,Helvetica,sans-serif;color:#1F3855}',
  '.wsz-ggb{position:relative;display:block;flex:1 1 auto;min-height:56px;margin:6px 0}',
  '.wsz-ggc{flex:0 0 auto;display:block;min-height:15px;padding:4px 0 0 0;border-top:2px solid #1F3855;font:700 12px/15px Arial,Helvetica,sans-serif;color:#1F3855;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}',
  /* Runde 18 (Dimi 11.11.2026, 20:13): Text immer vier Zeilen hoch, damit Bild und Querlinie in allen Kacheln auf einer Hoehe stehen */
  '.wsz-ggt{flex:0 0 68px;height:68px;display:-webkit-box;-webkit-line-clamp:4;-webkit-box-orient:vertical;overflow:hidden;margin:4px 0 0 0;font:12.5px/17px Arial,Helvetica,sans-serif;color:#41566F;-webkit-hyphens:auto;hyphens:auto}',
  /* kleine Kacheln (schmal) */
  '.wsz-gpm{position:absolute;left:0;top:0;bottom:0;width:100%;display:flex;flex-direction:column;gap:6px;opacity:0;pointer-events:none;transition:opacity .2s ease}',
  '.wsz-gm{flex:1 1 0;min-height:0;display:flex;flex-direction:column;box-sizing:border-box;padding:3px 3px 2px;background:#fff;border:1px solid #D5DDE6;border-left:3px solid #1F3855;color:#1F3855;text-decoration:none}',
  'a.wsz-gm:hover{border-color:#1F3855;box-shadow:0 2px 8px rgba(31,56,85,.18)}',
  'a.wsz-gm:focus-visible{outline:2px solid #F7BC0C;outline-offset:1px}',
  '.wsz-gmb{position:relative;flex:1 1 auto;min-height:0;overflow:hidden}',
  '.wsz-gmb img{position:absolute;display:block}',
  '.wsz-gmb img:not(.rh){left:0;top:0;width:100%;height:100%;object-fit:contain}',
  '.wsz-gmt{flex:0 0 auto;font:700 10px/13px Arial,Helvetica,sans-serif;text-align:center;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}',
  /* ausgefahren: Leiste schmal (98 px: Streifen und kleine Kacheln) oder nur der Streifen (32 px) */
  '.wsz-gpaus .wsz-gp{width:98px}',
  '.wsz-gpaus.wsz-gp-weg .wsz-gp{width:32px}',
  '.wsz-gpaus.wsz-gp-weg .wsz-gpl{gap:0}',
  '.wsz-gpaus .wsz-gpi{transform:translateX(105%);opacity:0;pointer-events:none}',
  '.wsz-gpaus.wsz-gp-schmal .wsz-gpm{opacity:1;pointer-events:auto;transition:opacity .3s ease .35s}',
  /* Bauteil-Kacheln erst, wenn die Anlage bedient wird oder der Balken sie holt */
  '.wsz-stzu{display:none}',
  '@media (max-width:1279px){.wsz-gp{--gpw:360px}.wsz-gk{grid-template-columns:104px minmax(0,1fr) 14px;gap:10px}}',
  '@media (max-width:999px){.wsz-sw{flex-direction:column;align-items:stretch;gap:10px}.wsz-stl{display:contents}',
  ' .wsz-stw{order:1}.wsz-stb{order:2}.wsz-gp{order:3}.wsz-stl .wsd-pk{order:4}.wsz-stzk .wsz-stl .wsd-pk{order:3}.wsz-stzk .wsz-gp{order:4}',
  ' .wsz-gp{width:auto!important;height:auto!important}.wsz-gpl{position:static;width:auto!important;display:block;background:none;box-shadow:none!important}.wsz-gpf{overflow:visible}',
  ' .wsz-gpi{position:static;width:auto;display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:8px;transform:none!important;opacity:1!important;pointer-events:auto!important}',
  ' .wsz-gpm,.wsz-gpg{display:none}.wsz-gpb{display:none}.wsz-gpaus .wsz-gpi{display:none}',
  ' .wsz-gpaus .wsz-gpb{display:flex;width:100%;height:42px}.wsz-gpaus .wsz-gpbt{display:inline}.wsz-gpp{width:10px;height:18px}}',
  '@media (max-width:560px){.wsz-gpi{grid-template-columns:minmax(0,1fr)}.wsz-gk{height:84px;grid-template-columns:104px minmax(0,1fr) 14px}.wsz-gkb{height:74px}',
  ' .wsz-start .wsd-rf{flex-wrap:wrap;row-gap:4px}.wsz-start .wsd-s{flex:1 1 100%}.wsz-start .wsd-fb{margin-left:auto}}',
  /* Handy-Runde (Dimi 12.11.2026, Prüfliste 25.4): in der schmalen Ansicht tragen die Balken Text, der Pfeil zeigt die Richtung */
  '@media (max-width:999px){.wsz-stb{height:40px;gap:10px}.wsz-stb::after{content:attr(data-t);font:700 14px/18px Arial,Helvetica,sans-serif}.wsz-stbp{width:20px;height:12px}',
  ' .wsz-gpaus .wsz-gpb{height:40px}.wsz-gpp{transform:rotate(-90deg)}.wsz-gpbt::after{content:" zeigen"}}',
  '@media (prefers-reduced-motion:reduce){.wsz-gp,.wsz-gpl,.wsz-gpi,.wsz-gpg,.wsz-gpm,.wsz-gpp,.wsz-stbp,.wsz-stw,.wsz-ol,.wsz-3k,.wsz-kn,.wsz-schem{transition:none!important}.wsz-stin{animation:none}}'
].join('');

/* ---------- Bauteil-Symbole mit Bereichen (Teil b) ----------
   Je Bauteil eine eigene Zeichnung. Bereichsnummern = Reihenfolge der Bereiche in den Daten (v13).
   bereich(k, f): alles in f gehoert zu Bereich k; verdeckt([k], f): wird bei Bereich k ausgeblendet;
   innenTeil(f): Innenflaechen, liegen unter allen Aussenflaechen. */
var EX = [1, 0, 0], EY = [0, 1, 0], EZ = [0, 0, 1], NX = [-1, 0, 0], NY = [0, -1, 0];
var SYM = {}, SYMC = {};
/* Masse (Runde 10 der Szene, Dimi 09.11.2026, Runde 11 Punkt 11): die wichtigsten Abmessungen je Formteil mit Masslinien, Pfeilen
   und Buchstaben (rechteckige Teile wie DIN 18379, Tabelle 2: a, b Querschnitt, l Laenge, r Radius, e Versatz ...). Nur in der
   3D-Ansicht der Kartei (teilErfassen sammelt sie), ein- und ausschaltbar. t Buchstabe, n Bedeutung (Druck), art:
   lin (a Punkt, b Punkt, c Versatz der Masslinie), dm (a Mitte, b Achse, c Radius, d Richtung), rad (a Mitte, b Punkt),
   win (a Mitte, b und c Richtungen, d Radius). Werte in mm wie die Zeichnung. */
var MASSE = null;
function mass(t, n, art, a, b, c, d) { if (!MASSE) { return; } MASSE.push({ t: t, n: n, art: art, a: a, b: b, c: c, d: d }); }

/* Hilfen */
function oeffnungR(p, A, r, pid, b) {
  var F = rahmen([sb(p, A), ad(p, A)]), q = [];
  for (var k = 0; k !== 28; k++) { var a = 2 * Math.PI * k / 28; q.push(ad(p, mu(ad(mu(F.N[0], Math.cos(a)), mu(F.B[0], Math.sin(a))), r))); }
  return bereich(null, function () {
    var it = oeffnung(q, A, pid, {});
    if (b) { if (it) { each(IT.slice(IT.length - 2), function (o) { o.d += b; }); } }
    return it;
  });
}
/* Tiefenzuschlag fuer Teile auf Rohroberflaechen (Rohre im Symbol fein geteilt, ch 30) */
var SB = 28, CHR = 30;
/* Sicke als erhabener Ring (Breite bw) */
function sicke(p, A, r, pid, bw, b) {
  var h = (bw || 10) / 2;
  schlauch(teile(sb(p, mu(A, h)), ad(p, mu(A, h)), 40), r + 3.5, 'm', pid, { b: b || 3, innen: false, ew: 0.8 });
}
/* Steckende: Rohrstueck p bis p+A*L, Sicke sk mm vor dem Ende, Lippendichtung am Ende */
function steckende(p, A, L, r, pid, o) {
  o = o || {};
  var e = ad(p, mu(A, L));
  mitA(o, 'rohr', function () { rohr(p, e, r, pid, { ch: CHR, innen: false, rim0: o.rim0 }); });
  mitA(o, 'sicke', function () { sicke(ad(p, mu(A, L - (o.sk || 45))), A, r, pid, 10, SB); });
  mitA(o, 'dicht', function () { lippe(e, A, r, pid, { b: SB }); });
  if (o.offen !== false) { oeffnungR(e, A, r, pid); }
  return e;
}
/* Runde 18 (Dimi 11.11.2026): nur noch beim Rundrohr mit Laengsnaht (lnr); alle Formstuecke zeigen Schweisspunkte (punktNaht).
   Laengsnaht rollnahtgeschweisst (Fable Runde 17, Dimi 11.11.2026: Rollnaht mit Drahtelektrode): die Blechkanten ueberlappen
   wenige Millimeter, die Elektrodenrollen hinterlassen eine durchgehende schmale Schweissspur. Gezeichnet in Stuecken (fuer
   die Tiefe) unter dem Winkel an (von +y Richtung +z): Blechkante als dunkle Linie, daneben die Spur als Band (6 mm), helle Kante.
   Unterschied zur punktgeschweissten Naht (punktNaht): durchgehende Spur statt einzelner Punkte */
function naht(p0, p1, r, pid, an) {
  var a = an || 64 * Math.PI / 180, n = Math.max(4, Math.round(len(sb(p1, p0)) / 30)), i;
  function off(d, h) { return [0, (r + h) * Math.cos(a + d / r), (r + h) * Math.sin(a + d / r)]; }
  var o0 = off(0, 0.6), o1 = off(2, 1.2), o2 = off(8, 1.2), o3 = off(10.5, 0.6), nn = [0, Math.cos(a + 5 / r), Math.sin(a + 5 / r)];
  for (i = 0; i !== n; i++) {
    var q0 = lp(p0, p1, i / n), q1 = lp(p0, p1, (i + 1) / n);
    face([ad(q0, o1), ad(q1, o1), ad(q1, o2), ad(q0, o2)], 'm', pid, { n: nn, c: '#B7C2CF', b: SB - 0.2 });
    line([ad(q0, o0), ad(q1, o0)], pid, { s: '#5E7189', w: 1.1, b: SB, lc: 'butt' });
    line([ad(q0, o3), ad(q1, o3)], pid, { s: '#FFFFFF', w: 1, b: SB, lc: 'butt' });
  }
}
/* Wickelfalz als Band (Fable Runde 17): der vierlagige Falz liegt als flaches, leicht erhabenes Band schraubenfoermig auf dem Rohr
   (Breite o.bw, Standard 9 mm). Gangrichtung wie wickel() in 10_kern.js: am Bildschirm rechtsgaengig wie das echte Rohr */
function wickelBand(p0, p1, r, pid, steig, o) {
  o = o || {};
  var t = nz(sb(p1, p0)), L = len(sb(p1, p0)), F = rahmen([p0, p1]), N = F.N[0], B = F.B[0], bw = o.bw || 9, bz = o.b || 1;
  var st = Math.ceil(L / steig * (o.nk || 64)), k;
  function H(s, d) {
    var w = -(2 * Math.PI * s / steig + (o.ph || 0)), v = ad(mu(N, Math.cos(w)), mu(B, Math.sin(w)));
    return { p: ad(ad(p0, mu(t, Math.min(L, s + d))), mu(v, r + 1.4)), v: v };
  }
  for (k = 0; k !== st; k++) {
    var a = H(L * k / st, 0), b = H(L * (k + 1) / st, 0), c = H(L * (k + 1) / st, bw), d = H(L * k / st, bw), vm = nz(ad(a.v, b.v));
    if (!D3) { if (!gt(dt(vm, VV), 0.04)) { continue; } }
    face([a.p, b.p, c.p, d.p], 'm', pid, { n: vm, b: bz, c: '#D1DAE4' });
    line([a.p, b.p], pid, { w: 1.1, s: '#4F6178', b: bz + 0.1 });
    line([d.p, c.p], pid, { w: 0.8, s: '#7D8DA0', b: bz + 0.1 });
  }
}
/* Laengsnaht punktgeschweisst (Runde 13 der Szene, Dimi 10.11.2026: Laengsnaht beider Koerper zeigen, punktgeschweisst):
   Naht laengs auf der sichtbaren Seite eines Rohrs (Achse p0 nach p1, Radius r): dunkle Linie mit heller Kante und
   Schweisspunkte im Abstand o.ab (Standard 45 mm); o.dreh dreht die Naht um die Achse (Grad, von der Blickrichtung aus) */
function punktNaht(p0, p1, r, pid, o) {
  o = o || {};
  var A = nz(sb(p1, p0)), w = sb(VV, mu(A, dt(VV, A))), i, k;
  if (!gt(len(w), 1e-6)) { w = gt(Math.abs(A[2]), 0.9) ? [1, 0, 0] : [0, 0, 1]; }
  w = nz(w);
  var q = cr(A, w), g = (o.dreh === undefined ? 25 : o.dreh) * Math.PI / 180, d = nz(ad(mu(w, Math.cos(g)), mu(q, Math.sin(g))));
  var e = nz(cr(A, d)), L = len(sb(p1, p0)), n = Math.max(4, Math.round(L / 30)), b = o.b || SB;
  for (i = 0; i !== n; i++) {
    var a0 = ad(lp(p0, p1, i / n), mu(d, r + 1)), a1 = ad(lp(p0, p1, (i + 1) / n), mu(d, r + 1));
    line([a0, a1], pid, { s: '#5E7189', w: 1.1, b: b, lc: 'butt' });
    line([ad(a0, mu(e, 9)), ad(a1, mu(e, 9))], pid, { s: '#FFFFFF', w: 1, b: b, lc: 'butt' });
  }
  var np = Math.max(2, Math.floor(L / (o.ab || 45)));
  for (i = 0; i !== np; i++) {
    var c = ad(lp(p0, p1, (i + 0.5) / np), mu(d, r + 1.5)), pts = [];
    for (k = 0; k !== 8; k++) { var aa = 2 * Math.PI * k / 8; pts.push(ad(c, ad(mu(A, 7 * Math.cos(aa)), mu(e, 7 * Math.sin(aa))))); }
    face(pts, 'd', pid, { n: d, c: '#4B5666', b: b + 0.5, k: 1 });
  }
}
/* Ringflaeche (Kreisring) in der Ebene senkrecht zu A, sichtbar in Richtung A */
function kreisring(p, A, r0, r1, m, pid, o) {
  o = o || {};
  var F = rahmen([sb(p, A), ad(p, A)]), G = [], NG = [];
  for (var i = 0; i !== 37; i++) {
    var a = 2 * Math.PI * i / 36, v = ad(mu(F.N[0], Math.cos(a)), mu(F.B[0], Math.sin(a)));
    G.push([ad(p, mu(v, r0)), ad(p, mu(v, r1))]); NG.push([A, A]);
  }
  return patch(G, m, pid, { NG: NG, f0: o.f0 ? 1 : 0, f1: o.f1 === false ? 0 : 1, e0: 0, e1: 0, b: o.b || 1, c: o.c });
}
/* Kreisflaeche auf einer ebenen Rasterflaeche r (Mitte u,v; Radius in mm) */
function kreisAuf(r, u, v, rad, m, pid, o) {
  o = o || {};
  var Lu = len(r.U), Lw = len(r.W), uu = nz(r.U), ww = nz(r.W), q = [], n = o.nk || 36;
  for (var k = 0; k !== n; k++) { var a = 2 * Math.PI * k / n; q.push(uvP(r, [u + rad * Math.cos(a) / Lu, v + rad * Math.sin(a) / Lw], o.h || 0.6)); }
  var it = face(q, m, pid, { n: r.n, d: (zelleD(r, u, v) || 0) + (o.b || 0.3), c: o.c, k: o.k });
  if (it) { if (o.s) { line(q.concat([q[0]]), pid, { d: it.d + 0.05, w: o.w || 0.8, s: o.s }); } }
  return it;
}

/* ===== Rechteckige Teile ===== */
/* Masse eines geraden Kanals (x 0..L, Breite w entlang y, Hoehe h entlang z): a, b am Ende, l unten vorn */
function masseKanal(L, w, h, lt2) {
  mass('a', 'Breite', 'lin', [L + 30, -w / 2, h / 2], [L + 30, w / 2, h / 2], [0, 0, 120]);
  mass('b', 'Höhe', 'lin', [L + 30, w / 2, -h / 2], [L + 30, w / 2, h / 2], [0, 120, 0]);
  mass('l', lt2 || 'Länge', 'lin', [0, w / 2, -h / 2], [L, w / 2, -h / 2], [0, 0, -130]);
}
/* Fable Runde 17 (Dimi 11.11.2026): Biegekanten als eigener Bereich (rk und kurzkanal 4, passlaenge 5), damit „Kanten und Laengsfalz
   schliessen“ beide Bereiche zeigen kann. Kanal aus zwei L-Teilen: zwei Biegekanten, zwei Laengsfalze an den anderen Ecken.
   Laengsfalz als Pittsburgh-Verbindung: Tasche (Pittsburghfalz) auf dem einen Blech, umgelegte Lippe auf dem Blech mit dem Stehfalz */
var RK_FALZ = { falz: 'ph', falz2: 1, falzB: 18, falzL: 9, kant: 1, kantB: 60, dicht: 1 };
SYM.rk = { hw: 'Beispiel: Kanal aus zwei L-Teilen mit je einer Biegekante; Längsfalz als Pittsburgh-Verbindung an den beiden anderen Ecken (Pittsburghfalz und Stehfalz), Steckrahmen mit Dichtband.', f: function () {
  kanalL([0, 0, 0], EX, 1000, EY, 600, EZ, 400, 'm', 'rk', ext(RK_FALZ, { A: { mantel: 0, falz: 1, rahmen: 2, sicke: 0, dicht: 3, kant: 4, innen: null } }));
  masseKanal(1000, 600, 400);
} };
/* Flaches Blech an den Stationen des 3-Maschinen-Systems (Runde 13, Dimi 10.11.2026): Zuschnitt fuer ein L-Teil,
   schematisch und mit groesseren Profilen gezeichnet, damit sie im kleinen Bild erkennbar bleiben.
   Bereich 0: Blech mit Versteifungssicken, Eckausklinkungen und Kerben an der Kantlinie; 1: Pittsburgh-Tasche an einer
   Laengskante (mit Dichtmasse); 2: PDF-Flansch an beiden Enden (nur Station 2, die Kerbe wird zum Gehrungsspalt) */
function flachBlech(pid, fl) {
  var L = 700, W = 700, K = 420, F = 60, P = 40, T = 22, H = 70, N = [0, 0, 1], D0 = -1e5;
  function Q(x, y, z) { return [x, y, z || 0]; }
  bereich(0, function () {
    var u = fl ? [[F, 0], [L - F, 0], [L - F, P], [L, P], [L, W], [0, W], [0, P], [F, P]]
      : [[F, 0], [L - F, 0], [L - F, P], [L, P], [L, K - F], [L - F, K], [L, K + F], [L, W], [0, W], [0, K + F], [F, K], [0, K - F], [0, P], [F, P]];
    var q = u.map(function (a) { return Q(a[0], a[1]); });
    face(q, 'm', pid, { n: N, d: D0 });
    line(q.concat([q[0]]), pid, { d: D0 + 1, w: 0.9 });
    /* Kantlinie: hier kantet Station 3 */
    line([Q(fl ? T : F, K), Q(fl ? L - T : L - F, K)], pid, { d: D0 + 1, w: 0.7, s: '#5E7189', da: '4 3', op: 0.85 });
    /* Versteifungssicken quer zur Kanalachse, je Seitenflaeche */
    var x = 110;
    while (lt(x, L - 100)) {
      each([[P + 25, K - 25], [K + 25, W - 25]], function (v) {
        line([Q(x, v[0]), Q(x, v[1])], pid, { d: D0 + 2, s: '#FFFFFF', w: 1.1, op: 0.95 });
        line([Q(x + 11, v[0]), Q(x + 11, v[1])], pid, { d: D0 + 2, s: '#5E7189', w: 0.8, op: 0.75 });
      });
      x += 160;
    }
  });
  /* Pittsburghfalz (Tasche): Kante doppelt umgelegt, Schlitz oben */
  bereich(1, function () {
    var x0 = F, x1 = L - F, h = 30;
    box(x0, 0, 0, x1, P, h, 'm', pid, { ch: 200 });
    line([Q(x0 + 4, P * 0.42, h + 0.5), Q(x1 - 4, P * 0.42, h + 0.5)], pid, { b: 2, w: 1.1, s: '#3E4652' });
  });
  /* Stehfalz am anderen Ende (Fable Runde 17, nach der Betriebsanleitung der Stufe 1: die querfahrende Pittsburgh-Einheit trennt
     das Band und profiliert in einem Zug beide Seiten der Naht, Pittsburghfalz am einen und Stehfalz am anderen Teil):
     Kante 90 Grad aufgestellt, hier hoeher gezeichnet als in Wirklichkeit */
  bereich(1, function () {
    var x0 = F, x1 = L - F, hs = 24, A = [Q(x0, W, 0), Q(x1, W, 0), Q(x1, W, hs), Q(x0, W, hs)];
    face(A, 'm', pid, { n: [0, 1, 0], two: 1, b: 1 });
    line(A.concat([A[0]]), pid, { b: 1.3, w: 0.9 });
  });
  if (!fl) { return; }
  /* PDF-Flansch an beiden Enden, stehend; an der Kantlinie ein Gehrungsspalt (45 Grad) */
  bereich(2, function () {
    each([0, 1], function (e) {
      var xa = e ? L - T : 0, xb = e ? L : T, xs = e ? xb : xb;
      each([[P, K, P, K - H], [K, W, K + H, W]], function (g) {
        /* g: y unten von..bis, y oben von..bis */
        var A = [Q(xs, g[0]), Q(xs, g[1]), Q(xs, g[3], H), Q(xs, g[2], H)];
        face(A, 'm', pid, { n: [1, 0, 0] });
        line(A.concat([A[0]]), pid, { b: 0.3, w: 0.8 });
        var O = [Q(xa, g[2], H), Q(xb, g[2], H), Q(xb, g[3], H), Q(xa, g[3], H)];
        face(O, 'm', pid, { n: N, b: 1 });
        line(O.concat([O[0]]), pid, { b: 1.3, w: 0.8 });
        /* Stirnseite am Gehrungsspalt (zeigt nach +y) bzw. am Blechrand */
        if (g[1] === K) {
          var S = [Q(xa, K, 0), Q(xb, K, 0), Q(xb, K - H, H), Q(xa, K - H, H)];
          face(S, 'm', pid, { n: nz([0, 1, 1]), b: 0.6 }); line(S.concat([S[0]]), pid, { b: 0.9, w: 0.7 });
        } else {
          var R = [Q(xa, W, 0), Q(xb, W, 0), Q(xb, W, H), Q(xa, W, H)];
          face(R, 'm', pid, { n: [0, 1, 0], b: 0.6 }); line(R.concat([R[0]]), pid, { b: 0.9, w: 0.7 });
        }
      });
    });
  });
}
SYM.rkflach1 = { hw: 'Stufe 1: Zuschnitt vom Coil mit Sicken und Ausklinkungen, noch flach; an einem Ende der Pittsburghfalz (Tasche), am anderen der Stehfalz.', f: function () { flachBlech('rkflach1', false); } };
SYM.rkflach2 = { hw: 'Stufe 2: PDF-Flansch an beiden Seiten des flachen Zuschnitts; die Kerbe an der Kantlinie wird zum Gehrungsspalt.', f: function () { flachBlech('rkflach2', true); } };
/* Kurzkanal und Passlaenge (Dimi 09.11.2026, Runde 10 der Antworten; Begriffe nach DIN 18379, Recherche 09.11.2026) */
SYM.kurzkanal = { hw: 'Beispiel: Kanalteil 400 mm lang (bis 900 mm), sonst wie der gerade Kanal.', f: function () {
  kanalL([0, 0, 0], EX, 400, EY, 600, EZ, 400, 'm', 'kurzkanal', ext(RK_FALZ, { A: { mantel: 0, falz: 1, rahmen: 2, sicke: 0, dicht: 3, kant: 4, innen: null } }));
  masseKanal(400, 600, 400, 'Länge (bis 900)');
} };
SYM.passlaenge = { hw: 'Beispiel: ein Rahmen fest mit Dichtband, der zweite liegt lose bei. Auf der Baustelle wird das Teil gekürzt und der Rahmen aufgeschoben.', f: function () {
  kanalL([0, 0, 0], EX, 1000, EY, 600, EZ, 400, 'm', 'passlaenge', ext(RK_FALZ, { A: { mantel: 0, falz: 1, rahmen: 2, sicke: 0, dicht: 4, kant: 5, innen: null }, fr1: false }));
  bereich(3, function () { profil([1170, 0, 0], NX, EY, 600, EZ, 400, 'passlaenge', {}); });
  masseKanal(1000, 600, 400, 'Länge (Passlänge l + 200)');
} };
SYM.rbogen = { vn: ['Rechteckbogen', 'Etagenstück mit Radien', 'Rohrgabelung'], hw: 'Im Wechsel: Bogen 90° mit einem Leitblech (Falz an den Kanten der Seitenbleche), Etagenstück mit Radien (Seitenbleche S-förmig, Mantelbleche gerundet, 500 × 400 mit 250 mm Versatz) und Rohrgabelung mit zwei Abgängen 90° mit Radien.', f: function () {
  var fx = [4];
  /* Runde 12 der Szene (Dimi 10.11.2026, Prüfliste Punkt 13): wieder die alte, schräge Perspektive; sie ist besser erkennbar */
  bogenR([0, 0, 0], EX, EY, 600, 400, 200, 'm', 'rbogen', { A: { seite: 0, mantel: 1, falz: 2, rahmen: 3, leit: 4, innen: null }, FX: { seite: fx, falz: fx, innen: fx }, falzB: 11, falzT: 17, leit: 1, innenFl: 1 });
  /* Bogen symmetrisch BS (DIN 18379 Nr. 6): Mitte C = (0, 500), Innenradius 200, Austritt bei y = 500 */
  mass('a', 'Breite', 'lin', [200, 530, 200], [800, 530, 200], [0, 110, 0]);
  mass('b', 'Höhe', 'lin', [800, 530, -200], [800, 530, 200], [120, 0, 0]);
  mass('r', 'Innenradius', 'rad', [0, 500, 200], [193.2, 448.2, 200]);
  mass('α', 'Winkel', 'win', [0, 500, 200], [0, -1, 0], [1, 0, 0], 140);
} };
SYM.rwinkel = { vn: ['Rechteckwinkel', 'T-Stück', 'Hosenstück'], hw: 'Im Wechsel: Winkel 90° und T-Stück 90°, beide mit Leitblechen auf der Diagonale, und Hosenstück nach DIN 18379 (ein Querschnitt teilt sich gerade auf zwei Abgänge übereinander); T-Stück und Hosenstück mit drei Rahmenverbindungen.', f: function () {
  var fx = [4];
  winkelR([0, 0, 0], EX, EY, 600, 400, 220, 220, 'm', 'rwinkel', { A: { seite: 0, mantel: 1, falz: 2, rahmen: 3, leit: 4, leitL: 4, innen: null }, FX: { seite: fx, falz: fx, innen: fx }, falzB: 11, falzT: 17, leit: 1, innenFl: 1 });
  /* Winkel symmetrisch WS (DIN 18379 Nr. 8): a, b am Austritt, e und f die geraden Schenkel innen */
  mass('a', 'Breite', 'lin', [220, 550, 200], [820, 550, 200], [0, 100, 0]);
  mass('b', 'Höhe', 'lin', [820, 550, -200], [820, 550, 200], [120, 0, 0]);
  mass('f', 'Schenkel', 'lin', [0, 300, 200], [220, 300, 200], [0, 165, 0]);
  mass('e', 'Schenkel', 'lin', [220, 300, 200], [220, 520, 200], [-55, 0, 0]);
} };
SYM.ruebergang = { hw: 'Beispiel: Längsnaht als Hakenfalz in der Mitte einer Seitenfläche, Steckende als eigener Ring mit Sicke und Lippendichtung.', f: function () {
  var r = 157.5, L = 420, pc = [L, 0, 0];
  uebergang([0, 0, 0], EX, L, EY, 500, EZ, 400, r, 'm', 'ruebergang', { A: { drei: 0, ecke: 0, naht: 1, rahmen: 2 }, naht: 1, haken: 16 });
  bereich(3, function () { steckende(pc, EX, 95, r, 'ruebergang', { sk: 52 }); });
  /* Rohruebergang RS (DIN 18379 Nr. 12): a, b am Rechteck, d am Rohr, l */
  mass('a', 'Breite', 'lin', [-30, -250, 200], [-30, 250, 200], [0, 0, 110]);
  mass('b', 'Höhe', 'lin', [-30, 250, -200], [-30, 250, 200], [0, 110, 0]);
  mass('d', 'Durchmesser', 'dm', [L + 95, 0, 0], EX, r, EZ);
  mass('l', 'Länge', 'lin', [0, 250, -200], [L, r, -200], [0, 0, -110], EX);
} };
SYM.retage = { vn: ['Etagenstück gekantet', 'Übergang einseitig', 'Übergang symmetrisch'], hw: 'Im Wechsel: Etagenstück gekantet (500 × 400, 250 mm Versatz in einer Ebene), Übergang einseitig und Übergang symmetrisch (je 600 × 400 auf 400 × 300). Seitenbleche mit Falzband an den Längsfalzen.', f: function () {
  etageR([0, 0, 0], EX, 900, NY, 250, 500, 400, 170, 'm', 'retage', { A: { seite: 0, mantel: 1, falz: 2, rahmen: 3, innen: null }, falzB: 11, falzT: 17, innenFl: 1 });
  masseEtage();
} };
/* Etage symmetrisch ES (DIN 18379 Nr. 14): Eintritt bei x = 0 (y -250..250), Austritt bei x = 900 (y -500..0) */
function masseEtage() {
  mass('a', 'Breite', 'lin', [930, -500, 200], [930, 0, 200], [0, 0, 110]);
  mass('b', 'Höhe', 'lin', [930, 0, -200], [930, 0, 200], [0, 110, 0]);
  mass('e', 'Versatz', 'lin', [900, 0, 200], [0, 250, 200], [140, 0, 0], EY);
  mass('l', 'Länge', 'lin', [0, -250, 200], [900, -500, 200], [0, -380, 0], EX);
}
SYM.rreduz = { hw: 'Beispiel: Übergang 600 × 400 auf 400 × 300, einseitig: eine Seite und der Boden laufen gerade durch.', f: function () {
  reduzR([0, 0, 0], EX, 520, EY, 600, 400, EZ, 400, 300, -100, -50, 'm', 'rreduz', { A: { bleche: 0, falz: 1, rahmen: 2, innen: null }, innenFl: 1 });
} };
/* Rohrgabelung: eigene Zeichnung fuer die Anlage (hose) und Bauform 3 von rbogen (52_varianten.js). Am Bereiche */
function gabelSym(pid, Am) {
  var w = 40 * Math.PI / 180, A = [Math.cos(w), Math.sin(w), 0], T = [Math.sin(w), -Math.cos(w), 0];
  hose([0, 0, 0], A, T, 800, 400, 200, 'm', pid, { A: Am, falzB: 11, falzT: 17 });
  var C = mu(T, 600), q = ad(C, mu(ad(mu(T, -Math.cos(Math.PI / 6)), mu(A, Math.sin(Math.PI / 6))), 200));
  mass('a', 'Breite Eintritt', 'lin', ad(mu(T, -400), [0, 0, 200]), ad(mu(T, 400), [0, 0, 200]), mu(A, -150));
  mass('b', 'Höhe', 'lin', ad(mu(T, 400), [0, 0, -200]), ad(mu(T, 400), [0, 0, 200]), ad(mu(A, -60), mu(T, 80)));
  mass('r', 'Innenradius', 'rad', ad(C, [0, 0, 200]), ad(q, [0, 0, 200]));
  /* Laenge vom Eintritt bis zur Aussenkante der Abgaenge (Runde 12 der Szene, Dimi 10.11.2026) */
  mass('l', 'Länge', 'lin', ad(mu(T, 400), [0, 0, -200]), ad(ad(mu(T, 600), mu(A, 600)), [0, 0, -200]), mu(T, 140), A);
}
SYM.hose = { hw: 'Beispiel: Rohrgabelung mit zwei Abgängen 90° mit Radien; Längsfalz als Pittsburgh-Verbindung an den Kanten der Seitenbleche.', f: function () {
  gabelSym('hose', { seite: 0, mantel: 1, falz: 2, spitze: 3, rahmen: 4, innen: null });
} };
/* Hosenstueck nach DIN 18379, Tabelle 2, Nr. 18 (HS): Eintritt 500 x 500, Abgaenge 500 x 280 oben und unten, Abstand 80 */
function hosenSym(pid) {
  var a = 500, b = 500, d = 280, hh = 280, mg = 80, L = 800;
  var k = hosenR([0, 0, 0], EX, EY, a, EZ, b, d, hh, mg, L, pid, { A: { seite: 0, mantel: 1, falz: 2, rahmen: 3, innen: null }, falzB: 11, falzT: 17 });
  mass('a', 'Breite', 'lin', [L + 30, -a / 2, k.zT1], [L + 30, a / 2, k.zT1], [0, 0, 110]);
  mass('d', 'Höhe oberer Abgang', 'lin', [L + 30, a / 2, k.zIu], [L + 30, a / 2, k.zT1], [0, 110, 0]);
  mass('m', 'Abstand', 'lin', [L + 30, a / 2, k.zIl], [L + 30, a / 2, k.zIu], [0, 110, 0]);
  mass('h', 'Höhe unterer Abgang', 'lin', [L + 30, a / 2, k.zB1], [L + 30, a / 2, k.zIl], [0, 110, 0]);
  mass('b', 'Höhe Eintritt', 'lin', [-30, a / 2, -b / 2], [-30, a / 2, b / 2], [0, 110, 0]);
  mass('l', 'Länge', 'lin', [0, a / 2, k.zB1], [L, a / 2, k.zB1], [0, 0, -120], EX);
}
SYM.hosenstueck = { hw: 'Hosenstück nach DIN 18379 (HS): ein Querschnitt teilt sich gerade auf zwei Abgänge übereinander, mit Abstand m für die Rahmen. Seitenbleche in Hosenform, Mantelbleche gekantet.', f: function () { hosenSym('hosenstueck'); } };
SYM.rboden = { hw: 'Beispiel: Einsteck-Deckel mit Bord im Kanalende, genietet oder gepunktet.', f: function () {
  var pid = 'rboden', L = 320, w = 600, h = 400, fx = [1];
  var k = kanalL([0, 0, 0], EX, L, EY, w, EZ, h, 'm', pid, { A: { mantel: null, rahmen: null, innen: null }, FX: { mantel: fx }, fr1: false, sicke: false, innen: false });
  /* Innenflaechen des Kanals */
  innenTeil(function () {
    plane([0, -w / 2 + 0.5, -h / 2], [L, 0, 0], [0, 0, h], 'i', pid, { out: EY, noedge: 1 });
    plane([0, -w / 2, -h / 2 + 0.5], [L, 0, 0], [0, w, 0], 'i', pid, { out: EZ, noedge: 1 });
  });
  bereich(0, function () { endrechteck([L + 0.5, 0, 0], EX, EY, w, EZ, h, 'm', pid, {}); });
  mass('a', 'Breite', 'lin', [L, -w / 2, h / 2], [L, w / 2, h / 2], [0, 0, 110]);
  mass('b', 'Höhe', 'lin', [L, w / 2, -h / 2], [L, w / 2, h / 2], [0, 110, 0]);
  bereich(0, function () {
    innenTeil(function () {
      var t = 40, x = L - t;
      plane([x, -w / 2 + 2, -h / 2 + 2], [t, 0, 0], [0, w - 4, 0], 'r', pid, { out: EZ, ew: 0.8 });
      plane([x, -w / 2 + 2, -h / 2 + 2], [t, 0, 0], [0, 0, h - 4], 'r', pid, { out: EY, ew: 0.8 });
      plane([x, -w / 2 + 2, h / 2 - 2], [t, 0, 0], [0, w - 4, 0], 'r', pid, { out: EZ, ew: 0.8 });
      plane([x, w / 2 - 2, -h / 2 + 2], [t, 0, 0], [0, 0, h - 4], 'r', pid, { out: EY, ew: 0.8 });
    });
  });
  bereich(1, function () {
    var u = (L - 20) / L;
    each([0.2, 0.5, 0.8], function (v) {
      kreisAuf(k.pw, u, v, 10, 'd', pid, { c: '#4B5666', b: 0.6, k: 1 });
      kreisAuf(k.ph, u, v, 10, 'd', pid, { c: '#4B5666', b: 0.6, k: 1 });
    });
  });
} };
SYM.rstutzen = { hw: 'Beispiel: Stutzen von außen eingesetzt, Laschen innen umgelegt, je Lasche ein Fügepunkt durch Kanalwand und Lasche.', f: function () {
  var pid = 'rstutzen', L = 900, w = 600, h = 400, rs = 125, zt = h / 2, xc = 450, Hs = 110, NL = 12;
  var k = kanalL([0, 0, 0], EX, L, EY, w, EZ, h, 'm', pid, { A: { mantel: null, rahmen: null, innen: null }, FX: { mantel: [1] }, sicke: false });
  var top = k.ph, uc = xc / L, vc = 0.5;
  innenTeil(function () {
    plane([0, -w / 2 + 0.5, -h / 2], [L, 0, 0], [0, 0, h], 'i', pid, { out: EY, noedge: 1 });
    plane([0, -w / 2, -h / 2 + 0.5], [L, 0, 0], [0, w, 0], 'i', pid, { out: EZ, noedge: 1 });
    /* Laschen innen unter der Kanalwand */
    bereich(1, function () {
      for (var j = 0; j !== NL; j++) {
        var a0 = 2 * Math.PI * (j + 0.14) / NL, a1 = 2 * Math.PI * (j + 0.86) / NL, q = [], i;
        for (i = 0; i !== 4; i++) { var a = a0 + (a1 - a0) * i / 3; q.push([xc + rs * Math.cos(a), rs * Math.sin(a), zt - 1.5]); }
        for (i = 3; i !== -1; i--) { var c2 = a0 + (a1 - a0) * i / 3; q.push([xc + (rs + 30) * Math.cos(c2), (rs + 30) * Math.sin(c2), zt - 1.5]); }
        var it = face(q, 'm', pid, { n: EZ, c: '#DDE4EC' });
        if (it) { line(q.concat([q[0]]), pid, { d: it.d + 0.05, w: 0.8 }); }
      }
    });
  });
  /* Ausschnitt */
  bereich(0, function () { kreisAuf(top, uc, vc, rs, 'm', pid, { c: INNEN, b: 0.3, s: '#4B5666', w: 0.9 }); });
  verdeckt([0], function () {
    bereich(1, function () { rohr([xc, 0, zt], [xc, 0, zt + Hs], rs, pid, { ch: 60, innen: false }); });
    oeffnungR([xc, 0, zt + Hs], EZ, rs, pid);
    bereich(1, function () { sicke([xc, 0, zt + 52], EZ, rs, pid, 11); });
  });
  mass('d', 'Durchmesser', 'dm', [xc, 0, zt + Hs], EZ, rs, EY);
  mass('l', 'Stutzenlänge', 'lin', [xc + rs, 0, zt], [xc + rs, 0, zt + Hs], [110, 0, 0]);
  /* Fuegepunkte auf der Kanalwand ueber den Laschen */
  bereich(2, function () {
    for (var j = 0; j !== NL; j++) {
      var am = 2 * Math.PI * (j + 0.5) / NL, x = xc + (rs + 16) * Math.cos(am), y = (rs + 16) * Math.sin(am);
      var d = zelleD(top, x / L, 0.5 + y / w);
      scheibe([x, y, zt + 1.5], EZ, 8, 'd', pid, { d: (d || 0) + 0.7, c: '#4B5666', k: 1 });
    }
  });
} };
SYM.kd = { hw: 'Beispiel: Klappenblatt im Kanal, außen Verstellsegment und Hebel.', f: function () {
  var pid = 'kd', L = 800, w = 500, h = 400, fx = [1], xc = 400;
  kanalL([0, 0, 0], EX, L, EY, w, EZ, h, 'm', pid, { A: { mantel: 0, falz: 0, rahmen: 0, sicke: 0, innen: null }, FX: { mantel: fx, falz: fx, sicke: fx, innen: fx }, falz: 'ph' });
  innenTeil(function () {
    plane([0, -w / 2 + 0.5, -h / 2], [L, 0, 0], [0, 0, h], 'i', pid, { out: EY, noedge: 1 });
    plane([0, -w / 2, -h / 2 + 0.5], [L, 0, 0], [0, w, 0], 'i', pid, { out: EZ, noedge: 1 });
  });
  bereich(1, function () {
    var ds = [Math.sin(Math.PI / 6), 0, Math.cos(Math.PI / 6)], c = [xc, 0, 0], hb = (h - 14) / 2, wb = (w - 12) / 2;
    innenTeil(function () {
      var q = [ad(ad(c, mu(EY, -wb)), mu(ds, -hb)), ad(ad(c, mu(EY, wb)), mu(ds, -hb)), ad(ad(c, mu(EY, wb)), mu(ds, hb)), ad(ad(c, mu(EY, -wb)), mu(ds, hb))];
      var it = face(q, 'r', pid, { two: 1 });
      if (it) { line(q.concat([q[0]]), pid, { d: it.d + 0.3, w: 0.9 }); }
      rohr([xc, -w / 2, 0], [xc, w / 2, 0], 8, pid, { m: 'd', innen: false, ch: 200 });
    });
    /* aussen auf der Seite +y: Verstellsegment, Hebel, Wellenende */
    var cS = [xc, w / 2, 0];
    function Q(rad, an, off) { return ad(ad(ad(cS, mu(EX, rad * Math.cos(an))), mu(EZ, rad * Math.sin(an))), mu(EY, off)); }
    var pts = [], k;
    for (k = 0; k !== 10; k++) { pts.push(Q(150, Math.PI * (0.25 + 0.5 * k / 9), 3)); }
    var sec = [ad(cS, mu(EY, 3))].concat(pts);
    face(sec, 'r', pid, { n: EY, b: 2 });
    line(sec.concat([sec[0]]), pid, { b: 2.5, w: 0.9 });
    for (k = 1; k !== 9; k++) { var a2 = Math.PI * (0.25 + 0.5 * k / 9); line([Q(120, a2, 4), Q(145, a2, 4)], pid, { b: 3, w: 0.6 }); }
    rohr(cS, ad(cS, mu(EY, 40)), 12, pid, { m: 'd', b: 5 });
    line([ad(cS, mu(EY, 30)), Q(175, Math.PI * 0.6, 30)], pid, { b: 6, w: 3.4, s: '#3E4652' });
  });
} };
SYM.anschlusskasten = { hw: 'Beispiel: Kasten mit seitlichem Stutzen; am Anschlussflansch unten wird der Luftdurchlass befestigt.', f: function () {
  var pid = 'anschlusskasten', s = 500, H = 380, rs = 100, e = 32;
  bereich(2, function () {
    var fl = box(-e, -e, 0, s + e, s + e, 3, 'm', pid, { ch: 300 });
    each([[0.5, 0.97], [0.18, 0.97], [0.82, 0.97]], function (uv) { kreisAuf(fl.t, uv[0], uv[1], 6, 'd', pid, { c: '#4B5666', b: 0.6, nk: 10, k: 1 }); kreisAuf(fl.t, uv[1], uv[0], 6, 'd', pid, { c: '#4B5666', b: 0.6, nk: 10, k: 1 }); });
  });
  bereich(0, function () { box(0, 0, 3, s, s, H, 'm', pid, { ch: 300 }); });
  bereich(1, function () {
    var p = [s, s / 2, H / 2 + 10];
    kreisring(ad(p, [1, 0, 0]), EX, rs, rs + 28, 'r', pid, { b: 200 });
    rohr(p, ad(p, [85, 0, 0]), rs, pid, { ch: CHR, innen: false, b: 210 });
    sicke(ad(p, [40, 0, 0]), EX, rs, pid, 9, 240);
  });
  oeffnungR([s + 85, s / 2, H / 2 + 10], EX, rs, 'anschlusskasten', 230);
  mass('a', 'Breite', 'lin', [0, s, H + 3], [s, s, H + 3], [0, 0, 110]);
  mass('b', 'Tiefe', 'lin', [s, 0, H + 3], [s, s, H + 3], [0, 0, 110]);
  mass('h', 'Höhe', 'lin', [0, s, 3], [0, s, H + 3], [0, 120, 0]);
  mass('d', 'Durchmesser Stutzen', 'dm', [s + 85, s / 2, H / 2 + 10], EX, rs, EZ);
} };
SYM.revision = { hw: 'Beispiel: Deckel mit zwei Schnellverschlüssen; die Dichtung liegt unter dem Deckel.', f: function () {
  var pid = 'revision', L = 1000, w = 500, h = 400, yw = w / 2;
  var k = kanalL([0, 0, 0], EX, L, EY, w, EZ, h, 'm', pid, { A: { mantel: null, rahmen: null, innen: null }, sicke: false });
  var x0 = 330, x1 = 670, z0 = -110, z1 = 110;
  bereich(0, function () { auf(k.pw, [[x0 / L, (z0 + h / 2) / h], [x1 / L, (z0 + h / 2) / h], [x1 / L, (z1 + h / 2) / h], [x0 / L, (z1 + h / 2) / h]], pid, { fill: 1, c: INNEN, s: '#4B5666', w: 0.9, b: 0.3 }); });
  bereich(1, function () {
    var f = 32, t = 6;
    box(x0 - f, yw, z1, x1 + f, yw + t, z1 + f, 'r', pid, { b: 150 });
    box(x0 - f, yw, z0 - f, x1 + f, yw + t, z0, 'r', pid, { b: 150 });
    box(x0 - f, yw, z0, x0, yw + t, z1, 'r', pid, { b: 150 });
    box(x1, yw, z0, x1 + f, yw + t, z1, 'r', pid, { b: 150 });
  });
  verdeckt([0, 1], function () {
    bereich(2, function () {
      var d = box(x0 - 20, yw + 6, z0 - 20, x1 + 20, yw + 26, z1 + 20, 'm', pid, { ch: 400, b: 170 });
      auf(d.y, [[0.04, 0.08], [0.96, 0.08], [0.96, 0.92], [0.04, 0.92], [0.04, 0.08]], pid, { s: '#8A96A6', w: 0.6 });
      each([z0 + 30, z1 - 70], function (zz) { box(x1 - 34, yw + 26, zz, x1 + 6, yw + 40, zz + 40, 'd', pid, { b: 190 }); });
    });
  });
  /* Masse (Runde 10 der Szene): lichte Oeffnung a x b */
  mass('a', 'Breite Öffnung', 'lin', [x0, yw + 40, z0 - 32], [x1, yw + 40, z0 - 32], [0, 0, -100]);
  mass('b', 'Höhe Öffnung', 'lin', [x1 + 32, yw + 40, z0], [x1 + 32, yw + 40, z1], [100, 0, 0]);
} };
SYM.dachhaube = { hw: 'Beispiel: Haube mit Pultdach und Vogelschutzgitter auf einem Sockel über dem Dach.', f: function () {
  bereich(null, function () {
    var d = box(-820, -640, -230, 820, 640, -30, 'w', 'dachhaube', { ch: 400, es: '#8C857B' });
    schraffur(d.y, 'dachhaube', 0, { d: 70 }); schraffur(d.x, 'dachhaube', 0, { d: 70 });
    box(-820, -640, -30, 820, 640, 0, 'r', 'dachhaube', { ch: 400 });
  });
  dachhaube(0, 0, 0, { A: { haube: 0, sockel: 1, gitter: 2 } });
} };

/* ===== Runde Teile ===== */
SYM.wfr = { hw: 'Wickelfalz mit einer Versteifungssicke dazwischen. Das Rohrende nimmt das Formstück auf (Muffenseite).', f: function () {
  var pid = 'wfr', r = 157.5, L = 760, st = 118, e = 30;
  bereich(2, function () {
    rohr([0, 0, 0], [e, 0, 0], r, pid, { innen: false, rim1: false, ch: CHR });
    rohr([L - e, 0, 0], [L, 0, 0], r, pid, { innen: false, rim0: false, ch: CHR });
  });
  bereich(0, function () { rohr([e, 0, 0], [L - e, 0, 0], r, pid, { innen: false, rim0: false, rim1: false, ch: CHR }); });
  oeffnungR([L, 0, 0], EX, r, pid);
  bereich(1, function () { wickelBand([0, 0, 0], [L, 0, 0], r, pid, st, { b: SB, nk: 64, bw: 10 }); });
  bereich(0, function () {
    wickel([0, 0, 0], [L, 0, 0], r, pid, st, { ph: Math.PI, w: 1.4, s: '#FFFFFF', b: SB, nk: 64 });
    wickel([0, 0, 0], [L, 0, 0], r, pid, st, { ph: Math.PI + 0.22, w: 0.8, s: '#6F829A', op: 0.9, b: SB, nk: 64 });
  });
  mass('d', 'Nenndurchmesser', 'dm', [L, 0, 0], EX, r, EZ);
  mass('l', 'Länge', 'lin', [0, r, 0], [L, r, 0], [0, 110, 0]);
} };
SYM.lnr = { hw: 'Beispiel: vorn Sicke und Lippendichtung, hinten Bördelrand; welches Ende, hängt von der Verbindung ab.', f: function () {
  var pid = 'lnr', r = 125, L = 620;
  bereich(0, function () { rohr([0, 0, 0], [L, 0, 0], r, pid, { innen: false, ch: CHR }); });
  oeffnungR([L, 0, 0], EX, r, pid);
  bereich(1, function () { naht([8, 0, 0], [L - 8, 0, 0], r, pid); });
  bereich(2, function () {
    sicke([L - 48, 0, 0], EX, r, pid, 10, SB);
    lippe([L, 0, 0], EX, r, pid, { b: SB });
    schlauch(teile([0, 0, 0], [5, 0, 0], 10), r + 11, 'm', pid, { innen: false, b: SB });
    kreisring([5, 0, 0], EX, r, r + 11, 'm', pid, { b: SB + 1 });
  });
  mass('d', 'Nenndurchmesser', 'dm', [L, 0, 0], EX, r, EZ);
  mass('l', 'Länge', 'lin', [0, r, 0], [L, r, 0], [0, 110, 0]);
} };
/* Hoehe des Stehfalzes zwischen den Segmenten in der Zeichnung (mm); die Profilierrollen der Segmentbogenmaschine gibt es fuer 5, 7,5 und 10 mm */
var SEG_RIPPE = 8;
SYM.segbogen = { vn: ['Segmentbogen 90°', 'Segmentbogen 45°', 'Etagenbogen'], hw: 'Im Wechsel: Bogen 90° aus fünf Segmenten, Bogen 45° aus drei Segmenten (je mit halben Endsegmenten) und Etagenbogen aus zwei Bögen 45° mit verlängertem Mittelsegment; zwischen den Segmenten der Stehfalz als Rippe, Längsnähte versetzt.', f: function () {
  var pid = 'segbogen', R = 250, r = 125, Ls = 75;
  var s = segBogen([0, 0, 0], EX, EY, R, r, 'm', pid, { A: { seg: 0, naht: 1, umf: 2 }, naht: 1, enden: 1, rippe: SEG_RIPPE });
  bereich(3, function () {
    steckende([0, 0, 0], NX, Ls, r, pid, { rim0: false });
    steckende(s.pe, EY, Ls, r, pid, { rim0: false });
  });
  mass('d', 'Nenndurchmesser', 'dm', ad(s.pe, mu(EY, Ls)), EY, r, EX);
  mass('r', 'Radius (Achse)', 'rad', [0, R, 0], [R * 0.7071, R - R * 0.7071, 0]);
  mass('α', 'Winkel', 'win', [0, R, 0], [0, -1, 0], [1, 0, 0], 95);
} };
/* ghost: Bereich, der nur Traeger ist (Dimi 09.11.2026: der Grundkoerper ist nicht das gemeinte Teil) – in der Kartei
   blendet er langsam ab und wieder auf, in kleinen Bildern steht er blass */
SYM.tstueck = { vn: ['Sattelstutzen 90°', 'Sattelstutzen 45°'], hw: 'Im Wechsel: Sattelstutzen 90° und 45° auf einem Grundrohr aus Wickelfalzrohr (nur Träger, blass); alle Enden mit Sicke und Lippendichtung.', ghost: 0, f: function () {
  var pid = 'tstueck', R = 157.5, r = 100, L = 440, st = 118, x1 = 175;
  bereich(0, function () {
    rohr([-L, 0, 0], [L, 0, 0], R, pid, { innen: false, ch: CHR });
    wickel([-L, 0, 0], [-x1, 0, 0], R, pid, st, { b: SB, nk: 64 });
    wickel([x1, 0, 0], [L, 0, 0], R, pid, st, { b: SB, ph: 2 * Math.PI * (x1 + L) / st, nk: 64 });
  });
  oeffnungR([L, 0, 0], EX, R, pid);
  var t = sattel([0, 0, 0], EX, R, EZ, r, R + 190, 'm', pid, { A: { abzweig: 1, rand: 2, ende: 3 }, sickeB: SB + 30, lipB: SB + 30, bA: SB, bR: SB + 2, bP: SB + 4 });
  oeffnungR(t.pe, EZ, r, pid);
  mass('d₁', 'Durchmesser Grundrohr', 'dm', [L, 0, 0], EX, R, EY);
  mass('d₂', 'Durchmesser Abzweig', 'dm', t.pe, EZ, r, EX);
  /* Stutzenlaenge vom Grundrohr bis zum Ende (Runde 12 der Szene, Dimi 10.11.2026) */
  mass('l', 'Stutzenlänge', 'lin', [r, 0, R], [r, 0, R + 190], [90, 0, 0]);
  bereich(4, function () { punktNaht([0, 0, R + 22], [0, 0, R + 190 - 66], r, pid, { b: SB + 6 }); });
  bereich(3, function () {
    sicke([L - 48, 0, 0], EX, R, pid, 10, SB); lippe([L, 0, 0], EX, R, pid, { b: SB });
    sicke([-L + 48, 0, 0], EX, R, pid, 10, SB); lippe([-L, 0, 0], NX, R, pid, { b: SB });
  });
} };
/* Breite des Fuegebords am Abzweig in der Zeichnung (mm) */
var T_BORD = 13;
SYM.tstueck90 = { vn: ['T-Stück 90°', 'Abzweig 45°', 'Kreuzstück', 'T-Stück mit kleinerem Abgang'], hw: 'Im Wechsel: T-Stück 90° (Ø 315, Abgang Ø 250), Abzweig 45°, Kreuzstück und T-Stück mit kleinerem Abgang (Ø 160); die Abgänge mit einem schmalen Bord am Grundkörper punktgeschweißt, alle Enden mit Sicke und Lippendichtung.', f: function () {
  var pid = 'tstueck90', R = 157.5, r = 125, L = 400;
  bereich(0, function () { rohr([-L, 0, 0], [L, 0, 0], R, pid, { innen: false, ch: CHR }); });
  oeffnungR([L, 0, 0], EX, R, pid);
  var t = tStueck90([0, 0, 0], EX, R, EZ, r, R + 230, 'm', pid, { A: { abzweig: 1, naht: 2, ende: 3 }, sickeB: SB + 30, lipB: SB + 30, bA: SB, bN: SB + 4, bord: T_BORD });
  oeffnungR(t.pe, EZ, r, pid);
  bereich(3, function () {
    sicke([L - 48, 0, 0], EX, R, pid, 10, SB); lippe([L, 0, 0], EX, R, pid, { b: SB });
    sicke([-L + 48, 0, 0], EX, R, pid, 10, SB); lippe([-L, 0, 0], NX, R, pid, { b: SB });
  });
  bereich(4, function () {
    punktNaht([-L + 70, 0, 0], [L - 70, 0, 0], R, pid, { b: SB + 2, dreh: 30 });
    punktNaht([0, 0, R + 24], [0, 0, R + 230 - 66], r, pid, { b: SB + 6 });
  });
  mass('d₁', 'Durchmesser Durchgang', 'dm', [L, 0, 0], EX, R, EY);
  mass('d₂', 'Durchmesser Abgang', 'dm', t.pe, EZ, r, EX);
  mass('l', 'Länge', 'lin', [-L, R, 0], [L, R, 0], [0, 110, 0]);
} };
SYM.reduz = { vn: ['Reduzierung zentrisch', 'Reduzierung exzentrisch', 'Gerades Rohrstück'], hw: 'Im Wechsel: Reduzierung zentrisch und exzentrisch (oben bündig), je Ø 315 auf Ø 200, und gerades Rohrstück ohne Querschnittsänderung (Ø 250).', f: function () {
  var pid = 'reduz', L = 380, r0 = 157.5, r1 = 100;
  reduz([0, 0, 0], EX, L, r0, r1, 'm', pid, { A: { konus: 0, ansch: 1, umf: 2, innen: null, laengs: 4 }, fein: 1, rb: SB, umfB: 14 });
  bereich(3, function () {
    sicke([45, 0, 0], EX, r0, pid, 10, SB); lippe([0, 0, 0], NX, r0, pid, { b: SB });
    sicke([L - 45, 0, 0], EX, r1, pid, 10, SB); lippe([L, 0, 0], EX, r1, pid, { b: SB });
  });
  mass('d₁', 'Durchmesser groß', 'dm', [0, 0, 0], NX, r0, EZ);
  mass('d₂', 'Durchmesser klein', 'dm', [L, 0, 0], EX, r1, EZ);
  mass('l', 'Länge', 'lin', [0, r0, 0], [L, r1, 0], [0, 110, 0], EX);
} };
SYM.enddeckel = { hw: 'Beispiel: Ronde und Ring (gerundet, Längsnaht) durch Bördeln verbunden; Steckende mit Sicke und Lippendichtung.', f: function () {
  var pid = 'enddeckel', r = 157.5, L = 95;
  bereich(1, function () { rohr([-L, 0, 0], [-10, 0, 0], r, pid, { innen: false, rim1: false, ch: CHR }); });
  /* Laengsnaht am Ring als eigener Bereich (Dimi 11.11.2026, 07:54: Elementbild „Längsnaht“) */
  bereich(4, function () { punktNaht([-L + 6, 0, 0], [-16, 0, 0], r, pid, { b: SB, ab: 30 }); });
  bereich(2, function () {
    /* Rand der Ronde mit der Sickenmaschine geformt, ueber den Ring gelegt und punktgeschweisst (Fable Runde 17) */
    umfangsNaht([-4, 0, 0], EX, r + 2.4, pid, { bw: 12, b: SB });
    kreisring([2, 0, 0], EX, r - 3, r + 4, 'm', pid, { b: 260, f0: 1 });
  });
  bereich(0, function () { scheibe([-2, 0, 0], EX, r - 3, 'm', pid, { nk: 40, b: 250 }); });
  bereich(3, function () { sicke([-L + 45, 0, 0], EX, r, pid, 10, SB); lippe([-L, 0, 0], NX, r, pid, { b: SB }); });
  mass('d', 'Nenndurchmesser', 'dm', [2, 0, 0], EX, r, EZ);
} };
/* Nippel: eigene Zeichnung fuer die Anlage (nippel, Bereiche 0 Rohrstueck, 1 Laengsnaht, 2 Sicke, 3 Dichtung) und Bauform 2 von lippe
   (52_varianten.js, Bereiche wie lippe: 0 Rohrende mit Bord, 1 Stoppsicke, 2 Dichtungssitz, 3 Lippendichtung, 4 Rohrstueck, 5 Laengsnaht).
   Am: Bereiche rohr, naht, sicke, dicht, dazu fuer lippe ende und sitz (Rohrende und Dichtungssitz unter der Dichtung) */
function nippelSym(pid, Am) {
  var r = 125, L = 120, fein = Am.sitz !== undefined, xe = fein ? L - 16 : L;
  bereich(Am.rohr, function () { rohr([-xe, 0, 0], [xe, 0, 0], r, pid, { innen: false, ch: CHR, rim0: !fein, rim1: !fein }); });
  if (fein) {
    each([1, -1], function (sg) {
      bereich(Am.sitz, function () { rohr([sg * (L - 16), 0, 0], [sg * (L - 5), 0, 0], r - 3, pid, { innen: false, ch: 12, rim0: false, rim1: false }); });
      bereich(Am.ende, function () { rohr([sg * (L - 5), 0, 0], [sg * L, 0, 0], r, pid, { innen: false, ch: 6, rim0: sg === -1, rim1: sg === 1 }); });
    });
  }
  oeffnungR([L, 0, 0], EX, r, pid);
  /* Runde 18 (Dimi 11.11.2026): Laengsnaht punktgeschweisst (Rollnaht nur beim Rundrohr mit Laengsnaht) */
  bereich(Am.naht, function () { punktNaht([-xe + 8, 0, 0], [-14, 0, 0], r, pid, { b: SB, ab: 32 }); punktNaht([14, 0, 0], [xe - (fein ? 8 : 20), 0, 0], r, pid, { b: SB, ab: 32 }); });
  bereich(Am.sicke, function () { sicke([0, 0, 0], EX, r, pid, 16, SB); });
  verdeckt(fein ? [Am.sitz, Am.ende] : [], function () {
    bereich(Am.dicht, function () { lippe([L, 0, 0], EX, r, pid, { b: SB }); lippe([-L, 0, 0], NX, r, pid, { b: SB }); });
  });
  mass('d', 'Nenndurchmesser', 'dm', [L, 0, 0], EX, r, EZ);
  mass('l', 'Länge', 'lin', [-L, r, 0], [L, r, 0], [0, 110, 0]);
}
SYM.nippel = { hw: 'Abgebildet: Nippel, er verbindet zwei Rohre. Die Muffe verbindet zwei Formstücke.', f: function () {
  nippelSym('nippel', { rohr: 0, naht: 1, sicke: 2, dicht: 3 });
} };
/* Muffe (Bauform 3 von lippe): glattes Rohrstueck, etwas weiter als das Formstueck, das eingesteckt wird; in der Mitte eine
   Sicke nach innen als Anschlag (von aussen eine Rille). Ohne Dichtung: es dichten die Lippendichtungen der Formstuecke.
   Bereiche wie lippe: 1 Stoppsicke, 4 Rohrstueck, 5 Laengsnaht */
function muffeSym(pid) {
  var r = 127, L = 100, g = 8;
  bereich(4, function () {
    rohr([-L, 0, 0], [-g, 0, 0], r, pid, { innen: false, ch: CHR, rim1: false });
    rohr([g, 0, 0], [L, 0, 0], r, pid, { innen: false, ch: CHR, rim0: false });
  });
  bereich(1, function () {
    rohr([-g, 0, 0], [g, 0, 0], r - 4, pid, { innen: false, ch: 8, rim0: false, rim1: false });
    kreisring([-g, 0, 0], EX, r - 4, r, 'm', pid, { b: 2 });
    ring([-g, 0, 0], EX, r, pid, { w: 0.9, b: SB }); ring([g, 0, 0], EX, r, pid, { w: 0.9, b: SB });
  });
  oeffnungR([L, 0, 0], EX, r, pid);
  bereich(5, function () { punktNaht([-L + 8, 0, 0], [-g - 8, 0, 0], r, pid, { b: SB, ab: 30 }); punktNaht([g + 8, 0, 0], [L - 8, 0, 0], r, pid, { b: SB, ab: 30 }); });
  mass('d', 'Nenndurchmesser', 'dm', [L, 0, 0], EX, r, EZ);
  mass('l', 'Länge', 'lin', [-L, r, 0], [L, r, 0], [0, 110, 0]);
}
SYM.lippe = { vn: ['Steckverbindung mit Lippendichtung', 'Nippel', 'Muffe'], hw: 'Im Wechsel: Steckende mit Lippendichtung in der Nahansicht (der Dichtungssitz liegt unter der Dichtung), Nippel (verbindet zwei Rohre, Dichtung an beiden Enden, Sicke in der Mitte als Anschlag) und Muffe (verbindet zwei Formstücke, ohne Dichtung).', f: function () {
  var pid = 'lippe', r = 100, L = 170, g0 = L - 36, g1 = L - 12, s0 = L - 86, s1 = L - 72;
  mass('d', 'Nenndurchmesser', 'dm', [L, 0, 0], EX, r, EZ);
  /* Runde 13 der Szene (Dimi 10.11.2026): Grundkoerper dazu, Rohrstueck (4) mit Laengsnaht (5); Rohrende mit Bord ab der Sicke */
  var x4 = s0 - 26;
  bereich(4, function () { rohr([0, 0, 0], [x4, 0, 0], r, pid, { innen: false, rim1: false, ch: CHR }); });
  bereich(0, function () {
    rohr([x4, 0, 0], [s0, 0, 0], r, pid, { innen: false, rim0: false, rim1: false, ch: 13 });
    rohr([s1, 0, 0], [g0, 0, 0], r, pid, { innen: false, rim0: false, rim1: false, ch: 12 });
    rohr([g1, 0, 0], [L, 0, 0], r, pid, { innen: false, rim0: false, ch: 12 });
  });
  bereich(5, function () { punktNaht([6, 0, 0], [x4 - 4, 0, 0], r, pid, { b: SB, ab: 26 }); });
  oeffnungR([L, 0, 0], EX, r, pid);
  bereich(1, function () {
    rohr([s0, 0, 0], [s1, 0, 0], r + 5, pid, { innen: false, ch: 14, b: 6 });
    kreisring([s1, 0, 0], EX, r, r + 5, 'm', pid, { b: 7 });
  });
  bereich(2, function () {
    rohr([g0, 0, 0], [g1, 0, 0], r - 4, pid, { innen: false, ch: 12 });
    kreisring([g0, 0, 0], EX, r - 4, r, 'm', pid, { b: 2 });
  });
  verdeckt([2], function () {
    bereich(3, function () {
      rohr([g0 + 1, 0, 0], [g1 - 1, 0, 0], r + 2, pid, { m: 'g', innen: false, ch: 22, b: 9, ew: 0.6 });
      each([[g0 + 3, g0 + 9], [g1 - 9, g1 - 3]], function (q) {
        rohr([q[0], 0, 0], [q[1], 0, 0], r + 8, pid, { m: 'g', innen: false, ch: 6, b: 12, ew: 0.6 });
        kreisring([q[1], 0, 0], EX, r + 2, r + 8, 'g', pid, { b: 13 });
      });
    });
  });
} };
SYM.flex = { hw: 'Beispiel: flexibles Aluminiumrohr, am Ende eine eingesteckte Muffe mit Schelle.', f: function () {
  var pid = 'flex', r = 100, p3 = [150, 260, 0];
  var C = bezier([-420, -160, 0], [-120, -160, 0], [150, -60, 0], p3, 18);
  bereich(0, function () { flexR(C, r, pid, { rb: SB }); });
  bereich(1, function () {
    rohr(sb(p3, [0, 4, 0]), ad(p3, [0, 62, 0]), r - 2, pid, { innen: false, ch: CHR, b: SB });
    sicke(ad(p3, [0, 34, 0]), EY, r - 2, pid, 9, SB);
  });
  oeffnungR(ad(p3, [0, 62, 0]), EY, r - 2, pid);
  bereich(null, function () { ring(sb(p3, [0, 22, 0]), EY, r + 3, pid, { w: 3.2, s: '#56606C', b: SB }); });
  mass('d', 'Nenndurchmesser', 'dm', ad(p3, [0, 62, 0]), EY, r - 2, EX);
} };
/* Kulissenschalldaempfer (Runde 11, Punkt 13, nach Herstellerunterlagen): Gehaeuse wie ein Rechteckkanal; im Wechsel die Abdeckung:
   wechselseitige Kammerbleche, Lochblech, ohne (nur Glasseide). Masse: a Breite, b Hoehe, l Laenge, s Kulissendicke */
var KUL_A = { geh: 0, krahmen: 1, profil: 1, tbuegel: 1, wolle: 1, seide: 1, abdeck: 1, innen: null };
function kulisseSym(abd) {
  kulisse(0, 1300, 0, 800, 0, 500, 2, 200, true, false, { A: KUL_A, FX: { geh: [1] }, abd: abd, pidK: 'kulisse' });
  mass('a', 'Breite', 'lin', [1330, 0, 500], [1330, 800, 500], [0, 0, 110]);
  mass('b', 'Höhe', 'lin', [1330, 800, 0], [1330, 800, 500], [0, 120, 0]);
  mass('l', 'Länge', 'lin', [0, 800, 0], [1300, 800, 0], [0, 0, -120]);
  mass('s', 'Kulissendicke', 'lin', [1300 - 120, 500, 496], [1300 - 120, 700, 496], [0, 0, 80]);
}
SYM.kulisse = { vn: ['Kulissen mit Kammerblechen', 'Kulissen mit Lochblech', 'Kulissen ohne Abdeckung'], hw: 'Im Wechsel: Schalldämpferkulissen mit wechselseitigen Kammerblechen (je Seite eine Hälfte), mit Lochblech und ohne Abdeckung (nur Glasseide). Das Gehäuse ist ein Rechteckkanal; Kulissen üblich 100 bis 300 mm dick.', f: function () {
  kulisseSym('kammer');
}, v: [{ f: function () { kulisseSym('loch'); } }, { f: function () { kulisseSym('ohne'); } }] };

/* Symbol berechnen (einmal je Bauteil); Wechselbilder (SYM[pid].v) siehe 52_varianten.js */
function symbolBauen(pid) {
  if (SYMC[pid] !== undefined) { return SYMC[pid]; }
  var S = SYM[pid];
  if (!S) { SYMC[pid] = null; return null; }
  SYMC[pid] = symbolRechnen(pid, S);
  return SYMC[pid];
}
function symbolRechnen(pid, S) {
  IT = []; SEQ = 0; FLOWS = []; MARKEN = []; ZONEN = []; AREA = null; FXL = null; INNENT = false; PIDNOW = pid;
  INS = true;
  try { S.f(); } finally { INS = false; }
  each(IT, function (o) { if (o.inn) { o.d = o.d - 1e6; } });
  var it = IT.slice().sort(function (a, b) { return (a.d - b.d) || (a.q - b.q); });
  IT = [];
  var x0 = 1e9, y0 = 1e9, x1 = -1e9, y1 = -1e9, used = {};
  each(it, function (o) {
    each(o.p, function (p) { x0 = Math.min(x0, p[0]); y0 = Math.min(y0, p[1]); x1 = Math.max(x1, p[0]); y1 = Math.max(y1, p[1]); });
    if (o.a !== undefined) { used[o.a] = 1; }
  });
  var m = Math.max(x1 - x0, y1 - y0) * 0.05 + 4;
  return { it: it, vb: [x0 - m, y0 - m, x1 - x0 + 2 * m, y1 - y0 + 2 * m], used: used, hw: S.hw || '' };
}

/* Bauteil „Schalldaempferkulisse“: liegend, Bauteile einzeln (Explosion) bzw. zusammengebaut.
   Bereiche: 0 Kulissenrahmen, 1 An- und Abstroemprofil, 2 T-Buegelprofil, 3 Mineralwolle, 4 Glasseide, 5 Abdeckung,
   6 Rundung bzw. Kante des Rahmenprofils (Runde 18, Dimi 11.11.2026: angehaengt, die Nummern 0 bis 5 bleiben) */
var SKUL_A = { krahmen: 0, profil: 1, tbuegel: 2, wolle: 3, seide: 4, abdeck: 5, rund: 6 };
function skulisseSym(ex, abd, hand) {
  var L = 1000, H = 600, T = 200;
  /* zusammengebaut: beim Zeigen innenliegender Teile werden die Lagen darueber ausgeblendet */
  var FX = ex ? { rund: [0, 1] } : { abdeck: [2, 3, 4], seide: [2, 3], rund: [0, 1] };
  kulisseEinzeln([0, 0, 0], L, H, T, 'skulisse', { ex: ex, abd: abd, hand: hand, A: SKUL_A, FX: FX });
  if (ex) { return; }
  mass('l', 'Länge', 'lin', [-KUL_D, H, 0], [L + KUL_D, H, 0], [0, 150, 0]);
  mass('h', 'Höhe', 'lin', [L + KUL_D, 0, 0], [L + KUL_D, H, 0], [150, 0, 0]);
  mass('s', 'Dicke', 'lin', [L + KUL_D, H, 0], [L + KUL_D, H, T], [0, 120, 0]);
}
/* Runde 13 der Szene (Dimi 10.11.2026): zuerst zusammengebaut (Kammerblech wechselseitig je eine Haelfte, daneben Glasseide, auf der
   Gegenseite versetzt; T-Buegelprofil in der Mitte sichtbar), dann die Bauteile einzeln, mit Lochblech und von Hand gefertigt.
   Das Elementbild der Tabelle zeigt die fertige Kulisse (erste Bauform). */
SYM.skulisse = { hw: 'Im Wechsel: Kulisse zusammengebaut (Kammerblech wechselseitig je eine Hälfte, daneben Glasseide; T-Bügelprofil in der Mitte), Bauteile einzeln (Kulissenrahmen, An- und Abströmprofil mit Radius, T-Bügelprofil, Mineralwolle, Glasseide, Kammerblech), mit Lochblech und von Hand gefertigt: Profil 90° gekantet ohne Radius, nur Glasseide. Dicke üblich 100 bis 300 mm.', f: function () {
  skulisseSym(0, 'kammer', false);
}, v: [{ f: function () { skulisseSym(200, 'kammer', false); } }, { f: function () { skulisseSym(0, 'loch', false); } }, { f: function () { skulisseSym(0, 'ohne', true); } }] };

/* Runde 19 (Dimi 11.11.2026, 22:43): Montage der Kulisse in Schritten, mit demselben Modell wie das Bauteilbild (kulisseEinzeln).
   Rahmen aus 2 x L (ueblich): Haelfte A = Langseite hinten und Profil links, Haelfte B = Langseite vorn und Profil rechts.
   s 0: Haelfte A liegt; 1: Kammerbleche und T-Buegelprofil eingesetzt; 2: Daemmung (Mineralwolle mit Glasseide) in der Haelfte;
   3: Haelfte B wird aufgeschoben (Pfeil); 4: Rahmen geschlossen; 5: T-Buegelprofil mittig an den Rahmen genietet;
   6: Rahmenteile an den Laschen und jede Ecke genietet (fertig). Neue Teile tragen die Klasse „neu“, Niete die Klasse „niet“.
   o.rund: Rundung des Rahmenprofils als eigener Bereich (fuer das Bild des Rahmenteils im Ablauf der Kulissenmaschine) */
function skulisseMontage(s, o) {
  o = o || {};
  var L = 1000, H = 600, T = 200, E = 300, pid = 'skulisse';
  var nur = { rahmenH: 1, endeL: 1 }, ver = {}, neu = {};
  if (gt(s, 0)) { nur.abdO = 1; nur.abdU = 1; nur.tbuegel = 1; }
  if (gt(s, 1)) { nur.wolle = 1; nur.seideO = 1; nur.seideU = 1; }
  if (gt(s, 2)) { nur.rahmenV = 1; nur.endeR = 1; }
  if (s === 1) { neu.abdO = 'neu'; neu.abdU = 'neu'; neu.tbuegel = 'neu'; }
  if (s === 2) { neu.wolle = 'neu'; neu.seideO = 'neu'; neu.seideU = 'neu'; }
  if (s === 3) { ver.rahmenV = [0, E, 0]; ver.endeR = [0, E, 0]; neu.rahmenV = 'neu'; neu.endeR = 'neu'; }
  var A = { krahmen: 0, profil: 1, tbuegel: 2, wolle: 3, seide: 4, abdeck: 5 };
  if (o.rund) { A.rund = 6; }
  kulisseEinzeln([0, 0, 0], L, H, T, pid, { abd: 'kammer', A: A, nur: nur, ver: ver, clsT: neu, offen: lt(s, 4), ch: 2000, nL: 1 });
  if (s === 3) {
    /* Pfeil: Haelfte B wird von vorn aufgeschoben */
    var ya = H + E + 170, yb = H + E + 40, xa = L * 0.42, za = T + 4;
    line([[xa, ya + 60, za], [xa, yb + 60, za]], pid, { w: 2, b: 900 });
    face([[xa, yb, za], [xa - 46, yb + 80, za], [xa + 46, yb + 80, za]], 'm', pid, { c: NAVY, b: 900, two: 1 });
  }
  /* Niete: kleine Scheiben auf der Flaeche (O Mitte, U und W in der Flaeche) */
  function niet(O, U, W, cls) {
    var q = [], i, r = 17;
    for (i = 0; i !== 10; i++) { var a = 2 * Math.PI * i / 10; q.push(ad(O, ad(mu(U, r * Math.cos(a)), mu(W, r * Math.sin(a))))); }
    face(q, 'm', pid, { c: '#F7BC0C', s: NAVY, w: 0.7, b: 900, two: 1, cls: cls });
  }
  if (gt(s, 4)) {
    /* T-Buegelprofil mittig an den Rahmen genietet: je ein Niet an beiden Langseiten */
    each([18, H - 18], function (y) { niet([L / 2, y, T + 2.5], [1, 0, 0], [0, 1, 0], s === 5 ? 'niet neu' : 'niet'); });
  }
  if (gt(s, 5)) {
    /* jede Ecke genietet (die Ecken sind so ausgeklinkt, dass sie fast nicht ueberlappen; nur eine kleine Lasche ueberlappt fuer den Niet,
       Dimi 12.11.2026, 07:03), Rahmenteile an den Laschen genietet (zwei Stoesse bei 2 x L) */
    each([[14, 16], [L - 14, 16], [14, H - 16], [L - 14, H - 16]], function (c) { niet([c[0], c[1], T + 2.5], [1, 0, 0], [0, 1, 0], 'niet neu'); });
    each([0.3, 0.7], function (v) {
      niet([70, H + 2.5, T * v], [1, 0, 0], [0, 0, 1], 'niet neu');
      niet([L + KUL_D + 2.5, 70, T * v], [0, 1, 0], [0, 0, 1], 'niet neu');
    });
  }
}

/* Runde 20 (Dimi 12.11.2026, 01:10): Bauformen des Kulissenrahmens, mit demselben Modell wie das Bauteilbild (kulisseEinzeln).
   bf 0: aus einem Blech gekanteter Rahmen (ein Stoss, gelb markiert); 1: 2 x L (meist): Haelfte A = Langseite hinten und Profil links,
   Haelfte B = Langseite vorn und Profil rechts; 2: 1 x U und 1 x I; 3: 4 x I. Die Teile einer Bauform liegen an ihren Stoessen
   auseinander (Abstand o.E). Das U bilden die Langseite hinten und beide Profile, das I ist die Langseite vorn; beim gekanteten
   Rahmen liegt der Stoss an einer Ecke (beides bestaetigt, Dimi 12.11.2026, 07:03). o.rund: Rundung des Rahmenprofils als eigener
   Bereich */
function skulisseRahmen(bf, o) {
  o = o || {};
  var L = 1000, H = 600, T = 200, E = o.E || 170, pid = 'skulisse', ver = {};
  if (bf === 1) { ver.rahmenV = [0, E, 0]; ver.endeR = [0, E, 0]; }
  if (bf === 2) { ver.rahmenV = [0, E, 0]; }
  if (bf === 3) { ver.rahmenV = [0, E, 0]; ver.rahmenH = [0, -E, 0]; ver.endeL = [-E, 0, 0]; ver.endeR = [E, 0, 0]; }
  var A = { krahmen: 0, profil: 1, tbuegel: 2, wolle: 3, seide: 4, abdeck: 5 };
  if (o.rund) { A.rund = 6; }
  kulisseEinzeln([0, 0, 0], L, H, T, pid, { abd: 'kammer', A: A, nur: { rahmenH: 1, rahmenV: 1, endeL: 1, endeR: 1 }, ver: ver, offen: 1, ch: 2000, nL: 1 });
  if (bf === 0) {
    /* der eine Stoss des gekanteten Rahmens: an der Ecke vorn links, ueber Vorderseite und Flansch */
    line([[0, H + 2.5, 6], [0, H + 2.5, T - 6]], pid, { s: '#F7BC0C', w: 3, b: 900, cls: 'stoss' });
    line([[0, H - KUL_FL, T + 2.5], [0, H, T + 2.5]], pid, { s: '#F7BC0C', w: 3, b: 900, cls: 'stoss' });
  }
}

/* ---------- Wechselbilder und neue Formstuecke (Dimi 09.11.2026) ----------
   Ein Bauteil kann mehrere Bauformen zeigen, die im Bauteilbild wechseln (SYM[pid].v, Liste weiterer Zeichnungen).
   Familien (Runde 6): Etagenstueck gekantet und Uebergang eckig einseitig und symmetrisch; Rechteckbogen und Etagenstueck
   mit Radien; Rechteckwinkel und T-Stueck eckig; Segmentbogen 90, 45 Grad und Etagenbogen; T-Stueck 90 Grad, Abzweig 45 Grad,
   Kreuzstueck und T-Stueck mit kleinerem Abgang; Reduzierung zentrisch und exzentrisch; Sattelstutzen 90 und 45 Grad;
   gepresster Bogen 90 und 45 Grad. Die Bereiche sind in allen Bauformen eines Bauteils gleich nummeriert.
   Die Szene zeigt immer die erste Bauform.
   Kartei (Inline-SVG): Wechsel per CSS (CSSV); ist ein Bereich hervorgehoben, steht die erste Bauform mit diesem Bereich.
   Kacheln und Chips (SVG als Bild): Wechsel ueber einen eigenen Stilblock im SVG. Ohne Bewegung: nur die erste Bauform. */

/* Etagenstueck mit Radien (S-Form): wie etageR, statt der Knicke zwei gegenlaeufige Boegen mit gleichem Radius.
   Anfang p0, Richtung A, Laenge L, Versatz off in Richtung Od, Querschnitt w (entlang Od) mal h, gerade Enden l0.
   Symbol: o.A Bereiche seite, mantel, falz, rahmen; o.falzB Falzband auf den Seitenblechen; o.innenFl Innenflaechen */
function etageS(p0, A, L, Od, off, w, h, l0, m, pid, o) {
  o = o || {};
  var Bn = nz(cr(A, Od)), D = L - 2 * l0, ph = 2 * Math.atan(off / D), R = D / (2 * Math.sin(ph)), i, j, nh = 3;
  function P3(s, y, z) { return ad(ad(ad(p0, mu(A, s)), mu(Od, y)), mu(Bn, z)); }
  /* Mittellinie: Punkte (s, y) mit Normale (ns, ny) in der Versatzebene, nach +y gedreht */
  var M = [];
  function pkt(s, y, ts, ty) { M.push({ s: s, y: y, ns: -ty, ny: ts }); }
  var nG = Math.max(1, Math.ceil(l0 / 120)), nB = 9;
  for (i = 0; i !== nG; i++) { pkt(l0 * i / nG, 0, 1, 0); }
  for (i = 0; i !== nB; i++) { var t = ph * i / nB; pkt(l0 + R * Math.sin(t), R - R * Math.cos(t), Math.cos(t), Math.sin(t)); }
  for (i = 0; i !== nB; i++) { var t2 = ph * (1 - i / nB); pkt(L - l0 - R * Math.sin(t2), off - R + R * Math.cos(t2), Math.cos(t2), Math.sin(t2)); }
  for (i = 0; i !== nG + 1; i++) { pkt(L - l0 + l0 * i / nG, off, 1, 0); }
  var n = M.length - 1;
  function W(k, q, z) { var c = M[k]; return P3(c.s + c.ns * q, c.y + c.ny * q, z); }
  function N3(k, sg) { var c = M[k]; return ad(mu(A, c.ns * sg), mu(Od, c.ny * sg)); }
  function seite(sg) { var G = []; for (var k = 0; k !== n + 1; k++) { G.push([W(k, -w / 2, sg * h / 2), W(k, w / 2, sg * h / 2)]); } return G; }
  function wand(q, sg, inn) {
    var G = [], NG = [];
    for (var k = 0; k !== n + 1; k++) {
      var row = [], nr = [], nn = N3(k, inn ? -sg : sg);
      for (j = 0; j !== nh + 1; j++) { row.push(W(k, q, -h / 2 + h * j / nh)); nr.push(nn); }
      G.push(row); NG.push(nr);
    }
    return { G: G, NG: NG };
  }
  var po = { cls: o.cls, b: o.b }, wa = {};
  mitAF(o, 'seite', function () {
    each([1, -1], function (sg) { wa[sg] = patch(seite(sg), m, pid, ext(po, { out: mu(Bn, sg), e0: 1, e1: 1, f0: 1, f1: 1 })); });
  });
  var MR = [];
  mitAF(o, 'mantel', function () {
    each([[w / 2, 1], [-w / 2, -1]], function (qq) { var x = wand(qq[0], qq[1], false); MR.push([patch(x.G, m, pid, ext(po, { NG: x.NG, e0: 1, e1: 1, f0: 1, f1: 1 })), qq[0], qq[1]]); });
  });
  var pe = P3(L, off, 0);
  mitAF(o, 'innen', function () { innenRechteck(p0, mu(A, -1), Od, w, Bn, h, pid, o); innenRechteck(pe, A, Od, w, Bn, h, pid, o); });
  mitAF(o, 'rahmen', function () {
    if (o.fr0 !== false) { profil(p0, A, Od, w, Bn, h, pid, o); }
    if (o.fr1 !== false) { profil(pe, mu(A, -1), Od, w, Bn, h, pid, o); }
  });
  /* Falzband entlang beider Mantelkanten auf den Seitenblechen (Bord der Seitenbleche, Tasche am Mantel) */
  if (o.falzB) {
    mitAF(o, 'falz', function () {
      var fb = o.falzB;
      /* Tasche (Pittsburghfalz) auf den Mantelblechen (Fable Runde 17, siehe taschenRand in 20_teile.js) */
      if (o.falzT) {
        each(MR, function (mr) {
          taschenRand(mr[0], n, function (k, q) { return W(k, mr[1] + mr[2] * 0.6, -h / 2 + q); }, function (k) { return N3(k, mr[2]); }, h, o.falzT, m, pid, o);
        });
      }
      each([1, -1], function (sg) {
        if (!wa[sg]) { return; }
        var z = sg * (h / 2 + 0.5);
        for (i = 0; i !== n; i++) {
          var q = wa[sg].Q[i][0]; if (!q.it) { continue; }
          each([[w / 2 - fb, w / 2], [-w / 2, -w / 2 + fb]], function (bb) {
            face([W(i, bb[0], z), W(i, bb[1], z), W(i + 1, bb[1], z), W(i + 1, bb[0], z)], m, pid, { n: mu(Bn, sg), d: q.it.d + 0.35, c: '#D1DAE4' });
          });
          line([W(i, w / 2 - fb, z), W(i + 1, w / 2 - fb, z)], pid, { d: q.it.d + 0.45, w: 0.75, s: '#5E7189' });
          line([W(i, -w / 2 + fb, z), W(i + 1, -w / 2 + fb, z)], pid, { d: q.it.d + 0.45, w: 0.75, s: '#5E7189' });
        }
      });
    });
  }
  if (o.innenFl) {
    innenTeil(function () {
      each([1, -1], function (sg) { patch(seite(sg), 'i', pid, { out: mu(Bn, -sg), noedge: 1 }); });
      each([[w / 2, 1], [-w / 2, -1]], function (qq) { var x = wand(qq[0], qq[1], true); patch(x.G, 'i', pid, { NG: x.NG, noedge: 1 }); });
    });
  }
  return { pe: pe, Bn: Bn, R: R };
}

/* T-Stueck eckig: Hauptkanal p0 bis p0 + A*L, Querschnitt a (entlang Tn) mal h; Abgang in Richtung Tn aus der Mitte,
   Breite b (entlang A), Laenge lb ab der Kanalwand. Seitenbleche T-foermig, Mantel an den Innenecken gekantet,
   drei Querverbinder. Symbol: o.A Bereiche seite, mantel, falz, rahmen; o.falzB Falzband; o.innenFl Innenflaechen */
function tStueckR(p0, A, L, Tn, a, h, b, lb, m, pid, o) {
  o = o || {};
  var Bn = nz(cr(A, Tn)), sm = L / 2;
  function P3(s, y, z) { return ad(ad(ad(p0, mu(A, s)), mu(Tn, y)), mu(Bn, z)); }
  var poly = [[0, -a / 2], [L, -a / 2], [L, a / 2], [sm + b / 2, a / 2], [sm + b / 2, a / 2 + lb], [sm - b / 2, a / 2 + lb], [sm - b / 2, a / 2], [0, a / 2]];
  var WAND = [[0, 1], [2, 3], [3, 4], [5, 6], [6, 7]], wg = {};
  function rand(k) { var pa = poly[WAND[k][0]], pb = poly[WAND[k][1]], dx = pb[0] - pa[0], dy = pb[1] - pa[1], l = Math.sqrt(dx * dx + dy * dy); return { a: pa, b: pb, ox: dy / l, oy: -dx / l }; }
  mitAF(o, 'seite', function () {
    each([1, -1], function (sg) {
      var p3 = poly.map(function (q) { return P3(q[0], q[1], sg * h / 2); });
      var it = face(p3, m, pid, { n: mu(Bn, sg), cls: o.cls });
      wg[sg] = it;
      if (it) { line(p3.concat([p3[0]]), pid, { d: it.d + 0.5, cls: o.cls }); }
    });
  });
  var MR = [];
  function mantel(mm, noedge) {
    each(WAND, function (wd, k) {
      var r = rand(k), O = P3(r.a[0], r.a[1], -h / 2), U = sb(P3(r.b[0], r.b[1], -h / 2), O), out = ad(mu(A, r.ox), mu(Tn, r.oy));
      var pr = plane(O, U, mu(Bn, h), mm, pid, { out: mm === 'i' ? mu(out, -1) : out, ch: 250, cls: o.cls, noedge: noedge });
      if (mm !== 'i') { MR.push(pr); }
    });
  }
  mitAF(o, 'mantel', function () { mantel(m, 0); });
  var E = [{ c: P3(0, 0, 0), n: mu(A, -1), W: Tn, w: a }, { c: P3(L, 0, 0), n: A, W: Tn, w: a }, { c: P3(sm, a / 2 + lb, 0), n: Tn, W: A, w: b }];
  mitAF(o, 'innen', function () { each(E, function (e) { innenRechteck(e.c, e.n, e.W, e.w, Bn, h, pid, o); }); });
  mitAF(o, 'rahmen', function () { each(E, function (e) { profil(e.c, mu(e.n, -1), e.W, e.w, Bn, h, pid, o); }); });
  if (o.falzB) {
    mitAF(o, 'falz', function () {
      var fb = o.falzB;
      if (o.falzT) { each(MR, function (pr) { taschenRandE(pr, o.falzT, pid, o); }); }
      each([1, -1], function (sg) {
        var it = wg[sg]; if (!it) { return; }
        var z = sg * (h / 2 + 0.5);
        each(WAND, function (wd, k) {
          var r = rand(k), ix = -r.ox * fb, iy = -r.oy * fb;
          var q = [P3(r.a[0], r.a[1], z), P3(r.b[0], r.b[1], z), P3(r.b[0] + ix, r.b[1] + iy, z), P3(r.a[0] + ix, r.a[1] + iy, z)];
          face(q, m, pid, { n: mu(Bn, sg), d: it.d + 0.35, c: '#D1DAE4' });
          line([q[3], q[2]], pid, { d: it.d + 0.45, w: 0.75, s: '#5E7189' });
        });
      });
    });
  }
  /* Leitbleche (Dimi 09.11.2026: auch das T-Stueck eckig kann Leitbleche haben): Schaufeln auf der Diagonale der
     Abzweigecke, Stroemung aus dem Hauptkanal in den Abgang; aussen Schiene und Befestigungspunkte auf den Seitenblechen */
  if (o.leit) {
    var Pi = [sm - b / 2, a / 2], Po = [sm + b / 2, a / 2 - Math.min(b, a)], diag = Math.sqrt(Math.pow(Po[0] - Pi[0], 2) + Math.pow(Po[1] - Pi[1], 2));
    var NL = Math.max(3, Math.round(diag / 115)), rr = (diag / NL) * 0.95;
    mitAF(o, 'leitL', function () {
      each([1, -1], function (sg) {
        var it = wg[sg]; if (!it) { return; }
        line([P3(Pi[0], Pi[1], sg * h / 2), P3(Po[0], Po[1], sg * h / 2)], pid, { d: it.d + 0.6, w: 0.8, s: '#5E7189', cls: o.cls });
      });
    });
    mitA(o, 'leit', function () {
      innenTeil(function () {
        for (var k = 0; k !== NL; k++) {
          var t = (k + 0.5) / NL, sk = Pi[0] + (Po[0] - Pi[0]) * t, tk = Pi[1] + (Po[1] - Pi[1]) * t;
          var cs = sk - rr / Math.SQRT2, ct = tk + rr / Math.SQRT2, G = [];
          for (var i = 0; i !== 7; i++) {
            var f = Math.PI / 2 * i / 6, ps = cs + rr * Math.sin(f), pt = ct - rr * Math.cos(f);
            G.push([P3(ps, pt, -h / 2 + 3), P3(ps, pt, 0), P3(ps, pt, h / 2 - 3)]);
          }
          patch(G, 'r', pid, { two: 1, e0: 1, e1: 1, f0: 1, f1: 1, ew: 0.75 });
          /* Wulst an der Anstroemkante jeder Schaufel (Runde 19, LEIT_WULST in 20_teile.js) */
          rohr(P3(cs, ct - rr, -h / 2 + 3), P3(cs, ct - rr, h / 2 - 3), LEIT_WULST, pid, { m: 'r', nr: 8, ch: 400 });
        }
      });
      each([1, -1], function (sg) {
        var it = wg[sg]; if (!it) { return; }
        for (var k = 0; k !== NL; k++) {
          var t = (k + 0.5) / NL, sk = Pi[0] + (Po[0] - Pi[0]) * t, tk = Pi[1] + (Po[1] - Pi[1]) * t;
          scheibe(P3(sk, tk, sg * (h / 2 + 1)), mu(Bn, sg), 9, 'd', pid, { d: it.d + 0.7, c: '#4B5666', k: 1 });
        }
      });
    });
  }
  if (o.innenFl) {
    innenTeil(function () {
      each([1, -1], function (sg) { face(poly.map(function (q) { return P3(q[0], q[1], sg * h / 2); }), 'i', pid, { n: mu(Bn, -sg) }); });
      mantel('i', 1);
    });
  }
  return { Bn: Bn, E: E };
}

/* Abzweig rund unter beliebigem Winkel (z. B. 45 Grad): wie tStueck90, die Verschneidung mit dem Grundkoerper wird je
   Umfangswinkel aus dem Abstand zur Achse bestimmt. pm Punkt auf der Achse, Am Achse, R Radius; Ab Achse des Abzweigs
   (nicht parallel zu Am), r Radius, Lb Laenge ab pm entlang Ab. o.A Bereiche abzweig, naht, ende */
function abzweigR(pm, Am, R, Ab, r, Lb, m, pid, o) {
  o = o || {};
  Ab = nz(Ab); Am = nz(Am);
  var e2 = nz(cr(Ab, Am)), e1 = nz(cr(e2, Ab)), nr = 28, G = [], NG = [], i, k;
  var aV = sb(Ab, mu(Am, dt(Ab, Am))), aa = dt(aV, aV);
  function sF(t, rr) {
    var c = ad(mu(e1, rr * Math.cos(t)), mu(e2, rr * Math.sin(t))), bV = sb(c, mu(Am, dt(c, Am)));
    var ab = dt(aV, bV), q = ab * ab - aa * (dt(bV, bV) - R * R);
    return (-ab + Math.sqrt(Math.max(q, 0))) / aa;
  }
  var smax = 0;
  for (i = 0; i !== nr; i++) { smax = Math.max(smax, sF(2 * Math.PI * i / nr, r)); }
  var nL = Math.max(2, Math.ceil((Lb - smax) / 120)) + 2;
  for (k = 0; k !== nL + 1; k++) {
    var row = [], nrow = [], tt = k / nL;
    for (i = 0; i !== nr; i++) {
      var t = 2 * Math.PI * i / nr, v = ad(mu(e1, Math.cos(t)), mu(e2, Math.sin(t)));
      row.push(ad(ad(pm, mu(Ab, sF(t, r) * (1 - tt) + Lb * tt)), mu(v, r))); nrow.push(v);
    }
    G.push(row); NG.push(nrow);
  }
  mitAF(o, 'abzweig', function () { patch(G, m, pid, { wrap: 1, NG: NG, e0: 0, e1: 1, cls: o.cls, b: o.bA || 2 }); });
  /* Fuegenaht entlang der Verschneidung: dunkle Linie mit heller Kante, nur auf der sichtbaren Seite (nicht bei gepressten Teilen) */
  if (!o.ohneNaht) mitAF(o, 'naht', function () {
    var n = 72, Pn = [];
    if (o.bord) { fuegeBord(pm, Am, Ab, e1, e2, sF, r, o.bord, pid, o); }
    for (i = 0; i !== n + 1; i++) {
      var t2 = 2 * Math.PI * i / n, v2 = ad(mu(e1, Math.cos(t2)), mu(e2, Math.sin(t2)));
      Pn.push({ p: ad(ad(pm, mu(Ab, sF(t2, r) + 1)), mu(v2, r + 1.5)), v: v2 });
    }
    for (i = 0; i !== n; i++) {
      var sv2 = D3 ? true : gt(dt(ad(Pn[i].v, Pn[i + 1].v), VV), 0.05);
      if (sv2) {
        line([Pn[i].p, Pn[i + 1].p], pid, { w: o.bord ? 1.1 : (o.nw || 2.2), s: '#3E4B5C', b: (o.bN || 4) + (o.bord ? 2 : 0), cls: o.cls });
        if (!o.bord) { line([ad(Pn[i].p, mu(Ab, 4)), ad(Pn[i + 1].p, mu(Ab, 4))], pid, { w: 0.9, s: '#FFFFFF', b: (o.bN || 4) + 0.1, cls: o.cls, op: 0.9 }); }
      }
    }
  });
  var pe = ad(pm, mu(Ab, Lb));
  mitAF(o, 'ende', function () {
    if (o.sickeB) { sicke(ad(pm, mu(Ab, Lb - 45)), Ab, r, pid, 10, o.sickeB); } else { ring(ad(pm, mu(Ab, Lb - 45)), Ab, r, pid, { w: 1, cls: o.cls }); }
    lippe(pe, Ab, r, pid, { cls: o.cls, b: o.lipB });
  });
  return { pe: pe, smax: smax };
}

/* Gepresster Bogen (rund): glatter Bogen ab p0 in Richtung A, dreht nach Tn; Mittelradius R, Rohrradius r, Winkel o.w (90).
   Naht der beiden Halbschalen in der Bogenebene, innen und aussen (Bauform mit Dimi pruefen).
   o.A Bereiche bogen, naht; o.naht false ohne Naht */
function pressBogen(p0, A, Tn, R, r, m, pid, o) {
  o = o || {};
  var Bn = nz(cr(A, Tn)), C = ad(p0, mu(Tn, R)), wg = (o.w || 90) * Math.PI / 180, n = o.n || 16, Cp = [], i;
  function rho(f) { return ad(mu(Tn, -Math.cos(f)), mu(A, Math.sin(f))); }
  for (i = 0; i !== n + 1; i++) { Cp.push(ad(C, mu(rho(wg * i / n), R))); }
  mitAF(o, 'bogen', function () { schlauch(Cp, r, m, pid, { innen: o.innen, rim0: o.rim0, rim1: o.rim1, b: o.b, cls: o.cls }); });
  if (o.naht !== false) {
    mitAF(o, 'naht', function () {
      each([1, -1], function (sg) {
        for (i = 0; i !== n; i++) {
          var f0 = wg * i / n, f1 = wg * (i + 1) / n, nn = mu(ad(rho(f0), rho(f1)), sg);
          if (!D3) { if (!gt(dt(nn, VV), 0.05)) { continue; } }
          var a0 = ad(C, mu(rho(f0), R + sg * (r + 0.8))), a1 = ad(C, mu(rho(f1), R + sg * (r + 0.8)));
          if (o.rand) {
            /* Rand der Halbschalen (Fable Runde 17; wie im Ablauf „Halbschalen schweissen“): die Raender der beiden Schalen liegen
               aneinander und stehen als schmaler Steg aussen und innen am Bogen, darin die Rollnaht */
            var b0 = ad(C, mu(rho(f0), R + sg * (r + o.rand))), b1 = ad(C, mu(rho(f1), R + sg * (r + o.rand)));
            face([a0, a1, b1, b0], m, pid, { n: Bn, two: 1, b: o.bN || 3, c: '#C9D3DF', cls: o.cls });
            line([b0, b1], pid, { w: 1, s: '#3E4B5C', b: (o.bN || 3) + 0.1, cls: o.cls });
            line([a0, a1], pid, { w: 0.8, s: '#5E7189', b: (o.bN || 3) + 0.1, cls: o.cls });
            continue;
          }
          line([a0, a1], pid, { w: o.nw || 2.2, s: '#3E4B5C', b: o.bN || 3, cls: o.cls });
          line([ad(a0, mu(Bn, 3)), ad(a1, mu(Bn, 3))], pid, { w: 0.8, s: '#FFFFFF', b: (o.bN || 3) + 0.1, cls: o.cls, op: 0.9 });
        }
      });
    });
  }
  return { pe: ad(C, mu(rho(wg), R)), te: ad(mu(Tn, Math.sin(wg)), mu(A, Math.cos(wg))), C: C, Bn: Bn };
}

/* Segmentkette (z. B. Etagenbogen aus zwei Boegen): Mittellinie als Streckenzug J, je Strecke ein Segment; die Stossebene
   in jedem inneren Knoten halbiert den Winkel zwischen den Achsen (wie segBogen). Bn Normale der Bogenebene, r Rohrradius.
   o.A Bereiche seg, naht, umf; o.naht Laengsnaht je Segment (versetzt); o.enden ohne Randlinie an den Enden */
function segKette(J, Bn, r, m, pid, o) {
  o = o || {};
  var nS = J.length - 1, AX = [], MJ = [], k, i;
  for (k = 0; k !== nS; k++) { AX.push(nz(sb(J[k + 1], J[k]))); }
  for (k = 0; k !== nS + 1; k++) { MJ.push(k === 0 ? AX[0] : (k === nS ? AX[nS - 1] : nz(ad(AX[k - 1], AX[k])))); }
  function SP(k0, kk, a) {
    var ax = AX[k0], nn = nz(cr(ax, Bn)), v = ad(mu(nn, Math.cos(a)), mu(Bn, Math.sin(a))), q0 = ad(J[k0], mu(v, r));
    return { p: ad(q0, mu(ax, -dt(sb(q0, J[kk]), MJ[kk]) / dt(ax, MJ[kk]))), v: v };
  }
  each(AX, function (ax, k) {
    var G = [], NG = [];
    each([k, k + 1], function (kk) {
      var row = [], nr = [];
      for (i = 0; i !== 28; i++) { var q = SP(k, kk, 2 * Math.PI * i / 28); row.push(q.p); nr.push(q.v); }
      G.push(row); NG.push(nr);
    });
    var e0 = (k === 0 ? (o.enden ? 0 : 1) : 1), e1 = (k === nS - 1 ? (o.enden ? 0 : 1) : 1);
    var res = mitAF(o, 'seg', function () {
      return patch(G, m, pid, { wrap: 1, NG: NG, e0: e0, e1: e1, ew: (k === 0 ? 1 : 1.25), cls: o.cls, eaR: (o.A ? o.A.umf : undefined), ewR: (o.A ? 1.9 : undefined) });
    });
    if (!o.enden) {
      mitAF(o, 'innen', function () {
        if (k === 0) { oeffnung(G[0], mu(ax, -1), pid, o); }
        if (k === nS - 1) { oeffnung(G[1], ax, pid, o); }
      });
    }
    if (o.naht) {
      mitAF(o, 'naht', function () {
        var NW = o.nw || [0.36 * Math.PI, 0.64 * Math.PI], an = NW[k % 2], ia = (Math.round(an / (2 * Math.PI) * 28) % 28 + 28) % 28, q = res.Q[0][ia];
        if (!q.it) { return; }
        var pa = SP(k, k, an).p, pb = SP(k, k + 1, an).p;
        line([lp(pa, pb, 0.06), lp(pa, pb, 0.94)], pid, { d: q.it.d + 0.4, w: 1.1, s: '#5E7189' });
        line([lp(pa, pb, 0.06), lp(pa, pb, 0.94)], pid, { d: q.it.d + 0.45, w: 0.6, s: '#FFFFFF', op: 0.9 });
      });
    }
  });
  /* Stehfalz zwischen den Segmenten als Rippe (o.rippe, siehe falzRippe in 20_teile.js) */
  if (o.rippe) {
    for (k = 1; k !== nS; k++) {
      (function (kk) { mitAF(o, 'umf', function () { falzRippe(function (a) { return SP(kk - 1, kk, a); }, J[kk], MJ[kk], r, o.rippe, pid, o); }); })(k);
    }
  }
  return { pe: J[nS], te: AX[nS - 1] };
}
/* Knoten eines Etagenbogens aus zwei Segmentboegen 45 Grad (je halbes Endsegment 11,25 Grad, ein Segment 22,5 Grad):
   Anfang p0 in Richtung A, Versatz nach Tn; Lm verlaengert das mittlere Segment (groesserer Versatz) */
function etagenBogenKnoten(p0, A, Tn, R, Lm) {
  var Lh = R * Math.tan(11.25 * Math.PI / 180), J = [p0], q = p0;
  function d(g) { var w = g * Math.PI / 180; return ad(mu(A, Math.cos(w)), mu(Tn, Math.sin(w))); }
  each([[0, Lh], [22.5, 2 * Lh], [45, 2 * Lh + Lm], [22.5, 2 * Lh], [0, Lh]], function (s) { q = ad(q, mu(d(s[0]), s[1])); J.push(q); });
  return J;
}

/* Sattelstutzen unter beliebigem Winkel (z. B. 45 Grad): wie sattel (20_teile.js), die Verschneidung mit dem Grundrohr
   allgemein wie abzweigR. pm Punkt auf der Achse, Am Achse, R Radius des Grundrohrs; Ab Achse des Stutzens, r Radius,
   Lb Laenge ab pm. Das Sattelblech folgt der Oberflaeche des Grundrohrs. o.A Bereiche abzweig, rand, ende; o.breit Breite.
   Rueckgabe: pe Ende, x0 und x1 Ausdehnung des Sattelblechs entlang Am (ab pm) */
function sattelW(pm, Am, R, Ab, r, Lb, m, pid, o) {
  o = o || {};
  Ab = nz(Ab); Am = nz(Am);
  var e2 = nz(cr(Ab, Am)), e1 = nz(cr(e2, Ab)), nr = 28, G = [], NG = [], i, k;
  var aV = sb(Ab, mu(Am, dt(Ab, Am))), aa = dt(aV, aV);
  function vv(t) { return ad(mu(e1, Math.cos(t)), mu(e2, Math.sin(t))); }
  function sF(t, rr) {
    var c = mu(vv(t), rr), bV = sb(c, mu(Am, dt(c, Am))), ab = dt(aV, bV), q = ab * ab - aa * (dt(bV, bV) - R * R);
    return (-ab + Math.sqrt(Math.max(q, 0))) / aa;
  }
  function nrm(p) { var d = sb(p, pm); return nz(sb(d, mu(Am, dt(d, Am)))); }
  function auf(t, rr, h) { var p = ad(ad(pm, mu(Ab, sF(t, rr))), mu(vv(t), rr)), n = nrm(p); return { p: ad(p, mu(n, h)), n: n }; }
  var smax = 0;
  for (i = 0; i !== nr; i++) { smax = Math.max(smax, sF(2 * Math.PI * i / nr, r)); }
  var nL = Math.max(2, Math.ceil((Lb - smax) / 120)) + 2;
  for (k = 0; k !== nL + 1; k++) {
    var row = [], nrow = [], tt = k / nL;
    for (i = 0; i !== nr; i++) {
      var t = 2 * Math.PI * i / nr, v = vv(t);
      row.push(ad(ad(pm, mu(Ab, sF(t, r) * (1 - tt) + Lb * tt)), mu(v, r))); nrow.push(v);
    }
    G.push(row); NG.push(nrow);
  }
  mitAF(o, 'abzweig', function () { patch(G, m, pid, { wrap: 1, NG: NG, e0: 1, e1: 1, cls: o.cls, b: o.bA || 2 }); });
  /* Sattelblech: Ring zwischen r und rs, 2 mm ueber dem Grundrohr */
  var rs = r + (o.breit || 38), G3 = [], N3 = [], x0 = 1e9, x1 = -1e9;
  for (i = 0; i !== 49; i++) {
    var t2 = 2 * Math.PI * (i % 48) / 48, a1 = auf(t2, r, 2), a2 = auf(t2, rs, 2), xa = dt(sb(a2.p, pm), Am);
    G3.push([a1.p, a2.p]); N3.push([a1.n, a2.n]); x0 = Math.min(x0, xa); x1 = Math.max(x1, xa);
  }
  mitAF(o, 'rand', function () {
    patch(G3, 'm', pid, { NG: N3, e0: 0, e1: 0, f0: 0, f1: 1, cls: o.cls, b: o.bR || 1.5 });
    /* Fuegepunkte */
    for (i = 0; i !== 8; i++) {
      var c3 = auf(Math.PI / 8 + i * Math.PI / 4, (r + rs) / 2, 3);
      if (!D3) { if (!gt(dt(c3.n, VV), 0.05)) { continue; } }
      var u1 = nz(cr(c3.n, Am)), u2 = nz(cr(c3.n, u1)), q3 = [];
      for (k = 0; k !== 8; k++) { var w3 = 2 * Math.PI * k / 8; q3.push(ad(c3.p, ad(mu(u1, 9 * Math.cos(w3)), mu(u2, 9 * Math.sin(w3))))); }
      face(q3, 'd', pid, { n: c3.n, c: '#4B5666', b: o.bP || 3, cls: o.cls, k: 1 });
    }
  });
  var pe = ad(pm, mu(Ab, Lb));
  mitAF(o, 'ende', function () {
    if (o.sickeB) { sicke(ad(pm, mu(Ab, Lb - 45)), Ab, r, pid, 10, o.sickeB); } else { ring(ad(pm, mu(Ab, Lb - 45)), Ab, r, pid, { w: 1, cls: o.cls }); }
    lippe(pe, Ab, r, pid, { cls: o.cls, b: o.lipB });
  });
  return { pe: pe, x0: x0, x1: x1 };
}

/* ---------- Bauformen im Wechsel ---------- */
/* Etagenstueck und Uebergang (eckig): 0 Seitenbleche, 1 Mantelbleche, 2 Laengsfalz (Pittsburgh), 3 Rahmen.
   Uebergang: die zwei seitlichen Trapezbleche sind Seitenbleche, oben und unten Mantelbleche, Eckfalze = Laengsfalz */
var AUEB = { seite: 0, mantel: 1, falz: 2, rahmen: 3, innen: null };
/* Masse eines Uebergangs (Runde 10 der Szene): Eintritt a x b, Austritt c x d, Laenge l (ew, eh: Versatz des Austritts) */
function masseUeb(ew, eh) {
  mass('a', 'Breite Eintritt', 'lin', [0, -300, 200], [0, 300, 200], [0, 0, 110]);
  mass('b', 'Höhe Eintritt', 'lin', [0, 300, -200], [0, 300, 200], [0, 110, 0]);
  mass('c', 'Breite Austritt', 'lin', [520, ew - 200, eh + 150], [520, ew + 200, eh + 150], [0, 0, 110]);
  mass('d', 'Höhe Austritt', 'lin', [520, ew + 200, eh - 150], [520, ew + 200, eh + 150], [0, 110, 0]);
  mass('l', 'Länge', 'lin', [0, -300, 200], [520, ew - 200, eh + 150], [0, -110, 0], EX);
}
SYM.retage.v = [{ f: function () {
  /* einseitig: die vordere Seite und der Boden laufen gerade durch, oben ist der Versatz zu sehen */
  reduzR([0, 0, 0], EX, 520, EY, 600, 400, EZ, 400, 300, 100, -50, 'm', 'retage', { A: AUEB, falzB: 11, falzT: 17, innenFl: 1 });
  masseUeb(100, -50);
} }, { f: function () {
  reduzR([0, 0, 0], EX, 520, EY, 600, 400, EZ, 400, 300, 0, 0, 'm', 'retage', { A: AUEB, falzB: 11, falzT: 17, innenFl: 1 });
  masseUeb(0, 0);
} }];
/* Rechteckbogen, Etagenstueck mit Radien und Rohrgabelung: 0 Seitenblech, 1 Mantelblech, 2 Laengsfalz, 3 Rahmen, 4 Leitblech (nur Bogen) */
SYM.rbogen.v = [{ f: function () {
  etageS([0, 0, 0], EX, 900, NY, 250, 500, 400, 170, 'm', 'rbogen', { A: { seite: 0, mantel: 1, falz: 2, rahmen: 3, innen: null }, falzB: 11, falzT: 17, innenFl: 1 });
  masseEtage();
} }, { f: function () {
  /* Bauform 3 (Fable Runde 17, Dimi 11.11.2026): Rohrgabelung, Zeichnung wie hose. Bereiche wie rbogen; die Bleche an der Spitze
     gehoeren zum Mantel (1), die Kante, an der sich die beiden Maentel treffen, zum Laengsfalz (2). Ohne Leitblech (4) */
  gabelSym('rbogen', { seite: 0, mantel: 1, falz: 2, spitzeK: 2, rahmen: 3, innen: null });
} }];
SYM.rwinkel.v = [{ f: function () {
  tStueckR([0, 0, 0], EX, 1200, EY, 500, 400, 360, 330, 'm', 'rwinkel', { A: { seite: 0, mantel: 1, falz: 2, rahmen: 3, leit: 4, leitL: 4, innen: null }, falzB: 11, falzT: 17, innenFl: 1, leit: 1 });
  /* Masse (Runde 10 der Szene): Kanal a x b, Abgang c, Laenge l */
  mass('a', 'Breite', 'lin', [1230, -250, 200], [1230, 250, 200], [0, 0, 110]);
  mass('b', 'Höhe', 'lin', [1230, 250, -200], [1230, 250, 200], [0, 110, 0]);
  mass('c', 'Breite Abgang', 'lin', [420, 580, 200], [780, 580, 200], [0, 0, 110]);
  mass('l', 'Länge', 'lin', [0, -250, 200], [1200, -250, 200], [0, -120, 0]);
} }, { f: function () {
  /* Bauform 3 (Fable Runde 17, Dimi 11.11.2026): Hosenstueck, Zeichnung wie hosenstueck; Bereiche wie rwinkel, ohne Leitbleche (4) */
  hosenSym('rwinkel');
} }];
/* Steckverbindung, Nippel und Muffe (Fable Runde 17, Dimi 11.11.2026): Bereiche wie lippe */
SYM.lippe.v = [{ f: function () { nippelSym('lippe', { ende: 0, sicke: 1, sitz: 2, dicht: 3, rohr: 4, naht: 5 }); } }, { f: function () { muffeSym('lippe'); } }];
/* Lage fuer Boegen 45 Grad: Bogenebene fast in der Bildebene (Achsen u = (1, -1, 0) und z), als flaches V; so erscheint der
   Winkel im Bild unverzerrt und beide Enden sind leicht offen zu sehen. Rueckgabe [A, Tn] fuer Bogenanfang und Biegerichtung */
var U45 = nz([1, -1, 0]);
function lage45() {
  var w = Math.PI / 8;
  return [ad(mu(U45, Math.cos(w)), mu(EZ, -Math.sin(w))), ad(mu(U45, Math.sin(w)), mu(EZ, Math.cos(w)))];
}
/* Segmentbogen: 0 Segmente, 1 Laengsnaht, 2 Umfangsfalz, 3 Anschlussenden */
SYM.segbogen.v = [{ f: function () {
  var pid = 'segbogen', R = 250, r = 125, Ls = 75;
  /* Naehte vorn (die Bogenebene zeigt hier nach hinten, deshalb negative Winkel) */
  var L = lage45(), s = segBogen([0, 0, 0], L[0], L[1], R, r, 'm', pid, { A: { seg: 0, naht: 1, umf: 2 }, naht: 1, enden: 1, g: [0, 11.25, 33.75, 45], nw: [-0.36 * Math.PI, -0.64 * Math.PI], rippe: SEG_RIPPE });
  bereich(3, function () {
    steckende([0, 0, 0], mu(L[0], -1), Ls, r, pid, { rim0: false });
    steckende(s.pe, s.te, Ls, r, pid, { rim0: false });
  });
  mass('d', 'Nenndurchmesser', 'dm', ad(s.pe, mu(s.te, Ls)), s.te, r);
  /* Runde 12 der Szene (Dimi 10.11.2026): auch hier Radius und Winkel */
  massBogen(L[0], L[1], R, 45);
} }, { f: function () {
  var pid = 'segbogen', R = 250, r = 125, Ls = 75;
  var s = segKette(etagenBogenKnoten([0, 0, 0], EX, EY, R, 150), EZ, r, 'm', pid, { A: { seg: 0, naht: 1, umf: 2 }, naht: 1, enden: 1, rippe: SEG_RIPPE });
  bereich(3, function () {
    steckende([0, 0, 0], NX, Ls, r, pid, { rim0: false });
    steckende(s.pe, s.te, Ls, r, pid, { rim0: false });
  });
  mass('d', 'Nenndurchmesser', 'dm', ad(s.pe, mu(s.te, Ls)), s.te, r);
  /* Etagenbogen aus zwei Boegen 45 Grad: Radius und Winkel am ersten Bogen (Runde 12 der Szene) */
  massBogen(EX, EY, R, 45);
} }];
/* Radius (Achse) und Winkel eines Bogens, der bei [0, 0, 0] in Richtung A beginnt und sich zur Seite Tn um w Grad dreht */
function massBogen(A, Tn, R, w) {
  var C = mu(Tn, R), g = w * Math.PI / 180;
  function rho(f) { return ad(mu(Tn, -Math.cos(f)), mu(A, Math.sin(f))); }
  /* Radius bei 30 % des Winkels, damit sich die Buchstaben r und α nicht ueberdecken */
  mass('r', 'Radius (Achse)', 'rad', C, ad(C, mu(rho(g * 0.3), R)));
  mass('α', 'Winkel', 'win', C, rho(0), rho(g), Math.min(95, R * 0.42));
}
/* T-Stueck und Abzweig (rund): 0 Grundkoerper, 1 Abzweig, 2 Fuegenaht, 3 Steckenden */
function tGrund(pid, R, L) {
  bereich(0, function () { rohr([-L, 0, 0], [L, 0, 0], R, pid, { innen: false, ch: CHR }); });
  oeffnungR([L, 0, 0], EX, R, pid);
  bereich(3, function () {
    sicke([L - 48, 0, 0], EX, R, pid, 10, SB); lippe([L, 0, 0], EX, R, pid, { b: SB });
    sicke([-L + 48, 0, 0], EX, R, pid, 10, SB); lippe([-L, 0, 0], NX, R, pid, { b: SB });
  });
}
SYM.tstueck90.v = [{ f: function () {
  var pid = 'tstueck90', R = 157.5, r = 125, L = 400, Ab = nz([1, 0, 1]);
  bereich(0, function () { rohr([-L, 0, 0], [L, 0, 0], R, pid, { innen: false, ch: CHR }); });
  oeffnungR([L, 0, 0], EX, R, pid);
  var t = abzweigR([-95, 0, 0], EX, R, Ab, r, 500, 'm', pid, { A: { abzweig: 1, naht: 2, ende: 3 }, sickeB: SB + 30, lipB: SB + 30, bA: SB, bN: SB + 4, bord: T_BORD });
  oeffnungR(t.pe, Ab, r, pid);
  bereich(3, function () {
    sicke([L - 48, 0, 0], EX, R, pid, 10, SB); lippe([L, 0, 0], EX, R, pid, { b: SB });
    sicke([-L + 48, 0, 0], EX, R, pid, 10, SB); lippe([-L, 0, 0], NX, R, pid, { b: SB });
  });
  bereich(4, function () {
    punktNaht([-L + 70, 0, 0], [L - 70, 0, 0], R, pid, { b: SB + 2, dreh: 30 });
    punktNaht(ad([-95, 0, 0], mu(Ab, 270)), ad([-95, 0, 0], mu(Ab, 500 - 66)), r, pid, { b: SB + 6, dreh: 0 });
  });
  mass('d₁', 'Durchmesser Durchgang', 'dm', [L, 0, 0], EX, R, EY);
  mass('d₂', 'Durchmesser Abgang', 'dm', t.pe, Ab, r, EY);
  mass('l', 'Länge', 'lin', [-L, R, 0], [L, R, 0], [0, 110, 0]);
} }, { f: function () {
  /* Kreuzstueck: zwei gegenueberliegende Abgaenge, der untere ohne Tiefenzuschlag (liegt hinter dem Grundkoerper) */
  var pid = 'tstueck90', R = 157.5, r = 125;
  tGrund(pid, R, 400);
  var t = tStueck90([0, 0, 0], EX, R, EZ, r, R + 230, 'm', pid, { A: { abzweig: 1, naht: 2, ende: 3 }, sickeB: SB + 30, lipB: SB + 30, bA: SB, bN: SB + 4, bord: T_BORD });
  oeffnungR(t.pe, EZ, r, pid);
  tStueck90([0, 0, 0], EX, R, [0, 0, -1], r, R + 230, 'm', pid, { A: { abzweig: 1, naht: 2, ende: 3 }, sickeB: SB + 30, lipB: SB + 30, bA: 1, bN: 1, bord: T_BORD });
  bereich(4, function () {
    punktNaht([-330, 0, 0], [330, 0, 0], R, pid, { b: SB + 2, dreh: 30 });
    punktNaht([0, 0, R + 24], [0, 0, R + 230 - 66], r, pid, { b: SB + 6 });
  });
  mass('d₁', 'Durchmesser Durchgang', 'dm', [400, 0, 0], EX, R, EY);
  mass('d₂', 'Durchmesser Abgang', 'dm', t.pe, EZ, r, EX);
  mass('l', 'Länge', 'lin', [-400, R, 0], [400, R, 0], [0, 110, 0]);
} }, { f: function () {
  /* T-Stueck mit kleinerem Abgang (reduziert) */
  var pid = 'tstueck90', R = 157.5, r = 80;
  tGrund(pid, R, 400);
  var t = tStueck90([0, 0, 0], EX, R, EZ, r, R + 230, 'm', pid, { A: { abzweig: 1, naht: 2, ende: 3 }, sickeB: SB + 30, lipB: SB + 30, bA: SB, bN: SB + 4, bord: T_BORD });
  oeffnungR(t.pe, EZ, r, pid);
  bereich(4, function () {
    punktNaht([-330, 0, 0], [330, 0, 0], R, pid, { b: SB + 2, dreh: 30 });
    punktNaht([0, 0, R + 24], [0, 0, R + 230 - 66], r, pid, { b: SB + 6 });
  });
  mass('d₁', 'Durchmesser Durchgang', 'dm', [400, 0, 0], EX, R, EY);
  mass('d₂', 'Durchmesser Abgang', 'dm', t.pe, EZ, r, EX);
  mass('l', 'Länge', 'lin', [-400, R, 0], [400, R, 0], [0, 110, 0]);
} }];
/* Reduzierung: 0 Konus, 1 Anschlussstuecke, 2 Umfangsnaehte, 3 Enden, 4 Laengsnaehte. Exzentrisch: oben buendig. Bauform 3: gerades Rohrstueck */
SYM.reduz.v = [{ f: function () {
  var pid = 'reduz', L = 380, r0 = 157.5, r1 = 100, E = mu(EZ, r0 - r1);
  reduz([0, 0, 0], EX, L, r0, r1, 'm', pid, { A: { konus: 0, ansch: 1, umf: 2, innen: null, laengs: 4 }, fein: 1, rb: SB, ex: EZ, umfB: 14 });
  bereich(3, function () {
    sicke([45, 0, 0], EX, r0, pid, 10, SB); lippe([0, 0, 0], NX, r0, pid, { b: SB });
    sicke(ad([L - 45, 0, 0], E), EX, r1, pid, 10, SB); lippe(ad([L, 0, 0], E), EX, r1, pid, { b: SB });
  });
  mass('d₁', 'Durchmesser groß', 'dm', [0, 0, 0], NX, r0, EZ);
  mass('d₂', 'Durchmesser klein', 'dm', ad([L, 0, 0], E), EX, r1, EZ);
  mass('l', 'Länge', 'lin', [0, r0, 0], ad([L, r1, 0], E), [0, 110, 0], EX);
} }, { f: function () {
  /* Bauform 3 (Fable Runde 17, Dimi 11.11.2026): gerades Rohrstueck ohne Querschnittsaenderung. Bereiche wie reduz: das Rohrstueck
     zaehlt zu den Anschlussstuecken (1), dazu Enden (3) und Laengsnaht (4); ohne Konus (0) und Umfangsnaehte (2) */
  var pid = 'reduz', L = 320, r = 125;
  bereich(1, function () { rohr([0, 0, 0], [L, 0, 0], r, pid, { innen: false, ch: CHR }); });
  oeffnungR([L, 0, 0], EX, r, pid);
  bereich(4, function () { punktNaht([58, 0, 0], [L - 58, 0, 0], r, pid, { b: SB }); });
  bereich(3, function () {
    sicke([45, 0, 0], EX, r, pid, 10, SB); lippe([0, 0, 0], NX, r, pid, { b: SB });
    sicke([L - 45, 0, 0], EX, r, pid, 10, SB); lippe([L, 0, 0], EX, r, pid, { b: SB });
  });
  mass('d', 'Nenndurchmesser', 'dm', [L, 0, 0], EX, r, EZ);
  mass('l', 'Länge', 'lin', [0, r, 0], [L, r, 0], [0, 110, 0]);
} }];
/* Sattelstutzen: 0 Grundrohr (nur Traeger, blass), 1 Abzweig, 2 Sattelrand mit Fuegepunkten, 3 Enden */
SYM.tstueck.v = [{ f: function () {
  var pid = 'tstueck', R = 157.5, r = 100, L = 440, st = 118, Ab = nz([1, 0, 1]);
  var t = sattelW([-120, 0, 0], EX, R, Ab, r, 500, 'm', pid, { A: { abzweig: 1, rand: 2, ende: 3 }, sickeB: SB + 30, lipB: SB + 30, bA: SB, bR: SB + 2, bP: SB + 4 });
  var g0 = -120 + t.x0 - 17, g1 = -120 + t.x1 + 17;
  bereich(0, function () {
    rohr([-L, 0, 0], [L, 0, 0], R, pid, { innen: false, ch: CHR });
    wickel([-L, 0, 0], [g0, 0, 0], R, pid, st, { b: SB, nk: 64 });
    wickel([g1, 0, 0], [L, 0, 0], R, pid, st, { b: SB, ph: 2 * Math.PI * (g1 + L) / st, nk: 64 });
  });
  oeffnungR([L, 0, 0], EX, R, pid);
  oeffnungR(t.pe, Ab, r, pid);
  bereich(3, function () {
    sicke([L - 48, 0, 0], EX, R, pid, 10, SB); lippe([L, 0, 0], EX, R, pid, { b: SB });
    sicke([-L + 48, 0, 0], EX, R, pid, 10, SB); lippe([-L, 0, 0], NX, R, pid, { b: SB });
  });
  mass('d₁', 'Durchmesser Grundrohr', 'dm', [L, 0, 0], EX, R, EY);
  mass('d₂', 'Durchmesser Abzweig', 'dm', t.pe, Ab, r, EY);
  /* Stutzenlaenge (Runde 12 der Szene): an der oberen Mantellinie des Stutzens vom Grundrohr bis zum Ende */
  var e = nz([-1, 0, 1]), sa = R * Math.SQRT2 - r;
  function X(q) { return ad(ad([-120, 0, 0], mu(Ab, q)), mu(e, r)); }
  mass('l', 'Stutzenlänge', 'lin', X(sa), X(500), mu(e, 90), Ab);
  bereich(4, function () { punktNaht(ad([-120, 0, 0], mu(Ab, 250)), ad([-120, 0, 0], mu(Ab, 500 - 66)), r, pid, { b: SB + 6, dreh: 0 }); });
} }];
/* Gepresste Formteile (Runde 11, Punkt 14): Bereiche Pressteile (Halbschalen), Naht der Halbschalen, Steckenden.
   Im Wechsel Bogen 90°, Bogen 45°, T-Stueck, Abzweig 45°; T-Stueck und Abzweig: Halbschalen in der Ebene beider Achsen geteilt,
   die Naht laeuft oben und unten am Durchgang und an beiden Seiten des Abgangs */
var PRESS_RAND = 6;
function pressNaht(P, pid, dir) {
  /* mit Richtung dir (nach aussen): Rand der Halbschalen als schmaler Steg wie am gepressten Bogen (Fable Runde 17) */
  if (dir) {
    var Q = P.map(function (q) { return ad(q, mu(dir, PRESS_RAND)); });
    face([P[0], P[1], Q[1], Q[0]], 'm', pid, { n: [0, 1, 0], two: 1, b: SB + 4, c: '#C9D3DF' });
    line(Q, pid, { w: 1, s: '#3E4B5C', b: SB + 4.1 }); line(P, pid, { w: 0.8, s: '#5E7189', b: SB + 4.1 });
    return;
  }
  /* Doppellinie wie die Naht des gepressten Bogens: dunkel, daneben hell */
  line(P, pid, { w: 2.2, s: '#3E4B5C', b: SB + 4 });
  line(P.map(function (q) { return ad(q, [0, 2.5, 0]); }), pid, { w: 0.9, s: '#FFFFFF', b: SB + 4.1, op: 0.9 });
}
function pressT(pid, Ab, r, Lb) {
  var R = 157.5, L = 400;
  bereich(0, function () { rohr([-L, 0, 0], [L, 0, 0], R, pid, { innen: false, ch: CHR }); });
  oeffnungR([L, 0, 0], EX, R, pid);
  var t = gt(Ab[0], 0.01) ? abzweigR([-95, 0, 0], EX, R, Ab, r, 500, 'm', pid, { A: { abzweig: 0, naht: null, ende: 2 }, sickeB: SB + 30, lipB: SB + 30, bA: SB, bN: SB + 4, ohneNaht: 1 })
    : tStueck90([0, 0, 0], EX, R, Ab, r, Lb, 'm', pid, { A: { abzweig: 0, ende: 2 }, sickeB: SB + 30, lipB: SB + 30, bA: SB, bN: SB + 4, ohneNaht: 1 });
  oeffnungR(t.pe, Ab, r, pid);
  bereich(1, function () {
    /* Naht in der Ebene y = 0: unten durchgehend, oben bis an den Abgang, am Abgang beidseits bis zum Steckende */
    pressNaht([[-L + 60, 0, -R - 0.8], [L - 60, 0, -R - 0.8]], pid, [0, 0, -1]);
    var xa = gt(Ab[0], 0.01) ? -95 - r * 1.35 : -r - 4, xb = gt(Ab[0], 0.01) ? -95 + r * 1.45 : r + 4;
    pressNaht([[-L + 60, 0, R + 0.8], [xa, 0, R + 0.8]], pid, EZ); pressNaht([[xb, 0, R + 0.8], [L - 60, 0, R + 0.8]], pid, EZ);
    var e1 = nz(cr(Ab, [0, 1, 0])), p0 = gt(Ab[0], 0.01) ? [-95, 0, 0] : [0, 0, 0];
    each([1, -1], function (sg) {
      var q0 = ad(ad(p0, mu(Ab, R + (gt(Ab[0], 0.01) ? 40 : 6))), mu(e1, sg * (r + 0.8))), q1 = ad(ad(p0, mu(Ab, (gt(Ab[0], 0.01) ? 500 : Lb) - 60)), mu(e1, sg * (r + 0.8)));
      pressNaht([q0, q1], pid, mu(e1, sg));
    });
  });
  bereich(2, function () {
    sicke([L - 48, 0, 0], EX, R, pid, 10, SB); lippe([L, 0, 0], EX, R, pid, { b: SB });
    sicke([-L + 48, 0, 0], EX, R, pid, 10, SB); lippe([-L, 0, 0], NX, R, pid, { b: SB });
  });
  mass('d₁', 'Durchmesser Durchgang', 'dm', [L, 0, 0], EX, R, EY);
  mass('d₂', 'Durchmesser Abgang', 'dm', t.pe, Ab, r, gt(Ab[0], 0.01) ? EY : EX);
}
SYM.pbogen = { vn: ['Bogen 90° gepresst', 'Bogen 45° gepresst', 'T-Stück gepresst', 'Abzweig 45° gepresst'], hw: 'Im Wechsel: gepresster Bogen 90° und 45°, gepresstes T-Stück und gepresster Abzweig 45°, je aus zwei gepressten Halbschalen; ihre Ränder sind rollnahtgeschweißt und stehen als schmaler Steg. Steckenden mit Sicke und Lippendichtung.', f: function () {
  var pid = 'pbogen', R = 200, r = 100, Ls = 70;
  /* Blick in beide Enden und auf die innere Naht */
  var s = pressBogen([0, 0, 0], NX, EY, R, r, 'm', pid, { A: { bogen: 0, naht: 1 }, rand: PRESS_RAND, innen: false, rim0: false, rim1: false, b: 1 });
  bereich(2, function () {
    steckende([0, 0, 0], EX, Ls, r, pid, { rim0: false });
    steckende(s.pe, EY, Ls, r, pid, { rim0: false });
  });
  mass('d', 'Nenndurchmesser', 'dm', ad(s.pe, mu(EY, Ls)), EY, r, EX);
  massBogen(NX, EY, R, 90);
}, v: [{ f: function () {
  var pid = 'pbogen', R = 200, r = 100, Ls = 70;
  var L = lage45(), s = pressBogen([0, 0, 0], L[0], L[1], R, r, 'm', pid, { A: { bogen: 0, naht: 1 }, rand: PRESS_RAND, innen: false, rim0: false, rim1: false, b: 1, w: 45, n: 8 });
  bereich(2, function () {
    steckende([0, 0, 0], mu(L[0], -1), Ls, r, pid, { rim0: false });
    steckende(s.pe, s.te, Ls, r, pid, { rim0: false });
  });
  mass('d', 'Nenndurchmesser', 'dm', ad(s.pe, mu(s.te, Ls)), s.te, r);
  massBogen(L[0], L[1], R, 45);
} }, { f: function () { pressT('pbogen', EZ, 125, 157.5 + 230); } }, { f: function () { pressT('pbogen', nz([1, 0, 1]), 125, 500); } }] };

/* Alle Bauformen eines Bauteils (erste = symbolBauen), einmal berechnet */
var SYMV = {};
function symbolVarianten(pid) {
  if (SYMV[pid] !== undefined) { return SYMV[pid]; }
  var S0 = symbolBauen(pid); if (!S0) { SYMV[pid] = null; return null; }
  var r = [S0];
  each(SYM[pid].v || [], function (vd) { r.push(symbolRechnen(pid, vd)); });
  SYMV[pid] = r;
  return r;
}
function bewegungErlaubt() {
  try { return !(window.matchMedia ? window.matchMedia('(prefers-reduced-motion: reduce)').matches : false); } catch (e) { return true; }
}
/* Wechsel fuer N Bauformen: je Bauform 9 s; nacheinander statt ueberblendet (Dimi 09.11.2026, Runde 11 Punkt 12: eine Bauform
   wird durchsichtig und verschwindet, dann kommt die naechste): 1 s ausblenden, 1 s einblenden. pre schraenkt auf ein Elternelement ein */
function varAnim(pre, N) {
  var T = 9 * N, fs = 1, f = 100 * fs / T, a = 100 / N;
  function pz(x) { return (Math.round(x * 100) / 100) + '%'; }
  var r = '@keyframes wsvZ' + N + '{0%{opacity:0}' + pz(f) + '{opacity:1}' + pz(a - f) + '{opacity:1}' + pz(a) + '{opacity:0}100%{opacity:0}}';
  r += pre + '.wsvN' + N + '{animation:wsvZ' + N + ' ' + T + 's ease-in-out infinite;animation-delay:-' + fs + 's}';
  for (var i = 1; i !== N; i++) { r += pre + '.wsvN' + N + '.wsv' + i + '{animation-delay:-' + ((N - i) * T / N + fs) + 's}'; }
  return r;
}
/* Bauformen in ein SVG zeichnen: je Bauform eine Gruppe mit eigenem SVG (eigener Ausschnitt, eingepasst in den
   Ausschnitt der ersten). inline: Kartei (Seiten-CSS, Bereichs-Hervorhebung); sonst Bild mit eigenem Stilblock. */
function variantenZeichnen(svg, V, inline, box) {
  var N = V.length, v0 = box || V[0].vb, gs = [], an = bewegungErlaubt();
  if (!inline) {
    if (an) { sv('style', {}, svg).textContent = '.wsv{opacity:0}.wsv0{opacity:1}' + varAnim('', N); }
    else { V = [V[0]]; }
  }
  each(V, function (S, i) {
    var g = sv('g', { 'class': 'wsv wsv' + i + ' wsvN' + N }, svg);
    var s2 = sv('svg', { 'class': 'wsv-s', x: f1(v0[0]), y: f1(v0[1]), width: f1(v0[2]), height: f1(v0[3]), viewBox: S.vb.map(f1).join(' '), overflow: 'visible' }, g);
    zeichneSymbol(sv('g', {}, s2), S.it);
    gs.push(g);
  });
  if (inline) {
    /* Bereich hervorgehoben: erste Bauform, die den Bereich zeigt (Klasse fuer Tests und Ruecksprung) */
    for (var k = 0; k !== 9; k++) {
      var w = 0;
      for (var i = N - 1; i !== -1; i--) { if (V[i].used[k]) { w = i; } }
      gs[w].classList.add('wsv-f' + k);
    }
    wechselSteuern(svg, V);
  }
  return gs;
}
/* Kartei-Bild mit Bauformen (Dimi 09.11.2026): Wechsel per Zeitgeber statt CSS-Animation. Er haelt an, solange ein Grund
   besteht (Zeiger ueber Bild oder Bereichsliste, hervorgehobener Bereich, 3D-Ansicht), und laeuft danach von der gezeigten
   Bauform weiter. Ein Bereich wird in der gezeigten Bauform hervorgehoben; nur wenn sie ihn nicht hat, wechselt das Bild
   zur ersten Bauform mit diesem Bereich. svg.wsvCtl: halt(grund, an), bereich(k), zeige(i), j() */
var WSV_MS = 9000, WSV_MIN = 3000;
/* Runde 13 der Szene (Dimi 10.11.2026): die Bauformen laufen einmal durch, danach bleibt das Leitbild (erste Bauform) stehen.
   Zeigt man spaeter eine andere Bauform (Bereich, Knopf), kehrt die Kartei nach WSV_MS einmal zum Leitbild zurueck. */
function wechselSteuern(svg, V) {
  var N = V.length, j = 0, halt = false, tm = null, an = bewegungErlaubt(), gr = {}, rest = WSV_MS, t0 = 0, fertig = false;
  svg.classList.add('wsv-js'); svg.classList.add('wsv-z0');
  function setz(i) {
    if (i === j) { return; }
    svg.classList.remove('wsv-z' + j); j = i; svg.classList.add('wsv-z' + j); rest = WSV_MS;
    if (svg.wsvNeu) { svg.wsvNeu(j); }
  }
  /* Zeitgeber anhalten: Restzeit merken (mindestens WSV_MIN, damit das Bild nach dem Verlassen nicht sofort wechselt) */
  function stopp() {
    if (!tm) { return; }
    window.clearTimeout(tm); tm = null; rest = Math.max(WSV_MIN, rest - (Date.now() - t0));
  }
  function plan(ms) {
    if (tm) { window.clearTimeout(tm); tm = null; }
    if (!an) { return; }
    if (halt) { return; }
    if (lt(N, 2)) { return; }
    if (fertig) { if (j === 0) { return; } }
    rest = ms; t0 = Date.now();
    tm = window.setTimeout(function () {
      tm = null; if (!svg.isConnected) { return; }
      if (fertig) { setz(0); return; }
      setz((j + 1) % N); if (j === 0) { fertig = true; return; } plan(WSV_MS);
    }, ms);
  }
  function grund() { for (var g in gr) { if (gr[g]) { return true; } } return false; }
  plan(WSV_MS);
  var api = {
    halt: function (g, on) {
      gr[g] = !!on; var h = grund(); if (h === halt) { return; }
      halt = h; if (h) { stopp(); } else { plan(rest); }
    },
    bereich: function (k) {
      if (k === null) { return; }
      if (k === undefined) { return; }
      if (V[j].used[k]) { return; }
      for (var i = 0; i !== N; i++) { if (V[i].used[k]) { setz(i); if (!halt) { plan(WSV_MS); } return; } }
    },
    zeige: function (i) { setz(i); if (!halt) { plan(WSV_MS); } },
    j: function () { return j; },
    haelt: function () { return halt; },
    n: N
  };
  svg.wsvCtl = api;
  return api;
}
var CSSV = (function () {
  /* inneres SVG je Bauform: immer die volle Flaeche des aeusseren Ausschnitts (Regeln fuer .wsy-bild svg gelten nicht) */
  var r = '.wsv .wsv-s.wsv-s{width:100%;height:100%;max-width:none;max-height:none}';
  r += '.wsv{opacity:0;transition:opacity .35s}.wsv0{opacity:1}';
  for (var n = 2; n !== 6; n++) { r += varAnim('.wsv-an ', n); }
  /* Kartei: gezeigte Bauform per Klasse wsv-zI (wechselSteuern), weiche Ueberblendung */
  /* nur die gezeigte Bauform nimmt den Zeiger an (unsichtbare Bauformen liegen darueber und loesten sonst Bereiche aus) */
  /* nacheinander: die alte Bauform blendet aus, die neue wartet so lange und blendet dann ein (Punkt 12) */
  r += '.wsv-js .wsv{animation:none;opacity:0;transition:opacity .8s ease-in-out;pointer-events:none}';
  for (var i = 0; i !== 6; i++) { r += '.wsv-js.wsv-z' + i + ' .wsv' + i + '{opacity:1;pointer-events:auto;transition-delay:.8s}'; }
  return r + '@media (prefers-reduced-motion:reduce){.wsv-an .wsv{animation:none}.wsv-js .wsv{transition:none}}';
})();

/* ---------- Prozess-Symbole (Teil c) ----------
   Stil wie die Bereichssymbole v3 der Website: flache Flaechen, Umriss navy, gelbes Merkmal.
   Beim Erscheinen baut sich das Symbol auf, danach bewegt sich das Merkmal einmal; Ueberfahren wiederholt es.
   Bewegung: Folgen (Bilder nacheinander), Zeichnen (zd), laufende Striche (zl), Verschieben (zu hin und zurueck, zv einmal),
   Punkt erscheint (zp), Blinken (zf), Ausblenden (zo), Einblenden (zi). */
var IKF = { T: '#EEF2F7', L: '#DCE4EE', R: '#C3D1E1', I: '#AFC1D6', B: '#1F3855', Y: '#F7BC0C', W: '#FFFFFF', G: '#3A4048', D: '#8C99A8' };
function PQ(p) { return [(p[0] - p[1]) * C30, (p[0] + p[1]) * 0.5 - p[2]]; }
function ikFarbe(n) {
  var a = Math.abs(n[0]), b = Math.abs(n[1]), c = Math.abs(n[2]);
  if (gt(c, Math.max(a, b) - 0.05)) { return gt(n[2], 0) ? IKF.T : IKF.I; }
  if (gt(b, a)) { return gt(n[1], 0) ? IKF.L : IKF.I; }
  return gt(n[0], 0) ? IKF.R : IKF.I;
}
function ikBasis(ax) { var a = nz(ax), t = gt(Math.abs(a[2]), 0.9) ? [1, 0, 0] : [0, 0, 1], u = nz(cr(a, t)); return [a, u, cr(a, u)]; }
function ikKreis(c, u, v, r, n, a0, a1) {
  var p = [], m = n || 32, s = (a0 === undefined) ? 0 : a0, e = (a1 === undefined) ? 2 * Math.PI : a1, zu = (a0 === undefined);
  for (var i = 0; i !== m + (zu ? 0 : 1); i++) { var t = s + (e - s) * i / m; p.push(ad(c, ad(mu(u, r * Math.cos(t)), mu(v, r * Math.sin(t))))); }
  return p;
}
function huelle(pts) {
  var P = pts.slice().sort(function (a, b) { return (a[0] - b[0]) || (a[1] - b[1]); });
  function k(o, a, b) { return (a[0] - o[0]) * (b[1] - o[1]) - (a[1] - o[1]) * (b[0] - o[0]); }
  var lo = [], up = [], i;
  for (i = 0; i !== P.length; i++) { while (gt(lo.length, 1)) { if (gt(k(lo[lo.length - 2], lo[lo.length - 1], P[i]), 0)) { break; } lo.pop(); } lo.push(P[i]); }
  for (i = P.length - 1; i !== -1; i--) { while (gt(up.length, 1)) { if (gt(k(up[up.length - 2], up[up.length - 1], P[i]), 0)) { break; } up.pop(); } up.push(P[i]); }
  lo.pop(); up.pop();
  return lo.concat(up);
}
function Ik() { this.it = []; this.fr = null; this.cl = null; this.ex = []; }
Ik.prototype.add = function (d, a, o) {
  o = o || {};
  var e = { d: d, q: this.it.length, a: a, cls: o.cls || this.cl, fr: this.fr, sty: o.sty, pts: o.pts };
  this.it.push(e);
  return e;
};
Ik.prototype.tiefe = function (p3, o) { return (o.d !== undefined) ? o.d : DE(mitte(p3)) + (o.db || 0); };
Ik.prototype.poly = function (p3, f, o) {
  o = o || {};
  if (o.cull) { if (!sicht(newell(p3))) { return null; } }
  var p = p3.map(PQ);
  return this.add(this.tiefe(p3, o), { d: pfad(p, 1), fill: f || ikFarbe(newell(p3)), stroke: o.st || IKF.B, 'stroke-width': o.sw || 1.5 }, { cls: o.cls, pts: p, sty: o.sty });
};
Ik.prototype.line = function (p3, o) {
  o = o || {};
  var p = p3.map(PQ), a = { d: pfad(p, 0), fill: 'none', stroke: o.st || IKF.B, 'stroke-width': o.sw || 1.5 };
  if (o.pl) { a.pathLength = 100; }
  if (o.da) { a['stroke-dasharray'] = o.da; }
  return this.add(this.tiefe(p3, o), a, { cls: o.cls, pts: p, sty: o.sty });
};
Ik.prototype.box = function (x, y, z, dx, dy, dz, o) {
  o = o || {};
  var d = o.d, r = [];
  function od(k) { return ext(o, { d: d === undefined ? undefined : d + k * 0.001 }); }
  r.push(this.poly([[x, y, z + dz], [x + dx, y, z + dz], [x + dx, y + dy, z + dz], [x, y + dy, z + dz]], o.ft || IKF.T, od(0)));
  r.push(this.poly([[x, y + dy, z], [x + dx, y + dy, z], [x + dx, y + dy, z + dz], [x, y + dy, z + dz]], o.fl || IKF.L, od(1)));
  r.push(this.poly([[x + dx, y, z], [x + dx, y + dy, z], [x + dx, y + dy, z + dz], [x + dx, y, z + dz]], o.fr || IKF.R, od(2)));
  return r;
};
/* Konvexes Polygon A am konvexen Polygon B abschneiden (Sutherland-Hodgman, Bildschirmkoordinaten) */
function ikSeite(a, b, sg, p) { return sg * ((b[0] - a[0]) * (p[1] - a[1]) - (b[1] - a[1]) * (p[0] - a[0])); }
function ikKreuz(a, b, p, q) {
  var dn = (p[0] - q[0]) * (a[1] - b[1]) - (p[1] - q[1]) * (a[0] - b[0]);
  if (lt(Math.abs(dn), 1e-12)) { return [p[0], p[1]]; }
  var t = ((p[0] - a[0]) * (a[1] - b[1]) - (p[1] - a[1]) * (a[0] - b[0])) / dn;
  return [p[0] + t * (q[0] - p[0]), p[1] + t * (q[1] - p[1])];
}
function ikSchnitt(A, B) {
  var fl = 0, i, j, out = A.slice();
  for (i = 0; i !== B.length; i++) { var p = B[i], q = B[(i + 1) % B.length]; fl += p[0] * q[1] - q[0] * p[1]; }
  var sg = gt(fl, 0) ? 1 : -1;
  for (i = 0; i !== B.length; i++) {
    if (!out.length) { return out; }
    var a = B[i], b = B[(i + 1) % B.length], inp = out; out = [];
    for (j = 0; j !== inp.length; j++) {
      var P = inp[j], Q = inp[(j + 1) % inp.length], sp = ikSeite(a, b, sg, P), sq = ikSeite(a, b, sg, Q);
      if (!lt(sp, 0)) { out.push(P); if (lt(sq, 0)) { out.push(ikKreuz(a, b, P, Q)); } }
      else if (!lt(sq, 0)) { out.push(ikKreuz(a, b, P, Q)); }
    }
  }
  return out;
}
/* Offenes Ende (Rohr oder Kanal) mit Blick ins Innere (Dimi 09.11.2026: sonst wirkt es wie ein Vollkoerper).
   rand: Innenkante der Oeffnung (3D-Punkte, konvex), ein: Richtung ins Innere, L: Laenge des Koerpers, o.m: Masz der Oeffnung
   (Radius bzw. halbe Breite). Innenwand am Rand hell, in der Tiefe dunkler; ist der Koerper kurz, blickt man durch (weiss). */
var IKI = ['#C9D2DC', '#B3BFCD', '#9AA8B8', '#8796A8'];
Ik.prototype.innen = function (rand, ein, L, d, o) {
  o = o || {};
  var E0 = rand.map(PQ), m = o.m || 10, st = [0.45, 1.15, 2.3], i;
  var q = { cls: o.cls, pts: E0, sty: o.sty };
  this.add(d, { d: pfad(E0, 1), fill: IKI[0], stroke: 'none' }, q);
  for (i = 0; i !== st.length; i++) {
    var tf = st[i] * m, durch = false;
    if (!lt(tf, L)) { tf = L; durch = true; }
    var v = mu(ein, tf), E1 = rand.map(function (p) { return PQ(ad(p, v)); }), S = ikSchnitt(E0, E1);
    if (gt(S.length, 2)) {
      this.add(d + 0.001 * (i + 1), { d: pfad(S, 1), fill: durch ? IKF.W : IKI[i + 1], stroke: durch ? IKF.B : 'none', 'stroke-width': 0.8 }, { cls: o.cls, pts: S, sty: o.sty });
    }
    if (durch) { break; }
  }
  this.add(d + 0.005, { d: pfad(E0, 1), fill: 'none', stroke: IKF.B, 'stroke-width': 1 }, q);
};
/* Zylinder als Umriss (Huelle), sichtbares Ende als Ellipse; o.offen oder o.hohl: Rohrende offen mit Blick ins Innere
   (Wanddicke o.wand), o.durch: Durchblick erlauben (kurzer Ring) */
Ik.prototype.zyl = function (c0, c1, r, o) {
  o = o || {};
  var b = ikBasis(sb(c1, c0)), k0 = ikKreis(c0, b[1], b[2], r), k1 = ikKreis(c1, b[1], b[2], r);
  var d = this.tiefe([c0, c1], o), h = huelle(k0.concat(k1).map(PQ));
  this.add(d, { d: pfad(h, 1), fill: o.f || IKF.L, stroke: o.st || IKF.B, 'stroke-width': o.sw || 1.5 }, { cls: o.cls, pts: h, sty: o.sty });
  var vorn = gt(dt(b[0], VV), 0), ke = vorn ? k1 : k0, ce = vorn ? c1 : c0;
  if (o.ende !== false) {
    var pe = ke.map(PQ);
    if (o.offen || o.hohl) {
      this.add(d + 0.01, { d: pfad(pe, 1), fill: o.fe || '#E3E9F0', stroke: o.st || IKF.B, 'stroke-width': o.sw || 1.5 }, { cls: o.cls, pts: pe, sty: o.sty });
      var wd = o.wand || Math.max(1.1, r * 0.09), ki = ikKreis(ce, b[1], b[2], r - wd, 40);
      this.innen(ki, vorn ? mu(b[0], -1) : b[0], o.durch ? len(sb(c1, c0)) : 1e6, d + 0.02, { m: r, cls: o.cls, sty: o.sty });
    } else {
      this.add(d + 0.01, { d: pfad(pe, 1), fill: o.fe || IKF.T, stroke: o.st || IKF.B, 'stroke-width': o.sw || 1.5 }, { cls: o.cls, pts: pe, sty: o.sty });
    }
  }
  return { ce: ce, b: b, ke: ke, d: d };
};
/* Rohr aus mehreren Stuecken mit einem gemeinsamen Umriss (dicke Linie unten, Flaeche ohne Linie oben) */
Ik.prototype.rohrZug = function (cs, r, o) {
  o = o || {};
  var all = '', pts = [], d = this.tiefe(cs, o);
  for (var i = 0; i !== cs.length - 1; i++) {
    var b = ikBasis(sb(cs[i + 1], cs[i])), h = huelle(ikKreis(cs[i], b[1], b[2], r).concat(ikKreis(cs[i + 1], b[1], b[2], r)).map(PQ));
    all += pfad(h, 1); pts = pts.concat(h);
  }
  this.add(d, { d: all, fill: o.f || IKF.L, stroke: IKF.B, 'stroke-width': 3 }, { cls: o.cls, pts: pts, sty: o.sty });
  this.add(d + 0.001, { d: all, fill: o.f || IKF.L, stroke: 'none' }, { cls: o.cls, pts: pts, sty: o.sty });
  return d;
};
/* sichtbare Haelfte eines Rings um die Achse ax (fuer Sicken, Fugen, Drehmarken) */
Ik.prototype.halbring = function (c, ax, r, o) {
  o = o || {};
  var b = ikBasis(ax), seg = [], cur = [], n = 96;
  for (var i = 0; i !== n + 1; i++) {
    var t = 2 * Math.PI * i / n, v = ad(mu(b[1], Math.cos(t)), mu(b[2], Math.sin(t)));
    if (gt(dt(v, VV), 0)) { cur.push(ad(c, mu(v, r))); } else { if (gt(cur.length, 1)) { seg.push(cur); } cur = []; }
  }
  if (gt(cur.length, 1)) { seg.push(cur); }
  if (gt(seg.length, 1)) { seg = [seg[seg.length - 1].concat(seg[0])].concat(seg.slice(1, seg.length - 1)); }
  var self = this, r2 = [];
  each(seg, function (s) { r2.push(self.line(s, o)); });
  return r2;
};
/* Flaechenband aus Gitter G[i][j] (j = 0..1 quer), beidseitig, Kanten als Linien; o.f Farbe aussen, o.fi innen; o.e0/o.e1 false: ohne Querkante am Anfang/Ende */
Ik.prototype.band = function (G, o) {
  o = o || {};
  var n = G.length - 1, i;
  for (i = 0; i !== n; i++) {
    var q = [G[i][0], G[i + 1][0], G[i + 1][1], G[i][1]], nn = newell(q), vis = sicht(nn), f = vis ? (o.f || ikFarbe(nn)) : (o.fi || IKF.I);
    var d = this.tiefe(q, o);
    var p = q.map(PQ);
    this.add(d, { d: pfad(p, 1), fill: f, stroke: f, 'stroke-width': 0.8 }, { cls: o.cls, pts: p, sty: o.sty });
    this.line([G[i][0], G[i + 1][0]], ext(o, { d: d + 0.01 }));
    this.line([G[i][1], G[i + 1][1]], ext(o, { d: d + 0.01 }));
    if (i === 0) { if (o.e0 !== false) { this.line([G[0][0], G[0][1]], ext(o, { d: d + 0.01 })); } }
    if (i === n - 1) { if (o.e1 !== false) { this.line([G[n][0], G[n][1]], ext(o, { d: d + 0.01 })); } }
  }
};
/* Bildfolge: n Bilder, f(k, t) zeichnet Bild k mit t = 0..1 */
Ik.prototype.folge = function (n, f) {
  for (var k = 0; k !== n; k++) { this.fr = { k: k, n: n }; f(k, n === 1 ? 1 : k / (n - 1)); }
  this.fr = null;
};
/* Klasse fuer alle Teile in f */
Ik.prototype.mit = function (cls, f) { var alt = this.cl; this.cl = cls; f(); this.cl = alt; };

/* Darstellung */
var IKC = {};
function ikBauen(id) {
  if (IKC[id] !== undefined) { return IKC[id]; }
  var S = PSYM[id];
  if (!S) { IKC[id] = null; return null; }
  var I = new Ik(); S.f(I);
  var it = I.it.slice().sort(function (a, b) { return (a.d - b.d) || (a.q - b.q); });
  var x0 = 1e9, y0 = 1e9, x1 = -1e9, y1 = -1e9;
  each(it, function (e) { each(e.pts || [], function (p) { x0 = Math.min(x0, p[0]); y0 = Math.min(y0, p[1]); x1 = Math.max(x1, p[0]); y1 = Math.max(y1, p[1]); }); });
  each(I.ex, function (p3) { var p = PQ(p3); x0 = Math.min(x0, p[0]); y0 = Math.min(y0, p[1]); x1 = Math.max(x1, p[0]); y1 = Math.max(y1, p[1]); });
  var m = 4;
  IKC[id] = { it: it, vb: [x0 - m, y0 - m, x1 - x0 + 2 * m, y1 - y0 + 2 * m], dt: S.dt || 0.22 };
  return IKC[id];
}
function ikSvg(id) {
  var B = ikBauen(id); if (!B) { return null; }
  var svg = sv('svg', { viewBox: B.vb.map(f1).join(' '), 'class': 'wps', 'aria-hidden': 'true', focusable: 'false', preserveAspectRatio: 'xMidYMid meet' });
  var n = 0, nn = 0;
  each(B.it, function (e) { if (!e.fr) { nn++; } });
  svg.style.setProperty('--bs', f1(900 / Math.max(nn, 1)) + 'ms');
  svg.style.setProperty('--dt', B.dt + 's');
  each(B.it, function (e) {
    var el = sv('path', e.a, svg), cls = e.cls || '';
    if (e.fr) {
      cls += ' fq' + (e.fr.k === 0 ? ' f0' : '') + (e.fr.k === e.fr.n - 1 ? ' fe' : '');
      el.style.setProperty('--k', e.fr.k);
    } else { el.style.setProperty('--n', n++); }
    if (e.sty) { for (var k in e.sty) { el.style.setProperty(k, e.sty[k]); } }
    cls = cls.replace(/^ +/, '');
    if (cls) { el.setAttribute('class', cls); }
  });
  return svg;
}
function ikNochmal(svg) { svg.classList.remove('go'); svg.getBoundingClientRect(); svg.classList.add('go'); }
var PCSS = [
  '.wps{display:block;width:100%;height:100%;overflow:visible;--bt:1.05s}',
  '.wps path{stroke-linejoin:round;stroke-linecap:round;vector-effect:non-scaling-stroke}',
  /* Runde 12 der Szene: gezeichnete Linien (zd, pathLength 100) ohne non-scaling-stroke, sonst rechnet Chrome die Strichlaenge am Bildschirm
     und zeigt in grossen Bildern nur einen Teil der Linie (z. B. die Dichtraupe) */
  '.wps path.zd{vector-effect:none}',
  '.wps .fq{opacity:0}.wps .fe{opacity:1}',
  '.wps.go path{animation:wpsB .35s ease-out calc(var(--n) * var(--bs)) both}',
  '.wps.go .fq{opacity:0;animation:wpsQ var(--dt) linear calc(var(--bt) + var(--k) * var(--dt)) forwards}',
  '.wps.go .f0{opacity:1;animation:wpsB .35s ease-out 0s both,wpsQ var(--dt) linear var(--bt) forwards}',
  '.wps.go .fe{animation:wpsE .01s linear calc(var(--bt) + var(--k) * var(--dt)) forwards}',
  '.wps.go .zd{stroke-dasharray:100 130;animation:wpsB .35s ease-out calc(var(--n) * var(--bs)) both,wpsZ var(--zt,1.6s) linear calc(var(--bt) + var(--zs,0s)) both}',
  '.wps.go .zl{animation:wpsB .35s ease-out calc(var(--n) * var(--bs)) both,wpsL var(--lt,.8s) linear calc(var(--bt) + var(--zs,0s)) var(--lz,3)}',
  '.wps.go .zu{animation:wpsB .35s ease-out calc(var(--n) * var(--bs)) both,wpsU var(--mt,1.2s) ease-in-out calc(var(--bt) + var(--zs,0s)) 1}',
  '.wps.go .zv{animation:wpsB .35s ease-out calc(var(--n) * var(--bs)) both,wpsV var(--mt,.8s) ease-in calc(var(--bt) + var(--zs,0s)) both}',
  '.wps.go .zp{animation:wpsB .35s ease-out calc(var(--n) * var(--bs)) both,wpsP .8s ease-out calc(var(--bt) + var(--zs,0s)) both}',
  '.wps.go .zf{animation:wpsB .35s ease-out calc(var(--n) * var(--bs)) both,wpsF .4s ease-in-out calc(var(--bt) + var(--zs,0s)) var(--fz,4)}',
  '.wps.go .zo{animation:wpsB .35s ease-out calc(var(--n) * var(--bs)) both,wpsO .8s ease-in-out calc(var(--bt) + var(--zs,0s)) both}',
  '.wps.go .zi{animation:wpsB .35s ease-out calc(var(--n) * var(--bs)) both,wpsI .5s ease-out calc(var(--bt) + var(--zs,0s)) both}',
  '.wps.go .zw{animation:wpsB .35s ease-out calc(var(--n) * var(--bs)) both,wpsW var(--mt,.9s) ease-out calc(var(--bt) + var(--zs,0s)) both}',
  '@keyframes wpsB{from{opacity:0}to{opacity:1}}',
  '@keyframes wpsQ{0%,99%{opacity:1}100%{opacity:0}}',
  '@keyframes wpsE{from{opacity:1}to{opacity:1}}',
  '@keyframes wpsZ{from{stroke-dashoffset:115}to{stroke-dashoffset:0}}',
  '@keyframes wpsL{from{stroke-dashoffset:0}to{stroke-dashoffset:-24}}',
  '@keyframes wpsU{0%,100%{transform:translate(0,0)}45%,60%{transform:translate(var(--mx,0px),var(--my,4px))}}',
  '@keyframes wpsV{from{transform:translate(0,0)}to{transform:translate(var(--mx,0px),var(--my,4px))}}',
  '@keyframes wpsP{0%{opacity:0;fill:#FFFFFF}45%{opacity:1;fill:#FFFFFF}100%{opacity:1}}',
  '@keyframes wpsF{0%,100%{opacity:1}50%{opacity:.15}}',
  '@keyframes wpsO{from{opacity:1}to{opacity:.12}}',
  '@keyframes wpsI{from{opacity:0}to{opacity:1}}',
  '@keyframes wpsW{from{transform:translate(var(--mx,0px),var(--my,-6px))}to{transform:translate(0,0)}}',
  '@media (prefers-reduced-motion:reduce){.wps.go path{animation:none!important}.wps.go .fq{opacity:0}.wps.go .fe{opacity:1}}'
].join('');

/* ===== Symbole ===== */
var PSYM = {};
function zs(s) { return { '--zs': s + 's' }; }
function ikStrich(I, p3, o) { return I.line(p3, ext({ st: IKF.Y, sw: 2.6 }, o || {})); }
/* Haltezeit: unsichtbarer Pfad, dessen Einblendung bis T (s nach --bt) laeuft; die Kachel zeigt das letzte Bild dann laenger
   (symZyklus wartet bis zum Ende aller Animationen, hoechstens 12 s) */
function ikHalten(I, T) { I.add(-1, { d: 'M0 0', fill: 'none', stroke: 'none' }, { cls: 'zi', sty: zs(Math.max(T - 0.5, 0)) }); }
/* Drehmarken auf einer sichtbaren Stirnflaeche (laufende Striche) */
function ikDreh(I, c, ax, r, o) {
  o = o || {};
  var b = ikBasis(ax), q = ikKreis(c, b[1], b[2], r, 40, 0, 2 * Math.PI);
  if (o.rueck) { q.reverse(); }
  return I.line(q, ext({ st: IKF.B, sw: 1.1, da: '4 8', cls: 'zl' }, o));
}

/* Coil auf dem Abwickelbock (Dimi 09.11.2026; Vorlage RF 20/30): Der Bock steht mit Fuessen auf dem Boden
   (zb = Unterkante des Maschinenbetts), die Achse liegt etwa auf halber Hoehe, das Band laeuft oben tangential und flach
   in Einlaufhoehe (Unterseite des Bandes z = 0, Oberkante des Betts) bis xe. Coil- und Bandbreite in allen Symbolen
   gleich (COIL). Bock: zwei Fuesse mit Rollen, Staender hinter dem Coil, Dorn durch den Coil. o.dreh: Drehmarken */
var COIL = { R: 12, W: 24, t: 1.2 };
function ikAbwickler(I, x, xe, zb, o) {
  o = o || {};
  var R = COIL.R, W = COIL.W, t = COIL.t, zc = -R, d = o.d || 0, c1 = [x, W / 2, zc], yS = -W / 2 - 7;
  /* Fuesse (quer zur Linie) mit Rollen vorn, Querstrebe hinten */
  each([-10, 7], function (dx, i) {
    I.box(x + dx, yS - 2, zb + 1.6, 3, W + 13, 2, { d: d - 3 + i * 0.01 });
    I.zyl([x + dx - 0.2, W / 2 + 6.5, zb + 1.6], [x + dx + 3.2, W / 2 + 6.5, zb + 1.6], 1.6, { d: d - 2.9 + i * 0.01 });
  });
  I.box(x - 10, yS - 2, zb + 3.6, 20, 4, 2, { d: d - 2.8 });
  /* Staender hinter dem Coil, Dorn */
  I.box(x - 2.5, yS, zb + 5.6, 5, 4, -zb - 2, { d: d - 2.5 });
  I.zyl([x, yS + 4, zc], [x, -W / 2, zc], 2.6, { d: d - 2.4, ende: false });
  /* Coil */
  I.zyl([x, -W / 2, zc], c1, R, { d: d, fe: IKF.T });
  I.line(ikKreis(c1, [1, 0, 0], [0, 0, 1], R - 4, 40), { d: d + 0.05, sw: 0.8 });
  if (o.dreh) { ikDreh(I, c1, [0, 1, 0], R - 7, { d: d + 0.1, sw: 0.9 }); }
  I.zyl([x, W / 2 - 0.5, zc], [x, W / 2 + 0.6, zc], 4, { d: d + 0.15, fe: IKF.W });
  I.zyl([x, W / 2 + 0.6, zc], [x, W / 2 + 2.4, zc], 2.4, { d: d + 0.2, fe: IKF.D });
  /* Band oben tangential vom Coil in den Einlauf */
  I.box(x, -W / 2, 0, xe - x, W, t, { d: d + 0.5 });
  if (o.strich !== false) { ikStrich(I, [[x + 4, 0, t + 0.05], [xe - 2, 0, t + 0.05]], { d: d + 0.6, da: '5 5', cls: 'zl', sty: { '--lt': '.6s', '--lz': '5' } }); }
  return { c1: c1, zc: zc };
}
/* Maschinenbett: Boden z = -BETT, Oberkante z = 0 (Hoehe wie Coil-Durchmesser plus Fuesse, Vorlage RF 20/30) */
var BETT = 28;
/* P02 Abwickeln: Coil dreht auf dem Abwickelbock, Band laeuft unten tangential aus */
PSYM.P02 = { f: function (I) {
  ikAbwickler(I, 0, 46, -BETT, { d: 2, dreh: 1 });
} };
/* P03 Richten: Band laeuft durch versetzte Walzen, die Welligkeit verschwindet */
PSYM.P03 = { f: function (I) {
  var r = 4.5, w = 13, i;
  each([-21, -3, 15], function (x) { I.zyl([x, -w - 3, -r - 0.6], [x, w + 3, -r - 0.6], r, { d: 0 }); });
  var G = [];
  for (i = 0; i !== 41; i++) {
    var x = -48 + 96 * i / 40, amp = Math.max(0, Math.min(1, (-16 - x) / 14)), z = 3.4 * amp * Math.sin((x + 48) * 0.3);
    G.push([[x, -w, z], [x, w, z]]);
  }
  I.band(G, { d: 2 });
  ikStrich(I, [[-46, 0, 0.2], [46, 0, 0.2]], { d: 2.5, da: '6 6', cls: 'zl', sty: { '--lt': '.6s', '--lz': '4' } });
  each([-12, 6], function (x) { var z = r + 0.6; I.zyl([x, -w - 3, z], [x, w + 3, z], r, { d: 4 }); ikDreh(I, [x, w + 3, z], [0, 1, 0], r * 0.6, { d: 4.1, sw: 0.9, da: '2 3' }); });
} };
/* P06 Scheren: Obermesser faehrt herab, das Teil faellt ab */
PSYM.P06 = { f: function (I) {
  var t = 2.4, xs = 6;
  /* Tisch mit Untermesser endet genau an der Schnittlinie (Pruefung 09.11.2026) */
  I.box(-40, -24, -6, 40 + xs, 48, 6, { d: 0, ft: IKF.I });
  I.box(-36, -22, 0, 36 + xs, 44, t, { d: 1 });
  I.mit('zv', function () { I.box(xs, -22, 0, 26, 44, t, { d: 1.5, sty: { '--zs': '1.1s', '--my': '9px', '--mt': '.5s' } }); });
  ikStrich(I, [[xs, -22, t + 0.05], [xs, 22, t + 0.05]], { d: 2, pl: 1, cls: 'zd', sty: { '--zt': '.9s', '--zs': '.2s' } });
  I.mit('zu', function () {
    var z0 = t + 4, z1 = t + 10, h = 6;
    I.poly([[xs, -27, z0 + h], [xs, 27, z1 + h], [xs - 3, 27, z1 + h], [xs - 3, -27, z0 + h]], IKF.T, { d: 5, sty: { '--my': '5px', '--mt': '1.2s' } });
    I.poly([[xs, -27, z0], [xs, 27, z1], [xs, 27, z1 + h], [xs, -27, z0 + h]], IKF.R, { d: 5.1, sty: { '--my': '5px', '--mt': '1.2s' } });
  });
  I.ex.push([xs + 26, 22, -10]);
} };
/* P07 Plasmaschneiden (Dimi 09.11.2026: vom Laser unterscheiden, Laser siehe P07L). Ablauf nach der Anleitung PC:
   Brenner im Eilgang ueber den Startpunkt, senkt auf Zuendhoehe, Lichtbogen zuendet, kurze Pause zum Lochstechen (Funken
   steigen auf), dann auf Schneidhoehe die Kontur langsam abfahren: breite Schnittfuge, hinter dem Brenner glueht sie nach,
   viele Funken nach hinten. Die Fuge waechst Bild fuer Bild (Zeichnen per Strichmuster reicht in grossen Bildern nicht). */
PSYM.P07 = { dt: 0.3, f: function (I) {
  var t = 2.4, c = [], i, N = 12, M = 60, V = 3;
  I.box(-36, -26, 0, 72, 52, t, { d: 0 });
  for (i = 0; i !== M + 1; i++) { var a = 2 * Math.PI * i / M, rr = 15 + 2.5 * Math.cos(2 * a); c.push([-2 + rr * Math.cos(a), 0.8 * rr * Math.sin(a), t + 0.05]); }
  I.folge(N + 1 + V, function (k) {
    var kk = Math.max(k - V, 0), j = Math.round(M * kk / N), p = c[j % M], q = c[(j + M - 2) % M], vx = p[0] - q[0], vy = p[1] - q[1], vl = Math.sqrt(vx * vx + vy * vy) || 1;
    var h = k === 0 ? 12 : (lt(k, V) ? 1.2 : 0), an = k !== 0, s, w, l, ux, uy;
    vx /= vl; vy /= vl;
    /* breite Fuge bis zum Brenner, das letzte Stueck glueht; beim Lochstechen nur das Loch */
    if (gt(j, 0)) {
      I.line(c.slice(0, j + 1), { st: IKF.G, sw: 4.6, d: 1 });
      I.line(c.slice(Math.max(0, j - 12), j + 1), { st: IKF.Y, sw: 1.8, d: 1.05 });
    } else if (k === V - 1) { I.poly(ikKreis(p, [1, 0, 0], [0, 1, 0], 1.6, 12), IKF.G, { d: 1, sw: 0.8 }); }
    /* Brenner: Koerper, Duesenkappe, Duese */
    I.zyl([p[0], p[1], 12 + h], [p[0], p[1], 32 + h], 5, { d: 10 });
    I.zyl([p[0], p[1], 7.5 + h], [p[0], p[1], 12 + h], 3.6, { d: 9.95 });
    I.zyl([p[0], p[1], 5 + h], [p[0], p[1], 7.5 + h], 2.2, { d: 9.9 });
    if (!an) { return; }
    /* Lichtbogen als Zickzack mit hellem Kern */
    I.line([[0, 0, 5 + h], [0.9, 0.3, 4.3 + h * 0.8], [-0.8, -0.3, 3.6 + h * 0.5], [0.7, 0.2, 3 + h * 0.3], [0, 0, t]].map(function (o) { return [p[0] + o[0], p[1] + o[1], o[2]]; }), { st: IKF.Y, sw: 2.8, d: 9.85 });
    I.line([[p[0], p[1], 5 + h], [p[0], p[1], t]], { st: IKF.W, sw: 0.8, d: 9.86 });
    if (lt(k, V)) {
      /* Lochstechen: Funken steigen rundum auf */
      for (s = 0; s !== 10; s++) {
        w = 2 * Math.PI * (s + 0.5 * k) / 10; l = 3 + 1.2 * ((s * 3 + k) % 4);
        I.line([[p[0] + 2 * Math.cos(w), p[1] + 2 * Math.sin(w), t + 0.4], [p[0] + (2 + 0.5 * l) * Math.cos(w), p[1] + (2 + 0.5 * l) * Math.sin(w), t + 1 + l]], { st: IKF.Y, sw: 1.3, d: 9.8 });
      }
      return;
    }
    /* viele Funken, vor allem nach hinten, von Bild zu Bild anders */
    for (s = 0; s !== 9; s++) {
      w = Math.PI + (s - 4) * 0.36 + 0.2 * ((k + s) % 3); l = 4 + 1.6 * ((s * 7 + k * 3) % 5);
      ux = vx * Math.cos(w) - vy * Math.sin(w); uy = vx * Math.sin(w) + vy * Math.cos(w);
      I.line([[p[0] + 1.8 * ux, p[1] + 1.8 * uy, t + 0.3], [p[0] + l * ux, p[1] + l * uy, t + 0.6 + 0.3 * l]], { st: IKF.Y, sw: 1.3, d: 9.8 });
    }
  });
} };
/* P11 Kanten (Schwenkbiegemaschine): Unterwange und Oberwange klemmen das Blech, die Oberwange reicht bis an die Biegelinie;
   die Biegewange schwenkt hoch und stellt den Schenkel auf 90 Grad (Pruefung 09.11.2026) */
PSYM.P11 = { dt: 0.2, f: function (I) {
  var t = 2.2, xb = 4, L2 = 24, hw = 6;
  I.box(-40, -22, -7, 40 + xb, 44, 7, { d: 0, ft: IKF.I });
  I.box(-36, -22, 0, 36 + xb, 44, t, { d: 1 });
  I.box(-30, -24, t, 26 + xb, 48, 7, { d: 3 });
  I.poly([[xb - 4, -24, t + 7], [xb - 4, 24, t + 7], [xb, 24, t], [xb, -24, t]], IKF.R, { d: 3.1 });
  I.poly([[xb - 4, 24, t], [xb, 24, t], [xb - 4, 24, t + 7]], IKF.L, { d: 3.15 });
  I.folge(6, function (k, s) {
    var a = s * Math.PI / 2, ca = Math.cos(a), sa = Math.sin(a);
    function P(u, y, w) { return [xb + u * ca - w * sa, y, u * sa + w * ca]; }
    /* Biegewange: liegt unter dem Schenkel und dreht mit ihm um die Biegelinie */
    var db = gt(s, 0.5) ? 4.5 : 3.6, lw = L2 - 9;
    I.poly([P(0, -24, -hw), P(0, 24, -hw), P(lw, 24, -hw), P(lw, -24, -hw)], '#C9D2DC', { d: db, cull: 1 });
    I.poly([P(0, 24, -hw), P(lw, 24, -hw), P(lw, 24, -0.3), P(0, 24, -0.3)], '#B9C5D2', { d: db + 0.05, cull: 1 });
    I.poly([P(lw, -24, -hw), P(lw, 24, -hw), P(lw, 24, -0.3), P(lw, -24, -0.3)], '#D5DDE6', { d: db + 0.1, cull: 1 });
    I.poly([P(0, -22, t), P(L2, -22, t), P(L2, 22, t), P(0, 22, t)], null, { d: 4, cull: 1 });
    I.poly([P(0, -22, 0), P(0, 22, 0), P(L2, 22, 0), P(L2, -22, 0)], null, { d: 4, cull: 1 });
    I.poly([P(0, 22, 0), P(L2, 22, 0), P(L2, 22, t), P(0, 22, t)], IKF.L, { d: 4.1 });
    I.poly([P(L2, -22, 0), P(L2, 22, 0), P(L2, 22, t), P(L2, -22, t)], null, { d: 4.2, cull: 1 });
  });
  I.folge(6, function (k) {
    if (k === 0) { I.line([[xb, -22, t + 0.1], [xb, 22, t + 0.1]], { d: 4.5, st: IKF.Y, sw: 2.2 }); }
    if (k === 5) { I.line([[xb - t / 2, -22, L2 + 0.1], [xb - t / 2, 22, L2 + 0.1]], { d: 5, st: IKF.Y, sw: 2.4 }); }
  });
  I.ex.push([xb + 24, 22, 0], [xb, -22, 26]);
} };
/* P12 Runden: drei Walzen drehen, das Blech rollt sich zum Mantel */
PSYM.P12 = { dt: 0.22, f: function (I) {
  var w = 20, L = 72, r = 5.5, dx = 9;
  var zb = r + 1.6, zt = zb + r + 1.6, Rs = [400, 70, 34, 20, 14], PV = Math.PI / 4;
  /* Unterwalzen: in jedem Bild aussen am Blech (Dreipunktbiegung; Pruefung 09.11.2026) */
  I.folge(Rs.length, function (k) {
    var R = Rs[k], ph = Math.asin(dx / R), c = r + 0.6;
    each([-1, 1], function (sg) {
      var px = sg * dx, pz = zb + R * (1 - Math.cos(ph)), nx = sg * Math.sin(ph), nzz = -Math.cos(ph), cx = px + nx * c, cz = pz + nzz * c;
      var dd = sg === 1 ? (gt(R, 30) ? 0 : 3.6) : 0;
      /* ohne Drehpfeil: die Strich-Animation wuerde die Bildfolge ueberdecken und den Pfeil in jedem Bild zeigen */
      I.zyl([cx, -w - 3, cz], [cx, w + 3, cz], r, { d: dd });
    });
  });
  /* Oberwalze liegt in jedem Bild zwischen hinterem und vorderem Teil des Blechs: hinten (Innenseite sichtbar) d 2, Walze d 2.5, vorn d 3.2 */
  I.folge(Rs.length, function (k) {
    var R = Rs[k], n = 32, A = [], B = [];
    function sp(ph) { return [[R * Math.sin(ph), -w, zb + R * (1 - Math.cos(ph))], [R * Math.sin(ph), w, zb + R * (1 - Math.cos(ph))]]; }
    for (var i = 0; i !== n + 1; i++) {
      var ph = (-L / 2 + L * i / n) / R;
      if (gt(ph, PV)) { if (!B.length) { A.push(sp(PV)); B.push(sp(PV)); } B.push(sp(ph)); } else { A.push(sp(ph)); }
    }
    if (B.length) { I.band(A, { d: 2, e1: false }); I.band(B, { d: 3.2, e0: false }); } else { I.band(A, { d: 2 }); }
  });
  I.zyl([0, -w - 3, zt], [0, w + 3, zt], r, { d: 2.5 });
  ikDreh(I, [0, w + 3, zt], [0, 1, 0], r * 0.6, { d: 3.5, sw: 0.9, da: '2 3', rueck: 1 });
  I.ex.push([-30, w, 34], [30, -w, 34]);
} };
/* P21 Punktschweissen: Zange schliesst, ein Punkt blitzt */
PSYM.P21 = { f: function (I) {
  var t = 2.2, yP = 0, xP = 2;
  I.box(-36, -22, 0, 46, 44, t, { d: 0 });
  I.box(-8, -22, t, 44, 44, t, { d: 1 });
  each([-16, -9], function (y) { I.poly(ikKreis([xP, y, 2 * t + 0.05], [1, 0, 0], [0, 1, 0], 2.2, 16), IKF.Y, { d: 2, st: IKF.Y, sw: 0.8 }); });
  I.poly(ikKreis([xP, yP, 2 * t + 0.05], [1, 0, 0], [0, 1, 0], 2.4, 16), IKF.Y, { d: 2.1, st: IKF.Y, sw: 0.8, cls: 'zp', sty: zs(1.0) });
  I.mit('zu', function () {
    I.zyl([xP, yP, 2 * t + 3.4], [xP, yP, 30], 3.8, { d: 10, sty: { '--my': '3px' } });
    I.zyl([xP, yP, 2 * t + 0.6], [xP, yP, 2 * t + 3.4], 1.9, { d: 9.9, ende: false, sty: { '--my': '3px' } });
    I.zyl([xP, yP, -24], [xP, yP, -0.6], 3.8, { d: -10, sty: { '--my': '-3px' } });
  });
  each([0.6, 2.2, 3.8, 5.2], function (g) { I.line([[xP + 3 * Math.cos(g), yP + 3 * Math.sin(g), 2 * t + 0.4], [xP + 7 * Math.cos(g), yP + 7 * Math.sin(g), 2 * t + 1.6]], { st: IKF.Y, sw: 1.5, d: 2.2, cls: 'zf', sty: { '--zs': '.55s', '--fz': '3' } }); });
} };
/* Verdeckter Zylinder: nur der Umriss gestrichelt (Normzeichnung: verdeckte Kante) */
function ikVerdeckt(I, c0, c1, r, o) {
  o = o || {};
  var b = ikBasis(sb(c1, c0)), h = huelle(ikKreis(c0, b[1], b[2], r).concat(ikKreis(c1, b[1], b[2], r)).map(PQ));
  return I.add(I.tiefe([c0, c1], o), { d: pfad(h, 1), fill: 'none', stroke: IKF.B, 'stroke-width': o.sw || 1, 'stroke-dasharray': o.da || '3 2.5' }, { pts: h, cls: o.cls, sty: o.sty });
}
/* Drehpfeil: Bogen um die Achse ax mit laufenden Strichen und Pfeilspitze (Winkel t0 bis t1 in der Basis von ikBasis) */
function ikDrehPfeil(I, c, ax, r, t0, t1, o) {
  o = o || {};
  var b = ikBasis(ax), q = ikKreis(c, b[1], b[2], r, 24, t0, t1), n = q.length;
  I.line(q, ext({ st: IKF.B, sw: 1.2, da: '4 4', cls: 'zl' }, o));
  var e = q[n - 1], tg = nz(sb(q[n - 1], q[n - 2])), nn = nz(sb(e, c)), L = 4.2, W = 2.4;
  var sp = ad(e, mu(tg, L * 0.6));
  I.poly([sp, ad(sb(e, mu(tg, L * 0.4)), mu(nn, W)), ad(sb(e, mu(tg, L * 0.4)), mu(nn, -W))], IKF.B, { d: (o.d || 4) + 0.01, sw: 0.8 });
}
/* Lupe in der Bildebene: weisse Scheibe mit Griff, f(P, k, t) zeichnet je Bild k der Folge (n Bilder) mit P(x, y) */
function ikLupe(I, c, R, n, f, o) {
  o = o || {};
  var ring = [];
  for (var k = 0; k !== 41; k++) { var a = 2 * Math.PI * k / 40; ring.push(S2(c, R * Math.cos(a), R * Math.sin(a))); }
  /* Scheibe und Griff erscheinen sofort (wie das erste Bild der Folge), nicht erst am Ende des Aufbaus */
  I.poly(ring, IKF.W, { d: 20, sw: 1.6, sty: { '--n': '0' } });
  I.line([S2(c, -R * 0.72, R * 0.72), S2(c, -R * 1.22, R * 1.22)], { d: 20.05, sw: 3.2, sty: { '--n': '0' } });
  function P(x, y) { return S2(c, x, y); }
  I.folge(n, function (k, t) { f(P, k, t); });
  if (o.von) { I.line([o.von, S2(c, -R * 0.94, -R * 0.34)], { d: o.dv || 5, sw: 0.9, da: '2 2' }); }
}
function ikPoly2(I, P, pts, f, d, o) { return I.poly(pts.map(function (q) { return P(q[0], q[1]); }), f, ext({ d: d, sw: 1 }, o || {})); }
function ikLinie2(I, P, pts, d, o) { return I.line(pts.map(function (q) { return P(q[0], q[1]); }), ext({ d: d }, o || {})); }
/* Sicke rundum: gelbe Wulst zwischen zwei duennen Kanten, zeichnet sich einmal um das Rohr */
function ikSicke(I, xb, R, o) {
  o = o || {};
  var z = { '--zt': o.zt || '1.3s', '--zs': o.zs || '0s' };
  I.halbring([xb, 0, 0], [1, 0, 0], R + 0.9, { st: IKF.Y, sw: 3.4, d: o.d || 1, pl: 1, cls: 'zd', sty: z });
  I.halbring([xb - 1.9, 0, 0], [1, 0, 0], R + 0.25, { st: IKF.B, sw: 0.8, d: (o.d || 1) + 0.05, pl: 1, cls: 'zd', sty: z });
  I.halbring([xb + 1.9, 0, 0], [1, 0, 0], R + 0.25, { st: IKF.B, sw: 0.8, d: (o.d || 1) + 0.05, pl: 1, cls: 'zd', sty: z });
}
/* Oberwalze auf ihrer Welle (parallel zur Rohrachse, aus der Maschine rechts) */
function ikOberwalze(I, R, x1, xb, o) {
  o = o || {};
  var ru = 5.5, zo = R + ru + 0.7;
  I.zyl([xb - 2.5, 0, zo], [xb + 2.5, 0, zo], ru, { d: 3, cls: o.cls, sty: o.sty });
  I.zyl([xb + 2.5, 0, zo], [x1 + 22, 0, zo], 1.7, { d: 3.1, ende: false, cls: o.cls, sty: o.sty });
}



/* ---------- Prozess-Symbole: weitere Verfahren ---------- */
/* Bildschirmebene (fuer Lupen): Punkt c plus x nach rechts, y nach unten */
var SXV = [0.5 / C30, -0.5 / C30, 0], SYV = [1, 1, 0];
function S2(c, x, y) { return ad(ad(c, mu(SXV, x)), mu(SYV, y)); }
function ringPfad(I, c, ax, r0, r1, f, o) {
  var b = ikBasis(ax), a = ikKreis(c, b[1], b[2], r1, 40).map(PQ), i2 = ikKreis(c, b[1], b[2], r0, 40).map(PQ);
  return I.add(I.tiefe([c], o || {}), { d: pfad(a, 1) + pfad(i2, 1), fill: f, 'fill-rule': 'evenodd', stroke: IKF.B, 'stroke-width': 1.3 }, ext({ pts: a }, o || {}));
}
function mvSty(v, zs0, mt) { var q = PQ(v); return { '--mx': f1(q[0]) + 'px', '--my': f1(q[1]) + 'px', '--zs': (zs0 || 0) + 's', '--mt': (mt || 0.9) + 's' }; }

/* P01 Abwicklung, CAD: Abwicklung zeichnet sich auf dem Bildschirm, ein Etikett kommt heraus */
PSYM.P01 = { f: function (I) {
  var W = 62, T = 3, H = 40, z0 = 10;
  I.box(-14, -8, 0, 28, 14, 2, { d: -2 }); I.box(-3, -3, 2, 6, 4, 8, { d: -1 });
  I.box(-W / 2, 0, z0, W, T, H, { d: 0 });
  function S(x, z) { return [x, T + 0.1, z]; }
  I.poly([S(-W / 2 + 3, z0 + 3), S(W / 2 - 3, z0 + 3), S(W / 2 - 3, z0 + H - 3), S(-W / 2 + 3, z0 + H - 3)], IKF.W, { d: 1, sw: 1.2 });
  var x0 = -22, x1 = 20, za = z0 + 11, zb = z0 + 29;
  ikStrich(I, [S(x0, za), S(x1, za), S(x1, zb), S(x0, zb), S(x0, za)], { d: 2, pl: 1, sw: 2.2, cls: 'zd', sty: { '--zt': '1.1s' } });
  each([-11.5, -1, 9.5], function (x) { I.line([S(x, za), S(x, zb)], { d: 2.1, sw: 1, da: '2 2', cls: 'zi', sty: zs(1.15) }); });
  I.line([S(x1, za + 3), S(x1 + 3, za + 5), S(x1 + 3, zb - 5), S(x1, zb - 3)], { d: 2.1, sw: 1, cls: 'zi', sty: zs(1.15) });
  I.box(W / 2 + 4, -2, 0, 15, 12, 9, { d: 3 });
  I.box(W / 2 + 6, 10, 2.5, 11, 10, 0.6, { d: 3.5, ft: IKF.W, cls: 'zw', sty: mvSty([0, -10, 0], 1.25, 0.6) });
  I.ex.push([W / 2 + 6, 20, 0]);
} };
/* P04d Kreuzbruch: Blech knickt flach entlang der Diagonalen, ein X entsteht */
PSYM.P04d = { dt: 0.3, f: function (I) {
  var a = 34, b = 24, t = 1.5;
  I.poly([[-a, b, 0], [a, b, 0], [a, b, t], [-a, b, t]], IKF.L, { d: 0.5 });
  I.poly([[a, -b, 0], [a, b, 0], [a, b, t], [a, -b, t]], IKF.R, { d: 0.5 });
  var F = ['#E3E9F0', '#EEF2F7', '#D7DFE9', '#E8EDF3'];
  I.folge(3, function (k, s) {
    var c = [0, 0, t + 5 * s], E = [[-a, -b, t], [a, -b, t], [a, b, t], [-a, b, t]];
    for (var i = 0; i !== 4; i++) { I.poly([E[i], E[(i + 1) % 4], c], s ? F[i] : IKF.T, { d: 1 + i * 0.01 }); }
  });
  ikStrich(I, [[-a, -b, t + 0.1], [0, 0, t + 5.1], [a, b, t + 0.1]], { d: 3, pl: 1, cls: 'zd', sty: { '--zt': '.7s', '--zs': '.5s' } });
  ikStrich(I, [[a, -b, t + 0.1], [0, 0, t + 5.1], [-a, b, t + 0.1]], { d: 3, pl: 1, cls: 'zd', sty: { '--zt': '.7s', '--zs': '.5s' } });
} };
/* P05 Ausklinken, Lochen: Stempel stoesst, Ecke faellt heraus */
PSYM.P05 = { f: function (I) {
  var t = 2.2, c = 13, X = 30, Y = 24;
  I.box(-40, -26, -7, 74, 54, 7, { d: 0, ft: IKF.I });
  I.poly([[-36, -Y, t], [X, -Y, t], [X, Y - c, t], [X - c, Y - c, t], [X - c, Y, t], [-36, Y, t]], IKF.T, { d: 1 });
  I.poly([[-36, Y, 0], [X - c, Y, 0], [X - c, Y, t], [-36, Y, t]], IKF.L, { d: 1.1 });
  I.poly([[X, -Y, 0], [X, Y - c, 0], [X, Y - c, t], [X, -Y, t]], IKF.R, { d: 1.1 });
  I.poly([[X - c, Y - c, 0], [X, Y - c, 0], [X, Y - c, t], [X - c, Y - c, t]], IKF.L, { d: 1.2 });
  I.poly([[X - c, Y - c, 0], [X - c, Y, 0], [X - c, Y, t], [X - c, Y - c, t]], IKF.R, { d: 1.2 });
  I.box(X - c, Y - c, 0, c, c, t, { d: 2, cls: 'zv', sty: { '--zs': '.7s', '--my': '11px', '--mt': '.45s' } });
  I.box(X - c - 1, Y - c - 1, t + 5, c + 2, c + 2, 16, { d: 5, cls: 'zu', sty: { '--my': '5px', '--mt': '1s' } });
  I.ex.push([X, Y, -12]);
} };
/* P08 Rotationsschneiden: Rohr dreht, Brenner schneidet das Abzweigloch */
PSYM.P08 = { f: function (I) {
  var R = 15, L = 40, rb = 8, q = [];
  I.zyl([-L, 0, 0], [L, 0, 0], R, { d: 0, offen: 1 });
  ikDreh(I, [L, 0, 0], [1, 0, 0], R - 6, { d: 0.5, sw: 0.9, da: '3 5' });
  for (var i = 0; i !== 49; i++) { var a = 2 * Math.PI * i / 48, y = rb * Math.sin(a); q.push([rb * Math.cos(a) - 6, y, Math.sqrt(R * R - y * y) + 0.1]); }
  ikStrich(I, q, { d: 1, pl: 1, cls: 'zd', sty: { '--zt': '1.6s' } });
  I.zyl([2, 0, R + 6], [2, 0, R + 26], 4, { d: 3 });
  I.zyl([2, 0, R + 1.5], [2, 0, R + 6], 2.1, { d: 2.9, ende: false });
  I.line([[2, 0, R + 1.5], [2, 0, R]], { st: IKF.Y, sw: 2.4, d: 2.8, cls: 'zf' });
} };
/* Hilfen: blasser Coil als Hinweis auf die Laufrichtung des Coils; Pfeil fuer die Laufrichtung des Werkstuecks */
function ikCoilHinweis(I, c, ax, R, L, o) {
  o = o || {};
  var b = ikBasis(ax), c0 = ad(c, mu(b[0], -L / 2)), c1 = ad(c, mu(b[0], L / 2)), d = o.d === undefined ? -3 : o.d, H = '#A9B6C4';
  I.zyl(c0, c1, R, { d: d, f: '#F3F5F8', fe: '#F7F9FB', st: H, sw: 1.1 });
  I.line(ikKreis(c1, b[1], b[2], R * 0.45, 30), { d: d + 0.02, sw: 0.8, st: H });
}
function ikPfeil(I, p0, p1, o) {
  o = o || {};
  var v = nz(sb(p1, p0)), q = o.q || [0, 0, 1], n = nz(cr(v, q)), L = o.L || 4.2, W = o.W || 2.3, d = o.d || 6;
  I.line([p0, ad(p1, mu(v, -L * 0.6))], { d: d, sw: o.sw || 1.5, st: o.st || IKF.B, cls: o.cls, sty: o.sty });
  I.poly([p1, ad(sb(p1, mu(v, L)), mu(n, W)), sb(sb(p1, mu(v, L)), mu(n, W))], o.st || IKF.B, { d: d + 0.01, sw: 0.6, st: o.st || IKF.B, cls: o.cls, sty: o.sty });
}
/* Kurzes Rollenpaar (Achse ax) ueber und unter dem Blech: oben bei zo, unten bei zu */
function ikRollenpaar(I, c, ax, r, L, zo, zu, o) {
  o = o || {};
  var b = nz(ax), h = mu(b, L / 2), d = o.d || 3;
  I.zyl(sb([c[0], c[1], zu], h), ad([c[0], c[1], zu], h), r, { d: o.du === undefined ? -1 : o.du });
  I.zyl(sb([c[0], c[1], zo], h), ad([c[0], c[1], zo], h), r, { d: d });
  var e = gt(dt(b, VV), 0) ? h : mu(h, -1);
  ikDreh(I, ad([c[0], c[1], zo], e), b, r * 0.55, { d: d + 0.05, sw: 0.9, da: '2 2.5' });
}
/* P16 Eckwinkel, Rahmen aufstecken: Eckwinkel gleitet ins Profil, der Rahmen schiebt sich aufs Kanalende */
PSYM.P16 = { css: '@keyframes wpsP16{0%{transform:translate(var(--ax),var(--ay))}35%,50%{transform:translate(var(--mx),var(--my))}100%{transform:translate(0,0)}}@keyframes wpsP16f{0%,50%{transform:translate(var(--mx),var(--my))}100%{transform:translate(0,0)}}.wps.go .p16e{animation:wpsB .35s ease-out calc(var(--n) * var(--bs)) both,wpsP16 2s ease-in-out var(--bt) both}.wps.go .p16f{animation:wpsB .35s ease-out calc(var(--n) * var(--bs)) both,wpsP16f 2s ease-in-out var(--bt) both}', f: function (I) {
  var L = 36, w = 17, h = 12, f = 3.5, tt = 5;
  I.poly([[-L, -w, h], [0, -w, h], [0, w, h], [-L, w, h]], IKF.T, { d: 0 });
  I.poly([[-L, w, -h], [0, w, -h], [0, w, h], [-L, w, h]], IKF.L, { d: 0.1 });
  I.poly([[0, -w, -h], [0, w, -h], [0, w, h], [0, -w, h]], '#E3E9F0', { d: 0.2 });
  /* offenes Kanalende: Blick ins Innere (Dimi 09.11.2026) */
  I.innen([[0, -w + 1.5, -h + 1.5], [0, w - 1.5, -h + 1.5], [0, w - 1.5, h - 1.5], [0, -w + 1.5, h - 1.5]], [-1, 0, 0], L, 0.25, { m: h });
  var mv = mvSty([16, 0, 0], 0, 2), xo = 0.2;
  var W2 = w + f, H2 = h + f;
  I.mit('p16f', function () {
    I.poly([[-tt, -W2, H2], [xo, -W2, H2], [xo, W2, H2], [-tt, W2, H2]], IKF.T, { d: 3, sty: mv });
    I.poly([[-tt, W2, -H2], [xo, W2, -H2], [xo, W2, H2], [-tt, W2, H2]], IKF.L, { d: 3.1, sty: mv });
    var O = [[xo, -W2, -H2], [xo, W2, -H2], [xo, W2, H2], [xo, -W2, H2]], In = [[xo, -w, -h], [xo, w, -h], [xo, w, h], [xo, -w, h]];
    for (var k = 0; k !== 4; k++) { I.poly([O[k], O[(k + 1) % 4], In[(k + 1) % 4], In[k]], IKF.R, { d: 3.2, sty: mv }); }
    each([[-1, -1], [-1, 1], [1, 1]], function (sg) { var y = sg[0] * (w + f / 2), z = sg[1] * (h + f / 2); I.poly([[xo + 0.1, y - 1.8, z - 1.8], [xo + 0.1, y + 1.8, z - 1.8], [xo + 0.1, y + 1.8, z + 1.8], [xo + 0.1, y - 1.8, z + 1.8]], '#5A6472', { d: 3.3, sty: mv, sw: 1 }); });
  });
  var y = w + f / 2, z = -(h + f / 2), q = PQ([0, 9, 0]), m = PQ([16, 0, 0]);
  I.poly([[xo + 0.1, y - 1.8, z - 1.8], [xo + 0.1, y + 1.8, z - 1.8], [xo + 0.1, y + 1.8, z + 1.8], [xo + 0.1, y - 1.8, z + 1.8]], IKF.Y, { d: 3.4, sw: 1, cls: 'p16e', sty: { '--mx': f1(m[0]) + 'px', '--my': f1(m[1]) + 'px', '--ax': f1(m[0] + q[0]) + 'px', '--ay': f1(m[1] + q[1]) + 'px' } });
  I.ex.push([16, -W2, H2], [16, W2 + 9, -H2]);
} };
/* P18 Wickeln: Band laeuft im Steigungswinkel von der Seite in den Formkopf, das Rohr waechst schraubenfoermig.
   Schraubenlinie in Weltkoordinaten linksgaengig; die Iso-Abbildung spiegelt, am Bildschirm erscheint sie rechtsgaengig wie das echte Rohr.
   Das Band trifft tangential unten auf das Rohr, Richtung = Tangente der Schraubenlinie dort. */
/* P18 (Wickelfalzrohrmaschine): Zeichnung in 62_anlagen.js; die fruehere Fassung an dieser Stelle war ueberschrieben und ist entfernt (Runde 18) */
/* P19 Fliegend trennen: Messer faehrt mit, das Rohr loest sich */
PSYM.P19 = { f: function (I) {
  var R = 13, xc = 4;
  I.zyl([-44, 0, 0], [xc - 0.3, 0, 0], R, { d: 0, offen: 1 });
  I.zyl([xc + 0.3, 0, 0], [40, 0, 0], R, { d: 0.5, offen: 1, cls: 'zv', sty: mvSty([9, 0, 0], 1.3, 0.6) });
  I.halbring([xc, 0, 0], [1, 0, 0], R + 0.3, { st: IKF.Y, sw: 2.6, d: 1, pl: 1, cls: 'zd', sty: { '--zt': '.8s', '--zs': '.35s' } });
  var c = [xc, 0, R + 9], m = mvSty([7, 0, -3], 0, 1.3);
  I.poly(ikKreis(c, [0, 1, 0], [0, 0, 1], 8, 24), IKF.R, { d: 3, cls: 'zu', sty: m });
  I.poly(ikKreis(c, [0, 1, 0], [0, 0, 1], 2.2, 12), IKF.W, { d: 3.1, cls: 'zu', sty: m });
  /* Halter bis zur Nabe (Achse der Trennscheibe), vor der Scheibe gezeichnet (Pruefung 09.11.2026) */
  I.line([c, ad(c, [0, 0, 16])], { d: 3.2, sw: 3, cls: 'zu', sty: m });
  I.ex.push([49, 0, -R]);
} };
/* P20 Rollennahtschweissen mit Drahtelektrode (Fable Runde 17, Dimi 11.11.2026: Rollnaht mit Drahtelektrode, Drahtschweissmaschine):
   die Blechkanten ueberlappen wenige Millimeter; zwischen jeder Elektrodenrolle und dem Blech laeuft ein Draht als
   Zwischenelektrode mit (oben sichtbar: er kommt von hinten, laeuft unter der Rolle durch und wieder weg). Die Rollen laufen ueber
   die Ueberlappung, dahinter liegt die durchgehende Naht. Lupe: Schnitt durch die Naht (Rollen, Draehte, Ueberlappung, Schweisslinse) */
PSYM.P20 = { dt: 0.17, f: function (I) {
  var t = 2, N = 10, R = 7, xs = 2, zc = 2 * t + R + 0.9, Rw = R + 0.5;
  ikHalten(I, N * 0.17 + 1.4);
  I.box(-36, -24, 0, 44, 48, t, { d: 0 });
  I.box(-4, -24, t, 40, 48, t, { d: 1 });
  ikStrich(I, [[xs, -22, 2 * t + 0.05], [xs, 22, 2 * t + 0.05]], { d: 2, pl: 1, sw: 2.8, cls: 'zd', sty: { '--zt': (N * 0.17) + 's' } });
  I.folge(N + 1, function (k) {
    var y = -22 + 44 * k / N, W = [], i;
    I.zyl([xs - 2.5, y, -R - 0.9], [xs + 2.5, y, -R - 0.9], R, { d: -1 });
    I.zyl([xs - 2.5, y, zc], [xs + 2.5, y, zc], R, { d: 5 });
    I.poly(ikKreis([xs + 2.6, y, zc], [0, 1, 0], [0, 0, 1], 2, 12), IKF.W, { d: 5.1, sw: 1 });
    /* Drahtelektrode: tangential von hinten oben, unter der Rolle durch, nach vorn oben weg */
    function pk(g) { var f = g * Math.PI / 180; return [xs, y + Rw * Math.cos(f), zc + Rw * Math.sin(f)]; }
    var p0 = pk(205), p1 = pk(335);
    W.push([xs, p0[1] - 4.65, p0[2] + 9.97]);
    for (i = 0; i !== 14; i++) { W.push(pk(205 + 130 * i / 13)); }
    W.push([xs, p1[1] + 4.65, p1[2] + 9.97]);
    I.line(W, { d: 5.2, sw: 3, st: IKF.W }); I.line(W, { d: 5.25, sw: 1.5, st: IKF.G });
  });
  ikLupe(I, [44, -34, 26], 13, N + 1, function (P, k) {
    var an = !lt(k, 3);
    I.poly(ikKreis2(P, 0, -8.6, 4.4), '#DCE4EE', { d: 20.1, sw: 1 }); I.poly(ikKreis2(P, 0, 8.6, 4.4), '#DCE4EE', { d: 20.1, sw: 1 });
    ikBlech2(I, P, [[-11.6, 1.2], [3.6, 1.2]], 2, 20.2, { f: '#EEF2F7' });
    ikBlech2(I, P, [[-3.6, -1.2], [11.6, -1.2]], 2, 20.21, { f: '#EEF2F7' });
    I.poly(ikKreis2(P, 0, -3.3, 1.15), IKF.G, { d: 20.3, sw: 0.6 }); I.poly(ikKreis2(P, 0, 3.3, 1.15), IKF.G, { d: 20.3, sw: 0.6 });
    if (an) { I.poly(ikEllipse2(P, 0, 0, 2.7, 1.5), IKF.Y, { d: 20.35, sw: 0.7 }); }
  }, { von: [xs, 6, 2 * t + 1] });
  I.ex.push([xs, -34, zc + R + 8], [xs, 36, zc + R + 8]);
} };
/* Kreis und Ellipse in der Lupe (2D) */
function ikKreis2(P, x, y, r) { var q = []; for (var i = 0; i !== 20; i++) { var a = 2 * Math.PI * i / 20; q.push(P(x + r * Math.cos(a), y + r * Math.sin(a))); } return q; }
function ikEllipse2(P, x, y, rx, ry) { var q = []; for (var i = 0; i !== 20; i++) { var a = 2 * Math.PI * i / 20; q.push(P(x + rx * Math.cos(a), y + ry * Math.sin(a))); } return q; }
/* Stehfalz am Segmentbogen (Fable Runde 17, nach der Betriebsanleitung der Segmentbogenmaschine, Abschnitte „Einfachen und
   doppelten Bord profilieren“ und „Falz schliessen“; Runde 18 von Dimi bestaetigt): Ein Segment bekommt eine Boerdelung 90 Grad,
   sie bleibt stehen. Das Gegenstueck bekommt eine Doppelboerdelung, die wie eine Stufe aussieht (90 Grad nach aussen, dann wieder
   in Rohrrichtung). Beide werden ineinandergelegt, dann wird die Stufenboerdelung um die 90-Grad-Boerdelung umgeschlagen und
   verpresst. Der fertige Falz steht als schmale Rippe rund um das Rohr.
   Lupe (Schnitt durch die Rohrwand): x laengs zum Rohr, y nach innen (oben ist aussen). SEGF: Hoehe des Bords, Lage der Bleche */
var SEGF = { h: 5.2, l: 3.3, sc: 1.5 };
/* Lage in der Lupe: vergroessert, Rohrwand am Lupenrand abgeschnitten */
function segT(q) { return [Math.max(-11.9, Math.min(11.9, q[0] * SEGF.sc)), q[1] * SEGF.sc + 1.2]; }
/* Mittellinien: doppelter Bord (links; o = 1 offen, Lippe in Rohrrichtung; o = 0 Lippe umgelegt; g Lagenabstand; dx Versatz),
   einfacher Bord (rechts; dx Abstand vor dem Einlegen) */
function segDoppel(o, g, dx) {
  var h = SEGF.h, x = dx || 0;
  return (o ? [[-12, 1.6], [x, 1.6], [x, 1.6 - h], [x + SEGF.l, 1.6 - h]] : [[-12, 1.6], [x, 1.6], [x, 1.6 - h], [x + 2 * g, 1.6 - h], [x + 2 * g, 1.6 - h + 3.6]]).map(segT);
}
function segEinfach(dx, g) { return [[12, 1.6], [g + dx, 1.6], [g + dx, 1.6 - SEGF.h + 0.95]].map(segT); }
/* Segment eines Segmentbogens (Runde 18, Dimi 11.11.2026: in den Ablaeufen Segmente zeichnen, kein Rohr): Zylinder um die Achse
   p0-p1 (Radius R), an beiden Enden schraeg geschnitten. n0 und n1 sind die Normalen der Schnittebenen durch p0 und p1, nach
   aussen (vom Segment weg). Umriss als Huelle beider Schnittkurven; das zum Betrachter zeigende Ende ist offen mit Blick ins
   Innere (o.ende false: ohne). Rueckgabe: k0, k1 Schnittkurven (3D), d Tiefe */
var SEG_W = 11.25 * Math.PI / 180;
function ikSeg(I, p0, p1, R, n0, n1, o) {
  o = o || {};
  var a = nz(sb(p1, p0)), b = ikBasis(a), k0 = [], k1 = [], ki = [], n = 40, i;
  var vorn = gt(dt(n1, VV), dt(n0, VV)), ce = vorn ? p1 : p0;
  for (i = 0; i !== n; i++) {
    var t = 2 * Math.PI * i / n, q = ad(p0, ad(mu(b[1], R * Math.cos(t)), mu(b[2], R * Math.sin(t))));
    k0.push(ad(q, mu(a, -dt(sb(q, p0), n0) / dt(a, n0)))); k1.push(ad(q, mu(a, dt(sb(p1, q), n1) / dt(a, n1))));
  }
  var d = I.tiefe([p0, p1], o), h = huelle(k0.concat(k1).map(PQ)), ke = vorn ? k1 : k0;
  I.add(d, { d: pfad(h, 1), fill: o.f || IKF.L, stroke: IKF.B, 'stroke-width': o.sw || 1.5 }, { cls: o.cls, pts: h, sty: o.sty });
  if (o.ende !== false) {
    if (gt(dt(vorn ? n1 : n0, VV), 0.02)) {
      var pe = ke.map(PQ), wd = Math.max(1.1, R * 0.09);
      I.add(d + 0.01, { d: pfad(pe, 1), fill: '#E3E9F0', stroke: IKF.B, 'stroke-width': o.sw || 1.5 }, { cls: o.cls, pts: pe, sty: o.sty });
      each(ke, function (q) { ki.push(ad(ce, mu(sb(q, ce), (R - wd) / R))); });
      I.innen(ki, vorn ? mu(a, -1) : a, o.durch ? len(sb(p1, p0)) : 1e6, d + 0.02, { m: R, cls: o.cls, sty: o.sty });
    }
  }
  return { k0: k0, k1: k1, d: d, vorn: vorn };
}
/* Bord an einem schraegen Segmentende: Ring in der Schnittebene zwischen der Schnittkurve k (Mitte c) und der um f vergroesserten Kurve */
function ikSegBord(I, k, c, f, farbe, o) {
  o = o || {};
  var au = k.map(function (q) { return PQ(ad(c, mu(sb(q, c), f))); }), inn = k.map(PQ);
  return I.add(I.tiefe([c], o), { d: pfad(au, 1) + pfad(inn, 1), fill: farbe, 'fill-rule': 'evenodd', stroke: IKF.B, 'stroke-width': 1.3 }, { pts: au, cls: o.cls, sty: o.sty });
}
/* P22 Segment boerdeln (Runde 18): ein Segment (schraeg geschnitten) dreht an den Profilierrollen, an der Schnittkante stellt sich der
   schmale Bord auf. Lupe: erst die Boerdelung 90 Grad (sie bleibt stehen), am Gegenstueck die Doppelboerdelung, die wie eine Stufe aussieht */
PSYM.P22 = { dt: 0.45, f: function (I) {
  var R = 16, L = 21, N = 4, hb = 3.4, w = SEG_W, n1 = [Math.cos(w), 0, Math.sin(w)], n0 = [-Math.cos(w), 0, Math.sin(w)];
  ikHalten(I, (N - 1) * 0.45 + 1.4);
  var S = ikSeg(I, [-L, 0, 0], [0, 0, 0], R, n0, n1, { d: 0 });
  I.folge(N, function (k, s) { if (k) { ikSegBord(I, S.k1, [0, 0, 0], 1 + hb * Math.min(1, s * 1.5) / R, k === N - 1 ? IKF.Y : IKF.R, { d: 1 }); } });
  ikDreh(I, [0, 0, 0], n1, R - 6, { d: 2, sw: 0.9, da: '3 5' });
  /* Profilierrolle aussen am Bord (oben an der kurzen Seite), Welle aus der Maschine rechts */
  var ru = 4.2, xo = -R * Math.tan(w), zo = R + ru + 0.5;
  I.zyl([xo - 4.4, 0, zo], [xo - 0.4, 0, zo], ru, { d: 3 });
  I.zyl([xo - 0.4, 0, zo], [xo + 16, 0, zo], 1.4, { d: 3.1, ende: false });
  ikLupe(I, [40, -30, 24], 13, N, function (P, k) {
    var D = k === 0 ? [[-12, 1.6], [-0.8, 1.6]].map(segT) : (k === 1 ? [[-12, 1.6], [-3, 1.6], [-3, 1.6 - SEGF.h]].map(segT) : segDoppel(1, 0, -3));
    var E = k === 0 ? [[12, 1.6], [1.4, 1.6]].map(segT) : segEinfach(3.4, 0);
    ikBlech2(I, P, D, 1.5, 20.2, { f: '#EEF2F7' });
    ikBlech2(I, P, E, 1.5, 20.21, { f: '#EEF2F7' });
    if (k === N - 1) { ikBlech2(I, P, D.slice(1), 1.5, 20.3, { f: IKF.Y }); ikBlech2(I, P, E.slice(1), 1.5, 20.31, { f: IKF.Y }); }
  }, { von: [xo, 0, R + hb] });
} };
/* P23 Segmente schliessen in drei Schritten (Runde 18, Dimi 11.11.2026): 1 ineinanderlegen (die Boerdelung 90 Grad des einen Segments
   liegt in der Stufe der Doppelboerdelung des anderen), 2 die Stufenboerdelung wird um die 90-Grad-Boerdelung umgeschlagen, 3 verpresst.
   Die 90-Grad-Boerdelung bleibt stehen, der Falz steht als Rippe zwischen den Segmenten. Ansicht: zwei Segmente im Winkel (wie im
   Bogen), die Druckrolle laeuft entlang der Umfangsnaht, die Segmente drehen. */
PSYM.P23 = { dt: 0.75, f: function (I) {
  var R = 15, N = 3, hr = 3.2, w = SEG_W, c = Math.cos(w), sn = Math.sin(w);
  ikHalten(I, (N - 1) * 0.75 + 1.6);
  var nj = [c, sn, 0], a2 = [Math.cos(2 * w), Math.sin(2 * w), 0], p2 = mu(a2, 24), n2 = [Math.cos(3 * w), Math.sin(3 * w), 0];
  ikSeg(I, [-27, 0, 0], [0, 0, 0], R, [-c, sn, 0], nj, { d: 0, ende: false });
  ikSeg(I, [0, 0, 0], p2, R, mu(nj, -1), n2, { d: 1 });
  ikDreh(I, p2, n2, R - 6, { d: 1.5, sw: 0.9, da: '3 5' });
  I.folge(N, function (k) {
    /* Rippe: offen breiter (die Stufe steht noch in Rohrrichtung), umgeschlagen schmal, am Ende gelb */
    var b = k === 0 ? 6.4 : 4.6, x = k === 0 ? 0.9 : 0.4;
    I.halbring(mu(nj, x), nj, R + hr / 2, { st: IKF.B, sw: b + hr, d: 2 });
    I.halbring(mu(nj, x), nj, R + hr / 2, { st: k === 2 ? IKF.Y : IKF.R, sw: b + hr - 2.6, d: 2.05 });
  });
  /* Druckrolle ueber dem Falz, Welle quer zur Naht */
  var ru = 4.6, zo = [0, 0, R + hr + ru + 0.9];
  I.zyl(ad(zo, mu(nj, -2)), ad(zo, mu(nj, 2.8)), ru, { d: 3 });
  I.zyl(ad(zo, mu(nj, 2.8)), ad(zo, mu(nj, 21)), 1.5, { d: 3.1, ende: false });
  ikLupe(I, [44, -30, 26], 13, N, function (P, k) {
    var g = k === 2 ? 1.05 : 1.3, D = segDoppel(k === 0 ? 1 : 0, g, -1), E = segEinfach(k === 0 ? -0.4 : -1, g);
    ikBlech2(I, P, D, 1.5, 20.2, { f: '#EEF2F7' });
    ikBlech2(I, P, E, 1.5, 20.21, { f: '#EEF2F7' });
    if (k === 0) { pfeil2(I, P, segT([7.4, -1.6]), segT([3.6, -1.6]), 20.3); }
    if (k === 1) { ikBlech2(I, P, D.slice(2), 1.5, 20.3, { f: IKF.Y }); pfeil2(I, P, segT([4.4, -6.4]), segT([4.4, -3.2]), 20.3); }
    if (k === 2) {
      ikBlech2(I, P, D.slice(1), 1.5, 20.3, { f: IKF.Y }); ikBlech2(I, P, E.slice(1), 1.5, 20.31, { f: IKF.Y });
      pfeil2(I, P, segT([-5.6, -1.9]), segT([-2.1, -1.9]), 20.4); pfeil2(I, P, segT([5.8, -1.9]), segT([2.3, -1.9]), 20.4);
    }
  }, { von: [0.4, 0, R + hr] });
} };
/* Pfeil in der Lupe (2D): Linie von a nach b mit Spitze; o.L, o.W Groesse der Spitze, o.sw Strichstaerke */
function pfeil2(I, P, a, b, d, o) {
  o = o || {};
  var dx = b[0] - a[0], dy = b[1] - a[1], l = Math.sqrt(dx * dx + dy * dy), ux = dx / l, uy = dy / l, L = o.L || 1.9, W = o.W || 1.1;
  ikLinie2(I, P, [a, [b[0] - ux * L * 0.6, b[1] - uy * L * 0.6]], d, { sw: o.sw || 1.2, st: o.st || IKF.B });
  ikPoly2(I, P, [b, [b[0] - ux * L - uy * W, b[1] - uy * L + ux * W], [b[0] - ux * L + uy * W, b[1] - uy * L - ux * W]], o.st || IKF.B, d + 0.01, { sw: 0.6, st: o.st || IKF.B });
}
/* Blech mit Dicke in der Lupe (Dimis Stil: Doppellinie, gerundete Biegungen): Mittellinie pts (2D), Dicke t:
   Umriss als Polygon (Gehrung begrenzt); doppelte Punkte werden uebersprungen */
function ikNorm2(a, b) { var dx = b[0] - a[0], dy = b[1] - a[1], l = Math.sqrt(dx * dx + dy * dy) || 1; return [-dy / l, dx / l]; }
function ikBand2(pts, t) {
  var q = [], i;
  for (i = 0; i !== pts.length; i++) { if (i) { var dx = pts[i][0] - pts[i - 1][0], dy = pts[i][1] - pts[i - 1][1]; if (lt(dx * dx + dy * dy, 1e-8)) { continue; } } q.push(pts[i]); }
  var n = q.length, L = [], R = [], h = t / 2;
  for (i = 0; i !== n; i++) {
    var n1 = i ? ikNorm2(q[i - 1], q[i]) : null, n2 = (i !== n - 1) ? ikNorm2(q[i], q[i + 1]) : null;
    var nn = n1 ? (n2 ? [n1[0] + n2[0], n1[1] + n2[1]] : n1) : n2, l = Math.sqrt(nn[0] * nn[0] + nn[1] * nn[1]);
    if (lt(l, 1e-6)) { nn = n1; l = 1; }
    nn = [nn[0] / l, nn[1] / l];
    var c = n1 ? Math.abs(n1[0] * nn[0] + n1[1] * nn[1]) : 1, m = h / Math.max(c, 0.4);
    L.push([q[i][0] + nn[0] * m, q[i][1] + nn[1] * m]); R.push([q[i][0] - nn[0] * m, q[i][1] - nn[1] * m]);
  }
  return L.concat(R.reverse());
}
function ikBlech2(I, P, pts, t, d, o) {
  o = o || {};
  return I.poly(ikBand2(pts, t).map(function (q) { return P(q[0], q[1]); }), o.f || '#EEF2F7', ext({ d: d, sw: o.sw || 1 }, o));
}
/* P26 Lippendichtung (Gasket Shaper), Dimi 09.11.2026: kurzer Ring statt langem Rohr, die Lupe (Schnitt durch die Wand)
   ist das Wichtigste und deshalb gross, der Ablauf langsam. 1 Stoppsicke und Dichtungssitz (Universal nacheinander, Automat
   in einem Schritt), 2 Rohrrand 90 Grad nach aussen boerdeln, 3 Dichtung auflegen, 4 Bord um den Dichtungsfuss legen und
   zudruecken. Dichtung beim Automaten vorher aufgelegt und von einer Vorrichtung zum Rohrende geschoben, an der
   Universalmaschine von Hand. Lupe: x zum Rohrende, y nach innen; die Lippe steht nach aussen und zeigt zur Stoppsicke. */
PSYM.P26 = { dt: 1.1, f: function (I) {
  var R = 10, x0 = -4, x1 = 12, xs = x1 - 7.6, xn = x1 - 2.8, N = 5;
  /* das letzte Bild (Bord zugedrueckt) bleibt laenger stehen */
  ikHalten(I, (N - 1) * 1.1 + 1.6);
  I.zyl([x0, 0, 0], [x1, 0, 0], R, { d: 0, hohl: 1, durch: 1 });
  /* Oberwalze passend zum kleinen Ring */
  var ru = 3.6, zo = R + ru + 0.6;
  I.zyl([xs - 1.8, 0, zo], [xs + 1.8, 0, zo], ru, { d: 3 });
  I.zyl([xs + 1.8, 0, zo], [x1 + 12, 0, zo], 1.3, { d: 3.1, ende: false });
  ikDrehPfeil(I, [x1 + 0.5, 0, 0], [1, 0, 0], R + 3.2, Math.PI * 0.12, Math.PI * 0.62, { d: 4 });
  /* Ring in der Ansicht: Sicke und Sitz, Bord, Dichtung, umgelegter Bord */
  I.folge(N, function (k) {
    if (gt(k, 0)) {
      I.halbring([xs, 0, 0], [1, 0, 0], R + 0.8, { st: IKF.W, sw: 2.6, d: 1 });
      I.halbring([xs - 1.3, 0, 0], [1, 0, 0], R + 0.3, { d: 1.05, sw: 0.8 });
      I.halbring([xs + 1.3, 0, 0], [1, 0, 0], R + 0.3, { d: 1.05, sw: 0.8 });
      I.halbring([xn, 0, 0], [1, 0, 0], R - 0.1, { d: 1.05, sw: 0.9, st: IKF.D });
    }
    if (k === 2) { ringPfad(I, [x1 + 0.2, 0, 0], [1, 0, 0], R, R + 2.6, IKF.R, { d: 1.2 }); }
    if (k === 3) {
      ringPfad(I, [x1 + 0.2, 0, 0], [1, 0, 0], R, R + 2.6, IKF.R, { d: 1.2 });
      I.halbring([x1 - 1.6, 0, 0], [1, 0, 0], R + 1.2, { st: IKF.G, sw: 4, d: 1.3 });
      I.halbring([x1 - 4.2, 0, 0], [1, 0, 0], R + 2.4, { st: IKF.G, sw: 1.4, d: 1.35 });
    }
    if (k === 4) {
      I.halbring([x1 - 4.2, 0, 0], [1, 0, 0], R + 2.4, { st: IKF.G, sw: 1.4, d: 1.3 });
      I.halbring([x1 - 1.6, 0, 0], [1, 0, 0], R + 1.1, { st: IKF.G, sw: 3.4, d: 1.32 });
      I.halbring([x1 - 1, 0, 0], [1, 0, 0], R + 2, { st: IKF.B, sw: 3.8, d: 1.4 });
      I.halbring([x1 - 1, 0, 0], [1, 0, 0], R + 2, { st: IKF.Y, sw: 2.2, d: 1.45 });
    }
  });
  /* Lupe gross: Ausschnitt um Sicke und Dichtungssitz (T vergroessert), Walzen am Lupenrand abgeschnitten */
  var RL = 24, Rc = RL - 0.9, sk = 2.45, tw = 0.7;
  function T(q) { return [sk * (q[0] - 0.5), sk * (q[1] + 2.2)]; }
  function zumRand(q, li) { return [(li ? -1 : 1) * Math.sqrt(Math.max(Rc * Rc - q[1] * q[1], 0)), q[1]]; }
  function walze(prof, oben) {
    var p = prof.map(T); p[0] = zumRand(p[0], 1); p[p.length - 1] = zumRand(p[p.length - 1], 0);
    var a0 = Math.atan2(p[p.length - 1][1], p[p.length - 1][0]), a1 = Math.atan2(p[0][1], p[0][0]);
    if (oben) { if (gt(a1, a0)) { a1 -= 2 * Math.PI; } } else { if (lt(a1, a0)) { a1 += 2 * Math.PI; } }
    for (var i = 1; i !== 16; i++) { var a = a0 + (a1 - a0) * i / 16; p.push([Rc * Math.cos(a), Rc * Math.sin(a)]); }
    return p;
  }
  var W0 = [[-9.4, 0], [-7.6, 0], [-6.8, -1.9], [-5, -1.9], [-4.2, 0], [-0.6, 0], [0, 1.3], [2.2, 1.3], [2.8, 0]];
  var FL = [[4.6, 0], [5, -0.4], [5, -3.6]], FU = [[4.6, 0], [5, -0.4], [5, -2.3], [4.6, -2.7], [1.4, -2.7]];
  var FUSS = [[0.3, 1.0], [2, 1.0], [2.6, -0.1], [4.3, -0.1], [4.3, -2.0], [0.1, -2.0], [-0.4, -0.2]];
  var LIPPE = [[-0.4, -1.3], [0.5, -1.9], [-3.4, -5.6], [-4.2, -5.0]];
  function wand(k) {
    var w = (k === 0) ? [[-9.4, 0], [6.6, 0]] : W0.concat(k === 1 ? [[6.6, 0]] : (k === 4 ? FU : FL)), q = w.map(T);
    q[0] = zumRand(q[0], 1); q[0][0] += 0.3;
    if (lt(k, 2)) { q[q.length - 1] = zumRand(q[q.length - 1], 0); q[q.length - 1][0] -= 0.3; }
    return q;
  }
  ikLupe(I, [44, -40, 30], RL, N, function (P, k) {
    if (k === 1) {
      /* Ober- und Unterwalze formen Sicke und Sitz (Schnitt) */
      ikPoly2(I, P, walze([[-9.6, -1.25], [-7.7, -1.25], [-6.8, -3.15], [-5, -3.15], [-4.1, -1.25], [-0.7, -1.25], [0, 0.05], [2.2, 0.05], [2.9, -1.25], [9.6, -1.25]], true), IKF.R, 20.1);
      ikPoly2(I, P, walze([[-9.6, 1.25], [-7.6, 1.25], [-6.8, -0.65], [-5, -0.65], [-4.2, 1.25], [-0.6, 1.25], [0, 2.55], [2.2, 2.55], [2.8, 1.25], [9.6, 1.25]], false), IKF.L, 20.1);
    }
    if (gt(k, 2)) {
      ikPoly2(I, P, (k === 4 ? FUSS.map(function (q) { return [q[0], Math.max(q[1], -1.8)]; }) : FUSS).map(T), IKF.G, 20.15, { st: IKF.G });
      ikPoly2(I, P, LIPPE.map(T), IKF.G, 20.15, { st: IKF.G });
    }
    ikBlech2(I, P, wand(k), tw * sk, 20.2, { f: '#EEF2F7' });
    if (k === 4) { ikBlech2(I, P, FU.slice(1).map(T), tw * sk, 20.25, { f: IKF.Y }); }
    var pa = { L: 3.2, W: 1.8, sw: 1.6 };
    if (k === 2) { pfeil2(I, P, T([7.2, 0.6]), T([7.2, -3.8]), 20.3, pa); }
    if (k === 3) { pfeil2(I, P, T([0.4, -5.6]), T([3.8, -5.6]), 20.3, pa); }
    if (k === 4) { pfeil2(I, P, T([3, -7.2]), T([3, -3.9]), 20.3, pa); }
  }, { von: [x1 - 3, 0, R + 1] });
} };


/* ---------- Ergebnisbilder der Anwendungs-Kacheln (Runde 7): stehen am Ende, bis die Kachel neu startet ---------- */
/* sichtbare Haelfte eines Kreises um die x-Achse als geordnete Liste von Richtungen */
function ikSichtBogen(n, kx) {
  var b = ikBasis([1, 0, 0]), seg = [], cur = [];
  for (var i = 0; i !== n + 1; i++) {
    var t = 2 * Math.PI * i / n, v = ad(mu(b[1], Math.cos(t)), mu(b[2], Math.sin(t)));
    if (gt(dt(v, VV) + (kx || 0) * VV[0], 0)) { cur.push(v); } else { if (gt(cur.length, 1)) { seg.push(cur); } cur = []; }
  }
  if (gt(cur.length, 1)) { seg.push(cur); }
  if (gt(seg.length, 1)) { seg = [seg[seg.length - 1].concat(seg[0])].concat(seg.slice(1, seg.length - 1)); }
  return seg[0] || [];
}
/* verdeckte Haelfte (Gegenstueck zu ikSichtBogen) */
function ikVerdecktBogen(n, kx) {
  var b = ikBasis([1, 0, 0]), seg = [], cur = [];
  for (var i = 0; i !== n + 1; i++) {
    var t = 2 * Math.PI * i / n, v = ad(mu(b[1], Math.cos(t)), mu(b[2], Math.sin(t)));
    if (!gt(dt(v, VV) + (kx || 0) * VV[0], 0)) { cur.push(v); } else { if (gt(cur.length, 1)) { seg.push(cur); } cur = []; }
  }
  if (gt(cur.length, 1)) { seg.push(cur); }
  if (gt(seg.length, 1)) { seg = [seg[seg.length - 1].concat(seg[0])].concat(seg.slice(1, seg.length - 1)); }
  return seg[0] || [];
}
/* Kegel- oder Zylinderband um die x-Achse zwischen (x0, r0) und (x1, r1): vordere Haelfte mit Tiefe d; o.dh: hintere
   Haelfte mit Tiefe o.dh (hinter dem Rohr, sichtbar nur, wo sie ueber den Umriss ragt) */
function ikKegel(I, x0, r0, x1, r1, f, d, o) {
  o = o || {};
  function band(V, ff, dd) { var A = V.map(function (v) { return [x0, v[1] * r0, v[2] * r0]; }), B = V.map(function (v) { return [x1, v[1] * r1, v[2] * r1]; }); return I.poly(A.concat(B.reverse()), ff, ext({ d: dd, sw: 1.1 }, o)); }
  /* sichtbar nach der Kegelnormalen (Radius aendert sich laengs), nicht nach der Zylindernormalen */
  var kx = -(r1 - r0) / ((x1 - x0) || 1);
  if (o.dh !== undefined) { band(ikVerdecktBogen(72, kx), o.fh || f, o.dh); }
  return band(ikSichtBogen(72, kx), f, d);
}
function ikBogenLinie(I, x, r, d, o) {
  return I.line(ikSichtBogen(72).map(function (v) { return [x, v[1] * r, v[2] * r]; }), ext({ d: d }, o || {}));
}
/* Rohrende mit Stoppsicke und Gummi-Lippendichtung (EPDM), Masse relativ zu R; gelb: Kamm der Sicke und Lippenkante */
function ikLippenEnde(I, R, L, d, gelb) {
  var xs = -0.95 * R, w = 0.14 * R, h = 0.08 * R;
  I.zyl([-L, 0, 0], [0, 0, 0], R, { d: d, offen: 1, durch: false, wand: Math.max(0.9, R * 0.05) });
  /* Stoppsicke: aufgewoelbter Ring */
  ikKegel(I, xs - w, R, xs, R + h, IKF.T, d + 0.2, { sw: 0.9, dh: d - 0.3 });
  ikKegel(I, xs, R + h, xs + w, R, '#CBD6E2', d + 0.21, { sw: 0.9, dh: d - 0.29 });
  ikBogenLinie(I, xs, R + h, d + 0.22, gelb ? { st: IKF.Y, sw: 2.2 } : { sw: 0.9 });
  /* Lippe: dunkler Kegel, vom Rohrende nach hinten aussen gerichtet; davor der umgelegte Bord */
  var xl0 = -0.1 * R, xl1 = -0.36 * R, rl1 = R * 1.17;
  ikKegel(I, xl0, R * 1.04, xl1, rl1, '#3A4048', d + 0.005, { st: '#1F2328', sw: 1, dh: d - 0.2, fh: '#2A2F35' });
  ikBogenLinie(I, xl1, rl1, d + 0.006, gelb ? { st: IKF.Y, sw: 2 } : { st: '#1F2328', sw: 1 });
  ikKegel(I, -0.16 * R, R * 1.06, 0, R * 1.06, '#E3E9F0', d + 0.007, { sw: 1 });
}
/* E25 Sicken und Dichten, Ergebnis: Zoom vom ganzen Rohr auf das Rohrende; gross bleiben Stoppsicke und Lippe stehen */
PSYM.E25 = { dt: 0.42, f: function (I) {
  var Rs = [5, 5, 5, 6.6, 8.6, 11.3, 14.6, 18.5], Ls = [46, 46, 46, 44, 43, 42, 41, 40], n = Rs.length;
  I.folge(n, function (k) { ikLippenEnde(I, Rs[k], Ls[k], 1, k === n - 1); });
} };
/* E20 Schweissen, Ergebnis: zwei ueberlappende Blechpaare, hinten gepunktet, vorn mit Rollnaht (Rollennaht- oder
   Drahtschweissen: flache Spur in der Mitte der Ueberlappung, Linsen dicht an dicht). Dimi 09.11.2026 (Runde 10 der
   Antworten): vorher Naht an der Blechkante mit Schuppung, das sah nach Elektrodenschweissen aus */
PSYM.E20 = { f: function (I) {
  var t = 2, ov = 7;
  each([[-34, -8, 0], [8, 34, 1]], function (q) {
    var y0 = q[0], y1 = q[1], dd = q[2] * 10;
    I.box(-36, y0, 0, 36 + ov, y1 - y0, t, { d: dd });
    I.box(-ov, y0, t, 36 + ov, y1 - y0, t, { d: dd + 1 });
    if (q[2] === 0) {
      /* Schweisspunkte nacheinander */
      for (var j = 0; j !== 4; j++) {
        var y = y0 + 4 + j * (y1 - y0 - 8) / 3;
        I.poly(ikKreis([0, y, 2 * t + 0.05], [1, 0, 0], [0, 1, 0], 2.3, 16), IKF.Y, { d: dd + 2, st: '#A97A00', sw: 0.9, cls: 'zp', sty: zs(0.4 + 0.45 * j) });
      }
    } else {
      /* Rollnaht in der Mitte der Ueberlappung, in kurzen Stuecken (Strichlaenge auch in grossen Bildern) */
      for (var g = 0; g !== 6; g++) {
        var ya = y0 + 1 + g * (y1 - y0 - 2) / 6, yb = y0 + 1 + (g + 1) * (y1 - y0 - 2) / 6;
        ikStrich(I, [[0, ya, 2 * t + 0.05], [0, yb + 0.05, 2 * t + 0.05]], { d: dd + 2, sw: 3.6, cls: 'zi', sty: zs(2.4 + 0.3 * g) });
      }
      /* Linsen der Rollnaht, ueberlappend */
      for (var m = 0; m !== 12; m++) {
        var yy = y0 + 2.2 + m * (y1 - y0 - 4.4) / 11;
        I.poly(ikKreis([0, yy, 2 * t + 0.1], [1, 0, 0], [0, 1, 0], 1.45, 14), 'none', { d: dd + 2.1, st: '#A97A00', sw: 0.6, cls: 'zi', sty: zs(4.4) });
      }
    }
  });
} };
/* P07L Laserschneiden (Faserlaser), Dimi 09.11.2026: schneller, praeziser, hochwertiger als Plasma (P07). Schlanker Kopf,
   duenner heller Strahl; zuerst die kleinen Loecher, dann die Aussenkontur mit scharfen Ecken und enger Nut; feine Fuge,
   saubere Kante, kaum Funken. Zum Schluss faehrt der Kopf hoch, die Loecher sind frei. Die Fuge waechst Bild fuer Bild. */
PSYM.P07L = { dt: 0.06, f: function (I) {
  var t = 2.4, z0 = t + 0.05, dt = 0.06, st = 6, W = [], F = [];
  I.box(-36, -26, 0, 72, 52, t, { d: 0 });
  function kreis(cx, cy, r, n) { var q = []; for (var j = 0; j !== n + 1; j++) { var a = -Math.PI / 2 + 2 * Math.PI * j / n; q.push([cx + r * Math.cos(a), cy + r * Math.sin(a), z0]); } return q; }
  W.push(kreis(-13, -8, 2.3, 16), kreis(-13, 8, 2.3, 16), kreis(3, 0, 4, 24));
  W.push([[-22, -15], [15, -15], [22, -8], [22, -3.2], [14, -3.2], [14, 3.2], [22, 3.2], [22, 15], [-22, 15], [-22, -15]].map(function (p) { return [p[0], p[1], z0]; }));
  /* Weg je Kontur nach Laenge: Teilstueck bis d */
  function bis(w, sg, d) {
    var m = 1, q = [w[0]];
    while (lt(sg[m], d - 1e-9)) { q.push(w[m]); m++; }
    var u = (d - sg[m - 1]) / ((sg[m] - sg[m - 1]) || 1);
    q.push(ad(w[m - 1], mu(sb(w[m], w[m - 1]), u)));
    return q;
  }
  each(W, function (w, j) {
    var L = 0, sg = [0], m;
    for (m = 1; m !== w.length; m++) { L += len(sb(w[m], w[m - 1])); sg.push(L); }
    var n = Math.max(3, Math.round(L / st));
    if (j) { F.push({ p: w[0], j: j, d: 0, sg: sg }); }
    for (m = 0; m !== n + 1; m++) { var q = bis(w, sg, L * m / n); F.push({ p: q[q.length - 1], j: j, d: L * m / n, sg: sg, an: true }); }
    /* Loch faellt heraus, sobald es geschnitten ist */
    if (lt(j, 3)) { I.poly(w.slice(0, w.length - 1), IKI[2], { d: 0.9, sw: 0.8, cls: 'zi', sty: zs((F.length - 1) * dt) }); }
  });
  F.push({ p: F[F.length - 1].p, j: W.length, d: 0, hoch: 1 });
  I.folge(F.length, function (k) {
    var f = F[k], p = f.p, h = f.hoch ? 9 : 0, i;
    /* feine Fuge: fertige Konturen ganz, die laufende bis zum Kopf */
    for (i = 0; i !== Math.min(f.j, W.length); i++) { I.line(W[i], { st: IKF.B, sw: 1.1, d: 1 }); }
    if (f.an) { if (gt(f.d, 0)) { I.line(bis(W[f.j], f.sg, f.d), { st: IKF.B, sw: 1.1, d: 1 }); } }
    I.zyl([p[0], p[1], 10 + h], [p[0], p[1], 28 + h], 2.6, { d: 10 });
    I.zyl([p[0], p[1], 6.5 + h], [p[0], p[1], 10 + h], 1.7, { d: 9.95 });
    I.zyl([p[0], p[1], 5 + h], [p[0], p[1], 6.5 + h], 0.9, { d: 9.94 });
    if (f.an) {
      I.line([[p[0], p[1], 5], [p[0], p[1], t]], { st: IKF.Y, sw: 1.2, d: 9.9 });
      I.poly(ikKreis([p[0], p[1], z0 + 0.02], [1, 0, 0], [0, 1, 0], 0.9, 10), IKF.W, { d: 9.92, sw: 1, st: IKF.Y });
    }
  });
} };
/* Offenes Kanalende (Stirn bei x = 0, Kanal nach -x), Blick ins Innere wie P16 */
function ikKanalOffen(I, L, w, h, e, d) {
  I.poly([[-L, -w, h], [0, -w, h], [0, w, h], [-L, w, h]], IKF.T, { d: d });
  I.poly([[-L, w, -h], [0, w, -h], [0, w, h], [-L, w, h]], IKF.L, { d: d + 0.1 });
  I.poly([[0, -w, -h], [0, w, -h], [0, w, h], [0, -w, h]], '#E3E9F0', { d: d + 0.2 });
  I.innen([[0, -w + e, -h + e], [0, w - e, -h + e], [0, w - e, h - e], [0, -w + e, h - e]], [-1, 0, 0], L, d + 0.25, { m: h });
}
/* Mittellinie mit gerundeten Biegungen: jede Ecke von pts (2D) mit Radius r (hoechstens bis zur halben Nachbarstrecke) */
function ikRund2(pts, r, n) {
  n = n || 6;
  var q = [pts[0]], i, j;
  for (i = 1; i !== pts.length - 1; i++) {
    var a = pts[i - 1], b = pts[i], c = pts[i + 1], l1 = Math.sqrt((a[0] - b[0]) * (a[0] - b[0]) + (a[1] - b[1]) * (a[1] - b[1])), l2 = Math.sqrt((c[0] - b[0]) * (c[0] - b[0]) + (c[1] - b[1]) * (c[1] - b[1]));
    var u1 = [(a[0] - b[0]) / l1, (a[1] - b[1]) / l1], u2 = [(c[0] - b[0]) / l2, (c[1] - b[1]) / l2], w = Math.acos(Math.max(-1, Math.min(1, u1[0] * u2[0] + u1[1] * u2[1])));
    if (gt(w, Math.PI - 0.01)) { q.push(b); continue; }
    var tw = Math.tan(w / 2), rr = Math.min(r, 0.5 * Math.min(l1, l2) * tw), dd = rr / tw;
    var bi = [u1[0] + u2[0], u1[1] + u2[1]], bl = Math.sqrt(bi[0] * bi[0] + bi[1] * bi[1]), hm = rr / Math.sin(w / 2);
    var m = [b[0] + bi[0] / bl * hm, b[1] + bi[1] / bl * hm], p1 = [b[0] + u1[0] * dd, b[1] + u1[1] * dd], p2 = [b[0] + u2[0] * dd, b[1] + u2[1] * dd];
    var a1 = Math.atan2(p1[1] - m[1], p1[0] - m[0]), a2 = Math.atan2(p2[1] - m[1], p2[0] - m[0]), da = a2 - a1;
    while (gt(da, Math.PI)) { da -= 2 * Math.PI; }
    while (lt(da, -Math.PI)) { da += 2 * Math.PI; }
    for (j = 0; j !== n + 1; j++) { var g = a1 + da * j / n; q.push([m[0] + rr * Math.cos(g), m[1] + rr * Math.sin(g)]); }
  }
  q.push(pts[pts.length - 1]);
  return q;
}
/* Eckfalze im Schnitt fuer E13 (Kreis 0..100, Mitte 50, y nach unten), aus /profile: Pittsburgh nach der Vorlage Lock seam
   (Wand mit Tasche, Bord des Bodens in der Tasche, Lippe umgelegt), Kanalfalz nach Dimis Bild (zwei eingehakte Haken).
   z: Vergroesserung f um den Punkt m, der nach z kommt (der Falz fuellt den Kreis, die Bleche laufen am Rand hinaus) */
var FALZ2 = {
  pit: { b: [[[22.1, 17.1], [22.1, 41.6], [35, 41.6], [35, 73.8], [30.8, 73.8], [30.8, 46.2], [22.1, 46.2], [22.1, 82.9], [38.6, 82.9]], [[26.4, 50.4], [26.4, 78.3], [77.9, 78.3]]], f: 1.4, m: [29, 62], z: [44, 48] },
  kan: { b: [[[83.3, 25.3], [83.3, 74.6], [48.9, 74.6], [48.9, 65.2], [73.9, 65.2]], [[53.3, 70.1], [78.4, 70.1], [78.4, 60.6], [44, 60.6], [44, 74.7], [16.6, 74.7]]], f: 1.35, m: [64, 67], z: [47, 54] }
};
/* Linienzug auf den Kreis (Mitte 50, 50, Radius rc) kuerzen: freie Enden ausserhalb werden am Rand abgeschnitten */
function ikImKreis(pts, rc) {
  function aus(p) { return gt((p[0] - 50) * (p[0] - 50) + (p[1] - 50) * (p[1] - 50), rc * rc); }
  function rand(p, q) {
    var dx = q[0] - p[0], dy = q[1] - p[1], fx = p[0] - 50, fy = p[1] - 50, A = dx * dx + dy * dy, B = 2 * (fx * dx + fy * dy), C = fx * fx + fy * fy - rc * rc;
    var D = Math.sqrt(Math.max(B * B - 4 * A * C, 0)), u1 = (-B - D) / (2 * A), u2 = (-B + D) / (2 * A), u = (lt(u1, 0) || gt(u1, 1)) ? u2 : u1;
    return [p[0] + dx * u, p[1] + dy * u];
  }
  var q = pts.slice(), i;
  if (aus(q[0])) { for (i = 0; aus(q[i + 1]); i++) { } q = [rand(q[i], q[i + 1])].concat(q.slice(i + 1)); }
  var n = q.length;
  if (aus(q[n - 1])) { for (i = n - 1; aus(q[i - 1]); i--) { } q = q.slice(0, i).concat([rand(q[i], q[i - 1])]); }
  return q;
}
/* Kreis mit Falz in Dimis Stil: Blech als Doppellinie mit Dicke, gerundete Biegungen; Mitte (x, y) und Radius R in der
   Bildebene um c; das zweite Blech gelb */
function ikFalzKreis(I, c, x, y, R, F, d) {
  var ring = [], k, s = R / 50, t = 2 * F.f;
  for (k = 0; k !== 48; k++) { var a = 2 * Math.PI * k / 48; ring.push(S2(c, x + R * Math.cos(a), y + R * Math.sin(a))); }
  /* Runde 13 der Szene (Dimi 10.11.2026: Profile ohne Kreise): weisse Scheibe ohne Rand, sie deckt nur den Kanal dahinter ab */
  I.poly(ring, IKF.W, { d: d, st: 'none' });
  function P(u, v) { return S2(c, x + (u - 50) * s, y + (v - 50) * s); }
  each(F.b, function (pts, j) {
    var q = ikImKreis(pts.map(function (p) { return [F.z[0] + (p[0] - F.m[0]) * F.f, F.z[1] + (p[1] - F.m[1]) * F.f]; }), 48.6);
    I.poly(ikBand2(ikRund2(q, t, 6), t).map(function (r) { return P(r[0], r[1]); }), j ? IKF.Y : IKF.L, { d: d + 0.1 + 0.01 * j, sw: 0.8 });
  });
}
/* E13 Falzen, Boerdeln, Falzschliessen, Ergebnis (Dimi 09.11.2026): Kanal mit zwei Eckfalzen; Zoom auf die Schnitte,
   links Pittsburghfalz, rechts Kanalfalz; zuletzt stehen nur die beiden Kreise */
PSYM.E13 = { dt: 0.45, f: function (I) {
  var n = 9, RL = 30, g = 2.5, w = 13, h = 9, L = 30, c = [-15, 0, 0], pq = PQ(c);
  var E = [[0, w - 1.4, -h + 1.4], [0, -w + 1.4, -h + 1.4]], Z = [[-(RL + g), 0], [RL + g, 0]], PR = [FALZ2.pit, FALZ2.kan];
  var A = E.map(function (p) { var q = PQ(p); return [q[0] - pq[0], q[1] - pq[1]]; });
  I.folge(n, function (k) {
    var u = gt(k, 2) ? (k - 2) / (n - 3) : 0;
    u = u * u * (3 - 2 * u);
    if (k !== n - 1) {
      ikKanalOffen(I, L, w, h, 1.4, 0);
      each(E, function (p) { I.line(ikKreis(p, [0, 1, 0], [0, 0, 1], 3, 20).concat([ad(p, [0, 3, 0])]), { st: IKF.Y, sw: 2.2, d: 5 }); });
    }
    if (gt(k, 2)) {
      each(Z, function (z, j) {
        var x = A[j][0] + (z[0] - A[j][0]) * u, y = A[j][1] + (z[1] - A[j][1]) * u, R = RL * (0.14 + 0.86 * u);
        if (k !== n - 1) {
          var vx = A[j][0] - x, vy = A[j][1] - y, vl = Math.sqrt(vx * vx + vy * vy);
          if (gt(vl, R + 1)) { I.line([E[j], S2(c, x + vx / vl * R, y + vy / vl * R)], { d: 19, sw: 0.9, da: '2 2' }); }
        }
        ikFalzKreis(I, c, x, y, R, PR[j], 20 + j);
      });
    }
  });
} };
/* P27 Abdichten: Dichtmasse laeuft als Raupe in die Ecke */
/* P27 (Abdichten von Hand): Zeichnung in 63_symbole_r10.js; die fruehere Fassung an dieser Stelle war ueberschrieben und ist entfernt (Runde 18) */
/* P28 Leitblech: Leitblech mit Kantenprofil (Wulst an der Anstroemkante) setzt sich in den Bogen */
PSYM.P28 = { f: function (I) {
  var ri = 10, ro = 42, h = 16, n = 16, i;
  function P(r, f, z) { var g = f + 0.5; return [-r * Math.cos(g), -r * Math.sin(g), z]; }
  var B = [];
  for (i = 0; i !== n + 1; i++) { B.push(P(ro, Math.PI / 2 * i / n, 0)); }
  for (i = n; i !== -1; i--) { B.push(P(ri, Math.PI / 2 * i / n, 0)); }
  I.poly(B, IKF.T, { d: 0 });
  var Go = [], Gi = [], Gv = [], rv = Math.sqrt(ri * ro);
  for (i = 0; i !== n + 1; i++) { var f = Math.PI / 2 * i / n; Go.push([P(ro, f, 0), P(ro, f, h)]); Gi.push([P(ri, f, 0), P(ri, f, h)]); Gv.push([P(rv, f, 1), P(rv, f, h - 1)]); }
  I.band(Go, { d: -1 });
  I.band(Gi, { d: 2 });
  I.mit('zw', function () { I.band(Gv, { d: 1, f: IKF.Y, fi: '#E0A800', sty: { '--my': '-16px', '--zs': '.1s', '--mt': '1s' } }); });
  /* Runde 19 (Dimi 11.11.2026): runde Wulst (Rundfalz) an der Kante des Leitblechs, auf die die Luft trifft */
  I.mit('zw', function () { I.zyl(P(rv, Math.PI / 2, 1), P(rv, Math.PI / 2, h - 1), 1.1, { d: 1.2, f: IKF.Y, fe: '#FFE27E', st: '#B88A00', sw: 1, sty: { '--my': '-16px', '--zs': '.1s', '--mt': '1s' } }); });
  I.ex.push(P(rv, 0.8, h + 20));
} };
/* P29 Clinchen: Fuegepresse drueckt, ein Fuegepunkt entsteht */
PSYM.P29 = { f: function (I) {
  var t = 2.2, xP = 2, yP = 0;
  I.box(-36, -22, 0, 46, 44, t, { d: 0 });
  I.box(-8, -22, t, 44, 44, t, { d: 1 });
  each([-15, -8], function (y) { ringPfad(I, [xP, y, 2 * t + 0.05], [0, 0, 1], 1.2, 2.6, IKF.Y, { d: 2 }); });
  ringPfad(I, [xP, yP, 2 * t + 0.05], [0, 0, 1], 1.3, 2.9, IKF.Y, { d: 2.1, cls: 'zp', sty: zs(1.0) });
  var mo = { '--my': '3px' }, mu2 = { '--my': '-3px' };
  I.zyl([xP, yP, 2 * t + 4], [xP, yP, 30], 4.4, { d: 10, cls: 'zu', sty: mo });
  I.zyl([xP, yP, 2 * t + 0.6], [xP, yP, 2 * t + 4], 2.4, { d: 9.9, ende: false, cls: 'zu', sty: mo });
  I.zyl([xP, yP, -26], [xP, yP, -0.6], 5.5, { d: -10, cls: 'zu', sty: mu2 });
} };
/* P30 Hakenfalz zudruecken: die beiden umgelegten Blechkanten sind ineinandergehakt, die Rolle drueckt den Falz flach.
   Lupe (Fable Runde 17): Schnitt durch die Naht, erst lose eingehakt, dann flach verpresst (Hakenfalz wie in profile_v1.json) */
PSYM.P30 = { dt: 0.16, f: function (I) {
  var R = 14, L = 38, N = 10;
  ikHalten(I, N * 0.16 + 1.4);
  I.zyl([-L, 0, 0], [L, 0, 0], R, { d: 0, offen: 1 });
  ikStrich(I, [[-L + 2, 0, R + 0.3], [L - 2, 0, R + 0.3]], { d: 1, pl: 1, sw: 2.6, cls: 'zd', sty: { '--zt': (N * 0.16) + 's' } });
  I.folge(N + 1, function (k) {
    var x = -L + 2 + (2 * L - 4) * k / N;
    if (lt(x, L - 4)) { I.box(x + 4, -2, R - 0.5, L - 2 - x - 4, 4, 3.2, { d: 0.8 }); }
    I.zyl([x, -2.6, R + 6.5], [x, 2.6, R + 6.5], 6, { d: 3 });
    I.poly(ikKreis([x, 2.7, R + 6.5], [1, 0, 0], [0, 0, 1], 2, 12), IKF.W, { d: 3.1, sw: 1 });
  });
  ikLupe(I, [46, -30, 26], 13, N + 1, function (P, k) {
    var zu = !lt(k, 5), g = zu ? 1.65 : 2.7, y0 = zu ? 2.6 : 4.1;
    /* unteres Blech von links mit Haken nach oben, oberes Blech von rechts mit Haken nach unten */
    var A = [[-11.4, y0], [4.6, y0], [4.6, y0 - 2 * g], [-4.2, y0 - 2 * g]];
    var B = [[11.4, y0 - 3 * g], [-4.8, y0 - 3 * g], [-4.8, y0 - g], [4.0, y0 - g]];
    if (!zu) { A[3] = [-4.0, y0 - 2 * g - 0.6]; B[3] = [3.8, y0 - g + 0.6]; }
    ikBlech2(I, P, A, 1.45, 20.2, { f: '#EEF2F7' });
    ikBlech2(I, P, B, 1.45, 20.21, { f: zu ? IKF.Y : '#DCE4EE' });
    if (zu) { pfeil2(I, P, [0, -9.6], [0, y0 - 3 * g - 1.6], 20.3); }
  }, { von: [L - 6, 0, R + 1] });
} };
/* P31 Rohruebergang kanten: faecherfoermige Kantungen von der Ecke zum Kreis */
PSYM.P31 = { f: function (I) {
  var a = 27, b = 21, r = 13, H = 30;
  var K = [[a, -b, 0], [a, b, 0], [-a, b, 0], [-a, -b, 0]];
  function KP(t) { return [r * Math.cos(t), r * Math.sin(t), H]; }
  var bog = [[-Math.PI / 2, 0], [0, Math.PI / 2], [Math.PI / 2, Math.PI], [Math.PI, 1.5 * Math.PI]], k, j, nl = 0;
  for (k = 0; k !== 4; k++) {
    var fan = [K[k]];
    for (j = 8; j !== -1; j--) { fan.push(KP(bog[k][0] + (bog[k][1] - bog[k][0]) * j / 8)); }
    var it = I.poly(fan, null, { d: 1 + k * 0.01, cull: 1 });
    if (it) {
      for (j = 1; j !== 8; j++) { ikStrich(I, [K[k], KP(bog[k][0] + (bog[k][1] - bog[k][0]) * j / 8)], { d: 2, sw: 1.8, pl: 1, cls: 'zd', sty: { '--zt': '.25s', '--zs': f1(0.12 * nl++) + 's' } }); }
    }
    I.poly([K[k], K[(k + 1) % 4], KP(bog[k][1])], null, { d: 1.5 + k * 0.01, cull: 1 });
  }
  I.poly(ikKreis([0, 0, H], [1, 0, 0], [0, 1, 0], r, 32), '#E3E9F0', { d: 3 });
  I.innen(ikKreis([0, 0, H + 0.05], [1, 0, 0], [0, 1, 0], r - 1.2, 32), [0, 0, -1], H, 3.1, { m: r });
} };
/* P32 Stutzen einsetzen: Stutzen durch den Ausschnitt, die Laschen klappen innen um */
PSYM.P32 = { dt: 0.2, f: function (I) {
  var r = 12, t = 1.5, NL = 8, i;
  var Pl = [[-36, -26, 0], [30, -26, 0], [30, 26, 0], [-36, 26, 0]];
  I.poly(ikKreis([0, 0, -0.1], [1, 0, 0], [0, 1, 0], r + 0.5, 32), IKF.I, { d: -2 });
  var m = { '--my': '-12px', '--mt': '.8s' };
  I.zyl([0, 0, -2], [0, 0, 22], r, { d: 1, cls: 'zw', sty: m, offen: 1 });
  I.folge(4, function (k, s) {
    var a = s * Math.PI / 2;
    var T = function (f, u) { var c = Math.cos(f), sn = Math.sin(f), rr = r + u * Math.sin(a); return [rr * c, rr * sn, -2 - u * Math.cos(a)]; };
    for (i = 0; i !== NL; i++) {
      var f0 = 2 * Math.PI * (i + 0.15) / NL, f1v = 2 * Math.PI * (i + 0.85) / NL, q = [];
      q.push(T(f0, 0), T(f1v, 0), T(f1v, 6), T(f0, 6));
      I.poly(q, IKF.Y, { d: -1 + i * 0.01, sw: 1, sty: { '--bt': '1.95s' } });
    }
  });
  var pl = I.poly(Pl, IKF.T, { d: 0 }); pl.a['fill-opacity'] = 0.55;
  I.poly([[-36, 26, -t], [30, 26, -t], [30, 26, 0], [-36, 26, 0]], IKF.L, { d: 0.1 });
  I.poly([[30, -26, -t], [30, 26, -t], [30, 26, 0], [30, -26, 0]], IKF.R, { d: 0.1 });
  I.line(ikKreis([0, 0, 0.1], [1, 0, 0], [0, 1, 0], r + 0.5, 32).concat([[r + 0.5, 0, 0.1]]), { d: 0.2, sw: 1.2 });
  I.ex.push([0, 0, 34], [0, 0, -10]);
} };
/* P33 Boerdelrand: Rohrende rollt sich zum Boerdel fuer den Spannring */
PSYM.P33 = { dt: 0.25, f: function (I) {
  var R = 15, x1 = 18;
  I.zyl([-40, 0, 0], [x1, 0, 0], R, { d: 0, offen: 1 });
  I.folge(4, function (k, s) {
    if (!k) { return; }
    var a = s * Math.PI / 2, L = 7, xe = x1 + L * Math.cos(a), re = R + L * Math.sin(a);
    var b = ikBasis([1, 0, 0]), k0 = ikKreis([x1, 0, 0], b[1], b[2], R), k1 = ikKreis([xe, 0, 0], b[1], b[2], re);
    var h = huelle(k0.concat(k1).map(PQ));
    I.add(1, { d: pfad(h, 1), fill: IKF.L, stroke: IKF.B, 'stroke-width': 1.5 }, { pts: h });
    ringPfad(I, [xe + 0.1, 0, 0], [1, 0, 0], R - 2, re, k === 3 ? IKF.Y : IKF.R, { d: 1.1 });
    I.innen(ikKreis([xe + 0.15, 0, 0], [0, 1, 0], [0, 0, 1], R - 2, 40), [-1, 0, 0], 1e6, 1.12, { m: R });
  });
  ikDrehPfeil(I, [x1 - 6, 0, 0], [1, 0, 0], R + 3.5, Math.PI * 0.82, Math.PI * 1.38, { d: 4 });
} };
/* P34 Rohrstuetze setzen: Rohr quer durch den Kanal, aussen Mutter und Scheibe */
PSYM.P34 = { f: function (I) {
  var L = 34, w = 20, h = 16, r = 3;
  I.poly([[-L, -w, -h], [L, -w, -h], [L, -w, h], [-L, -w, h]], IKF.L, { d: -5 });
  I.poly([[-L, -w, -h], [L, -w, -h], [L, w, -h], [-L, w, -h]], IKF.T, { d: -4 });
  var m = mvSty([0, 22, 0], 0.1, 0.9);
  I.zyl([0, -w - 4, 0], [0, w + 5, 0], r, { d: -2, cls: 'zw', sty: m, fe: IKF.R });
  var wl = I.poly([[-L, w, -h], [L, w, -h], [L, w, h], [-L, w, h]], IKF.L, { d: 2 }); wl.a['fill-opacity'] = 0.88;
  /* offenes Kanalende (Dimi 09.11.2026): Stirn als Rahmen mit Wanddicke, durch die Oeffnung sieht man Boden, Rueckwand und Rohr */
  var e = 1.6, Ra = [[L, -w, -h], [L, w, -h], [L, w, h], [L, -w, h]].map(PQ), Ri = [[L, -w + e, -h + e], [L, w - e, -h + e], [L, w - e, h - e], [L, -w + e, h - e]].map(PQ);
  I.add(2.1, { d: pfad(Ra, 1) + pfad(Ri, 1), fill: '#E3E9F0', 'fill-rule': 'evenodd', stroke: IKF.B, 'stroke-width': 1.5 }, { pts: Ra });
  I.line([[-L, -w, h], [L, -w, h], [L, w, h], [-L, w, h], [-L, -w, h]], { d: 2.2, sw: 1.2 });
  I.zyl([0, w, 0], [0, w + 5, 0], r + 0.4, { d: 3, cls: 'zw', sty: m, offen: 1, wand: 0.9 });
  I.zyl([0, w + 0.2, 0], [0, w + 1.2, 0], 6.5, { d: 3.2, fe: IKF.Y, cls: 'zi', sty: zs(1.05) });
  I.zyl([0, w + 1.2, 0], [0, w + 4.4, 0], 4.6, { d: 3.3, fe: IKF.Y, cls: 'zi', sty: zs(1.3) });
  I.ex.push([0, w + 27, 0]);
} };
/* P35 (Schalldaempferkulissenmaschine): seit Runde 19 in 65_symbole_r19.js (Ablauf der Maschine statt des fertigen Schalldaempfers) */
/* CSS aller Symbole */
function pcssAlle() { var r = PCSS; for (var k in PSYM) { if (PSYM[k].css) { r += PSYM[k].css; } } return r; }
/* Gelbe Kiste (ausgewaehltes Teil): Flaechen in den Gelbtoenen */
var IKY = { ft: '#FFE27E', fl: '#F9C83A', fr: '#EDB20E' };
/* P36 Selektieren: drei Baender von verschiedenen Coils liegen uebereinander in der Selektiereinheit,
   nacheinander wird eines gewaehlt (gelb) und laeuft auf der Vorschublinie weiter */
PSYM.P36 = { dt: 0.6, f: function (I) {
  var w = 12, t = 1.2, zs = [0, 9, 18];
  each(zs, function (z, i) { I.box(-56, -w, z, 48, 2 * w, t, { d: i * 0.1 }); });
  I.folge(4, function (k) { var i = [2, 0, 1, 1][k]; I.box(-56, -w, zs[i], 48, 2 * w, t, ext(IKY, { d: i * 0.1 + 0.05 })); });
  I.box(-8, -w - 3, -5, 16, 2 * w + 6, 30, { d: 1 });
  I.box(8, -w, 9, 38, 2 * w, t, { d: 2 });
  ikStrich(I, [[10, 0, 9 + t + 0.05], [44, 0, 9 + t + 0.05]], { d: 2.1, da: '6 6', cls: 'zl', sty: { '--lt': '.6s', '--lz': '5' } });
} };
/* P37 Vorschub: Walzenpaar klemmt das Band und schiebt es um einen Takt vor */
PSYM.P37 = { f: function (I) {
  var w = 13, r = 6, t = 1.2, s = 24;
  I.zyl([0, -w - 3, -r - 0.6], [0, w + 3, -r - 0.6], r, { d: 0 });
  I.box(-48, -w, 0, 96, 2 * w, t, { d: 1 });
  I.poly([[10, -w + 3, t + 0.05], [14, -w + 3, t + 0.05], [14, w - 3, t + 0.05], [10, w - 3, t + 0.05]], IKF.Y, { d: 1.2, cls: 'zv', sty: mvSty([s, 0, 0], 0.4, 0.9) });
  I.zyl([0, -w - 3, r + t + 0.6], [0, w + 3, r + t + 0.6], r, { d: 3 });
  ikDreh(I, [0, w + 3, r + t + 0.6], [0, 1, 0], r * 0.6, { d: 3.1, sw: 0.9, da: '2 3', rueck: 1 });
  var y = -w - 5, z = t;
  I.line([[12, y, z], [12 + s, y, z]], { d: 4, sw: 1.2, cls: 'zi', sty: zs(1.3) });
  each([[12, 1], [12 + s, -1]], function (q) {
    I.poly([[q[0], y, z], [q[0] + q[1] * 3.4, y - 1.6, z], [q[0] + q[1] * 3.4, y + 1.6, z]], IKF.B, { d: 4.1, sw: 0.6, cls: 'zi', sty: zs(1.3) });
    I.line([[q[0], y - 3, z], [q[0], y + 3, z]], { d: 4.1, sw: 0.9, cls: 'zi', sty: zs(1.3) });
  });
} };
/* P38 Kanalanlage: vom Coil durch die Stationen der Linie; heraus kommt der Zuschnitt, der zum Kanalteil gekantet wird */
/* P38 (Kanalanlage): Zeichnung in 62_anlagen.js; die fruehere Fassung an dieser Stelle war ueberschrieben und ist entfernt (Runde 18) */
/* P43 Rohranlage (PR, SWA): vom Coil durch Zuschnitt, Rundwalzen und Naht in einer Linie; heraus kommt das fertige
   Rundrohr mit Laengsnaht (Dimi 09.11.2026: die Anlage vereint alle Bereiche, das Symbol zeigt die ganze Linie) */
PSYM.P43 = { dt: 0.5, f: function (I) {
  var r = 10;
  ikAbwickler(I, -76, -44, -BETT, { d: 0 });
  I.box(-46, -16, -BETT, 122, 32, BETT, { d: 1 });
  I.box(-40, -14, 0, 12, 28, 10, { d: 1.5 });
  /* Rundwalzen: drei Walzen laengs der Linie, zwei unten, eine oben */
  each([[-6, 4.5], [6, 4.5], [0, 12.5]], function (q, i) { I.zyl([-22, q[0], q[1]], [-4, q[0], q[1]], 4, { d: 1.6 + i * 0.05 }); });
  I.box(4, -14, 0, 12, 28, 10, { d: 1.8 });
  I.folge(3, function (k) {
    var x0 = 40, x1 = 72;
    if (k === 0) { I.poly([[x0, -16, 0.2], [x1, -16, 0.2], [x1, 16, 0.2], [x0, 16, 0.2]], IKF.T, { d: 3 }); return; }
    I.zyl([x0, 0, r], [x1, 0, r], r, { d: 3, hohl: 1 });
    if (k === 2) { I.line([[x0, 0, 2 * r + 0.1], [x1, 0, 2 * r + 0.1]], { d: 3.3, st: IKF.Y, sw: 2.2 }); }
  });
} };
/* P44 Rohrschweissanlage (SWA): Zuschnitte vom Stapel, Rundformer, Formwerkzeug mit Schweissrolle und Drahtspule
   (Rollennaht mit Kupferdraht); heraus kommt das kurze Rohr bzw. Bogensegment (Recherche 09.11.2026) */
PSYM.P44 = { dt: 0.5, f: function (I) {
  var t = 1.1, r = 10, zb = -BETT;
  /* Stapeltisch am Boden (Unterkante des Betts), der oberste Zuschnitt liegt in Einlaufhoehe (Unterseite z = 0) */
  I.box(-84, -15, zb, 30, 30, zb * -1 - 3.4 - 0.2, { d: -1 });
  each([-3.4, -1.7, 0], function (z, i) { I.box(-82, -13, z, 26, 26, t, { d: i * 0.1 }); });
  ikStrich(I, [[-54, 0, t + 0.05], [-44, 0, t + 0.05]], { d: 0.5, da: '4 4', cls: 'zl', sty: { '--lt': '.6s', '--lz': '4' } });
  I.box(-44, -16, -BETT, 108, 32, BETT, { d: 1 });
  each([[-6, 4.5], [6, 4.5], [0, 12.5]], function (q, i) { I.zyl([-40, q[0], q[1]], [-22, q[0], q[1]], 4, { d: 1.6 + i * 0.05 }); });
  I.box(-12, -14, 0, 30, 28, 12, { d: 1.8 });
  /* Schweissrolle sitzt im Gehaeuse; Drahtspule auf einem Halter, der Kupferdraht laeuft tangential auf die Rolle */
  var rc = [2, 18], rr = 7, sc = [12, 32], rs = 5, nx = -0.741, nz2 = 0.672;
  I.zyl([2, -3, rc[1]], [2, 3, rc[1]], rr, { d: 2, fe: IKF.T });
  I.box(14.5, -9, 12, 3, 3, 23, { d: 1.9 });
  I.zyl([sc[0], -6, sc[1]], [sc[0], -5, sc[1]], 1.6, { d: 2.05, ende: false });
  I.zyl([sc[0], -5, sc[1]], [sc[0], 5, sc[1]], rs, { d: 2.1, fe: IKF.T });
  I.line(ikKreis([sc[0], 5, sc[1]], [1, 0, 0], [0, 0, 1], rs - 2, 24), { d: 2.15, sw: 0.7 });
  var bo = []; for (var k = 0; k !== 9; k++) { var a = Math.atan2(nz2, nx) + (Math.PI * 1.5 - Math.atan2(nz2, nx)) * k / 8; bo.push([rc[0] + (rr + 0.3) * Math.cos(a), 0, rc[1] + (rr + 0.3) * Math.sin(a)]); }
  I.line([[sc[0] + rs * nx, 0, sc[1] + rs * nz2]].concat(bo), { d: 2.2, sw: 0.9 });
  I.folge(3, function (k) {
    var x0 = 40, x1 = 60;
    if (k === 0) { I.poly([[x0, -16, 0.2], [x1, -16, 0.2], [x1, 16, 0.2], [x0, 16, 0.2]], IKF.T, { d: 3 }); return; }
    I.zyl([x0, 0, r], [x1, 0, r], r, { d: 3, hohl: 1, durch: 1 });
    if (k === 2) { I.line([[x0, 0, 2 * r + 0.1], [x1, 0, 2 * r + 0.1]], { d: 3.3, st: IKF.Y, sw: 2.2 }); }
  });
} };
/* P39 Selektier-, Vorschub- und Richteinheit: Baender aus der Selektiereinheit, Vorschubwalzen, dann Richtwalzen */
PSYM.P39 = { f: function (I) {
  var w = 11, t = 1.1, r = 4.2, zs = [-9, 0, 9];
  each(zs, function (z, i) { I.box(-84, -w, z, 22, 2 * w, t, i === 1 ? ext(IKY, { d: i * 0.1 }) : { d: i * 0.1 }); });
  I.box(-62, -w - 3, -13, 12, 2 * w + 6, 26, { d: 1 });
  I.zyl([-36, -w - 3, -r - 0.6], [-36, w + 3, -r - 0.6], r, { d: 1.5 });
  each([-18, -4, 10], function (x) { I.zyl([x, -w - 3, -r - 0.6], [x, w + 3, -r - 0.6], r, { d: 1.5 }); });
  I.box(-50, -w, 0, 84, 2 * w, t, { d: 2 });
  ikStrich(I, [[-48, 0, t + 0.05], [32, 0, t + 0.05]], { d: 2.1, da: '6 6', cls: 'zl', sty: { '--lt': '.6s', '--lz': '5' } });
  I.zyl([-36, -w - 3, r + t + 0.6], [-36, w + 3, r + t + 0.6], r, { d: 3 });
  ikDreh(I, [-36, w + 3, r + t + 0.6], [0, 1, 0], r * 0.6, { d: 3.1, sw: 0.9, da: '2 3', rueck: 1 });
  each([-11, 3], function (x) { I.zyl([x, -w - 3, r + t + 0.6], [x, w + 3, r + t + 0.6], r, { d: 3.2 }); });
} };
/* Handgefuehrtes Elektrowerkzeug: Arbeitskopf am Punkt k, Getriebekopf und Motorgehaeuse entlang ax (vom Kopf weg) */
function ikHandWz(I, k, ax, o) {
  o = o || {};
  var a = nz(ax), g0 = ad(k, mu(a, 3)), g1 = ad(k, mu(a, 11)), m1 = ad(k, mu(a, 33)), d = o.d || 10, c = o.cls, s = o.sty;
  I.zyl(g1, m1, 4.6, { d: d, f: '#CDD6E0', fe: '#DCE3EB', cls: c, sty: s });
  I.zyl(g0, g1, 3, { d: d + 0.5, f: IKF.L, cls: c, sty: s });
  I.zyl(k, g0, 1.6, { d: d + 0.6, f: IKF.R, ende: false, cls: c, sty: s });
  return { m1: m1 };
}
/* P40 Schneiden mit der Handschere (TRUMPF TruTool S): die Schere faehrt die Linie entlang, das Blech trennt sich ohne Span */
PSYM.P40 = { f: function (I) {
  var t = 1.5, y = 8, x0 = -41, x1 = 30, m = mvSty([x1 - x0, 0, 0], 0, 1.4);
  I.box(-42, -26, 0, 84, 26 + y, t, { d: 0 });
  I.box(-42, y + 0.6, -0.6, 84, 26 - y - 0.6, t, { d: 0.2 });
  ikStrich(I, [[x0, y + 0.3, t + 0.05], [x1, y + 0.3, t + 0.05]], { d: 1, pl: 1, cls: 'zd', sty: { '--zt': '1.4s' } });
  ikHandWz(I, [x0, y + 0.3, t + 0.3], [-0.55, 0.2, 0.81], { d: 10, cls: 'zv', sty: m });
} };
/* P42 Falz schliessen von Hand (TRUMPF TruTool F): der Falzschliesser laeuft auf der Kante, hinter ihm liegt die Lippe um */
PSYM.P42 = { dt: 0.18, f: function (I) {
  var L = 36, N = 8, x0 = -28, x1 = 28;
  I.box(-L, -22, -1.5, 2 * L, 22, 1.5, { d: 0 });
  I.box(-L, -1.5, -26, 2 * L, 1.5, 24.5, { d: 0.1 });
  I.folge(N + 1, function (k) {
    var x = x0 + (x1 - x0) * k / N;
    if (gt(L - 0.5, x)) { I.box(x, -1.5, 0, L - x, 1.5, 3.2, { d: 0.2 }); }
    if (gt(x, -L + 0.5)) { I.box(-L, -1.5, 0, x + L, 3.2, 1.2, { d: 0.25, ft: IKF.Y, fl: '#F9C83A', fr: '#EDB20E' }); }
    I.box(x - 4, -6, -6, 8, 9, 11, { d: 9 });
    ikHandWz(I, [x, -1.5, 5], [-0.8, -0.2, 0.56], { d: 10 });
  });
} };

/* ---------- Anlagen-Symbole (Runde 7, Dimi 09.11.2026 12:37: Kanalanlagen und Wickelfalzrohr aufwendiger) ----------
   Ersetzt PSYM.P38 (Kanalanlage, Steckrahmen-Weg) und PSYM.P18 (Wickelfalzrohr) aus 61_prozess_sym.js und ergaenzt
   PSYM.P45 (vollautomatische PDF-Anlage). Ablaeufe nach den Betriebsanleitungen (MCL Ultra, CL ECO, DS, TF 1401 Ultra,
   Stage 1, RF PDF 3 und Stage 3 PDF 3, Layout der Volllinie) und nach unserer Website (TF 1401 Ultra: fuenf Schritte
   vom Coil zum Rohr). Bildfolgen ruhig (etwa 9 s); ohne Klasse go steht das Endbild (letztes Bild der Folge).
   Regel: Teile in einer Bildfolge (I.folge) bekommen keine Bewegungsklassen (zd, zl, zu ...), sonst ueberschreibt deren
   Animation das Ein- und Ausblenden der Bilder. Bewegung zu einem Bild: festes Teil mit --zs = Bildnummer mal dt.
   Offene Rohrenden ueber I.zyl(..., { offen: 1, hohl: 1 }), offene Kanalenden ueber anKanal (Innenflaechen dunkler).
   Achsen wie ueberall: x laengs der Linie, y quer (Coilbreite = Kanallaenge), z nach oben, Oberkante Bett z = 0. */

/* Farben im Kanal: Boden innen hell, Wand innen dunkler, Stirnkante der Wand fast weiss */
var ANF = { boden: '#C9D4E0', wand: '#A7B5C6', stirn: '#F4F7FA', bett: '#E4EAF1', sicke: '#6E7F94', gelbRand: '#C99600' };
/* Umriss fuer gelbe Merkmalsflaechen (Flansch, Rahmen): dunkleres Gelb, damit das Merkmal auch in der kleinen Kachel gelb bleibt */
function anRand(F) { return F === IKY ? ANF.gelbRand : IKF.B; }
function anPoly(I, pts, f, d, o) { return I.poly(pts, f, ext({ d: d }, o || {})); }
/* Rechteck in der Ebene y = konstant */
function anRechtY(y, xa, xb, za, zb) { return [[xa, y, za], [xb, y, za], [xb, y, zb], [xa, y, zb]]; }
/* Konvexes Polygon (Punkte [u, v]) am Halbraum a*u + b*v + c nicht negativ abschneiden */
function anKappe(P, a, b, c) {
  var r = [], n = P.length;
  for (var i = 0; i !== n; i++) {
    var p = P[i], q = P[(i + 1) % n], fp = a * p[0] + b * p[1] + c, fq = a * q[0] + b * q[1] + c;
    if (!lt(fp, 0)) { r.push(p); }
    if (lt(fp, 0) !== lt(fq, 0)) { var t = fp / (fp - fq); r.push([p[0] + (q[0] - p[0]) * t, p[1] + (q[1] - p[1]) * t]); }
  }
  return r;
}
/* Kanal (Kasten) laengs y von y0 (hinten) bis y1 (vorn), Querschnitt x0..x1 und z0..z1, Wanddicke t.
   Sichtbar sind Deckel, rechte Seite und das offene vordere Ende. Im Ende: Boden innen hell, linke Wand innen dunkler;
   die Grenze ist die innere Ecke, sie laeuft in der Isometrie unter 45 Grad. o.teil 'mantel' oder 'ende' zeichnet nur
   einen Teil (dazwischen kann der vordere Flansch liegen). o.fT, o.fR Farben. */
function anKanal(I, K, o) {
  o = o || {};
  var d = o.d || 0, t = K.t || 1.2, x0 = K.x0, x1 = K.x1, z0 = K.z0, z1 = K.z1, y0 = K.y0, y1 = K.y1, op = { cls: o.cls, sty: o.sty };
  if (o.teil !== 'ende') {
    anPoly(I, [[x0, y0, z1], [x1, y0, z1], [x1, y1, z1], [x0, y1, z1]], o.fT || IKF.T, d, op);
    anPoly(I, [[x1, y0, z0], [x1, y1, z0], [x1, y1, z1], [x1, y0, z1]], o.fR || IKF.R, d + 0.01, op);
  }
  if (o.teil === 'mantel') { return; }
  anPoly(I, anRechtY(y1, x0, x1, z0, z1), ANF.stirn, d + 0.02, op);
  var xa = x0 + t, xb = x1 - t, za = z0 + t, zb = z1 - t, R = [[xa, za], [xb, za], [xb, zb], [xa, zb]];
  var Pb = anKappe(R, 1, -1, za - xa), Pw = anKappe(R, -1, 1, xa - za);
  function y3(P) { return P.map(function (q) { return [q[0], y1, q[1]]; }); }
  if (gt(Pw.length, 2)) { anPoly(I, y3(Pw), ANF.wand, d + 0.03, ext(op, { sw: 0.9 })); }
  if (gt(Pb.length, 2)) { anPoly(I, y3(Pb), ANF.boden, d + 0.035, ext(op, { sw: 0.9 })); }
}
/* Querlinien (Sicken) auf Deckel und rechter Seite eines Kanals bei y */
function anSickenKanal(I, K, ys, d, o) {
  each(ys, function (y) { I.line([[K.x0, y, K.z1 + 0.05], [K.x1, y, K.z1 + 0.05], [K.x1 + 0.05, y, K.z0]], ext({ d: d, sw: 0.7, st: ANF.sicke }, o || {})); });
}
/* Aufgesteckter Rahmen (Steckrahmen) am Kanalende y: Rahmenflaeche um den Querschnitt, h nach aussen, Schenkel l parallel
   zum Kanal (s = -1 am vorderen, +1 am hinteren Ende). Rahmenflaeche bei d, oberer und rechter Schenkel bei dl. o.f Farbsatz. */
function anFlansch(I, K, y, h, l, s, d, dl, o) {
  o = o || {};
  var F = o.f || { ft: IKF.T, fl: IKF.L, fr: IKF.R }, op = { cls: o.cls, sty: o.sty, sw: 1, st: anRand(F) };
  var xa = K.x0 - h, xb = K.x1 + h, za = K.z0 - h, zb = K.z1 + h, ya = Math.min(y, y + s * l), yb = Math.max(y, y + s * l);
  if (d !== null) { anPoly(I, anRechtY(y, xa, xb, za, zb), F.fl, d, op); }
  if (dl !== null) {
    anPoly(I, [[xa, ya, zb], [xb, ya, zb], [xb, yb, zb], [xa, yb, zb]], F.ft, dl, op);
    anPoly(I, [[xb, ya, za], [xb, yb, za], [xb, yb, zb], [xb, ya, zb]], F.fr, dl + 0.01, op);
  }
}
/* Angeformter PDF-Flansch am Kanalende y: je Kanalseite ein Stueck, h nach aussen, an den Ecken ausgeklinkt (Luecke g);
   oberes und rechtes Stueck mit Aussenkante (Tiefe l zum Kanal hin, s = -1 vorn, +1 hinten) */
function anPdfRing(I, K, y, h, l, g, s, d, F) {
  var x0 = K.x0, x1 = K.x1, z0 = K.z0, z1 = K.z1, e = g / 2, ya = Math.min(y, y + s * l), yb = Math.max(y, y + s * l), o = { sw: 1, st: anRand(F) };
  anPoly(I, [[x0 + e, ya, z1 + h], [x1 - e, ya, z1 + h], [x1 - e, yb, z1 + h], [x0 + e, yb, z1 + h]], F.ft, d, o);
  anPoly(I, [[x1 + h, ya, z0 + e], [x1 + h, yb, z0 + e], [x1 + h, yb, z1 - e], [x1 + h, ya, z1 - e]], F.fr, d + 0.01, o);
  anPoly(I, [[x0 + e, y, z1], [x1 - e, y, z1], [x1 - e, y, z1 + h], [x0 + e, y, z1 + h]], F.fl, d + 0.02, o);
  anPoly(I, [[x1, y, z0 + e], [x1 + h, y, z0 + e], [x1 + h, y, z1 - e], [x1, y, z1 - e]], F.fl, d + 0.02, o);
  anPoly(I, [[x0 + e, y, z0 - h], [x1 - e, y, z0 - h], [x1 - e, y, z0], [x0 + e, y, z0]], F.fl, d + 0.02, o);
  anPoly(I, [[x0 - h, y, z0 + e], [x0, y, z0 + e], [x0, y, z1 - e], [x0 - h, y, z1 - e]], F.fl, d + 0.02, o);
}
/* Geschlossener Kanal K mit offenem vorderen Ende (Innenflaechen sichtbar).
   o.pdf: { h, l, g } angeformter Flansch an beiden Enden; o.rahmen: { h, l } aufgesteckter Rahmen an beiden Enden;
   o.gelb: Flansch bzw. Rahmen gelb; o.sicken: Querlinien; o.naht: Falz an der Kante rechts unten ('gelb' oder 'blau') */
function anKanalZu(I, K, d, o) {
  o = o || {};
  var F = o.gelb ? IKY : { ft: IKF.T, fl: IKF.L, fr: IKF.R }, P = o.pdf, S = o.rahmen;
  if (P) { anPdfRing(I, K, K.y0, P.h, P.l, P.g, 1, d, F); }
  if (S) { anFlansch(I, K, K.y0, S.h, S.l, 1, d, null, { f: F }); }
  anKanal(I, K, { d: d + 1, teil: 'mantel' });
  if (o.sicken) { anSickenKanal(I, K, o.sicken, d + 1.05); }
  if (o.naht) {
    var gn = o.naht === 'gelb';
    I.line([[K.x1 - 0.1, K.y0 + 0.2, K.z0 + 0.9], [K.x1 - 0.1, K.y1 - 0.2, K.z0 + 0.9]], { d: d + 1.06, sw: gn ? 2.4 : 1.1, st: gn ? IKF.Y : IKF.B });
  }
  if (S) {
    anFlansch(I, K, K.y0, S.h, S.l, 1, null, d + 1.1, { f: F });
    anFlansch(I, K, K.y1, S.h, S.l, -1, d + 1.3, d + 1.2, { f: F });
    /* Eckwinkel in den Rahmenecken */
    each([[K.x0 - S.h, K.z0 - S.h], [K.x1, K.z0 - S.h], [K.x1, K.z1], [K.x0 - S.h, K.z1]], function (c) {
      anPoly(I, anRechtY(K.y1 + 0.02, c[0], c[0] + S.h, c[1], c[1] + S.h), IKF.D, d + 1.32, { sw: 0.8 });
    });
  }
  if (P) { anPdfRing(I, K, K.y1, P.h, P.l, P.g, -1, d + 1.3, F); }
  anKanal(I, K, { d: d + 1.4, teil: 'ende' });
}
/* Offenes Profil (Querschnitt C in x-z als Linienzug) laengs y von y0 bis y1. Aussen liegt links vom Linienzug
   (x nach rechts, z nach oben). Sichtbare Innenflaechen dunkler. o.flansch: Hoehe des angeformten Flansches an beiden
   Enden (nach aussen), o.gelbF: Flansch gelb, o.luecke: Flanschstuecke an den Ecken um die Luecke gekuerzt (Ausklinkung),
   sonst an den Ecken verlaengert; o.sicken: Querlinien bei diesen y auf der sichtbaren Seite. */
function anProfilY(I, C, y0, y1, d, o) {
  o = o || {};
  var h = o.flansch || 0, g = o.luecke, FF = o.gelbF ? IKY : { ft: IKF.T, fl: IKF.L, fr: IKF.R }, op = { cls: o.cls, sty: o.sty };
  function seg(i) {
    var p = C[i], q = C[i + 1], ux = q[0] - p[0], uz = q[1] - p[1], L = Math.sqrt(ux * ux + uz * uz);
    return { p: p, q: q, ux: ux / L, uz: uz / L, nx: -uz / L, nz: ux / L };
  }
  function streifen(y, dd) {
    if (!gt(h, 0)) { return; }
    for (var i = 0; i !== C.length - 1; i++) {
      var s = seg(i), ea, eb;
      if (g !== undefined) { ea = -g / 2; eb = -g / 2; } else { ea = i === 0 ? 0 : h; eb = i === C.length - 2 ? 0 : h; }
      var a = [s.p[0] - s.ux * ea, s.p[1] - s.uz * ea], b = [s.q[0] + s.ux * eb, s.q[1] + s.uz * eb];
      anPoly(I, [[a[0], y, a[1]], [b[0], y, b[1]], [b[0] + s.nx * h, y, b[1] + s.nz * h], [a[0] + s.nx * h, y, a[1] + s.nz * h]], FF.fl, dd + i * 0.001, ext(op, { sw: 1, st: anRand(FF) }));
    }
  }
  streifen(y0, d - 0.5);
  for (var i = 0; i !== C.length - 1; i++) {
    var s = seg(i), p = s.p, q = s.q, aussenSicht = gt(s.nx + s.nz, 0), f;
    if (aussenSicht) { f = ikFarbe([s.nx, 0, s.nz]); } else { f = gt(Math.abs(s.nz), Math.abs(s.nx)) ? ANF.boden : ANF.wand; }
    var dd = d + (p[0] + q[0]) * 0.002 + (p[1] + q[1]) * 0.002;
    anPoly(I, [[p[0], y0, p[1]], [q[0], y0, q[1]], [q[0], y1, q[1]], [p[0], y1, p[1]]], f, dd, op);
    if (o.sicken) {
      var e = aussenSicht ? 0.06 : -0.06;
      each(o.sicken, function (y) { I.line([[p[0] + s.nx * e, y, p[1] + s.nz * e], [q[0] + s.nx * e, y, q[1] + s.nz * e]], ext(op, { d: dd + 0.0005, sw: 0.7, st: ANF.sicke })); });
    }
  }
  streifen(y1, d + 0.8);
}
/* Flaches Blech (Band oder Zuschnitt) von x0 bis x1, Breite COIL.W quer, Dicke COIL.t, Unterseite z = 0.
   o.sx: Sicken (Linien laengs bei o.ys) ab x; o.kl: Ausklinkungen (x-Positionen, an beiden Raendern);
   o.fl: Liste [xa, xb] der Flanschstuecke, nach unten angeformt an beiden Raendern (o.gelb gelb, Hoehe o.h, Tiefe o.l);
   o.pv / o.ph: Falz an der vorderen / hinteren Kante (gelbe Linie) */
function anBlech(I, x0, x1, d, o) {
  o = o || {};
  if (!gt(x1 - x0, 0.05)) { return; }
  var t = COIL.t, W2 = COIL.W / 2, h = o.h || 2.2, l = o.l || 1.6, F = o.gelb ? IKY : { ft: IKF.T, fl: IKF.L, fr: IKF.R };
  each(o.fl || [], function (r) {
    var xa = Math.max(x0, r[0]), xb = Math.min(x1, r[1]);
    if (!gt(xb - xa, 0.2)) { return; }
    I.box(xa, -W2, -h, xb - xa, l, h, { d: d - 0.03, ft: F.ft, fl: F.fl, fr: F.fr, sw: 1, st: anRand(F) });
    I.box(xa, W2 - l, -h, xb - xa, l, h, { d: d - 0.02, ft: F.ft, fl: F.fl, fr: F.fr, sw: 1, st: anRand(F) });
  });
  I.box(x0, -W2, 0, x1 - x0, COIL.W, t, { d: d });
  if (o.sx !== undefined) {
    var xs = Math.max(x0, o.sx);
    if (gt(x1 - xs, 0.5)) { each(o.ys || [-6, 0, 6], function (y) { I.line([[xs, y, t + 0.05], [x1 - 0.3, y, t + 0.05]], { d: d + 0.01, sw: 0.7, st: ANF.sicke }); }); }
  }
  each(o.kl || [], function (xk) {
    if (lt(xk, x0 + 0.9) || gt(xk, x1 - 0.9)) { return; }
    each([-1, 1], function (sg) { I.poly([[xk - 0.9, sg * W2, t + 0.06], [xk + 0.9, sg * W2, t + 0.06], [xk, sg * (W2 - 1.6), t + 0.06]], IKF.G, { d: d + 0.02, sw: 0.5 }); });
  });
  if (o.pv) { ikStrich(I, [[x1 - 0.5, -W2 + 0.3, t + 0.08], [x1 - 0.5, W2 - 0.3, t + 0.08]], { d: d + 0.03, sw: 1.8 }); }
  if (o.ph) { ikStrich(I, [[x0 + 0.5, -W2 + 0.3, t + 0.08], [x0 + 0.5, W2 - 0.3, t + 0.08]], { d: d + 0.03, sw: 1.8 }); }
}
/* Abwickelbock mit Coil (wie ikAbwickler, quer verschoben um yv, ohne Band) */
function anCoilBock(I, x, yv, zb, d) {
  var R = COIL.R, W = COIL.W, zc = -R, c1 = [x, yv + W / 2, zc], yS = yv - W / 2 - 7;
  each([-10, 7], function (dx, i) {
    I.box(x + dx, yS - 2, zb + 1.6, 3, W + 13, 2, { d: d - 3 + i * 0.01 });
    I.zyl([x + dx - 0.2, yv + W / 2 + 6.5, zb + 1.6], [x + dx + 3.2, yv + W / 2 + 6.5, zb + 1.6], 1.6, { d: d - 2.9 + i * 0.01 });
  });
  I.box(x - 10, yS - 2, zb + 3.6, 20, 4, 2, { d: d - 2.8 });
  I.box(x - 2.5, yS, zb + 5.6, 5, 4, -zb - 2, { d: d - 2.5 });
  I.zyl([x, yS + 4, zc], [x, yv - W / 2, zc], 2.6, { d: d - 2.4, ende: false });
  I.zyl([x, yv - W / 2, zc], c1, R, { d: d, fe: IKF.T });
  I.line(ikKreis(c1, [1, 0, 0], [0, 0, 1], R - 4, 40), { d: d + 0.05, sw: 0.8 });
  I.zyl([x, yv + W / 2 - 0.5, zc], [x, yv + W / 2 + 0.6, zc], 4, { d: d + 0.15, fe: IKF.W });
  I.zyl([x, yv + W / 2 + 0.6, zc], [x, yv + W / 2 + 2.4, zc], 2.4, { d: d + 0.2, fe: IKF.D });
}
/* Coil-Selektor: Coils nebeneinander quer zur Linie (Mitten ym, Breiten wb, Radien rb) auf einem gemeinsamen Rahmen,
   je Coil ein Staender mit Dorn (seitlich beladen); das vordere Coil (y = 0) speist die Linie. */
function anCoilWahl(I, x, ym, wb, rb, zb, d) {
  var n = ym.length, zc = -COIL.R, yh = ym[n - 1] - wb[n - 1] / 2 - 6;
  I.box(x - 9, yh, zb, 18, -yh + COIL.W / 2 + 3, 3, { d: d - 4 });
  for (var i = n - 1; i !== -1; i--) {
    var yv = ym[i], w2 = wb[i] / 2, R = rb[i], dd = d - i * 0.8, c1 = [x, yv + w2, zc], yS = yv - w2 - 3.6;
    I.box(x - 2.4, yS, zb + 3, 4.8, 2.4, zc + 2.4 - zb - 3, { d: dd - 0.3 });
    I.zyl([x, yS + 2.4, zc], [x, yv - w2, zc], 2.4, { d: dd - 0.2, ende: false });
    I.zyl([x, yv - w2, zc], c1, R, { d: dd, fe: IKF.T });
    I.line(ikKreis(c1, [1, 0, 0], [0, 0, 1], R - 4, 40), { d: dd + 0.05, sw: 0.8 });
    I.zyl([x, yv + w2 - 0.5, zc], [x, yv + w2 + 0.6, zc], 4, { d: dd + 0.15, fe: IKF.W });
    I.zyl([x, yv + w2 + 0.6, zc], [x, yv + w2 + 2.4, zc], 2.4, { d: dd + 0.2, fe: IKF.D });
  }
}
/* Walzenenden als Kreise auf der vorderen Seitenwand (y = yw) eines Gehaeuses: zeigt das Walzwerk im Gehaeuse */
function anWalzen(I, yw, P, r, d) {
  each(P, function (q) {
    I.poly(ikKreis([q[0], yw, q[1]], [1, 0, 0], [0, 0, 1], r, 18), IKF.D, { d: d, sw: 0.8 });
    I.poly(ikKreis([q[0], yw + 0.05, q[1]], [1, 0, 0], [0, 0, 1], r * 0.35, 10), IKF.W, { d: d + 0.01, sw: 0.6 });
  });
}
/* Gehaeuse auf dem Bett (Kasten ueber dem Band) */
function anGehaeuse(I, x, b, h, d, o) {
  o = o || {};
  var yw = o.yw || 17;
  I.box(x, -yw, 0, b, 2 * yw, h, { d: d });
  return yw;
}
/* Quader mit Ursprung P0 und Kantenvektoren ea, eb, ec (schraeg liegende Gehaeuse); gezeichnet werden die sichtbaren
   Seiten in fester Folge (zuerst die Seiten quer zu ea, dann eb, dann ec), Farben nach der Lage */
function anQuader(I, P0, ea, eb, ec, d, o) {
  o = o || {};
  var V = [ea, eb, ec], r = [];
  for (var k = 0; k !== 3; k++) {
    var u = V[(k + 1) % 3], v = V[(k + 2) % 3], w = V[k], n = cr(u, v);
    if (lt(dt(n, w), 0)) { n = mu(n, -1); }
    var P = gt(dt(n, VV), 0) ? ad(P0, w) : P0;
    if (!gt(Math.abs(dt(n, VV)), 1e-6)) { continue; }
    var f = gt(dt(n, VV), 0) ? n : mu(n, -1);
    var q = [P, ad(P, u), ad(ad(P, u), v), ad(P, v)];
    var ff = o.f ? o.f[k] : null;
    r.push(I.poly(q, ff || ikFarbe(f), ext({ d: d + k * 0.01 }, o.op || {})));
  }
  return r;
}
/* Lupe nur im aktuellen Bild der Folge: Scheibe in der Bildebene um c (Radius R), Griff (Winkel wg), Hinweislinie von p3
   von bis zum Rand (Winkel wv); Winkel in Grad, 0 = rechts, 90 = unten. Inhalt f(P) mit P(x, y) (x rechts, y unten). */
function anLupe(I, c, R, von, d, f, wg, wv) {
  var ring = [], g = (wg === undefined ? 135 : wg) * Math.PI / 180, v = (wv === undefined ? 200 : wv) * Math.PI / 180;
  for (var k = 0; k !== 41; k++) { var a = 2 * Math.PI * k / 40; ring.push(S2(c, R * Math.cos(a), R * Math.sin(a))); }
  if (von) { I.line([von, S2(c, R * Math.cos(v), R * Math.sin(v))], { d: d - 0.1, sw: 0.9, da: '2 2' }); }
  I.poly(ring, IKF.W, { d: d, sw: 1.6 });
  I.line([S2(c, R * 1.02 * Math.cos(g), R * 1.02 * Math.sin(g)), S2(c, R * 1.7 * Math.cos(g), R * 1.7 * Math.sin(g))], { d: d + 0.05, sw: 3.2 });
  f(function (x, y) { return S2(c, x, y); });
}
/* Blechprofile in Dimis Stil (Mittellinien, Box 0..100, y nach unten; nachgezeichnet, siehe profile_v1.json):
   PDF 3 (Flansch mit Kammer und Wandtasche) und Wickelfalz (zwei Bandkanten ineinander) */
var ANP3 = [[29.8, 85.0], [29.9, 76.6], [30.4, 74.2], [31.1, 73.6], [34.2, 72.9], [35.7, 71.9], [36.9, 69.6], [37.0, 68.2], [37.0, 55.4], [36.8, 54.0], [35.8, 53.7], [34.9, 54.0], [34.7, 54.9], [34.7, 67.9], [34.5, 69.5], [34.0, 70.3], [32.7, 70.8], [31.9, 70.8], [30.4, 70.0], [30.0, 68.7], [29.9, 22.8], [30.4, 20.9], [31.0, 20.4], [32.1, 20.1], [76.8, 20.2], [77.8, 21.0], [78.2, 22.7], [78.0, 34.9], [77.8, 35.8], [77.1, 36.7], [76.0, 37.0], [74.2, 36.9], [67.1, 30.0], [65.7, 29.6], [51.4, 29.6], [49.5, 30.0], [47.9, 30.9], [46.0, 32.9], [32.6, 50.0], [32.4, 51.0], [32.2, 65.9]];
var ANWF = [
  [[43.6, 65.7], [59.0, 65.6], [59.3, 65.2], [59.3, 61.4], [58.9, 60.9], [39.5, 60.9], [39.1, 61.5], [39.1, 64.2], [38.8, 64.4], [19.6, 64.5]],
  [[80.2, 64.4], [61.9, 64.4], [61.6, 64.7], [61.6, 67.4], [61.2, 67.9], [41.8, 67.9], [41.3, 67.4], [41.3, 63.9], [41.8, 63.3], [57.1, 63.3]]
];
/* Profil in die Lupe: Punkte p (0..100) mit Mitte (cx, cy), Massstab s, Drehung dr (0: wie gezeichnet, 1: 90 Grad,
   unten wird rechts); o.gelb: Liste von Bereichen [von, bis] (Punktindex), die gelb ueber dem Profil liegen (Merkmal) */
function anProfilLupe(I, P, pts, cx, cy, s, dr, d, o) {
  o = o || {};
  function T(q) { return dr ? P((q[1] - cy) * s, -(q[0] - cx) * s) : P((q[0] - cx) * s, (q[1] - cy) * s); }
  I.line(pts.map(T), { d: d, sw: o.sw || 1.8, st: o.st || IKF.B });
  each(o.gelb || [], function (g) { I.line(pts.slice(g[0], g[1] + 1).map(T), { d: d + 0.01, sw: o.swg || 2.4, st: IKF.Y }); });
}

/* ===== P38 Kanalanlage (MCL Ultra, CL ECO, ODIN): Steckrahmen-Weg =====
   Laut Betriebsanleitungen MCL Ultra und CL ECO: Coil auf dem Spreizdorn, Einzug- und Richtwalzen, Profilwalzen fuer die
   Z-Sicke (in Laufrichtung, am Kanal quer zur Achse), Stanzeinheit fuer die Klinkungen, Kantstation: das Blech laeuft unter
   den Niederhalter, der klemmt, die Biegewange kantet um 90 Grad (Box: dreimal); das Messer vor dem Niederhalter trennt ab.
   Die Anlage liefert den Kanal ohne Falz. Danach (eigene Maschinen): Eckfalz formen und schliessen (DS), Steckrahmen an
   beiden Enden aufsetzen. Endbild: geschlossener Kanal mit Rahmen an beiden Enden. */
PSYM.P38 = { dt: 1.0, f: function (I) {
  var t = 1.2, W2 = COIL.W / 2, E = 26, a = 10, b = 14, f = 3, yS = [-6, 0, 6], DT = 1.0;
  ikAbwickler(I, -118, -96, -BETT, { d: 0 });
  /* Bett bis hinter die Kantstation (dort Ablage) */
  I.box(-98, -16, -BETT, E + 98 + 30, 32, BETT, { d: 1, ft: ANF.bett });
  /* Walzwerk: Einzug-, Richt- und Profilwalzen im Gehaeuse */
  var y1 = anGehaeuse(I, -92, 24, 13, 3);
  anWalzen(I, y1 + 0.05, [[-88, 3.4], [-82, 3.4], [-76, 3.4], [-85, 7.4], [-79, 7.4]], 1.9, 3.2);
  anWalzen(I, y1 + 0.05, [[-71.5, 5.2]], 2.9, 3.2);
  /* Stanzeinheit mit Zylinder; der Stempel faehrt im zweiten Bild einmal ab (festes Teil, Zeit = Bild 1) */
  anGehaeuse(I, -60, 12, 11, 3.3);
  I.zyl([-54, 0, 11], [-54, 0, 16], 2.4, { d: 3.4 });
  I.mit('zu', function () { I.zyl([-54, 0, 13], [-54, 0, 18], 1.4, { d: 3.45, sty: { '--my': '3px', '--mt': '.8s', '--zs': (DT + 0.1) + 's' } }); });
  /* Kantstation: Staender hinter dem Blech, Niederhalter quer ueber dem Blech, Biegewange an der Kante E */
  I.box(E - 22, -30, -BETT, 24, 12, BETT + 22, { d: 0.5 });
  I.box(E - 7, -18, t + 0.3, 6, 6, 3.2, { d: 0.6 });
  I.box(E - 7, -12, t + 0.3, 6, W2 + 11, 3.2, { d: 2.5 });
  I.box(E, -W2 - 2, 0, 3, COIL.W + 4, 2, { d: 1.2 });
  /* Blech: laeuft vom Walzwerk bis xe; Sicken hinter dem Walzwerk, Klinkungen hinter der Stanze */
  function blech(xe, klink) {
    anBlech(I, -68, xe, 2, { sx: -68, kl: klink ? [E - b - f, E - b, E, E + a].filter(function (x) { return gt(x, -46); }) : [] });
  }
  /* Kanal auf der Ablage hinter der Kantstation */
  var K = { x0: E + 8, x1: E + 8 + b, z0: 0, z1: a, y0: -W2, y1: W2, t: 1.1 };
  I.folge(9, function (k) {
    if (k === 0) { blech(-38, false); return; }
    if (k === 1) { blech(E + a, true); return; }
    if (k !== 6) { if (lt(k, 6)) { blech(k === 5 ? E - b - f : E, true); } }
    /* Kantfolge an der Kante E: Schenkel a hoch; umgekehrtes L; offene Box ueber dem Blech; Messer trennt */
    var C = null;
    if (k === 2) { C = [[E, a], [E, 0]]; }
    if (k === 3) { C = [[E - a, b], [E, b], [E, 0]]; }
    if (k === 4 || k === 5) { C = [[E - b, 0], [E - b, a], [E, a], [E, 0]]; }
    if (C) {
      anProfilY(I, C, -W2, W2, 3, { sicken: k === 4 || k === 5 ? yS : null });
      if (k === 2) { ikStrich(I, [[E + 0.05, -W2, 0.2], [E + 0.05, W2, 0.2]], { d: 4, sw: 2.2 }); }
      if (k === 5) {
        /* Messer hat geschnitten: Bodenstueck mit Falzzugabe (gelb) bleibt an der Box, das Band endet am Messer */
        anBlech(I, E - b - f, E, 2.8, { sx: E - b - f });
        anPoly(I, [[E - b - f, -W2, t + 0.12], [E - b, -W2, t + 0.12], [E - b, W2, t + 0.12], [E - b - f, W2, t + 0.12]], IKY.ft, 2.9, { sw: 0.8 });
        I.box(E - b - f - 2.2, -W2 - 1, t + 3, 1.2, COIL.W + 2, 9, { d: 4.2, ft: IKF.D });
      }
      return;
    }
    if (k === 6) {
      /* Kanal auf der Ablage, noch ohne Falz: offene Ecke rechts unten, Falzzugabe (gelb) steht ueber */
      blech(E - b - f, true);
      var Co = [[K.x1 + f, 0], [K.x0, 0], [K.x0, a], [K.x1, a], [K.x1, 0.6]];
      anProfilY(I, Co, -W2, W2, 4, { sicken: yS });
      anPoly(I, [[K.x1, -W2, 0.06], [K.x1 + f, -W2, 0.06], [K.x1 + f, W2, 0.06], [K.x1, W2, 0.06]], IKY.ft, 4.3, { sw: 0.8 });
      return;
    }
    blech(E - b - f, true);
    if (k === 7) {
      /* Eckfalz geformt und geschlossen (Kanal-Falz-Schliessmaschine) */
      anKanalZu(I, K, 4, { sicken: yS, naht: 'gelb' });
      return;
    }
    /* k = 8: Steckrahmen an beiden Enden aufgesetzt: geschlossener Kanal mit Rahmen (Endbild) */
    anKanalZu(I, K, 4, { sicken: yS, naht: 'blau', rahmen: { h: 3.2, l: 3.2 }, gelb: 1 });
  });
} };

/* ===== P45 Vollautomatische PDF-Anlage: vom Coil zum geschlossenen Kanal mit beidseitig angeformtem Flansch =====
   Stationen nach den Betriebsanleitungen Stage 1, RF PDF 3 und Stage 3 (PDF 3) und dem Layout der Volllinie:
   Coil-Selektor (4 Coils), Einzug, Richten, Z-Sicke; Ausklinken links und rechts (Pittsburgh-Ausklinkung an Anfang und Ende,
   Eckausklinkung an den Biegestellen); querfahrende Pittsburgh-Einheit: Trennrollen schneiden quer ab, die folgenden
   Rollen formen an beiden neuen Kanten den Falz (vorne maennlich, hinten weiblich), Dichtmittel in den weiblichen Falz;
   Flanschprofilierer formt an beiden Laengskanten gleichzeitig den PDF-3-Flansch; Foerderer; Kantautomat: die
   Biegewange kantet dreimal an den Eckausklinkungen, der Falz wird eingelegt und von hinten geschlossen.
   Ergebnis: geschlossener Kanal, Flansch an beiden Enden (Ecken ausgeklinkt; Eckwinkel zeigen wir nicht). */
PSYM.P45 = { dt: 0.95, f: function (I) {
  var DT = 0.95, t = COIL.t, W = COIL.W, W2 = W / 2, a = 8, b = 11, f = 2.5, h = 2.2, l = 1.6, g = 1.2, ys = [-6, 0, 6];
  var Lb = 2 * a + 2 * b + f, xc = -206, xB = -190, xS = -166, xK = -146, xP = -134, xR0 = -124, xR1 = -70, E = -14;
  /* Ausklinkungen eines Zuschnitts mit Vorderkante xv: Ecken c1..c3, Falzecke c4; Flanschstuecke dazwischen ab xa */
  function kl(xv) { return [xv - a, xv - a - b, xv - 2 * a - b, xv - Lb + f]; }
  function fl(xv, xa) {
    var c = kl(xv), r = [[c[3] + g / 2, c[2] - g / 2], [c[2] + g / 2, c[1] - g / 2], [c[1] + g / 2, c[0] - g / 2], [c[0] + g / 2, xv - g / 2]];
    return r.map(function (q) { return [Math.max(q[0], xa === undefined ? -1e9 : xa), q[1]]; });
  }
  /* Coil-Selektor mit vier Coils, das vordere laeuft; Band bis zum Bett */
  anCoilWahl(I, xc, [0, -30, -58, -87], [COIL.W, 16, 12, 18], [COIL.R, 10.5, 11.5, 9.5], -BETT, 0);
  ikDreh(I, [xc, W2 + 0.1, -COIL.R], [0, 1, 0], COIL.R - 7, { d: 0.3, sw: 0.9 });
  I.box(xc, -W2, 0, xB - xc, W, t, { d: 0.5 });
  I.line([[xc + 4, 0, t + 0.05], [xB - 1, 0, t + 0.05]], { d: 0.6, sw: 1, da: '3 4', cls: 'zl', sty: { '--lt': '.9s', '--lz': '9' } });
  /* Stufe 1 auf einem Bett: Einzug-, Richt- und Sickenwalzen; Ausklinkpresse; querfahrende Pittsburgh-Einheit */
  I.box(xB, -16, -BETT, -128 - xB, 32, BETT, { d: 1, ft: ANF.bett });
  I.box(xP - 5, -17, 0, 10, 4, 17, { d: 1.1 });
  var yw = anGehaeuse(I, -186, 20, 12, 1.5);
  anWalzen(I, yw + 0.05, [[-183, 3.2], [-178.5, 3.2], [-174, 3.2], [-180.8, 7], [-176.3, 7]], 1.7, 1.55);
  anWalzen(I, yw + 0.05, [[-169.5, 4.4]], 2.5, 1.55);
  anGehaeuse(I, -158, 12, 10, 1.8);
  I.zyl([-152, 0, 10], [-152, 0, 14.5], 2.4, { d: 1.85 });
  I.mit('zu', function () { I.zyl([-152, 0, 12], [-152, 0, 17], 1.4, { d: 1.9, sty: { '--my': '3px', '--mt': '.8s', '--zs': (DT + 0.1) + 's' } }); });
  /* Pittsburgh-Einheit: Schiene quer ueber dem Band, Wagen mit Trenn- und Profilrollen faehrt im dritten Bild quer
     ueber das Band und zurueck; gelb: Trennschnitt mit Falz an beiden neuen Kanten, Dichtmittel */
  I.box(xP - 4, -17, 14, 8, W2 + 21, 3, { d: 2.3 });
  var mvP = mvSty([0, -19, 0], 2 * DT + 0.05, 1.8);
  I.mit('zu', function () {
    I.box(xP - 4, W2 - 6, 4, 8, 7, 10, { d: 2.4, sty: mvP });
    I.zyl([xP - 1.2, W2 - 2.5, 2.6], [xP + 1.2, W2 - 2.5, 2.6], 1.9, { d: 2.42, sty: mvP });
    I.line([[xP + 2.4, W2 - 4.5, 3.9], [xP + 2.4, W2 - 4.5, t + 0.4]], { st: IKF.Y, sw: 1.6, d: 2.44, sty: mvP });
  });
  ikStrich(I, [[xP, W2 - 0.3, t + 0.1], [xP, -W2 + 0.3, t + 0.1]], { d: 1.3, pl: 1, sw: 2.2, cls: 'zd', sty: { '--zt': '.8s', '--zs': (2 * DT + 0.1) + 's' } });
  /* Flanschprofilierer (Duplex): Rollenstaender auf beiden Seiten, das Blech laeuft dazwischen auf einer Auflage */
  I.box(xR0, -18, -BETT, xR1 - xR0, 36, BETT - 7, { d: 3.0, ft: ANF.bett });
  I.box(xR0, -8, -7, xR1 - xR0, 16, 7, { d: 3.1 });
  I.box(xR0, -18, -7, xR1 - xR0, 5.4, 13, { d: 3.2 });
  I.box(xR0, 12.6, -7, xR1 - xR0, 5.4, 2.6, { d: 3.8 });
  each([-119, -110, -101, -92, -83, -74], function (xs, i) {
    I.box(xs - 1.6, 12.6, -4.4, 3.2, 5.4, 9.4, { d: 3.9 + i * 0.01 });
    anWalzen(I, 18.05, [[xs, 2.8]], 1.3, 3.905 + i * 0.01);
  });
  /* Foerderer und Kantautomat: schmale Auflagen (die Flansche haengen seitlich daneben), Staender hinten,
     Klemmbalken quer ueber dem Blech (der Kanal entsteht um ihn herum), Biegewange an der Kante E; Entnahmetisch */
  I.box(-66, -8, -BETT, 18, 16, BETT, { d: 5.0 });
  each([-4.5, 4.5], function (y) { I.line([[-65, y, 0.05], [-49, y, 0.05]], { d: 5.05, sw: 1, da: '2 2', cls: 'zl', sty: { '--lz': '6' } }); });
  I.box(E - 22, -32, -BETT, 26, 10, BETT + 20, { d: 6.0 });
  I.box(-44, -8, -BETT, E + 44, 16, BETT, { d: 6.2 });
  I.box(E, -W2 - 2, -4, 3, W + 4, 4, { d: 6.3 });
  I.box(E - 7, -22, t + 0.3, 6, 10, 3.4, { d: 6.15 });
  I.box(E - 7, -12, t + 0.3, 6, W2 + 11, 3.4, { d: 6.8 });
  each([[-4, -13], [19, -13], [-4, 10], [19, 10]], function (q, i) { I.box(q[0], q[1], -BETT, 3, 3, BETT - 3, { d: 8.9 + i * 0.01 }); });
  I.box(-6, -15, -3, 28, 30, 3, { d: 9.0 });
  /* Band in Stufe 1 bis zur Vorderkante xv (ueber dem Profilierer eigene Tiefe) */
  function band(xv, k) {
    var o = { sx: xS, kl: kl(xv).filter(function (x) { return gt(x, xK); }) };
    anBlech(I, xB, Math.min(xv, -128), 1.2, ext(o, { pv: !gt(xv, -128) }));
    if (gt(xv, -128)) { anBlech(I, -128, xv, 3.5, ext(o, { pv: 1 })); }
  }
  /* Restband nach dem Trennen: wartet an der Pittsburgh-Einheit (vordere Kante profiliert) */
  function rest() { anBlech(I, xB, xP, 1.2, { sx: xS, kl: kl(xP).filter(function (x) { return gt(x, xK); }) }); }
  var C5 = [[E, a], [E, 0]], C6 = [[E - a, b], [E, b], [E, 0]], C7 = [[E - b, 0], [E - b, a], [E, a], [E, 0]];
  var PF = { flansch: h, gelbF: 1, luecke: g, sicken: ys };
  I.folge(10, function (k) {
    if (k === 0) { band(-120, k); return; }
    if (k === 1) { band(-106, k); return; }
    if (k === 2) { band(xP + Lb, k); return; }
    rest();
    if (k === 3) {
      /* im Flanschprofilierer: vorne schon angeformt */
      var x0 = -112;
      anBlech(I, x0, x0 + Lb, 3.5, { sx: -1e9, kl: kl(x0 + Lb), fl: fl(x0 + Lb, -96), gelb: 1, pv: 1, ph: 1 });
      return;
    }
    if (k === 4) { anBlech(I, -68, -68 + Lb, 6.6, { sx: -1e9, kl: kl(-68 + Lb), fl: fl(-68 + Lb), gelb: 1, pv: 1, ph: 1 }); return; }
    if (k === 5) { anBlech(I, E + a - Lb, E, 6.6, { sx: -1e9, kl: kl(E + a), fl: fl(E + a), gelb: 1, ph: 1 }); anProfilY(I, C5, -W2, W2, 7.2, PF); return; }
    if (k === 6) { anBlech(I, E + a + b - Lb, E, 6.6, { sx: -1e9, kl: kl(E + a + b), fl: fl(E + a + b), gelb: 1, ph: 1 }); anProfilY(I, C6, -W2, W2, 7.2, PF); return; }
    if (k === 7) { anBlech(I, E - b - f, E, 6.6, { sx: -1e9, fl: fl(E + 2 * a + b), gelb: 1, ph: 1 }); anProfilY(I, C7, -W2, W2, 7.2, PF); return; }
    var Pd = { h: h, l: l, g: g };
    if (k === 8) {
      /* Falz eingelegt und von hinten geschlossen: Kanal zu; die Naht sieht man innen durch die Oeffnung */
      var K8 = { x0: E - b, x1: E, z0: 0, z1: a, y0: -W2, y1: W2, t: 1.1 };
      anKanalZu(I, K8, 7, { pdf: Pd, gelb: 1, sicken: ys });
      I.box(E - b - 3.6, -W2, 0.3, 2.4, W, 2.4, { d: 6.9 });
      ikStrich(I, [[E - b + 1.2, W2 - 0.1, 1.2], [E - b + 1.2, W2 - 6.5, 1.2]], { d: 8.6, sw: 2.2 });
      return;
    }
    /* k = 9: fertiger Kanal auf dem Entnahmetisch (Endbild), Falz oben rechts; Lupe: Querschnitt PDF-3-Flansch */
    var Kf = { x0: 2, x1: 2 + b, z0: h, z1: h + a, y0: -W2, y1: W2, t: 1.1 };
    anKanalZu(I, Kf, 10, { pdf: Pd, gelb: 1, sicken: ys });
    I.line([[Kf.x1 - 0.8, Kf.y0 + 0.3, Kf.z1 + 0.06], [Kf.x1 - 0.8, Kf.y1 - 0.3, Kf.z1 + 0.06]], { d: 11.06, sw: 1.1 });
    anLupe(I, [-10, -54, 30], 18, [Kf.x1 + h * 0.6, W2, Kf.z1 + h * 0.6], 20, function (P) {
      anProfilLupe(I, P, ANP3, 54, 52.5, 0.42, 1, 20.1, { gelb: [[2, 19], [20, 40]], sw: 1.9 });
    }, 45, 128);
  });
} };

/* ===== P18 Wickelfalzrohr (TF 1401 Ultra, TF 1600 Ultra) =====
   Nach Betriebsanleitung TF 1401 Ultra und unserer Website (fuenf Schritte): 1 Abwickeln: Coil auf der Haspel;
   2 Anprofilieren: Bandfuehrung und Walzwerk profilieren beide Bandkanten (eine maennlich, eine als Falztasche), Schmierung
   auf das Band; 3 Wickeln: Vorschubwalzen schieben das Band schraeg in das Formwerkzeug, es legt sich als Schraube an;
   4 Falzen: die Schliessrolle drueckt von unten, der Falz wird flach und dicht; das Rohr dreht und waechst auf den
   Aufnahmetisch; 5 Trennen und Ablegen: das untere Rollenmesser sticht durch, der Schlitten faehrt mit dem Rohr mit,
   danach rollt der Abwurf das Rohr seitlich auf die Ablage. Endbild: Rohr mit Wickelfalz auf der Ablage, Enden offen;
   Lupe: Querschnitt des geschlossenen Falzes. Schraubenlinie in Weltkoordinaten linksgaengig, am Bildschirm rechtsgaengig
   wie das echte Rohr (wie bisher). */
PSYM.P18 = { dt: 1.0, f: function (I) {
  var R = 12, st = 13, kk = 2 * Math.PI / st, b = 12, xh0 = -34, xh1 = -26, xe = -30, zs = -R + 0.4, ZB = -R - 16;
  var al = Math.atan(st / (2 * Math.PI * R)), dx = Math.sin(al), dy = Math.cos(al), nn = [dy, dx, 0], ub = [-dx, dy, 0], ez = [0, 0, 1];
  /* Punkt auf dem Band: u = Abstand vom Einlauf in das Formwerkzeug gegen die Laufrichtung, q = quer zum Band */
  function BP(u, q, z) { return [xe - dx * u + nn[0] * q, dy * u + nn[1] * q, z === undefined ? zs : z]; }
  var xm = -6, xT0 = 0, xT1 = 54, yA = 27, zA = ZB + 2 + R, Lb = 76, u1 = 24, u2 = 42;
  /* Falz als Schraubenlinie auf der sichtbaren Seite eines Rohrs mit Achse (x, y0, z0) */
  function naht(xa, xb, y0, z0, d) {
    if (!gt(xb - xa, 0.5)) { return; }
    var seg = [], cur = [], n = Math.max(8, Math.round((xb - xa) * 3));
    for (var i = 0; i !== n + 1; i++) {
      var x = xa + (xb - xa) * i / n, ph = -Math.PI / 2 - kk * (x - xe), v = [0, Math.cos(ph), Math.sin(ph)];
      if (gt(v[1] + v[2], 0.08)) { cur.push([x, y0 + R * v[1], z0 + R * v[2]]); } else { if (gt(cur.length, 1)) { seg.push(cur); } cur = []; }
    }
    if (gt(cur.length, 1)) { seg.push(cur); }
    each(seg, function (s) {
      I.line(s.map(function (p) { return [p[0] + 0.9, p[1], p[2]]; }), { d: d, sw: 0.8 });
      ikStrich(I, s, { d: d + 0.01, sw: 2.2 });
    });
  }
  /* Versteifungssicke (Dimi 09.11.2026, Runde 9: kann gezeigt werden, kein Muss): die TF rollt 0, 1 oder 2 Sicken in das Band,
     sie laufen deshalb als Schraubenlinie parallel zum Falz; gezeigt wird eine Sicke mitten zwischen den Falzen (grau, ohne Gelb) */
  function sicke(xa, xb, y0, z0, d) {
    if (!gt(xb - xa, 0.5)) { return; }
    var seg = [], cur = [], n = Math.max(8, Math.round((xb - xa) * 3));
    for (var i = 0; i !== n + 1; i++) {
      var x = xa + (xb - xa) * i / n, ph = Math.PI / 2 - kk * (x - xe), v = [0, Math.cos(ph), Math.sin(ph)];
      if (gt(v[1] + v[2], 0.08)) { cur.push([x, y0 + R * v[1], z0 + R * v[2]]); } else { if (gt(cur.length, 1)) { seg.push(cur); } cur = []; }
    }
    if (gt(cur.length, 1)) { seg.push(cur); }
    each(seg, function (s) {
      I.line(s, { d: d, sw: 0.55, st: '#7B8796' });
      I.line(s.map(function (p) { return [p[0] + 0.7, p[1], p[2]]; }), { d: d + 0.005, sw: 0.5, st: '#FFFFFF' });
    });
  }
  function rohr(x0, x1, y0, z0, d) {
    I.zyl([Math.max(x0, xh1), y0, z0], [x1, y0, z0], R, { d: d, offen: 1, hohl: 1 });
    sicke(Math.max(x0, xh1 + 0.4) + 0.3, x1 - 0.4, y0, z0, d + 0.05);
    naht(Math.max(x0, xh1 + 0.4) + 0.3, x1 - 0.4, y0, z0, d + 0.1);
  }
  /* Maschinengestell hinter dem Formwerkzeug */
  I.box(-50, -15, ZB, 16, 30, R + 2 - ZB, { d: -3 });
  /* Schlitten-Fuehrung der Trennvorrichtung, Aufnahmetisch mit Abwurf, Ablage davor */
  I.box(xm - 7, -5, ZB, 15, 10, 2, { d: -2.5 });
  I.box(xT0, -7, ZB, xT1 - xT0, 14, -R - 0.6 - ZB, { d: -0.5 });
  each([6, 25, 44], function (x) { I.box(x, 7, -R - 3.2, 2.4, 4, 2.6, { d: -0.45 }); });
  each([7, 41], function (x) { I.box(x, 11, ZB, 3, 30, 2, { d: -0.4 }); });
  /* Band vom Coil bis in das Formwerkzeug; Mittellinie laeuft (Vorschub) */
  I.poly([BP(0, -b / 2), BP(Lb, -b / 2), BP(Lb, b / 2), BP(0, b / 2)], IKF.T, { d: -1 });
  I.line([BP(Lb - 3, 0, zs + 0.1), BP(3, 0, zs + 0.1)], { d: -0.9, sw: 1, da: '4 6', cls: 'zl', sty: { '--lt': '1s', '--lz': '8' } });
  /* Schritt 2: profilierte Bandkanten (gelb) vom Walzwerk bis zum Formwerkzeug */
  each([-1, 1], function (sg) {
    ikStrich(I, [BP(u1, sg * (b / 2 - 0.7), zs + 0.15), BP(1, sg * (b / 2 - 0.7), zs + 0.15)], { d: -0.85, sw: 2, pl: 1, cls: 'zd', sty: { '--zt': '1.2s', '--zs': '.1s' } });
  });
  /* Walzwerk (Rollenpaare fuer beide Kanten) auf einem Sockel, schraeg wie das Band */
  anQuader(I, BP(u1, -b / 2 - 3, ZB), mu(ub, u2 - u1), mu(nn, b + 6), [0, 0, zs - 5 - ZB], -0.8);
  anQuader(I, BP(u1, -b / 2 - 3, zs - 5), mu(ub, u2 - u1), mu(nn, b + 6), [0, 0, 11], -0.7);
  each([u1 + 3.5, u1 + 8, u1 + 12.5], function (u) {
    each([[zs + 2.6, 2.1], [zs - 2.2, 1.8]], function (zr) {
      var c = BP(u, b / 2 + 3.05, zr[0]);
      I.poly(ikKreis(c, ub, ez, zr[1], 16), IKF.D, { d: -0.65, sw: 0.8 });
      I.poly(ikKreis(ad(c, mu(nn, 0.05)), ub, ez, zr[1] * 0.35, 10), IKF.W, { d: -0.64, sw: 0.6 });
    });
  });
  /* Schmierung: Duese ueber dem Band vor dem Walzwerk spritzt fein auf das Band */
  var cD = BP(u2 + 7, 0, zs + 7);
  I.zyl(cD, ad(cD, [0, 0, 3]), 1.1, { d: -0.6 });
  each([-3, 0, 3], function (q) { I.line([ad(cD, [0, 0, -0.4]), BP(u2 + 7 + q * 0.2, q, zs + 0.3)], { d: -0.62, sw: 0.9, st: IKF.D, da: '1.2 1.6', cls: 'zl', sty: { '--lt': '.7s', '--lz': '10' } }); });
  /* Vorschubwalzen schieben das Band in das Formwerkzeug */
  ikRollenpaar(I, BP(15, 0), nn, 2.3, b + 4, zs + 2.5, zs - 2.5, { d: -0.55, du: -1.2 });
  /* Coil auf der Haspel, Achse quer zum Band; das Band laeuft unten tangential ab */
  var Rc = 11, C = BP(Lb, 0, zs + Rc), Cs = ad(C, mu(nn, -b / 2 - 3));
  I.box(Cs[0] - 1.6, Cs[1] - 1.6, ZB, 3.2, 3.2, C[2] - ZB, { d: -0.3 });
  I.box(Cs[0] - 7, Cs[1] - 3, ZB, 14, 6, 2, { d: -0.35 });
  I.zyl(Cs, ad(C, mu(nn, -b / 2)), 2, { d: -0.25, ende: false });
  I.zyl(ad(C, mu(nn, -b / 2)), ad(C, mu(nn, b / 2)), Rc, { d: 0.2, fe: IKF.T });
  I.line(ikKreis(ad(C, mu(nn, b / 2 + 0.05)), ub, ez, Rc - 3.5, 40), { d: 0.25, sw: 0.8 });
  I.zyl(ad(C, mu(nn, b / 2)), ad(C, mu(nn, b / 2 + 1.6)), 2.6, { d: 0.3, fe: IKF.D });
  ikDreh(I, ad(C, mu(nn, b / 2 + 0.1)), nn, Rc - 6.5, { d: 0.32, sw: 0.9 });
  /* Formwerkzeug als Ring um den Rohranfang; Schliessrolle unter dem Rohr direkt dahinter (dreht) */
  I.zyl([xh0, 0, 0], [xh1, 0, 0], R + 2.8, { d: 1.5, ende: false, f: IKF.I });
  ringPfad(I, [xh1, 0, 0], [1, 0, 0], R + 0.2, R + 2.8, IKF.R, { d: 1.6 });
  var xr = xh1 + 4.6, zr = -R - 3.4;
  I.box(xr - 1, -1.4, ZB, 2, 2.8, zr - ZB, { d: 1.55 });
  I.zyl([xr - 1.5, 0, zr], [xr + 1.5, 0, zr], 3.2, { d: 1.65 });
  ikDreh(I, [xr + 1.55, 0, zr], [1, 0, 0], 1.9, { d: 1.7, sw: 0.9, da: '2 3', rueck: 1 });
  /* Bildfolge: Rohr waechst; Trennen; abtrennen; Abwurf auf die Ablage (Endbild mit Lupe) */
  var X1 = [-6, 9, 24, 38, 50];
  /* Trennvorrichtung: Schlitten auf der Fuehrung, unteres Rollenmesser (hoch: sticht durch) */
  function messer(x, hoch, d) {
    var zc = hoch ? -R - 3.6 : -R - 5.2;
    I.box(x - 3.4, -4.5, ZB + 2, 6.8, 9, zc - 2.6 - ZB - 2, { d: d });
    I.poly(ikKreis([x + 0.4, 0, zc], [0, 1, 0], [0, 0, 1], 4.4, 28), IKF.T, { d: d + 0.1, sw: 1.3 });
    I.poly(ikKreis([x + 0.45, 0, zc], [0, 1, 0], [0, 0, 1], 1.3, 12), IKF.D, { d: d + 0.11, sw: 0.8 });
  }
  I.folge(8, function (k) {
    if (lt(k, 5)) {
      rohr(xh0, X1[k], 0, 0, 1.8);
      messer(xm, false, 1.3);
      ikDrehPfeil(I, [X1[k] - 5, 0, 0], [-1, 0, 0], R + 3, -Math.PI * 0.55, -Math.PI * 0.08, { d: 2.2, cls: '' });
      return;
    }
    if (k === 5) {
      /* Trennen: Messer sticht von unten durch und faehrt mit, der Schnitt laeuft rundum */
      rohr(xh0, X1[4] + 2, 0, 0, 1.8);
      messer(xm + 2, true, 1.3);
      I.halbring([xm + 2, 0, 0], [1, 0, 0], R + 0.15, { st: IKF.B, sw: 3.4, d: 2.0 });
      I.halbring([xm + 2, 0, 0], [1, 0, 0], R + 0.15, { st: IKF.W, sw: 1.4, d: 2.01 });
      return;
    }
    if (k === 6) {
      rohr(xh0, xm + 3, 0, 0, 1.8);
      rohr(xm + 6, X1[4] + 6, 0, 0, 1.9);
      messer(xm, false, 1.3);
      return;
    }
    /* k = 7: Rohr liegt auf der Ablage (Endbild), das naechste Rohr waechst; Lupe: geschlossener Wickelfalz */
    rohr(xh0, xm + 9, 0, 0, 1.8);
    messer(xm, false, 1.3);
    rohr(xm + 6, X1[4] + 6, yA, zA, 3);
    anLupe(I, [10.2, -30.2, 20], 16, [26, yA + R * 0.5, zA + R * 0.86], 20, function (P) {
      var s = 0.8, cx = 50.2, cy = 64.4, x0 = cx - 13.6 / s, x1 = cx + 13.6 / s;
      var A = ANWF[0].slice(0, ANWF[0].length - 1).concat([[x0, 64.5]]), B = [[x1, 64.4]].concat(ANWF[1].slice(1));
      ikPoly2(I, P, [[38, 59.6], [62.4, 59.6], [62.4, 69.2], [38, 69.2]].map(function (q) { return [(q[0] - cx) * s, (q[1] - cy) * s]; }), IKY.ft, 20.05, { st: IKF.Y, sw: 1 });
      anProfilLupe(I, P, A, cx, cy, s, 0, 20.1, { sw: 1.9 });
      anProfilLupe(I, P, B, cx, cy, s, 0, 20.12, { sw: 1.9, st: '#3D6A99' });
    }, 45, 120);
  });
} };

/* ---------- Prozess-Symbole, Runde 10 der Szene (Dimi 09.11.2026, Antworten Runde 11, Punkte 24 bis 39) ----------
   Ersetzt P04 (Versteifung: das Blech laeuft durch die Rollenpaare), P09 (Falzprofilieranlage: viele Rollenpaare, das Blech
   wird durchgezogen), P10 (Boerdelmaschine: Bord nach und nach auf Boegen, aussen und innen), P13 (Falzschliessmaschine: Kanal
   mit der Ecke nach unten durch Dreiergruppen von Rollen), P14 (Rahmenprofilieranlage: Steckrahmenprofil laeuft durch), P15
   (Ablaengsaege: Steckrahmenprofil, Schnittflaeche gelb), P17 (PDF Stufe 2: Blech durchziehen, umdrehen, andere Seite), P24
   (Bogenautomat: Rohr rein, Messer, Segmente drehen, Falze zu), P25 (Sickenmaschine: eine Rolle innen, eine aussen), P41
   (Schlitzschere: auch Kurven). Neu: P46 Bohrschrauber, P47 PDF Stufe 1 Zuschnitt, P48 PDF Stufe 3 Kanten und Falz schliessen,
   P49 freistehende Falzschliessmaschine, P50 Segmentbogenmaschine mit zwei Stationen.
   Bausteine aus 60_prozess.js, 61_prozess_sym.js und 62_anlagen.js (P47 und P48 wie die Stationen in P45).
   Regel wie in 62_anlagen.js: Teile in einer Bildfolge (I.folge) bekommen keine Bewegungsklassen. */

/* Steckrahmenprofil im Schnitt (y quer, z hoch), schematisch: Kasten mit Hohlkammer fuer den Eckwinkel, darunter der
   doppelwandige Schenkel mit der Tasche fuer das Kanalblech (offen nach +y) */
var SRP = { aussen: [[0, 0], [18, 0], [18, 1.8], [4, 1.8], [4, 3.6], [18, 3.6], [18, 5.4], [7.5, 5.4], [7.5, 15], [0, 15]], kammer: [[1.3, 6.6], [6.2, 6.6], [6.2, 13.8], [1.3, 13.8]] };
/* Runde 12 der Szene (Dimi 10.11.2026): das Steckrahmenprofil ist duennes Blech wie im Lupenbild (profile_v1.json steckrahmen), kein
   Vollkoerper. Mittellinie aus der Lupe, um 90 Grad gedreht: y = in der Lupe nach unten (zur Kanalwand, Tasche offen nach +y),
   z = in der Lupe nach rechts (Flansch nach oben); Masse etwa wie vorher (13 breit, 15 hoch). SRP bleibt fuer aeltere Aufrufe. */
var SRPB = null;
function srpBlech() {
  if (SRPB) { return SRPB; }
  var P = (DATA.prof || {}).steckrahmen, k = 0.29, m = [];
  if (P) { each(P.teile, function (t) { if (t.r === 'profil') { m = t.p.map(function (q) { return [(q[1] - 20.2) * k, (q[0] - 25.6) * k]; }); } }); }
  SRPB = { m: m, t: 0.8 };
  return SRPB;
}
/* Blech im Schnitt: Band der Dicke t um die Mittellinie M */
function srpBand(M, t) {
  var L = [], R = [], n = M.length, h = t / 2;
  for (var i = 0; i !== n; i++) {
    var a = M[Math.max(0, i - 1)], b = M[Math.min(n - 1, i + 1)], dx = b[0] - a[0], dy = b[1] - a[1], l = Math.sqrt(dx * dx + dy * dy) || 1;
    L.push([M[i][0] - dy / l * h, M[i][1] + dx / l * h]); R.push([M[i][0] + dy / l * h, M[i][1] - dx / l * h]);
  }
  return L.concat(R.reverse());
}
/* Profil laengs x von x0 bis x1: Blechstreifen (nach Tiefe geordnet) und die vordere Stirn; o.s Massstab, o.gelb Stirn gelb */
function ikProfilX(I, x0, x1, y0, z0, d, o) {
  o = o || {};
  var S = srpBlech(), M = S.m, n = M.length, i, s = o.s || 1, F = [], t0 = 1e9, t1 = -1e9;
  if (!n) { return; }
  function P(x, q) { return [x, y0 + q[0] * s, z0 + q[1] * s]; }
  for (i = 0; i !== n - 1; i++) {
    var q4 = [P(x0, M[i]), P(x1, M[i]), P(x1, M[i + 1]), P(x0, M[i + 1])], tt = DE(mitte(q4));
    F.push({ q: q4, t: tt }); t0 = Math.min(t0, tt); t1 = Math.max(t1, tt);
  }
  each(F, function (f) { I.poly(f.q, null, { d: d + 0.015 * (gt(t1, t0) ? (f.t - t0) / (t1 - t0) : 0), sw: 0.8, cls: o.cls, sty: o.sty }); });
  var gelb = !!o.gelb;
  I.poly(srpBand(M, S.t).map(function (q) { return P(x1, q); }), gelb ? IKF.Y : (o.f || IKF.B), { d: d + 0.02, sw: gelb ? 1.4 : 0.6, st: gelb ? IKF.Y : IKF.B, cls: o.cls, sty: o.sty });
}
/* Rollenpaar ueber und unter dem Blech (Achse ax): unten z0 - r, oben z1 + r */
function ikRollen2(I, x, y, ax, r, L, z0, z1, d) {
  var h = mu(nz(ax), L / 2);
  I.zyl(sb([x, y, z0 - r], h), ad([x, y, z0 - r], h), r, { d: d - 4 });
  I.zyl(sb([x, y, z1 + r], h), ad([x, y, z1 + r], h), r, { d: d });
  var e = gt(dt(nz(ax), VV), 0) ? h : mu(h, -1);
  ikDreh(I, ad([x, y, z1 + r], e), ax, r * 0.55, { d: d + 0.05, sw: 0.9, da: '2 2.5' });
}

/* P04 Versteifung (Z-, V-, Trapezsicke, Punkt 24): das Blech laeuft durch die Rollenpaare, hinter den Rollen stehen die Sicken */
function sickenBild(I, art) {
  var t = 1.5, w = 22, ys = (art === 'v') ? [0] : [-12, 0, 12], N = 6, L = 84;
  I.folge(N + 1, function (k, s) {
    var x0 = -82 + 56 * s, x1 = x0 + L;
    I.box(x0, -w, 0, L, 2 * w, t, { d: 0 });
    each(ys, function (y, i) {
      if (!gt(x1, 3)) { return; }
      var xa = 3, xb = x1 - 1;
      if (art === 't') {
        I.poly([[xa, y - 1.8, t + 0.05], [xb, y - 1.8, t + 0.05], [xb, y + 1.8, t + 0.05], [xa, y + 1.8, t + 0.05]], IKF.I, { d: 1 + i * 0.01, sw: 0.8, st: IKF.I });
        I.line([[xa, y - 1.8, t + 0.1], [xb, y - 1.8, t + 0.1]], { st: IKF.Y, sw: 2.2, d: 1.1 });
        I.line([[xa, y + 1.8, t + 0.1], [xb, y + 1.8, t + 0.1]], { st: IKF.Y, sw: 2.2, d: 1.1 });
      } else {
        if (art === 'z') { I.line([[xa, y + 1.8, t + 0.1], [xb, y + 1.8, t + 0.1]], { d: 1.05, sw: 1.1 }); }
        I.line([[xa, y, t + 0.1], [xb, y, t + 0.1]], { st: IKF.Y, sw: 2.6, d: 1.1 });
      }
    });
  });
  each(ys, function (y, i) {
    I.zyl([0, y - 2.4, -7], [0, y + 2.4, -7], 5.6, { d: -3 + i * 0.1 });
    I.zyl([0, y - 2.4, t + 7], [0, y + 2.4, t + 7], 7, { d: 4 + i * 0.1 });
    ikDreh(I, [0, y + 2.4, t + 7], [0, 1, 0], 4.2, { d: 4.05 + i * 0.1, sw: 0.9, da: '2 3' });
  });
  ikPfeil(I, [-40, w + 6, t], [-22, w + 6, t], { d: 0.5, sw: 1.4 });
  ikLupe(I, [40, -44, 26], 12.5, 3, function (P, k) {
    var h = [0, 0.55, 1][k], W;
    if (art === 'z') { W = [[-10, 1.6], [-1.8, 1.6], [1.8, 1.6 - 3.4 * h], [10, 1.6 - 3.4 * h]]; }
    else if (art === 'v') { W = [[-10, -1], [-3.2, -1], [0, -1 + 3.4 * h], [3.2, -1], [10, -1]]; }
    else { W = [[-10, -1], [-4.4, -1], [-2.6, -1 + 2.4 * h], [2.6, -1 + 2.4 * h], [4.4, -1], [10, -1]]; }
    ikLinie2(I, P, W, 20.2, { sw: 2.4 });
    if (k === 2) { ikLinie2(I, P, W.slice(1, W.length - 1), 20.3, { sw: 2.6, st: IKF.Y }); }
  }, { von: [14, ys[0], t + 0.2] });
  I.ex.push([60, w, 0], [-82, -w, 0]);
}
PSYM.P04 = { dt: 0.45, f: function (I) { sickenBild(I, 'z'); } };
PSYM.P04b = { dt: 0.45, f: function (I) { sickenBild(I, 'v'); } };
PSYM.P04c = { dt: 0.45, f: function (I) { sickenBild(I, 't'); } };

/* P09 Falzprofilieranlage (Punkt 27): der Zuschnitt wird quer zur Coilrichtung durch fuenf Rollenpaare an seiner Kante gezogen,
   die Tasche waechst von Station zu Station; im Endbild steckt das hintere Ende noch in den Rollen, der vordere Teil ist fertig.
   Lupe: Querschnitt der Pittsburgh-Tasche */
PSYM.P09 = { dt: 0.42, f: function (I) {
  var t = 1.5, Lb = 40, f = 7, hP = 4.2, r = 3.6, xk = 26, ys = [16, 8, 0, -8, -16], N = 6;
  I.box(xk - f - 2, -24, -14, f + 6, 48, 6, { d: -6, ft: IKF.I });
  I.folge(N + 1, function (k, s) {
    var yv = 58 - 42 * s;
    I.box(xk - 44, yv - Lb, 0, 44 - f, Lb, t, { d: 0 });
    var grenzen = [1e9].concat(ys).concat([-1e9]);
    for (var j = 0; j !== grenzen.length - 1; j++) {
      var ya = Math.max(Math.min(grenzen[j], yv), yv - Lb), yb = Math.max(Math.min(grenzen[j + 1], yv), yv - Lb);
      if (!gt(ya - yb, 0.3)) { continue; }
      var hh = t + (hP - t) * j / ys.length;
      I.box(xk - f, yb, 0, f, ya - yb, hh, j === ys.length ? ext(IKY, { d: 0.2 + j * 0.01 }) : { d: 0.2 + j * 0.01 });
    }
  });
  each(ys, function (y, i) { ikRollen2(I, xk - f / 2, y, [1, 0, 0], r, f + 3, 0, hP, 3 + i * 0.1); });
  ikPfeil(I, [-6, 40, t + 0.1], [-6, 24, t + 0.1], { d: 1.5, sw: 1.5 });
  var c = [36, -50, 26], R = 12.5, ring = [];
  for (var k = 0; k !== 41; k++) { var a = 2 * Math.PI * k / 40; ring.push(S2(c, R * Math.cos(a), R * Math.sin(a))); }
  I.poly(ring, IKF.W, { d: 20, sw: 1.6, sty: { '--n': '0' } });
  I.line([S2(c, -R * 0.72, R * 0.72), S2(c, -R * 1.22, R * 1.22)], { d: 20.05, sw: 3.2, sty: { '--n': '0' } });
  function bog(cu, cv, rr, a0, a1) { var q = []; for (var i = 0; i !== 7; i++) { var a = a0 + (a1 - a0) * i / 6; q.push([cu + rr * Math.cos(a), cv + rr * Math.sin(a)]); } return q; }
  var vO = -3.4, vM = 0, vU = 3.4, rO = (vM - vO) / 2, rU = (vU - vM) / 2;
  var PP = [
    [[-11, vO], [10, vO]],
    [[-11, vO], [5, vO]].concat(bog(5, vO + rO, rO, -Math.PI / 2, Math.PI / 2)).concat([[-1, vM], [-1, vM + 6]]),
    [[-11, vO], [5, vO]].concat(bog(5, vO + rO, rO, -Math.PI / 2, Math.PI / 2)).concat([[-1, vM]]).concat(bog(-1, vM + rU, rU, -Math.PI / 2, -1.5 * Math.PI)).concat([[9.5, vU]])
  ];
  I.folge(3, function (j) { I.line(PP[j].map(function (q) { return S2(c, q[0], q[1]); }), { d: 20.2, st: IKF.Y, sw: 2.2 }); });
  I.line([[xk - f / 2, -20, hP + 0.2], S2(c, -R * 0.94, R * 0.34)], { d: 5, sw: 0.9, da: '2 2' });
  I.ex.push([xk - 44, 58, 0], [xk, -40, 0]);
} };

/* P10 Boerdelmaschine (Punkt 28): Seitenblech eines Bogens (Viertelring) laeuft zwischen zwei Rollen durch, der 90-Grad-Bord
   stellt sich nach und nach auf, erst am Aussenradius, dann am Innenradius; fertige Borde gelb */
PSYM.P10 = { dt: 0.28, f: function (I) {
  var ri = 16, ro = 40, t = 1.4, hB = 5.5, N = 10, M = 18, i;
  function Pk(r, a, z) { return [r * Math.cos(a) - 28, r * Math.sin(a) - 28, z]; }
  var G = [];
  for (i = 0; i !== M + 1; i++) { var a = Math.PI / 2 * i / M; G.push([Pk(ri, a, t), Pk(ro, a, t)]); }
  var top = []; each(G, function (q) { top.push(q[1]); }); for (i = M; i !== -1; i--) { top.push(G[i][0]); }
  I.poly(top, IKF.T, { d: 0 });
  I.band(G.map(function (q) { return [[q[1][0], q[1][1], 0], q[1]]; }), { d: -0.5 });
  function bord(r, a1, gelb, d) {
    var n = Math.max(1, Math.round(M * a1 / (Math.PI / 2))), H = [];
    for (var j = 0; j !== n + 1; j++) { var aa = a1 * j / n; H.push([Pk(r, aa, t), Pk(r, aa, t + hB)]); }
    I.band(H, { d: d, f: gelb ? IKF.Y : null });
  }
  function rollen(r, a, d) {
    var p = Pk(r, a, 0), nrm = [Math.cos(a), Math.sin(a), 0];
    I.zyl(ad(p, ad(mu(nrm, 4.2), [0, 0, -2])), ad(p, ad(mu(nrm, 4.2), [0, 0, hB + 6])), 3.4, { d: d });
    I.zyl(ad(p, ad(mu(nrm, -4.2), [0, 0, t + 0.5])), ad(p, ad(mu(nrm, -4.2), [0, 0, hB + 6])), 3.4, { d: d + 0.1 });
  }
  I.folge(N + 1, function (k) {
    var h = N / 2;
    if (!gt(k, h)) {
      var a1 = Math.PI / 2 * k / h; if (gt(a1, 0.01)) { bord(ro, a1, k === h, 1); }
      rollen(ro, Math.max(a1, 0.05), 3);
    } else {
      bord(ro, Math.PI / 2, true, 1);
      var a2 = Math.PI / 2 * (k - h) / h; if (gt(a2, 0.01)) { bord(ri, a2, k === N, 1.2); }
      rollen(ri, Math.max(a2, 0.05), 3);
    }
  });
  I.ex.push(Pk(ro + 8, 0, 0), Pk(ro + 8, Math.PI / 2, 0), Pk(0, 0, 14));
} };

/* P13 Falzschliessmaschine (DS, Punkt 30): der Kanal liegt um 45 Grad gedreht, die offene Falzecke unten. Zehn Rollengruppen
   (eine Rolle unter der Ecke, je eine an den beiden Waenden) ziehen ihn durch; vor den Rollen steht die Lippe offen nach
   unten, dahinter ist der Kanalfalz geschlossen (gelb). Die Stirn zeigt den gedrehten Querschnitt. */
PSYM.P13 = { dt: 0.24, f: function (I) {
  var wb = 16, c = wb * Math.SQRT1_2, L = 56, N = 8, xs = [], j, xa = -27, xe = 27, wd = 1.3;
  for (j = 0; j !== 10; j++) { xs.push(xa + 6 * j); }
  var nv = [0, Math.SQRT1_2, -Math.SQRT1_2], ev = [0, Math.SQRT1_2, Math.SQRT1_2], nu = [0, -Math.SQRT1_2, -Math.SQRT1_2], eu = [0, -Math.SQRT1_2, Math.SQRT1_2];
  I.box(-33, -7, -13, 66, 14, 4, { d: -8, ft: IKF.I });
  each(xs, function (x, i) {
    I.zyl([x, -2.2, -4.9], [x, 2.2, -4.9], 2.4, { d: -6 + i * 0.01 });
    var pv = ad(ad([x, 0, 0], mu(ev, 3.2)), mu(nv, 2.1)), pu = ad(ad([x, 0, 0], mu(eu, 3.2)), mu(nu, 2.1));
    I.zyl(sb(pu, mu(eu, 1.4)), ad(pu, mu(eu, 1.4)), 1.9, { d: -7 + i * 0.01 });
    I.zyl(sb(pv, mu(ev, 1.4)), ad(pv, mu(ev, 1.4)), 1.9, { d: -5.5 + i * 0.01 });
  });
  function lippe(x) { return 3.2 * Math.max(0, Math.min(1, (xe - x) / (xe - xa))); }
  I.folge(N + 1, function (k, s) {
    var x1 = 4 + 52 * s, x0 = x1 - L;
    function B(x) { return [x, 0, 0]; } function V(x) { return [x, c, c]; } function T(x) { return [x, 0, 2 * c]; } function U(x) { return [x, -c, c]; }
    I.poly([V(x0), T(x0), T(x1), V(x1)], null, { d: 0 });
    /* offene Lippe unter der Ecke, im Rollenbereich wird sie flacher */
    var xl = Math.min(x1, xe);
    if (gt(xl - x0, 0.3)) {
      var q = [B(x0), B(xl)], m = 8;
      for (var i = m; i !== -1; i--) { var x = x0 + (xl - x0) * i / m; q.push([x, 0, -lippe(x)]); }
      I.poly(q, IKF.L, { d: 0.3, sw: 1.1 });
    }
    var xg = Math.max(x0, xe);
    if (gt(x1 - xg, 0.3)) { I.line([[xg, 0.15, 0.15], [x1 - 0.3, 0.15, 0.15]], { st: IKF.Y, sw: 3, d: 0.4 }); }
    /* Stirn mit Blick ins Innere, die geschlossene Ecke gelb */
    I.poly([B(x1), V(x1), T(x1), U(x1)], '#E3E9F0', { d: 0.5 });
    I.innen([[x1, 0, wd * 1.41], [x1, c - wd * 1.41, c], [x1, 0, 2 * c - wd * 1.41], [x1, -c + wd * 1.41, c]], [-1, 0, 0], L, 0.55, { m: c });
    if (gt(x1 - 0.3, xe)) { I.poly([[x1 + 0.05, 0, 0], [x1 + 0.05, 1.6, 1.6], [x1 + 0.05, 0, 2.6], [x1 + 0.05, -1.6, 1.6]], IKF.Y, { d: 0.62, sw: 0.8 }); }
  });
  ikPfeil(I, [-40, -c - 4, 2 * c + 2], [-24, -c - 4, 2 * c + 2], { d: 1, sw: 1.4 });
  I.ex.push([60, 0, -13], [-56, 0, 2 * c + 2]);
} };

/* P14 Rahmenprofilieranlage (Punkt 31): das Band laeuft durch die Stationen, heraus laeuft das Steckrahmenprofil */
PSYM.P14 = { dt: 0.3, f: function (I) {
  var w = 5, t = 1, h = 6, r = 4.6, X = [[-54, -36], [-28, -10], [-2, 16]], N = 6;
  each(X, function (q, i) {
    var x0 = q[0], L = q[1] - q[0];
    I.box(x0, -w, 0, L, 2 * w, t, { d: 1 + i });
    if (i) { I.box(x0, w - t, 0, L, t, h, { d: 1.2 + i }); }
    if (gt(i, 1)) { I.box(x0, -w, 0, L, t, h, { d: 1.1 + i }); }
  });
  each([-32, -6], function (x, i) { ikRollenpaar(I, [x, 0, 0], [0, 1, 0], r, 2 * w + 2, h + r + 0.6, -r - 0.6, { d: 6 + i, du: -1 + i * 0.1 }); });
  ikStrich(I, [[-54, 0, t + 0.05], [14, 0, t + 0.05]], { d: 5, da: '5 6', cls: 'zl', sty: { '--lt': '.7s', '--lz': '6' } });
  I.folge(N + 1, function (k, s) { ikProfilX(I, 18, 24 + 28 * s, -3.9, -0.5, 9, { s: 0.6, gelb: k === N }); });
  ikPfeil(I, [-54, -w - 7, 0], [-40, -w - 7, 0], { d: 0.5, sw: 1.3 });
  I.ex.push([52, 6, 10]);
} };

/* Farbe zwischen zwei Hexfarben (fuer Rundungen: weicher Verlauf statt Kanten; Runde 18) */
function ikMisch(a, b, t) {
  function h(s, i) { return parseInt(s.substr(1 + 2 * i, 2), 16); }
  var r = '#';
  for (var i = 0; i !== 3; i++) { var v = Math.round(h(a, i) + (h(b, i) - h(a, i)) * t).toString(16); r += (v.length === 1 ? '0' : '') + v; }
  return r;
}
/* P58 (Rollformer fuer den Kulissenrahmen) und P59 (T-Buegel-Profil): seit Runde 19 in 65_symbole_r19.js (zwei Durchgaenge bzw.
   doppelt gelegter Steg); die Fassungen der Runde 18 an dieser Stelle sind entfernt. */

/* P15 Ablaengsaege (Punkt 29): das Steckrahmenprofil wird abgelaengt; danach ist die Schnittflaeche gelb */
PSYM.P15 = { f: function (I) {
  var xc = 6, R = 15, y0 = -6.4, SB2 = srpBlech();
  ikProfilX(I, -44, xc - 0.5, y0, 0, 1, {});
  I.mit('zv', function () { ikProfilX(I, xc + 0.5, xc + 30, y0, 0, 1.5, { sty: mvSty([10, 0, 0], 1.25, 0.5) }); });
  /* Schnittflaeche gelb: das Blech im Schnitt (Runde 12 der Szene: duennes Profil wie in der Lupe) */
  I.poly(srpBand(SB2.m, SB2.t).map(function (p) { return [xc - 0.45, y0 + p[0], p[1]]; }), IKF.Y, { d: 2.4, sw: 1.8, st: IKF.Y, cls: 'zi', sty: zs(1.5) });
  var c = [xc, 0, 15 + R - 3], z = [];
  for (var i = 0; i !== 48; i++) { var a = 2 * Math.PI * i / 48, rr = (i % 2) ? R : R + 1.8; z.push(ad(c, [0, rr * Math.cos(a), rr * Math.sin(a)])); }
  var m = { '--my': '8px', '--mt': '1.1s' };
  I.poly(z, IKF.R, { d: 3, cls: 'zu', sty: m });
  I.poly(ikKreis(c, [0, 1, 0], [0, 0, 1], 3.2, 14), IKF.W, { d: 3.1, cls: 'zu', sty: m });
  I.ex.push([xc + 40, 9, 0]);
} };

/* P17 PDF Stufe 2, Rahmenprofilierer (Punkt 33): Maschine mit Rollen auf beiden Seiten, vorn fuer das grosse Profil (30 mm),
   hinten fuer das kleine (20 mm). Die Platine wird an einer Seite durchgezogen, dann umgedreht und mit der anderen Kante
   noch einmal durchgezogen; danach hat sie an beiden Kanten den Flansch (gelb). Lupe: die beiden Profilgroessen. */
PSYM.P17 = { dt: 0.55, f: function (I) {
  var t = COIL.t, W = COIL.W, Lb = 30, h = 2.6, l = 1.5, ya = 4.5, yb = ya + W, xs = [-24, -16, -8, 0, 8, 16, 24], N = 7;
  I.box(-30, -10, -BETT, 60, 14.5, BETT - 2.5, { d: -2 });
  each(xs, function (x, i) {
    I.zyl([x, ya - 1.2, -h - 2.4], [x, ya + 2.4, -h - 2.4], 2.4, { d: -1 + i * 0.01 });
    I.zyl([x, ya - 1.2, t + 3], [x, ya + 2.4, t + 3], 3, { d: 4 + i * 0.01 });
    I.zyl([x, -12.6, -3.8], [x, -10, -3.8], 1.6, { d: -3 + i * 0.01 });
    I.zyl([x, -12.6, 0], [x, -10, 0], 1.6, { d: -2.9 + i * 0.01 });
  });
  function platine(x0, vorn, hinten, teil) {
    I.box(x0, ya, 0, Lb, W, t, { d: 1 });
    if (hinten) { I.box(x0, yb - l, -h, Lb, l, h, ext(IKY, { d: 0.8, sw: 1, st: ANF.gelbRand })); }
    var xv = teil ? Math.max(x0, 0) : x0;
    if (vorn) { if (gt(x0 + Lb - xv, 0.3)) { I.box(xv, ya, -h, x0 + Lb - xv, l, h, ext(IKY, { d: 0.9, sw: 1, st: ANF.gelbRand })); } }
  }
  I.folge(N, function (k) {
    if (k === 0) { platine(-66, 0, 0); return; }
    if (k === 1) { platine(-15, 1, 0, 1); return; }
    if (k === 2) { platine(36, 1, 0); return; }
    if (k === 3) { platine(36, 0, 1); ikDrehPfeil(I, [36 + Lb / 2, ya + W / 2, 4], [0, 0, 1], 15, 0.5, 2.6, { d: 9, cls: '' }); return; }
    if (k === 4) { platine(-66, 0, 1); return; }
    if (k === 5) { platine(-15, 1, 1, 1); return; }
    platine(36, 1, 1);
  });
  ikPfeil(I, [-62, yb + 6, 0], [-46, yb + 6, 0], { d: 0.5, sw: 1.3 });
  anLupe(I, [2, -48, 32], 15, [24, -12.6, 1.6], 20, function (P) {
    anProfilLupe(I, function (x, y) { return P(x - 6.5, y + 1.5); }, ANP3, 54, 52.5, 0.17, 1, 20.1, { gelb: [[2, 19], [20, 40]], sw: 1.5, swg: 2 });
    anProfilLupe(I, function (x, y) { return P(x + 5.5, y); }, ANP3, 54, 52.5, 0.255, 1, 20.1, { gelb: [[2, 19], [20, 40]], sw: 1.6, swg: 2.2 });
  }, 45, 160);
  I.ex.push([66, yb, -h]);
} };

/* P24 Bogenautomat (Punkt 39; Runde 18, Dimi 11.11.2026): Der Falz sieht aus wie an der Segmentbogenmaschine, die Maschine arbeitet
   anders. Ein geschweisstes Rohr laeuft ein; die Maschine schneidet es schraeg in Segmente und boerdelt sie im selben Durchgang.
   Weil die Segmente so aneinandergesetzt wieder ein Rohr ergaeben, dreht sie jedes Segment nach dem Abschneiden und Boerdeln um
   180 Grad und verbindet es dann mit dem vorigen. Bildfolge: Rohr, Schnitt und Bord (gelb), Segment gedreht (Drehpfeil), verbunden
   (Falz gelb); das wiederholt sich, am Ende steht der fertige Bogen.
   Segmente als schraeg geschnittene Stuecke (ikSeg); der Bogen liegt und waechst rechts nach vorn.
   Runde 19 (Dimi 12.11.2026, Pruefliste 22.7 a; Abgleich mit den Patentschriften zu diesem Maschinentyp): Schneidrolle statt Messer,
   das Rohr dreht sich beim Schneiden (Drehpfeil); die Formrolle neben der Schneidrolle boerdelt im selben Umlauf; das Segment dreht
   um die Rohrachse; eine Rolle schliesst den Falz am Bogen, der an der Maschine waechst. */
PSYM.P24 = { dt: 0.5, f: function (I) {
  var r = 9, s = 11, w = SEG_W, xc = -8, N = 8, c = Math.cos(w), sn = Math.sin(w);
  ikHalten(I, (N - 1) * 0.5 + 1.6);
  /* Bogen aus n Segmenten ab xb, liegend: die Achse dreht je Stoss um 22,5 Grad zur Seite (nach vorn); gelb 1: letzter Falz, 2: alle.
     Nur das letzte Segment zeigt sein offenes Ende */
  function bogen(n, xb, gelb, fertig) {
    var p = [xb, 0, 0], dir = 0, j, naht = null;
    for (j = 0; j !== n; j++) {
      var letzt = j === n - 1, L = (j === 0 || (fertig ? letzt : false)) ? s * 0.62 : s;
      var ax = [Math.cos(dir), Math.sin(dir), 0], q = ad(p, mu(ax, L));
      var nA = j === 0 ? [-1, 0, 0] : [-Math.cos(dir - w), -Math.sin(dir - w), 0];
      var nB = (fertig ? letzt : false) ? ax : [Math.cos(dir + w), Math.sin(dir + w), 0];
      ikSeg(I, p, q, r, nA, nB, { d: 1 + j * 0.2, ende: letzt });
      if (j) {
        var nj = [Math.cos(dir - w), Math.sin(dir - w), 0];
        I.halbring(p, nj, r + 1.1, { st: IKF.B, sw: 4.4, d: 1.05 + j * 0.2 });
        I.halbring(p, nj, r + 1.1, { st: (gelb === 2 || (gelb === 1 ? letzt : false)) ? IKF.Y : IKF.R, sw: 2.4, d: 1.06 + j * 0.2 });
        if (letzt) { naht = { p: p, n: nj, d: 1.3 + j * 0.2 }; }
      }
      p = q; if (!letzt) { dir += 2 * w; }
    }
    /* Schliessrolle am zuletzt geschlossenen Falz (Achse quer zum Falz, oben auf dem Bogen) */
    if (gelb === 1) { if (naht) { var cz = ad(naht.p, [0, 0, r + 1.1 + 2.6]); I.zyl(sb(cz, mu(naht.n, 1.3)), ad(cz, mu(naht.n, 1.3)), 2.6, { d: naht.d }); } }
  }
  /* Schneidrolle (schmal) und Formrolle daneben, Achsen quer zur Schnittebene; zu: an das Rohr gestellt, sonst abgehoben */
  function rollen(zu, gerade) {
    var ax = gerade ? [1, 0, 0] : [c, 0, sn], h = zu ? 0 : 3.2, m = [xc - 0.2, 0, r + 3.4 + h];
    I.zyl(sb(m, mu(ax, 0.5)), ad(m, mu(ax, 0.5)), 3.6, { d: 0.9 });
    I.zyl(ad(m, mu(ax, 0.6)), ad(m, mu(ax, 3)), 2.5, { d: 0.92 });
    I.zyl(ad(m, mu(ax, 3)), ad(m, mu(ax, 7)), 1, { d: 0.88, ende: false });
  }
  /* Rohr bis zur Schneidrolle, Laengsnaht als Linie; schnitt: die Rollen stehen am Rohr, das Rohr dreht (Drehpfeil) */
  function rohr(x1, schnitt) {
    ikSeg(I, [-44, 0, 0], [x1, 0, 0], r, [-1, 0, 0], [c, 0, sn], { d: 0.2 });
    I.line([[-42, -r * 0.42, r * 0.9], [x1 - 1.5, -r * 0.42, r * 0.9]], { st: '#6F829A', sw: 1.4, d: 0.4 });
    rollen(schnitt, 0);
    if (schnitt) {
      var bb = ikBasis([1, 0, 0]), q = ikKreis([-30, 0, 0], bb[1], bb[2], r + 3.4, 24, Math.PI * 1.05, Math.PI * 1.95), m = q.length;
      var e = q[m - 1], tg = nz(sb(q[m - 1], q[m - 2])), nn = nz(sb(e, [-30, 0, 0]));
      I.line(q, { d: 0.95, sw: 1.4 });
      I.poly([ad(e, mu(tg, 3)), ad(sb(e, mu(tg, 1.6)), mu(nn, 2.2)), ad(sb(e, mu(tg, 1.6)), mu(nn, -2.2))], IKF.B, { d: 0.96, sw: 0.8 });
    }
  }
  /* loses Segment zwischen Messer und Bogen: wie geschnitten (kurze Seite unten) oder um 180 Grad gedreht (kurze Seite oben) */
  function segment(x0, gedreht, bord) {
    var sg = gedreht ? 1 : -1, n0 = [-c, 0, sg * sn], n1 = [c, 0, sg * sn];
    var S = ikSeg(I, [x0, 0, 0], [x0 + s, 0, 0], r, n0, n1, { d: 0.6 });
    ikSegBord(I, S.k1, [x0 + s, 0, 0], 1.2, bord ? IKF.Y : IKF.R, { d: 0.7 });
    I.halbring([x0, 0, 0], n0, r + 0.9, { st: bord ? IKF.Y : IKF.R, sw: 2.2, d: 0.72 });
    if (gedreht) {
      /* Drehpfeil ueber dem Segment (ohne Bewegungsklasse, weil in der Bildfolge): halbe Drehung um die Rohrachse */
      var bb = ikBasis([1, 0, 0]), q = ikKreis([x0 + s / 2, 0, 0], bb[1], bb[2], r + 4.6, 24, Math.PI * 1.02, Math.PI * 1.98), m = q.length;
      var e = q[m - 1], tg = nz(sb(q[m - 1], q[m - 2])), nn = nz(sb(e, [x0 + s / 2, 0, 0]));
      I.line(q, { d: 0.95, sw: 1.5 });
      I.poly([ad(e, mu(tg, 3)), ad(sb(e, mu(tg, 1.6)), mu(nn, 2.4)), ad(sb(e, mu(tg, 1.6)), mu(nn, -2.4))], IKF.B, { d: 0.96, sw: 0.8 });
    }
  }
  I.folge(N, function (k) {
    if (k === 0) { ikSeg(I, [-44, 0, 0], [8, 0, 0], r, [-1, 0, 0], [1, 0, 0], { d: 0.2 }); I.line([[-42, -r * 0.42, r * 0.9], [6.5, -r * 0.42, r * 0.9]], { st: '#6F829A', sw: 1.4, d: 0.4 }); rollen(0, 1); return; }
    if (k === N - 1) { rohr(xc - 1.2, 0); bogen(5, 22, 2, 1); return; }
    var nb = Math.floor((k - 1) / 3), ph = (k - 1) % 3;
    rohr(xc - 1.2, ph === 0);
    if (ph === 0) { segment(xc + 2.4, 0, 1); if (nb) { bogen(nb + 1, 22, 0, 0); } }
    if (ph === 1) { segment(xc + 2.4, 1, 0); if (nb) { bogen(nb + 1, 22, 0, 0); } }
    if (ph === 2) { bogen(nb + 2, 22, 1, 0); }
  });
  I.ex.push([-46, 0, -r], [56, 0, 0], [50, 44, 0], [xc, 0, r + 15]);
} };

/* P25 Sicken rund (Punkt 37): immer ein Rollenpaar, eine Rolle innen, eine aussen; das Rohrende dreht, die Sicke formt sich */
PSYM.P25 = { dt: 0.45, f: function (I) {
  var R = 15, x1 = 18, xb = x1 - 8, ru = 4.2;
  I.zyl([-40, 0, 0], [x1, 0, 0], R, { d: 0, offen: 1 });
  I.zyl([xb - 2.2, 0, R - ru - 1.2], [xb + 2.2, 0, R - ru - 1.2], ru, { d: 2.2, f: IKF.R });
  I.zyl([xb + 2.2, 0, R - ru - 1.2], [x1 + 22, 0, R - ru - 1.2], 1.5, { d: 2.25, ende: false });
  ikSicke(I, xb, R, { zs: '.2s' });
  ikOberwalze(I, R, x1, xb);
  ikDrehPfeil(I, [x1 + 0.5, 0, 0], [1, 0, 0], R + 3.5, Math.PI * 0.12, Math.PI * 0.62, { d: 4 });
  ikLupe(I, [40, -30, 24], 13, 3, function (P, k) {
    var h = [0, 1.6, 3][k], dy = 3 - h, W = [[-10, 0], [-3.4, 0], [-2, -h], [2, -h], [3.4, 0], [10, 0]];
    ikPoly2(I, P, [[-8, -10], [8, -10], [8, -1.2], [3.6, -1.2], [2.2, -4.2], [-2.2, -4.2], [-3.6, -1.2], [-8, -1.2]], IKF.R, 20.1);
    ikPoly2(I, P, [[-8, 10], [8, 10], [8, 1.2 + dy], [3.4, 1.2 + dy], [2, -1.8 + dy], [-2, -1.8 + dy], [-3.4, 1.2 + dy], [-8, 1.2 + dy]], IKF.L, 20.1);
    ikLinie2(I, P, W, 20.2, { sw: 2.2 });
    if (k === 2) { ikLinie2(I, P, W.slice(1, 5), 20.3, { sw: 2.4, st: IKF.Y }); }
  }, { von: [xb, 0, R + 1] });
} };

/* P41 Schlitzschere (Punkt 25): sie schneidet auch Kurven; der Span rollt sich auf */
PSYM.P41 = { dt: 0.16, f: function (I) {
  var t = 1.5, N = 10, K = [], i;
  I.box(-42, -26, 0, 84, 52, t, { d: 0 });
  for (i = 0; i !== 41; i++) { var u = i / 40; K.push([34 - 66 * u, 2 + 11 * Math.sin(Math.PI * 1.6 * u), t + 0.08]); }
  I.folge(N + 1, function (k) {
    var j = Math.round(40 * k / N), p = K[j];
    if (gt(j, 0)) { I.line(K.slice(0, j + 1), { st: IKF.B, sw: 3.2, d: 1 }); I.line(K.slice(Math.max(0, j - 6), j + 1), { st: IKF.Y, sw: 1.6, d: 1.05 }); }
    var sp = [];
    for (var q = 0; q !== 21; q++) { var a = 4 * Math.PI * q / 20, rr = 1.5 + 2.4 * q / 20; sp.push([p[0] + 1 + 1.6 * q / 20, p[1] + rr * Math.cos(a) * 0.4, t + 3 + rr * Math.sin(a)]); }
    I.line(sp, { d: 11.5, st: IKF.Y, sw: 1.6 });
    ikHandWz(I, [p[0], p[1], t + 0.3], [0.4, -0.5, 0.77], { d: 10 });
  });
} };

/* P46 Bohrschrauber (Punkt 26, TruTool DD 1010): der Akku-Bohrschrauber steht senkrecht ueber dem Blech und dreht die Schraube
   ein; Griff seitlich, Akku am Griffende; am Ende ist der Schraubenkopf gelb */
PSYM.P46 = { dt: 0.32, f: function (I) {
  var t = 1.6, N = 4, x = 0;
  I.box(-30, -22, 0, 60, 44, t, { d: 0 });
  I.box(-30, -22, -5, 60, 44, 5 - 0.2, { d: -1 });
  I.folge(N + 1, function (k, s) {
    var z = t + 6 - 6 * s, gelb = k === N;
    if (gt(z, t + 0.3)) { I.zyl([x, 0, t], [x, 0, z], 1, { d: 2, ende: false }); }
    I.zyl([x, 0, z], [x, 0, z + 1.3], 2.8, { d: 2.1, fe: gelb ? IKF.Y : IKF.T, f: gelb ? IKF.Y : IKF.L });
    var zb = z + 1.3;
    I.zyl([x, 0, zb], [x, 0, zb + 3.4], 0.8, { d: 3, ende: false });
    I.zyl([x, 0, zb + 3.4], [x, 0, zb + 9], 3, { d: 3.1, f: IKF.R });
    I.zyl([x, 0, zb + 9], [x, 0, zb + 27], 5.6, { d: 3.2, f: '#CDD6E0', fe: '#DCE3EB' });
    I.box(x + 3.5, -2.6, zb + 19, 15, 5.2, 6.4, { d: 3.3, ft: '#D5DDE6', fl: '#C3CDD8', fr: '#B5C1CE' });
    I.box(x + 16, -5, zb + 11, 8, 10, 17, { d: 3.4, ft: '#55606E', fl: '#3F4855', fr: '#4A5462' });
    ikDreh(I, [x, 0, zb + 9], [0, 0, 1], 4.2, { d: 3.5, sw: 1, da: '3 3', cls: '' });
  });
  I.ex.push([30, 22, -5], [-30, -22, 46]);
} };

/* P47 PDF Stufe 1, Zuschnitt (Punkt 32): Kanalanlage ohne Biegen. Haspel, Einzug, Richten, Versteifen (Sicke), seitliches
   Ausklinken; die querfahrende Profilieranlage formt an beiden neuen Kanten den Pittsburgh-Falz und trennt. Ergebnis:
   Platine mit Falz vorn und hinten (gelb) und Ausklinkungen an den Biegelinien. Stationen wie in P45. */
PSYM.P47 = { dt: 0.95, f: function (I) {
  var DT = 0.95, t = COIL.t, W = COIL.W, W2 = W / 2, a = 8, b = 11, f = 2.5, Lb = 2 * a + 2 * b + f;
  var xc = -206, xB = -190, xS = -166, xK = -146, xP = -134, xT0 = -125, xT1 = -72;
  function kl(xv) { return [xv - a, xv - a - b, xv - 2 * a - b, xv - Lb + f]; }
  anCoilBock(I, xc, 0, -BETT, 0);
  ikDreh(I, [xc, W2 + 0.1, -COIL.R], [0, 1, 0], COIL.R - 7, { d: 0.3, sw: 0.9 });
  I.box(xc, -W2, 0, xB - xc, W, t, { d: 0.5 });
  I.line([[xc + 4, 0, t + 0.05], [xB - 1, 0, t + 0.05]], { d: 0.6, sw: 1, da: '3 4', cls: 'zl', sty: { '--lt': '.9s', '--lz': '9' } });
  I.box(xB, -16, -BETT, -128 - xB, 32, BETT, { d: 1, ft: ANF.bett });
  I.box(xP - 5, -17, 0, 10, 4, 17, { d: 1.1 });
  var yw = anGehaeuse(I, -186, 20, 12, 1.5);
  anWalzen(I, yw + 0.05, [[-183, 3.2], [-178.5, 3.2], [-174, 3.2], [-180.8, 7], [-176.3, 7]], 1.7, 1.55);
  anWalzen(I, yw + 0.05, [[-169.5, 4.4]], 2.5, 1.55);
  anGehaeuse(I, -158, 12, 10, 1.8);
  I.zyl([-152, 0, 10], [-152, 0, 14.5], 2.4, { d: 1.85 });
  I.mit('zu', function () { I.zyl([-152, 0, 12], [-152, 0, 17], 1.4, { d: 1.9, sty: { '--my': '3px', '--mt': '.8s', '--zs': (DT + 0.1) + 's' } }); });
  I.box(xP - 4, -17, 14, 8, W2 + 21, 3, { d: 2.3 });
  var mvP = mvSty([0, -19, 0], 2 * DT + 0.05, 1.8);
  I.mit('zu', function () {
    I.box(xP - 4, W2 - 6, 4, 8, 7, 10, { d: 2.4, sty: mvP });
    I.zyl([xP - 1.2, W2 - 2.5, 2.6], [xP + 1.2, W2 - 2.5, 2.6], 1.9, { d: 2.42, sty: mvP });
    I.line([[xP + 2.4, W2 - 4.5, 3.9], [xP + 2.4, W2 - 4.5, t + 0.4]], { st: IKF.Y, sw: 1.6, d: 2.44, sty: mvP });
  });
  ikStrich(I, [[xP, W2 - 0.3, t + 0.1], [xP, -W2 + 0.3, t + 0.1]], { d: 1.3, pl: 1, sw: 2.2, cls: 'zd', sty: { '--zt': '.8s', '--zs': (2 * DT + 0.1) + 's' } });
  /* Ablagetisch hinter der Pittsburgh-Einheit */
  each([[xT0 + 2, -13], [xT1 - 5, -13], [xT0 + 2, 10], [xT1 - 5, 10]], function (q, i) { I.box(q[0], q[1], -BETT, 3, 3, BETT - 3, { d: 2.6 + i * 0.01 }); });
  I.box(xT0, -15, -3, xT1 - xT0, 30, 3, { d: 2.7 });
  function band(xv) {
    var o = { sx: xS, kl: kl(xv).filter(function (x) { return gt(x, xK); }) };
    anBlech(I, xB, Math.min(xv, -128), 1.2, ext(o, { pv: !gt(xv, -128) }));
    if (gt(xv, -128)) { anBlech(I, -128, xv, 3.5, ext(o, { pv: 1 })); }
  }
  I.folge(5, function (k) {
    if (k === 0) { band(-120); return; }
    if (k === 1) { band(-106); return; }
    if (k === 2) { band(xP + Lb); return; }
    anBlech(I, xB, xP, 1.2, { sx: xS, kl: kl(xP).filter(function (x) { return gt(x, xK); }), pv: 1 });
    var x0 = k === 3 ? xP + 1.5 : xT1 - Lb - 5;
    anBlech(I, x0, x0 + Lb, 3.5, { sx: -1e9, kl: kl(x0 + Lb), pv: 1, ph: 1 });
  });
} };

/* P48 PDF Stufe 3, Kanten und Falz schliessen (Punkt 34): die Platine mit angeformtem Flansch kommt ueber den Foerderer, die
   Biegewange kantet sie dreimal an den Eckausklinkungen zur Box, der Falz wird eingelegt und verpresst (zweite Biegeeinheit
   oder Rollen). Endbild: geschlossener Kanal auf dem Entnahmetisch, Falz gelb. Stationen wie in P45. */
PSYM.P48 = { dt: 0.95, f: function (I) {
  var t = COIL.t, W = COIL.W, W2 = W / 2, a = 8, b = 11, f = 2.5, h = 2.2, l = 1.6, g = 1.2, ys = [-6, 0, 6];
  var Lb = 2 * a + 2 * b + f, E = -14;
  function kl(xv) { return [xv - a, xv - a - b, xv - 2 * a - b, xv - Lb + f]; }
  function fl(xv) { var c = kl(xv); return [[c[3] + g / 2, c[2] - g / 2], [c[2] + g / 2, c[1] - g / 2], [c[1] + g / 2, c[0] - g / 2], [c[0] + g / 2, xv - g / 2]]; }
  I.box(-66, -8, -BETT, 18, 16, BETT, { d: 5.0 });
  each([-4.5, 4.5], function (y) { I.line([[-65, y, 0.05], [-49, y, 0.05]], { d: 5.05, sw: 1, da: '2 2', cls: 'zl', sty: { '--lz': '6' } }); });
  I.box(E - 22, -32, -BETT, 26, 10, BETT + 20, { d: 6.0 });
  I.box(-44, -8, -BETT, E + 44, 16, BETT, { d: 6.2 });
  I.box(E, -W2 - 2, -4, 3, W + 4, 4, { d: 6.3 });
  I.box(E - 7, -22, t + 0.3, 6, 10, 3.4, { d: 6.15 });
  I.box(E - 7, -12, t + 0.3, 6, W2 + 11, 3.4, { d: 6.8 });
  each([[-4, -13], [19, -13], [-4, 10], [19, 10]], function (q, i) { I.box(q[0], q[1], -BETT, 3, 3, BETT - 3, { d: 8.9 + i * 0.01 }); });
  I.box(-6, -15, -3, 28, 30, 3, { d: 9.0 });
  var C5 = [[E, a], [E, 0]], C6 = [[E - a, b], [E, b], [E, 0]], C7 = [[E - b, 0], [E - b, a], [E, a], [E, 0]];
  var PF = { flansch: h, gelbF: 1, luecke: g, sicken: ys }, Pd = { h: h, l: l, g: g };
  I.folge(6, function (k) {
    if (k === 0) { anBlech(I, -68, -68 + Lb, 6.6, { sx: -1e9, kl: kl(-68 + Lb), fl: fl(-68 + Lb), gelb: 1, pv: 1, ph: 1 }); return; }
    if (k === 1) { anBlech(I, E + a - Lb, E, 6.6, { sx: -1e9, kl: kl(E + a), fl: fl(E + a), gelb: 1, ph: 1 }); anProfilY(I, C5, -W2, W2, 7.2, PF); return; }
    if (k === 2) { anBlech(I, E + a + b - Lb, E, 6.6, { sx: -1e9, kl: kl(E + a + b), fl: fl(E + a + b), gelb: 1, ph: 1 }); anProfilY(I, C6, -W2, W2, 7.2, PF); return; }
    if (k === 3) { anBlech(I, E - b - f, E, 6.6, { sx: -1e9, fl: fl(E + 2 * a + b), gelb: 1, ph: 1 }); anProfilY(I, C7, -W2, W2, 7.2, PF); return; }
    if (k === 4) {
      var K8 = { x0: E - b, x1: E, z0: 0, z1: a, y0: -W2, y1: W2, t: 1.1 };
      anKanalZu(I, K8, 7, { pdf: Pd, gelb: 1, sicken: ys });
      I.box(E - b - 3.6, -W2, 0.3, 2.4, W, 2.4, { d: 6.9 });
      ikStrich(I, [[E - b + 1.2, W2 - 0.1, 1.2], [E - b + 1.2, W2 - 6.5, 1.2]], { d: 8.6, sw: 2.2 });
      return;
    }
    var Kf = { x0: 2, x1: 2 + b, z0: h, z1: h + a, y0: -W2, y1: W2, t: 1.1 };
    anKanalZu(I, Kf, 10, { pdf: Pd, gelb: 1, sicken: ys });
    ikStrich(I, [[Kf.x1 - 0.8, Kf.y0 + 0.3, Kf.z1 + 0.06], [Kf.x1 - 0.8, Kf.y1 - 0.3, Kf.z1 + 0.06]], { d: 11.06, sw: 2.2 });
  });
} };

/* P49 freistehende Falzschliessmaschine (Punkt 35, senkrecht oder waagerecht; gezeigt: senkrecht): der Kanal steht, ein Wagen
   mit zwei Rollen faehrt an der Saeule die Falzecke hoch und drueckt den Falz zu; unter den Rollen ist er geschlossen (gelb) */
PSYM.P49 = { dt: 0.24, f: function (I) {
  var w = 14, d0 = 10, H = 50, N = 8, r = 2.6;
  I.box(-w - 6, -d0 - 6, -4, 2 * w + 26, 2 * d0 + 12, 4, { d: -4, ft: IKF.I });
  I.box(w + 11, -3, 0, 5, 5, H + 6, { d: -3 });
  I.box(-w, -d0, 0, 2 * w, 2 * d0, H, { d: 0 });
  I.innen([[-w + 1.2, -d0 + 1.2, H], [w - 1.2, -d0 + 1.2, H], [w - 1.2, d0 - 1.2, H], [-w + 1.2, d0 - 1.2, H]], [0, 0, -1], H, 0.4, { m: d0 });
  I.folge(N + 1, function (k, s) {
    var z = 4 + (H - 8) * s;
    if (gt(H - z, 0.5)) { I.poly([[w, d0, z], [w, d0, H], [w + 1.8, d0 + 1.8, H], [w + 1.8, d0 + 1.8, z]], IKF.L, { d: 0.5, sw: 1 }); }
    if (gt(z, 0.5)) { I.line([[w + 0.25, d0 + 0.25, 0.3], [w + 0.25, d0 + 0.25, z - 2]], { st: IKF.Y, sw: 3, d: 0.6 }); }
    I.box(w + 3.4, -1, z - 2.5, 8, 3, 5, { d: 1.5 });
    I.box(w + 2.6, -1, z - 3, 3.2, d0 + 6.4, 6, { d: 1.6 });
    I.zyl([w + r + 0.2, d0 - 3.5, z], [w + r + 0.2, d0 + 0.6, z], r, { d: 2.1 });
    I.zyl([w - 3.5, d0 + r + 0.2, z], [w + 0.6, d0 + r + 0.2, z], r, { d: 2.2 });
  });
  I.ex.push([w + 18, d0 + 8, -4], [-w, -d0, H + 6]);
} };

/* P50 Segmentbogenmaschine (Punkt 38), Runde 13 der Szene (Dimi 10.11.2026): Boerdeln und Falzschliessen waagerecht.
   Runde 18 (Dimi 11.11.2026: Segmente zeichnen, kein Rohr; nach der Betriebsanleitung der Maschine): Das Segment steht mit der
   Kante, die geboerdelt wird, auf dem Arbeitstisch, das andere Ende ist schraeg. Links Boerdeln: das Segment dreht, die Profilierrolle
   stellt den Bord am Tisch waagerecht nach aussen auf. Rechts Schliessen: zwei Segmente stehen aufeinander, die Doppelboerdelung
   (Stufe) des unteren umgreift die 90-Grad-Boerdelung des oberen; die Schliessteller oben und unten druecken den Falz zu (gelb).
   Der Falz bleibt als Rippe stehen. */
PSYM.P50 = { dt: 0.5, f: function (I) {
  var R = 10, H = 12, N = 4, x2 = 40, z1 = 2, pv = Math.PI / 4, w = SEG_W, c = Math.cos(w), sn = Math.sin(w), pr = -Math.PI * 0.12;
  ikHalten(I, (N - 1) * 0.5 + 1.4);
  I.box(-18, -18, -4, x2 + 36, 36, 4, { d: -8, ft: IKF.I });
  /* Station 1: Drehteller, Segment steht auf der Kante, die geboerdelt wird */
  I.zyl([0, 0, 0], [0, 0, z1], R + 5.5, { d: -6 });
  ikDreh(I, [0, 0, z1], [0, 0, 1], R + 4.6, { d: -5.9, sw: 0.9, da: '3 5' });
  /* Station 2: Drehteller */
  I.zyl([x2, 0, 0], [x2, 0, z1], R + 4, { d: -5.8 });
  I.folge(N, function (k) {
    var h1 = [0, 1.6, 3.2, 3.2][k];
    if (gt(h1, 0)) { ringPfad(I, [0, 0, z1 + 0.25], [0, 0, 1], R - 0.2, R + h1, k === 3 ? IKF.Y : IKF.R, { d: -0.5 }); }
    ikSeg(I, [0, 0, z1 + 0.3], [0, 0, z1 + H], R, [0, 0, -1], [sn, 0, c], { d: 0 });
    /* Profilierrolle am Bord (seitlich), Welle nach oben */
    var co = [(R + 2.9) * Math.cos(pr), (R + 2.9) * Math.sin(pr)];
    I.zyl([co[0], co[1], z1 + 0.5], [co[0], co[1], z1 + 3.4], 3.3, { d: 0.6 });
    I.zyl([co[0], co[1], z1 + 3.4], [co[0], co[1], z1 + 13], 1.2, { d: 0.62 });
    /* Station 2: unteres Segment mit der Doppelboerdelung nach oben, oberes mit der 90-Grad-Boerdelung nach unten; Falz offen (dick) oder zu (gelb) */
    var zu = k === 3, zf = z1 + H + 0.8, dz = [3, 1.2, 0, 0][k];
    ikSeg(I, [x2, 0, z1 + R * Math.tan(w)], [x2, 0, zf - 0.6], R, [-sn, 0, -c], [0, 0, 1], { d: 1, ende: false });
    ikSeg(I, [x2, 0, zf + 0.6], [x2, 0, zf + H], R, [0, 0, -1], [sn, 0, c], { d: 2 });
    I.halbring([x2, 0, zf], [0, 0, 1], R + (zu ? 1.5 : 2.6), { st: IKF.B, sw: zu ? 6.4 : 8.4, d: 1.5 });
    I.halbring([x2, 0, zf], [0, 0, 1], R + (zu ? 1.5 : 2.6), { st: zu ? IKF.Y : IKF.R, sw: zu ? 4.2 : 6, d: 1.55 });
    /* Schliessteller oben und unten am Falz (vorn) */
    var tx = x2 + (R + 5.6) * Math.cos(pv), ty = (R + 5.6) * Math.sin(pv);
    I.zyl([tx, ty, zf + 1.4 + dz], [tx, ty, zf + 3.4 + dz], 4.2, { d: 3 });
    I.zyl([tx, ty, zf + 3.4 + dz], [tx, ty, zf + 10 + dz], 1.2, { d: 3.05 });
    I.zyl([tx, ty, zf - 3.4 - dz], [tx, ty, zf - 1.4 - dz], 4.2, { d: 3.1 });
  });
  I.ex.push([x2 + 18, 18, -4], [-18, -18, z1 + 2 * H + 8]);
} };

/* ---------- Runde 12 der Szene (Dimi 10.11.2026): Dichten mit der Kartusche von Hand ----------
   Kartusche mit Duese, Kolbenstange und Griff (Handpistole), Duese bei tip, Achse dir (von der Duese nach hinten). */
function ikKartusche(I, tip, dir, d, k) {
  k = k || 1;
  /* g: oben am Geraet (senkrecht zur Achse, so weit wie moeglich nach oben); der Griff haengt nach unten */
  var a = nz(dir), up = sb([0, 0, 1], mu(a, a[2])), g = gt(len(up), 0.2) ? nz(up) : nz(cr(a, [1, -1, 0]));
  function A(t) { return ad(tip, mu(a, t * k)); }
  I.zyl(tip, A(9), 1.4 * k, { d: d, ende: false });
  I.zyl(A(9), A(26), 4.2 * k, { d: d + 0.1 });
  I.line([A(26.4), A(32)], { d: d + 0.15, sw: 1.4 });
  /* Griff mit Abzug, schraeg nach unten */
  var h0 = ad(A(21.5), mu(g, -4.1 * k)), h1 = ad(h0, ad(mu(g, -9 * k), mu(a, 3 * k)));
  I.poly([h0, ad(h0, mu(a, 4 * k)), ad(h1, mu(a, 4 * k)), h1], IKF.T, { d: d + 0.2, sw: 1.1 });
  I.line([ad(A(17.5), mu(g, -4.1 * k)), ad(A(19), mu(g, -7.8 * k))], { d: d + 0.21, sw: 1.3 });
}
/* P27 Abdichten von Hand (Falzabdichtung): die Kartusche zieht die Dichtmasse als Raupe in Falz und Ecke */
PSYM.P27 = { dt: 0.15, f: function (I) {
  var L = 34, N = 10;
  I.box(-L, -24, -2, 2 * L, 34, 2, { d: 0 });
  I.box(-L, -26, -2, 2 * L, 2, 26, { d: 0.1 });
  ikStrich(I, [[-L + 3, -22.6, 1.2], [L - 3, -22.6, 1.2]], { d: 1, pl: 1, sw: 3.4, cls: 'zd', sty: { '--zt': (N * 0.15) + 's' } });
  I.folge(N + 1, function (k) {
    var x = -L + 3 + (2 * L - 6) * k / N;
    ikKartusche(I, [x, -22, 2.2], [-0.8, 0.45, 0.75], 3);
  });
  I.ex.push([L + 10, 12, 34]);
} };
/* P51 Ecken abdichten (Runde 12 der Szene): Blick in die Ecke eines Kanals mit Steckrahmen; die Kartusche fuehrt die Duese in die
   Ecke, die Dichtmasse fuellt die Ecke von Rahmen und Kanal (gelb) und laeuft ein Stueck entlang der Fuge */
PSYM.P51 = { dt: 0.22, f: function (I) {
  var L = 38, w = 7, h = 4.5, D = 20, N = 9, ts = 0.22;
  I.poly([[w, w, -D], [L, w, -D], [L, w, 0], [w, w, 0]], IKF.L, { d: 0 });
  I.poly([[w, w, -D], [w, L, -D], [w, L, 0], [w, w, 0]], IKF.R, { d: 0.05 });
  I.box(0, 0, 0, L, w, h, { d: 1 });
  I.box(0, w, 0, w, L - w, h, { d: 1.05 });
  /* Eckwinkel angedeutet: Stoss der Schenkel */
  I.line([[0, w, h + 0.02], [w, w, h + 0.02]], { d: 1.2, sw: 0.9 });
  var z = { '--zt': (ts * 5) + 's', '--zs': (ts * 3) + 's' };
  ikStrich(I, [[w + 0.4, w + 0.4, h - 0.2], [w + 0.4, w + 0.4, -7]], { d: 2, pl: 1, sw: 3.6, cls: 'zd', sty: z });
  ikStrich(I, [[w + 0.4, w + 0.4, 0.2], [w + 13, w + 0.4, 0.2]], { d: 2.05, pl: 1, sw: 3, cls: 'zd', sty: z });
  ikStrich(I, [[w + 0.4, w + 0.4, 0.2], [w + 0.4, w + 13, 0.2]], { d: 2.1, pl: 1, sw: 3, cls: 'zd', sty: z });
  I.folge(N + 1, function (k) {
    var s = Math.min(1, k / 3), tip = [w + 1.2 + 6 * (1 - s), w + 1.2 + 6 * (1 - s), h + 0.8 + 10 * (1 - s)];
    ikKartusche(I, tip, [0.75, 0.3, 0.8], 3, 0.8);
  });
  I.ex.push([L, L, 34], [0, 0, -D]);
} };

/* ---------- Prozess-Symbole, Runde 13 der Szene (Dimi 10.11.2026) ----------
   Fuer die Stufenkacheln (Ruhebild plus einmaliger Ablauf) und die neuen Verfahren:
   P52 Blech vom Stapel (Tafel 3 m x 1,5 m), P53 Segment schneiden mit der Schere (gerade und wellige Kante),
   P54 Segment schneiden mit dem Laser (Fischform), P55 Runden mit dem Rundautomaten (Greifer nimmt den Zuschnitt vom Stapel
   und fuehrt ihn in die Rundmaschine), P56 Halbschalen pressen (Matrize und Stempel), P57 Halbschalen schweissen (Rollennaht mit
   Drahtelektrode, bogengefuehrt). Neu gefasst: P50 (Boerdeln und Falzschliessen waagerecht, in 63_symbole_r10.js).
   Regel wie in 62_anlagen.js: Teile in einer Bildfolge (I.folge) bekommen keine Bewegungsklassen. */

/* Gekruemmte Flaeche aus Gitter G[i][j] ohne innere Linien: Vierecke in der Flaechenfarbe (aussen sichtbar: Licht nach der
   Normalen, sonst o.fi oder Innenfarbe), Linien am Rand und dort, wo die Sichtbarkeit wechselt (Umriss).
   Tiefe: d0 plus ein kleiner Anteil der Lage, so bleibt die Flaeche als Gruppe zwischen den uebrigen Teilen.
   o.rand: Raender mit Linie, z. B. 'i0 i1 j0 j1' (Standard alle); o.st, o.sw Linienfarbe und -staerke der Raender;
   o.dreh: Normale umkehren; o.nurSicht: nur zum Betrachter zeigende Vierecke; o.innen: Farbe wie in einer Mulde (ikHell) */
function ikGitter(I, G, o) {
  o = o || {};
  var n = G.length - 1, m = G[0].length - 1, i, j, d0 = o.d || 0, V = [], Dq = [], rd = o.rand === undefined ? 'i0 i1 j0 j1' : o.rand;
  function tf(q) { return d0 + 0.001 * DE(mitte(q)); }
  for (i = 0; i !== n; i++) {
    V.push([]); Dq.push([]);
    for (j = 0; j !== m; j++) {
      var q = [G[i][j], G[i + 1][j], G[i + 1][j + 1], G[i][j + 1]], nn = newell(q);
      if (o.dreh) { nn = mu(nn, -1); }
      var vis = sicht(nn), f = o.innen ? ikHell(nn) : (vis ? (o.f || ikGlatt(nn)) : (o.fi || ikInnenFarbe(nn)));
      V[i].push(vis); Dq[i].push(null);
      if (o.nurSicht) { if (!vis) { continue; } }
      var p = q.map(PQ), dq = tf(q);
      Dq[i][j] = dq;
      I.add(dq, { d: pfad(p, 1), fill: f, stroke: f, 'stroke-width': 0.7 }, { cls: o.cls, pts: p, sty: o.sty });
    }
  }
  /* Linie gleich nach dem tiefsten angrenzenden gezeichneten Viereck: so verdecken die Nachbarn sie nicht, wohl aber Teile davor */
  function L(a, b, rand, d1, d2) {
    var dd = null;
    each([d1, d2], function (x) { if (x !== null) { if (x !== undefined) { dd = dd === null ? x : Math.max(dd, x); } } });
    if (dd === null) { if (o.nurSicht) { return; } dd = tf([a, b]); }
    I.line([a, b], { d: dd + 0.0004, st: rand ? (o.st || IKF.B) : IKF.B, sw: rand ? (o.sw || 1.3) : 1.3, cls: o.cls, sty: o.sty });
  }
  for (i = 0; i !== n; i++) {
    for (j = 0; j !== m + 1; j++) {
      var rand1 = (j === 0) ? rd.indexOf('j0') !== -1 : ((j === m) ? rd.indexOf('j1') !== -1 : false);
      var wech = (j === 0 || j === m) ? false : V[i][j - 1] !== V[i][j];
      if (rand1 || wech) { L(G[i][j], G[i + 1][j], rand1, j === 0 ? null : Dq[i][j - 1], j === m ? null : Dq[i][j]); }
    }
  }
  for (j = 0; j !== m; j++) {
    for (i = 0; i !== n + 1; i++) {
      var rand2 = (i === 0) ? rd.indexOf('i0') !== -1 : ((i === n) ? rd.indexOf('i1') !== -1 : false);
      var wech2 = (i === 0 || i === n) ? false : V[i - 1][j] !== V[i][j];
      if (rand2 || wech2) { L(G[i][j], G[i][j + 1], rand2, i === 0 ? null : Dq[i - 1][j], i === n ? null : Dq[i][j]); }
    }
  }
}
/* Glatte Schattierung gekruemmter Flaechen: Mischung aus Oben-, Links- und Rechtsfarbe nach der Normalen */
var IKG = null;
function ikGlatt(nn) {
  if (!IKG) { IKG = [rgb(IKF.T), rgb(IKF.L), rgb(IKF.R)]; }
  var wT = pos(nn[2]) * pos(nn[2]), wL = pos(nn[1]) * pos(nn[1]), wR = pos(nn[0]) * pos(nn[0]), sm = wT + wL + wR, c = [0, 0, 0], k;
  if (!gt(sm, 1e-6)) { return IKF.L; }
  for (k = 0; k !== 3; k++) { c[k] = (IKG[0][k] * wT + IKG[1][k] * wL + IKG[2][k] * wR) / sm; }
  return '#' + hx2(c[0]) + hx2(c[1]) + hx2(c[2]);
}
/* Mulde (Blick in die Form): Flaeche zeigt zum Betrachter, heller je direkter */
function ikHell(nn) {
  var s = (nn[0] + nn[1] + nn[2]) / 1.732;
  if (gt(s, 0.62)) { return IKI[0]; }
  if (gt(s, 0.3)) { return IKI[1]; }
  return IKI[2];
}
/* Innenseite: heller, wenn sie zum Betrachter zeigt (Blick in eine Mulde) */
function ikInnenFarbe(nn) {
  var s = -(nn[0] + nn[1] + nn[2]) / 1.732;
  if (gt(s, 0.6)) { return IKI[0]; }
  if (gt(s, 0.25)) { return IKI[1]; }
  return IKI[2];
}
/* Linie entlang eines Bogens (Kreis um c in der waagerechten Ebene z) von Winkel a0 bis a1 */
function ikBogenPkt(c, r, a0, a1, n, z) {
  var q = [];
  for (var k = 0; k !== n + 1; k++) { var a = a0 + (a1 - a0) * k / n; q.push([c[0] + r * Math.cos(a), c[1] + r * Math.sin(a), z === undefined ? c[2] : z]); }
  return q;
}
/* Saugheber: senkrechte Stange von oben, Traverse mit vier Saugern; Unterkante der Sauger bei z (Mitte x, y) */
function ikSauger(I, x, y, z, d, b) {
  b = b || 1;
  I.zyl([x, y, z + 6], [x, y, z + 34], 1.4, { d: d });
  I.box(x - 18 * b, y - 1.6, z + 4, 36 * b, 3.2, 2.2, { d: d + 0.1 });
  each([-14 * b, 14 * b], function (dx) {
    I.box(x + dx - 1.4, y - 9, z + 4, 2.8, 18, 1.6, { d: d + 0.2 });
    each([-7, 7], function (dy) {
      I.zyl([x + dx, y + dy, z + 1.6], [x + dx, y + dy, z + 4], 0.9, { d: d + 0.3, ende: false });
      I.zyl([x + dx, y + dy, z], [x + dx, y + dy, z + 1.6], 2.4, { d: d + 0.35, fe: IKF.D });
    });
  });
}

/* P52 Blech vom Stapel: Tafeln 3 m x 1,5 m auf der Palette; der Saugheber setzt auf, hebt die oberste Tafel und bringt sie
   zur Maschine (Kante gelb) */
PSYM.P52 = { dt: 0.55, f: function (I) {
  var Lx = 64, Ly = 32, t = 1.4, n = 6, z0;
  /* Palette mit Kufen */
  each([-28, -2, 24], function (x) { I.box(x, -Ly / 2 - 1, -6, 4, Ly + 2, 3, { d: -2 }); });
  I.box(-Lx / 2 - 1, -Ly / 2 - 1, -3, Lx + 2, Ly + 2, 3, { d: -1.5, ft: '#D9CBB0', fl: '#C9B998', fr: '#BBA985' });
  for (var i = 0; i !== n - 1; i++) { I.box(-Lx / 2, -Ly / 2, i * t, Lx, Ly, t, { d: -1 + i * 0.01 }); }
  z0 = (n - 1) * t;
  I.folge(4, function (k) {
    var hz = [0, 0, 12, 12][k], dx = [0, 0, 0, 46][k], zs = [16, 0, 0, 0][k];
    I.box(-Lx / 2 + dx, -Ly / 2, z0 + hz, Lx, Ly, t, { d: 1 });
    if (k === 3) { ikStrich(I, [[dx + Lx / 2, -Ly / 2, z0 + hz + t + 0.05], [dx + Lx / 2, Ly / 2, z0 + hz + t + 0.05], [dx - Lx / 2, Ly / 2, z0 + hz + t + 0.05]], { d: 1.5, sw: 2.4 }); }
    ikSauger(I, dx, 0, z0 + hz + t + zs, 3, 1);
  });
  I.ex.push([46 + Lx / 2, Ly / 2, -6], [-Lx / 2, -Ly / 2, z0 + 50]);
} };

/* Abwicklung eines Segments: Kante y = w(x) als Sinus ueber eine Periode (schraeger Schnitt am Rohr) */
function ikWelle(x0, x1, ym, a, n) {
  var q = [];
  for (var k = 0; k !== n + 1; k++) { var x = x0 + (x1 - x0) * k / n; q.push([x, ym + a * Math.cos(2 * Math.PI * (x - x0) / (x1 - x0))]); }
  return q;
}
/* P53 Segment schneiden mit der Schere (manuell): die eine Kante ist gerade (Tafelschere), die andere schneidet die Handschere
   entlang der Welle der Abwicklung; der Rest faellt ab, die Kante des Segments ist gelb */
PSYM.P53 = { dt: 0.16, f: function (I) {
  var t = 1.5, x0 = -40, x1 = 40, N = 10, W = ikWelle(x0, x1, 7, 6, 40), z = t + 0.05;
  I.box(-46, -30, -7, 92, 60, 7, { d: -1, ft: IKF.I });
  I.folge(N + 1, function (k) {
    var j = Math.round(40 * k / N), p = W[j], i;
    if (k !== N) {
      I.box(-42, -26, 0, 84, 52, t, { d: 0 });
      if (gt(j, 0)) { I.line(W.slice(0, j + 1).map(function (q) { return [q[0], q[1], z]; }), { st: IKF.B, sw: 1.2, d: 1 }); }
      ikHandWz(I, [p[0], p[1], t + 0.3], [-0.55, 0.2, 0.81], { d: 10 });
      return;
    }
    /* Segment (Blech bis zur Welle) und abfallender Rest */
    var A = [[-42, -26, 0], [42, -26, 0]].concat(W.slice().reverse().map(function (q) { return [q[0], q[1], 0]; }));
    var Ao = A.map(function (q) { return [q[0], q[1], t]; });
    I.poly(Ao, IKF.T, { d: 0 });
    I.poly([[42, -26, 0], [42, W[40][1], 0], [42, W[40][1], t], [42, -26, t]], IKF.R, { d: 0.1 });
    var G = [];
    for (i = 0; i !== W.length; i++) { G.push([[W[i][0], W[i][1], 0], [W[i][0], W[i][1], t]]); }
    I.band(G, { d: 0.2 });
    var B = W.map(function (q) { return [q[0], q[1] + 4, -0.8]; });
    I.poly(B.concat([[42, 30, -0.8], [-42, 30, -0.8]]).map(function (q) { return [q[0], q[1], q[2] + t]; }), IKF.T, { d: 0.5 });
    I.poly([[-42, 30, -0.8], [42, 30, -0.8], [42, 30, t - 0.8], [-42, 30, t - 0.8]], IKF.L, { d: 0.55 });
    ikStrich(I, W.map(function (q) { return [q[0], q[1], z]; }), { d: 0.6, sw: 2.4 });
  });
  I.ex.push([-46, -30, 40], [46, 30, -7]);
} };

/* P54 Segment schneiden mit dem Laser: Zuschnitt in Fischform (beide Kanten wellig, Mittelsegment eines Segmentbogens);
   der Kopf faehrt die Kontur ab, die Fuge waechst, zuletzt faehrt der Kopf hoch und die Kontur ist gelb */
PSYM.P54 = { dt: 0.07, f: function (I) {
  var t = 2.4, z0 = t + 0.05, st = 5, i;
  I.box(-40, -26, 0, 80, 52, t, { d: 0 });
  /* Kontur: oben und unten Kosinus (breit in der Mitte = Bogenaussenseite), Enden senkrecht */
  var K = [], n = 24, x0 = -32, x1 = 32;
  function h(x) { return 7 + 8 * Math.pow(Math.cos(Math.PI * x / (x1 - x0)), 2); }
  for (i = 0; i !== n + 1; i++) { var x = x0 + (x1 - x0) * i / n; K.push([x, -h(x), z0]); }
  for (i = n; i !== -1; i--) { var x2 = x0 + (x1 - x0) * i / n; K.push([x2, h(x2), z0]); }
  K.push(K[0]);
  var Ls = [0], Lg = 0, F = [];
  for (i = 1; i !== K.length; i++) { Lg += len(sb(K[i], K[i - 1])); Ls.push(Lg); }
  function bis(d) {
    var m = 1, q = [K[0]];
    while (lt(Ls[m], d - 1e-9)) { q.push(K[m]); m++; }
    var u = (d - Ls[m - 1]) / ((Ls[m] - Ls[m - 1]) || 1);
    q.push(ad(K[m - 1], mu(sb(K[m], K[m - 1]), u)));
    return q;
  }
  var nf = Math.max(3, Math.round(Lg / st));
  for (i = 0; i !== nf + 1; i++) { F.push({ d: Lg * i / nf }); }
  F.push({ d: Lg, hoch: 1 });
  I.folge(F.length, function (k) {
    var f = F[k], q = bis(f.d), p = q[q.length - 1], hz = f.hoch ? 9 : 0;
    if (f.hoch) { ikStrich(I, K, { d: 1, sw: 2.2 }); } else if (gt(f.d, 0)) { I.line(q, { st: IKF.B, sw: 1.1, d: 1 }); }
    I.zyl([p[0], p[1], 10 + hz], [p[0], p[1], 28 + hz], 2.6, { d: 10 });
    I.zyl([p[0], p[1], 6.5 + hz], [p[0], p[1], 10 + hz], 1.7, { d: 9.95 });
    I.zyl([p[0], p[1], 5 + hz], [p[0], p[1], 6.5 + hz], 0.9, { d: 9.94 });
    if (!f.hoch) {
      I.line([[p[0], p[1], 5], [p[0], p[1], t]], { st: IKF.Y, sw: 1.2, d: 9.9 });
      I.poly(ikKreis([p[0], p[1], z0 + 0.02], [1, 0, 0], [0, 1, 0], 0.9, 10), IKF.W, { d: 9.92, sw: 1, st: IKF.Y });
    }
  });
} };

/* P55 Runden mit dem Rundautomaten: der Greifer nimmt den obersten Zuschnitt (Fischform) vom Stapel, schiebt ihn zwischen die
   drei Walzen, die Walzen runden ihn zum Segment (Naht gelb). Walzen wie P12 (Dreipunktbiegung). */
PSYM.P55 = { dt: 0.5, f: function (I) {
  var r = 5.5, dx = 9, zb = r + 1.6, zt = zb + r + 1.6, L = 60, t = 1.2, xs = -82, nS = 5, i;
  function h(s) { return 6 + 6 * Math.pow(Math.cos(Math.PI * s / L), 2); }
  /* flacher Zuschnitt um (cx, z): Umriss oben */
  function flach(cx, z, d, gelb) {
    var O = [], U = [], n = 16;
    for (var k = 0; k !== n + 1; k++) { var s = -L / 2 + L * k / n; O.push([cx + s, -h(s), z + t]); U.push([cx + s, h(s), z + t]); }
    I.poly(O.concat(U.reverse()), gelb ? IKF.Y : IKF.T, { d: d, sw: 1.2 });
    I.poly([[cx + L / 2, -h(L / 2), z], [cx + L / 2, h(L / 2), z], [cx + L / 2, h(L / 2), z + t], [cx + L / 2, -h(L / 2), z + t]], IKF.R, { d: d + 0.01, sw: 1 });
  }
  /* Stapel auf dem Tisch */
  I.box(xs - L / 2 - 3, -16, -6, L + 6, 32, 6, { d: -3, ft: IKF.I });
  for (i = 0; i !== nS - 1; i++) { flach(xs, i * t, -2 + 0.01 * i); }
  var zS = (nS - 1) * t;
  /* Gestell der Walzen */
  I.box(-20, -18, -6, 40, 36, 6, { d: -3.5, ft: IKF.I });
  /* Portal des Greifers */
  I.box(xs - 6, -3, 46, 100, 4, 3, { d: -0.5 });
  var Rs = [0, 0, 0, 0, 400, 26, 14, L / (2 * Math.PI) + 0.15], PV = Math.PI / 4, N = Rs.length;
  I.folge(N, function (k) {
    /* Unterwalzen aussen am Blech (wie P12) */
    var R = Rs[k] || 400, ph = Math.asin(dx / R), c = r + 0.6;
    each([-1, 1], function (sg) {
      var px = sg * dx, pz = zb + R * (1 - Math.cos(ph)), nx = sg * Math.sin(ph), nzz = -Math.cos(ph);
      I.zyl([px + nx * c, -15, pz + nzz * c], [px + nx * c, 15, pz + nzz * c], r, { d: sg === 1 ? (gt(R, 30) ? 0 : 3.6) : 0 });
    });
    /* Greifer: am Stapel, gehoben, an der Walze, zurueck */
    var gx = [xs, xs, xs, -40, -40, xs, xs, xs][k], gz = [zS + t + 14, zS + t, zS + t + 8, zb + t, zb + t + 14, zS + t + 14, zS + t + 14, zS + t + 14][k];
    if (lt(k, 4)) {
      var bx = [xs, xs, xs, -40 + L / 2 - 28][k], bz = [zS, zS, zS + 8, zb][k];
      if (k === 3) { bx = -40; }
      flach(bx, bz, 2.4);
    } else {
      /* gerundeter Zuschnitt (Band mit veraenderlicher Breite), hinten und vorn getrennt wie P12 */
      var A = [], B = [], n2 = 32;
      for (i = 0; i !== n2 + 1; i++) {
        var s = -L / 2 + L * i / n2, p2 = s / R, xx = R * Math.sin(p2), zz = zb + R * (1 - Math.cos(p2));
        var e = [[xx, -h(s), zz], [xx, h(s), zz]];
        if (gt(p2, PV)) { if (!B.length) { A.push(e); B.push(e); } B.push(e); } else { A.push(e); }
      }
      var o1 = k === N - 1 ? { f: '#FBE7A1' } : {};
      if (B.length) { I.band(A, ext(o1, { d: 2, e1: false })); I.band(B, ext(o1, { d: 3.2, e0: false })); } else { I.band(A, ext(o1, { d: 2 })); }
    }
    I.zyl([gx, 0, gz + 1.2], [gx, 0, 46], 1.3, { d: 4 });
    I.zyl([gx, 0, gz], [gx, 0, gz + 1.2], 4.5, { d: 4.1, fe: IKF.D });
    I.box(gx - 4, -4, 44, 8, 8, 5, { d: 4.2 });
  });
  I.zyl([0, -15, zt], [0, 15, zt], r, { d: 2.5 });
  ikDreh(I, [0, 15, zt], [0, 1, 0], r * 0.6, { d: 3.5, sw: 0.9, da: '2 3', rueck: 1 });
  I.ex.push([30, 18, -6], [xs - L / 2 - 3, -16, 52]);
} };

/* Rohrbogen 90 Grad in der waagerechten Ebene: Mitte (0, 0), Biegeradius Rb, Rohrradius rt; Punkt auf der Wand bei Bogenwinkel a
   (0 = Austritt bei y = 0, pi/2 bei x = 0) und Umfangswinkel f (0 aussen in der Ebene, pi/2 oben) */
function ikTorusP(Rb, rt, a, f, dz) {
  var n = [Math.cos(a), Math.sin(a), 0];
  return [n[0] * (Rb + rt * Math.cos(f)), n[1] * (Rb + rt * Math.cos(f)), rt * Math.sin(f) + (dz || 0)];
}
function ikTorusG(Rb, rt, f0, f1, dz, na, nf) {
  var G = [], i, j;
  for (i = 0; i !== na + 1; i++) {
    var a = Math.PI / 2 * i / na, row = [];
    for (j = 0; j !== nf + 1; j++) { row.push(ikTorusP(Rb, rt, a, f0 + (f1 - f0) * j / nf, dz)); }
    G.push(row);
  }
  return G;
}
/* Ringsektor (Draufsicht) in der Hoehe z zwischen r0 und r1 */
function ikRingSektor(r0, r1, z) { return ikBogenPkt([0, 0, z], r1, 0, Math.PI / 2, 18).concat(ikBogenPkt([0, 0, z], r0, Math.PI / 2, 0, 18)); }

/* P56 Halbschalen pressen (gepresster Bogen): der Zuschnitt liegt auf der Matrize, der Stempel faehrt herab und presst ihn in die
   Form; heraus kommt die Halbschale (Rand gelb). Zwei Halbschalen ergeben den Bogen (P57). */
PSYM.P56 = { dt: 0.6, f: function (I) {
  var Rb = 24, rt = 8, Hd = 12;
  /* Matrize: gebogener Block mit der Mulde (Viertelbogen, halber Rohrquerschnitt). Reihenfolge: Oberseite innen, Mulde (nur die
     zum Betrachter zeigende Wand), Aussenwand und Rand; die Aussenwand verdeckt, was hinter ihr in der Mulde liegt */
  var ro = Rb + rt + 1.6, ri = Rb - rt - 9, Aw = [];
  I.poly(ikRingSektor(ri, Rb - rt, 0), IKF.T, { d: 0, sw: 1.3 });
  ikGitter(I, ikTorusG(Rb, rt, 0, -Math.PI, 0, 14, 10), { d: 0.3, nurSicht: 1, innen: 1, rand: 'i0 i1 j0 j1' });
  each(ikBogenPkt([0, 0, 0], ro, 0, Math.PI / 2, 18), function (p) { Aw.push([[p[0], p[1], -Hd], [p[0], p[1], 0]]); });
  I.band(Aw, { d: 0.6 });
  I.poly(ikRingSektor(Rb + rt, ro, 0), IKF.T, { d: 0.65, sw: 1.3 });
  I.folge(4, function (k) {
    var zp = [22, 0.2, 22, 22][k];
    if (k === 0) {
      var w = Math.PI * rt / 2;
      I.poly(ikRingSektor(Rb - w, Rb + w, 0.15), IKF.T, { d: 1, sw: 1.3 });
    }
    if (k === 3) {
      /* Halbschale angehoben: aussen gewoelbt (unten), innen die Mulde; Rand gelb */
      var G = ikTorusG(Rb, rt, 0, -Math.PI, 14, 14, 10);
      ikGitter(I, G, { d: 2, dreh: 1, rand: 'i0 i1 j0 j1', st: IKF.Y, sw: 2 });
    }
    if (k === 2) {
      ikGitter(I, ikTorusG(Rb, rt - 0.3, 0, -Math.PI, 0.1, 14, 10), { d: 0.45, nurSicht: 1, f: '#E3E9F0', rand: 'j0 j1', st: IKF.Y, sw: 2 });
    }
    /* Stempel: Ringsektor-Block, Oberseite und gewoelbte Aussenwand; Stoessel darueber */
    var r0 = Rb - rt - 0.6, r1 = Rb + rt + 0.6, h = 7, zo = zp + h;
    var Aw = [];
    each(ikBogenPkt([0, 0, 0], r1, 0, Math.PI / 2, 18), function (p) { Aw.push([[p[0], p[1], zp], [p[0], p[1], zo]]); });
    I.band(Aw, { d: 5, f: IKF.R });
    I.poly(ikRingSektor(r0, r1, zo), IKF.T, { d: 5.1, sw: 1.4 });
    var cm = [Rb * Math.cos(Math.PI / 4), Rb * Math.sin(Math.PI / 4)];
    I.zyl([cm[0], cm[1], zo], [cm[0], cm[1], zo + 22], 4, { d: 5.2 });
  });
  I.ex.push([ro, ro, -Hd], [0, 0, 60]);
} };

/* P57 Halbschalen schweissen (bogengefuehrt): die beiden Halbschalen liegen aneinander (zuerst noch getrennt); die Elektrodenrollen
   fahren auf einem Bogen an der Aussennaht entlang, die Naht wird gelb. Gestrichelt: der Weg der Rollen.
   Der Bogen steht senkrecht (Ebene x-z), die Aussenseite zeigt zum Betrachter, die Halbschalen teilen ihn vorn und hinten (y). */
function ikTorusXZ(Rb, rt, t, f, dy) {
  var r = Rb + rt * Math.cos(f);
  return [r * Math.cos(t), rt * Math.sin(f) + (dy || 0), r * Math.sin(t)];
}
function ikTorusXZG(Rb, rt, f0, f1, dy, na, nf) {
  var G = [], i, j;
  for (i = 0; i !== na + 1; i++) {
    var t = Math.PI / 2 * i / na, row = [];
    for (j = 0; j !== nf + 1; j++) { row.push(ikTorusXZ(Rb, rt, t, f0 + (f1 - f0) * j / nf, dy)); }
    G.push(row);
  }
  return G;
}
PSYM.P57 = { dt: 0.24, f: function (I) {
  /* Runde 14 der Szene (Dimi 10.11.2026): Rollennahtschweissen mit Drahtelektrode. Die Halbschalen liegen aneinander, ihre Raender
     bilden aussen am Bogen den Falz. Eine Elektrodenrolle faehrt aussen ueber den Falz, die andere innen im Bogen (gestrichelt, im Rohr);
     beide rollen gemeinsam die Naht entlang des Bogens, die Naht wird gelb. Die Rollen stehen quer zur Naht (Achse senkrecht zur
     Bogenebene); ohne Schwenkarm gezeichnet, damit die beiden Rollen deutlich bleiben. */
  var Rb = 22, rt = 8, fb = 2.4, rw = 4.2, N = 9, V0 = 3, m;
  var rA = Rb + rt + fb + rw, rI = Rb + rt - rw - 0.6;
  function rand(t0, t1, y) {
    var A = [], B = [], n = 16;
    for (m = 0; m !== n + 1; m++) { var t = t0 + (t1 - t0) * m / n; A.push([(Rb + rt) * Math.cos(t), y, (Rb + rt) * Math.sin(t)]); B.push([(Rb + rt + fb) * Math.cos(t), y, (Rb + rt + fb) * Math.sin(t)]); }
    return A.concat(B.reverse());
  }
  function kreis(c, nO, tO, r, y) {
    var P = [], a;
    for (m = 0; m !== 29; m++) { a = 2 * Math.PI * m / 28; P.push([c[0] + r * (Math.cos(a) * nO[0] + Math.sin(a) * tO[0]), y, c[2] + r * (Math.cos(a) * nO[2] + Math.sin(a) * tO[2])]); }
    return P;
  }
  I.folge(N + 2 + V0, function (k0) {
    var vorn = [12, 12, 5][k0], k = Math.max(k0 - V0, 0);
    if (vorn === undefined) { vorn = 0; }
    var zu = !gt(vorn, 0);
    ikGitter(I, ikTorusXZG(Rb, rt, Math.PI, 2 * Math.PI, 0, 14, 10), { d: 1, nurSicht: zu ? 1 : 0, dreh: 1, rand: zu ? 'i0 i1' : 'i0 i1 j0 j1' });
    I.poly(rand(0, Math.PI / 2, 0), IKF.T, { d: 1.5, sw: 1.2 });
    if (!zu) { I.poly(rand(0, Math.PI / 2, vorn), IKF.T, { d: 2.5, sw: 1.2 }); }
    ikGitter(I, ikTorusXZG(Rb, rt, 0, Math.PI, vorn, 14, 10), { d: 2, nurSicht: 1, dreh: 1, rand: 'i0 i1' });
    if (!zu) { return; }
    var u = Math.min(Math.max(k - 1, 0), N) / N, t = 0.05 + (Math.PI / 2 - 0.1) * u, ab = (k === N + 1) ? 7 : 0;
    var nO = [Math.cos(t), 0, Math.sin(t)], tO = [-Math.sin(t), 0, Math.cos(t)];
    if (gt(u, 0)) { I.poly(rand(0, t, 0.05), IKF.Y, { d: 2.6, sw: 1.2 }); }
    /* innere Rolle im Rohr: gestrichelter Umriss */
    var ci = mu(nO, rI - ab * 0.3);
    I.line(kreis(ci, nO, tO, rw, -1.4), { d: 3.4, sw: 1.1, da: '2 2' });
    I.line(kreis(ci, nO, tO, rw, 1.4), { d: 3.41, sw: 1.1, da: '2 2' });
    /* aeussere Rolle ueber dem Falz, Achse quer zur Naht */
    var ca = mu(nO, rA + ab);
    I.zyl(ad(ca, [0, -1.6, 0]), ad(ca, [0, 1.6, 0]), rw, { d: 3.5 });
    I.zyl(ad(ca, [0, -1.6, 0]), ad(ca, [0, -5, 0]), 1.3, { d: 3.45, fe: IKF.D });
  });
  /* Weg der Rollen: aussen ueber dem Falz und innen im Bogen (gestrichelt) */
  var Fa = [], Fi = [];
  for (m = 0; m !== 25; m++) { var a = Math.PI / 2 * m / 24; Fa.push([(rA + rw + 1.5) * Math.cos(a), 0, (rA + rw + 1.5) * Math.sin(a)]); Fi.push([(rI - rw - 1) * Math.cos(a), 0, (rI - rw - 1) * Math.sin(a)]); }
  I.line(Fa, { d: 0.5, sw: 1, da: '3 3' });
  I.line(Fi, { d: 3.3, sw: 0.8, da: '2 3' });
  I.ex.push([0, -rt - 9, Rb + rt + 14], [Rb + rt + 14, 14, -rt]);
} };

/* ---------- Prozess-Symbole, Runde 19 der Szene (Dimi 11.11.2026, 22:43; Antworten auf die Fragen der Runde 18) ----------
   Neu gefasst: P58 (Rollformer fuer den Kulissenrahmen: zwei Durchgaenge, Blech wenden, Kante nach oben), P59 (T-Buegel-Profil mit
   doppelt gelegtem Steg), P35 (Kulissenmaschine: Ablauf vom Coil bis zum gebogenen Rahmenteil).
   Neu: P60 Kulisse montieren, P61 Schnappfalz profilieren, P62 Hakenfalz profilieren, P63 S-Cleat profilieren,
   P64 Rundfalz am Luftleitblech profilieren, P65 Auflageleisten reinigen, P66 Sandwichpaneel trennen.
   Runde 20 (Dimi 12.11.2026, 01:10): P35 mit Trennen vor dem Biegen und den Bauformen des Rahmens in der Lupe,
   P63 mit dem Standing S-Cleat als zweitem Bild.
   Bausteine aus 60_prozess.js, 61_prozess_sym.js, 62_anlagen.js und 63_symbole_r10.js.
   Regel wie dort: Teile in einer Bildfolge (I.folge) bekommen keine Bewegungsklassen. */

/* Farbe einer Blechflaeche nach ihrer Lage, mit weichem Verlauf (fuer Rundungen): oben hell, vorn mittel, hinten dunkler */
function r19Farbe(q4) {
  var n = nz(newell(q4));
  if (lt(n[2], 0)) { n = mu(n, -1); }
  var s = 1 - Math.abs(n[2]);
  return ikMisch(IKF.T, lt(n[1] + n[0], -0.05) ? IKF.I : IKF.L, Math.min(1, s));
}
/* Blechprofil laengs x von x0 bis x1 mit dem Querschnitt M (Punkte [y, z]): Flaechen nach Tiefe geordnet, Laengskanten und Enden
   als Linien. o.gelb(i): Flaeche i gelb; o.dz(i): Tiefenzuschlag der Flaeche i; o.stirn: Blechdicke an der Stirn bei x1
   (1 dunkel, 2 gelb); o.ohne: Liste von Flaechen, die nicht gezeichnet werden (Luecken im Querschnitt);
   o.map(x, q): Lage eines Punktes, wenn das Profil nicht laengs x liegt (z. B. hochgebogener Schenkel) */
function r19Band(I, M, x0, x1, d, o) {
  o = o || {};
  var n = M.length, i, F = [], t0 = 1e9, t1 = -1e9;
  function P(x, q) { return o.map ? o.map(x, q) : [x, q[0], q[1]]; }
  for (i = 0; i !== n - 1; i++) {
    if (o.ohne) { if (o.ohne.indexOf(i) !== -1) { continue; } }
    var q4 = [P(x0, M[i]), P(x1, M[i]), P(x1, M[i + 1]), P(x0, M[i + 1])], tt = DE(mitte(q4));
    F.push({ q: q4, t: tt, i: i }); t0 = Math.min(t0, tt); t1 = Math.max(t1, tt);
  }
  each(F, function (f) {
    var g = o.gelb ? o.gelb(f.i) : false, c = g ? IKF.Y : r19Farbe(f.q), dd = d + 0.015 * (gt(t1, t0) ? (f.t - t0) / (t1 - t0) : 0) + (o.dz ? o.dz(f.i) : 0);
    I.poly(f.q, c, { d: dd, sw: 0.7, st: c });
    I.line([f.q[0], f.q[3]], { d: dd + 0.002, sw: 1.3 });
    I.line([f.q[1], f.q[2]], { d: dd + 0.002, sw: 1.3 });
    if (f.i === 0) { I.line([f.q[0], f.q[1]], { d: dd + 0.002, sw: 1.4 }); }
    if (f.i === n - 2) { I.line([f.q[3], f.q[2]], { d: dd + 0.002, sw: 1.4 }); }
    if (o.kanten) { if (o.kanten.indexOf(f.i) !== -1) { I.line([f.q[3], f.q[2]], { d: dd + 0.002, sw: 0.8 }); } }
  });
  if (o.stirn) {
    var dm = d + 0.02 + (o.dz ? o.dz(-1) : 0);
    I.poly(srpBand(M, o.dick || 0.9).map(function (q) { return P(x1, q); }), o.stirn === 2 ? IKF.Y : IKF.B, { d: dm, sw: o.stirn === 2 ? 1.4 : 0.6, st: o.stirn === 2 ? IKF.Y : IKF.B });
  }
}
/* Pfeil entlang einer Punktfolge (3D), Spitze am Ende */
function r19Pfeil(I, q, d, o) {
  o = o || {};
  var m = q.length, e = q[m - 1], tg = nz(sb(q[m - 1], q[m - 2])), qq = o.q || [0, 0, 1], nn = nz(cr(tg, qq)), L = o.L || 3.4, W = o.W || 2.2;
  I.line(q, { d: d, sw: o.sw || 1.5, da: o.da });
  I.poly([ad(e, mu(tg, L * 0.7)), ad(sb(e, mu(tg, L * 0.5)), mu(nn, W)), ad(sb(e, mu(tg, L * 0.5)), mu(nn, -W))], IKF.B, { d: d + 0.01, sw: 0.8 });
}

/* ===== P58 Rollformer fuer den Kulissenrahmen (Antwort Dimi 11.11.2026: zwei Durchgaenge, Blech wenden, Kante nach oben) =====
   Querschnitt [y, z]: flache Mitte, vorn (aF) und hinten (aB) eine Kante mit Radius nach oben angebogen; die Blechbreite bleibt gleich.
   Rueckgabe: Punkte von vorn nach hinten, typ je Flaeche (0 flach, 1 Rundung, 2 Schenkel), seite (1 vorn, -1 hinten) */
var KR2 = { yc: 5, Rr: 5, l: 3, n: 5 };
function kr2Quer(aF, aB, K0) {
  var K = K0 || KR2;
  function seite(sg, a) {
    var P = [], j;
    if (gt(a, 0.01)) { for (j = 1; j !== K.n + 1; j++) { var f = a * j / K.n; P.push([sg * (K.yc + K.Rr * Math.sin(f)), K.Rr - K.Rr * Math.cos(f)]); } }
    var e = P.length ? P[P.length - 1] : [sg * K.yc, 0], ll = K.l + K.Rr * (Math.PI / 2 - a);
    P.push([e[0] + sg * Math.cos(a) * ll, e[1] + Math.sin(a) * ll]);
    return P;
  }
  var V = seite(1, aF).reverse(), H = seite(-1, aB), M = V.concat([[K.yc, 0], [-K.yc, 0]]).concat(H), typ = [], sei = [], i;
  for (i = 0; i !== M.length - 1; i++) {
    if (lt(i, V.length)) { typ.push(i === 0 ? 2 : 1); sei.push(1); }
    else if (i === V.length) { typ.push(0); sei.push(0); }
    else { typ.push(i === M.length - 2 ? 2 : 1); sei.push(-1); }
  }
  return { M: M, typ: typ, sei: sei, aF: aF, aB: aB };
}
PSYM.P58 = { dt: 0.42, f: function (I) {
  var K = KR2, DT = 0.42, r = 4.4, t = 0.9, XS = [-12, 10], W = [0, Math.PI / 4, Math.PI / 2], Lb = 38, N = 12, H = Math.PI / 2;
  var X1 = [-18, 2, 22, 40, 54];
  ikHalten(I, (N - 1) * DT + 1.4);
  /* Rollenpaare auf der flachen Mitte; hinten an der Kante die Formrolle (45 Grad, dann senkrecht) */
  each(XS, function (x, i) {
    ikRollenpaar(I, [x, 0, 0], [0, 1, 0], r, 2 * K.yc - 1, t + r + 0.3, -r - 0.6, { d: 6 + i, du: -1 + i * 0.1 });
    var a = W[i + 1], Q = kr2Quer(0, a).M, e0 = Q[Q.length - 2], e1 = Q[Q.length - 1], m = [(e0[0] + e1[0]) / 2, (e0[1] + e1[1]) / 2];
    var dir = [-Math.cos(a), Math.sin(a)], no = [-Math.sin(a), -Math.cos(a)], rr = 2.6, c = [m[0] + no[0] * (rr + 0.5), m[1] + no[1] * (rr + 0.5)];
    I.zyl([x, c[0] - dir[0] * 4, c[1] - dir[1] * 4], [x, c[0] + dir[0] * 4, c[1] + dir[1] * 4], rr, { d: 0.6 + i * 0.1 });
  });
  ikPfeil(I, [-58, K.yc + 16, 0], [-44, K.yc + 16, 0], { d: 0.5, sw: 1.3 });
  /* Blech der Laenge Lb mit der vorderen Kante bei x1: je Abschnitt zwischen den Stationen der passende Querschnitt */
  function blech(x1, aF, gelb) {
    var x0 = x1 - Lb, G = [-1e9, XS[0], XS[1], 1e9], j;
    for (j = 0; j !== 3; j++) {
      var xa = Math.max(x0, G[j]), xb = Math.min(x1, G[j + 1]);
      if (!gt(xb - xa, 0.3)) { continue; }
      (function (Q) {
        r19Band(I, Q.M, xa, xb, 1 + j, {
          gelb: function (i) { return gelb ? Q.typ[i] === 1 : false; },
          dz: function (i) { if (i === -1) { return aF ? 6.6 : 0; } return (Q.sei[i] === 1 ? (aF ? 6.5 : 0) : 0); },
          stirn: (xb === x1) ? (gelb ? 2 : 1) : 0
        });
      })(kr2Quer(aF, W[j]));
    }
  }
  I.folge(N, function (k) {
    if (lt(k, 5)) { blech(X1[k], 0, 0); return; }
    if (k === 5) {
      /* Wenden: das Blech liegt gedreht hinter der Maschine (die geformte Kante jetzt vorn) und wird noch einmal eingelegt */
      blech(X1[4], H, 0);
      var c = [X1[4] - Lb / 2, 0, 11], q = ikKreis(c, [1, 0, 0], [0, 1, 0], 12, 22, Math.PI * 0.15, Math.PI * 1.25);
      r19Pfeil(I, q, 9.5, { sw: 1.6 });
      r19Pfeil(I, [[X1[4] - Lb - 2, K.yc + 16, 0], [-38, K.yc + 16, 0]], 0.6, { sw: 1.3, da: '4 3' });
      return;
    }
    if (lt(k, 11)) { blech(X1[k - 6], H, 0); return; }
    blech(X1[4], H, 1);
  });
  /* Lupe: Querschnitt (hintere Kante rechts, oben = oben) */
  ikLupe(I, [22, -42, 32], 14, N, function (P, k) {
    var aF = lt(k, 5) ? 0 : H, kk = lt(k, 5) ? k : (k === 5 ? -1 : Math.min(k - 6, 4)), aB = kk === -1 ? 0 : (kk === 0 ? 0 : (kk === 1 ? H / 2 : H));
    var Q = kr2Quer(aF, aB), s = 0.72;
    function U(q) { return P(-q[0] * s, 4 - q[1] * s); }
    I.line(Q.M.map(U), { d: 20.2, sw: 2.4 });
    if (k === 5) { pfeil2(I, P, [-5, 8], [5, 8], 20.3, { sw: 1.2 }); pfeil2(I, P, [5, 8], [-5, 8], 20.3, { sw: 1.2 }); }
    if (k === N - 1) {
      var a = [], b = [], i;
      for (i = 0; i !== Q.M.length; i++) { if (lt(i, K.n + 2)) { if (gt(i, 0)) { a.push(U(Q.M[i])); } } if (gt(i, Q.M.length - K.n - 3)) { if (lt(i, Q.M.length - 1)) { b.push(U(Q.M[i])); } } }
      I.line(a, { d: 20.3, sw: 2.8, st: IKF.Y }); I.line(b, { d: 20.3, sw: 2.8, st: IKF.Y });
    }
  }, { von: [X1[4] - 4, -K.yc - K.Rr, K.Rr + 2], dv: 9.6 });
  I.ex.push([56, 16, 0], [-58, K.yc + 18, 0], [-18 - Lb, -16, 0]);
} };

/* ===== P59 Profilierer fuer das T-Buegel-Profil (Antwort Dimi 11.11.2026: Steg doppelt gelegt) =====
   Ein flaches Band laeuft durch die Rollenstationen; die Bandmitte stellt sich als Dach auf und wird zum doppelt gelegten Steg
   zusammengedrueckt, die beiden Raender bleiben als Flansch liegen. Schenkel gleich lang (Strukturdaten Runde 12).
   Querschnitt [y, z] fuer den Aufstellwinkel a: Flansch, Stegseite, Falte oben, Stegseite, Flansch */
var TB2 = { s: 7, h: 7, g: 0.5 };
function tb2Quer(a, gg) {
  var T = TB2, c = T.h * Math.cos(a), hs = T.h * Math.sin(a), g = gt(a, 0.01) ? (gg || T.g) : 0;
  return [[T.s + c + g, 0], [c + g, 0], [g, hs], [-g, hs], [-c - g, 0], [-T.s - c - g, 0]];
}
PSYM.P59 = { dt: 0.34, f: function (I) {
  var T = TB2, DT = 0.34, r = 4.2, t = 0.9, N = 7, XR = [-30, -17, -4], A = [0, 0.7, 1.2, Math.PI / 2];
  ikHalten(I, (N - 1) * DT + 1.4);
  var G = [-48, XR[0], XR[1], XR[2], 4];
  each(A, function (a, j) {
    r19Band(I, tb2Quer(a), G[j], G[j + 1], 1 + j * 0.2, { kanten: [1, 3] });
  });
  /* Rollen: unten durchgehend, oben je eine Scheibe links und rechts des Stegs auf den Flanschen */
  each(XR, function (x, i) {
    var Q = tb2Quer(A[i + 1]), yv = (Q[0][0] + Q[1][0]) / 2, zo = t + r + 0.3;
    I.zyl([x, -T.s - T.h - 1, -r - 0.6], [x, T.s + T.h + 1, -r - 0.6], r, { d: -1 + i * 0.1 });
    I.zyl([x, -yv - 2.4, zo], [x, -yv + 2.4, zo], r, { d: 0.6 + i * 0.2 });
    I.zyl([x, yv - 2.4, zo], [x, yv + 2.4, zo], r, { d: 6 + i });
    ikDreh(I, [x, yv + 2.4, zo], [0, 1, 0], r * 0.55, { d: 6.05 + i, sw: 0.9, da: '2 2.5' });
  });
  ikStrich(I, [[-48, T.s + T.h - 2, t + 0.05], [XR[0] - 5, T.s + T.h - 2, t + 0.05]], { d: 5, da: '5 6', cls: 'zl', sty: { '--lt': '.7s', '--lz': '6' } });
  var QE = tb2Quer(Math.PI / 2);
  I.folge(N, function (k, s) {
    r19Band(I, QE, 4, 14 + 30 * s, 9, { stirn: k === N - 1 ? 2 : 1, dick: 0.8, kanten: [1, 3] });
  });
  ikPfeil(I, [-50, T.s + T.h + 8, 0], [-36, T.s + T.h + 8, 0], { d: 0.5, sw: 1.3 });
  /* Lupe: Querschnitt in vier Schritten (flach, Dach, steiles Dach, Steg doppelt gelegt) */
  ikLupe(I, [34, -40, 32], 14, N, function (P, k) {
    var a = A[Math.min(3, Math.max(0, k - 1))], Q = tb2Quer(a, 1.5), s = 0.74;
    if (lt(k, 2)) { Q = tb2Quer(0); }
    var pts = Q.map(function (q) { return P(q[0] * s, 5.5 - q[1] * s * 1.5); });
    I.line(pts, { d: 20.2, sw: 2 });
    if (k === N - 1) { I.line(pts.slice(1, 5), { d: 20.3, sw: 2.4, st: IKF.Y }); }
  }, { von: [-10, -1, 7], dv: 9.6 });
  I.ex.push([46, 8, 0], [-50, T.s + T.h + 10, 0]);
} };

/* ===== Bauteilmodell (10_kern.js, 31_kulisse.js) in einem Ablaufsymbol =====
   Das Modell wird wie ein Bauteilbild berechnet (symbolRechnen) und Element fuer Element uebernommen: dasselbe Bild wie in der Kartei.
   tr(p): Lage im Symbol (2D), gelb(o): Element gelb hervorheben. Muster (Mineralwolle, Lochblech) stehen einmal im Dokument. */
function r19Muster() {
  if (!document.getElementById('wsz-loch')) { var hs = sv('svg', { width: 0, height: 0, 'aria-hidden': 'true' }); hs.style.position = 'absolute'; muster(hs); document.body.appendChild(hs); }
}
function r19Rechnen(f) { return symbolRechnen('skulisse', { f: f }); }
function r19Modell(I, R, d0, tr, gelb) {
  each(R.it, function (o, i) {
    if (!o.p) { return; }
    var p = o.p.map(tr), g = gelb ? gelb(o) : false, a;
    if (o.t === 'f') {
      var f = g ? ((String(o.f).indexOf('url') === 0) ? o.f : shade('y', o.n || [0, 0, 1])) : o.f;
      a = { d: pfad(p, 1), fill: f, stroke: g ? '#B88A00' : (o.s || f), 'stroke-width': (o.s || g) ? (o.w || 0.8) : 0.6 };
    } else if (o.t === 'l') {
      a = { d: pfad(p, 0), fill: 'none', stroke: g ? '#B88A00' : o.s, 'stroke-width': o.w };
      if (o.da) { a['stroke-dasharray'] = o.da; }
    } else { return; }
    if (o.op !== undefined) { if (o.op !== null) { a.opacity = o.op; } }
    I.add(d0 + i * 1e-4, a, { pts: p });
  });
}

/* ===== P60 Kulisse montieren (Dimi 11.11.2026, 22:43 und Pruefliste 22.8 a: eigener Schritt, von Hand) =====
   Kammerbleche und T-Buegelprofil einsetzen; Daemmung in die eine Rahmenhaelfte, die andere Haelfte aufschieben, sodass die Daemmung
   umschlossen ist; T-Buegelprofil mittig an den Rahmen nieten; Rahmenteile an den Laschen miteinander nieten; jede Ecke nieten.
   Neue Teile sind im Bild ihres Schritts gelb, am Ende stehen die Niete gelb. */
PSYM.P60 = { dt: 0.85, f: function (I) {
  var N = 7, DT = 0.85, R = [], k;
  r19Muster();
  for (k = 0; k !== N; k++) { (function (s) { R.push(r19Rechnen(function () { skulisseMontage(s); })); })(k); }
  ikHalten(I, (N - 1) * DT + 1.6);
  I.folge(N, function (k) {
    r19Modell(I, R[k], 1, function (p) { return [p[0], p[1]]; }, function (o) { return o.cls ? String(o.cls).indexOf('neu') !== -1 : false; });
  });
} };

/* ===== P35 Schalldaempferkulissenmaschine (Dimi 11.11.2026, 22:43; Runde 20, Dimi 12.11.2026, 01:10) =====
   Ablauf: Blech vom Coil, richten; an den Ecken beidseitig ausklinken, wo spaeter gekantet wird (damit die anprofilierten Rahmen mit
   Radius beim Biegen sauber abschliessen; die Ecken ueberlappen danach fast nicht, nur eine kleine Lasche fuer den Niet, Dimi
   12.11.2026, 07:03); laengs versteifen (meist Trapezsicken);
   beidseitig profilieren; das Rahmenteil vom Band trennen (Runde 20: „vor biegen“); zum Schluss biegen und ausgeben.
   Die Stationen sind Gehaeuse wie an der Maschine (Hauben); zwischen ihnen ist das Band mit dem jeweils neuen Merkmal zu sehen.
   Das Trennwerkzeug ist nicht belegt: gezeichnet ist nur die Schnittlinie am Band (gelb; bleibt so, Dimi 12.11.2026, 07:03), danach liegt das Rahmenteil mit Abstand
   zum Band in der Biegestation. Im Ablauf entsteht die uebliche Bauform 2 x L.
   Letzte Bilder: das Rahmenteil liegt hinter der Maschine; die Lupe zeigt nacheinander die Bauformen des Rahmens aus dem Modell der
   Kartei (51_skulisse.js, skulisseRahmen): aus einem Blech gekantet, 1 x U und 1 x I, 4 x I, zuletzt 2 x L (Ruhebild).
   Was ueber mehrere Bilder gleich bleibt, steht nur einmal im Bild und erscheint zu seinem Zeitpunkt (Klassen p35a ab Bild 4:
   Band bis zur Schnittlinie; p35b ab Bild 6: Rahmenteil auf dem Tisch und Lupe; 4 bzw. 6 Bilder zu je 0,85 s). */
var K35 = { yc: 6, Rr: 3, l: 1.3, n: 4 };
PSYM.P35 = { dt: 0.85, css: '.wps .p35h{fill-opacity:.3}.wps.go .p35a{animation:wpsI .01s linear calc(var(--bt) + 3.4s) both}.wps.go .p35b{animation:wpsI .01s linear calc(var(--bt) + 5.1s) both}', f: function (I) {
  var DT = 0.85, NB = 4, N = 6 + NB, t = COIL.t, W = COIL.W, W2 = W / 2, K = K35, H = Math.PI / 2;
  var xc = -152, xB = -136, xK = -103, xS = -85, xP = -55, xT = -36, la = 16, lb = 30, lt2 = la + lb, ab = 4, xG = xT + ab + lb, xE = xG - 1, kt = K.l + K.Rr * H;
  var QP = kr2Quer(H, H, K), nq = QP.M.length, mitteI = K.n + 1, RM = [], BF = [0, 2, 3, 1], j0;
  r19Muster();
  ikHalten(I, (N - 1) * DT + 1.6);
  /* Coil, Bett (bis hinter die Biegestation), Tisch hinter der Maschine */
  anCoilBock(I, xc, 0, -BETT, 0);
  ikDreh(I, [xc, W2 + 0.1, -COIL.R], [0, 1, 0], COIL.R - 7, { d: 0.3, sw: 0.9 });
  I.box(xc, -W2, 0, xB - xc, W, t, { d: 0.5 });
  I.line([[xc + 4, 0, t + 0.05], [xB - 1, 0, t + 0.05]], { d: 0.6, sw: 1, da: '3 4', cls: 'zl', sty: { '--lt': '.9s', '--lz': '8' } });
  I.box(xB, -16, -BETT, xE - xB, 32, BETT, { d: 1, ft: ANF.bett });
  each([[xE + 5, -13], [38, -13], [xE + 5, 10], [38, 10]], function (q, i) { I.box(q[0], q[1], -BETT, 3, 3, BETT - 3, { d: 2.42 + i * 0.01 }); });
  I.box(xE + 2, -15, -3, 42 - xE, 30, 3, { d: 2.5 });
  /* Stationen: Richten, Ausklinken (Stempel), Versteifen, Profilieren beidseitig, (Trennen: Schnittlinie), Biegen */
  /* Hauben durchscheinend (wie die Fenster der Maschine): das Band ist darunter zu sehen */
  var yw = 17;
  I.mit('p35h', function () {
    anGehaeuse(I, -132, 14, 12, 1.5); anGehaeuse(I, -108, 10, 11, 1.7); anGehaeuse(I, -90, 10, 12, 1.9); anGehaeuse(I, -70, 30, 12, 2.1); anGehaeuse(I, xG - 9, 7, 10, 2.3);
  });
  anWalzen(I, yw + 0.05, [[-129.5, 3.2], [-125, 3.2], [-120.5, 3.2], [-127.3, 7], [-122.8, 7]], 1.7, 1.55);
  each([-9, 9], function (y, i) {
    I.zyl([xK, y, 11], [xK, y, 14.5], 2.2, { d: 1.75 + i * 0.01 });
    I.zyl([xK, y, 13], [xK, y, 18], 1.3, { d: 1.8 + i * 0.01, cls: 'zu', sty: { '--my': '3px', '--mt': '.7s', '--zs': (DT * 0.9) + 's' } });
  });
  anWalzen(I, yw + 0.05, [[xS, 3.6], [xS, 8.6]], 2.3, 1.95);
  anWalzen(I, yw + 0.05, [[-64, 3.4], [-64, 8.4], [-55, 3.4], [-55, 8.4], [-46, 3.4], [-46, 8.4]], 2.2, 2.15);
  ikPfeil(I, [xB + 2, 26, 0], [xB + 16, 26, 0], { d: 0.4, sw: 1.3 });
  /* Sicken auf der flachen Mitte von xa bis xb (Trapezsicken: je zwei Linien) */
  function sicken(xa, xb, d, map, gelb) {
    if (!gt(xb - xa, 0.4)) { return; }
    each([-3.4, 0, 3.4], function (y) {
      each([-0.55, 0.55], function (dy) {
        var a = [xa, y + dy, t + 0.06], b = [xb, y + dy, t + 0.06];
        if (map) { a = map(xa, [y + dy, 0.06]); b = map(xb, [y + dy, 0.06]); }
        I.line([a, b], { d: d, sw: gelb ? 1.5 : 0.7, st: gelb ? IKF.Y : ANF.sicke });
      });
    });
  }
  /* flaches Band bis xe: Ausklinkungen (beidseitig, Tiefe = Zuschnitt fuer Rundung und Schenkel) hinter dem Stempel, Sicken hinter den Rollen */
  function flach(xe, NL, hv) {
    I.box(xB, -W2, 0, xe - xB, W, t, { d: 1.2 });
    sicken(xS, xe - 0.3, 1.22, null, hv === 2);
    each(NL, function (xn) {
      if (lt(xn, xK) || gt(xn, xe - 1)) { return; }
      each([-1, 1], function (sg) { I.poly([[xn - 1, sg * W2, t + 0.07], [xn + 1, sg * W2, t + 0.07], [xn + 1, sg * (W2 - kt), t + 0.07], [xn - 1, sg * (W2 - kt), t + 0.07]], hv === 1 ? IKF.Y : IKF.G, { d: 1.23, sw: 0.5 }); });
    });
  }
  /* profiliertes Stueck von xa bis xb: beide Kanten mit Radius nach oben; an den Ausklinkungen fehlen Rundung und Schenkel */
  function profil(xa, xb, NL, d, gelb, map) {
    var G = [xa], j, nur = [];
    if (!gt(xb - xa, 0.3)) { return; }
    each(NL, function (xn) { if (gt(xn - 1, xa)) { if (lt(xn + 1, xb)) { G.push(xn - 1); G.push(xn + 1); } } });
    G.push(xb);
    for (j = 0; j !== nq - 1; j++) { if (j !== mitteI) { nur.push(j); } }
    for (j = 0; j !== G.length - 1; j++) {
      r19Band(I, QP.M, G[j], G[j + 1], d, { map: map, ohne: (j % 2) ? nur : null, gelb: function (i) { return gelb ? QP.typ[i] === 1 : false; }, dz: function (i) { return (i !== -1) ? (QP.sei[i] === 1 ? 0.05 : 0) : 0; } });
    }
    sicken(xa + 0.3, xb - 0.3, d + 0.1, map);
  }
  /* Ausklinkungen im Band mit der Vorderkante xf: jedes Rahmenteil ist la + lb lang, die Biegestelle liegt la hinter seiner Vorderkante */
  function klinken(xf) { return [xf - la, xf - la - lt2, xf - la - 2 * lt2]; }
  /* profiliertes Band bis zur Schnittlinie; das naechste Rahmenteil beginnt dort */
  function band() { var NL = klinken(xT); flach(xP, NL, 0); profil(xP, xT, NL, 1.3, 0); }
  I.folge(N, function (k) {
    var XV = [-112, -90, -74, xT - 1], xv, NL;
    if (lt(k, 4)) {
      xv = XV[k]; NL = klinken(xv);
      flach(Math.min(xv, xP), NL, k === 1 ? 1 : (k === 2 ? 2 : 0));
      if (gt(xv, xP)) { profil(xP, xv, NL, 1.3, 1); }
      return;
    }
    if (k === 4) {
      /* Trennen: das Rahmenteil (la + lb) ist ueber die Schnittlinie hinausgelaufen; Schnittlinie quer ueber das Profil, gelb */
      NL = [xT + lb];
      profil(xT, xE, NL, 1.31, 0); profil(xE, xT + lt2, NL, 2.6, 0);
      I.line(QP.M.map(function (q) { return [xT, q[0], q[1] + 0.12]; }), { d: 3.2, st: IKF.Y, sw: 2.8 });
      return;
    }
    if (k === 5) {
      /* Biegen: das abgetrennte Teil liegt mit Abstand zum Band in der Biegestation; der vordere Schenkel stellt sich an der Ausklinkung um 90 Grad auf */
      profil(xT + ab, xE, [], 1.31, 0);
      profil(xG + 1, xG + la, [], 3, 0, function (x, q) { return [xG - q[1], q[0], x - xG]; });
      I.poly([[xG - 1, -K.yc, t], [xG + 1, -K.yc, t], [xG + 1, K.yc, t], [xG - 1, K.yc, t]], IKF.T, { d: 2.61, sw: 0.8 });
      I.line([[xG, -K.yc, t + 0.1], [xG, K.yc, t + 0.1]], { d: 3.1, st: IKF.Y, sw: 2.4 });
      return;
    }
  });
  I.mit('p35a', function () { band(); });
  /* letzte Bilder: fertiges Rahmenteil (L) auf dem Tisch, Rundungen gelb; Lupe mit den Bauformen des Rahmens aus dem Modell */
  for (j0 = 0; j0 !== NB; j0++) { (function (bf) { RM.push(r19Rechnen(function () { skulisseRahmen(bf); })); })(BF[j0]); }
  var c = [14, -56, 34], RL = 27, cq = PQ(c), gr = 0, ring = [], j;
  each(RM, function (R) { gr = Math.max(gr, R.vb[2], R.vb[3]); });
  for (j = 0; j !== 49; j++) { var a = 2 * Math.PI * j / 48; ring.push([cq[0] + RL * Math.cos(a), cq[1] + RL * Math.sin(a)]); }
  var x0 = xE + 8, xk = x0 + lb, vq = PQ([xk, -K.yc, la]);
  I.mit('p35b', function () {
    profil(x0, xk - 1, [], 3.4, 1);
    profil(xk + 1, xk + la, [], 3.6, 1, function (x, q) { return [xk - q[1], q[0], x - xk]; });
    I.poly([[xk - 1, -K.yc, t], [xk + 1, -K.yc, t], [xk + 1, K.yc, t], [xk - 1, K.yc, t]], IKF.T, { d: 3.41, sw: 0.8 });
    I.add(19.9, { d: pfad([vq, [cq[0] + RL * 0.5, cq[1] + RL * 0.86]], 0), fill: 'none', stroke: IKF.B, 'stroke-width': 0.9, 'stroke-dasharray': '2 2' }, { pts: [vq] });
    I.add(20, { d: pfad(ring, 1), fill: IKF.W, stroke: IKF.B, 'stroke-width': 1.6 }, { pts: ring });
  });
  I.folge(N, function (k) {
    if (lt(k, 6)) { return; }
    var R = RM[k - 6], vb = R.vb, s = 2 * RL * 0.9 / gr, mx = vb[0] + vb[2] / 2, my = vb[1] + vb[3] / 2;
    r19Modell(I, R, 20.1, function (p) { return [cq[0] + (p[0] - mx) * s, cq[1] + (p[1] - my) * s]; });
  });
  I.ex.push([xc - 12, 0, 0], [46, 16, 0], [14, -56, 62]);
} };

/* ===== Kantenprofilierer (wie P09): der Zuschnitt wird mit seiner Kante durch die Rollenpaare gezogen =====
   o.N Bilder, o.hP Hoehe des Profils an der Kante, o.f Breite, o.rund: Wulst (Rohr) statt Tasche, o.R Radius der Lupe,
   o.lupe(P, k): Querschnitt im Bild k (P(x, y): x rechts, y unten), o.sk Massstab in der Lupe. Die Lupe laeuft mit der Bildfolge. */
function r19KantenBild(I, o) {
  var t = 1.5, Lb = 40, f = o.f || 7, hP = o.hP || 4.2, r = 3.6, xk = 26, ys = [16, 8, 0, -8, -16], N = o.N || 6, R = o.R || 14;
  ikHalten(I, N * (o.dt || 0.42) + 1.4);
  I.box(xk - f - 2, -24, -14, f + 6, 48, 6, { d: -6, ft: IKF.I });
  I.folge(N + 1, function (k, s) {
    var yv = 58 - 42 * Math.min(1, k / (N - 1)), fertig = k === N;
    I.box(xk - 44, yv - Lb, 0, 44 - f, Lb, t, { d: 0 });
    var grenzen = [1e9].concat(ys).concat([-1e9]);
    for (var j = 0; j !== grenzen.length - 1; j++) {
      var ya = Math.max(Math.min(grenzen[j], yv), yv - Lb), yb = Math.max(Math.min(grenzen[j + 1], yv), yv - Lb);
      if (!gt(ya - yb, 0.3)) { continue; }
      var q = j / ys.length, hh = t + (hP - t) * q, gelb = j === ys.length;
      if (o.rund) {
        /* die Kante rollt sich von Station zu Station weiter ein: flach, dann Wulst */
        var rr = o.rund;
        if (lt(q, 0.35)) { I.box(xk - f, yb, 0, f, ya - yb, t, { d: 0.2 + j * 0.01 }); }
        else {
          I.box(xk - f, yb, 0, f - 2 * rr * q, ya - yb, t, { d: 0.2 + j * 0.01 });
          I.zyl([xk - rr, yb, rr * q + (1 - q) * t], [xk - rr, ya, rr * q + (1 - q) * t], rr * (0.55 + 0.45 * q), { d: 0.22 + j * 0.01, f: gelb ? IKF.Y : IKF.L, fe: gelb ? '#FFE27E' : IKF.T, hohl: gelb ? 1 : 0 });
        }
      } else {
        I.box(xk - f, yb, 0, f, ya - yb, hh, gelb ? ext(IKY, { d: 0.2 + j * 0.01 }) : { d: 0.2 + j * 0.01 });
      }
    }
  });
  each(ys, function (y, i) { ikRollen2(I, xk - f / 2, y, [1, 0, 0], r, f + 3, 0, hP, 3 + i * 0.1); });
  ikPfeil(I, [-6, 40, t + 0.1], [-6, 24, t + 0.1], { d: 1.5, sw: 1.5 });
  var sk = o.sk || 1;
  ikLupe(I, o.c || [38, -52, 28], R, N + 1, function (P, k) { o.lupe(function (x, y) { return P(x * sk, y * sk); }, k); }, { von: [xk - f / 2, -20, hP + 0.2] });
  I.ex.push([xk - 44, 58, 0], [xk, -40, 0]);
}
function r19L(I, P, pts, o) { o = o || {}; return I.line(pts.map(function (q) { return P(q[0], q[1]); }), { d: o.d || 20.2, sw: o.sw || 2.1, st: o.st || IKF.B }); }

/* ===== P61 Schnappfalz profilieren (Dimi 11.11.2026: eigenes Symbol mit der Falzform; Form nach den Herstellerzeichnungen) =====
   Weibliche Seite: Umschlag an der Blechkante, Tasche, Ruecklauf mit nach innen umgelegter Rastkante. Maennliche Seite: 90-Grad-Bord
   mit ausgestellter Nocke (Widerhaken). Lupe: flach, Umschlag, fertige weibliche Seite, zuletzt daneben die maennliche Seite (gelb).
   Die Zwischenform (Umschlag) ist schematisch; die Rollenfolge der Maschine ist nicht belegt. */
var SNF = [[-14.5, 4], [6.6, 4], [7.5, 3.2], [6.6, 2.4], [-5.5, 2.4], [-7.2, 0.8], [-5.5, -0.8], [5, -1.7], [6, -1], [5.3, -0.1], [2.6, 0.6]];
PSYM.P61 = { dt: 0.42, f: function (I) {
  r19KantenBild(I, { N: 7, hP: 4.4, R: 22, sk: 1.3, c: [46, -66, 34], lupe: function (P, k) {
    var st = lt(k, 2) ? 0 : (lt(k, 4) ? 1 : (lt(k, 6) ? 2 : 3));
    if (st === 0) { r19L(I, P, [[-14.5, 4], [11, 4]]); return; }
    if (st === 1) { r19L(I, P, SNF.slice(0, 5).concat([[-5.5, 2.4], [-7, -0.5], [-7, -9]])); return; }
    r19L(I, P, SNF);
    if (st === 3) {
      /* maennliche Seite: Bord mit Nocke */
      r19L(I, P, [[13.4, -9], [13.4, 3], [12.6, 4], [8.6, 4]], { st: IKF.Y, sw: 2.3 });
      I.poly([P(9.4, 3.6), P(11.6, 1.9), P(11.6, 3.6)], IKF.Y, { d: 20.25, sw: 0.8, st: IKF.Y });
    }
  } });
} };

/* ===== P62 Hakenfalz profilieren (eigenes Symbol; Form nach der Herstellerzeichnung „Hakfalz“ der Maschinenseite) =====
   Die Blechkante wird abgesetzt und zum offenen Haken umgelegt; zwei solche Kanten werden ineinandergehakt und zugedrueckt
   (Falzschliesser, eigener Ablauf). Lupe: flach, abgesetzt, Haken (gelb). */
PSYM.P62 = { dt: 0.42, f: function (I) {
  var HK = [[-14, -1], [1, -1], [3.4, 2], [8.6, 2.2], [10.6, 1], [10.9, -0.6], [9.6, -1.9], [4.2, -3.4]];
  r19KantenBild(I, { N: 6, hP: 3.4, f: 6, R: 18, sk: 1.22, c: [42, -58, 30], lupe: function (P, k) {
    var st = lt(k, 2) ? 0 : (lt(k, 4) ? 1 : (lt(k, 6) ? 2 : 3));
    if (st === 0) { r19L(I, P, [[-14, -1], [12, -1]]); return; }
    if (st === 1) { r19L(I, P, [[-14, -1], [1, -1], [3.4, 2], [12.5, 2.2]]); return; }
    r19L(I, P, HK);
    if (st === 3) { r19L(I, P, HK.slice(2), { st: IKF.Y, sw: 2.5, d: 20.3 }); }
  } });
} };

/* ===== P64 Rundfalz am Luftleitblech profilieren (Dimi 11.11.2026: runde Wulst an der Kante, auf die die Luft trifft, etwa 10 mm) =====
   Maschinenseite: Kantenprofil direkt am Luftleitblech, neun Stationen (gezeichnet fuenf). Lupe: die Kante rollt sich zum Rohr. */
PSYM.P64 = { dt: 0.42, f: function (I) {
  r19KantenBild(I, { N: 6, hP: 4.6, f: 8, rund: 2.3, R: 18, sk: 1.25, c: [42, -58, 30], lupe: function (P, k) {
    var st = lt(k, 2) ? 0 : (lt(k, 4) ? 1 : (lt(k, 6) ? 2 : 3)), a = [0, 2.2, 4.3, 2 * Math.PI - 0.25][st], rr = 3.1, x0 = -5, pts = [[-13, 4.2], [x0, 4.2]], j, n = 22;
    /* Bogenlaenge bleibt gleich: der noch flache Rest laeuft tangential weiter */
    for (j = 1; j !== n + 1; j++) { var w = a * j / n; pts.push([x0 + rr * Math.sin(w), 4.2 - rr + rr * Math.cos(w)]); }
    var rest = rr * (2 * Math.PI - 0.25 - a), e = pts[pts.length - 1];
    if (gt(rest, 0.2)) { pts.push([e[0] + Math.cos(a) * rest, e[1] - Math.sin(a) * rest]); }
    r19L(I, P, pts);
    if (st === 3) { r19L(I, P, pts.slice(1), { st: IKF.Y, sw: 2.5, d: 20.3 }); }
  } });
} };

/* ===== P63 S-Cleat profilieren (Dimi 11.11.2026: eigenes Symbol mit dem S-Profil statt des Steckrahmenprofils) =====
   Form nach der Herstellerzeichnung „S-Cleat“ der Maschinenseite: Blechstreifen zum flachen S gelegt, zwei Taschen, die sich nach
   entgegengesetzten Seiten oeffnen, beide Blechkanten nach innen umgeschlagen. Der Streifen laeuft durch die Stationen (neun,
   gezeichnet drei) und kommt als S-Profil heraus. Die Zwischenformen sind schematisch.
   Runde 20 (Dimi 12.11.2026, 01:10: „ok“): Der Standing S-Cleat kommt als zweites Bild dazu, Form nach der Herstellerzeichnung
   „Standing S-Cleat“ derselben Maschinenseite (Breite 28 mm, Hoehe 25 mm, Materialzugabe 136 mm, 12 Stationen): flaches S wie beim
   S-Cleat, an einer Seite ein stehender, doppelt gelegter Schenkel, dessen Ende zwischen die Lagen zurueckgelegt ist.
   Ablauf: erst der S-Cleat (laeuft aus der Maschine, Lupe: flach, aufgestellt, S), dann in der Lupe der Standing S-Cleat
   (breiterer Streifen, S mit noch liegendem Schenkel, Schenkel aufgestellt); Ruhebild: beide Profile in der Lupe, gelb. */
var SCL = { w: 7, h: 2.1 };
function sclQuer(a) {
  /* drei Felder: Mitte liegt, das vordere Feld klappt nach unten unter die Mitte, das hintere nach oben ueber die Mitte (a = 0 flach, PI geschlossen) */
  var S = SCL, w = S.w, c = Math.cos(a), s = Math.sin(a);
  if (gt(a, Math.PI - 0.01)) {
    return [[2, S.h + 0.8], [w - 0.4, S.h + 0.8], [w, S.h + 0.4], [w - 0.4, 0], [-w + 0.5, 0], [-w, S.h * 0.5], [-w + 0.5, S.h], [w - 0.5, S.h], [w, S.h * 1.5], [w - 0.5, 2 * S.h], [-w + 0.4, 2 * S.h], [-w, 2 * S.h - 0.4], [-w + 0.4, S.h + 1.3 - 0.1], [-2, S.h + 1.2]];
  }
  return [[w + 2 * w * c, S.h - 2 * w * s], [w, S.h], [-w, S.h], [-w - 2 * w * c, S.h + 2 * w * s]];
}
/* Querschnitte in der Lupe (x rechts, y unten), beide Profile gleich breit (28 mm): S-Cleat und Standing S-Cleat.
   sscQuer(st): 0 flacher Streifen (laenger als beim S-Cleat: Materialzugabe 136 statt 92 mm), 1 S gelegt, Schenkel liegt noch flach,
   2 fertig: Schenkel steht, doppelt, Ende zwischen die Lagen zurueckgelegt */
var SCQ = [[4, -1.2], [10.4, -1.2], [11.2, -2.1], [10.4, -3], [-10.4, -3], [-11.4, -1.5], [-10.4, 0], [10.4, 0], [11.4, 1.5], [10.4, 3], [-10.4, 3], [-11.2, 2.1], [-10.4, 1.2], [-4, 1.2]];
function sscQuer(st) {
  var S3 = [[-12.2, 5.6], [-11.4, 5], [9.4, 5], [10.4, 3.8], [9.4, 2.6], [-9.2, 2.6], [-10.2, 1.4], [-9.2, 0.2]];
  if (st === 0) { return [[-15, 2.6], [15, 2.6]]; }
  if (st === 1) { return S3.concat([[14.5, 0.2]]); }
  return S3.concat([[7.8, 0.2], [8.6, -0.6], [8.6, -14.5], [9.5, -15.5], [10.4, -14.5], [10.4, 0.8], [9.8, 1.4], [5.8, 1.4]]);
}
PSYM.P63 = { dt: 0.34, f: function (I) {
  var S = SCL, DT = 0.34, r = 4.4, N1 = 6, N = 10, XR = [-30, -17, -4], G = [-50, XR[0], XR[1], XR[2], 4], zo = 2 * S.h + 0.6 + r;
  ikHalten(I, (N - 1) * DT + 1.4);
  /* flacher Streifen laeuft ein (breiter als das fertige Profil); die Umformung zwischen den dicht stehenden Rollen zeigt die Lupe */
  I.box(G[0], -1.7 * S.w, 0, XR[0] - G[0], 3.4 * S.w, 0.9, { d: 1 });
  I.box(XR[0], -S.w, 0, G[4] - XR[0], 2 * S.w, 2 * S.h, { d: 1.1 });
  ikStrich(I, [[G[0], 0, 0.95], [XR[0] - 5, 0, 0.95]], { d: 5, da: '5 6', cls: 'zl', sty: { '--lt': '.7s', '--lz': '6' } });
  each(XR, function (x, i) {
    var b = i === 0 ? 1.7 * S.w + 1 : S.w + 1, z1 = i === 0 ? 0.9 + r + 0.3 : zo;
    I.zyl([x, -b, -r - 0.4], [x, b, -r - 0.4], r, { d: -1 + i * 0.1 });
    I.zyl([x, -b, z1], [x, b, z1], r, { d: 6 + i });
    ikDreh(I, [x, b, z1], [0, 1, 0], r * 0.55, { d: 6.05 + i, sw: 0.9, da: '2 2.5' });
  });
  /* der S-Cleat laeuft in den ersten N1 Bildern aus der Maschine; danach bleibt er liegen (Stirn gelb) */
  var QE = sclQuer(Math.PI);
  I.folge(N, function (k) { var s = Math.min(1, k / (N1 - 1)); r19Band(I, QE, 4, 14 + 30 * s, 9, { stirn: gt(k, N1 - 2) ? 2 : 1, dick: 0.7 }); });
  ikPfeil(I, [-52, 1.7 * S.w + 8, 0], [-38, 1.7 * S.w + 8, 0], { d: 0.5, sw: 1.3 });
  /* Lupe: S-Cleat (flach, aufgestellt, S, gelb), dann Standing S-Cleat (flach, S mit liegendem Schenkel, fertig), zuletzt beide gelb */
  ikLupe(I, [42, -52, 36], 21, N, function (P0, k) {
    function P(x, y) { return P0(x * 1.15, y * 1.15); }
    function PA(x, y) { return P0((x - 1.5) * 0.92, (y - 13) * 0.92); }
    function PB(x, y) { return P0((x + 1.2) * 0.92, (y + 8.6) * 0.92); }
    var st = lt(k, 2) ? 0 : (lt(k, 3) ? 1 : 2), Q, sc;
    if (k === N - 1) {
      r19L(I, PA, SCQ, { sw: 2, st: IKF.Y, d: 20.3 });
      r19L(I, PB, sscQuer(2), { sw: 2, st: IKF.Y, d: 20.3 });
      return;
    }
    if (gt(k, N1 - 1)) { r19L(I, PB, sscQuer(k - N1), { sw: 1.9 }); return; }
    if (st === 2) {
      r19L(I, P, SCQ, { sw: 1.9 });
      if (k === N1 - 1) { r19L(I, P, SCQ, { sw: 2.2, st: IKF.Y, d: 20.3 }); }
      return;
    }
    sc = [0.6, 0.72][st];
    Q = sclQuer([0, 1][st]).map(function (q) { return [-q[0] * sc, (S.h - q[1]) * sc]; });
    r19L(I, P, Q, { sw: 1.9 });
  }, { von: [-10, -2, 6], dv: 9.6 });
  I.ex.push([46, 8, 0], [-52, 1.7 * S.w + 10, 0]);
} };

/* ===== P65 Auflageleisten reinigen (Auflageleistenreiniger TruTool TSC 100; nach den Herstellerangaben der Maschinenseite) =====
   Das Geraet steht mit seiner Grundplatte auf den Auflageleisten der Flachbettlasermaschine und faehrt eine Leiste entlang; die
   Reinigungswerkzeuge unter der Platte greifen die Leiste von beiden Seiten und loesen die Schlacke. Hinter dem Geraet ist die
   Leiste sauber (gelb), davor haengt die Schlacke (dunkel). */
PSYM.P65 = { dt: 0.4, f: function (I) {
  var N = 7, DT = 0.4, YL = [-18, -9, 0, 9, 18], x0 = -40, x1 = 40, hz = 9, zt = 3;
  ikHalten(I, (N - 1) * DT + 1.4);
  /* Auflageleisten mit Zaehnen; alle Leisten ausser der bearbeiteten sind fest */
  function leiste(y, d, xa, xb, f, st) {
    var p = [[xa, y, 0]], x;
    for (x = xa; lt(x, xb - 0.1); x += 4) { p.push([x, y, hz]); p.push([Math.min(x + 2, xb), y, hz + zt]); p.push([Math.min(x + 4, xb), y, hz]); }
    p.push([xb, y, 0]);
    I.poly(p, f || IKF.L, { d: d, sw: 1, st: st });
  }
  function schlacke(y, d, xa, xb) {
    for (var x = xa + 2; lt(x, xb); x += 4) { I.poly(ikKreis([x, y + 0.05, hz + zt - 1.6], [1, 0, 0], [0, 0, 1], 1.5, 8), IKF.G, { d: d, sw: 0.5, st: IKF.G }); I.poly(ikKreis([x + 1.6, y + 0.05, hz - 1.5], [1, 0, 0], [0, 0, 1], 1.1, 8), IKF.G, { d: d, sw: 0.5, st: IKF.G }); }
  }
  each(YL, function (y, i) { if (y !== 0) { leiste(y, i, x0, x1); schlacke(y, i + 0.05, x0, x1); } });
  I.folge(N, function (k, s) {
    var xg = -30 + 50 * s, fertig = k === N - 1;
    /* bearbeitete Leiste: hinter dem Geraet sauber, davor mit Schlacke */
    leiste(0, 2, x0, xg - 4, fertig ? '#FFE27E' : IKF.T, fertig ? '#C99600' : IKF.B);
    leiste(0, 2.01, xg - 4, x1);
    schlacke(0, 2.05, xg + 8, x1);
    /* Geraet: Grundplatte auf den Leisten, Gehaeuse, Buegelgriff, zwei Werkzeuge unter der Platte an der Leiste */
    I.zyl([xg + 2, -1.7, hz - 2], [xg + 2, -1.7, hz + zt + 1], 1.2, { d: 2.3 });
    I.box(xg - 10, -13, hz + zt + 1, 22, 26, 1.2, { d: 6 });
    I.zyl([xg + 2, 1.7, hz - 2], [xg + 2, 1.7, hz + zt + 1], 1.2, { d: 2.6 });
    I.box(xg - 5, -7, hz + zt + 2.2, 14, 14, 12, { d: 6.5, ft: '#3D6A99', fl: '#335A85', fr: '#2B4E74' });
    I.line([[xg - 9, -9, hz + zt + 2.2], [xg - 9, -9, hz + zt + 20], [xg + 4, -9, hz + zt + 20], [xg + 4, 9, hz + zt + 20], [xg - 9, 9, hz + zt + 20], [xg - 9, 9, hz + zt + 2.2]], { d: 7.2, sw: 2.6 });
    ikPfeil(I, [xg + 13, 14, hz + zt + 2], [xg + 22, 14, hz + zt + 2], { d: 7.5, sw: 1.3 });
  });
  I.ex.push([x0, -20, 0], [x1, 20, 0], [0, 0, hz + zt + 24]);
} };

/* ===== P66 Sandwichpaneel trennen (Panel Cutter TruTool TPC 165; nach den Herstellerangaben der Maschinenseite) =====
   Das Geraet liegt mit der Grundplatte auf dem Paneel, das Schwert taucht durch die ganze Dicke (Deckbleche und Daemmkern) und
   trennt in einem Arbeitsgang. Das Paneel ist dick gezeichnet (bis 165 mm), die Schnittfuge am Ende gelb. */
PSYM.P66 = { dt: 0.4, f: function (I) {
  var N = 7, DT = 0.4, L = 34, B = 26, D = 12, ys = 2, KERN = '#F3EEDC';
  ikHalten(I, (N - 1) * DT + 1.4);
  /* Paneel: Deckblech oben und unten, Daemmkern dazwischen; rechts des Schnitts faellt nichts ab, die Fuge waechst */
  function paneel(xa, xb, ya, yb, d) {
    I.poly([[xa, ya, D], [xb, ya, D], [xb, yb, D], [xa, yb, D]], IKF.T, { d: d });
    I.poly([[xa, yb, 0], [xb, yb, 0], [xb, yb, D], [xa, yb, D]], KERN, { d: d + 0.01 });
    I.poly([[xb, ya, 0], [xb, yb, 0], [xb, yb, D], [xb, ya, D]], KERN, { d: d + 0.02 });
    I.line([[xa, yb, 0.6], [xb, yb, 0.6], [xb, ya, 0.6]], { d: d + 0.03, sw: 1.6 });
    I.line([[xa, yb, D - 0.6], [xb, yb, D - 0.6], [xb, ya, D - 0.6]], { d: d + 0.03, sw: 1.6 });
  }
  paneel(-L, L, -B, B, 0);
  I.folge(N, function (k, s) {
    var xg = -L + 8 + (2 * L - 16) * s, fertig = k === N - 1, xe = fertig ? L : xg;
    /* Schnittfuge hinter dem Schwert */
    I.line([[-L, ys, D + 0.05], [xe, ys, D + 0.05]], { d: 1, sw: fertig ? 3 : 2.2, st: fertig ? IKF.Y : IKF.G });
    if (fertig) { I.line([[L, ys, D], [L, ys, 0]], { d: 1.02, sw: 3, st: IKF.Y }); xg = L - 12; }
    /* Schwert (durch das ganze Paneel), Grundplatte, Gehaeuse, zwei Griffe */
    I.box(xg - 9, ys - 6, D + 0.1, 20, 12, 1.1, { d: 5 });
    I.box(xg - 6, ys - 4, D + 1.2, 13, 8, 6, { d: 5.2, ft: '#3A4048', fl: '#2E333A', fr: '#252A30' });
    I.zyl([xg + 1, ys - 4.5, D + 5], [xg + 1, ys + 4.5, D + 5], 3.4, { d: 5.4, f: '#3D6A99', fe: '#335A85' });
    I.line([[xg - 5, ys, D + 7.2], [xg - 8, ys, D + 13], [xg - 2, ys, D + 15]], { d: 5.6, sw: 3 });
    I.line([[xg + 5, ys, D + 7.2], [xg + 9, ys, D + 12]], { d: 5.6, sw: 3 });
    if (!fertig) { ikPfeil(I, [xg + 14, ys + 9, D + 0.2], [xg + 23, ys + 9, D + 0.2], { d: 5.8, sw: 1.3 }); }
  });
  I.ex.push([-L, -B, 0], [L, B, 0], [0, 0, D + 18]);
} };

/* ---------- Prozess-Symbole, Runde 20 der Szene (Dimi 12.11.2026, 01:10; Antworten auf die Fragen der Runde 19) ----------
   Neu: P67 Absaugen und Filtern (Absaug- und Filteranlagen von Sideros, bisher mit dem Symbol des Plasmaschneidens).
   Bausteine aus 60_prozess.js und 61_prozess_sym.js.
   Regel wie dort: Teile in einer Bildfolge (I.folge) bekommen keine Bewegungsklassen. */

/* Rauchwolke in der Bildebene um den Punkt p (3D): drei Kreise; o.f Fuellung, o.st Rand */
function r20Wolke(I, p, r, d, o) {
  o = o || {};
  each([[-0.55, 0.15, 0.75], [0.5, 0.25, 0.7], [0, -0.35, 0.85]], function (q, i) {
    var ring = [], j;
    for (j = 0; j !== 14; j++) { var a = 2 * Math.PI * j / 14; ring.push(S2(p, r * (q[0] + q[2] * Math.cos(a)), r * (q[1] + q[2] * Math.sin(a)))); }
    I.poly(ring, o.f || '#B4BDC8', { d: d + i * 0.001, sw: 0.6, st: o.st || '#7C8A9A' });
  });
}

/* ===== P67 Absaugen und Filtern (Filtergeraet fuer Laserschneidanlagen; nach den Unterlagen von Sideros: Datenblaetter der
   Filtergeraete mit 6 Filterpatronen, Vorstellung der Filtergeraete, Herstellerseite) =====
   Prinzip: Der Rauch der Schneidanlage wird durch ein Rohr (mit Einstellklappe) abgesaugt. Am Filtergeraet durchstroemt er zuerst
   den Funkenabscheider mit Vorfilter aus Metallgewebe, dann die Filterpatronen (liegend eingebaut, hier sechs). Der Motorventilator
   sitzt oben auf dem Geraet, die gereinigte Luft tritt oben aus (in die Halle oder ins Freie). Die Patronen werden selbsttaetig mit
   Druckluftstoessen abgereinigt, der Staub faellt in den fahrbaren Sammelbehaelter unter dem Geraet.
   Schematisch: die Schneidanlage als Tisch mit Blech und Schneidkopf, die Fuehrung des Rohrs, die Anordnung der Patronen (zwei
   Spalten, drei Reihen) und die Lage des Luftaustritts neben dem Motor. Der Rauch ist als Wolken auf seinem Weg gezeichnet (auch vor
   dem Rohr), die gereinigte Luft als gelbe Pfeile. */
PSYM.P67 = { dt: 0.85, f: function (I) {
  var N = 5, DT = 0.85, zt = 15, ts = 1.2, px = -47, py = 3, zr = 8, yr = 30, xa = -40, xr = 32, zh = 36, BLAU = { ft: '#4A78A8', fl: '#3D6A99', fr: '#335A85' };
  ikHalten(I, (N - 1) * DT + 1.6);
  /* Schneidanlage: Tisch, Blech, Schneidkopf mit Strahl, begonnene Schnittfuge */
  I.box(-74, -17, 0, 50, 34, zt, { d: 1, ft: IKF.I });
  I.box(-72, -15, zt, 46, 30, ts, { d: 1.2 });
  I.line([[-62, -8, zt + ts + 0.05], [-36, -8, zt + ts + 0.05], [-36, 3, zt + ts + 0.05], [px, py, zt + ts + 0.05]], { d: 1.3, sw: 1.1 });
  I.zyl([px, py, zt + ts + 9], [px, py, zt + ts + 24], 2.6, { d: 2.2 });
  I.zyl([px, py, zt + ts + 5.5], [px, py, zt + ts + 9], 1.7, { d: 2.15 });
  I.zyl([px, py, zt + ts + 4], [px, py, zt + ts + 5.5], 0.9, { d: 2.14 });
  I.line([[px, py, zt + ts + 4], [px, py, zt + ts]], { st: IKF.Y, sw: 1.2, d: 2.1 });
  I.poly(ikKreis([px, py, zt + ts + 0.07], [1, 0, 0], [0, 1, 0], 0.9, 10), IKF.W, { d: 2.12, sw: 1, st: IKF.Y });
  /* Filtergeraet: Fuesse, fahrbarer Sammelbehaelter, Gehaeuse, Funkenabscheider an der Seite, Motorventilator und Luftaustritt oben */
  each([[20, -13], [44, -13], [20, 11], [44, 11]], function (q, i) { I.box(q[0], q[1], 0, 2, 2, 14, { d: 4 + i * 0.01 }); });
  I.box(24, -9, 2, 18, 18, 10, ext({ d: 4.3 }, BLAU));
  each([27, 39], function (x, i) { I.zyl([x, 9.2, 1.3], [x, 10.4, 1.3], 1.3, { d: 4.35 + i * 0.01, f: IKF.G, fe: IKF.D }); });
  I.box(20, -13, 14, 26, 26, 34, { d: 5 });
  I.box(24, 13, zh - 9, 16, 10, 17, { d: 5.2 });
  I.box(23, -10, 48, 20, 20, 6, { d: 5.5 });
  I.zyl([29, 0, 54], [29, 0, 59.5], 3.3, { d: 5.7, f: BLAU.fl, fe: BLAU.ft });
  I.zyl([38.5, 0, 54], [38.5, 0, 57.5], 3.1, { d: 5.8, hohl: 1 });
  /* Funkenabscheider: Vorfilter aus Metallgewebe (Fenster mit Gitter) */
  var gx = 40.06, ga = zh - 7, gb = zh + 6, gi;
  I.poly([[gx, 14.2, ga], [gx, 21.8, ga], [gx, 21.8, gb], [gx, 14.2, gb]], '#C9D2DC', { d: 5.25, sw: 0.9 });
  for (gi = 1; gi !== 6; gi++) { I.line([[gx, 14.2 + gi * 7.6 / 6, ga], [gx, 14.2 + gi * 7.6 / 6, gb]], { d: 5.26, sw: 0.5, st: '#6E7F94' }); }
  for (gi = 1; gi !== 9; gi++) { I.line([[gx, 14.2, ga + gi * 13 / 9], [gx, 21.8, ga + gi * 13 / 9]], { d: 5.26, sw: 0.5, st: '#6E7F94' }); }
  /* Blick auf die Filterpatronen: liegend, Stirnseiten zur Wartungstuer (sechs Patronen) */
  var fx = 46.06, PAT = [];
  I.poly([[fx, -11, 17.5], [fx, 11, 17.5], [fx, 11, 45], [fx, -11, 45]], '#C9D2DC', { d: 5.9, sw: 1 });
  each([5.3, -5.3], function (y) { each([40, 31.2, 22.4], function (z) { PAT.push([fx + 0.04, y, z]); }); });
  each(PAT, function (c, i) {
    I.poly(ikKreis(c, [0, 1, 0], [0, 0, 1], 3.9, 22), IKF.T, { d: 6 + i * 0.01, sw: 1.1 });
    I.poly(ikKreis([c[0] + 0.02, c[1], c[2]], [0, 1, 0], [0, 0, 1], 2.1, 16), IKF.W, { d: 6.005 + i * 0.01, sw: 0.7 });
  });
  /* Rohr von der Schneidanlage zum Funkenabscheider, mit Einstellklappe (Hebel) */
  var WEG = [[xa, 17, zr], [xa, yr, zr], [xr, yr, zr], [xr, yr, zh], [xr, 23, zh]];
  I.rohrZug(WEG, 2.6, { d: 6.6 });
  I.zyl([-18.7, yr, zr], [-17.3, yr, zr], 3.5, { d: 6.62 });
  I.line([[-18, yr, zr + 3.5], [-18, yr, zr + 6.5], [-15.5, yr, zr + 6.5]], { d: 6.63, sw: 1.8 });
  I.line([[xa, 20, zr], [xa, yr, zr], [xr, yr, zr], [xr, yr, zh]], { d: 6.64, sw: 1, st: '#6E7F94', da: '3 4', cls: 'zl', sty: { '--lt': '.9s', '--lz': '5' } });
  /* Ablauf: 0 Rauch an der Schneidstelle, 1 im Rohr, 2 im Funkenabscheider (Funken bleiben am Vorfilter), 3 an den Filterpatronen,
     Staub faellt nach unten, 4 gereinigte Luft tritt oben aus (gelb), Ruhebild */
  var RW = [[xa, 24, zr + 0.4], [-31, yr, zr + 0.4], [-10, yr, zr + 0.4], [8, yr, zr + 0.4], [24, yr, zr + 0.4], [xr, yr, zr + 10], [xr, yr, zr + 21]];
  I.folge(N, function (k) {
    var i, s;
    r20Wolke(I, [px + 3.2, py - 2.2, zt + ts + 2.6], 2.1, 2.3);
    r20Wolke(I, [px + 5.5, py - 5, zt + ts + 4.6], 1.6, 2.31);
    if (gt(k, 0)) { for (i = 0; i !== (k === 1 ? 4 : RW.length); i++) { r20Wolke(I, RW[i], 1.5, 6.7 + i * 0.01); } }
    if (gt(k, 1)) {
      r20Wolke(I, [gx + 0.05, 18.6, zh + 2.6], 1.7, 5.3);
      for (s = 0; s !== 4; s++) { I.line([[gx + 0.06, 15.2 + s * 1.7, zh - 4.6 + (s % 2) * 1.6], [gx + 0.06, 16 + s * 1.7, zh - 3.4 + (s % 2) * 1.6]], { d: 5.31, st: IKF.Y, sw: 1.5 }); }
    }
    if (gt(k, 2)) {
      r20Wolke(I, [fx + 0.1, 0, 35.6], 1.8, 6.2); r20Wolke(I, [fx + 0.1, 9.4, 26.8], 1.5, 6.21); r20Wolke(I, [fx + 0.1, 0, 26.8], 1.6, 6.22); r20Wolke(I, [fx + 0.1, -9.4, 35.6], 1.5, 6.23);
      /* abgeschiedener Staub faellt in den Sammelbehaelter */
      each([[-7.5, 19.6], [-3, 18.6], [0, 19.8], [3, 18.5], [7.5, 19.4], [-5, 20.6], [5.4, 20.4]], function (q) { I.poly(ikKreis([fx + 0.1, q[0], q[1]], [0, 1, 0], [0, 0, 1], 0.45, 6), IKF.G, { d: 6.3, sw: 0.4, st: IKF.G }); });
    }
    if (gt(k, 3)) {
      each([[38.5, 59, 69], [34.2, 60.5, 66.5], [42.8, 60.5, 66.5]], function (q, j) {
        ikPfeil(I, [q[0], 0, q[1]], [q[0], 0, q[2]], { d: 7 + j * 0.02, sw: j ? 1.8 : 2.6, st: IKF.Y, q: [1, 1, 0], L: j ? 3.4 : 4.6, W: j ? 1.9 : 2.6 });
      });
    }
  });
  I.ex.push([-76, 17, 0], [46, 13, 0], [38.5, 0, 71], [-74, -17, zt + 26]);
} };

/* ---------- 3D-Ansicht: drehen und zoomen (WebGL 2) ----------
   Erfassung: szene() mit D3 = true liefert alle Seiten als 3D-Flaechen und Linien (siehe 10_kern.js).
   Darstellung mit Tiefenpuffer, damit nichts falsch vor oder hinter etwas anderem liegt.
   Parallelprojektion wie die Isometrie, gleiche Farben und Linien. Das Licht dreht mit der Blickrichtung
   um die Hochachse, so sieht jede Ansicht aus wie die Zeichnung. Umrisse gekruemmter Flaechen bestimmt
   der Shader je Ansicht (Kante zwischen zugewandter und abgewandter Zelle).
   Regel: auch in den Shadern keine Zeichen Kleiner, Groesser, Kaufmanns-Und. */
var D3G = null, D3B = null;
var SK = C30 * KS * Math.SQRT2; /* Isometrie: Bildeinheiten je mm */
var ISO_AZ = Math.PI / 4, ISO_EL = Math.atan(1 / Math.SQRT2);
var EL_MIN = -89.5 * Math.PI / 180, EL_MAX = 89.5 * Math.PI / 180;
function erfassen3() {
  if (D3G) { return D3G; }
  var aIT = IT, aSEQ = SEQ, aF = FLOWS, aM = MARKEN, aZ = ZONEN, aP = PIDNOW;
  IT = []; SEQ = 0; FLOWS = []; MARKEN = []; ZONEN = []; PIDNOW = null;
  D3 = true;
  try { szene(); } finally { D3 = false; }
  D3G = { it: IT, fl: FLOWS, mk: MARKEN, zo: ZONEN };
  IT = aIT; SEQ = aSEQ; FLOWS = aF; MARKEN = aM; ZONEN = aZ; PIDNOW = aP;
  return D3G;
}
/* Zusammenhaengende Stuecke je Bauteil (3D-Huellquader beruehren sich) */
function gruppen3(it) {
  var nach = {}, G = [], pid;
  each(it, function (o) {
    if (!o.pid) { return; }
    var P = o.t === 't' ? [o.p3] : o.p3, b = [1e9, 1e9, 1e9, -1e9, -1e9, -1e9];
    each(P, function (p) { for (var k = 0; k !== 3; k++) { b[k] = Math.min(b[k], p[k]); b[k + 3] = Math.max(b[k + 3], p[k]); } });
    o.bb3 = b; (nach[o.pid] = nach[o.pid] || []).push(o);
  });
  function teilen(L) {
    var P = [], i, j, k;
    for (i = 0; i !== L.length; i++) { P.push(i); }
    var wz = function (x) { while (P[x] !== x) { P[x] = P[P[x]]; x = P[x]; } return x; };
    for (i = 0; i !== L.length; i++) {
      for (j = i + 1; j !== L.length; j++) {
        if (gt(L[j].bb3[0], L[i].bb3[3] + 3)) { break; }
        var ok = true;
        for (k = 1; k !== 3; k++) { if (gt(L[j].bb3[k], L[i].bb3[k + 3] + 3)) { ok = false; } if (gt(L[i].bb3[k], L[j].bb3[k + 3] + 3)) { ok = false; } }
        if (ok) { var a = wz(i), c = wz(j); if (a !== c) { P[a] = c; } }
      }
    }
    var map = {};
    for (i = 0; i !== L.length; i++) {
      var w = wz(i);
      if (map[w] === undefined) { map[w] = G.length; G.push({ pid: L[i].pid, bb: [1e9, 1e9, 1e9, -1e9, -1e9, -1e9] }); }
      var g = G[map[w]], bb = L[i].bb3; L[i].g3 = map[w];
      for (k = 0; k !== 3; k++) { g.bb[k] = Math.min(g.bb[k], bb[k]); g.bb[k + 3] = Math.max(g.bb[k + 3], bb[k + 3]); }
    }
  }
  for (pid in nach) { teilen(nach[pid].slice().sort(function (a, b) { return a.bb3[0] - b.bb3[0]; })); }
  return G;
}
/* Polygon in Dreiecke (Ohrenschnitt in der Ebene der Flaeche), Indizes in P */
function imDreieck(p, a, b, c, sg) {
  var d1 = ((b[0] - a[0]) * (p[1] - a[1]) - (b[1] - a[1]) * (p[0] - a[0])) * sg;
  var d2 = ((c[0] - b[0]) * (p[1] - b[1]) - (c[1] - b[1]) * (p[0] - b[0])) * sg;
  var d3 = ((a[0] - c[0]) * (p[1] - c[1]) - (a[1] - c[1]) * (p[0] - c[0])) * sg;
  return !lt(Math.min(d1, d2, d3), -1e-9);
}
function dreiecke(P, n) {
  var Q = [], i, j;
  for (i = 0; i !== P.length; i++) { if (gt(len(sb(P[(i + 1) % P.length], P[i])), 1e-6)) { Q.push(i); } }
  if (lt(Q.length, 3)) { return []; }
  if (Q.length === 3) { return [[Q[0], Q[1], Q[2]]]; }
  var ax = Math.abs(n[0]), ay = Math.abs(n[1]), az = Math.abs(n[2]), u = 0, v = 1;
  if (gt(ax, ay)) { if (gt(ax, az)) { u = 1; v = 2; } } else if (gt(ay, az)) { u = 0; v = 2; }
  var pt = Q.map(function (k) { return [P[k][u], P[k][v]]; }), A = 0;
  for (i = 0; i !== pt.length; i++) { var p = pt[i], q = pt[(i + 1) % pt.length]; A += p[0] * q[1] - q[0] * p[1]; }
  var sg = gt(A, 0) ? 1 : -1, idx = Q.slice(), tri = [];
  while (gt(idx.length, 3)) {
    var gef = false;
    for (i = 0; i !== idx.length; i++) {
      var i0 = (i + idx.length - 1) % idx.length, i2 = (i + 1) % idx.length, a = pt[i0], b = pt[i], c = pt[i2];
      var kr = ((b[0] - a[0]) * (c[1] - a[1]) - (b[1] - a[1]) * (c[0] - a[0])) * sg;
      if (!gt(kr, 1e-9)) { continue; }
      var drin = false;
      for (j = 0; j !== idx.length; j++) { if (j !== i0) { if (j !== i) { if (j !== i2) { if (imDreieck(pt[j], a, b, c, sg)) { drin = true; break; } } } } }
      if (drin) { continue; }
      tri.push([idx[i0], idx[i], idx[i2]]); idx.splice(i, 1); pt.splice(i, 1); gef = true; break;
    }
    if (!gef) { for (i = 1; i !== idx.length - 1; i++) { tri.push([idx[0], idx[i], idx[i + 1]]); } return tri; }
  }
  tri.push([idx[0], idx[1], idx[2]]);
  return tri;
}
/* Wachsende Puffer */
function Wachs(st) { this.st = st; this.n = 0; this.u8 = null; this.neu(4096); }
Wachs.prototype.neu = function (c) {
  var nb = new ArrayBuffer(c * this.st);
  if (this.u8) { new Uint8Array(nb).set(this.u8.subarray(0, this.n * this.st)); }
  this.cap = c; this.f = new Float32Array(nb); this.i8 = new Int8Array(nb); this.u8 = new Uint8Array(nb); this.i16 = new Int16Array(nb);
};
Wachs.prototype.platz = function (k) { if (gt(this.n + k, this.cap)) { var c = this.cap * 2; while (gt(this.n + k, c)) { c = c * 2; } this.neu(c); } };
Wachs.prototype.daten = function () { return this.u8.subarray(0, this.n * this.st); };
function Liste32(fl) { this.n = 0; this.a = fl ? new Float32Array(8192) : new Uint32Array(8192); this.fl = fl; }
Liste32.prototype.add = function (v) {
  if (this.n === this.a.length) { var b = this.fl ? new Float32Array(this.n * 2) : new Uint32Array(this.n * 2); b.set(this.a); this.a = b; }
  this.a[this.n] = v; this.n = this.n + 1;
};
Liste32.prototype.add3 = function (p) { this.add(p[0]); this.add(p[1]); this.add(p[2]); };
Liste32.prototype.daten = function () { return this.a.subarray(0, this.n); };
/* Materialien: Index in die Farbtabelle; 20 feste Farbe, 21 Lochblech, 22 Mineralwolle */
var MATK = ['m', 'a', 'w', 'f', 'k', 'x', 'h', 'd', 'r', 'g', 'i', 'y', 'z'], MATI = {};
each(MATK, function (k, i) { MATI[k] = i; });
var INNEN3 = ['#A6B3C2', '#9AA8B8', '#8E9DAE', '#8191A3']; /* Innenseite (Blick in ein offenes Ende) */
function deck(o) { return Math.round(255 * ((o.op === undefined || o.op === null) ? 1 : o.op)); }
function farbe3(o) {
  var a = deck(o), c = o.c;
  if (c === 'url(#wsz-loch)') { return { mat: 21, col: [211, 218, 226, a] }; }
  if (c === 'url(#wsz-wolle)') { return { mat: 22, col: [237, 203, 98, a] }; }
  if (c) { if (c.charAt(0) === '#') { var q = rgb(c); return { mat: 20, col: [q[0], q[1], q[2], a] }; } }
  var mi = MATI[o.m]; if (mi === undefined) { mi = 0; }
  return { mat: mi, col: [0, 0, 0, a] };
}
function flaeche3(o, W, I, Z, zc) {
  var P = o.p3, n = nz(o.n), tri = dreiecke(P, n);
  if (!tri.length) { return; }
  var fb = farbe3(o), id = (o.g3 === undefined ? -1 : o.g3) + 1, mode = o.two ? 1 : (o.cull ? 2 : 0), i;
  W.platz(P.length);
  var base = W.n;
  for (i = 0; i !== P.length; i++) {
    var v = W.n, b = v * 24, f = v * 6, p = P[i];
    W.f[f] = p[0]; W.f[f + 1] = p[1]; W.f[f + 2] = p[2];
    W.i8[b + 12] = Math.round(n[0] * 127); W.i8[b + 13] = Math.round(n[1] * 127); W.i8[b + 14] = Math.round(n[2] * 127); W.i8[b + 15] = mode;
    W.u8[b + 16] = fb.col[0]; W.u8[b + 17] = fb.col[1]; W.u8[b + 18] = fb.col[2]; W.u8[b + 19] = fb.col[3];
    W.u8[b + 20] = fb.mat; W.u8[b + 21] = 0; W.u8[b + 22] = id % 256; W.u8[b + 23] = Math.floor(id / 256);
    W.n = v + 1;
    if (Z) { Z.add3(zc); }
  }
  each(tri, function (t) { I.add(base + t[0]); I.add(base + t[1]); I.add(base + t[2]); });
}
function linie3(o, W, Z, zc) {
  var P = o.p3; if (lt(P.length, 2)) { return; }
  var q = rgb(o.s.charAt(0) === '#' ? o.s : NAVY), a = deck(o), w = Math.max(1, Math.min(255, Math.round((o.w || 1) * 40)));
  var cap = o.lc === 'butt' ? 0 : 1, id = (o.g3 === undefined ? -1 : o.g3) + 1, nA = o.nA || [0, 0, 0], nB = o.nB || [0, 0, 0];
  for (var i = 0; i !== P.length - 1; i++) {
    var A = P[i], B = P[i + 1];
    if (!gt(len(sb(B, A)), 0.01)) { continue; }
    W.platz(1);
    var s = W.n, f = s * 12, h = s * 24, b = s * 48;
    W.f[f] = A[0]; W.f[f + 1] = A[1]; W.f[f + 2] = A[2]; W.f[f + 3] = B[0]; W.f[f + 4] = B[1]; W.f[f + 5] = B[2];
    W.i16[h + 12] = Math.round(nA[0] * 32767); W.i16[h + 13] = Math.round(nA[1] * 32767); W.i16[h + 14] = Math.round(nA[2] * 32767); W.i16[h + 15] = 0;
    W.i16[h + 16] = Math.round(nB[0] * 32767); W.i16[h + 17] = Math.round(nB[1] * 32767); W.i16[h + 18] = Math.round(nB[2] * 32767); W.i16[h + 19] = 0;
    W.u8[b + 40] = q[0]; W.u8[b + 41] = q[1]; W.u8[b + 42] = q[2]; W.u8[b + 43] = a;
    W.u8[b + 44] = w; W.u8[b + 45] = cap; W.u8[b + 46] = id % 256; W.u8[b + 47] = Math.floor(id / 256);
    W.n = s + 1;
    if (Z) { Z.add3(zc); }
  }
}
/* Klasse einer Flaeche: op deckend, sd Gehaeuse Schalldaempfer (wird beim Oeffnen durchsichtig),
   gl durchscheinend (Wand), tr nur Trefferflaeche (unsichtbar) */
function klasse3(o) {
  if (o.c === 'transparent') { return 'tr'; }
  if (o.cls === 'sdw') { return 'sd'; }
  if (lt(deck(o), 254)) { return 'gl'; }
  return 'op';
}
function gruppenMitte(g) { var b = g.bb; return [(b[0] + b[3]) / 2, (b[1] + b[4]) / 2, (b[2] + b[5]) / 2]; }
function bauen3() {
  if (D3B) { return D3B; }
  var t0 = window.performance ? window.performance.now() : 0;
  var S = erfassen3(), GR = gruppen3(S.it), F = {}, L = { op: new Wachs(48), sd: new Wachs(48) }, TX = [], nach = {}, nf = 0, nl = 0;
  each(['op', 'sd', 'gl', 'tr'], function (k) { F[k] = { W: new Wachs(24), I: new Liste32(false) }; });
  each(S.it, function (o) {
    if (o.pid) { (nach[o.pid] = nach[o.pid] || []).push(o); }
    if (o.t === 'f') { var k = klasse3(o); flaeche3(o, F[k].W, F[k].I); nf++; }
    else if (o.t === 'l') { linie3(o, o.cls === 'sdw' ? L.sd : L.op); nl++; }
    else if (o.t === 't') { TX.push(o); }
  });
  /* Punkte fuer das Einpassen: Ecken der Stuecke und Luftwege */
  var PE = [], bb = [1e9, 1e9, 1e9, -1e9, -1e9, -1e9];
  each(GR, function (g) {
    if (BAU.indexOf(g.pid) !== -1) { if (g.pid === 'dach') { return; } }
    var b = g.bb;
    for (var m = 0; m !== 8; m++) { var p = [b[m % 2 ? 3 : 0], b[Math.floor(m / 2) % 2 ? 4 : 1], b[Math.floor(m / 4) ? 5 : 2]]; PE.push(p); }
    for (var k = 0; k !== 3; k++) { bb[k] = Math.min(bb[k], b[k]); bb[k + 3] = Math.max(bb[k + 3], b[k + 3]); }
  });
  each(S.fl, function (f) { each(f.p, function (p) { PE.push(p); }); });
  var dg = len([bb[3] - bb[0], bb[4] - bb[1], bb[5] - bb[2]]);
  D3B = { S: S, GR: GR, F: F, L: L, TX: TX, nach: nach, PE: PE, bb: bb, RZ: dg * 1.1 + 2000, nf: nf, nl: nl,
    ms: window.performance ? Math.round(window.performance.now() - t0) : 0 };
  return D3B;
}
function dreiMoeglich() {
  if (DREI_OK !== null) { return DREI_OK; }
  try { var c = document.createElement('canvas'); DREI_OK = !!(c.getContext('webgl2')); } catch (e) { DREI_OK = false; }
  return DREI_OK;
}
var DREI_OK = null;
/* ---------- Shader ---------- */
var VS_F = [
  '#version 300 es', 'precision highp float;',
  'in vec3 aP; in vec4 aN; in vec4 aC; in vec4 aM; in vec3 aG;',
  'uniform mat4 uM; uniform vec3 uV; uniform vec2 uRz; uniform float uS; uniform vec3 uPal[56];',
  'out vec3 vF; out vec3 vB; out vec3 vW; out float vS;',
  'flat out vec3 vN; flat out float vMat; flat out float vMode; flat out float vA; flat out vec2 vId;',
  'vec3 schatt(int m, vec3 n) {',
  '  vec3 p = max(n, vec3(0.0)); vec3 q = max(-n, vec3(0.0));',
  '  float wR = p.x * p.x; float wL = p.y * p.y; float wT = p.z * p.z; float wI = q.x * q.x + q.y * q.y + q.z * q.z * 1.4;',
  '  float s = max(wR + wL + wT + wI, 0.000001); int b = m * 4;',
  '  return (uPal[b] * wT + uPal[b + 1] * wL + uPal[b + 2] * wR + uPal[b + 3] * wI) / s;',
  '}',
  'void main() {',
  '  vec3 w = aG + (aP - aG) * uS;',
  '  gl_Position = uM * vec4(w, 1.0);',
  '  vec3 n = normalize(aN.xyz + vec3(0.0, 0.0, 0.000001));',
  '  vec3 nl = vec3(uRz.x * n.x - uRz.y * n.y, uRz.y * n.x + uRz.x * n.y, n.z);',
  '  float mat = aM.x; float mode = floor(aN.w * 127.0 + 0.5); int mi = int(min(mat, 12.0) + 0.5);',
  '  vec3 cf = schatt(mi, nl);',
  '  vec3 cb = mix(schatt(13, -nl), schatt(mi, -nl), step(0.5, mode) * (1.0 - step(1.5, mode)));',
  '  float fx = step(19.5, mat);',
  '  vF = mix(cf, aC.rgb, fx); vB = mix(cb, aC.rgb, fx); vW = aP; vS = dot(n, uV);',
  '  vN = n; vMat = mat; vMode = mode; vA = aC.a; vId = aM.zw;',
  '}'].join('\n');
var FS_F = [
  '#version 300 es', 'precision highp float;',
  'in vec3 vF; in vec3 vB; in vec3 vW; in float vS;',
  'flat in vec3 vN; flat in float vMat; flat in float vMode; flat in float vA; flat in vec2 vId;',
  'uniform float uDim; uniform float uAl; uniform float uPass;',
  'out vec4 o;',
  'vec2 ebene(vec3 w, vec3 n) {',
  '  vec3 a = abs(n); float sx = step(max(a.y, a.z), a.x); float sy = (1.0 - sx) * step(a.z, a.y); float sz = 1.0 - sx - sy;',
  '  return sx * w.yz + sy * w.xz + sz * w.xy;',
  '}',
  'vec3 loch(vec2 uv) {',
  '  vec2 g = uv / 26.0; float d = length(fract(g) - 0.5) * 26.0; float fw = max(fwidth(d), 0.0001);',
  '  float k = smoothstep(6.2 - fw, 6.2 + fw, d);',
  '  vec3 b = vec3(0.827, 0.855, 0.886); vec3 h = vec3(0.529, 0.584, 0.651);',
  '  float fein = clamp(length(fwidth(g)) * 2.5 - 0.5, 0.0, 1.0);',
  '  return mix(mix(h, b, k), mix(b, h, 0.18), fein);',
  '}',
  'vec3 wolle(vec2 uv) {',
  '  float x = uv.x * 6.2831853 / 60.0;',
  '  float v1 = mod(uv.y - 12.0 - 4.0 * sin(x + 0.6) + 20.0, 40.0) - 20.0;',
  '  float v2 = mod(uv.y - 31.0 - 4.0 * sin(x + 2.3) + 20.0, 40.0) - 20.0;',
  '  float d = min(abs(v1), abs(v2)); float fw = max(fwidth(uv.y), 0.0001);',
  '  float k = 1.0 - smoothstep(1.75 - fw, 1.75 + fw, d);',
  '  vec3 b = vec3(0.929, 0.796, 0.384); vec3 l = vec3(0.788, 0.643, 0.227);',
  '  float fein = clamp(fwidth(uv.y) / 6.0 - 0.3, 0.0, 1.0);',
  '  return mix(mix(b, l, k), mix(b, l, 0.12), fein);',
  '}',
  'void main() {',
  '  float fr = step(0.0, vS);',
  '  if (vMode * (1.0 - fr) == 2.0) { discard; }',
  '  if (uPass == 1.0) { if (fr == 1.0) { discard; } }',
  '  if (uPass == 2.0) { if (fr == 0.0) { discard; } }',
  '  vec3 c = mix(vB, vF, fr);',
  '  if (vMat == 21.0) { c = loch(ebene(vW, vN)); }',
  '  if (vMat == 22.0) { c = wolle(ebene(vW, vN)); }',
  '  float g = dot(c, vec3(0.299, 0.587, 0.114));',
  '  c = mix(c, vec3(g), uDim); c = mix(c, vec3(1.0), uDim * 0.72);',
  '  float a = vA * uAl;',
  '  o = vec4(c * a, a);',
  '}'].join('\n');
var FS_FID = [
  '#version 300 es', 'precision highp float;',
  'in vec3 vF; in vec3 vB; in vec3 vW; in float vS;',
  'flat in vec3 vN; flat in float vMat; flat in float vMode; flat in float vA; flat in vec2 vId;',
  'out vec4 o;',
  'void main() {',
  '  float fr = step(0.0, vS);',
  '  if (vMode * (1.0 - fr) == 2.0) { discard; }',
  '  o = vec4(vId.x / 255.0, vId.y / 255.0, 0.0, 1.0);',
  '}'].join('\n');
var VS_L = [
  '#version 300 es', 'precision highp float;',
  'in vec2 aT; in vec3 aA; in vec3 aB; in vec4 aNA; in vec4 aNB; in vec4 aC; in vec4 aX; in vec3 aG;',
  'uniform mat4 uM; uniform vec3 uV; uniform vec2 uPx; uniform float uWk; uniform float uWmin; uniform float uS; uniform float uDim; uniform float uAl; uniform float uBias;',
  'out vec4 vC; flat out vec2 vId;',
  'void main() {',
  '  float sil = step(dot(aNA.xyz, uV) * dot(aNB.xyz, uV), 0.0);',
  '  float kand = step(0.0001, dot(aNA.xyz, aNA.xyz));',
  '  vec4 a = uM * vec4(aG + (aA - aG) * uS, 1.0); vec4 b = uM * vec4(aG + (aB - aG) * uS, 1.0);',
  '  vec2 d = (b.xy - a.xy) / uPx; float L = length(d); vec2 t = d / max(L, 0.0001); vec2 nn = vec2(-t.y, t.x);',
  '  float w = max(aX.x / 40.0 * uWk, uWmin) * sil;',
  '  vec3 nf = mix(aNB.xyz, aNA.xyz, step(0.0, dot(aNA.xyz, uV)));',
  '  vec2 sd = (uM * vec4(nf, 0.0)).xy / uPx;',
  '  float seite = sign(dot(sd, nn)) * kand;',
  '  float e = min(0.5 * w * aX.y / max(L, 0.0001), 0.5);',
  '  vec4 p = mix(a, b, aT.x + (aT.x * 2.0 - 1.0) * e);',
  '  p.xy = p.xy + nn * (aT.y + seite) * 0.5 * w * uPx;',
  '  p.z = p.z - uBias;',
  '  gl_Position = p;',
  '  vec3 c = aC.rgb; float g = dot(c, vec3(0.299, 0.587, 0.114));',
  '  c = mix(c, vec3(g), uDim); c = mix(c, vec3(1.0), uDim * 0.72);',
  '  vC = vec4(c, aC.a * uAl); vId = aX.zw;',
  '}'].join('\n');
var FS_L = ['#version 300 es', 'precision highp float;', 'in vec4 vC; flat in vec2 vId; out vec4 o;', 'void main() { o = vec4(vC.rgb * vC.a, vC.a); }'].join('\n');
var FS_LID = ['#version 300 es', 'precision highp float;', 'in vec4 vC; flat in vec2 vId; out vec4 o;', 'void main() { o = vec4(vId.x / 255.0, vId.y / 255.0, 0.0, 1.0); }'].join('\n');
var VS_T = [
  '#version 300 es', 'precision highp float;',
  'in vec3 aP; in vec2 aU; in vec4 aK;',
  'uniform mat4 uM; uniform vec3 uG; uniform float uS;',
  'out vec2 vU; out vec4 vK;',
  'void main() { gl_Position = uM * vec4(uG + (aP - uG) * uS, 1.0); vU = aU; vK = aK; }'].join('\n');
var FS_T = [
  '#version 300 es', 'precision highp float;',
  'in vec2 vU; in vec4 vK; uniform sampler2D uTex; uniform float uDim; out vec4 o;',
  'void main() {',
  '  float a = texture(uTex, vU).a; vec3 c = vK.rgb; float g = dot(c, vec3(0.299, 0.587, 0.114));',
  '  c = mix(c, vec3(g), uDim); c = mix(c, vec3(1.0), uDim * 0.72);',
  '  o = vec4(c * a, a);',
  '}'].join('\n');
function glShader(gl, typ, src) {
  var s = gl.createShader(typ); gl.shaderSource(s, src); gl.compileShader(s);
  if (!gl.getShaderParameter(s, gl.COMPILE_STATUS)) { throw new Error('Shader: ' + gl.getShaderInfoLog(s)); }
  return s;
}
function glProg(gl, vs, fs, attr) {
  var p = gl.createProgram(); gl.attachShader(p, vs); gl.attachShader(p, fs);
  each(attr, function (a, i) { gl.bindAttribLocation(p, i, a); });
  gl.linkProgram(p);
  if (!gl.getProgramParameter(p, gl.LINK_STATUS)) { throw new Error('Programm: ' + gl.getProgramInfoLog(p)); }
  var u = {}, n = gl.getProgramParameter(p, gl.ACTIVE_UNIFORMS);
  for (var i = 0; i !== n; i++) { var inf = gl.getActiveUniform(p, i); u[inf.name.replace('[0]', '')] = gl.getUniformLocation(p, inf.name); }
  return { p: p, u: u };
}
function glPuffer(gl, typ, daten) { var b = gl.createBuffer(); gl.bindBuffer(typ, b); gl.bufferData(typ, daten, gl.STATIC_DRAW); return b; }
function vaoF(gl, vb, ib, zb) {
  var v = gl.createVertexArray(); gl.bindVertexArray(v);
  gl.bindBuffer(gl.ARRAY_BUFFER, vb);
  gl.enableVertexAttribArray(0); gl.vertexAttribPointer(0, 3, gl.FLOAT, false, 24, 0);
  gl.enableVertexAttribArray(1); gl.vertexAttribPointer(1, 4, gl.BYTE, true, 24, 12);
  gl.enableVertexAttribArray(2); gl.vertexAttribPointer(2, 4, gl.UNSIGNED_BYTE, true, 24, 16);
  gl.enableVertexAttribArray(3); gl.vertexAttribPointer(3, 4, gl.UNSIGNED_BYTE, false, 24, 20);
  if (zb) { gl.bindBuffer(gl.ARRAY_BUFFER, zb); gl.enableVertexAttribArray(4); gl.vertexAttribPointer(4, 3, gl.FLOAT, false, 12, 0); } else { gl.disableVertexAttribArray(4); }
  gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, ib);
  gl.bindVertexArray(null);
  return v;
}
function vaoL(gl, tpl, tib, lb, zb) {
  var v = gl.createVertexArray(); gl.bindVertexArray(v);
  gl.bindBuffer(gl.ARRAY_BUFFER, tpl); gl.enableVertexAttribArray(0); gl.vertexAttribPointer(0, 2, gl.FLOAT, false, 8, 0); gl.vertexAttribDivisor(0, 0);
  gl.bindBuffer(gl.ARRAY_BUFFER, lb);
  each([[1, 3, gl.FLOAT, false, 0], [2, 3, gl.FLOAT, false, 12], [3, 4, gl.SHORT, true, 24], [4, 4, gl.SHORT, true, 32], [5, 4, gl.UNSIGNED_BYTE, true, 40], [6, 4, gl.UNSIGNED_BYTE, false, 44]], function (a) {
    gl.enableVertexAttribArray(a[0]); gl.vertexAttribPointer(a[0], a[1], a[2], a[3], 48, a[4]); gl.vertexAttribDivisor(a[0], 1);
  });
  if (zb) { gl.bindBuffer(gl.ARRAY_BUFFER, zb); gl.enableVertexAttribArray(7); gl.vertexAttribPointer(7, 3, gl.FLOAT, false, 12, 0); gl.vertexAttribDivisor(7, 1); } else { gl.disableVertexAttribArray(7); }
  gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, tib);
  gl.bindVertexArray(null);
  return v;
}
/* Beschriftungen auf Flaechen (z. B. Abschnitte am Zentralgeraet) als Textur.
   Fable Runde 17 (Dimi 11.11.2026: Logo und Beschriftungen scharf): Atlas 2048 px breit, Zeilen zu 256 px (Schrift 176 px),
   das ganze Logo ueber die volle Breite (2.024 x 640 px fuer 1.000 mm). Die Textur hat nur einen Kanal (Deckung), sie braucht
   so viel Speicher wie die bisherige mit 1.024 px und vier Kanaelen. Schraeg gesehen bleibt die Schrift durch anisotrope
   Filterung lesbar (wenn das Geraet sie anbietet). */
function textAtlas(gl, TX) {
  var AW = 2048, ZH = 256, Y0 = [], LH = [], rows = 0, H = ZH;
  each(TX, function (o) {
    var lh = 0, n = 1;
    if (o.lg) { var F0 = logoForm(o.sy); lh = Math.floor(Math.min(3 * ZH - 16, (AW - 24) * F0.h / F0.w)); n = Math.ceil((lh + 16) / ZH); }
    Y0.push(rows); LH.push(lh); rows += n;
  });
  rows = Math.max(1, rows);
  while (lt(H, rows * ZH)) { H = H * 2; }
  var c = document.createElement('canvas'); c.width = AW; c.height = H;
  var x = c.getContext('2d'), Q = [], fpx = 176;
  x.clearRect(0, 0, AW, H); x.fillStyle = '#FFFFFF'; x.textBaseline = 'alphabetic'; x.textAlign = 'left';
  each(TX, function (o, i) {
    /* Logo (33_logo.js): Viereck in der Flaeche um die Mitte o.p3 */
    if (o.lg) {
      var LF = logoForm(o.sy), ly0 = Y0[i] * ZH, lhp = LH[i], lsk = lhp / LF.h, lw = Math.round(LF.w * lsk);
      x.save(); x.translate(12 - LF.x * lsk, ly0 + 8 - LF.y * lsk); x.scale(lsk, lsk);
      var lpth = new Path2D(LF.d);
      if (o.lgh) { x.lineWidth = 9 * lhp / 112 / lsk; x.lineJoin = 'round'; x.strokeStyle = '#FFFFFF'; x.stroke(lpth); }
      x.fill(lpth, 'evenodd'); x.restore();
      var LD = [1, 0, 0], LU = [0, 0, 1], LN = [0, 1, 0];
      if (o.m === 'x') { LD = [0, -1, 0]; LN = [1, 0, 0]; }
      if (o.m === 't') { LU = [0, -1, 0]; LN = [0, 0, 1]; }
      var lb2 = o.lb / 2, lh2 = o.lb * LF.h / LF.w / 2, lp = o.p3;
      var LP = function (a, z) { return ad(ad(lp, mu(LD, a)), mu(LU, z)); };
      Q.push({ o: o, n: LN, ecken: [LP(-lb2, -lh2), LP(lb2, -lh2), LP(lb2, lh2), LP(-lb2, lh2)],
        uv: [[12 / AW, (ly0 + 8 + lhp) / H], [(12 + lw) / AW, (ly0 + 8 + lhp) / H], [(12 + lw) / AW, (ly0 + 8) / H], [12 / AW, (ly0 + 8) / H]] });
      return;
    }
    x.font = 'bold ' + fpx + 'px Arial, Helvetica, sans-serif';
    var w = Math.min(AW - 34, x.measureText(o.s).width), y0 = Y0[i] * ZH;
    x.fillText(o.s, 12, y0 + 200, AW - 34);
    var k = o.fs / fpx, tw = w * k, l = 12 * k, ww = (w + 24) * k, b = 56 * k, hh = ZH * k;
    var x0 = o.an === 'middle' ? -tw / 2 - l : (o.an === 'end' ? -tw - l : -l);
    var D = [1, 0, 0], U = [0, 0, 1], N = [0, 1, 0];
    if (o.m === 'x') { D = [0, -1, 0]; N = [1, 0, 0]; }
    if (o.m === 't') { U = [0, -1, 0]; N = [0, 0, 1]; }
    var p = o.p3;
    function P(a, z) { return ad(ad(p, mu(D, a)), mu(U, z)); }
    Q.push({ o: o, n: N, ecken: [P(x0, -b), P(x0 + ww, -b), P(x0 + ww, -b + hh), P(x0, -b + hh)], uv: [[0, (y0 + ZH) / H], [(w + 24) / AW, (y0 + ZH) / H], [(w + 24) / AW, y0 / H], [0, y0 / H]] });
  });
  var tex = gl.createTexture();
  gl.bindTexture(gl.TEXTURE_2D, tex);
  gl.pixelStorei(gl.UNPACK_ALIGNMENT, 1);
  gl.texImage2D(gl.TEXTURE_2D, 0, gl.ALPHA, gl.ALPHA, gl.UNSIGNED_BYTE, c);
  gl.generateMipmap(gl.TEXTURE_2D);
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_LINEAR);
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
  var ani = gl.getExtension('EXT_texture_filter_anisotropic');
  if (ani) { gl.texParameterf(gl.TEXTURE_2D, ani.TEXTURE_MAX_ANISOTROPY_EXT, Math.min(8, gl.getParameter(ani.MAX_TEXTURE_MAX_ANISOTROPY_EXT) || 1)); }
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
  /* je Beschriftung 4 Ecken: Lage (3), Texturpunkt (2), Farbe (4 Byte) */
  var buf = new ArrayBuffer(Q.length * 4 * 24), f = new Float32Array(buf), u8 = new Uint8Array(buf), I = new Uint16Array(Q.length * 6);
  each(Q, function (q, i) {
    var col = rgb(q.o.fc || '#5C6670');
    for (var k = 0; k !== 4; k++) {
      var v = i * 4 + k, e = q.ecken[k];
      f[v * 6] = e[0]; f[v * 6 + 1] = e[1]; f[v * 6 + 2] = e[2]; f[v * 6 + 3] = q.uv[k][0]; f[v * 6 + 4] = q.uv[k][1];
      u8[v * 24 + 20] = col[0]; u8[v * 24 + 21] = col[1]; u8[v * 24 + 22] = col[2]; u8[v * 24 + 23] = 255;
    }
    I.set([i * 4, i * 4 + 1, i * 4 + 2, i * 4, i * 4 + 2, i * 4 + 3], i * 6);
  });
  var vao = gl.createVertexArray(); gl.bindVertexArray(vao);
  glPuffer(gl, gl.ARRAY_BUFFER, buf);
  gl.enableVertexAttribArray(0); gl.vertexAttribPointer(0, 3, gl.FLOAT, false, 24, 0);
  gl.enableVertexAttribArray(1); gl.vertexAttribPointer(1, 2, gl.FLOAT, false, 24, 12);
  gl.enableVertexAttribArray(2); gl.vertexAttribPointer(2, 4, gl.UNSIGNED_BYTE, true, 24, 20);
  glPuffer(gl, gl.ELEMENT_ARRAY_BUFFER, I);
  gl.bindVertexArray(null);
  return { tex: tex, vao: vao, Q: Q };
}
/* ---------- Ansicht ---------- */
/* Handy-Runde (Dimi 12.11.2026, Prüfliste 25.3): zwei Finger gehoeren der 3D-Ansicht. Ueber Touch-Ereignisse (nicht ueber Zeiger-
   Ereignisse, die der Browser abbricht, sobald er selbst zoomt oder schiebt) und mit preventDefault, damit der Browser bei zwei
   Fingern weder die Seite vergroessert noch schiebt (auch iPhone: gesture-Ereignisse). Ein Finger bleibt beim Browser (senkrecht:
   Seite scrollen) bzw. bei den Zeiger-Ereignissen der Ansicht (waagerecht: drehen). o.zwei(f, m, dm): Faktor, Mitte, Verschiebung;
   o.senkrecht(): ein Finger wischt senkrecht (Hinweis „Zum Zoomen zwei Finger“). */
function zweiFingerBinden(cv, o) {
  var P = null, E1 = null;
  function lage(t) { var r = cv.getBoundingClientRect(); return [t.clientX - r.left, t.clientY - r.top]; }
  function zwei(ev) { var a = lage(ev.touches[0]), b = lage(ev.touches[1]); return { d: Math.max(1, Math.sqrt(Math.pow(a[0] - b[0], 2) + Math.pow(a[1] - b[1], 2))), m: [(a[0] + b[0]) / 2, (a[1] + b[1]) / 2] }; }
  cv.addEventListener('touchstart', function (ev) {
    if (lt(ev.touches.length, 2)) { E1 = { x: ev.touches[0].clientX, y: ev.touches[0].clientY, h: false }; return; }
    if (ev.cancelable) { ev.preventDefault(); }
    P = zwei(ev); E1 = null; if (o.start) { o.start(); }
  }, { passive: false });
  cv.addEventListener('touchmove', function (ev) {
    if (lt(ev.touches.length, 2)) {
      if (E1) { if (!E1.h) { var dx = Math.abs(ev.touches[0].clientX - E1.x), dy = Math.abs(ev.touches[0].clientY - E1.y); if (gt(dy, 24)) { if (gt(dy, dx * 1.5)) { E1.h = true; if (o.senkrecht) { o.senkrecht(); } } } } }
      return;
    }
    if (ev.cancelable) { ev.preventDefault(); }
    var z = zwei(ev);
    if (!P) { P = z; return; }
    o.zwei(z.d / P.d, z.m, [z.m[0] - P.m[0], z.m[1] - P.m[1]]);
    P = z;
  }, { passive: false });
  function aus(ev) { if (lt(ev.touches.length, 2)) { if (P) { P = null; if (o.ende) { o.ende(); } } } if (!ev.touches.length) { E1 = null; } }
  cv.addEventListener('touchend', aus); cv.addEventListener('touchcancel', aus);
  each(['gesturestart', 'gesturechange', 'gestureend'], function (n) { cv.addEventListener(n, function (ev) { if (ev.cancelable) { ev.preventDefault(); } }, { passive: false }); });
}
function drei3(bu, root, G, H) {
  var B = bauen3(), S = B.S;
  var wrap = ht('div', 'wsz-3d', null, bu), cv = ht('canvas', null, null, wrap);
  cv.setAttribute('tabindex', '0'); cv.setAttribute('aria-label', '3D-Ansicht der Lüftungsanlage: ziehen zum Drehen, Mausrad oder zwei Finger zum Zoomen');
  var ov = sv('svg', { 'class': 'wsz-ov wsz-ov3', 'aria-hidden': 'true' }, wrap);
  var kn = ht('div', 'wsz-3k', null, wrap);
  /* Bedienung (Dimi 11.11.2026, 10:32): ohne Zusatztaste. Das Mausrad zoomt, sobald die Maus in der Ansicht bewegt wurde; scrollt man
     die Seite und die Ansicht gleitet unter den Zeiger, scrollt die Seite weiter. Herausgezoomt bis zur Gesamtansicht scrollt das Rad die
     Seite weiter (wie ein Fenster im Fenster). Dazu Knoepfe + und −, Touchpad-Spreizen, am Handy zwei Finger. */
  var bZm = ht('button', null, null, kn), bZp = ht('button', null, null, kn);
  bZm.type = 'button'; bZp.type = 'button'; bZm.title = 'Verkleinern'; bZp.title = 'Vergrößern'; bZm.setAttribute('aria-label', 'Verkleinern'); bZp.setAttribute('aria-label', 'Vergrößern');
  zoomIcon(bZm, false); zoomIcon(bZp, true);
  var bR = ht('button', null, null, kn); bR.type = 'button'; bR.title = 'Ansicht zurücksetzen';
  resetIcon(bR); bR.setAttribute('aria-label', 'Ansicht zurücksetzen');
  var touch = false;
  try { touch = window.matchMedia('(pointer: coarse)').matches; } catch (e) { touch = false; }
  /* Runde 13 der Szene (Dimi 10.11.2026): Bedienhinweis als Symbole wie in CAD-Programmen (drehen, zoomen, verschieben), ohne Text;
     er steht kurz und blendet dann aus. Die Erklaerung in Worten steht im Hilfetext des Fensters (aria-label). */
  var hin = ht('div', 'wsz-3h', null, wrap);
  hin.setAttribute('aria-hidden', 'true');
  hinweisSymbole(hin, ['dreh', 'zoom', 'schieb']);
  cv.setAttribute('aria-label', touch ? '3D-Ansicht: ein Finger nach oben oder unten scrollt die Seite, seitwärts dreht; zwei Finger zoomen und verschieben; Tippen wählt ein Bauteil' : '3D-Ansicht: Ziehen dreht; nach einem Klick in die Ansicht (blauer Rahmen) zoomt das Mausrad, Klick daneben oder Maus hinaus: das Rad scrollt die Seite; Knöpfe plus und minus zoomen, rechte Maustaste verschiebt');
  var toast = ht('div', 'wsz-3t', 'Zwei Finger: zoomen und verschieben', wrap), toastT = null;
  function toastZeigen(ms) { toast.style.opacity = '1'; if (toastT) { window.clearTimeout(toastT); } toastT = window.setTimeout(function () { toast.style.opacity = '0'; }, ms || 1600); }
  var gl = cv.getContext('webgl2', { antialias: true, alpha: false, premultipliedAlpha: true, preserveDrawingBuffer: false });
  if (!gl) { wrap.parentNode.removeChild(wrap); return null; }
  /* Programme */
  var vsF = glShader(gl, gl.VERTEX_SHADER, VS_F), vsL = glShader(gl, gl.VERTEX_SHADER, VS_L);
  var AF = ['aP', 'aN', 'aC', 'aM', 'aG'], AL = ['aT', 'aA', 'aB', 'aNA', 'aNB', 'aC', 'aX', 'aG'];
  var PF = glProg(gl, vsF, glShader(gl, gl.FRAGMENT_SHADER, FS_F), AF), PFI = glProg(gl, vsF, glShader(gl, gl.FRAGMENT_SHADER, FS_FID), AF);
  var PL = glProg(gl, vsL, glShader(gl, gl.FRAGMENT_SHADER, FS_L), AL), PLI = glProg(gl, vsL, glShader(gl, gl.FRAGMENT_SHADER, FS_LID), AL);
  var PT = glProg(gl, glShader(gl, gl.VERTEX_SHADER, VS_T), glShader(gl, gl.FRAGMENT_SHADER, FS_T), ['aP', 'aU', 'aK']);
  /* Farbtabelle */
  var pal = new Float32Array(56 * 3);
  each(MATK.concat(['n']), function (k, i) { each(k === 'n' ? INNEN3 : MAT[k], function (h, j) { var q = rgb(h); pal[(i * 4 + j) * 3] = q[0] / 255; pal[(i * 4 + j) * 3 + 1] = q[1] / 255; pal[(i * 4 + j) * 3 + 2] = q[2] / 255; }); });
  /* Puffer */
  var tpl = glPuffer(gl, gl.ARRAY_BUFFER, new Float32Array([0, -1, 1, -1, 1, 1, 0, 1])), tib = glPuffer(gl, gl.ELEMENT_ARRAY_BUFFER, new Uint16Array([0, 1, 2, 0, 2, 3]));
  var VF = {}, VL = {};
  each(['op', 'sd', 'gl', 'tr'], function (k) {
    var f = B.F[k];
    VF[k] = { vao: vaoF(gl, glPuffer(gl, gl.ARRAY_BUFFER, f.W.daten()), glPuffer(gl, gl.ELEMENT_ARRAY_BUFFER, f.I.daten()), null), n: f.I.n };
  });
  each(['op', 'sd'], function (k) { VL[k] = { vao: vaoL(gl, tpl, tib, glPuffer(gl, gl.ARRAY_BUFFER, B.L[k].daten()), null), n: B.L[k].n }; });
  var TA = textAtlas(gl, B.TX);
  /* Zustand */
  var Wc = 1, Hc = 1, dpr = 1, FB = null, idAlt = true, idKey = '', aktiv = false;
  var K = { az: ISO_AZ, el: ISO_EL, S: 0.1, T: [0, 0, 0] }, ANI = null;
  var DIM = 0, DIMZ = 0, HS = 1, HSZ = 1, SDA = 1, SDAZ = 1, HV = null, HVpid = null, offen = false;
  var raf = null, letzt = 0, ovNeu = true, erstAn = false, LBIAS = 1.0;
  /* Bildrate (Fable Runde 17, Dimi 11.11.2026: Bildrate am Rechner und am Handy). QS = Anteil der vollen Aufloesung. Kommt das Geraet
     beim Drehen oder Zoomen nicht nach (9 von 12 Bildern brauchen laenger als 34 ms bis zum naechsten Bildtakt), rechnet die Ansicht
     mit weniger Bildpunkten (bis zur halben Aufloesung); 0,26 s nach dem letzten Bild zeichnet sie einmal wieder scharf.
     Strichstaerken rechnen mit QS, die Bedienung und die Trefferflaeche bleiben unberuehrt. */
  var QS = 1, QN = 0, QL = 0, qT = null, qP = null;
  function qLeinwand() {
    var cw = Math.max(1, Math.round(Wc * dpr * QS)), ch = Math.max(1, Math.round(Hc * dpr * QS));
    if (cv.width !== cw) { cv.width = cw; } if (cv.height !== ch) { cv.height = ch; }
  }
  function qMessen(ts) {
    if (qP) { return; }
    qP = window.requestAnimationFrame(function (t2) {
      qP = null;
      var d = t2 - ts; if (gt(d, 1500)) { return; }
      QN++; if (gt(d, 34)) { QL++; }
      if (lt(QN, 12)) { return; }
      var runter = !lt(QL, 9); QN = 0; QL = 0;
      if (runter) { if (gt(QS, 0.5)) { QS = Math.max(0.5, QS - 0.2); qLeinwand(); if (aktiv) { zeichnen(); } } }
    });
  }
  function qRuhe() {
    if (qT) { window.clearTimeout(qT); }
    qT = window.setTimeout(function () {
      qT = null; QN = 0; QL = 0;
      if (!lt(QS, 1)) { return; }
      if (raf) { qRuhe(); return; }
      QS = 1; qLeinwand(); if (aktiv) { zeichnen(); }
    }, 260);
  }
  /* Kanten (Fable Runde 17): Strichstaerke folgt dem Massstab ein wenig. In der Uebersicht wie bisher (Zeichnung); herangezoomt werden
     die Kanten kraeftiger (bis 1,5-fach), weit herausgezoomt und auf schmalen Bildschirmen feiner, damit die Anlage nicht zulaeuft */
  var KSI = 0;
  function kantenMass() {
    if (!KSI) { KSI = isoZiel(G.vb).S; }
    var kz = Math.max(0.74, Math.min(1.5, Math.pow(K.S / Math.max(KSI, 1e-9), 0.3)));
    var kb = Math.sqrt(Math.max(0.6, Math.min(1, Wc / 760)));
    return kz * kb;
  }
  function achsen() {
    var ca = Math.cos(K.az), sa = Math.sin(K.az), ce = Math.cos(K.el), se = Math.sin(K.el);
    var v = [ce * ca, ce * sa, se], r = [sa, -ca, 0];
    return { v: v, r: r, u: cr(r, v) };
  }
  function matrix(A) {
    var sx = 2 * K.S / Wc, sy = 2 * K.S / Hc, sz = 1 / B.RZ, r = A.r, u = A.u, v = A.v, T = K.T;
    return new Float32Array([r[0] * sx, u[0] * sy, -v[0] * sz, 0, r[1] * sx, u[1] * sy, -v[1] * sz, 0, r[2] * sx, u[2] * sy, -v[2] * sz, 0, -dt(T, r) * sx, -dt(T, u) * sy, dt(T, v) * sz, 1]);
  }
  function proj(A, p) { var d = sb(p, K.T); return [Wc / 2 + dt(d, A.r) * K.S, Hc / 2 - dt(d, A.u) * K.S]; }
  /* Isometrie wie in der Zeichnung: gleicher Ausschnitt wie viewBox vb */
  /* Am Handy liegen Legende und Knoepfe oben im Bild: die Anlage beginnt darunter (Dimi 09.11.2026) */
  function oben() { return lt(Wc, 700) ? 72 : 0; }
  function isoZiel(vb) {
    var A = { v: nz([1, 1, 1]), r: nz([1, -1, 0]), u: nz([-1, -1, 2]) }, mo = oben();
    var k = Math.min(Wc / vb[2], (Hc - mo) / vb[3]), cx = vb[0] + vb[2] / 2, cy = vb[1] + vb[3] / 2 - mo / 2 / k;
    var c3 = [(B.bb[0] + B.bb[3]) / 2, (B.bb[1] + B.bb[4]) / 2, (B.bb[2] + B.bb[5]) / 2];
    var T = ad(ad(mu(A.r, cx / SK), mu(A.u, -cy / SK)), mu(A.v, dt(c3, A.v)));
    return { az: ISO_AZ, el: ISO_EL, S: k * SK, T: T };
  }
  function ganz(az, el) {
    var keep = { az: K.az, el: K.el }; K.az = az; K.el = el;
    var A = achsen(); K.az = keep.az; K.el = keep.el;
    var x0 = 1e9, x1 = -1e9, y0 = 1e9, y1 = -1e9;
    each(B.PE, function (p) { var a = dt(p, A.r), b = dt(p, A.u); x0 = Math.min(x0, a); x1 = Math.max(x1, a); y0 = Math.min(y0, b); y1 = Math.max(y1, b); });
    var m = 25 / SK, mo = oben(), w = x1 - x0 + 2 * m, h = y1 - y0 + 2 * m, s = Math.min(Wc / w, (Hc - mo) / h);
    var c3 = [(B.bb[0] + B.bb[3]) / 2, (B.bb[1] + B.bb[4]) / 2, (B.bb[2] + B.bb[5]) / 2];
    var T = ad(ad(mu(A.r, (x0 + x1) / 2), mu(A.u, (y0 + y1) / 2 + mo / 2 / s)), mu(A.v, dt(c3, A.v)));
    return { az: az, el: el, S: s, T: T };
  }
  var SMIN = 0.01, SMAX = 10;
  /* Bezugsrahmen (Dimi 11.11.2026, 10:32): Massstab und Breite, die man zuletzt selbst eingestellt hat. Wird die Anlage schmaler
     (Gruppenleiste auf zwei Drittel), schrumpft sie im selben Verhaeltnis und bleibt mittig; wird sie wieder breiter, kehrt derselbe
     Ausschnitt zurueck */
  var REF = null;
  function refSetzen() { REF = { S: K.S, W: Wc }; }
  function grenzen() {
    var g = isoZiel(G.vb); SMIN = g.S * 0.45; SMAX = g.S * 30;
    K.S = Math.max(SMIN, Math.min(SMAX, K.S));
    K.el = Math.max(EL_MIN, Math.min(EL_MAX, K.el));
    var b = B.bb;
    K.T = [Math.max(b[0] - 1000, Math.min(b[3] + 1000, K.T[0])), Math.max(b[1] - 1000, Math.min(b[4] + 1000, K.T[1])), Math.max(b[2] - 1000, Math.min(b[5] + 1000, K.T[2]))];
  }
  function winkel(a, b) { var d = b - a; while (gt(d, Math.PI)) { d -= 2 * Math.PI; } while (lt(d, -Math.PI)) { d += 2 * Math.PI; } return d; }
  function fahre(z, ms) {
    /* sanfter (Dimi 09.11.2026, Runde 11 Punkt 12): Standard 1,1 s statt 0,52 s */
    ANI = { a: { az: K.az, el: K.el, S: K.S, T: K.T.slice() }, z: z, t0: jetzt(), d: ms === undefined ? 1100 : ms };
    if (!ms) { if (ms === 0) { ANI.d = 1; } }
    anfordern();
  }
  function jetzt() { return window.performance ? window.performance.now() : Date.now(); }
  /* Groesse */
  function hoehe(w) { return szeneHoehe(w, G.vb[3] / G.vb[2], root); }
  function groesse() {
    if (!wrap.clientWidth) { if (gt(Wc, 1)) { return; } }
    var w = Math.max(50, wrap.clientWidth || bu.clientWidth || 600), h = hoehe(w);
    if (w === Wc) { if (h === Hc) { return; } }
    var alt = Wc, altH = Hc;
    wrap.style.height = h + 'px';
    dpr = Math.min(window.devicePixelRatio || 1, 2);
    cv.width = Math.max(1, Math.round(w * dpr * QS)); cv.height = Math.max(1, Math.round(h * dpr * QS));
    Wc = w; Hc = h; ov.setAttribute('viewBox', '0 0 ' + w + ' ' + h);
    if (FB) { gl.deleteFramebuffer(FB.fb); gl.deleteRenderbuffer(FB.rb); gl.deleteRenderbuffer(FB.db); }
    FB = idPuffer(Math.round(w), Math.round(h));
    /* Startseite (11.11.2026): feste Hoehe, die Breite aendert sich mit der Gruppenleiste; die Anlage bleibt ganz im Bild */
    if (gt(alt, 1)) {
      if (root.wszStartH ? !!REF : false) { K.S = REF.S * Math.min(w / Math.max(1, REF.W), 1); }
      else { K.S = K.S * (root.wszStartH ? Math.min(w / alt, h / Math.max(1, altH)) : w / alt); }
    }
    KSI = 0; idAlt = true; ovNeu = true; anfordern();
  }
  function idPuffer(w, h) {
    var fb = gl.createFramebuffer(), rb = gl.createRenderbuffer(), db = gl.createRenderbuffer();
    gl.bindRenderbuffer(gl.RENDERBUFFER, rb); gl.renderbufferStorage(gl.RENDERBUFFER, gl.RGBA8, w, h);
    gl.bindRenderbuffer(gl.RENDERBUFFER, db); gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_COMPONENT24, w, h);
    gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
    gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, rb);
    gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, db);
    gl.bindFramebuffer(gl.FRAMEBUFFER, null);
    return { fb: fb, rb: rb, db: db, w: w, h: h };
  }
  /* Zeichnen */
  function uniformsF(P, M, A, dim, al) {
    gl.useProgram(P.p);
    gl.uniformMatrix4fv(P.u.uM, false, M); gl.uniform3fv(P.u.uV, A.v);
    var th = ISO_AZ - K.az; gl.uniform2f(P.u.uRz, Math.cos(th), Math.sin(th));
    gl.uniform1f(P.u.uS, 1); gl.uniform3fv(P.u.uPal, pal);
    if (P.u.uDim) { gl.uniform1f(P.u.uDim, dim); gl.uniform1f(P.u.uAl, al); gl.uniform1f(P.u.uPass, 0); }
    gl.vertexAttrib3f(4, 0, 0, 0);
  }
  function uniformsL(P, M, A, dim, al, wmin) {
    gl.useProgram(P.p);
    gl.uniformMatrix4fv(P.u.uM, false, M); gl.uniform3fv(P.u.uV, A.v);
    gl.uniform2f(P.u.uPx, 2 / cv.width, 2 / cv.height); gl.uniform1f(P.u.uWk, dpr * QS * kantenMass()); gl.uniform1f(P.u.uWmin, wmin || 0); gl.uniform1f(P.u.uS, 1);
    gl.uniform1f(P.u.uBias, LBIAS / B.RZ);
    if (P.u.uDim) { gl.uniform1f(P.u.uDim, dim); gl.uniform1f(P.u.uAl, al); }
    gl.vertexAttrib3f(7, 0, 0, 0);
  }
  function zf(v) { if (v.n) { gl.bindVertexArray(v.vao); gl.drawElements(gl.TRIANGLES, v.n, gl.UNSIGNED_INT, 0); } }
  function zl(v) { if (v.n) { gl.bindVertexArray(v.vao); gl.drawElementsInstanced(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0, v.n); } }
  function durchsichtig(P, v, al) {
    gl.uniform1f(P.u.uAl, al);
    gl.uniform1f(P.u.uPass, 1); zf(v);
    gl.uniform1f(P.u.uPass, 2); zf(v);
    gl.uniform1f(P.u.uPass, 0);
  }
  function texte(M, A, nurPid, g, s) {
    if (!TA.Q.length) { return; }
    gl.useProgram(PT.p); gl.uniformMatrix4fv(PT.u.uM, false, M);
    gl.uniform3fv(PT.u.uG, g || [0, 0, 0]); gl.uniform1f(PT.u.uS, s || 1); gl.uniform1f(PT.u.uDim, nurPid ? 0 : DIM);
    gl.activeTexture(gl.TEXTURE0); gl.bindTexture(gl.TEXTURE_2D, TA.tex); gl.uniform1i(PT.u.uTex, 0);
    gl.bindVertexArray(TA.vao);
    gl.enable(gl.BLEND); gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA); gl.depthMask(false);
    each(TA.Q, function (q, i) {
      if (nurPid) { if (q.o.pid !== nurPid) { return; } }
      if (!gt(dt(q.n, A.v), 0.02)) { return; }
      gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, i * 12);
    });
    gl.depthMask(true);
  }
  function zeichnen() {
    var A = achsen(), M = matrix(A);
    gl.bindFramebuffer(gl.FRAMEBUFFER, null);
    gl.viewport(0, 0, cv.width, cv.height);
    gl.clearColor(1, 1, 1, 1); gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
    gl.enable(gl.DEPTH_TEST); gl.depthFunc(gl.LEQUAL); gl.depthMask(true); gl.disable(gl.BLEND); gl.disable(gl.CULL_FACE);
    /* deckende Flaechen */
    uniformsF(PF, M, A, DIM, 1);
    zf(VF.op); if (!lt(SDA, 0.999)) { zf(VF.sd); }
    texte(M, A, null);
    /* Linien (leicht zum Betrachter verschoben, Umrisse nach aussen) */
    gl.enable(gl.BLEND); gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
    uniformsL(PL, M, A, DIM, 1); zl(VL.op);
    gl.uniform1f(PL.u.uAl, SDA); zl(VL.sd);
    /* durchscheinende Flaechen: erst Rueckseiten, dann Vorderseiten */
    gl.depthMask(false);
    uniformsF(PF, M, A, DIM, 1);
    durchsichtig(PF, VF.gl, 1);
    if (lt(SDA, 0.999)) { durchsichtig(PF, VF.sd, SDA); }
    gl.depthMask(true);
    /* hervorgehobenes Bauteil obenauf, vergroessert */
    if (HV) {
      gl.clear(gl.DEPTH_BUFFER_BIT); gl.disable(gl.BLEND);
      uniformsF(PF, M, A, 0, 1); gl.uniform1f(PF.u.uS, HS);
      zf(HV.op); if (!lt(SDA, 0.999)) { zf(HV.sd); }
      each(HV.tx, function (t) { texte(M, A, t.pid, t.g, HS); });
      gl.enable(gl.BLEND); gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
      uniformsL(PL, M, A, 0, 1); gl.uniform1f(PL.u.uS, HS); zl(HV.lop); gl.uniform1f(PL.u.uAl, SDA); zl(HV.lsd);
      if (lt(SDA, 0.999)) {
        gl.depthMask(false);
        uniformsF(PF, M, A, 0, 1); gl.uniform1f(PF.u.uS, HS); durchsichtig(PF, HV.sd, SDA);
        gl.depthMask(true);
      }
    }
    gl.bindVertexArray(null);
    if (ovNeu) { ovSetzen(A); ovNeu = false; }
  }
  function idZeichnen() {
    var A = achsen(), M = matrix(A);
    gl.bindFramebuffer(gl.FRAMEBUFFER, FB.fb);
    gl.viewport(0, 0, FB.w, FB.h);
    gl.clearColor(0, 0, 0, 0); gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
    gl.enable(gl.DEPTH_TEST); gl.depthFunc(gl.LEQUAL); gl.depthMask(true); gl.disable(gl.BLEND);
    uniformsF(PFI, M, A);
    zf(VF.op); zf(VF.tr); if (!offen) { zf(VF.sd); }
    uniformsL(PLI, M, A, 0, 1, 3); gl.uniform1f(PLI.u.uWk, 1); gl.uniform2f(PLI.u.uPx, 2 / FB.w, 2 / FB.h); zl(VL.op);
    gl.bindVertexArray(null);
    gl.bindFramebuffer(gl.FRAMEBUFFER, null);
    idAlt = false; idKey = schluessel(); idPxOk = false;
  }
  function schluessel() { return K.az + '|' + K.el + '|' + K.S + '|' + K.T.join(',') + '|' + Wc + '|' + Hc; }
  /* Handy-Runde (Prüfliste 25.7): das Trefferbild wird einmal je Kamerastand ganz gelesen und danach nachgeschlagen (vorher eine
     Abfrage je Punkt, bis 18 je Beschriftung, jede haelt die Grafik an); Ergebnis gleich */
  var idPx = null, idPxOk = false;
  function gruppeAn(x, y) {
    if (!FB) { return null; }
    if (idAlt || schluessel() !== idKey) { idZeichnen(); }
    var xi = Math.floor(x), yi = Math.floor(Hc - y);
    if (lt(xi, 0) || lt(yi, 0)) { return null; }
    if (!lt(xi, FB.w) || !lt(yi, FB.h)) { return null; }
    if (!idPxOk) {
      if (!idPx || idPx.length !== FB.w * FB.h * 4) { idPx = new Uint8Array(FB.w * FB.h * 4); }
      gl.bindFramebuffer(gl.FRAMEBUFFER, FB.fb);
      gl.readPixels(0, 0, FB.w, FB.h, gl.RGBA, gl.UNSIGNED_BYTE, idPx);
      gl.bindFramebuffer(gl.FRAMEBUFFER, null);
      idPxOk = true;
    }
    var o = (yi * FB.w + xi) * 4, id = idPx[o] + idPx[o + 1] * 256;
    return id ? id - 1 : null;
  }
  /* Hervorhebung: Puffer nur fuer das Bauteil, je Stueck um seine Mitte skaliert */
  function hvBauen(pid) {
    var f = { op: { W: new Wachs(24), I: new Liste32(false), Z: new Liste32(true) }, sd: { W: new Wachs(24), I: new Liste32(false), Z: new Liste32(true) } };
    var l = { op: { W: new Wachs(48), Z: new Liste32(true) }, sd: { W: new Wachs(48), Z: new Liste32(true) } }, tx = [], gs = {};
    each(Array.isArray(pid) ? pid : [pid], function (px) {
      each(B.nach[px] || [], function (o) {
        var zc = gruppenMitte(B.GR[o.g3]);
        if (o.t === 'f') { var k = klasse3(o); if (k === 'op' || k === 'sd') { flaeche3(o, f[k].W, f[k].I, f[k].Z, zc); } }
        else if (o.t === 'l') { var kl = o.cls === 'sdw' ? 'sd' : 'op'; linie3(o, l[kl].W, l[kl].Z, zc); }
        else if (o.t === 't') { if (!gs[o.g3]) { gs[o.g3] = 1; tx.push({ pid: px, g: zc }); } }
      });
    });
    var R = { tx: tx, puf: [] };
    function pf(typ, d) { var b = glPuffer(gl, typ, d); R.puf.push(b); return b; }
    each(['op', 'sd'], function (k) {
      R[k] = { vao: vaoF(gl, pf(gl.ARRAY_BUFFER, f[k].W.daten()), pf(gl.ELEMENT_ARRAY_BUFFER, f[k].I.daten()), pf(gl.ARRAY_BUFFER, f[k].Z.daten())), n: f[k].I.n };
      R['l' + k] = { vao: vaoL(gl, tpl, tib, pf(gl.ARRAY_BUFFER, l[k].W.daten()), pf(gl.ARRAY_BUFFER, l[k].Z.daten())), n: l[k].W.n };
    });
    return R;
  }
  function hvWeg() {
    if (!HV) { return; }
    each(HV.puf, function (b) { gl.deleteBuffer(b); });
    each(['op', 'sd', 'lop', 'lsd'], function (k) { gl.deleteVertexArray(HV[k].vao); });
    HV = null;
  }
  function zeige(pid) {
    var key = pid ? (Array.isArray(pid) ? pid.join(',') : pid) : pid;
    if (key === HVpid) { return; }
    HVpid = key; hvWeg();
    if (pid) { HV = hvBauen(pid); HS = 1; var b = Array.isArray(pid) ? null : BT[pid]; HSZ = Array.isArray(pid) ? 1.04 : (b ? (b.klick === 'ja' ? 1.07 : 1.03) : 1.03); DIMZ = 1; }
    else { DIMZ = 0; HSZ = 1; }
    anfordern();
  }
  /* Ueberlagerung: Luftwege, Bereiche, Beschriftungen des Schalldaempfers */
  var OV = { fl: [], zo: [], mk: [] };
  (function () {
    /* Luftwege in Gruppen wsz-lfg: nur beim Zeigen sichtbar (40_ui.js luft, Runde 9) */
    var unter = sv('g', { 'class': 'wsz-lfg' }, ov), dash = sv('g', { 'class': 'wsz-lfg' }, ov), pf = sv('g', { 'class': 'wsz-lfg' }, ov), lauf = {};
    each(S.fl, function (f) {
      var c = LUFT[f.a].c, cls = 'wsz-flg' + (f.o.offen ? ' wsz-of' : '') + (f.o.zu ? ' wsz-zu' : '');
      var u = sv('path', { fill: 'none', stroke: '#FFFFFF', 'stroke-width': LW.halo, 'stroke-linecap': 'round', 'stroke-linejoin': 'round', opacity: 0.6, 'class': cls + ' wsz-fu', 'data-p': f.pid }, unter);
      var e = sv('path', { fill: 'none', stroke: c, 'stroke-width': f.o.aus ? LW.kurz : LW.linie, 'stroke-linecap': 'round', 'stroke-linejoin': 'round', 'stroke-dasharray': f.o.aus ? LW.strichKurz : LW.strich, 'class': cls + ' wsz-fl' + (f.o.aus ? ' wsz-fk' : ''), 'data-p': f.pid }, dash);
      var key = f.a + (f.o.offen ? 'o' : ''), P = 40, T = P / ((f.o.g || 55) * 0.6);
      if (f.o.aus) { T = 15 / ((f.o.g || 40) * 0.6); }
      e.style.animationDuration = f1(T * 100) / 100 + 's';
      var a = sv('path', { fill: c, stroke: '#FFFFFF', 'stroke-width': 1, 'class': cls, 'data-p': f.pid }, pf);
      OV.fl.push({ f: f, u: u, e: e, a: a, key: key, T: T });
    });
    each(S.zo, function (z) {
      var t = sv('text', { 'text-anchor': z.an, 'font-size': 9, fill: '#7B8796', 'font-weight': 700, 'letter-spacing': 0.6, 'font-family': 'Arial, Helvetica, sans-serif', 'class': 'wsz-zo' }, ov);
      t.textContent = z.s.toUpperCase(); OV.zo.push({ z: z, t: t });
    });
    each(S.mk, function (m) {
      var gg = sv('g', { 'class': 'wsz-mk' }, ov);
      var l = sv('path', { stroke: '#1F3855', 'stroke-width': 1, fill: 'none' }, gg), c = sv('circle', { r: 1.6, fill: '#1F3855' }, gg);
      var r = sv('rect', { rx: 1.5, fill: '#FFFFFF', stroke: '#1F3855', 'stroke-width': 1 }, gg);
      var t = sv('text', { 'text-anchor': 'middle', fill: '#1F3855', 'font-weight': 700, 'font-family': 'Arial, Helvetica, sans-serif' }, gg);
      t.textContent = m.s; OV.mk.push({ m: m, g: gg, l: l, c: c, r: r, t: t });
    });
    OV.lauf = lauf;
  })();
  /* Bereichs- und Schalldaempfer-Beschriftungen: waehrend der Bewegung aus, danach nur, wo sie nichts verdecken
     bzw. wo ihr Ankerpunkt sichtbar ist */
  var pruefT = null;
  function beschriftungPruefen() {
    pruefT = null;
    if (!aktiv) { return; }
    if (ANI) { pruefT = window.setTimeout(beschriftungPruefen, 120); return; }
    each(OV.zo, function (x) {
      var bb = null, frei = true;
      try { bb = x.t.getBBox(); } catch (e) { bb = null; }
      if (!bb) { frei = false; }
      else {
        if (lt(bb.x, 6) || lt(bb.y, 6) || gt(bb.x + bb.width, Wc - 6) || gt(bb.y + bb.height, Hc - 6)) { frei = false; }
        /* nicht unter dem Bedienhinweis oder dem Knopf */
        each([hin, kn], function (e) {
          if (e === hin) { if (hin.style.opacity === '0') { return; } }
          var r = e.getBoundingClientRect(), c = cv.getBoundingClientRect(), x0 = r.left - c.left, y0 = r.top - c.top;
          if (lt(bb.x, x0 + r.width)) { if (gt(bb.x + bb.width, x0)) { if (lt(bb.y, y0 + r.height)) { if (gt(bb.y + bb.height, y0)) { frei = false; } } } }
        });
        for (var i = 0; i !== 6; i++) { for (var j = 0; j !== 3; j++) { if (frei) { if (gruppeAn(bb.x + bb.width * (i + 0.5) / 6, bb.y + bb.height * (j + 0.5) / 3) !== null) { frei = false; } } } }
      }
      x.t.style.visibility = frei ? '' : 'hidden';
    });
    each(OV.mk, function (x) {
      if (x.g.style.display === 'none') { return; }
      var g = gruppeAn(x.ax[0], x.ax[1]);
      x.g.style.visibility = (g !== null ? (B.GR[g].pid === 'kulisse' || B.GR[g].pid === 'skulisse') : false) ? '' : 'hidden';
    });
  }
  function ovSetzen(A) {
    var k = K.S / SK, lauf = {};
    each(OV.zo, function (x) { x.t.style.visibility = 'hidden'; });
    each(OV.mk, function (x) { x.g.style.visibility = 'hidden'; });
    if (pruefT) { window.clearTimeout(pruefT); }
    pruefT = window.setTimeout(beschriftungPruefen, 160);
    each(OV.fl, function (x) {
      var pts = x.f.p.map(function (p) { return proj(A, p); }), L = 0, i;
      for (i = 1; i !== pts.length; i++) { L += Math.sqrt(Math.pow(pts[i][0] - pts[i - 1][0], 2) + Math.pow(pts[i][1] - pts[i - 1][1], 2)); }
      var dp = pfad(pts, 0); x.u.setAttribute('d', dp); x.e.setAttribute('d', dp);
      var d0 = lauf[x.key] || 0; lauf[x.key] = d0 + L;
      if (!x.ph) { x.ph = 1; x.e.style.animationDelay = '-' + f1(((40 - (d0 % 40)) / 40) * x.T * 100) / 100 + 's'; }
      if (!gt(L, 30)) { x.a.setAttribute('d', ''); return; }
      var ziel = x.f.o.aus ? L : L * 0.55, s = 0, a = pts[0], b = pts[1], m = null;
      for (i = 1; i !== pts.length; i++) {
        var l = Math.sqrt(Math.pow(pts[i][0] - pts[i - 1][0], 2) + Math.pow(pts[i][1] - pts[i - 1][1], 2));
        if (!lt(s + l, ziel - 0.001)) { var t = l ? (ziel - s) / l : 0; a = pts[i - 1]; b = pts[i]; m = [a[0] + (b[0] - a[0]) * t, a[1] + (b[1] - a[1]) * t]; break; }
        s += l;
      }
      if (!m) { m = pts[pts.length - 1]; }
      var dx = b[0] - a[0], dy = b[1] - a[1], dl = Math.sqrt(dx * dx + dy * dy) || 1; dx /= dl; dy /= dl;
      var q = Math.min(1.6, Math.max(0.9, k * 1.1)) * LW.spitze, tip = [m[0] + dx * 6 * q, m[1] + dy * 6 * q], l1 = [m[0] - dx * 5 * q - dy * 5.5 * q, m[1] - dy * 5 * q + dx * 5.5 * q], l2 = [m[0] - dx * 5 * q + dy * 5.5 * q, m[1] - dy * 5 * q - dx * 5.5 * q];
      x.a.setAttribute('d', pfad([tip, l1, l2], 1));
    });
    each(OV.zo, function (x) {
      var q = proj(A, x.z.p), fs = Math.max(9, Math.min(16, 9 * k));
      x.t.setAttribute('x', f1(q[0])); x.t.setAttribute('y', f1(q[1] + 12 * Math.max(1, k))); x.t.setAttribute('font-size', f1(fs));
    });
    /* Schalldaempfer-Beschriftungen: nur bei Blick auf die geschnittene Kulisse (von +y), Groesse begrenzt,
       Kaesten schieben sich nicht uebereinander */
    var vorn = gt(A.v[1], 0.15), MK = [], kk = Math.max(1, Math.min(1.5, k)), ko = Math.max(1, Math.min(2.2, k)), i, j, it;
    each(OV.mk, function (x) {
      x.g.style.display = vorn ? '' : 'none';
      if (!vorn) { return; }
      var a = proj(A, x.m.p);
      x.ax = a; MK.push({ x: x, a: a, b: [a[0] + x.m.dx * ko, a[1] + x.m.dy * ko], w: (x.m.s.length * 4.3 + 6) * kk * 1.25, h: 10 * kk * 1.25 });
    });
    MK.sort(function (P, Q) { return P.b[1] - Q.b[1]; });
    for (it = 0; it !== 8; it++) {
      var bewegt = false;
      for (i = 0; i !== MK.length; i++) {
        for (j = i + 1; j !== MK.length; j++) {
          var P = MK[i], Q = MK[j];
          if (lt(Math.abs(P.b[0] - Q.b[0]), (P.w + Q.w) / 2 + 4)) { if (lt(Math.abs(P.b[1] - Q.b[1]), P.h + 3)) { Q.b[1] = P.b[1] + P.h + 3; bewegt = true; } }
        }
      }
      if (!bewegt) { break; }
    }
    each(MK, function (q) {
      var x = q.x, a = q.a, b = q.b, w = q.w, h = q.h;
      x.l.setAttribute('d', pfad([a, b], 0)); x.c.setAttribute('cx', f1(a[0])); x.c.setAttribute('cy', f1(a[1]));
      x.r.setAttribute('x', f1(b[0] - w / 2)); x.r.setAttribute('y', f1(b[1])); x.r.setAttribute('width', f1(w)); x.r.setAttribute('height', f1(h));
      x.t.setAttribute('x', f1(b[0])); x.t.setAttribute('y', f1(b[1] + h * 0.73)); x.t.setAttribute('font-size', f1(h * 0.74));
    });
  }
  /* Bildschleife: zeichnet nur bei Bedarf */
  function anfordern() { if (!raf) { if (aktiv) { raf = window.requestAnimationFrame(bild); } } }
  function bild(ts) {
    raf = null;
    var dtm = letzt ? Math.min(100, ts - letzt) : 16, weiter = false; letzt = ts;
    if (ANI) {
      var t = Math.min(1, (jetzt() - ANI.t0) / ANI.d), e = lt(t, 0.5) ? 4 * t * t * t : 1 - Math.pow(-2 * t + 2, 3) / 2;
      K.az = ANI.a.az + winkel(ANI.a.az, ANI.z.az) * e; K.el = ANI.a.el + (ANI.z.el - ANI.a.el) * e;
      K.S = ANI.a.S * Math.pow(ANI.z.S / ANI.a.S, e); K.T = lp(ANI.a.T, ANI.z.T, e);
      ovNeu = true;
      if (lt(t, 1)) { weiter = true; } else { ANI = null; refSetzen(); }
    }
    function nah(v, z, sch) { if (gt(Math.abs(z - v), sch)) { weiter = true; return v + (z - v) * Math.min(1, dtm / 90); } return z; }
    DIM = nah(DIM, DIMZ, 0.01); HS = nah(HS, HSZ, 0.001);
    if (SDA !== SDAZ) { var st = dtm / 600; SDA = gt(SDAZ, SDA) ? Math.min(SDAZ, SDA + st) : Math.max(SDAZ, SDA - st); weiter = true; }
    zeichnen(); qMessen(ts); qRuhe();
    if (weiter) { anfordern(); } else { letzt = 0; }
  }
  /* Bedienung */
  var ZG = {}, zug = null, hovXY = null, hovRaf = null, scharf = false, benutzt = false;
  /* Zoom per Klick (Dimi 11.11.2026, 16:23, Antwort 1a): Ein Klick in die Ansicht schaltet das Mausrad auf Zoomen, die Ansicht bekommt
     einen duennen blauen Rahmen. Ein Klick ausserhalb oder die Maus verlaesst die Ansicht: das Rad scrollt wieder die Seite. Strg/Cmd und
     Touchpad-Spreizen zoomen immer; ganz herausgezoomt gibt das Rad beim Herauszoomen an die Seite weiter und schaltet ab. */
  var zAktiv = false, zHin = false;
  function zoomAn(an) { zAktiv = an; wrap.classList.toggle('za', an); }
  /* Handy-Runde 2 (Dimi 12.11.2026, 09:23): am Handy schaltet Antippen das Drehen ein (blauer Rahmen wie am Rechner); dann dreht und
     kippt ein Finger frei, zwei Finger zoomen. Heraus kommt man immer: Knopf „✕ Fertig“ in der Anlage, Tippen ausserhalb der Anlage
     oder die Anlage aus dem Bild scrollen. Vorher scrollt ein Finger die Seite. Am Rechner gibt es Knopf und Zustand nicht. */
  var DRA = false, taK = null, taHin = 0;
  function taSetzen(an) {
    if (!touch) { return; } an = !!an; if (DRA === an) { return; }
    DRA = an; wrap.classList.toggle('ta', an); wrap.classList.toggle('za', an); bu.classList.toggle('wsz-ta', an);
    if (an) { var t = jetzt(); if (gt(t - taHin, 15000)) { taHin = t; toast.textContent = 'Drehen: ein Finger · Zoomen: zwei Finger'; toastZeigen(2200); } }
    /* die Anlage ganz ins Bild holen, damit „✕ Fertig“ immer erreichbar ist (quer fuellt sie den Bildschirm) */
    if (an) {
      var r = bu.getBoundingClientRect(), vh = window.innerHeight || 800;
      if (lt(r.top, 0) || gt(r.bottom, vh)) {
        var y = Math.max(0, r.top + (window.pageYOffset || 0) - Math.max(0, (vh - r.height) / 2));
        try { window.scrollTo({ top: y, behavior: 'smooth' }); } catch (e) { window.scrollTo(0, y); }
      }
    }
  }
  if (touch) {
    taK = ht('button', 'wsz-3f', '✕ Fertig', wrap); taK.type = 'button'; taK.setAttribute('aria-label', 'Drehen beenden, Seite scrollen');
    taK.addEventListener('click', function (ev) { ev.stopPropagation(); taSetzen(false); });
    taK.addEventListener('pointerdown', function (ev) { ev.stopPropagation(); });
    document.addEventListener('pointerdown', function (ev) { if (DRA) { if (!bu.contains(ev.target)) { taSetzen(false); } } }, true);
    if (window.IntersectionObserver) { new IntersectionObserver(function (es) { each(es, function (e) { if (lt(e.intersectionRatio, 0.3)) { taSetzen(false); } }); }, { threshold: [0, 0.3] }).observe(wrap); }
  }
  document.addEventListener('pointerdown', function (ev) { if (zAktiv) { if (!wrap.contains(ev.target)) { zoomAn(false); } } }, true);
  function zahl() { var n = 0; for (var k in ZG) { if (ZG[k]) { n++; } } return n; }
  function zwei() { var a = []; for (var k in ZG) { if (ZG[k]) { a.push(ZG[k]); } } return a; }
  function lokal(ev) { var r = cv.getBoundingClientRect(); return [ev.clientX - r.left, ev.clientY - r.top]; }
  function hilfeWeg() { hin.style.opacity = '0'; }
  function drehen(dx, dy) {
    K.az = K.az + dx * 0.0055; K.el = Math.max(EL_MIN, Math.min(EL_MAX, K.el + dy * 0.0055));
    ovNeu = true; anfordern();
  }
  function schieben(dx, dy) {
    var A = achsen();
    K.T = ad(K.T, ad(mu(A.r, -dx / K.S), mu(A.u, dy / K.S)));
    grenzen(); ovNeu = true; anfordern();
  }
  function zoomen(f, x, y) {
    var A = achsen(), s0 = K.S, s1 = Math.max(SMIN, Math.min(SMAX, K.S * f));
    var dx = x - Wc / 2, dy = Hc / 2 - y, k = 1 / s0 - 1 / s1;
    K.T = ad(K.T, ad(mu(A.r, dx * k), mu(A.u, dy * k)));
    K.S = s1; grenzen(); refSetzen(); ovNeu = true; anfordern();
  }
  /* Herauszoomen mit dem Rad: hoechstens bis zur Gesamtansicht; der Ausschnitt laeuft dabei in die Mitte der Gesamtansicht zurueck */
  function heraus(f, x, y) {
    var g = isoZiel(G.vb), s0 = K.S;
    zoomen(Math.max(f, g.S / Math.max(1e-9, s0)), x, y);
    var q = gt(s0 - g.S, 1e-9) ? Math.max(0, Math.min(1, (K.S - g.S) / (s0 - g.S))) : 0;
    K.T = lp(g.T, K.T, q); grenzen(); refSetzen(); ovNeu = true; anfordern();
  }
  cv.addEventListener('contextmenu', function (ev) { ev.preventDefault(); });
  cv.addEventListener('pointerdown', function (ev) {
    try { cv.setPointerCapture(ev.pointerId); } catch (e) { }
    var p = lokal(ev); ZG[ev.pointerId] = { x: p[0], y: p[1] };
    ANI = null; hilfeWeg(); scharf = true; benutzt = true; if (ev.pointerType === 'mouse') { zoomAn(true); }
    if (zahl() === 1) { zug = { art: (ev.button === 2 || ev.shiftKey || ev.ctrlKey || ev.metaKey) ? 'schieb' : ((ev.pointerType === 'touch' ? !DRA : false) ? 'tipp' : 'dreh'), x: p[0], y: p[1], sx: p[0], sy: p[1], weg: 0, t: jetzt(), n: 1, tol: ev.pointerType === 'mouse' ? 5 : 11 }; }
    else if (ev.pointerType === 'touch') { zug = { art: 'aus', weg: 99, n: 2 }; }
    else { var z = zwei(); zug = { art: 'pinch', d: Math.max(1, Math.sqrt(Math.pow(z[0].x - z[1].x, 2) + Math.pow(z[0].y - z[1].y, 2))), m: [(z[0].x + z[1].x) / 2, (z[0].y + z[1].y) / 2], weg: 99, n: 2 }; }
    cv.classList.add('zieh');
    ev.preventDefault();
  });
  cv.addEventListener('pointermove', function (ev) {
    var p = lokal(ev);
    if (ZG[ev.pointerId]) { ZG[ev.pointerId] = { x: p[0], y: p[1] }; }
    if (!zug) {
      if (ev.pointerType === 'mouse') { hovXY = { x: p[0], y: p[1], ev: ev }; if (!hovRaf) { hovRaf = window.requestAnimationFrame(hovPruefen); } }
      return;
    }
    if (zug.art === 'aus') { return; }
    if (zug.art === 'pinch') {
      var z = zwei(); if (lt(z.length, 2)) { return; }
      var d = Math.max(1, Math.sqrt(Math.pow(z[0].x - z[1].x, 2) + Math.pow(z[0].y - z[1].y, 2))), m = [(z[0].x + z[1].x) / 2, (z[0].y + z[1].y) / 2];
      schieben(m[0] - zug.m[0], m[1] - zug.m[1]); zoomen(d / zug.d, m[0], m[1]);
      zug.d = d; zug.m = m; return;
    }
    var dx = p[0] - zug.x, dy = p[1] - zug.y; zug.x = p[0]; zug.y = p[1];
    zug.weg += Math.abs(dx) + Math.abs(dy);
    if (lt(zug.weg, zug.tol || 5)) { return; }
    if (zug.art === 'tipp') { return; }
    if (zug.art === 'dreh') { drehen(dx, dy); } else { schieben(dx, dy); }
  });
  function ende(ev) {
    var p = lokal(ev), war = zug; delete ZG[ev.pointerId];
    if (zahl() === 0) { zug = null; cv.classList.remove('zieh'); }
    else if (zahl() === 1) { var z = zwei()[0]; zug = war ? (war.art === 'aus' ? { art: 'aus', weg: 99, n: 2 } : null) : null; if (!zug) { zug = { art: 'dreh', x: z.x, y: z.y, weg: 99, n: 1 }; } }
    if (war) { if (war.n === 1) { if (lt(war.weg, (war.tol || 5) + 1)) { if (ev.type === 'pointerup') { if (ev.pointerType !== 'mouse' || ev.button === 0) { if (war.art === 'dreh' || war.art === 'tipp') { if (ev.pointerType === 'touch') { taSetzen(true); } if (!doppelTippen(p, ev)) { klick(p[0], p[1], ev); } } } } } } }
  }
  /* Handy-Runde (Prüfliste 25.3): Doppeltippen zoomt an der Stelle auf das Doppelte; das erste Tippen hat schon ausgewaehlt */
  var TT = null;
  function doppelTippen(p, ev) {
    if (ev.pointerType !== 'touch') { return false; }
    var t = jetzt(), war = TT; TT = { t: t, x: p[0], y: p[1] };
    if (!war) { return false; }
    if (gt(t - war.t, 330)) { return false; }
    if (gt(Math.abs(p[0] - war.x) + Math.abs(p[1] - war.y), 36)) { return false; }
    TT = null; ANI = null; hilfeWeg(); zoomen(2, p[0], p[1]);
    try { bu.dispatchEvent(new CustomEvent('wszzoom')); } catch (e) { }
    return true;
  }
  cv.addEventListener('pointerup', ende);
  cv.addEventListener('pointercancel', ende);
  cv.addEventListener('pointerleave', function (ev) { if (ev.pointerType === 'mouse') { if (!zug) { zoomAn(false); hovXY = null; scharf = false; H.weg(); cv.style.cursor = ''; } } });
  cv.addEventListener('wheel', function (ev) {
    var spreiz = ev.ctrlKey || ev.metaKey, d = ev.deltaY * (ev.deltaMode === 1 ? 16 : (ev.deltaMode === 2 ? 400 : 1));
    if (!spreiz) {
      /* nicht aktiv: die Seite scrollt; einmal je Seite ein kurzer Hinweis */
      if (!zAktiv) { if (!zHin) { zHin = true; toast.textContent = 'Zum Zoomen in die Anlage klicken'; toastZeigen(1800); } return; }
      /* Runde 18 (Dimi 11.11.2026, 20:13): ganz herausgezoomt scrollt das Rad nicht mehr die Seite; erst Klick daneben oder Maus hinaus */
      if (gt(d, 0)) { if (!gt(K.S, isoZiel(G.vb).S * 1.002)) { ev.preventDefault(); return; } }
    }
    ev.preventDefault(); ANI = null; hilfeWeg(); toast.style.opacity = '0';
    var p = lokal(ev), f = Math.exp(-d * 0.0015);
    if (spreiz) { zoomen(f, p[0], p[1]); } else if (lt(f, 1)) { heraus(f, p[0], p[1]); } else { zoomen(f, p[0], p[1]); }
    try { bu.dispatchEvent(new CustomEvent('wszzoom')); } catch (e) { }
  }, { passive: false });
  cv.addEventListener('keydown', function (ev) {
    var k = ev.key, z = true;
    if (k === 'ArrowLeft') { drehen(-25, 0); } else if (k === 'ArrowRight') { drehen(25, 0); }
    else if (k === 'ArrowUp') { drehen(0, -25); } else if (k === 'ArrowDown') { drehen(0, 25); }
    else if (k === '+' || k === '=') { zoomen(1.25, Wc / 2, Hc / 2); } else if (k === '-') { zoomen(0.8, Wc / 2, Hc / 2); }
    else if (k === '0') { zuruecksetzen(); } else { z = false; }
    if (z) { ev.preventDefault(); hilfeWeg(); }
  });
  function pidVon(g) { if (g === null) { return null; } var x = B.GR[g]; return x ? x.pid : null; }
  function hovPruefen() {
    hovRaf = null;
    if (!hovXY) { return; }
    if (zug) { return; }
    var g = gruppeAn(hovXY.x, hovXY.y), pid = pidVon(g);
    var ok = pid ? (BT[pid] ? BAU.indexOf(pid) === -1 : false) : false;
    cv.style.cursor = H.gewaehlt() ? '' : (ok ? (BT[pid].klick === 'ja' ? 'pointer' : 'default') : '');
    H.hover(ok ? pid : null, hovXY.ev);
  }
  function klick(x, y, ev) {
    var g = gruppeAn(x, y), pid = pidVon(g);
    if (pid) { if (!BT[pid] || BAU.indexOf(pid) !== -1) { pid = null; g = null; } }
    H.klick(pid, g, ev);
  }
  function zuruecksetzen() { fahre(isoZiel(G.vb), 1000); }
  bR.addEventListener('click', function () { hilfeWeg(); zuruecksetzen(); });
  bZp.addEventListener('click', function () { hilfeWeg(); ANI = null; zoomen(1.3, Wc / 2, Hc / 2); });
  bZm.addEventListener('click', function () { hilfeWeg(); ANI = null; zoomen(1 / 1.3, Wc / 2, Hc / 2); });
  /* Handy: beim ersten Beruehren kurz der Hinweis auf zwei Finger (ein Finger senkrecht scrollt die Seite, touch-action pan-y) */
  var tHin = 0;
  zweiFingerBinden(cv, {
    start: function () { ANI = null; hilfeWeg(); toast.style.opacity = '0'; scharf = true; benutzt = true; taSetzen(true); },
    zwei: function (f, m, dm) { schieben(dm[0], dm[1]); zoomen(f, m[0], m[1]); },
    ende: function () { try { bu.dispatchEvent(new CustomEvent('wszzoom')); } catch (e) { } },
    senkrecht: function () { if (DRA) { return; } var t = jetzt(); if (lt(t - tHin, 10000)) { return; } tHin = t; toast.textContent = 'Zum Drehen antippen · Zoomen: zwei Finger'; toastZeigen(1900); }
  });
  /* Bauteil in den Blick nehmen: wie in der Zeichnung etwa ein Drittel der Breite */
  function fokus(pid, g) {
    if (!pid) { fahre(ganz(K.az, K.el)); return; }
    var bb = null;
    if (g !== null) { if (g !== undefined) { if (B.GR[g]) { bb = B.GR[g].bb; } } }
    if (!bb) {
      var ps = Array.isArray(pid) ? pid : [pid];
      each(B.GR, function (x) { if (ps.indexOf(x.pid) === -1) { return; } if (!bb) { bb = x.bb.slice(); return; } for (var k = 0; k !== 3; k++) { bb[k] = Math.min(bb[k], x.bb[k]); bb[k + 3] = Math.max(bb[k + 3], x.bb[k + 3]); } });
    }
    if (!bb) { return; }
    var A = achsen(), x0 = 1e9, x1 = -1e9, y0 = 1e9, y1 = -1e9;
    for (var m = 0; m !== 8; m++) {
      var p = [bb[m % 2 ? 3 : 0], bb[Math.floor(m / 2) % 2 ? 4 : 1], bb[Math.floor(m / 4) ? 5 : 2]], a = dt(p, A.r), b = dt(p, A.u);
      x0 = Math.min(x0, a); x1 = Math.max(x1, a); y0 = Math.min(y0, b); y1 = Math.max(y1, b);
    }
    var full = ganz(K.az, K.el), Wf = Wc / full.S, w = Math.max((x1 - x0) * 3, Wf * 0.2), h = w * Hc / Wc;
    if (lt(h, (y1 - y0) * 2.2)) { h = (y1 - y0) * 2.2; w = h * Wc / Hc; }
    var c = [(bb[0] + bb[3]) / 2, (bb[1] + bb[4]) / 2, (bb[2] + bb[5]) / 2];
    fahre({ az: K.az, el: K.el, S: Math.max(SMIN, Math.min(SMAX, Wc / w)), T: c });
  }
  function offenSetzen(a) { offen = !!a; SDAZ = offen ? 0.08 : 1; idAlt = true; anfordern(); }
  var RO = null;
  if (window.ResizeObserver) { RO = new ResizeObserver(function () { if (aktiv) { groesse(); } }); RO.observe(bu); }
  /* Fensterhoehe aendert die Szenenhoehe (Dimi 09.11.2026), auch wenn die Breite gleich bleibt */
  window.addEventListener('resize', function () { if (aktiv) { groesse(); } });
  cv.addEventListener('webglcontextlost', function (ev) { ev.preventDefault(); H.verloren(); });
  return {
    ov: ov, B: B,
    an: function (sel, g) {
      aktiv = true; wrap.style.display = 'block'; groesse(); grenzen();
      if (!erstAn) { erstAn = true; K = isoZiel(G.vb); grenzen(); refSetzen(); hin.style.opacity = ''; window.setTimeout(hilfeWeg, 3200); }
      ovNeu = true;
      if (sel) { fokus(sel, g === undefined ? null : g); } else { anfordern(); }
    },
    aus: function () { taSetzen(false); aktiv = false; wrap.style.display = 'none'; if (raf) { window.cancelAnimationFrame(raf); raf = null; } },
    zeige: zeige, fokus: fokus, offen: offenSetzen, zurueck: zuruecksetzen,
    /* fuer Tests */
    kamera: function (z, ms) {
      if (z) {
        var q = { az: K.az, el: K.el, S: K.S, T: K.T }; for (var k in z) { q[k] = z[k]; }
        if (ms) { fahre(q, ms); } else { ANI = null; K = q; grenzen(); refSetzen(); ovNeu = true; anfordern(); }
      }
      return { az: K.az, el: K.el, S: K.S, T: K.T.slice() };
    },
    bias: function (b) { LBIAS = b; anfordern(); },
    /* Bild der Ansicht (Drucken und Bildschirmfoto, Runde 11 Punkt 10) */
    bild: function () { if (!aktiv) { return ''; } zeichnen(); try { return cv.toDataURL('image/png'); } catch (e) { return ''; } },
    /* Hoehe neu (gezogene Szene, Runde 11 Punkt 9) */
    neu: function () { if (aktiv) { groesse(); } },
    ganz: function () { ANI = null; K = ganz(K.az, K.el); refSetzen(); ovNeu = true; anfordern(); },
    gruppe: function (x, y) { var g = gruppeAn(x, y); return g === null ? null : { g: g, pid: pidVon(g) }; },
    projektion: function (p) { return proj(achsen(), p); },
    info: function () { return { qs: QS, nf: B.nf, nl: B.nl, ms: B.ms, faces: { op: VF.op.n / 3, sd: VF.sd.n / 3, gl: VF.gl.n / 3, tr: VF.tr.n / 3 }, linien: VL.op.n + VL.sd.n, gruppen: B.GR.length, texte: TA.Q.length, W: Wc, H: Hc, dpr: dpr }; }
  };
}
var CSS3 = [
  '.wsz-3d{position:relative;display:none;width:100%;background:#fff;overflow:hidden}',
  '.wsz-3d canvas{display:block;width:100%;height:100%;touch-action:pan-y;cursor:grab;outline:none}',
  '.wsz-3d canvas.zieh{cursor:grabbing}',
  '.wsz-3d canvas:focus-visible{box-shadow:inset 0 0 0 2px #1F3855}',
  /* rechts daneben der Knopf Einklappen der Buehne (40_ui.js, .wsz-ek 112 px breit, am Handy 34 px) */
  /* Runde 11 der Szene (Dimi 10.11.2026, Antworten Runde 12, Punkt 20): nur Symbole, links neben Drucken und Einklappen (je 34 px, Abstand 6 px) */
  '.wsz-3k{position:absolute;right:88px;top:8px;display:flex;gap:6px}',
  '.wsz-3k button{display:inline-flex;align-items:center;justify-content:center;width:34px;height:30px;padding:0;font-family:inherit;border:1px solid #1F3855;background:rgba(255,255,255,.92);color:#1F3855;cursor:pointer}',
  '.wsz-3k button:hover{background:#EEF2F6}',
  /* Symbole in Kartei-Groesse (sonst greift .wsz-buehne svg mit voller Breite) */
  '.wsz-3k svg.wdk-ic{width:16px;height:16px}',
  '.wsz-3s{display:none}',
  /* Handy: die Anlage ist klein, die Luftwege noch etwas duenner */
  '@media (max-width:560px){.wsz-ov3 .wsz-fl{stroke-width:2px}.wsz-ov3 .wsz-fl.wsz-fk{stroke-width:1.6px}.wsz-ov3 .wsz-fu{stroke-width:3.8px}}',

  '.wsz-3h{position:absolute;right:10px;bottom:12px;display:flex;gap:6px;pointer-events:none;transition:opacity .8s}',
  /* Handy-Runde (Dimi 12.11.2026, Prüfliste 25.2): am Handy die Knoepfe unten rechts, 40 x 40 px, nie unter der Legende */
  /* Handy-Runde 2: Drehen eingeschaltet – der Finger gehoert der Anlage, Knopf „✕ Fertig“ unten links */
  '.wsz-3d.ta canvas{touch-action:none}',
  '.wsz-3f{display:none}',
  '@media (pointer:coarse){.wsz-3d.ta .wsz-3f{display:flex;position:absolute;left:10px;bottom:10px;z-index:7;height:40px;padding:0 14px;align-items:center;border:0;background:#1F3855;color:#fff;font:700 14px/18px Arial,Helvetica,sans-serif;cursor:pointer;box-shadow:0 2px 8px rgba(16,30,48,.25)}.wsz-ta .wsz-schem{display:none}}',
  '@media (pointer:coarse){.wsz-3k{top:auto;bottom:10px;right:10px;z-index:6}.wsz-3k button{width:40px;height:40px}.wsz-3k svg.wdk-ic{width:18px;height:18px}.wsz-3h{display:none}}',
  /* doppelte Klasse: schlaegt .wsz-buehne svg und .wsy-bild svg (volle Breite) */
  '.w3hs.w3hs{display:block;flex:0 0 auto;width:34px;height:34px;max-width:none;padding:3px;box-sizing:border-box;background:rgba(255,255,255,.92);border:1px solid #C3CCD6}',
  '.wsz-3d.za::after{content:"";position:absolute;left:0;top:0;right:0;bottom:0;border:2px solid #1F3855;pointer-events:none;z-index:8}',
  '.wsz-3t{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);max-width:80%;text-align:center;font-size:14px;line-height:19px;color:#fff;background:rgba(31,56,85,.88);padding:8px 14px;pointer-events:none;opacity:0;transition:opacity .3s}',
  '.wsz-mod{display:inline-flex}',
  '.wsz-mod[hidden]{display:none}',
  '.wsz-kn .wsz-mod button{margin:0}',
  '.wsz-kn .wsz-mod button + button{border-left:0}',
  '.wsz-kn .wsz-mod button:disabled{opacity:.45;cursor:not-allowed}'
].join('');
/* Bedienhinweis als Symbole (Runde 13 der Szene, Dimi 10.11.2026: wie in CAD, ohne Text): dreh = Orbit um einen Wuerfel,
   zoom = Lupe mit Plus, schieb = Kreuz mit vier Pfeilen */
var HS_PFADE = {
  dreh: ['M14 8 L19 10.5 L14 13 L9 10.5 Z', 'M9 10.5 L9 16.5 L14 19 L19 16.5 L19 10.5', 'M14 13 L14 19', 'M3.5 16 A10.5 5 0 0 0 24.5 16', 'M21.6 13.6 L24.6 16 L21 17.4'],
  zoom: ['M17.2 17.2 L24 24', 'M8.6 12 L15.4 12', 'M12 8.6 L12 15.4'],
  schieb: ['M14 3.5 L14 24.5', 'M3.5 14 L24.5 14', 'M11.2 6.3 L14 3.5 L16.8 6.3', 'M11.2 21.7 L14 24.5 L16.8 21.7', 'M6.3 11.2 L3.5 14 L6.3 16.8', 'M21.7 11.2 L24.5 14 L21.7 16.8']
};
function hinweisSymbole(par, arten) {
  each(arten, function (a) {
    var s = sv('svg', { viewBox: '0 0 28 28', 'class': 'w3hs', focusable: 'false' }, par);
    if (a === 'zoom') { sv('circle', { cx: 12, cy: 12, r: 6.6, fill: 'none', stroke: '#1F3855', 'stroke-width': 1.7 }, s); }
    if (a === 'dreh') { sv('path', { d: 'M24.5 14 A10.5 5 0 0 0 3.5 14', fill: 'none', stroke: '#1F3855', 'stroke-width': 1.2, 'stroke-dasharray': '2 2.2', opacity: 0.7 }, s); }
    each(HS_PFADE[a] || [], function (d, i) {
      sv('path', { d: d, fill: (a === 'dreh' ? (i === 0 ? '#F7BC0C' : 'none') : 'none'), stroke: '#1F3855', 'stroke-width': 1.7, 'stroke-linecap': 'round', 'stroke-linejoin': 'round' }, s);
    });
  });
}

/* ---------- Bauteil einzeln in 3D (Kartei): drehen und zoomen (Dimi 09.11.2026) ----------
   Erfasst die Zeichnung des Bauteilbilds (SYM[pid], Bauform vi aus SYM[pid].v) mit D3 = true wie erfassen3() die Szene
   und zeichnet sie mit den Shadern der 3D-Ansicht (70_drei.js) in eine eigene WebGL-2-Flaeche. Gleiche Farben, Linien
   und Lichtfuehrung wie in der Szene; Rueckseiten erscheinen in der Innenfarbe.
   teil3d(box, pid, vi, o) setzt die Flaeche an die Stelle des Bildes (o.svg, sonst das erste svg in box) und gibt
   { an(), aus(), zu(), zurueck(), bereich(k), bauform(vi, weich), kamera(), info() } zurueck. Runde 9 der Szene (Dimi
   09.11.2026): keine Knoepfe mehr im Bild; die Kartei startet die Ansicht gleich (symbolBlock), Antippen der Bauteil-Kachel
   setzt sie zurueck (zurueck). o.weg: Rueckruf, wenn sich die Ansicht selbst freigibt (Kartei neu aufgebaut);
   o.beruehrt: Rueckruf beim ersten Drehen, Schieben oder Zoomen; o.h: Hoehe in px.
   Regel: auch in den Shadern keine Zeichen Kleiner, Groesser, Kaufmanns-Und. */
var T3C = {}, T3N = 0;
/* Geometrie einer Bauform (zwischengespeichert) */
function teilErfassen(pid, vi) {
  var key = pid + '|' + (vi || 0);
  if (T3C[key]) { return T3C[key]; }
  var S0 = SYM[pid]; if (!S0) { return null; }
  var S = S0;
  if (vi) { if (S0.v) { if (S0.v[vi - 1]) { S = S0.v[vi - 1]; } } }
  var aIT = IT, aSEQ = SEQ, aF = FLOWS, aM = MARKEN, aZ = ZONEN, aP = PIDNOW, aA = AREA, aX = FXL, aN = INNENT, aI = INS, aMs = MASSE, it = null, ms = null;
  IT = []; SEQ = 0; FLOWS = []; MARKEN = []; ZONEN = []; AREA = null; FXL = null; INNENT = false; PIDNOW = pid; MASSE = [];
  D3 = true; INS = true;
  try { S.f(); } finally {
    D3 = false; it = IT; ms = MASSE;
    IT = aIT; SEQ = aSEQ; FLOWS = aF; MARKEN = aM; ZONEN = aZ; PIDNOW = aP; AREA = aA; FXL = aX; INNENT = aN; INS = aI; MASSE = aMs;
  }
  T3C[key] = { it: it, gh: S0.ghost, ms: ms };
  return T3C[key];
}
/* Puffer: deckende und durchscheinende Flaechen, Linien; je Ecke bzw. Linie die Bereichsnummer + 1 (0 = kein Bereich)
   im freien Byte (Flaeche: Byte 21) bzw. in der 4. Komponente der Normalen A (Linie) */
/* Flaechen, die auf einer frueheren in derselben Ebene liegen (Dichtband und Eckwinkel am Rahmen, Skala, Tuer ...): in der
   Zeichnung regelt die Reihenfolge, in 3D flimmerten beide. Die spaetere Flaeche wird je Lage um 0,3 mm entlang ihrer
   Normalen angehoben (hoechstens 3 Lagen; Linien liegen 1 mm davor und bleiben sichtbar). Rueckgabe: Hub in mm je Eintrag */
function teilLagen(it) {
  var F = [], hub = {};
  each(it, function (o, i) {
    if (o.t !== 'f') { return; } if (!o.p3) { return; } if (o.inn) { return; } if (lt(o.p3.length, 3)) { return; }
    var n = nz(o.n || newell(o.p3)), b = [1e9, 1e9, 1e9, -1e9, -1e9, -1e9];
    each(o.p3, function (p) { for (var k = 0; k !== 3; k++) { b[k] = Math.min(b[k], p[k]); b[k + 3] = Math.max(b[k + 3], p[k]); } });
    F.push({ i: i, n: n, d: dt(o.p3[0], n), b: b, p: o.p3, lage: 0 });
  });
  function kasten(A, C) {
    for (var k = 0; k !== 3; k++) { if (gt(A.b[k], C.b[k + 3] + 0.1)) { return false; } if (gt(C.b[k], A.b[k + 3] + 0.1)) { return false; } }
    return true;
  }
  /* Ueberdeckung in der Ebene (Trennachsen der Kanten; Beruehren an einer Kante zaehlt nicht) */
  function deckt(A, C) {
    var e1 = nz(cr(C.n, gt(Math.abs(C.n[0]), 0.9) ? [0, 1, 0] : [1, 0, 0])), e2 = cr(C.n, e1);
    function flach(P) { return P.map(function (p) { return [dt(p, e1), dt(p, e2)]; }); }
    var PA = flach(A.p), PC = flach(C.p), ok = true;
    function achsen(P) {
      for (var k = 0; k !== P.length; k++) {
        var q = P[k], r = P[(k + 1) % P.length], ax = [q[1] - r[1], r[0] - q[0]], l = Math.sqrt(ax[0] * ax[0] + ax[1] * ax[1]);
        if (!gt(l, 1e-6)) { continue; }
        var a0 = 1e9, a1 = -1e9, c0 = 1e9, c1 = -1e9;
        each(PA, function (x) { var v = (x[0] * ax[0] + x[1] * ax[1]) / l; a0 = Math.min(a0, v); a1 = Math.max(a1, v); });
        each(PC, function (x) { var v = (x[0] * ax[0] + x[1] * ax[1]) / l; c0 = Math.min(c0, v); c1 = Math.max(c1, v); });
        if (!gt(Math.min(a1, c1) - Math.max(a0, c0), 0.5)) { ok = false; return; }
      }
    }
    achsen(PA); if (ok) { achsen(PC); }
    return ok;
  }
  for (var a = 1; lt(a, F.length); a++) {
    var A = F[a];
    for (var c = 0; c !== a; c++) {
      var C = F[c];
      if (!kasten(A, C)) { continue; }
      if (lt(Math.abs(dt(A.n, C.n)), 0.9995)) { continue; }
      if (gt(Math.abs(dt(A.p[0], C.n) - C.d), 0.05)) { continue; }
      if (deckt(A, C)) { A.lage = Math.max(A.lage, C.lage + 1); }
    }
    if (A.lage) { hub[A.i] = Math.min(A.lage, 3) * 0.3; }
  }
  return hub;
}
function teilPuffer(E) {
  var F = { op: { W: new Wachs(24), I: new Liste32(false) }, gl: { W: new Wachs(24), I: new Liste32(false) } };
  var L = new Wachs(48), PE = [], bb = [1e9, 1e9, 1e9, -1e9, -1e9, -1e9], used = {}, nf = 0, nl = 0;
  if (!E.hub) { E.hub = teilLagen(E.it); }
  each(E.it, function (o, ix) {
    if (!o.p3) { return; }
    if (o.t === 't') { return; }
    /* Innenflaechen der Zeichnung (innenTeil, Material i) liegen auf den Waenden; in 3D zeigen deren Rueckseiten
       die Innenfarbe selbst, die Doppelung wuerde flimmern */
    if (o.inn) { return; }
    var a = (o.a === undefined || o.a === null) ? -1 : o.a, x = o, v, s;
    /* Traeger (z. B. Grundrohr beim Sattelstutzen) blass wie im Bild */
    if (E.gh !== undefined) { if (a === E.gh) { x = ext(o, { op: 0.3 }); } }
    /* Gehaeuse des Schalldaempfers (Klasse sdw) durchscheinend wie beim Oeffnen in der Szene: die Kulissen sind das Teil */
    if (o.cls === 'sdw') { x = ext(x, { op: o.t === 'f' ? 0.22 : 0.45, cls: null }); }
    if (E.hub[ix]) { var hn = mu(nz(o.n || newell(o.p3)), E.hub[ix]); x = ext(x, { p3: o.p3.map(function (p) { return ad(p, hn); }) }); }
    if (o.t === 'f') {
      var k = klasse3(x); if (k === 'tr') { return; } if (k === 'sd') { k = 'op'; }
      var W = F[k].W, n0 = W.n;
      flaeche3(x, W, F[k].I);
      for (v = n0; v !== W.n; v++) { W.u8[v * 24 + 21] = a + 1; }
      if (W.n !== n0) { nf++; }
      each(x.p3, function (p) { PE.push(p); for (var j = 0; j !== 3; j++) { bb[j] = Math.min(bb[j], p[j]); bb[j + 3] = Math.max(bb[j + 3], p[j]); } });
      if (a !== -1) { used[a] = 1; }
    } else if (o.t === 'l') {
      var s0 = L.n;
      linie3(x, L);
      for (s = s0; s !== L.n; s++) { L.i16[s * 24 + 15] = a + 1; }
      nl += L.n - s0;
    }
  });
  return { F: F, L: L, PE: PE, bb: bb, used: used, nf: nf, nl: nl, nh: Object.keys(E.hub).length };
}
/* Shader der Szene mit Hervorhebung von Bereichen: uBer = Summe von 2 hoch Bereich (0 = keiner); die Ecken tragen
   Bereich + 1 (0 = kein Bereich). Mehrere Bereiche fuer zusammengelegte Zeilen der Tabelle (Runde 9) */
function teilShader() {
  var vf = VS_F.replace('uniform float uS;', 'uniform float uS; uniform float uBer;')
    .replace('int mi = int(min(mat, 12.0) + 0.5);', 'float ab = floor(aM.y + 0.5); float hb = step(0.5, ab) * mod(floor(uBer / exp2(ab - 1.0)), 2.0); int mi = int(mix(min(mat, 12.0), 11.0, hb) + 0.5);')
    .replace('float fx = step(19.5, mat);', 'cb = mix(cb, schatt(11, -nl), hb); float fx = step(19.5, mat) * (1.0 - hb);');
  var vl = VS_L.replace('uniform float uBias;', 'uniform float uBias; uniform float uBer;')
    .replace('void main() {', 'void main() {\n  float ab = floor(aNA.w * 32767.0 + 0.5); float hb = step(0.5, ab) * mod(floor(uBer / exp2(ab - 1.0)), 2.0);')
    .replace('float w = max(aX.x / 40.0 * uWk, uWmin) * sil;', 'float w = max(aX.x / 40.0 * uWk, uWmin) * sil * (1.0 + 0.7 * hb);')
    .replace('vec3 c = aC.rgb;', 'vec3 c = mix(aC.rgb, vec3(0.663, 0.478, 0.0), hb);');
  return { vf: vf, vl: vl };
}
var CSST3 = [
  '.wt3{position:relative;width:100%;background:#fff;overflow:hidden}',
  '.wt3 canvas{display:block;width:100%;height:100%;touch-action:pan-y;cursor:grab;outline:none}',
  /* Handy-Runde 2: Drehen eingeschaltet, Knopf „✕ Fertig“ oben links */
  '.wt3.ta canvas{touch-action:none}',
  '.wt3-f{display:none}',
  '@media (pointer:coarse){.wt3.ta .wt3-f{display:flex;position:absolute;left:6px;top:6px;z-index:7;height:36px;padding:0 12px;align-items:center;border:0;background:#1F3855;color:#fff;font:700 13px/16px Arial,Helvetica,sans-serif;cursor:pointer;box-shadow:0 2px 8px rgba(16,30,48,.25)}}',
  '.wt3 canvas.zieh{cursor:grabbing}',
  '.wt3 canvas:focus-visible{box-shadow:inset 0 0 0 2px #1F3855}',
  '.wt3.za::after{content:"";position:absolute;left:0;top:0;right:0;bottom:0;border:2px solid #1F3855;pointer-events:none;z-index:6}',
  '.wt3-h{position:absolute;right:8px;bottom:7px;display:flex;gap:5px;pointer-events:none;transition:opacity .8s}',
  /* Wechsel nacheinander (Dimi 09.11.2026, Runde 11 Punkt 12): ausblenden, tauschen, einblenden */
  '.wt3 canvas,.wt3 .wt3-ms{transition:opacity .45s ease}',
  '.wt3.blend canvas,.wt3.blend .wt3-ms{opacity:0}',
  '.wt3-ms{position:absolute;left:0;top:0;width:100%;height:100%;pointer-events:none;overflow:visible}',
  '.wt3-ms text{font:italic 700 15px Georgia,"Times New Roman",serif;fill:#14304F;paint-order:stroke;stroke:#fff;stroke-width:4px;stroke-linejoin:round}',
  '.wt3-h .w3hs.w3hs{width:30px;height:30px}',
  '.wt3-t{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);max-width:86%;text-align:center;font-size:12px;line-height:16px;color:#fff;background:rgba(31,56,85,.88);padding:6px 10px;pointer-events:none;opacity:0;transition:opacity .3s}'
].join('');
function t3Css() {
  if (document.getElementById('wsz-t3css')) { return; }
  stilEinsetzen('wsz-t3css', CSST3);
}
/* Eckpunkte ohne Doppelte (fuer Ausschnitt und Mitte) */
function teilPunkte(PE) {
  var M = {}, r = [];
  each(PE, function (p) { var k = Math.round(p[0]) + ',' + Math.round(p[1]) + ',' + Math.round(p[2]); if (!M[k]) { M[k] = 1; r.push(p); } });
  return r;
}
/* 3D-Punkte der Massketten (Runde 10 der Szene): mit eingeschalteten Massen passen Teil und Masse samt Buchstaben ins Bild */
function massPunkte(ms) {
  var r = [];
  each(ms || [], function (m) {
    if (m.art === 'lin') {
      var q0 = ad(m.a, m.c), q1 = ad(m.b, m.c);
      if (m.d) { var dd = nz(m.d); q1 = ad(q0, mu(dd, dt(sb(m.b, m.a), dd))); }
      var ue = mu(m.c, 0.45);
      r.push(q0, q1, ad(q0, ue), ad(q1, ue));
    } else if (m.art === 'dm') {
      var ax = nz(m.b), d0 = nz(m.d || cr(ax, gt(Math.abs(ax[2]), 0.9) ? EX : EZ));
      r.push(ad(m.a, mu(d0, -m.c)), ad(m.a, mu(d0, m.c * 1.75)));
    } else if (m.art === 'rad') { r.push(m.a, m.b); }
    else if (m.art === 'win') { r.push(ad(m.a, mu(nz(m.b), m.d * 1.35)), ad(m.a, mu(nz(m.c), m.d * 1.35))); }
  });
  return r;
}
function teilAchsen(az, el) {
  var ca = Math.cos(az), sa = Math.sin(az), ce = Math.cos(el), se = Math.sin(el);
  var v = [ce * ca, ce * sa, se], r = [sa, -ca, 0];
  return { v: v, r: r, u: cr(r, v) };
}
/* Ausdehnung in Bildrichtung: Mitte (cx, cy) und Breite, Hoehe (ex, ey) */
function teilAusdehnung(P, A) {
  var x0 = 1e9, x1 = -1e9, y0 = 1e9, y1 = -1e9;
  each(P, function (p) {
    var a = dt(p, A.r), c = dt(p, A.u);
    if (lt(a, x0)) { x0 = a; } if (gt(a, x1)) { x1 = a; } if (lt(c, y0)) { y0 = c; } if (gt(c, y1)) { y1 = c; }
  });
  if (!gt(x1, x0)) { x0 = -1; x1 = 1; } if (!gt(y1, y0)) { y0 = -1; y1 = 1; }
  return { cx: (x0 + x1) / 2, cy: (y0 + y1) / 2, ex: x1 - x0, ey: y1 - y0 };
}
/* Ausdehnung aus vielen Blickrichtungen (einmal je Bauform): daraus der Massstab, bei dem das Teil beim Drehen im Bild bleibt */
var T3EL = [-89.5, -70, -50, -30, -10, 10, 30, 50, 70, 89.5];
function teilBlicke(P) {
  var r = [];
  for (var a = 0; a !== 24; a++) { each(T3EL, function (e) { r.push(teilAusdehnung(P, teilAchsen(a * Math.PI / 12, e * Math.PI / 180))); }); }
  return r;
}
/* Freies Drehen wie eine Kugel unter der Hand (Runde 12 der Szene, Dimi 10.11.2026: „man zieht daran, aber es dreht sich fast nicht“):
   die Lage der Kamera ist eine Basis A = {r, u, v} (rechts, oben, zur Kamera). Ziehen waagerecht dreht um die Bildsenkrechte,
   senkrecht um die Bildwaagerechte, ohne Anschlag und ohne Pol. Zuruecksetzen fuehrt ueber Quaternionen (slerp) in die Ausgangslage. */
function t3Ortho(A) { var v = nz(A.v), r = nz(sb(A.r, mu(v, dt(A.r, v)))); return { r: r, v: v, u: cr(r, v) }; }
function t3Dreh(A, a, b) {
  var ca = Math.cos(a), sa = Math.sin(a), cb = Math.cos(b), sbb = Math.sin(b);
  var v1 = sb(mu(A.v, ca), mu(A.r, sa)), r1 = ad(mu(A.r, ca), mu(A.v, sa)), u1 = A.u;
  var v2 = ad(mu(v1, cb), mu(u1, sbb)), u2 = sb(mu(u1, cb), mu(v1, sbb));
  return t3Ortho({ r: r1, u: u2, v: v2 });
}
/* Basis als Drehung (Zeilen r, u, -v) und zurueck */
function t3Quat(A) {
  var w3 = mu(A.v, -1), m = [A.r, A.u, w3], tr = m[0][0] + m[1][1] + m[2][2], q, s;
  if (gt(tr, 0)) { s = Math.sqrt(tr + 1) * 2; q = [0.25 * s, (m[2][1] - m[1][2]) / s, (m[0][2] - m[2][0]) / s, (m[1][0] - m[0][1]) / s]; }
  else if (gt(m[0][0], m[1][1]) ? gt(m[0][0], m[2][2]) : false) { s = Math.sqrt(1 + m[0][0] - m[1][1] - m[2][2]) * 2; q = [(m[2][1] - m[1][2]) / s, 0.25 * s, (m[0][1] + m[1][0]) / s, (m[0][2] + m[2][0]) / s]; }
  else if (gt(m[1][1], m[2][2])) { s = Math.sqrt(1 + m[1][1] - m[0][0] - m[2][2]) * 2; q = [(m[0][2] - m[2][0]) / s, (m[0][1] + m[1][0]) / s, 0.25 * s, (m[1][2] + m[2][1]) / s]; }
  else { s = Math.sqrt(1 + m[2][2] - m[0][0] - m[1][1]) * 2; q = [(m[1][0] - m[0][1]) / s, (m[0][2] + m[2][0]) / s, (m[1][2] + m[2][1]) / s, 0.25 * s]; }
  return q;
}
function t3Basis(q) {
  var w = q[0], x = q[1], y = q[2], z = q[3];
  var r = [1 - 2 * (y * y + z * z), 2 * (x * y - z * w), 2 * (x * z + y * w)];
  var u = [2 * (x * y + z * w), 1 - 2 * (x * x + z * z), 2 * (y * z - x * w)];
  var w3 = [2 * (x * z - y * w), 2 * (y * z + x * w), 1 - 2 * (x * x + y * y)];
  return t3Ortho({ r: r, u: u, v: mu(w3, -1) });
}
function t3Slerp(a, b, t) {
  var d = a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3], c = b.slice();
  if (lt(d, 0)) { d = -d; c = c.map(function (x) { return -x; }); }
  if (gt(d, 0.9995)) { var l = a.map(function (x, i) { return x + (c[i] - x) * t; }), n = Math.sqrt(l[0] * l[0] + l[1] * l[1] + l[2] * l[2] + l[3] * l[3]); return l.map(function (x) { return x / n; }); }
  var th = Math.acos(d), s0 = Math.sin((1 - t) * th) / Math.sin(th), s1 = Math.sin(t * th) / Math.sin(th);
  return a.map(function (x, i) { return x * s0 + c[i] * s1; });
}
/* Massketten (Runde 11, Punkt 11): Elemente aus MASSE der Zeichnung (50_symbole.js mass), projiziert je Bild */
var MASSE_AN = false;
function teil3d(box, pid, vi, o) {
  o = o || {}; vi = vi || 0;
  if (!dreiMoeglich()) { return null; }
  var E = teilErfassen(pid, vi); if (!E) { return null; }
  t3Css();
  var svg = o.svg || box.querySelector('svg');
  /* Hoehe wie das Bild (kein Springen der Kartei), mindestens 200 px */
  var h0 = o.h || (svg ? Math.round(svg.getBoundingClientRect().height) : 0);
  var wrap = ht('div', 'wt3', null, null);
  if (svg) { if (svg.parentNode) { svg.parentNode.insertBefore(wrap, svg); } } else { box.appendChild(wrap); }
  wrap.style.height = Math.max(200, h0) + 'px';
  var cv = ht('canvas', null, null, wrap);
  cv.setAttribute('tabindex', '0');
  var bt = BT[pid];
  cv.setAttribute('aria-label', '3D-Modell ' + (bt ? bt.t : pid) + ': ziehen oder Pfeiltasten drehen, Mausrad nach einer Mausbewegung im Modell, zwei Finger oder Plus und Minus zoomen, Doppelklick oder 0 setzt zurück');
  var touch = false;
  try { touch = window.matchMedia('(pointer: coarse)').matches; } catch (e) { touch = false; }
  /* kurzer Hinweis, blendet nach wenigen Sekunden aus (Dimi 09.11.2026: weniger Text im Feld) */
  /* Runde 13 der Szene (Dimi 10.11.2026): statt „Ziehen: drehen“ ein Symbol wie in CAD (Orbit), kurz sichtbar, dann ausgeblendet */
  var hin = ht('div', 'wt3-h', null, wrap);
  hin.setAttribute('aria-hidden', 'true');
  hinweisSymbole(hin, touch ? ['dreh', 'zoom'] : ['dreh']);
  var hinT = window.setTimeout(function () { hin.style.opacity = '0'; }, 2600);
  /* Dimi 11.11.2026, 07:54: das Mausrad scrollt immer die Seite; Zoomen mit Strg + Mausrad, den Knoepfen oder zwei Fingern */
  var toast = ht('div', 'wt3-t', 'Zwei Finger: zoomen', wrap), toastT = null;
  var MS = sv('svg', { 'class': 'wt3-ms', 'aria-hidden': 'true' }, wrap), msE = E.ms || [];
  var gl = cv.getContext('webgl2', { antialias: true, alpha: false, premultipliedAlpha: true, preserveDrawingBuffer: !!o.test });
  if (!gl) { wrap.parentNode.removeChild(wrap); return null; }
  if (svg) { svg.style.display = 'none'; }
  T3N++;
  var GLO = { b: [], v: [], s: [], p: [] };
  function sh(typ, src) { var s = glShader(gl, typ, src); GLO.s.push(s); return s; }
  function pr(vs, fs, attr) { var p = glProg(gl, vs, fs, attr); GLO.p.push(p.p); return p; }
  function pu(typ, d) { var x = glPuffer(gl, typ, d); GLO.b.push(x); return x; }
  var SH = teilShader();
  var AF = ['aP', 'aN', 'aC', 'aM', 'aG'], AL = ['aT', 'aA', 'aB', 'aNA', 'aNB', 'aC', 'aX', 'aG'];
  var PF = pr(sh(gl.VERTEX_SHADER, SH.vf), sh(gl.FRAGMENT_SHADER, FS_F), AF);
  var PL = pr(sh(gl.VERTEX_SHADER, SH.vl), sh(gl.FRAGMENT_SHADER, FS_L), AL);
  var pal = new Float32Array(56 * 3);
  each(MATK.concat(['n']), function (k, i) { each(k === 'n' ? INNEN3 : MAT[k], function (hx, j) { var q = rgb(hx); pal[(i * 4 + j) * 3] = q[0] / 255; pal[(i * 4 + j) * 3 + 1] = q[1] / 255; pal[(i * 4 + j) * 3 + 2] = q[2] / 255; }); });
  var tpl = pu(gl.ARRAY_BUFFER, new Float32Array([0, -1, 1, -1, 1, 1, 0, 1])), tib = pu(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array([0, 1, 2, 0, 2, 3]));
  /* Modell (je Bauform neu): Puffer, Eckpunkte, Ausdehnung aus allen Blickrichtungen */
  var MG = null, B = null, P = null, BL = null, VF = null, VL = null, RZ = 1, C3 = [0, 0, 0], RP = 1;
  /* Punkte fuer Mitte und Massstab: das Teil, mit eingeschalteten Massen auch die Massketten */
  function punkte() {
    P = teilPunkte(MASSE_AN ? (msE.length ? B.PE.concat(massPunkte(msE)) : B.PE) : B.PE); BL = teilBlicke(P); RP = 1;
    each(BL, function (x) { RP = Math.max(RP, x.ex / 2, x.ey / 2); });
  }
  /* oben rechts liegen die Knoepfe (Masse, Drucken): mit Massen bleibt ein Streifen frei, das Bild rueckt etwas nach unten */
  function OY() { return MASSE_AN ? (msE.length ? -15 : 0) : 0; }
  function laden(E2) {
    if (MG) { each(MG.v, function (x) { gl.deleteVertexArray(x); }); each(MG.b, function (x) { gl.deleteBuffer(x); }); }
    MG = { b: [], v: [] };
    function pm(typ, d) { var x = glPuffer(gl, typ, d); MG.b.push(x); return x; }
    B = teilPuffer(E2);
    RZ = len([B.bb[3] - B.bb[0], B.bb[4] - B.bb[1], B.bb[5] - B.bb[2]]) * 1.2 + 400;
    C3 = [(B.bb[0] + B.bb[3]) / 2, (B.bb[1] + B.bb[4]) / 2, (B.bb[2] + B.bb[5]) / 2];
    punkte();
    VF = {};
    each(['op', 'gl'], function (k) {
      var f = B.F[k], va = vaoF(gl, pm(gl.ARRAY_BUFFER, f.W.daten()), pm(gl.ELEMENT_ARRAY_BUFFER, f.I.daten()), null);
      MG.v.push(va); VF[k] = { vao: va, n: f.I.n };
    });
    var vl0 = vaoL(gl, tpl, tib, pm(gl.ARRAY_BUFFER, B.L.daten()), null); MG.v.push(vl0);
    VL = { vao: vl0, n: B.L.n };
  }
  laden(E);
  /* Kamera: Blickrichtung az/el, Massstab S (px je mm), Verschiebung D (px). Das Teil bleibt beim Drehen in der Bildmitte
     (Mitte seiner Ausdehnung in der jeweiligen Blickrichtung); S0 ist so gewaehlt, dass es dabei im Bild bleibt
     (hoechstens 20 % kleiner als in der Ausgangslage noetig waere). */
  var Wc = 1, Hc = 1, dpr = 1, S0 = 0, K = kNeu(ISO_AZ, ISO_EL, 0.1, [0, 0]), ANI = null, BER = 0, aktiv = false, raf = null, weg = false;
  function kNeu(az, el, S, D) { return { az: az, el: el, S: S, D: D.slice(), A: teilAchsen(az, el) }; }
  var SMIN = 0.001, SMAX = 100, scharf = false;
  function massstab() {
    var g = teilAusdehnung(P, teilAchsen(ISO_AZ, ISO_EL));
    var Hn = Math.max(60, Hc + 2 * OY()), si = Math.min(Wc / g.ex, Hn / g.ey) * 0.86, sa = 1e9;
    each(BL, function (x) { sa = Math.min(sa, Math.min(Wc / x.ex, Hn / x.ey)); });
    return Math.min(si, Math.max(sa * 0.94, si * 0.8));
  }
  function neuMassstab() {
    var s1 = massstab();
    if (gt(S0, 0)) { K.S = K.S * s1 / S0; }
    S0 = s1; SMIN = S0 * 0.4; SMAX = S0 * 12;
  }
  function matrix(A) {
    var g = teilAusdehnung(P, A), sx = 2 * K.S / Wc, sy = 2 * K.S / Hc, sz = 1 / RZ, r = A.r, u = A.u, v = A.v;
    return new Float32Array([r[0] * sx, u[0] * sy, -v[0] * sz, 0, r[1] * sx, u[1] * sy, -v[1] * sz, 0, r[2] * sx, u[2] * sy, -v[2] * sz, 0,
      -g.cx * sx + 2 * K.D[0] / Wc, -g.cy * sy + 2 * (K.D[1] + OY()) / Hc, dt(C3, v) * sz, 1]);
  }
  function grenzen() {
    K.S = Math.max(SMIN, Math.min(SMAX, K.S));
    var mx = Math.max(0, Wc / 2 + RP * K.S - 40), my = Math.max(0, Hc / 2 + RP * K.S - 40);
    K.D = [Math.max(-mx, Math.min(mx, K.D[0])), Math.max(-my, Math.min(my, K.D[1]))];
  }
  function jetzt() { return window.performance ? window.performance.now() : Date.now(); }
  function winkel(a, c) { var d = c - a; while (gt(d, Math.PI)) { d -= 2 * Math.PI; } while (lt(d, -Math.PI)) { d += 2 * Math.PI; } return d; }
  function winkelNorm(x) { while (gt(x, Math.PI)) { x -= 2 * Math.PI; } while (lt(x, -Math.PI)) { x += 2 * Math.PI; } return x; }
  /* Uebergang (bei reduzierter Bewegung sofort) */
  function fahre(z, ms) {
    if (!bewegungErlaubt()) { ANI = null; K = kNeu(z.az, z.el, z.S, z.D); grenzen(); anfordern(); return; }
    ANI = { a: { q: t3Quat(K.A), S: K.S, D: K.D.slice() }, z: z, zq: t3Quat(teilAchsen(z.az, z.el)), t0: jetzt(), d: ms || 520 }; anfordern();
  }
  function groesse() {
    var w = Math.max(50, wrap.clientWidth || 300), h = Math.max(50, wrap.clientHeight || 230);
    if (w === Wc) { if (h === Hc) { return; } }
    var w0 = Wc, h0b = Hc;
    dpr = Math.min(window.devicePixelRatio || 1, 2);
    cv.width = Math.round(w * dpr); cv.height = Math.round(h * dpr);
    Wc = w; Hc = h;
    K.D = [K.D[0] * w / w0, K.D[1] * h / h0b];
    neuMassstab(); grenzen();
    anfordern();
  }
  /* Zeichnen */
  function zeichnen() {
    /* Licht folgt der Waagerechten der Kamera (wie frueher dem Azimut) */
    var A = K.A, M = matrix(A), th = ISO_AZ - Math.atan2(A.r[0], -A.r[1]);
    gl.viewport(0, 0, cv.width, cv.height);
    gl.clearColor(1, 1, 1, 1); gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
    gl.enable(gl.DEPTH_TEST); gl.depthFunc(gl.LEQUAL); gl.depthMask(true); gl.disable(gl.BLEND); gl.disable(gl.CULL_FACE);
    function uf() {
      gl.useProgram(PF.p);
      gl.uniformMatrix4fv(PF.u.uM, false, M); gl.uniform3fv(PF.u.uV, A.v); gl.uniform2f(PF.u.uRz, Math.cos(th), Math.sin(th));
      gl.uniform1f(PF.u.uS, 1); gl.uniform3fv(PF.u.uPal, pal); gl.uniform1f(PF.u.uDim, 0); gl.uniform1f(PF.u.uAl, 1); gl.uniform1f(PF.u.uPass, 0);
      gl.uniform1f(PF.u.uBer, BER); gl.vertexAttrib3f(4, 0, 0, 0);
    }
    function zf(x) { if (x.n) { gl.bindVertexArray(x.vao); gl.drawElements(gl.TRIANGLES, x.n, gl.UNSIGNED_INT, 0); } }
    uf(); zf(VF.op);
    gl.enable(gl.BLEND); gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
    gl.useProgram(PL.p);
    gl.uniformMatrix4fv(PL.u.uM, false, M); gl.uniform3fv(PL.u.uV, A.v);
    gl.uniform2f(PL.u.uPx, 2 / cv.width, 2 / cv.height); gl.uniform1f(PL.u.uWk, dpr); gl.uniform1f(PL.u.uWmin, 0); gl.uniform1f(PL.u.uS, 1);
    gl.uniform1f(PL.u.uBias, 1 / RZ); gl.uniform1f(PL.u.uDim, 0); gl.uniform1f(PL.u.uAl, 1); gl.uniform1f(PL.u.uBer, BER);
    gl.vertexAttrib3f(7, 0, 0, 0);
    if (VL.n) { gl.bindVertexArray(VL.vao); gl.drawElementsInstanced(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0, VL.n); }
    /* durchscheinende Flaechen (Traeger): erst Rueckseiten, dann Vorderseiten */
    if (VF.gl.n) {
      gl.depthMask(false); uf();
      gl.uniform1f(PF.u.uPass, 1); zf(VF.gl);
      gl.uniform1f(PF.u.uPass, 2); zf(VF.gl);
      gl.uniform1f(PF.u.uPass, 0); gl.depthMask(true);
    }
    gl.bindVertexArray(null);
    masseZeichnen(A);
  }
  /* Punkt p (mm) auf die Flaeche (px) */
  function proj(A, g, p) { return [K.S * (dt(p, A.r) - g.cx) + K.D[0] + Wc / 2, Hc / 2 - (K.S * (dt(p, A.u) - g.cy) + K.D[1] + OY())]; }
  function masseZeichnen(A) {
    while (MS.firstChild) { MS.removeChild(MS.firstChild); }
    if (!MASSE_AN) { return; } if (!msE.length) { return; }
    MS.setAttribute('viewBox', '0 0 ' + Wc + ' ' + Hc);
    var g = teilAusdehnung(P, A), L = sv('g', { stroke: '#14304F', 'stroke-width': 1.15, fill: 'none' }, MS), T = sv('g', {}, MS);
    function pr(p) { return proj(A, g, p); }
    function pf(q) { return 'M' + q.map(function (x) { return f1(x[0]) + ' ' + f1(x[1]); }).join(' L'); }
    function pfeil(a, b) {
      var dx = b[0] - a[0], dy = b[1] - a[1], l = Math.sqrt(dx * dx + dy * dy); if (!gt(l, 0.5)) { return; }
      var ux = dx / l, uy = dy / l, s = 9, w = 3.2;
      sv('path', { d: pf([[b[0] - ux * s - uy * w, b[1] - uy * s + ux * w], b, [b[0] - ux * s + uy * w, b[1] - uy * s - ux * w]]) + ' Z', fill: '#14304F', stroke: 'none' }, L);
    }
    function text(t, q, nx, ny) { var x = sv('text', { x: f1(q[0] + nx * 11), y: f1(q[1] + ny * 11 + 5), 'text-anchor': 'middle' }, T); x.textContent = t; }
    function senk(a, b) { var dx = b[0] - a[0], dy = b[1] - a[1], l = Math.sqrt(dx * dx + dy * dy) || 1; return [-dy / l, dx / l]; }
    each(msE, function (m) {
      if (m.art === 'lin') {
        /* m.d: Messrichtung (ausgerichtetes Mass, z. B. nur die Laenge entlang der Achse); Hilfslinien je Punkt bis zur Masslinie */
        var p0 = m.a, p1 = m.b, v = m.c, q0 = ad(p0, v), q1 = ad(p1, v);
        if (m.d) { var dd = nz(m.d); q1 = ad(q0, mu(dd, dt(sb(p1, p0), dd))); }
        var v1 = sb(q1, p1), e0 = ad(p0, mu(v, 0.12)), e1 = ad(p1, mu(v1, 0.12)), u0 = ad(p0, mu(v, 1.12)), u1 = ad(p1, mu(v1, 1.12));
        if (gt(len(v1), 1.12 * len(v) + 20)) { e1 = ad(q1, mu(nz(v1), -0.12 * len(v) - len(v1) + 0.12 * len(v))); e1 = ad(p1, mu(nz(v1), 8)); u1 = ad(q1, mu(nz(v1), 0.12 * len(v))); }
        var s0 = pr(q0), s1 = pr(q1);
        sv('path', { d: pf([pr(e0), pr(u0)]) + ' ' + pf([pr(e1), pr(u1)]), 'stroke-width': 0.8, opacity: 0.85 }, L);
        sv('path', { d: pf([s0, s1]) }, L);
        pfeil(s1, s0); pfeil(s0, s1);
        var mi = [(s0[0] + s1[0]) / 2, (s0[1] + s1[1]) / 2], n = senk(s0, s1), vv = pr(ad(lp(q0, q1, 0.5), mu(v, 0.3)));
        if (lt((vv[0] - mi[0]) * n[0] + (vv[1] - mi[1]) * n[1], 0)) { n = [-n[0], -n[1]]; }
        text(m.t, mi, n[0], n[1]);
      } else if (m.art === 'dm') {
        var c = m.a, ax = nz(m.b), r = m.c, d0 = nz(m.d || cr(ax, gt(Math.abs(ax[2]), 0.9) ? EX : EZ));
        var a0 = pr(ad(c, mu(d0, -r))), a1 = pr(ad(c, mu(d0, r))), ue = pr(ad(c, mu(d0, r * 1.45)));
        sv('path', { d: pf([a0, ue]) }, L);
        pfeil(ue, a1); pfeil(pr(ad(c, mu(d0, -r * 0.2))), a0);
        var n2 = senk(a0, ue); text(m.t, [(a1[0] + ue[0]) / 2, (a1[1] + ue[1]) / 2], n2[0], n2[1]);
      } else if (m.art === 'rad') {
        var cc = pr(m.a), pp = pr(m.b);
        sv('path', { d: pf([cc, pp]), 'stroke-dasharray': '0' }, L); pfeil(cc, pp);
        sv('circle', { cx: f1(cc[0]), cy: f1(cc[1]), r: 2, fill: '#14304F', stroke: 'none' }, L);
        var n3 = senk(cc, pp); text(m.t, [(cc[0] + pp[0]) / 2, (cc[1] + pp[1]) / 2], n3[0], n3[1]);
      } else if (m.art === 'win') {
        var c0 = m.a, w1 = nz(m.b), w2 = nz(m.c), rr = m.d, q = [], nn = 18, ang = Math.acos(Math.max(-1, Math.min(1, dt(w1, w2)))), w3 = nz(sb(w2, mu(w1, dt(w1, w2))));
        for (var i = 0; i !== nn + 1; i++) { var t = ang * i / nn; q.push(pr(ad(c0, ad(mu(w1, rr * Math.cos(t)), mu(w3, rr * Math.sin(t)))))); }
        sv('path', { d: pf(q) }, L); pfeil(q[1], q[0]); pfeil(q[nn - 1], q[nn]);
        var cm = pr(c0), qm = q[Math.round(nn / 2)], dx = qm[0] - cm[0], dy = qm[1] - cm[1], dl = Math.sqrt(dx * dx + dy * dy) || 1;
        text(m.t, qm, dx / dl, dy / dl);
      }
    });
  }
  function anfordern() { if (!raf) { if (aktiv) { if (!weg) { raf = window.requestAnimationFrame(bild); } } } }
  function bild() {
    raf = null;
    if (!wrap.isConnected) { selbstWeg(); return; }
    var weiter = false;
    if (ANI) {
      var t = Math.min(1, (jetzt() - ANI.t0) / ANI.d), e = t * t * (3 - 2 * t);
      K.A = t3Basis(t3Slerp(ANI.a.q, ANI.zq, e));
      K.S = ANI.a.S * Math.pow(ANI.z.S / ANI.a.S, e);
      K.D = [ANI.a.D[0] + (ANI.z.D[0] - ANI.a.D[0]) * e, ANI.a.D[1] + (ANI.z.D[1] - ANI.a.D[1]) * e];
      if (lt(t, 1)) { weiter = true; } else { K.az = ANI.z.az; K.el = ANI.z.el; K.A = teilAchsen(K.az, K.el); ANI = null; }
    }
    zeichnen();
    if (weiter) { anfordern(); }
  }
  /* Bedienung: Ziehen dreht, rechte Maustaste oder Umschalt verschiebt, Rad (nach Klick oder mit Strg) und zwei Finger zoomen */
  var ZG = {}, zug = null;
  /* Zoom per Klick wie in der Anlage (Dimi 11.11.2026, 16:23, Antwort 1a): Klick ins Modell, blauer Rahmen, das Rad zoomt; Klick
     daneben oder die Maus verlaesst das Modell: das Rad scrollt die Seite */
  var zAktiv = false;
  function zoomAn(an) { zAktiv = an; wrap.classList.toggle('za', an); }
  /* Handy-Runde 2 (Dimi 12.11.2026, 09:23): wie in der Anlage – Antippen schaltet Drehen ein (Rahmen), dann dreht ein Finger frei,
     zwei Finger zoomen; „✕ Fertig“, Tippen ausserhalb oder Wegscrollen schaltet zurueck. Nur am Handy. */
  var DRA = false;
  function taSetzen(an) { if (!touch) { return; } an = !!an; if (DRA === an) { return; } DRA = an; wrap.classList.toggle('ta', an); wrap.classList.toggle('za', an); }
  if (touch) {
    var taK = ht('button', 'wt3-f', '✕ Fertig', wrap); taK.type = 'button'; taK.setAttribute('aria-label', 'Drehen beenden, Seite scrollen');
    taK.addEventListener('click', function (ev) { ev.stopPropagation(); taSetzen(false); });
    taK.addEventListener('pointerdown', function (ev) { ev.stopPropagation(); });
    document.addEventListener('pointerdown', function (ev) { if (DRA) { if (!wrap.contains(ev.target)) { taSetzen(false); } } }, true);
    if (window.IntersectionObserver) { new IntersectionObserver(function (es) { each(es, function (e) { if (lt(e.intersectionRatio, 0.3)) { taSetzen(false); } }); }, { threshold: [0, 0.3] }).observe(wrap); }
  }
  document.addEventListener('pointerdown', function (ev) { if (zAktiv) { if (!wrap.contains(ev.target)) { zoomAn(false); } } }, true);
  function zahl() { var n = 0; for (var k in ZG) { if (ZG[k]) { n++; } } return n; }
  function zwei() { var a = []; for (var k in ZG) { if (ZG[k]) { a.push(ZG[k]); } } return a; }
  function lokal(ev) { var r = cv.getBoundingClientRect(); return [ev.clientX - r.left, ev.clientY - r.top]; }
  function hilfeWeg() { hin.style.opacity = '0'; }
  var beruehrt = false;
  function bewegt() { if (beruehrt) { return; } beruehrt = true; if (o.beruehrt) { o.beruehrt(); } }
  /* Ziehen dreht frei in alle Richtungen, auch ueber oben und unten hinweg; steht das Teil kopf, dreht die Waagerechte andersherum,
     damit es der Hand folgt (Runde 12 der Szene, Dimi 10.11.2026) */
  function drehen(dx, dy) {
    K.A = t3Dreh(K.A, dx * 0.0105, dy * 0.0105);
    K.el = Math.asin(Math.max(-1, Math.min(1, K.A.v[2]))); K.az = Math.atan2(K.A.v[1], K.A.v[0]);
    bewegt(); anfordern();
  }
  function schieben(dx, dy) { K.D = [K.D[0] + dx, K.D[1] - dy]; grenzen(); bewegt(); anfordern(); }
  function zoomen(f, x, y) {
    var s1 = Math.max(SMIN, Math.min(SMAX, K.S * f)), q = s1 / K.S, mx = x - Wc / 2, my = Hc / 2 - y;
    K.D = [mx - (mx - K.D[0]) * q, my - (my - K.D[1]) * q];
    K.S = s1; grenzen(); bewegt(); anfordern();
  }
  function zurueck() { beruehrt = false; fahre({ az: ISO_AZ, el: ISO_EL, S: S0, D: [0, 0] }, 600); }
  cv.addEventListener('contextmenu', function (ev) { ev.preventDefault(); });
  cv.addEventListener('pointerdown', function (ev) {
    try { cv.setPointerCapture(ev.pointerId); } catch (e) { }
    var p = lokal(ev); ZG[ev.pointerId] = { x: p[0], y: p[1] };
    ANI = null; hilfeWeg(); scharf = true; if (ev.pointerType === 'mouse') { zoomAn(true); }
    if (zahl() === 1) { zug = { art: (ev.button === 2 || ev.shiftKey) ? 'schieb' : ((ev.pointerType === 'touch' ? !DRA : false) ? 'tipp' : 'dreh'), x: p[0], y: p[1], sx: p[0], sy: p[1], t0: jetzt() }; }
    else if (ev.pointerType === 'touch') { zug = { art: 'aus' }; }
    else { var z = zwei(); zug = { art: 'pinch', d: Math.max(1, Math.sqrt(Math.pow(z[0].x - z[1].x, 2) + Math.pow(z[0].y - z[1].y, 2))), m: [(z[0].x + z[1].x) / 2, (z[0].y + z[1].y) / 2] }; }
    cv.classList.add('zieh'); ev.preventDefault(); ev.stopPropagation();
  });
  cv.addEventListener('pointermove', function (ev) {
    var p = lokal(ev);
    if (ZG[ev.pointerId]) { ZG[ev.pointerId] = { x: p[0], y: p[1] }; }
    if (!zug) { return; }
    if (zug.art === 'aus' || zug.art === 'tipp') { return; }
    if (zug.art === 'pinch') {
      var z = zwei(); if (lt(z.length, 2)) { return; }
      var d = Math.max(1, Math.sqrt(Math.pow(z[0].x - z[1].x, 2) + Math.pow(z[0].y - z[1].y, 2))), m = [(z[0].x + z[1].x) / 2, (z[0].y + z[1].y) / 2];
      schieben(m[0] - zug.m[0], m[1] - zug.m[1]); zoomen(d / zug.d, m[0], m[1]);
      zug.d = d; zug.m = m; return;
    }
    var dx = p[0] - zug.x, dy = p[1] - zug.y; zug.x = p[0]; zug.y = p[1];
    if (zug.art === 'dreh') { drehen(dx, dy); } else { schieben(dx, dy); }
  });
  function ende(ev) {
    var war = zug, p = lokal(ev);
    delete ZG[ev.pointerId];
    if (zahl() === 0) { zug = null; cv.classList.remove('zieh'); }
    else if (zahl() === 1) { var z = zwei()[0]; zug = war ? (war.art === 'aus' ? { art: 'aus' } : null) : null; if (!zug) { zug = { art: 'dreh', x: z.x, y: z.y }; } }
    /* Handy-Runde (Prüfliste 25.3): Doppeltippen zoomt an der Stelle auf das Doppelte */
    if (ev.type === 'pointerup') { if (ev.pointerType === 'touch') { if (war ? war.sx !== undefined : false) { if (lt(Math.abs(p[0] - war.sx) + Math.abs(p[1] - war.sy), 12)) { taSetzen(true); tippen3(p); } } } }
  }
  var TT = null, tHin = 0, LPT = 'mouse';
  function tippen3(p) {
    var t = jetzt(), w = TT; TT = { t: t, x: p[0], y: p[1] };
    if (!w) { return; } if (gt(t - w.t, 330)) { return; } if (gt(Math.abs(p[0] - w.x) + Math.abs(p[1] - w.y), 36)) { return; }
    TT = null; ANI = null; hilfeWeg(); zoomen(2, p[0], p[1]);
  }
  function toastZeigen(t, ms) { toast.textContent = t; toast.style.opacity = '1'; if (toastT) { window.clearTimeout(toastT); } toastT = window.setTimeout(function () { toast.style.opacity = '0'; }, ms || 1600); }
  zweiFingerBinden(cv, {
    start: function () { ANI = null; hilfeWeg(); toast.style.opacity = '0'; scharf = true; taSetzen(true); },
    zwei: function (f, m, dm) { schieben(dm[0], dm[1]); zoomen(f, m[0], m[1]); },
    senkrecht: function () { if (DRA) { return; } var t = jetzt(); if (lt(t - tHin, 10000)) { return; } tHin = t; toastZeigen('Zum Drehen antippen · Zoomen: zwei Finger', 1900); }
  });
  cv.addEventListener('pointerdown', function (ev) { LPT = ev.pointerType || 'mouse'; }, true);
  cv.addEventListener('pointerup', ende);
  cv.addEventListener('pointercancel', ende);
  cv.addEventListener('click', function (ev) { ev.stopPropagation(); });
  cv.addEventListener('dblclick', function (ev) { ev.preventDefault(); ev.stopPropagation(); if (LPT === 'touch') { return; } zurueck(); });
  cv.addEventListener('mouseleave', function () { if (!zug) { zoomAn(false); } });
  cv.addEventListener('wheel', function (ev) {
    var spreiz = ev.ctrlKey || ev.metaKey, d = ev.deltaY * (ev.deltaMode === 1 ? 16 : (ev.deltaMode === 2 ? 400 : 1));
    if (!spreiz) {
      if (!zAktiv) { return; }
      /* Runde 18: ganz herausgezoomt bleibt das Rad in der Ansicht (kein Wechsel zum Seiten-Scrollen) */
      if (gt(d, 0)) { if (!gt(K.S, S0 * 1.002)) { ev.preventDefault(); return; } }
    }
    ev.preventDefault(); ANI = null; hilfeWeg(); toast.style.opacity = '0';
    var p = lokal(ev), f = Math.exp(-d * 0.0015);
    if (!spreiz ? lt(f, 1) : false) {
      var s0 = K.S; zoomen(Math.max(f, S0 / Math.max(1e-9, s0)), p[0], p[1]);
      var q = gt(s0 - S0, 1e-9) ? Math.max(0, Math.min(1, (K.S - S0) / (s0 - S0))) : 0;
      K.D = [K.D[0] * q, K.D[1] * q]; grenzen(); anfordern();
    } else { zoomen(f, p[0], p[1]); }
  }, { passive: false });
  cv.addEventListener('keydown', function (ev) {
    var k = ev.key, z = true;
    if (k === 'ArrowLeft') { drehen(-20, 0); } else if (k === 'ArrowRight') { drehen(20, 0); }
    else if (k === 'ArrowUp') { drehen(0, -20); } else if (k === 'ArrowDown') { drehen(0, 20); }
    else if (k === '+' || k === '=') { zoomen(1.25, Wc / 2, Hc / 2); } else if (k === '-') { zoomen(0.8, Wc / 2, Hc / 2); }
    else if (k === '0') { zurueck(); } else { z = false; }
    if (z) { ev.preventDefault(); ev.stopPropagation(); hilfeWeg(); }
  });
  /* Wird die Kartei neu aufgebaut (Flaeche nicht mehr im Dokument), gibt sich die Ansicht selbst frei */
  function selbstWeg() { if (weg) { return; } api.zu(); if (o.weg) { o.weg(); } }
  var RO = null;
  if (window.ResizeObserver) { RO = new ResizeObserver(function () { if (!wrap.isConnected) { selbstWeg(); return; } if (aktiv) { groesse(); } }); RO.observe(wrap); }
  cv.addEventListener('webglcontextlost', function (ev) { ev.preventDefault(); weg = true; });
  var erst = true, frei = false, BLT = null;
  function blende(weich, f) {
    if (!weich || !bewegungErlaubt()) { f(); return; }
    if (BLT) { window.clearTimeout(BLT); }
    wrap.classList.add('blend');
    BLT = window.setTimeout(function () { BLT = null; f(); window.requestAnimationFrame(function () { window.requestAnimationFrame(function () { wrap.classList.remove('blend'); }); }); }, 470);
  }
  var api = {
    an: function () {
      if (weg) { return; }
      aktiv = true; wrap.style.display = ''; if (svg) { svg.style.display = 'none'; }
      groesse();
      if (erst) { erst = false; K = kNeu(ISO_AZ, ISO_EL, S0, [0, 0]); grenzen(); }
      anfordern();
    },
    aus: function () {
      aktiv = false; wrap.style.display = 'none'; if (svg) { svg.style.display = ''; }
      if (raf) { window.cancelAnimationFrame(raf); raf = null; }
    },
    /* Schliessen: Flaeche entfernen, Bild zurueck, Puffer und Kontext freigeben */
    zu: function () {
      api.aus();
      if (RO) { RO.disconnect(); RO = null; }
      if (toastT) { window.clearTimeout(toastT); } window.clearTimeout(hinT); if (BLT) { window.clearTimeout(BLT); }
      if (!weg) {
        if (MG) { each(MG.v, function (x) { gl.deleteVertexArray(x); }); each(MG.b, function (x) { gl.deleteBuffer(x); }); MG = null; }
        each(GLO.v, function (x) { gl.deleteVertexArray(x); });
        each(GLO.b, function (x) { gl.deleteBuffer(x); });
        each(GLO.p, function (x) { gl.deleteProgram(x); });
        each(GLO.s, function (x) { gl.deleteShader(x); });
        var ext3 = gl.getExtension('WEBGL_lose_context'); if (ext3) { ext3.loseContext(); }
      }
      if (!frei) { frei = true; T3N--; }
      weg = true;
      if (wrap.parentNode) { wrap.parentNode.removeChild(wrap); }
    },
    /* Bereich k farbig (wie im Bild); k: Zahl oder Feld (zusammengelegte Zeilen), null hebt auf */
    bereich: function (k) {
      var m = 0;
      each(k === null || k === undefined ? [] : (Array.isArray(k) ? k : [k]), function (x) { if (gt(x, -1)) { if (lt(x, 20)) { m += Math.pow(2, x); } } });
      BER = m; anfordern();
    },
    /* andere Bauform (Wechselbild der Kartei): Blickrichtung und Zoom bleiben; weich: ausblenden, tauschen, einblenden
       (nacheinander, Dimi 09.11.2026, Runde 11 Punkt 12) */
    bauform: function (v2, weich) {
      v2 = v2 || 0; if (weg) { return; } if (v2 === vi) { return; }
      var E2 = teilErfassen(pid, v2); if (!E2) { return; }
      blende(weich, function () { if (weg) { return; } vi = v2; msE = E2.ms || []; laden(E2); neuMassstab(); grenzen(); anfordern(); });
    },
    /* anderes Bauteil (Kartei „Alle …“): Ausgangslage, weich nacheinander */
    teil: function (p2, v2, weich, fertig) {
      v2 = v2 || 0; if (weg) { return; }
      var E2 = teilErfassen(p2, v2); if (!E2) { return; }
      blende(weich, function () {
        if (weg) { return; }
        pid = p2; vi = v2; msE = E2.ms || []; laden(E2); neuMassstab();
        K = kNeu(ISO_AZ, ISO_EL, S0, [0, 0]); ANI = null; grenzen(); anfordern();
        var b2 = BT[p2]; cv.setAttribute('aria-label', '3D-Modell ' + (b2 ? b2.t : p2) + ': ziehen oder Pfeiltasten drehen');
        if (fertig) { fertig(); }
      });
    },
    /* Masse ein- und ausblenden; masse(): gibt es Masse fuer diese Bauform */
    masse: function (an) { if (an !== undefined) { MASSE_AN = !!an; punkte(); neuMassstab(); grenzen(); anfordern(); } return msE.length !== 0; },
    /* Bild der Flaeche mit Massen (fuer Druck und Bildschirmfoto): Rueckruf mit data-URL */
    bild: function (cb) {
      if (weg) { cb(''); return; }
      zeichnen(); var u = ''; try { u = cv.toDataURL('image/png'); } catch (e) { u = ''; }
      if (!MASSE_AN) { cb(u); return; }
      bildMitSvg(u, MS, cv.width, cv.height, Wc, Hc, cb);
    },
    pid: function () { return pid; },
    /* Ausgangslage (Antippen der Bauteil-Kachel) */
    zurueck: function () { ANI = null; zurueck(); },
    /* Zoomen mit den Knoepfen der Kartei (Faktor um die Bildmitte) */
    zoom: function (f) { if (weg) { return; } ANI = null; hilfeWeg(); zoomen(f, Wc / 2, Hc / 2); },
    /* fuer Tests: Blickrichtung in Grad, Massstab der Ausgangslage */
    kamera: function (az, el, ms) {
      if (az !== undefined) { var z = { az: az * Math.PI / 180, el: el * Math.PI / 180, S: S0, D: [0, 0] }; if (ms) { fahre(z, ms); } else { ANI = null; K = kNeu(z.az, z.el, z.S, z.D); grenzen(); anfordern(); } }
      return { az: K.az * 180 / Math.PI, el: K.el * 180 / Math.PI, S: K.S, S0: S0 };
    },
    info: function () { return { vi: vi, nf: B.nf, nl: B.nl, faces: { op: VF.op.n / 3, gl: VF.gl.n / 3 }, linien: VL.n, bereiche: Object.keys(B.used), W: Wc, H: Hc, bb: B.bb, punkte: P.length, angehoben: B.nh }; },
    flaeche: wrap
  };
  api.an();
  return api;
}
/* Testzugang: teil3d und die Bauteile mit Bild (Zahl der Bauformen) */
window.wmsTeil3d = teil3d;
window.wmsMasse = function (an) { if (an !== undefined) { MASSE_AN = !!an; } return MASSE_AN; };
window.wmsTeilErf = teilErfassen;
window.wmsTeil3dOffen = function () { return T3N; };
window.wmsTeilListe = function () {
  var r = [];
  each(DATA.bauteile, function (b) { if (b.klick !== 'ja') { return; } if (!SYM[b.id]) { return; } r.push({ pid: b.id, n: 1 + ((SYM[b.id].v || []).length) }); });
  return r;
};

/* ---------- Start (am Ende, damit alle Teile geladen sind) ---------- */
function start() {
  var q = document.querySelectorAll('div.wms[data-wms="anlage"]');
  for (var i = 0; i !== q.length; i++) { init(q[i]); }
}
if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', start); } else { start(); }
if (window.MutationObserver) { new MutationObserver(function () { start(); }).observe(document.documentElement, { childList: true, subtree: true }); }
window.wmsAnlage = { start: start, bauen: bauen, daten: function (pid) { return BT[pid]; },
  prozessTest: function (el, id) {
    cssEinmal();
    var s = ikSvg(id); if (s) { el.appendChild(s); } return s;
  },
  symbolTest: function (el, pid, k, v) {
  cssEinmal();
  var S = symbolBauen(pid), b = BT[pid] || (EM_FLACH[pid] ? { id: pid, t: 'Zuschnitt', bereiche: EM_FLACH[pid] } : null); if (!S) { return null; }
  if (v !== undefined) { S = (symbolVarianten(pid) || [S])[v] || S; }
  var d = ht('div', 'wsy-bild', null, el), svg = symbolSvg(S, b, v); d.appendChild(svg); bereichSetzen(svg, k === undefined ? null : k);
  var used = []; for (var a in S.used) { used.push(parseInt(a, 10)); }
  return { n: b.bereiche.length, used: used.sort(), el: S.it.length, nv: (symbolVarianten(pid) || [S]).length };
},
  profilTest: function (el, key, o) { cssEinmal(); return profilSvg(key, el, o || {}); },
  merkliste: { lesen: mkLesen, schreiben: mkSchreiben, druck: mkDruck, panel: mkPanel },
  treffer: function (q) { return suchTreffer(q).map(function (x) { return x.e.k + ':' + x.e.id + ':' + x.s; }); },
  stufen: function (pid) { return BT[pid] ? stufenListe(BT[pid]) : null; }
};

})();
