{"id":2409,"date":"2026-08-19T17:54:51","date_gmt":"2026-08-19T15:54:51","guid":{"rendered":"https:\/\/cad-kompass.de\/?p=2409"},"modified":"2026-08-19T17:55:27","modified_gmt":"2026-08-19T15:55:27","slug":"formstueck-oder-muffe","status":"publish","type":"post","link":"https:\/\/cad-kompass.de\/?p=2409","title":{"rendered":"Formst\u00fcck oder Muffe?"},"content":{"rendered":"\n<style>\n    .fm-box {\n        --fm-primary: #3f5f75;\n        --fm-primary-dark: #2c4a5e;\n        --fm-primary-deep: #1e3548;\n        --fm-ink: #1e293b;\n        --fm-text: #334155;\n        --fm-muted: #64748b;\n        --fm-border: #c8d6e0;\n        --fm-surface: #f7f9fb;\n        --fm-good: #059669;\n        --fm-good-deep: #15803d;\n        --fm-warn: #d97706;\n        --fm-warn-deep: #92700c;\n        --fm-warn-border: #f4cf81;\n        --fm-error: #dc2626;\n        --fm-accent: #e8913a;\n        \/* Formstueck-Akzent braucht einen eigenen dunklen Ton fuer Chip\/Text-Kontrast,\n           angelehnt an den Boeschungs-Bronzeton aus 08-Profilkoerper. *\/\n        --fm-accent-deep: #b45309;\n        background: var(--fm-surface);\n        border: 3px solid var(--fm-primary);\n        border-radius: 8px;\n        margin: 28px 0;\n        overflow: hidden;\n        position: relative;\n        font-family: inherit;\n        color: var(--fm-text);\n        line-height: 1.55;\n    }\n    .fm-box, .fm-box *, .fm-box *::before, .fm-box *::after { box-sizing: border-box; }\n\n    .fm-header {\n        background: linear-gradient(135deg, var(--fm-primary-deep) 0%, var(--fm-primary-dark) 100%);\n        padding: 20px 28px 18px;\n        position: relative;\n    }\n    .fm-header::after {\n        content: '';\n        position: absolute;\n        left: 0; right: 0; bottom: 0;\n        height: 3px;\n        background: repeating-linear-gradient(90deg, var(--fm-primary) 0px, var(--fm-primary) 8px, transparent 8px, transparent 12px);\n    }\n    .fm-header-top { display: flex; align-items: center; gap: 14px; }\n    .fm-header-icon { width: 36px; height: 36px; flex-shrink: 0; }\n    .fm-box-title { font-size: 1.15rem; color: #fff; font-weight: 700; margin: 0; letter-spacing: -0.01em; }\n    .fm-box-desc { font-size: 0.85rem; color: rgba(255,255,255,0.68); margin: 6px 0 0; line-height: 1.55; }\n\n    .fm-body { padding: 22px 28px 24px; }\n    .fm-privacy {\n        background: #f0fdf4;\n        border: 1px solid #bbf7d0;\n        border-radius: 3px;\n        padding: 9px 14px;\n        margin-bottom: 16px;\n        font-size: 0.8rem;\n        color: var(--fm-good-deep);\n        line-height: 1.5;\n        display: flex;\n        align-items: center;\n        gap: 8px;\n    }\n    .fm-privacy::before { content: '\\1F512'; flex-shrink: 0; font-size: 0.9rem; }\n    .fm-intro {\n        background: #f0f5fa;\n        border-left: 3px solid var(--fm-primary);\n        border-radius: 0 4px 4px 0;\n        padding: 11px 15px;\n        margin-bottom: 16px;\n        font-size: 0.86rem;\n        color: var(--fm-text);\n    }\n    .fm-intro strong { color: var(--fm-ink); }\n\n    .fm-section-label {\n        font-size: 0.66rem;\n        font-weight: 800;\n        text-transform: uppercase;\n        letter-spacing: 0.1em;\n        color: var(--fm-muted);\n        margin: 0 0 8px;\n    }\n    .fm-sub-title {\n        font-size: 0.72rem;\n        font-weight: 800;\n        color: var(--fm-primary);\n        text-transform: uppercase;\n        letter-spacing: 0.08em;\n        margin: 22px 0 9px;\n        padding-top: 16px;\n        border-top: 1px solid #e4ebf1;\n    }\n\n    .fm-verdict { border: 1px solid var(--fm-border); border-radius: 4px; background: #fff; padding: 12px 16px; margin-bottom: 14px; }\n    .fm-verdict.is-live { border-left: 3px solid var(--fm-primary); border-radius: 0 4px 4px 0; }\n    .fm-verdict-head { display: flex; align-items: center; gap: 10px; margin-bottom: 8px; }\n    .fm-verdict-title {\n        font-size: 0.66rem;\n        font-weight: 800;\n        text-transform: uppercase;\n        letter-spacing: 0.1em;\n        color: var(--fm-muted);\n    }\n    .fm-chip {\n        display: inline-flex;\n        align-items: center;\n        min-height: 22px;\n        padding: 2px 10px;\n        border-radius: 999px;\n        font-size: 0.72rem;\n        font-weight: 800;\n        background: #edf4f8;\n        border: 1px solid #cfe0ea;\n        color: var(--fm-primary-deep);\n        font-variant-numeric: tabular-nums;\n    }\n    .fm-chip.is-good { background: #f0fdf4; border-color: #bbf7d0; color: var(--fm-good-deep); }\n    .fm-chip.is-accent { background: #fdf1e4; border-color: #f3d9b7; color: var(--fm-accent-deep); }\n    .fm-chip.is-error { background: #fef2f2; border-color: #fac5c5; color: var(--fm-error); }\n    .fm-verdict-text { font-size: 0.85rem; line-height: 1.6; color: var(--fm-text); margin: 0; }\n    .fm-verdict-text strong { color: var(--fm-ink); }\n\n    .fm-svg-wrap {\n        border: 1px solid var(--fm-border);\n        border-radius: 4px;\n        background: #fff;\n        padding: 12px 14px 10px;\n        margin-bottom: 14px;\n    }\n    .fm-svg-wrap svg { width: 100%; height: auto; display: block; font-family: inherit; user-select: none; }\n\n    .fm-legend {\n        display: flex;\n        flex-wrap: wrap;\n        gap: 9px 14px;\n        align-items: center;\n        margin-top: 9px;\n        padding-top: 9px;\n        border-top: 1px solid #edf2f7;\n        font-size: 0.73rem;\n        color: var(--fm-muted);\n    }\n    .fm-legend-item { display: inline-flex; align-items: center; gap: 5px; }\n    .fm-line-swatch { width: 20px; height: 0; border-top: 3px solid currentColor; border-radius: 999px; }\n    .fm-line-swatch.is-dash {\n        height: 2px;\n        border-top: 0;\n        background: repeating-linear-gradient(90deg, currentColor 0 6px, transparent 6px 10px);\n    }\n    .fm-dot-swatch { width: 10px; height: 10px; border-radius: 50%; border: 2px solid currentColor; background: #fff; }\n    .fm-tri-swatch { width: 0; height: 0; border-left: 5px solid transparent; border-right: 5px solid transparent; border-bottom: 9px solid currentColor; }\n\n    .fm-controls {\n        border: 1px solid var(--fm-border);\n        border-radius: 4px;\n        background: var(--fm-surface);\n        padding: 14px 16px 16px;\n        display: grid;\n        grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));\n        gap: 14px 18px;\n        align-items: start;\n        margin-bottom: 14px;\n    }\n    .fm-control-block { min-width: 0; }\n    .fm-field { margin-bottom: 12px; padding-left: 9px; border-left: 3px solid var(--fm-border); }\n    .fm-field:last-child { margin-bottom: 0; }\n    .fm-field-label { display: flex; justify-content: space-between; gap: 8px; font-size: 0.76rem; font-weight: 800; color: var(--fm-ink); margin-bottom: 4px; }\n    .fm-field-unit { color: var(--fm-muted); font-size: 0.74rem; font-weight: 700; font-variant-numeric: tabular-nums; }\n\n    \/* Zonen-Skala unter dem Theta-Slider: 9px seitlich eingerueckt, damit die\n       Zonengrenzen mit der Thumb-Mitte des 18px-Sliderknopfs fluchten. *\/\n    .fm-zonebar { display: flex; gap: 2px; height: 7px; margin: 7px 9px 6px; }\n    .fm-zonebar span { display: block; height: 100%; border-radius: 2px; min-width: 2px; }\n    .fm-zone-line { display: flex; flex-wrap: wrap; gap: 3px 12px; font-size: 0.71rem; color: var(--fm-muted); line-height: 1.45; }\n    .fm-zone-item { display: inline-flex; align-items: center; gap: 5px; white-space: nowrap; }\n    .fm-zone-swatch { width: 8px; height: 8px; border-radius: 1px; flex-shrink: 0; }\n\n    .fm-box .fm-range {\n        -webkit-appearance: none !important;\n        -moz-appearance: none !important;\n        appearance: none !important;\n        width: 100% !important;\n        height: 6px !important;\n        padding: 0 !important;\n        margin: 8px 0 2px !important;\n        background: #dbe4ec !important;\n        border: 0 !important;\n        border-radius: 3px !important;\n        outline: none !important;\n        box-shadow: none !important;\n        box-sizing: border-box !important;\n        accent-color: var(--fm-primary);\n    }\n    .fm-box .fm-range::-webkit-slider-runnable-track {\n        -webkit-appearance: none !important;\n        appearance: none !important;\n        height: 6px !important;\n        background: transparent !important;\n        border: 0 !important;\n        box-shadow: none !important;\n    }\n    .fm-box .fm-range::-webkit-slider-thumb {\n        -webkit-appearance: none !important;\n        appearance: none !important;\n        width: 18px !important;\n        height: 18px !important;\n        border-radius: 50% !important;\n        background: var(--fm-primary) !important;\n        border: 2px solid #fff !important;\n        box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2) !important;\n        margin-top: -6px !important;\n        cursor: pointer !important;\n    }\n    .fm-box .fm-range::-moz-range-track {\n        height: 6px !important;\n        background: transparent !important;\n        border: 0 !important;\n        box-shadow: none !important;\n    }\n    .fm-box .fm-range::-moz-range-thumb {\n        -moz-appearance: none !important;\n        appearance: none !important;\n        width: 18px !important;\n        height: 18px !important;\n        border-radius: 50% !important;\n        background: var(--fm-primary) !important;\n        border: 2px solid #fff !important;\n        box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2) !important;\n        cursor: pointer !important;\n    }\n    .fm-box .fm-range::-moz-focus-outer { border: 0 !important; }\n    .fm-box .fm-range:focus-visible { outline: 2px solid var(--fm-primary) !important; outline-offset: 4px !important; border-radius: 3px !important; }\n    .fm-box .fm-range:disabled { opacity: 0.42 !important; cursor: not-allowed !important; }\n    .fm-box .fm-range:disabled::-webkit-slider-thumb { background: #aab8c2 !important; }\n    .fm-box .fm-range:disabled::-moz-range-thumb { background: #aab8c2 !important; }\n\n    .fm-box .fm-btn {\n        -webkit-appearance: none !important;\n        appearance: none !important;\n        font-family: inherit !important;\n        font-size: 0.78rem !important;\n        font-weight: 800 !important;\n        line-height: 1.2 !important;\n        color: #fff !important;\n        background: var(--fm-primary) !important;\n        border: 1px solid var(--fm-primary) !important;\n        border-radius: 3px !important;\n        min-height: 36px !important;\n        padding: 7px 13px !important;\n        cursor: pointer !important;\n        box-shadow: none !important;\n        text-transform: none !important;\n        white-space: nowrap !important;\n        transition: background-color 0.15s, border-color 0.15s, color 0.15s;\n    }\n    .fm-box .fm-btn:hover { background: var(--fm-primary-dark) !important; border-color: var(--fm-primary-dark) !important; color: #fff !important; }\n    .fm-box .fm-btn:active { background: var(--fm-primary-deep) !important; }\n    .fm-box .fm-btn:focus-visible { outline: 2px solid var(--fm-primary) !important; outline-offset: 2px !important; }\n    .fm-box .fm-btn:disabled { background: #aab8c2 !important; border-color: #aab8c2 !important; cursor: not-allowed !important; }\n\n    .fm-seg { display: inline-flex; flex-wrap: wrap; border: 1px solid var(--fm-border); border-radius: 3px; overflow: hidden; background: #fff; width: 100%; }\n    .fm-box .fm-seg button {\n        -webkit-appearance: none !important;\n        appearance: none !important;\n        font-family: inherit !important;\n        font-size: 0.73rem !important;\n        font-weight: 800 !important;\n        line-height: 1.2 !important;\n        color: var(--fm-text) !important;\n        background: #fff !important;\n        border: none !important;\n        border-radius: 0 !important;\n        min-height: 34px !important;\n        padding: 6px 10px !important;\n        cursor: pointer !important;\n        box-shadow: none !important;\n        text-transform: none !important;\n        flex: 1 1 auto;\n        transition: background-color 0.15s, color 0.15s;\n    }\n    .fm-box .fm-seg button + button { border-left: 1px solid var(--fm-border) !important; }\n    .fm-box .fm-seg button.is-active { background: var(--fm-primary) !important; color: #fff !important; }\n    .fm-box .fm-seg button:hover:not(.is-active):not(:disabled) { background: #edf4f8 !important; color: var(--fm-primary) !important; }\n    .fm-box .fm-seg button:active:not(:disabled) { background: #e2ecf2 !important; }\n    .fm-box .fm-seg button:focus-visible { outline: 2px solid var(--fm-primary) !important; outline-offset: -2px !important; }\n    .fm-box .fm-seg button:disabled { opacity: 0.45 !important; cursor: not-allowed !important; color: var(--fm-muted) !important; }\n\n    .fm-mini-hint { font-size: 0.74rem; color: var(--fm-muted); line-height: 1.45; margin-top: 8px; }\n    .fm-mini-hint strong { color: var(--fm-ink); }\n\n    .fm-tile-grid { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 7px; margin-bottom: 14px; }\n    .fm-tile {\n        background: #fff;\n        border: 1px solid #dde7ee;\n        border-radius: 3px;\n        padding: 8px 9px;\n        min-width: 0;\n    }\n    .fm-tile.is-error { border-color: #fac5c5; background: #fef8f8; }\n    .fm-tile-label {\n        display: block;\n        color: var(--fm-muted);\n        font-size: 0.62rem;\n        font-weight: 800;\n        text-transform: uppercase;\n        letter-spacing: 0.05em;\n    }\n    .fm-tile-value {\n        display: block;\n        color: var(--fm-ink);\n        font-size: 0.9rem;\n        font-weight: 800;\n        font-variant-numeric: tabular-nums;\n        margin-top: 2px;\n    }\n    .fm-tile.is-error .fm-tile-value { color: var(--fm-error); }\n\n    .fm-hint-box {\n        background: #fdf6ec;\n        border-left: 3px solid var(--fm-accent);\n        border-radius: 0 4px 4px 0;\n        padding: 11px 15px;\n        font-size: 0.83rem;\n        color: var(--fm-text);\n    }\n    .fm-hint-box strong { color: var(--fm-ink); }\n\n    \/* SVG-Praesentation: Farben hartkodiert (Safari versteht keine CSS-Variablen in SVG-Attributen) *\/\n    .fm-svg-label { fill: #64748b; font-size: 10px; font-weight: 800; letter-spacing: 0.06em; text-transform: uppercase; }\n\n    @media (max-width: 700px) {\n        .fm-header { padding: 16px 20px 14px; }\n        .fm-body { padding: 18px 18px 20px; }\n        .fm-tile-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }\n    }\n    @media (max-width: 480px) {\n        .fm-tile-grid { grid-template-columns: 1fr; }\n    }\n    @media (prefers-reduced-motion: reduce) {\n        \/* !important noetig: Accessibility-Override muss beliebige Spezifitaeten der CSS-Box schlagen. *\/\n        .fm-box * { transition: none !important; animation: none !important; }\n    }\n<\/style>\n\n<div class=\"fm-box\" data-fm-root>\n    <div class=\"fm-header\">\n        <div class=\"fm-header-top\">\n            <svg class=\"fm-header-icon\" viewBox=\"0 0 36 36\" fill=\"none\" aria-hidden=\"true\">\n                <line x1=\"4\" y1=\"26\" x2=\"16\" y2=\"26\" stroke=\"rgba(255,255,255,0.9)\" stroke-width=\"2.4\" stroke-linecap=\"round\"\/>\n                <circle cx=\"16\" cy=\"26\" r=\"2.6\" fill=\"rgba(255,255,255,0.2)\" stroke=\"#fff\" stroke-width=\"1.6\"\/>\n                <line x1=\"16\" y1=\"26\" x2=\"30\" y2=\"10\" stroke=\"rgba(255,255,255,0.9)\" stroke-width=\"2.4\" stroke-linecap=\"round\"\/>\n                <path d=\"M6 15 A14 14 0 0 1 20 6\" stroke=\"rgba(255,255,255,0.4)\" stroke-width=\"1.4\" stroke-dasharray=\"2 3\" fill=\"none\"\/>\n            <\/svg>\n            <div>\n                <h2 class=\"fm-box-title\">Formst&uuml;ck oder Muffe?<\/h2>\n                <div class=\"fm-box-desc\">Knick in der Leitung: Formst&uuml;ck setzen oder &uuml;ber die Muffen auswinkeln? Du siehst die Entscheidung live, ganz ohne Civil 3D.<\/div>\n            <\/div>\n        <\/div>\n    <\/div>\n\n    <div class=\"fm-body\">\n        <div class=\"fm-privacy\">L&auml;uft komplett im Browser. Keine Daten verlassen deinen Rechner.<\/div>\n\n        <div class=\"fm-intro\">\n            Ein Formst&uuml;ck aus dem Katalog kennt nur feste Winkel: <strong>11,25&deg;, 22,5&deg;, 45&deg; und 90&deg;<\/strong>. Jede Steckmuffe erlaubt daneben noch ein paar Grad Spiel, DN- und werkstoffabh&auml;ngig zwischen etwa 1,5&deg; und 5&deg;. Civil 3D pr&uuml;ft genau diese Toleranz in der Entwurfs&uuml;berpr&uuml;fung als sogenannte <strong>Abschr&auml;gung (Muffenabwinklung)<\/strong> und markiert jeden Knick, der dar&uuml;ber hinausgeht. Zieh am Regler und sieh, ab wann sich der Muffenweg nicht mehr lohnt und ein Formst&uuml;ck her muss.\n        <\/div>\n\n        <div class=\"fm-verdict is-live\">\n            <div class=\"fm-verdict-head\">\n                <span class=\"fm-verdict-title\">Befund<\/span>\n                <span class=\"fm-chip\" id=\"fmChip\" aria-hidden=\"true\">l&auml;dt<\/span>\n            <\/div>\n            <p class=\"fm-verdict-text\" id=\"fmVerdictText\" aria-live=\"polite\"><\/p>\n        <\/div>\n\n        <div class=\"fm-svg-wrap\">\n            <svg id=\"fmSvgHero\" viewBox=\"0 0 620 300\" preserveAspectRatio=\"xMidYMid meet\" role=\"img\" aria-labelledby=\"fmHeroTitle\">\n                <title id=\"fmHeroTitle\">Draufsicht der Leitung mit dem gew&uuml;nschten Knick und der gew&auml;hlten L&ouml;sung: Muffenweg, Formst&uuml;ck oder &Uuml;berschreitung der Abschr&auml;gung<\/title>\n                <g id=\"fmHeroDraw\"><\/g>\n            <\/svg>\n            <div class=\"fm-legend\">\n                <span class=\"fm-legend-item\" style=\"color:#3f5f75;\"><span class=\"fm-line-swatch is-dash\"><\/span> Wunsch-Verlauf (Trasse)<\/span>\n                <span class=\"fm-legend-item\" style=\"color:#059669;\"><span class=\"fm-line-swatch\"><\/span> L&ouml;sung: Muffenweg oder Biegung<\/span>\n                <span class=\"fm-legend-item\" style=\"color:#059669;\"><span class=\"fm-dot-swatch\"><\/span> Muffe<\/span>\n                <span class=\"fm-legend-item\" style=\"color:#e8913a;\"><span class=\"fm-line-swatch\"><\/span> Formst&uuml;ck \/ Formteil<\/span>\n                <span class=\"fm-legend-item\" style=\"color:#dc2626;\"><span class=\"fm-tri-swatch\"><\/span> Abschr&auml;gung &uuml;berschritten<\/span>\n            <\/div>\n        <\/div>\n\n        <div class=\"fm-controls\">\n            <div class=\"fm-control-block\">\n                <div class=\"fm-field\">\n                    <label class=\"fm-field-label\" for=\"fmTheta\">Zielwinkel &Theta; am Knick <span class=\"fm-field-unit\" id=\"fmThetaText\">20&deg;<\/span><\/label>\n                    <input class=\"fm-range\" id=\"fmTheta\" type=\"range\" min=\"0\" max=\"90\" step=\"1\" value=\"20\">\n                    <div class=\"fm-zonebar\" id=\"fmZoneBar\" aria-hidden=\"true\"><\/div>\n                    <div class=\"fm-zone-line\" id=\"fmZoneLine\"><\/div>\n                    <div class=\"fm-section-label\" style=\"margin-top:10px;\">Katalogwinkel direkt anfahren<\/div>\n                    <span class=\"fm-seg\" id=\"fmKat\" role=\"group\" aria-label=\"Katalogwinkel als Zielwinkel setzen\">\n                        <button type=\"button\" data-fm-kat=\"11.25\">11,25&deg;<\/button>\n                        <button type=\"button\" data-fm-kat=\"22.5\">22,5&deg;<\/button>\n                        <button type=\"button\" data-fm-kat=\"45\">45&deg;<\/button>\n                        <button type=\"button\" data-fm-kat=\"90\">90&deg;<\/button>\n                    <\/span>\n                <\/div>\n                <div class=\"fm-section-label\" style=\"margin-top:12px;\">Rohr \/ Werkstoff<\/div>\n                <span class=\"fm-seg\" id=\"fmDN\" role=\"group\" aria-label=\"Nennweite DN w&auml;hlen\">\n                    <button type=\"button\" data-fm-dn=\"100\">DN 100<\/button>\n                    <button type=\"button\" data-fm-dn=\"200\">DN 200<\/button>\n                    <button type=\"button\" data-fm-dn=\"300\" class=\"is-active\">DN 300<\/button>\n                    <button type=\"button\" data-fm-dn=\"400\">DN 400<\/button>\n                    <button type=\"button\" data-fm-dn=\"600\">DN 600<\/button>\n                    <button type=\"button\" data-fm-dn=\"800\">DN 800<\/button>\n                <\/span>\n                <span class=\"fm-seg\" id=\"fmMaterial\" role=\"group\" aria-label=\"Werkstoff w&auml;hlen\" style=\"margin-top:8px;\">\n                    <button type=\"button\" data-fm-material=\"duktil\" class=\"is-active\">Duktilguss<\/button>\n                    <button type=\"button\" data-fm-material=\"pvc\">PVC-U<\/button>\n                    <button type=\"button\" data-fm-material=\"pehd\">PE-HD<\/button>\n                <\/span>\n                <div class=\"fm-mini-hint\" id=\"fmAlphaHint\"><\/div>\n            <\/div>\n            <div class=\"fm-control-block\">\n                <div class=\"fm-section-label\">Verlegeweg<\/div>\n                <span class=\"fm-seg\" id=\"fmWeg\" role=\"group\" aria-label=\"Verlegeweg w&auml;hlen\">\n                    <button type=\"button\" data-fm-weg=\"automatisch\" class=\"is-active\">Automatisch<\/button>\n                    <button type=\"button\" data-fm-weg=\"muffen\">Nur Muffen<\/button>\n                    <button type=\"button\" data-fm-weg=\"formstueck\">Formst&uuml;ck<\/button>\n                <\/span>\n                <div class=\"fm-mini-hint\"><strong>Rohrl&auml;nge L = 6 m<\/strong> (Standard-Baul&auml;nge Duktilguss, fest). <strong>Automatisch<\/strong> w&auml;hlt selbst zwischen Muffenweg und Formst&uuml;ck. <strong>Nur Muffen<\/strong> erzwingt den Muffenweg, das ist der Provokations-Modus f&uuml;r die Entwurfs&uuml;berpr&uuml;fung. <strong>Formst&uuml;ck<\/strong> zeigt immer den n&auml;chsten Katalogwinkel.<\/div>\n            <\/div>\n        <\/div>\n\n        <div class=\"fm-tile-grid\">\n            <div class=\"fm-tile\" id=\"fmTileWegBox\"><span class=\"fm-tile-label\">Weg<\/span><span class=\"fm-tile-value\" id=\"fmTileWeg\">&#8211;<\/span><\/div>\n            <div class=\"fm-tile\" id=\"fmTileMuffenBox\"><span class=\"fm-tile-label\">Muffen (n)<\/span><span class=\"fm-tile-value\" id=\"fmTileMuffen\">&#8211;<\/span><\/div>\n            <div class=\"fm-tile\" id=\"fmTileRBox\"><span class=\"fm-tile-label\">Radius R<\/span><span class=\"fm-tile-value\" id=\"fmTileR\">&#8211;<\/span><\/div>\n            <div class=\"fm-tile\" id=\"fmTileAlphaBox\"><span class=\"fm-tile-label\">je Muffe &alpha;<\/span><span class=\"fm-tile-value\" id=\"fmTileAlpha\">&#8211;<\/span><\/div>\n        <\/div>\n\n        <div class=\"fm-hint-box\">\n            <strong>Gut zu wissen:<\/strong> Die zul&auml;ssige Abwinklung &alpha; je Muffe ist DN- und werkstoffabh&auml;ngig, die hier gerechneten Werte sind Richtwerte aus dem Katalog von vonRoll\/Duktus (EN 545), nicht die Norm-Zahl deines Produkts. Im Projekt z&auml;hlt das Datenblatt des tats&auml;chlich verbauten Rohrs. In Civil 3D hei&szlig;t diese Toleranz <strong>Abschr&auml;gung<\/strong> und sitzt in der Komponentenliste je Bauteilgr&ouml;&szlig;e.\n        <\/div>\n    <\/div>\n<\/div>\n\n<script>\n    (function () {\n        \"use strict\";\n        var ROOT = document.querySelector(\"[data-fm-root]\");\n        if (!ROOT) { return; }\n\n        \/\/ Farbpalette als JS-Konstanten. Safari versteht keine CSS-Variablen in\n        \/\/ SVG-Attributwerten, deshalb hier hartkodierte Hex-Werte.\n        var COLORS = {\n            primary: \"#3f5f75\",\n            primaryDark: \"#2c4a5e\",\n            primaryDeep: \"#1e3548\",\n            ink: \"#1e293b\",\n            muted: \"#64748b\",\n            faint: \"#94a3b8\",\n            wish: \"#3f5f75\",\n            good: \"#059669\",\n            goodDeep: \"#15803d\",\n            accent: \"#e8913a\",\n            accentDeep: \"#b45309\",\n            error: \"#dc2626\",\n            errorFill: \"#fef2f2\",\n            errorBorder: \"#fac5c5\"\n        };\n\n        var SVGNS = \"http:\/\/www.w3.org\/2000\/svg\";\n        function $(id) { return ROOT.querySelector(\"#\" + id); }\n        function el(tag, attrs) {\n            var n = document.createElementNS(SVGNS, tag);\n            Object.keys(attrs || {}).forEach(function (k) { n.setAttribute(k, attrs[k]); });\n            return n;\n        }\n        function clear(node) { while (node.firstChild) { node.removeChild(node.firstChild); } }\n        function fmt(v, d) {\n            var digits = typeof d === \"number\" ? d : 2;\n            var val = isFinite(v) ? v : 0;\n            return val.toLocaleString(\"de-DE\", { minimumFractionDigits: digits, maximumFractionDigits: digits });\n        }\n        \/\/ Formatiert Gradwerte ohne unnoetige Nachkommastellen: 22.5 -> \"22,5 Grad\", 45 -> \"45 Grad\".\n        function degStr(v) {\n            var s = fmt(v, 2);\n            s = s.replace(\/0+$\/, \"\").replace(\/,$\/, \"\");\n            return s + String.fromCharCode(176);\n        }\n        \/\/ Meterwert kompakt: \"6,3 m\", aber \"16 m\" statt \"16,0 m\".\n        function mStr(v) {\n            return fmt(v, 1).replace(\/,0$\/, \"\") + \" m\";\n        }\n        function line(group, x1, y1, x2, y2, attrs) {\n            group.appendChild(el(\"line\", Object.assign({ x1: x1, y1: y1, x2: x2, y2: y2 }, attrs || {})));\n        }\n        function text(group, x, y, content, attrs) {\n            var base = { x: x, y: y, \"font-family\": \"inherit\" };\n            var t = el(\"text\", Object.assign(base, attrs || {}));\n            t.textContent = content;\n            group.appendChild(t);\n            return t;\n        }\n        function rect(group, x, y, w, h, attrs) {\n            group.appendChild(el(\"rect\", Object.assign({ x: x, y: y, width: w, height: h }, attrs || {})));\n        }\n        function circle(group, x, y, r, attrs) {\n            group.appendChild(el(\"circle\", Object.assign({ cx: x, cy: y, r: r }, attrs || {})));\n        }\n        function path(group, d, attrs) {\n            group.appendChild(el(\"path\", Object.assign({ d: d }, attrs || {})));\n        }\n        function card(group, x, y, w, h, title) {\n            rect(group, x, y, w, h, { fill: \"#fff\", stroke: \"#d9e4ec\", \"stroke-width\": 1.2, rx: 4 });\n            if (title) { text(group, x + 14, y + 22, title, { class: \"fm-svg-label\" }); }\n        }\n        function labelBox(group, x, y, label, opts) {\n            opts = opts || {};\n            var fs = opts.size || 9.5;\n            var pad = opts.pad || 6;\n            var w = opts.width || Math.max(30, label.length * fs * 0.6 + pad * 2);\n            var h = opts.height || 17;\n            rect(group, x - w \/ 2, y - h + 3, w, h, { fill: opts.fill || \"#fff\", stroke: opts.stroke || \"#d9e4ec\", \"stroke-width\": 1, rx: 3 });\n            text(group, x, y - 3, label, {\n                \"font-size\": fs,\n                fill: opts.color || \"#1e293b\",\n                \"text-anchor\": \"middle\",\n                \"font-weight\": opts.weight || 800\n            });\n        }\n        function dotMark(group, x, y, color, r) {\n            circle(group, x, y, r || 4.4, { fill: \"#fff\", stroke: color, \"stroke-width\": 2.2 });\n        }\n        function weldMark(group, x, y, color, s) {\n            var d = s || 4.4;\n            rect(group, x - d, y - d, d * 2, d * 2, { fill: \"#fff\", stroke: color, \"stroke-width\": 2.2, transform: \"rotate(45 \" + x + \" \" + y + \")\" });\n        }\n        function leader(group, ax, ay, lx, ly, color) {\n            line(group, ax, ay, lx, ly, { stroke: color, \"stroke-width\": 1, \"stroke-dasharray\": \"3 3\", opacity: 0.7 });\n        }\n        \/\/ ---- Freiflaechen-Platzierung fuer Labels ----\n        \/\/ Die Rohrkette rollt sich bei vielen Muffen ein und belegt den Platz ueber UND\n        \/\/ unter ihrem Ende. Ein fester Versatz reicht dort nicht, deshalb werden\n        \/\/ Kandidatenpunkte der Reihe nach geprueft und der erste freie genommen.\n        function rectsOverlap(a, b) {\n            if (a.x >= b.x + b.w) { return false; }\n            if (b.x >= a.x + a.w) { return false; }\n            if (a.y >= b.y + b.h) { return false; }\n            if (b.y >= a.y + a.h) { return false; }\n            return true;\n        }\n        function pointInRect(px, py, r) {\n            if (px < r.x) { return false; }\n            if (px > r.x + r.w) { return false; }\n            if (py < r.y) { return false; }\n            if (py > r.y + r.h) { return false; }\n            return true;\n        }\n        \/\/ Segment gegen Rechteck: dichte Abtastung (Schrittweite unter 5 px, das\n        \/\/ Rechteck wird zusaetzlich gepolstert geprueft).\n        function segHitsRect(s, r) {\n            var steps = 60, i, t;\n            for (i = 0; i <= steps; i += 1) {\n                t = i \/ steps;\n                if (pointInRect(s.x1 + (s.x2 - s.x1) * t, s.y1 + (s.y2 - s.y1) * t, r)) { return true; }\n            }\n            return false;\n        }\n        \/\/ Ankerpunkt wie in labelBox: Box laeuft von x-w\/2 bis x+w\/2 und y-h+3 bis y+3.\n        function spotFrei(anchor, w, h, segs, boxes, area) {\n            var r = { x: anchor.x - w \/ 2, y: anchor.y - h + 3, w: w, h: h };\n            if (r.x < area.x) { return false; }\n            if (r.y < area.y) { return false; }\n            if (r.x + r.w > area.x + area.w) { return false; }\n            if (r.y + r.h > area.y + area.h) { return false; }\n            var pad = { x: r.x - 5, y: r.y - 5, w: r.w + 10, h: r.h + 10 };\n            var boxFrei = boxes.every(function (b) { return rectsOverlap(pad, b) ? false : true; });\n            if (!boxFrei) { return false; }\n            return segs.every(function (s) { return segHitsRect(s, pad) ? false : true; });\n        }\n        function pickSpot(cands, w, h, segs, boxes, area) {\n            var i;\n            for (i = 0; i < cands.length; i += 1) {\n                if (spotFrei(cands[i], w, h, segs, boxes, area)) { return cands[i]; }\n            }\n            return cands[cands.length - 1];\n        }\n        function triWarn(group, x, y, color) {\n            path(group, \"M \" + x + \" \" + (y - 9) + \" L \" + (x - 8) + \" \" + (y + 6) + \" L \" + (x + 8) + \" \" + (y + 6) + \" Z\", { fill: \"#fef3cd\", stroke: color, \"stroke-width\": 1.3 });\n            text(group, x, y + 4, \"!\", { \"font-size\": 8.5, fill: color, \"text-anchor\": \"middle\", \"font-weight\": 800 });\n        }\n        function syncSeg(containerId, attr, value) {\n            ROOT.querySelectorAll(\"#\" + containerId + \" button\").forEach(function (b) {\n                b.classList.toggle(\"is-active\", b.getAttribute(attr) === value);\n            });\n        }\n        \/\/ Richtungsvektor fuer einen Winkel (Grad, mathematisch gegen den Uhrzeigersinn,\n        \/\/ aber y zeigt im SVG nach unten -> positive Winkel biegen sichtbar nach oben ab.\n        function dirVec(angleDeg) {\n            var r = angleDeg * Math.PI \/ 180;\n            return { dx: Math.cos(r), dy: -Math.sin(r) };\n        }\n        function rotatePoint(base, angleDeg, length) {\n            var d = dirVec(angleDeg);\n            return { x: base.x + d.dx * length, y: base.y + d.dy * length };\n        }\n        \/\/ Kruemmer-\/Formteil-Bogen als tangentiale Eckausrundung: die Leitung stoppt\n        \/\/ im Abstand \"arm\" VOR dem Knickpunkt (t1), der Bogen laeuft von dort exakt\n        \/\/ tangential in die neue Richtung bis t2. Kontrollpunkt ist der Knickpunkt\n        \/\/ selbst, so schmiegt sich das Bauteil in die Ecke, statt (wie ein Bogen, der\n        \/\/ erst am Eckpunkt startet) darueber hinauszuschiessen.\n        function filletBend(group, vertex, angleIn, angleOut, arm, attrs) {\n            var din = dirVec(angleIn), dout = dirVec(angleOut);\n            var t1 = { x: vertex.x - din.dx * arm, y: vertex.y - din.dy * arm };\n            var t2 = { x: vertex.x + dout.dx * arm, y: vertex.y + dout.dy * arm };\n            var d = \"M \" + t1.x.toFixed(1) + \" \" + t1.y.toFixed(1) + \" Q \" + vertex.x.toFixed(1) + \" \" + vertex.y.toFixed(1) + \" \" + t2.x.toFixed(1) + \" \" + t2.y.toFixed(1);\n            path(group, d, Object.assign({ fill: \"none\" }, attrs || {}));\n            return { t1: t1, t2: t2 };\n        }\n\n        \/\/ ============ MODELL (bindend nach TOOL-SPEC) ============\n        var ALPHA_MAX = { 100: 5, 200: 5, 300: 4, 400: 3, 600: 3, 800: 2 };\n        var KATALOG = [11.25, 22.5, 45, 90];\n        var ROHRLAENGE = 6; \/\/ m, feste Baulaenge (keine Eingabe)\n\n        function alphaMaxFuer(dn, material) {\n            var basis = ALPHA_MAX[dn];\n            if (material === \"pvc\") { return Math.min(3, basis); }\n            if (material === \"pehd\") { return null; }\n            return basis;\n        }\n        function nearestKatalog(theta) {\n            var best = KATALOG[0], bestD = Math.abs(theta - KATALOG[0]), i;\n            for (i = 1; i < KATALOG.length; i += 1) {\n                var d = Math.abs(theta - KATALOG[i]);\n                if (d < bestD) { bestD = d; best = KATALOG[i]; }\n            }\n            return { angle: best, delta: bestD };\n        }\n        function muffenweg(theta, alphaMax) {\n            var raw = theta \/ alphaMax;\n            var n = Math.max(1, Math.ceil(raw - 1e-9));\n            var alphaUsed = theta \/ n;\n            var alphaRad = alphaUsed * Math.PI \/ 180;\n            \/\/ Sehnenformel: die 6-m-Rohre sind Sehnen eines Bogens, je Stoss Knick alpha,\n            \/\/ also R = L \/ (2 sin(alpha\/2)).\n            var r = alphaUsed > 0.0001 ? ROHRLAENGE \/ (2 * Math.sin(alphaRad \/ 2)) : Infinity;\n            return { n: n, alphaUsed: alphaUsed, r: r, bogen: n * ROHRLAENGE };\n        }\n\n        \/\/ PE-HD hat keine Muffe. Die Richtungsaenderung laeuft ueber den elastischen\n        \/\/ Biegeradius des Rohres. Aussendurchmesser je DN in Metern: PE wird nach\n        \/\/ Aussendurchmesser bezeichnet, die DN-Angabe ist der gerundete Nachbarwert\n        \/\/ (DN 300 entspricht d 315 mm).\n        var PE_DA = { 100: 0.110, 200: 0.200, 300: 0.315, 400: 0.400, 600: 0.630, 800: 0.800 };\n        var PE_FAKTOR = 20;           \/\/ Rechenwert; Richtwert-Spanne 20 bis 50 x da (Addendum)\n        var KATALOG_MIN = KATALOG[0]; \/\/ 11,25 Grad: darunter gibt es kein Formteil zu kaufen\n        function peModell(theta, dn) {\n            var da = PE_DA[dn];\n            var rZul = PE_FAKTOR * da;\n            \/\/ Winkel, den eine Rohrlaenge elastisch aufnimmt (Bogenlaenge = R * Theta).\n            var thetaGeo = (ROHRLAENGE \/ rZul) * 180 \/ Math.PI;\n            \/\/ Schwelle: was die Biegung traegt, gedeckelt auf den kleinsten Katalogwinkel.\n            var grenze = Math.min(thetaGeo, KATALOG_MIN);\n            var rErf = theta > 0.0001 ? ROHRLAENGE \/ (theta * Math.PI \/ 180) : Infinity;\n            return { da: da, rZul: rZul, thetaGeo: thetaGeo, grenze: grenze, rErf: rErf };\n        }\n\n        function evaluate(theta, dn, material, weg) {\n            var alphaMax = alphaMaxFuer(dn, material);\n            var isPE = material === \"pehd\";\n            var effektivWeg = weg;\n            if (isPE) { effektivWeg = weg === \"muffen\" ? \"automatisch\" : weg; }\n            var kat = nearestKatalog(theta);\n            var out = { theta: theta, dn: dn, material: material, alphaMax: alphaMax, isPE: isPE, weg: effektivWeg };\n\n            if (theta < 0.05) {\n                out.fall = \"null\";\n                return out;\n            }\n            if (isPE) {\n                var pe = peModell(theta, dn);\n                out.pe = pe;\n                \/\/ Modus \"Formstueck\" zeigt das Bauteil auch unterhalb der Schwelle, dann\n                \/\/ aber ausdruecklich als erzwungen gekennzeichnet.\n                var peErzwungen = effektivWeg === \"formstueck\" ? theta <= pe.grenze + 1e-9 : false;\n                out.peErzwungen = peErzwungen;\n                if (peErzwungen ? false : theta <= pe.grenze + 1e-9) {\n                    out.fall = \"pe-bogen\";\n                    return out;\n                }\n                out.fall = \"pe-formteil\";\n                out.form = kat;\n                return out;\n            }\n            if (effektivWeg === \"muffen\") {\n                var mwF = muffenweg(theta, alphaMax);\n                var ueberlast = (theta \/ 8) > alphaMax + 1e-9;\n                out.mw = mwF;\n                out.fall = ueberlast ? \"fehler\" : \"muffen-erzwungen\";\n                return out;\n            }\n            if (effektivWeg === \"formstueck\") {\n                out.form = kat;\n                out.fall = \"formstueck-erzwungen\";\n                return out;\n            }\n            \/\/ Automatisch\n            if (theta <= alphaMax + 1e-9) {\n                out.fall = 1;\n                out.mw = muffenweg(theta, alphaMax);\n                return out;\n            }\n            var mw = muffenweg(theta, alphaMax);\n            var passtAlsMuffenweg = theta <= 15 + 1e-9 ? mw.n <= 6 : false;\n            if (passtAlsMuffenweg) {\n                out.fall = 2;\n                out.mw = mw;\n                return out;\n            }\n            out.fall = 3;\n            out.form = kat;\n            return out;\n        }\n\n        var state = { theta: 20, dn: 300, material: \"duktil\", weg: \"automatisch\" };\n        var MATERIAL_LABEL = { duktil: \"Duktilguss\", pvc: \"PVC-U\", pehd: \"PE-HD\" };\n\n        \/\/ ============ HERO-SVG: DRAUFSICHT ============\n        var A_PT = { x: 66, y: 214 };\n        var APEX = { x: 296, y: 214 };\n        var WISH_LEN = 132;\n\n        function drawWunsch(g, theta) {\n            var wishEnd = rotatePoint(APEX, theta, WISH_LEN);\n            line(g, A_PT.x, A_PT.y, APEX.x, APEX.y, { stroke: COLORS.wish, \"stroke-width\": 2, \"stroke-dasharray\": \"7 5\", \"stroke-linecap\": \"round\", opacity: 0.75 });\n            line(g, APEX.x, APEX.y, wishEnd.x, wishEnd.y, { stroke: COLORS.wish, \"stroke-width\": 2, \"stroke-dasharray\": \"7 5\", \"stroke-linecap\": \"round\", opacity: 0.75 });\n            \/\/ Theta-Hinweis bewusst UNTERHALB der ankommenden Leitung platziert (fester\n            \/\/ Versatz, unabhaengig vom Fall): die Loesung (Muffenweg\/Formstueck\/Fehler)\n            \/\/ liegt immer oberhalb des Knicks, so kollidiert das Label nie damit.\n            if (theta > 0.5) {\n                labelBox(g, APEX.x - 4, APEX.y + 34, String.fromCharCode(920) + \" = \" + degStr(theta), { width: 62, size: 8.6, color: COLORS.muted, fill: \"#f4f7f9\" });\n            }\n            return wishEnd;\n        }\n\n        function renderHero() {\n            var g = $(\"fmHeroDraw\");\n            clear(g);\n            syncSeg(\"fmDN\", \"data-fm-dn\", String(state.dn));\n            syncSeg(\"fmMaterial\", \"data-fm-material\", state.material);\n            syncSeg(\"fmWeg\", \"data-fm-weg\", state.weg);\n            syncSeg(\"fmKat\", \"data-fm-kat\", String(state.theta));\n\n            var isPeSelected = state.material === \"pehd\";\n            ROOT.querySelectorAll(\"#fmWeg button[data-fm-weg='muffen']\").forEach(function (b) {\n                b.disabled = isPeSelected;\n            });\n\n            var ev = evaluate(state.theta, state.dn, state.material, state.weg);\n\n            card(g, 24, 14, 572, 272, \"DRAUFSICHT DER LEITUNG (SCHEMATISCH, WINKEL \" + String.fromCharCode(220) + \"BERH\" + String.fromCharCode(214) + \"HT)\");\n            \/\/ PE-HD kommt geschweisst (12-m-Stangen oder Ringbund), nicht in 6-m-Steckmuffenrohren.\n            \/\/ Die 6 m bleiben dort trotzdem der Bezugswert, auf den die Bogenrechnung den Knick verteilt.\n            var laengeTxt = ev.isPE\n                ? \"Bezugsl\" + String.fromCharCode(228) + \"nge \" + ROHRLAENGE + \" m Trasse\"\n                : \"Rohrl\" + String.fromCharCode(228) + \"nge L = \" + ROHRLAENGE + \" m je Rohr (fest)\";\n            text(g, 40, 270, laengeTxt, { \"font-size\": 8, fill: COLORS.faint, \"font-weight\": 700 });\n\n            var wishEnd = drawWunsch(g, ev.theta);\n\n            if (ev.fall === \"null\") {\n                line(g, A_PT.x, A_PT.y, APEX.x + WISH_LEN, APEX.y, { stroke: COLORS.good, \"stroke-width\": 3, \"stroke-linecap\": \"round\" });\n                labelBox(g, (A_PT.x + APEX.x + WISH_LEN) \/ 2, APEX.y - 20, \"kein Knick, 0\" + String.fromCharCode(176), { width: 100, size: 9, color: COLORS.goodDeep, fill: \"#f0fdf4\", stroke: \"#bbf7d0\" });\n            } else if (ev.fall === 1) {\n                line(g, A_PT.x, A_PT.y, APEX.x, APEX.y, { stroke: COLORS.good, \"stroke-width\": 3.4, \"stroke-linecap\": \"round\" });\n                line(g, APEX.x, APEX.y, wishEnd.x, wishEnd.y, { stroke: COLORS.good, \"stroke-width\": 3.4, \"stroke-linecap\": \"round\" });\n                dotMark(g, APEX.x, APEX.y, COLORS.good, 5.4);\n                leader(g, wishEnd.x, wishEnd.y, wishEnd.x + 14, wishEnd.y - 16, COLORS.goodDeep);\n                labelBox(g, wishEnd.x + 34, wishEnd.y - 16, \"1 Muffe reicht\", { width: 92, size: 8.8, color: COLORS.goodDeep });\n            } else if (ev.fall === 2 || ev.fall === \"muffen-erzwungen\") {\n                var mw = ev.mw;\n                line(g, A_PT.x, A_PT.y, APEX.x, APEX.y, { stroke: COLORS.good, \"stroke-width\": 3, \"stroke-linecap\": \"round\" });\n                var visAlpha = Math.max(6, Math.min(16, mw.alphaUsed * 3));\n                \/\/ Zeichnerische Rohrlaenge: Grundwert wie bisher, danach so weit gestaucht,\n                \/\/ dass die eingerollte Kette unter der Kartenueberschrift und rechts im\n                \/\/ Kartenfeld bleibt. Rein zeichnerisch, n \/ Alpha \/ R bleiben unberuehrt.\n                var segLen = Math.max(30, Math.min(62, 210 \/ mw.n));\n                var sumX = 0, sumY = 0, extX = 0, extY = 0, kk;\n                for (kk = 1; kk <= mw.n; kk += 1) {\n                    sumX += Math.cos(kk * visAlpha * Math.PI \/ 180);\n                    sumY += Math.sin(kk * visAlpha * Math.PI \/ 180);\n                    extX = Math.max(extX, sumX);\n                    extY = Math.max(extY, sumY);\n                }\n                if (extY > 0.01) { segLen = Math.min(segLen, (APEX.y - 56) \/ extY); }\n                if (extX > 0.01) { segLen = Math.min(segLen, (578 - APEX.x) \/ extX); }\n                var cur = { x: APEX.x, y: APEX.y }, ang = 0, i;\n                var kette = [];\n                dotMark(g, cur.x, cur.y, COLORS.good, 4.6);\n                for (i = 0; i < mw.n; i += 1) {\n                    ang += visAlpha;\n                    var next = rotatePoint(cur, ang, segLen);\n                    line(g, cur.x, cur.y, next.x, next.y, { stroke: COLORS.good, \"stroke-width\": 3, \"stroke-linecap\": \"round\" });\n                    kette.push({ x1: cur.x, y1: cur.y, x2: next.x, y2: next.y });\n                    dotMark(g, next.x, next.y, COLORS.good, 4.2);\n                    cur = next;\n                }\n                \/\/ Belegte Flaechen: Rohrkette, Wunsch-Verlauf, Kartentitel, Theta-Label.\n                var mSegs = kette.concat([\n                    { x1: A_PT.x, y1: A_PT.y, x2: APEX.x, y2: APEX.y },\n                    { x1: APEX.x, y1: APEX.y, x2: wishEnd.x, y2: wishEnd.y }\n                ]);\n                var mBoxes = [\n                    { x: 34, y: 20, w: 400, h: 24 },\n                    { x: APEX.x - 35, y: APEX.y + 17, w: 62, h: 17 }\n                ];\n                \/\/ Erster Kandidat ist die bisherige Lage, damit kurze Ketten unveraendert\n                \/\/ bleiben. Danach rund um das Kettenende, zuletzt die immer freie Flaeche\n                \/\/ links der Kette (die liegt nie links von x = 296).\n                var mSpot = pickSpot([\n                    { x: cur.x + 50, y: cur.y - 20 },\n                    { x: cur.x + 50, y: cur.y + 30 },\n                    { x: cur.x + 84, y: cur.y + 4 },\n                    { x: cur.x, y: cur.y - 36 },\n                    { x: cur.x, y: cur.y + 48 },\n                    { x: cur.x - 52, y: cur.y - 28 },\n                    { x: cur.x - 84, y: cur.y + 4 },\n                    { x: cur.x - 52, y: cur.y + 40 },\n                    { x: 176, y: 170 },\n                    { x: 176, y: 124 },\n                    { x: 176, y: 78 }\n                ], 138, 17, mSegs, mBoxes, { x: 30, y: 22, w: 560, h: 234 });\n                var mvx = mSpot.x - cur.x, mvy = mSpot.y - cur.y;\n                var mvl = Math.sqrt(mvx * mvx + mvy * mvy);\n                if (mvl > 8) {\n                    var mStop = Math.max(22, mvl - 30);\n                    leader(g, cur.x, cur.y, cur.x + mvx \/ mvl * mStop, cur.y + mvy \/ mvl * mStop, COLORS.goodDeep);\n                }\n                labelBox(g, mSpot.x, mSpot.y, mw.n + String.fromCharCode(215) + \" Muffe, R \" + String.fromCharCode(8776) + \" \" + fmt(mw.r, 0) + \" m\", { width: 138, size: 8.6, color: COLORS.goodDeep });\n                text(g, 300, 274, \"Winkel je Muffe hier gr\" + String.fromCharCode(246) + String.fromCharCode(223) + \"er gezeichnet als real (\" + degStr(mw.alphaUsed) + \" je Sto\" + String.fromCharCode(223) + \")\", { \"font-size\": 7.6, fill: COLORS.faint, \"text-anchor\": \"middle\" });\n            } else if (ev.fall === \"pe-bogen\") {\n                \/\/ PE: kein Bauteil am Knick, die Leitung schneidet die Ecke als weicher\n                \/\/ elastischer Bogen. Tangentenlaenge nur zeichnerisch, Radius nicht massstaeblich.\n                var tanLen = 74;\n                var dIn = dirVec(0);\n                var pA = { x: APEX.x - dIn.dx * tanLen, y: APEX.y - dIn.dy * tanLen };\n                var dOut = dirVec(ev.theta);\n                var pB = { x: APEX.x + dOut.dx * tanLen, y: APEX.y + dOut.dy * tanLen };\n                line(g, A_PT.x, A_PT.y, pA.x, pA.y, { stroke: COLORS.good, \"stroke-width\": 3.4, \"stroke-linecap\": \"round\" });\n                path(g, \"M \" + pA.x.toFixed(1) + \" \" + pA.y.toFixed(1) + \" Q \" + APEX.x + \" \" + APEX.y + \" \" + pB.x.toFixed(1) + \" \" + pB.y.toFixed(1), { fill: \"none\", stroke: COLORS.good, \"stroke-width\": 3.4, \"stroke-linecap\": \"round\" });\n                line(g, pB.x, pB.y, wishEnd.x, wishEnd.y, { stroke: COLORS.good, \"stroke-width\": 3.4, \"stroke-linecap\": \"round\" });\n                var weldX = (A_PT.x + pA.x) \/ 2;\n                weldMark(g, weldX, A_PT.y, COLORS.goodDeep);\n                text(g, weldX, A_PT.y + 21, \"Schwei\" + String.fromCharCode(223) + \"naht\", { \"font-size\": 7.6, fill: COLORS.faint, \"text-anchor\": \"middle\", \"font-weight\": 700 });\n                leader(g, wishEnd.x, wishEnd.y, wishEnd.x + 14, wishEnd.y - 22, COLORS.goodDeep);\n                labelBox(g, wishEnd.x + 68, wishEnd.y - 22, \"ohne Formteil, R \" + String.fromCharCode(8805) + \" \" + mStr(ev.pe.rZul), { width: 164, size: 8.6, color: COLORS.goodDeep, fill: \"#f0fdf4\", stroke: \"#bbf7d0\" });\n                text(g, 320, 274, \"Bogen schematisch, Radius nicht ma\" + String.fromCharCode(223) + \"stabsgetreu\", { \"font-size\": 7.6, fill: COLORS.faint, \"text-anchor\": \"middle\" });\n            } else if (ev.fall === 3 || ev.fall === \"formstueck-erzwungen\" || ev.fall === \"pe-formteil\") {\n                var form = ev.form;\n                var armLen = 40;\n                \/\/ Das Bauteil sitzt als tangentiale Ausrundung IM Eck: die gruene\n                \/\/ Leitung stoppt vor dem Knickpunkt, dazwischen liegt der orange\n                \/\/ Kruemmer (Farbe wie in der Legende), und an seinen beiden Enden\n                \/\/ sitzen die Verbindungen: Muffen bei Guss\/PVC, Schweissnaehte bei PE.\n                var fit = filletBend(g, APEX, 0, form.angle, armLen, { stroke: COLORS.accent, \"stroke-width\": 6.5, \"stroke-linecap\": \"round\" });\n                line(g, A_PT.x, A_PT.y, fit.t1.x, fit.t1.y, { stroke: COLORS.good, \"stroke-width\": 3.4, \"stroke-linecap\": \"round\" });\n                var out2 = rotatePoint(APEX, form.angle, WISH_LEN * 0.92);\n                line(g, fit.t2.x, fit.t2.y, out2.x, out2.y, { stroke: COLORS.good, \"stroke-width\": 3.4, \"stroke-linecap\": \"round\" });\n                if (ev.isPE) {\n                    weldMark(g, fit.t1.x, fit.t1.y, COLORS.goodDeep, 3.8);\n                    weldMark(g, fit.t2.x, fit.t2.y, COLORS.goodDeep, 3.8);\n                } else {\n                    dotMark(g, fit.t1.x, fit.t1.y, COLORS.good, 4.6);\n                    dotMark(g, fit.t2.x, fit.t2.y, COLORS.good, 4.6);\n                }\n                \/\/ Formstueck-Label auf die Innenseite des Knicks, auf die Winkelhalbierende\n                \/\/ zwischen ankommendem und abgehendem Schenkel. Dieser Keil ist in jeder\n                \/\/ Winkellage leer, deshalb liegt die Box weder auf der gruenen Loesung noch\n                \/\/ auf der gestrichelten Trasse. Der Leader bindet sie an den Knick an.\n                var innerAng = (180 + form.angle) \/ 2;\n                var lblPt = rotatePoint(APEX, innerAng, 96);\n                \/\/ Startabstand 26: der Fillet-Bogen kreuzt die Winkelhalbierende bei\n                \/\/ grossen Winkeln bis rund 20 px vor dem Knick, der Leader beginnt dahinter.\n                var lblNear = rotatePoint(APEX, innerAng, 26);\n                var lblFar = rotatePoint(APEX, innerAng, 84);\n                leader(g, lblNear.x, lblNear.y, lblFar.x, lblFar.y, COLORS.accent);\n                \/\/ PE bekommt ein geschweisstes Formteil, kein Steckmuffen-Kruemmer.\n                var formWort = ev.isPE ? \"Formteil \" : \"Formst\" + String.fromCharCode(252) + \"ck \";\n                labelBox(g, lblPt.x, lblPt.y, formWort + degStr(form.angle), { width: 108, size: 9, color: COLORS.accentDeep, fill: \"#fdf1e4\", stroke: \"#f3d9b7\" });\n                if (form.delta > 0.2) {\n                    leader(g, out2.x, out2.y, wishEnd.x, wishEnd.y, COLORS.accent);\n                    \/\/ Delta-Label winkelabhaengig nach aussen setzen: Radius 176 liegt immer\n                    \/\/ hinter dem laengsten Schenkel (132), damit stossen die beiden Boxen auch\n                    \/\/ bei kleinem Theta nicht mehr aneinander und keine Box landet auf einer Linie.\n                    var midAng = (form.angle + ev.theta) \/ 2;\n                    var dPt = rotatePoint(APEX, midAng, 176);\n                    if (dPt.y < 66) { dPt.y = 66; }\n                    var anchor = { x: (out2.x + wishEnd.x) \/ 2, y: (out2.y + wishEnd.y) \/ 2 };\n                    var dvx = dPt.x - anchor.x;\n                    var dvy = dPt.y - anchor.y;\n                    var dvl = Math.sqrt(dvx * dvx + dvy * dvy);\n                    if (dvl > 0.5) {\n                        var back = dvl > 46 ? 34 : dvl * 0.45;\n                        leader(g, anchor.x, anchor.y, dPt.x - dvx \/ dvl * back, dPt.y - dvy \/ dvl * back, COLORS.accent);\n                    }\n                    labelBox(g, dPt.x, dPt.y, String.fromCharCode(916) + \" \" + degStr(form.delta), { width: 62, size: 8.4, color: COLORS.accentDeep, fill: \"#fdf1e4\", stroke: \"#f3d9b7\" });\n                }\n            } else if (ev.fall === \"fehler\") {\n                line(g, A_PT.x, A_PT.y, APEX.x, APEX.y, { stroke: COLORS.error, \"stroke-width\": 3, \"stroke-linecap\": \"round\" });\n                line(g, APEX.x, APEX.y, wishEnd.x, wishEnd.y, { stroke: COLORS.error, \"stroke-width\": 3.4, \"stroke-linecap\": \"round\" });\n                dotMark(g, APEX.x, APEX.y, COLORS.error, 5.4);\n                triWarn(g, APEX.x, APEX.y - 24, COLORS.error);\n                leader(g, wishEnd.x, wishEnd.y, wishEnd.x + 10, wishEnd.y - 24, COLORS.error);\n                labelBox(g, wishEnd.x + 60, wishEnd.y - 24, \"Abschr\" + String.fromCharCode(228) + \"gung \" + String.fromCharCode(252) + \"berschritten\", { width: 150, size: 8.6, color: COLORS.error, fill: COLORS.errorFill, stroke: COLORS.errorBorder });\n            }\n\n            renderVerdict(ev);\n            renderTiles(ev);\n            renderAlphaHint(ev);\n            renderZones(ev);\n        }\n\n        \/\/ ============ ZONEN-SKALA UNTER DEM SLIDER ============\n        \/\/ Die Schwellen sind dieselben wie in evaluate(), damit Balken und Befund\n        \/\/ nie auseinanderlaufen: bis alphaMax eine Muffe; Muffenweg bis\n        \/\/ min(15 Grad, 6 Muffen); im Modus Nur Muffen bis 8 Muffen, danach meldet\n        \/\/ die Entwurfsueberpruefung; PE elastisch bis zum kleinsten Katalogwinkel.\n        function zoneEintrag(w, color, txt) { return { w: w, color: color, txt: txt }; }\n        function renderZones(ev) {\n            var bar = $(\"fmZoneBar\"), zeile = $(\"fmZoneLine\");\n            clear(bar);\n            clear(zeile);\n            var AE = String.fromCharCode(228), UE = String.fromCharCode(252);\n            var zones = [];\n            if (ev.isPE) {\n                if (ev.weg === \"formstueck\") {\n                    zones.push(zoneEintrag(90, COLORS.accent, \"jeder Winkel: n\" + AE + \"chstes Formteil\"));\n                } else {\n                    var grenzePE = peModell(1, ev.dn).grenze;\n                    zones.push(zoneEintrag(grenzePE, COLORS.good, \"bis \" + degStr(grenzePE) + \" elastische Biegung\"));\n                    zones.push(zoneEintrag(90 - grenzePE, COLORS.accent, \"ab \" + degStr(grenzePE) + \" Formteil\"));\n                }\n            } else if (ev.weg === \"formstueck\") {\n                zones.push(zoneEintrag(90, COLORS.accent, \"jeder Winkel: n\" + AE + \"chster Katalogwinkel\"));\n            } else if (ev.weg === \"muffen\") {\n                var ende = Math.min(90, 8 * ev.alphaMax);\n                zones.push(zoneEintrag(ev.alphaMax, COLORS.goodDeep, \"bis \" + degStr(ev.alphaMax) + \" eine Muffe\"));\n                zones.push(zoneEintrag(ende - ev.alphaMax, COLORS.good, \"bis \" + degStr(ende) + \" Muffenweg\"));\n                zones.push(zoneEintrag(90 - ende, COLORS.error, \"ab \" + degStr(ende) + \" Abschr\" + AE + \"gung \" + UE + \"berschritten\"));\n            } else {\n                var mEnde = Math.min(15, 6 * ev.alphaMax);\n                zones.push(zoneEintrag(ev.alphaMax, COLORS.goodDeep, \"bis \" + degStr(ev.alphaMax) + \" eine Muffe\"));\n                zones.push(zoneEintrag(mEnde - ev.alphaMax, COLORS.good, \"bis \" + degStr(mEnde) + \" Muffenweg\"));\n                zones.push(zoneEintrag(90 - mEnde, COLORS.accent, \"ab \" + degStr(mEnde) + \" Formst\" + UE + \"ck\"));\n            }\n            zones.forEach(function (z) {\n                var seg = document.createElement(\"span\");\n                seg.style.width = (z.w \/ 90 * 100).toFixed(2) + \"%\";\n                seg.style.background = z.color;\n                bar.appendChild(seg);\n                var item = document.createElement(\"span\");\n                item.className = \"fm-zone-item\";\n                var sw = document.createElement(\"span\");\n                sw.className = \"fm-zone-swatch\";\n                sw.style.background = z.color;\n                item.appendChild(sw);\n                item.appendChild(document.createTextNode(z.txt));\n                zeile.appendChild(item);\n            });\n        }\n\n        \/\/ ============ BEFUND \/ TEXT ============\n        function chipSet(kind, txt) {\n            var c = $(\"fmChip\");\n            c.className = \"fm-chip \" + kind;\n            c.textContent = txt;\n        }\n        function dnTxt(dn) { return \"DN \" + dn; }\n\n        function renderVerdict(ev) {\n            var html, chipKind, chipTxt;\n            var dn = ev.dn, mat = MATERIAL_LABEL[ev.material];\n            if (ev.fall === \"null\") {\n                chipKind = \"is-good\"; chipTxt = \"kein Knick\";\n                html = \"<strong>Kein Richtungswechsel.<\/strong> Bei 0\" + String.fromCharCode(176) + \" gibt es nichts auszuwinkeln, die Leitung l\" + String.fromCharCode(228) + \"uft gerade durch. Zieh den Regler nach rechts, um einen Knick zu erzeugen.\";\n            } else if (ev.fall === \"pe-bogen\") {\n                chipKind = \"is-good\"; chipTxt = \"Elastische Biegung\";\n                html = \"<strong>PE wird geschwei\" + String.fromCharCode(223) + \"t, es gibt keine Muffe zum Auswinkeln.<\/strong> Bei diesem kleinen Knick von \" + degStr(ev.theta) + \" tr\" + String.fromCharCode(228) + \"gt der elastische Biegeradius des Rohres die Kurve: zul\" + String.fromCharCode(228) + \"ssig ist R \" + String.fromCharCode(8805) + \" 20 \" + String.fromCharCode(215) + \" Au\" + String.fromCharCode(223) + \"endurchmesser, bei \" + dnTxt(dn) + \" (au\" + String.fromCharCode(223) + \"en rund \" + fmt(ev.pe.da * 1000, 0) + \" mm) also etwa \" + mStr(ev.pe.rZul) + \". Selbst wenn der Knick auf nur sechs Metern Trasse sitzt, liegt der Bogen bei R \" + String.fromCharCode(8776) + \" \" + fmt(ev.pe.rErf, 0) + \" m und bleibt damit klar \" + String.fromCharCode(252) + \"ber dem Mindestradius. Erst ab \" + degStr(KATALOG_MIN) + \", dem kleinsten Katalogwinkel, kommt ein geschwei\" + String.fromCharCode(223) + \"tes Formteil ins Spiel.\";\n            } else if (ev.fall === \"pe-formteil\") {\n                var peForm = ev.form;\n                chipKind = \"is-accent\"; chipTxt = \"Formteil \" + degStr(peForm.angle) + \" (geschwei\" + String.fromCharCode(223) + \"t)\";\n                var peLead = ev.peErzwungen\n                    ? \"Erzwungenes Formteil (Modus Formst\" + String.fromCharCode(252) + \"ck).\"\n                    : \"Hier geh\" + String.fromCharCode(246) + \"rt ein geschwei\" + String.fromCharCode(223) + \"tes Formteil hin.\";\n                \/\/ Der erreichte Radius wird nur MIT Bezugslaenge ausgegeben und gegen den\n                \/\/ zulaessigen Mindestradius gestellt, sonst haengt die Zahl in der Luft.\n                var peR6 = \"Verteilt auf \" + ROHRLAENGE + \" m Trasse liegt der Bogen bei R \" + String.fromCharCode(8776) + \" \" + mStr(ev.pe.rErf) + \", zul\" + String.fromCharCode(228) + \"ssig sind R \" + String.fromCharCode(8805) + \" \" + mStr(ev.pe.rZul) + \" (20 \" + String.fromCharCode(215) + \" Au\" + String.fromCharCode(223) + \"endurchmesser).\";\n                \/\/ Oberhalb der Schwelle entscheidet der Praxisgrund, nicht die Geometrie: bei\n                \/\/ allen angebotenen Nennweiten traegt die Biegung rechnerisch weit mehr als\n                \/\/ 11,25 Grad. Der geometrische Hinweis kommt deshalb nur, wenn die Bezugslaenge\n                \/\/ wirklich nicht mehr reicht (theta groesser als thetaGeo).\n                var peGeoEng = ev.theta > ev.pe.thetaGeo + 1e-9\n                    ? \" Bei diesem Winkel reicht die Bezugsl\" + String.fromCharCode(228) + \"nge daf\" + String.fromCharCode(252) + \"r nicht mehr: Der Bogen bliebe unter dem Mindestradius, er m\" + String.fromCharCode(252) + \"sste \" + String.fromCharCode(252) + \"ber eine l\" + String.fromCharCode(228) + \"ngere Trasse laufen.\"\n                    : \"\";\n                var peWhy = ev.peErzwungen\n                    ? \"Bei \" + degStr(ev.theta) + \" tr\" + String.fromCharCode(228) + \"gt der elastische Biegeradius des Rohres den Knick allein, ein Bauteil brauchst du daf\" + String.fromCharCode(252) + \"r nicht. \" + peR6 + \" Unterhalb von \" + degStr(KATALOG_MIN) + \" gibt es ohnehin nichts zu kaufen, das ist der kleinste Formteilwinkel.\"\n                    : \"PE hat keine Muffe zum Auswinkeln, und ab \" + degStr(KATALOG_MIN) + \" gibt es ein Formteil zu kaufen. An einem Knoten ist das auch der praktische Weg: Der Richtungswechsel sitzt an einem Punkt, ein elastischer Bogen m\" + String.fromCharCode(252) + \"sste dagegen als gekr\" + String.fromCharCode(252) + \"mmter Graben mit definiertem Radius hergestellt werden. \" + peR6 + peGeoEng;\n                var peRest = peForm.delta < 0.3\n                    ? \"das trifft deinen Winkel fast genau\"\n                    : \"die Restabweichung von \" + degStr(peForm.delta) + \" nimmt die elastische Biegung des Rohres auf\";\n                html = \"<strong>\" + peLead + \"<\/strong> \" + peWhy + \" Der Katalog liefert das n\" + String.fromCharCode(228) + \"chste Formteil mit \" + degStr(peForm.angle) + \", \" + peRest + \".\";\n            } else if (ev.fall === 1) {\n                chipKind = \"is-good\"; chipTxt = \"1 Muffe reicht\";\n                html = \"<strong>Eine Muffe reicht.<\/strong> Bei \" + dnTxt(dn) + \" \/ \" + mat + \" sind je Sto\" + String.fromCharCode(223) + \" rund \" + degStr(ev.alphaMax) + \" zul\" + String.fromCharCode(228) + \"ssig, dein Knick von \" + degStr(ev.theta) + \" passt in einen einzigen Muffensto\" + String.fromCharCode(223) + \", kein Formst\" + String.fromCharCode(252) + \"ck n\" + String.fromCharCode(246) + \"tig.\";\n            } else if (ev.fall === 2 || ev.fall === \"muffen-erzwungen\") {\n                var mw = ev.mw;\n                var lead = ev.fall === \"muffen-erzwungen\" ? \"Erzwungener Muffenweg (Modus Nur Muffen).\" : \"\" + String.fromCharCode(220) + \"ber die Muffen auswinkeln.\";\n                chipKind = \"is-good\"; chipTxt = \"Muffenweg, \" + mw.n + \" Muffen\";\n                html = \"<strong>\" + lead + \"<\/strong> \" + mw.n + \" Muffen \" + String.fromCharCode(224) + \" \" + degStr(mw.alphaUsed) + \" ergeben einen weiten Bogen mit R \" + String.fromCharCode(8776) + \" \" + fmt(mw.r, 0) + \" m \" + String.fromCharCode(252) + \"ber rund \" + fmt(mw.bogen, 0) + \" m Leitungsl\" + String.fromCharCode(228) + \"nge. Das spart das Formst\" + String.fromCharCode(252) + \"ck, braucht aber Platz.\";\n            } else if (ev.fall === 3 || ev.fall === \"formstueck-erzwungen\") {\n                var form = ev.form;\n                chipKind = \"is-accent\"; chipTxt = \"Formst\" + String.fromCharCode(252) + \"ck \" + degStr(form.angle);\n                var restTxt = form.delta <= ev.alphaMax + 1e-9\n                    ? \"nimmt eine Muffe auf\" + (form.delta < 0.3 ? \" (passt fast exakt)\" : \"\")\n                    : \"braucht zus\" + String.fromCharCode(228) + \"tzlich \" + Math.ceil(form.delta \/ ev.alphaMax) + \" Muffen\";\n                html = \"<strong>Hier geh\" + String.fromCharCode(246) + \"rt ein Formst\" + String.fromCharCode(252) + \"ck hin.<\/strong> \" + degStr(ev.theta) + \" schafft keine Muffenkette mehr sinnvoll, der Katalog liefert den Kr\" + String.fromCharCode(252) + \"mmer \" + degStr(form.angle) + \"; die Restabweichung von \" + degStr(form.delta) + \" \" + restTxt + \".\";\n            } else {\n                chipKind = \"is-error\"; chipTxt = \"Abschr\" + String.fromCharCode(228) + \"gung \" + String.fromCharCode(252) + \"berschritten\";\n                var mwF = ev.mw;\n                html = \"<strong>Die Entwurfs\" + String.fromCharCode(252) + \"berpr\" + String.fromCharCode(252) + \"fung meldet: Abschr\" + String.fromCharCode(228) + \"gung \" + String.fromCharCode(252) + \"berschritten.<\/strong> Bei \" + dnTxt(dn) + \" \/ \" + mat + \" sind je Muffe nur \" + degStr(ev.alphaMax) + \" zul\" + String.fromCharCode(228) + \"ssig, hier br\" + String.fromCharCode(228) + \"uchte es \" + mwF.n + \" Muffen oder ein Formst\" + String.fromCharCode(252) + \"ck.\";\n            }\n            chipSet(chipKind, chipTxt);\n            $(\"fmVerdictText\").innerHTML = html;\n        }\n\n        function tileSet(id, val, isErr) {\n            var v = $(id);\n            v.textContent = val;\n            var box = $(id + \"Box\");\n            if (box) { box.classList.toggle(\"is-error\", Boolean(isErr)); }\n        }\n\n        function renderTiles(ev) {\n            if (ev.fall === \"null\") {\n                tileSet(\"fmTileWeg\", \"kein Knick\", false);\n                tileSet(\"fmTileMuffen\", \"0\", false);\n                tileSet(\"fmTileR\", \"-\", false);\n                tileSet(\"fmTileAlpha\", \"0\" + String.fromCharCode(176), false);\n                return;\n            }\n            if (ev.fall === \"pe-bogen\") {\n                \/\/ Kennzahl des PE-Falls ist der zulaessige Biegeradius, nicht die Muffe.\n                tileSet(\"fmTileWeg\", \"Elastische Biegung\", false);\n                tileSet(\"fmTileMuffen\", \"-\", false);\n                tileSet(\"fmTileR\", String.fromCharCode(8805) + \" \" + mStr(ev.pe.rZul), false);\n                tileSet(\"fmTileAlpha\", \"-\", false);\n                return;\n            }\n            if (ev.fall === \"pe-formteil\") {\n                tileSet(\"fmTileWeg\", \"Formteil \" + degStr(ev.form.angle), false);\n                tileSet(\"fmTileMuffen\", \"-\", false);\n                tileSet(\"fmTileR\", String.fromCharCode(8805) + \" \" + mStr(ev.pe.rZul), false);\n                tileSet(\"fmTileAlpha\", \"-\", false);\n                return;\n            }\n            if (ev.fall === 1) {\n                var mw1 = ev.mw;\n                tileSet(\"fmTileWeg\", \"1 Muffe\", false);\n                tileSet(\"fmTileMuffen\", \"1\", false);\n                tileSet(\"fmTileR\", fmt(mw1.r, 0) + \" m\", false);\n                tileSet(\"fmTileAlpha\", degStr(mw1.alphaUsed), false);\n                return;\n            }\n            if (ev.fall === 2 || ev.fall === \"muffen-erzwungen\") {\n                var mw2 = ev.mw;\n                tileSet(\"fmTileWeg\", \"Muffenweg\", false);\n                tileSet(\"fmTileMuffen\", String(mw2.n), false);\n                tileSet(\"fmTileR\", fmt(mw2.r, 0) + \" m\", false);\n                tileSet(\"fmTileAlpha\", degStr(mw2.alphaUsed), false);\n                return;\n            }\n            if (ev.fall === 3 || ev.fall === \"formstueck-erzwungen\") {\n                var form = ev.form;\n                tileSet(\"fmTileWeg\", \"Formst\" + String.fromCharCode(252) + \"ck \" + degStr(form.angle), false);\n                tileSet(\"fmTileMuffen\", form.delta <= ev.alphaMax + 1e-9 ? \"0 bis 1\" : String(Math.ceil(form.delta \/ ev.alphaMax)), false);\n                tileSet(\"fmTileR\", \"-\", false);\n                tileSet(\"fmTileAlpha\", degStr(form.delta) + \" Rest\", false);\n                return;\n            }\n            \/\/ Fehlerfall\n            var mwF = ev.mw;\n            tileSet(\"fmTileWeg\", \"Abschr\" + String.fromCharCode(228) + \"gung \" + String.fromCharCode(252) + \"berschritten\", true);\n            tileSet(\"fmTileMuffen\", String(mwF.n), true);\n            tileSet(\"fmTileR\", fmt(mwF.r, 0) + \" m\", true);\n            tileSet(\"fmTileAlpha\", degStr(mwF.alphaUsed), true);\n        }\n\n        function renderAlphaHint(ev) {\n            var el2 = $(\"fmAlphaHint\");\n            var dn = ev.dn, mat = MATERIAL_LABEL[ev.material];\n            if (ev.isPE) {\n                var peH = peModell(ev.theta, ev.dn);\n                el2.innerHTML = \"<strong>PE-HD wird geschwei\" + String.fromCharCode(223) + \"t:<\/strong> Kurven laufen \" + String.fromCharCode(252) + \"ber den zul\" + String.fromCharCode(228) + \"ssigen Biegeradius des Rohres, nicht \" + String.fromCharCode(252) + \"ber Muffenspiel, deshalb ist der Muffenweg hier deaktiviert. PE-Rohre werden nach Au\" + String.fromCharCode(223) + \"endurchmesser bezeichnet, \" + dnTxt(dn) + \" entspricht rund \" + fmt(peH.da * 1000, 0) + \" mm au\" + String.fromCharCode(223) + \"en. Als Mindestradius gelten je nach Rohrtemperatur und Sicherheitsreserve 20 bis 50 \" + String.fromCharCode(215) + \" Au\" + String.fromCharCode(223) + \"endurchmesser, hier gerechnet mit dem Faktor 20: R \" + String.fromCharCode(8805) + \" \" + mStr(peH.rZul) + \". Bis \" + degStr(KATALOG_MIN) + \" tr\" + String.fromCharCode(228) + \"gt die Biegung den Knick, dar\" + String.fromCharCode(252) + \"ber setzt du ein geschwei\" + String.fromCharCode(223) + \"tes Formteil.\";\n            } else {\n                \/\/ PVC-U rechnet bis DN 800 mit, gebaut wird es dort im deutschen Trinkwassernetz\n                \/\/ aber kaum. Statt die Nennweite zu sperren, ordnet ein Satz das ein.\n                var pvcGross = ev.material === \"pvc\" ? dn >= 400 : false;\n                var pvcTxt = pvcGross\n                    ? \" Gro\" + String.fromCharCode(223) + \"e Nennweiten in PVC-U bleiben im deutschen Trinkwassernetz die Ausnahme, ab etwa DN 400 liegen dort in der Regel Duktilguss oder PE. Der Wert steht hier zum Vergleich.\"\n                    : \"\";\n                el2.innerHTML = \"<strong>Zul\" + String.fromCharCode(228) + \"ssige Abschr\" + String.fromCharCode(228) + \"gung bei \" + dnTxt(dn) + \" \/ \" + mat + \":<\/strong> ca. \" + degStr(ev.alphaMax) + \" je Muffe.\" + pvcTxt;\n            }\n        }\n\n        \/\/ ============ STEUERUNG ============\n        ROOT.addEventListener(\"click\", function (e) {\n            var dnBtn = e.target.closest ? e.target.closest(\"[data-fm-dn]\") : null;\n            if (dnBtn ? ROOT.contains(dnBtn) : false) { state.dn = parseInt(dnBtn.getAttribute(\"data-fm-dn\"), 10); renderHero(); return; }\n            var matBtn = e.target.closest ? e.target.closest(\"[data-fm-material]\") : null;\n            if (matBtn ? ROOT.contains(matBtn) : false) {\n                state.material = matBtn.getAttribute(\"data-fm-material\");\n                if (state.material === \"pehd\" ? state.weg === \"muffen\" : false) { state.weg = \"automatisch\"; }\n                renderHero();\n                return;\n            }\n            var wegBtn = e.target.closest ? e.target.closest(\"[data-fm-weg]\") : null;\n            if (wegBtn ? ROOT.contains(wegBtn) : false) {\n                if (wegBtn.disabled) { return; }\n                state.weg = wegBtn.getAttribute(\"data-fm-weg\");\n                renderHero();\n                return;\n            }\n            var katBtn = e.target.closest ? e.target.closest(\"[data-fm-kat]\") : null;\n            if (katBtn ? ROOT.contains(katBtn) : false) {\n                state.theta = parseFloat(katBtn.getAttribute(\"data-fm-kat\"));\n                \/\/ Slider mitfuehren: der programmatische Wert darf die step-Rasterung\n                \/\/ verlassen (11,25 \/ 22,5), erst der naechste Drag rastet wieder ganzzahlig.\n                $(\"fmTheta\").value = state.theta;\n                $(\"fmThetaText\").textContent = degStr(state.theta);\n                renderHero();\n                return;\n            }\n        });\n\n        ROOT.addEventListener(\"input\", function (e) {\n            if (e.target.id === \"fmTheta\") {\n                state.theta = parseFloat(e.target.value);\n                if (isNaN(state.theta)) { state.theta = 0; }\n                $(\"fmThetaText\").textContent = degStr(state.theta);\n                renderHero();\n            }\n        });\n\n        renderHero();\n    })();\n<\/script>\n\n","protected":false},"excerpt":{"rendered":"<p>Formst&uuml;ck oder Muffe? Knick in der Leitung: Formst&uuml;ck setzen oder &uuml;ber die Muffen auswinkeln? Du siehst die Entscheidung live, ganz [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_uag_custom_page_level_css":"","site-sidebar-layout":"default","site-content-layout":"","ast-site-content-layout":"default","site-content-style":"default","site-sidebar-style":"default","ast-global-header-display":"","ast-banner-title-visibility":"disabled","ast-main-header-display":"","ast-hfb-above-header-display":"","ast-hfb-below-header-display":"","ast-hfb-mobile-header-display":"","site-post-title":"","ast-breadcrumbs-content":"","ast-featured-img":"","footer-sml-layout":"","ast-disable-related-posts":"","theme-transparent-header-meta":"","adv-header-id-meta":"","stick-header-meta":"","header-above-stick-meta":"","header-main-stick-meta":"","header-below-stick-meta":"","astra-migrate-meta-layouts":"default","ast-page-background-enabled":"default","ast-page-background-meta":{"desktop":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"ast-content-background-meta":{"desktop":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"footnotes":""},"categories":[48],"tags":[],"class_list":["post-2409","post","type-post","status-publish","format-standard","hentry","category-druckrohrnetz"],"uagb_featured_image_src":{"full":false,"thumbnail":false,"medium":false,"medium_large":false,"large":false,"1536x1536":false,"2048x2048":false},"uagb_author_info":{"display_name":false,"author_link":"https:\/\/cad-kompass.de\/?author=1"},"uagb_comment_info":0,"uagb_excerpt":"Formst&uuml;ck oder Muffe? Knick in der Leitung: Formst&uuml;ck setzen oder &uuml;ber die Muffen auswinkeln? Du siehst die Entscheidung live, ganz [&hellip;]","_links":{"self":[{"href":"https:\/\/cad-kompass.de\/index.php?rest_route=\/wp\/v2\/posts\/2409","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/cad-kompass.de\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/cad-kompass.de\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/cad-kompass.de\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/cad-kompass.de\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=2409"}],"version-history":[{"count":1,"href":"https:\/\/cad-kompass.de\/index.php?rest_route=\/wp\/v2\/posts\/2409\/revisions"}],"predecessor-version":[{"id":2410,"href":"https:\/\/cad-kompass.de\/index.php?rest_route=\/wp\/v2\/posts\/2409\/revisions\/2410"}],"wp:attachment":[{"href":"https:\/\/cad-kompass.de\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=2409"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/cad-kompass.de\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=2409"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/cad-kompass.de\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=2409"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}