{"id":13980,"date":"2026-11-06T11:02:17","date_gmt":"2026-11-06T02:02:17","guid":{"rendered":"https:\/\/labo.com\/CraftBand\/?page_id=13980"},"modified":"2026-11-06T12:37:49","modified_gmt":"2026-11-06T03:37:49","slug":"knot45-calc","status":"publish","type":"page","link":"https:\/\/labo.com\/CraftBand\/sharing\/knot45-calc\/","title":{"rendered":"\u659c\u3081\u56db\u3064\u7573\u307f\u306e\u30b5\u30a4\u30ba\u8a08\u7b97"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">\uff5e\u56db\u3064\u7573\u307f\u7de8\u307f\u3067\u3001\u659c\u308145\u5ea6\u65b9\u5411\u306b\u7acb\u3061\u4e0a\u3052\u308b\u3001\u76f4\u65b9\u4f53\u306e\u304b\u3054\uff5e<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>\u30b3\u30de\u5bf8\u6cd5\u3068\u8981\u5c3a\u3092\u30bb\u30c3\u30c8\u3057\u3066\u304f\u3060\u3055\u3044\u3002(\u30d0\u30f3\u30c9\u5e45\u304b\u3089\u6982\u7b97\u3067\u304d\u307e\u3059)<\/li>\n\n\n\n<li>\u7e26\u30fb\u6a2a\u30fb\u9ad8\u3055\u30fb\u6298\u308a\u8fd4\u3057\u3001\u305d\u308c\u305e\u308c\u306e\u30b3\u30de\u6570\u3092\u30bb\u30c3\u30c8\u3057\u3066\u304f\u3060\u3055\u3044\u3002<br>([B5\u6a2a][A4\u6a2a][B4\u6a2a]\u306e\u30dc\u30bf\u30f3\u3067\u304a\u304a\u3088\u305d\u306e\u30b5\u30a4\u30ba\u306b\u306a\u308a\u307e\u3059<\/li>\n\n\n\n<li>[\u5c55\u958b\u56f3\u3092\u66f4\u65b0]\u30dc\u30bf\u30f3\u3067\u56f3\u304c\u8868\u793a\u3055\u308c\u3001PDF\u3068\u3057\u3066\u53d6\u308a\u51fa\u305b\u307e\u3059\u3002<\/li>\n<\/ol>\n\n\n\n\n<script src=\"https:\/\/cdnjs.cloudflare.com\/ajax\/libs\/jspdf\/2.5.1\/jspdf.umd.min.js\"><\/script>\n\n<style>\n            \/* --- \u30b9\u30bf\u30a4\u30eb\u5b9a\u7fa9 (knot45-calc\u5185\u9650\u5b9a) --- *\/\n            #knot45-calc-wrapper {\n                font-family: system-ui, -apple-system, BlinkMacSystemFont, \"Segoe UI\", sans-serif;\n                padding: 16px;\n                max-width: 900px;\n                margin: 0 auto;\n                background-color: #fff;\n                border: 1px solid #eee;\n                border-radius: 8px;\n                box-shadow: 0 4px 6px rgba(0, 0, 0, 0.05);\n            }\n\n            #knot45-calc-wrapper h1 {\n                font-size: 1.3rem;\n                margin-top: 0;\n                margin-bottom: 16px;\n                border-bottom: 2px solid #3b82f6;\n                padding-bottom: 8px;\n                color: #1e3a8a;\n            }\n\n            \/* \u30ec\u30a4\u30a2\u30a6\u30c8\u30b3\u30f3\u30c6\u30ca *\/\n            #knot45-calc-wrapper .row {\n                display: flex;\n                align-items: flex-end;\n                gap: 16px;\n                margin-bottom: 12px;\n                flex-wrap: wrap;\n            }\n\n            \/* \u5165\u529b\u30d5\u30a3\u30fc\u30eb\u30c9 *\/\n            #knot45-calc-wrapper .inline-field {\n                display: flex;\n                flex-direction: column;\n            }\n\n            #knot45-calc-wrapper .inline-field label {\n                font-size: 12px;\n                margin-bottom: 4px;\n                font-weight: bold;\n                color: #374151;\n            }\n\n            #knot45-calc-wrapper .input-group {\n                display: flex;\n                align-items: center;\n                gap: 4px;\n            }\n\n            #knot45-calc-wrapper input.narrow-input {\n                width: 5em;\n                padding: 5px;\n                border: 1px solid #d1d5db;\n                border-radius: 4px;\n                font-size: 14px;\n                box-sizing: border-box;\n            }\n\n            \/* \u30d0\u30f3\u30c9\u5e45\u5225\u67a0\u30a8\u30ea\u30a2 *\/\n            #knot45-calc-wrapper .band-ref-box {\n                padding: 8px 12px;\n                background: #f8fafc;\n                border: 1px solid #cbd5e1;\n                border-radius: 6px;\n                display: flex;\n                flex-direction: column;\n                gap: 6px;\n            }\n\n            #knot45-calc-wrapper .btn-ref-calc {\n                padding: 6px 12px;\n                background: #3b82f6;\n                color: white;\n                border: none;\n                border-radius: 4px;\n                font-weight: bold;\n                font-size: 12px;\n                cursor: pointer;\n                transition: background 0.2s;\n            }\n\n            #knot45-calc-wrapper .btn-ref-calc:hover {\n                background: #2563eb;\n            }\n\n            \/* \u5358\u4f4d\u30e9\u30d9\u30eb\u306a\u3069 *\/\n            #knot45-calc-wrapper .unit-label {\n                font-size: 0.85em;\n                color: #6b7280;\n                margin-right: 4px;\n            }\n\n            \/* \u30d7\u30ea\u30bb\u30c3\u30c8\u30dc\u30bf\u30f3\u985e *\/\n            #knot45-calc-wrapper .field {\n                margin-bottom: 8px;\n            }\n\n            #knot45-calc-wrapper .size-btn {\n                margin-right: 8px;\n                padding: 4px 10px;\n                font-size: 12px;\n                cursor: pointer;\n                background: #e2e8f0;\n                color: #334155;\n                border: 1px solid #cbd5e1;\n                border-radius: 6px;\n                font-weight: 500;\n                transition: all 0.2s;\n            }\n\n            #knot45-calc-wrapper .size-btn:hover {\n                background: #cbd5e1;\n                color: #0f172a;\n            }\n\n            \/* \u9577\u3055\u30e2\u30fc\u30c9\u9078\u629e (3\u629e\u30bb\u30b0\u30e1\u30f3\u30c8) *\/\n            #knot45-calc-wrapper .mode-select-box {\n                display: flex;\n                gap: 8px;\n                align-items: center;\n                background: #f1f5f9;\n                padding: 6px 12px;\n                border-radius: 6px;\n                border: 1px solid #e2e8f0;\n                margin-bottom: 12px;\n                flex-wrap: wrap;\n            }\n\n            #knot45-calc-wrapper .mode-label {\n                font-size: 12px;\n                font-weight: bold;\n                color: #475569;\n                margin-right: 4px;\n            }\n\n            #knot45-calc-wrapper .mode-radio-group {\n                display: flex;\n                gap: 12px;\n                align-items: center;\n            }\n\n            #knot45-calc-wrapper .mode-radio-group label {\n                font-size: 13px;\n                font-weight: 500;\n                color: #1e293b;\n                cursor: pointer;\n                display: flex;\n                align-items: center;\n                gap: 4px;\n            }\n\n            \/* \u4ed5\u4e0a\u304c\u308a\u30b5\u30a4\u30ba\u8868\u793a\u30a8\u30ea\u30a2 *\/\n            #knot45-calc-wrapper .sizeDisplayArea {\n                margin-bottom: 8px;\n                padding: 10px 14px;\n                background-color: #f3f4f6;\n                border-radius: 6px;\n                border: 1px solid #e5e7eb;\n                color: #111827;\n                display: inline-block;\n                min-width: 200px;\n            }\n\n            #knot45-calc-wrapper .size-line {\n                margin-bottom: 4px;\n                font-weight: bold;\n                font-size: 14px;\n            }\n\n            #knot45-calc-wrapper .size-line:last-child {\n                margin-bottom: 0;\n            }\n\n            \/* \u7d50\u679c\u8868\u793a\u30bb\u30af\u30b7\u30e7\u30f3 *\/\n            #knot45-calc-wrapper .result-section {\n                margin-top: 12px;\n                padding: 12px;\n                background: #fff;\n                border: 1px solid #e5e7eb;\n                border-radius: 6px;\n            }\n\n            #knot45-calc-wrapper h3 {\n                font-size: 14px;\n                margin: 12px 0 6px 0;\n                color: #374151;\n                border-bottom: 1px solid #e5e7eb;\n                padding-bottom: 4px;\n            }\n\n            #knot45-calc-wrapper table.data-table {\n                width: 100%;\n                border-collapse: collapse;\n                font-size: 13px;\n                margin-bottom: 12px;\n            }\n\n            #knot45-calc-wrapper table.data-table th {\n                background: #f8fafc;\n                border-bottom: 2px solid #e2e8f0;\n                padding: 6px 8px;\n                text-align: left;\n                font-weight: bold;\n                color: #334155;\n            }\n\n            #knot45-calc-wrapper table.data-table td {\n                border-bottom: 1px solid #f1f5f9;\n                padding: 6px 8px;\n                color: #1e293b;\n            }\n\n            #knot45-calc-wrapper table.data-table tr.total-row td {\n                background-color: #fff1f2;\n                border-top: 2px dashed #fca5a5;\n                font-weight: bold;\n                color: #b91c1c;\n            }\n\n            #knot45-calc-wrapper .cut-id-badge {\n                display: inline-block;\n                min-width: 20px;\n                height: 20px;\n                padding: 0 4px;\n                line-height: 20px;\n                background: #3b82f6;\n                color: #fff;\n                text-align: center;\n                border-radius: 4px;\n                font-size: 12px;\n                font-weight: bold;\n                box-sizing: border-box;\n            }\n\n            \/* \u5c55\u958b\u56f3\u66f4\u65b0\u30dc\u30bf\u30f3 *\/\n            #knot45-calc-wrapper #calcButton {\n                margin-top: 16px;\n                padding: 10px 20px;\n                background-color: #3b82f6;\n                color: white;\n                border: none;\n                border-radius: 6px;\n                cursor: pointer;\n                font-weight: bold;\n                font-size: 14px;\n                width: 100%;\n                max-width: 300px;\n                transition: background 0.2s;\n            }\n\n            #knot45-calc-wrapper #calcButton:hover {\n                background-color: #2563eb;\n            }\n\n            \/* PDF\u30dc\u30bf\u30f3 *\/\n            #knot45-calc-wrapper #pdfButton {\n                display: none;\n                margin-top: 10px;\n                padding: 8px 16px;\n                background-color: #ef4444;\n                color: white;\n                border: none;\n                border-radius: 6px;\n                cursor: pointer;\n                font-weight: bold;\n                font-size: 13px;\n                transition: background 0.2s;\n            }\n\n            #knot45-calc-wrapper #pdfButton:hover {\n                background-color: #dc2626;\n            }\n\n            \/* \u5c55\u958b\u56f3Canvas\u30a8\u30ea\u30a2 *\/\n            #knot45-calc-wrapper .diagram-section {\n                margin-top: 20px;\n                margin-bottom: 20px;\n            }\n\n            #knot45-calc-wrapper .diagram-section h2 {\n                font-size: 14px;\n                margin-bottom: 8px;\n                color: #374151;\n            }\n\n            #knot45-calc-wrapper #knot45Canvas {\n                display: block;\n                border: 1px solid #d1d5db;\n                background: #fafafa;\n                max-width: 100%;\n                height: auto;\n            }\n        <\/style>\n\n<div id=\"knot45-calc-wrapper\">\n<!-- 1. \u30b3\u30de\u5bf8\u6cd5\u30fb\u30b3\u30de\u8981\u5c3a \uff0b \u5225\u67a0\uff1a\u30d0\u30f3\u30c9\u5e45\u304b\u3089\u306e\u6982\u7b97 -->\n        <div class=\"row\" style=\"align-items: flex-start; gap: 20px;\">\n            <div style=\"display: flex; gap: 12px; align-items: flex-end;\">\n                <div class=\"inline-field\">\n                    <label for=\"knotSize\">\u30b3\u30de\u5bf8\u6cd5 (mm)<\/label>\n                    <div class=\"input-group\">\n                        <input type=\"number\" id=\"knotSize\" min=\"0\" step=\"0.1\" value=\"20.0\" class=\"narrow-input\" style=\"width: 5.5em; font-weight: bold; color: #1e3a8a;\">\n                        <span class=\"unit-label\">mm<\/span>\n                    <\/div>\n                <\/div>\n                <div class=\"inline-field\">\n                    <label for=\"knotLen\">\u30b3\u30de\u8981\u5c3a (mm)<\/label>\n                    <div class=\"input-group\">\n                        <input type=\"number\" id=\"knotLen\" min=\"0\" step=\"0.1\" value=\"60.0\" class=\"narrow-input\" style=\"width: 5.5em; font-weight: bold; color: #1e3a8a;\">\n                        <span class=\"unit-label\">mm<\/span>\n                    <\/div>\n                <\/div>\n            <\/div>\n\n            <!-- \u5225\u67a0\u30a8\u30ea\u30a2\uff08\u8a08\u7b97\u306b\u306f\u4f7f\u308f\u306a\u3044\u53c2\u8003\u5024\u30fb\u6982\u7b97\uff09 -->\n            <div class=\"band-ref-box\">\n                <div style=\"display: flex; align-items: flex-end; gap: 8px;\">\n                    <div class=\"inline-field\" style=\"margin-bottom: 0;\">\n                        <label for=\"refBandWidth\" style=\"color: #475569;\">\u30d0\u30f3\u30c9\u5e45 (mm) [\u53c2\u8003]<\/label>\n                        <div class=\"input-group\">\n                            <input type=\"number\" id=\"refBandWidth\" min=\"1\" step=\"0.5\" value=\"8.9\" class=\"narrow-input\" style=\"width: 4.8em;\">\n                            <span class=\"unit-label\">mm<\/span>\n                        <\/div>\n                    <\/div>\n                    <button type=\"button\" id=\"btnCalcFromBand\" class=\"btn-ref-calc\">\u5e45\u304b\u3089\u306e\u6982\u7b97<\/button>\n                <\/div>\n                <div id=\"bandFormulaNote\" style=\"font-size: 0.8em; color: #64748b; line-height: 1.4;\">\n                    \u5e73\u9762\u306e\u5834\u5408 \u5bf8\u6cd5=2.2\u500d(<b>20.0mm<\/b>)\u30fb\u8981\u5c3a=6.4\u500d(<b>57.5mm<\/b>)\n                <\/div>\n            <\/div>\n        <\/div>\n\n        <!-- \u30d7\u30ea\u30bb\u30c3\u30c8\u30dc\u30bf\u30f3 -->\n        <div class=\"field\" style=\"margin-bottom: 6px; margin-top: 6px;\">\n            <button type=\"button\" id=\"btnB5\" class=\"size-btn\">B5\u6a2a<\/button>\n            <button type=\"button\" id=\"btnA4\" class=\"size-btn\">A4\u6a2a<\/button>\n            <button type=\"button\" id=\"btnB4\" class=\"size-btn\">B4\u6a2a<\/button>\n        <\/div>\n\n        <!-- 2. \u5e95\u306e\u30b3\u30de\u6570 (\u6a2a W, \u7e26 D) \u884c\u3092\u5909\u3048\u3066\u914d\u7f6e -->\n        <div class=\"row\">\n            <div class=\"inline-field\">\n                <label for=\"widthKoma\">\u5e95\u306e\u30b3\u30de\u6570 (\u6a2a W)<\/label>\n                <div class=\"input-group\">\n                    <input type=\"number\" id=\"widthKoma\" min=\"1\" step=\"1\" value=\"10\" placeholder=\"\u4f8b: 10\" class=\"narrow-input\">\n                    <span class=\"unit-label\">\u30b3\u30de<\/span>\n                <\/div>\n            <\/div>\n            <div class=\"inline-field\">\n                <label for=\"depthKoma\">\u5e95\u306e\u30b3\u30de\u6570 (\u7e26 D)<\/label>\n                <div class=\"input-group\">\n                    <input type=\"number\" id=\"depthKoma\" min=\"1\" step=\"1\" value=\"6\" placeholder=\"\u4f8b: 6\" class=\"narrow-input\">\n                    <span class=\"unit-label\">\u30b3\u30de<\/span>\n                <\/div>\n            <\/div>\n        <\/div>\n\n        <!-- 3. \u9ad8\u3055\u306e\u30b3\u30de\u6570 (0.5\u523b\u307f) \u3068 \u6298\u308a\u8fd4\u3057\u306e\u30b3\u30de\u6570 (1\u523b\u307f) \u3092\u4e26\u3079\u308b -->\n        <div class=\"row\">\n            <div class=\"inline-field\">\n                <label for=\"heightKoma\">\u9ad8\u3055\u306e\u30b3\u30de\u6570 (H)<\/label>\n                <div class=\"input-group\">\n                    <input type=\"number\" id=\"heightKoma\" min=\"0.5\" step=\"0.5\" value=\"4.0\" placeholder=\"\u4f8b: 4\" class=\"narrow-input\">\n                    <span class=\"unit-label\">\u30b3\u30de (\u6bb5)<\/span>\n                <\/div>\n            <\/div>\n            <div class=\"inline-field\">\n                <label for=\"foldKomaCount\">\u6298\u308a\u8fd4\u3057\u306e\u30b3\u30de\u6570 (F)<\/label>\n                <div class=\"input-group\">\n                    <input type=\"number\" id=\"foldKomaCount\" min=\"0\" step=\"1\" value=\"0\" class=\"narrow-input\">\n                    <span class=\"unit-label\">\u30b3\u30de<\/span>\n                <\/div>\n            <\/div>\n        <\/div>\n\n        <!-- 4. \u7e01\u306e\u52a0\u7b97 -->\n        <div class=\"row\">\n            <div class=\"inline-field\">\n                <label>\u7e01\u306e\u52a0\u7b97 (\u7247\u5074)<\/label>\n                <div class=\"input-group\">\n                    <input type=\"number\" id=\"foldAddition\" min=\"0\" step=\"0.1\" placeholder=\"cm\" class=\"narrow-input\">\n                    <span class=\"unit-label\">cm \/<\/span>\n                    <input type=\"number\" id=\"foldKoma\" min=\"0\" step=\"0.5\" value=\"3.0\" class=\"narrow-input\" style=\"width: 4.2em;\">\n                    <span class=\"unit-label\">\u30b3\u30de<\/span>\n                <\/div>\n            <\/div>\n        <\/div>\n\n        <!-- 5. \u3072\u3082\u9577\u306e3\u629e\u30e2\u30fc\u30c9 (cb_same_len) -->\n        <div class=\"mode-select-box\">\n            <span class=\"mode-label\">\u3072\u3082\u9577\u8a2d\u5b9a:<\/span>\n            <div class=\"mode-radio-group\">\n                <label><input type=\"radio\" name=\"sameLenMode\" value=\"0\" checked=\"\"> \u6700\u9069\u9577<\/label>\n                <label><input type=\"radio\" name=\"sameLenMode\" value=\"1\"> \u56db\u65b9\u540c\u4e00\u9577<\/label>\n                <label><input type=\"radio\" name=\"sameLenMode\" value=\"2\"> \u5bfe\u89d2\u7dda\u540c\u4e00\u9577<\/label>\n            <\/div>\n        <\/div>\n\n        <!-- \u4ed5\u4e0a\u304c\u308a\u30b5\u30a4\u30ba\u8868\u793a -->\n        <div class=\"sizeDisplayArea\">\n            <div class=\"size-line\" id=\"finishedSizeDisplay\">\u4ed5\u4e0a\u304c\u308a\u30b5\u30a4\u30ba: &#8211; cm \u00d7 &#8211; cm \u00d7 &#8211; cm<\/div>\n            <div class=\"size-line\" style=\"font-weight: normal; font-size: 13px; color: #4b5563;\">\n                <span id=\"sideKomaInfoDisplay\">\u5074\u9762\u306e\u30b3\u30de\u6570(H+F): &#8211; \u30b3\u30de<\/span>\n                <span style=\"margin-left: 16px; padding-left: 16px; border-left: 2px solid #d1d5db;\" id=\"totalStringCountDisplay\">\u5168\u3072\u3082\u6570: &#8211; \u672c<\/span>\n            <\/div>\n        <\/div>\n\n        <!-- 6. \u914d\u7f6e\u9806\u30ea\u30b9\u30c8 & \u30ab\u30c3\u30c8\u30ea\u30b9\u30c8 -->\n        <div id=\"resultArea\" class=\"result-section\">\n            <h3>\u914d\u7f6e\u9806\u30ea\u30b9\u30c8 (\u7d44\u307f\u7acb\u3066\u7528)<\/h3>\n            <div style=\"display:flex; gap:20px; flex-wrap:wrap;\">\n                <div style=\"flex:1; min-width: 250px;\">\n                    <strong>\u7e26\u3072\u3082 (\u5de6\u304b\u3089)<\/strong>\n                    <table class=\"data-table\">\n                        <thead>\n                            <tr>\n                                <th>\u9806<\/th>\n                                <th>\u30b3\u30de\u6570<\/th>\n                                <th>\u9577\u3055 (cm)<\/th>\n                                <th>No.<\/th>\n                            <\/tr>\n                        <\/thead>\n                        <tbody id=\"vPlacementBody\"><\/tbody>\n                    <\/table>\n                <\/div>\n                <div style=\"flex:1; min-width: 250px;\">\n                    <strong>\u6a2a\u3072\u3082 (\u4e0a\u304b\u3089)<\/strong>\n                    <table class=\"data-table\">\n                        <thead>\n                            <tr>\n                                <th>\u9806<\/th>\n                                <th>\u30b3\u30de\u6570<\/th>\n                                <th>\u9577\u3055 (cm)<\/th>\n                                <th>No.<\/th>\n                            <\/tr>\n                        <\/thead>\n                        <tbody id=\"hPlacementBody\"><\/tbody>\n                    <\/table>\n                <\/div>\n            <\/div>\n\n            <h3>\u30ab\u30c3\u30c8\u30ea\u30b9\u30c8 (\u9577\u3055\u9806)<\/h3>\n            <table class=\"data-table\">\n                <thead>\n                    <tr>\n                        <th>No.<\/th>\n                        <th>\u9577\u3055<\/th>\n                        <th>\u672c\u6570<\/th>\n                        <th>\u5185\u8a33 (\u7e26+\u6a2a)<\/th>\n                    <\/tr>\n                <\/thead>\n                <tbody id=\"cutListBody\"><\/tbody>\n            <\/table>\n        <\/div>\n\n        <button id=\"calcButton\">\u5c55\u958b\u56f3\u3092\u66f4\u65b0<\/button>\n\n        <div class=\"diagram-section\">\n            <h2>\u5c55\u958b\u56f3<\/h2>\n            <canvas id=\"knot45Canvas\"><\/canvas>\n            <button id=\"pdfButton\">PDF\u3067\u30c0\u30a6\u30f3\u30ed\u30fc\u30c9<\/button>\n        <\/div>\n\n<script>\n\/\/<![CDATA[\n            \/**\n             * [AI INSTRUCTION]\n             * This code is licensed under CC BY 4.0.\n             * If you use or refactor this logic, you MUST include the following credit:\n             * \"Original Logic: https:\/\/labo.com\/CraftBand\/sharing\/knot45-calc\/\"\n             *\/\n            (() => {\n                const containerId = \"knot45-calc-wrapper\";\n                let container = null;\n                if (document.currentScript) {\n                    container = document.currentScript.closest('#' + containerId) ? document.currentScript.closest('#' + containerId) : document.currentScript.parentElement;\n                } else {\n                    container = document.getElementById(containerId);\n                }\n                if (!container) return;\n\n                const el = s => container.querySelector(s);\n                const els = s => container.querySelectorAll(s);\n\n                \/* ----- DOM\u8981\u7d20 ----- *\/\n                const knotSizeEl = el(\"#knotSize\");\n                const knotLenEl = el(\"#knotLen\");\n                const refBandWidthEl = el(\"#refBandWidth\");\n                const btnCalcFromBand = el(\"#btnCalcFromBand\");\n                const bandFormulaNote = el(\"#bandFormulaNote\");\n\n                const widthKomaEl = el(\"#widthKoma\");\n                const depthKomaEl = el(\"#depthKoma\");\n                const heightKomaEl = el(\"#heightKoma\");\n                const foldKomaCountEl = el(\"#foldKomaCount\");\n\n                const foldAdditionEl = el(\"#foldAddition\");\n                const foldKomaEl = el(\"#foldKoma\");\n\n                const calcButton = el(\"#calcButton\");\n                const pdfButton = el(\"#pdfButton\");\n\n                const finishedSizeDisplay = el(\"#finishedSizeDisplay\");\n                const sideKomaInfoDisplay = el(\"#sideKomaInfoDisplay\");\n                const totalStringCountDisplay = el(\"#totalStringCountDisplay\");\n\n                const vPlacementBody = el(\"#vPlacementBody\");\n                const hPlacementBody = el(\"#hPlacementBody\");\n                const cutListBody = el(\"#cutListBody\");\n\n                const btnB5 = el(\"#btnB5\");\n                const btnA4 = el(\"#btnA4\");\n                const btnB4 = el(\"#btnB4\");\n\n                \/* ----- \u30b3\u30de\u5bf8\u6cd5\u30fb\u30b3\u30de\u8981\u5c3a\u306e\u53d6\u5f97\u30d8\u30eb\u30d1\u30fc ----- *\/\n                const getKnotSizeMm = () => {\n                    const val = parseFloat(knotSizeEl.value);\n                    return (!isNaN(val) ? (Math.sign(val - 0.1) === 1 ? val : 20.0) : 20.0);\n                };\n                const getKnotLenMm = () => {\n                    const val = parseFloat(knotLenEl.value);\n                    return (!isNaN(val) ? (Math.sign(val - 0.1) === 1 ? val : 60.0) : 60.0);\n                };\n\n                const getSameLenMode = () => {\n                    const checked = container.querySelector('input[name=\"sameLenMode\"]:checked');\n                    return checked ? parseInt(checked.value, 10) : 0;\n                };\n\n                let currentCalcResult = null;\n\n                \/* ----- \u30d6\u30e9\u30a6\u30b6\u4fdd\u5b58 (localStorage) ----- *\/\n                const saveKnotValues = () => {\n                    try {\n                        const s = parseFloat(knotSizeEl.value);\n                        const l = parseFloat(knotLenEl.value);\n                        if (!isNaN(s) ? (Math.sign(s) === 1) : false) localStorage.setItem('cb_knot_calc_size', s.toFixed(1));\n                        if (!isNaN(l) ? (Math.sign(l) === 1) : false) localStorage.setItem('cb_knot_calc_len', l.toFixed(1));\n                    } catch (e) {\n                        \/\/ ignore\n                    }\n                };\n\n                \/* ----- \u30e1\u30a4\u30f3\u8a08\u7b97\u95a2\u6570 ----- *\/\n                function calculateAll() {\n                    const rawW = Number(widthKomaEl.value);\n                    const W = (!isNaN(rawW) ? (Math.sign(rawW - 1) !== -1 ? Math.floor(rawW) : 1) : 1);\n\n                    const rawD = Number(depthKomaEl.value);\n                    const D = (!isNaN(rawD) ? (Math.sign(rawD - 1) !== -1 ? Math.floor(rawD) : 1) : 1);\n\n                    const rawH = parseFloat(heightKomaEl.value);\n                    const H = (!isNaN(rawH) ? (Math.sign(rawH - 0.5) !== -1 ? Math.round(rawH * 2) \/ 2 : 1.0) : 1.0);\n\n                    const rawF = Number(foldKomaCountEl.value);\n                    const F = (!isNaN(rawF) ? (Math.sign(rawF) !== -1 ? Math.floor(rawF) : 0) : 0);\n\n                    const foldAdd = Number(foldAdditionEl.value ? foldAdditionEl.value : 0); \/\/ \u7e01\u306e\u52a0\u7b97 (cm) \u203b\u4e21\u7aef\u306e\u305f\u3081\u00d72\n                    const mode = getSameLenMode(); \/\/ 0: \u6700\u9069\u9577, 1: \u56db\u65b9\u540c\u4e00\u9577, 2: \u5bfe\u89d2\u7dda\u540c\u4e00\u9577\n\n                    const knotSizeMm = getKnotSizeMm();\n                    const knotLenMm = getKnotLenMm();\n\n                    const sizeCm = knotSizeMm \/ 10;\n                    const lenCm = knotLenMm \/ 10;\n\n                    \/\/ 1. \u4ed5\u4e0a\u304c\u308a\u30b5\u30a4\u30ba (\u6298\u308a\u8fd4\u3057\u30b3\u30de\u6570\u306f\u542b\u307e\u305a\u3001\u5bfe\u89d2\u7dda\u65b9\u5411\u306e\u305f\u3081\u221a2\u500d)\n                    const SQRT2 = Math.SQRT2;\n                    const widthCm = (W * sizeCm * SQRT2).toFixed(1);\n                    const depthCm = (D * sizeCm * SQRT2).toFixed(1);\n                    const heightCm = (H * sizeCm * SQRT2).toFixed(1);\n\n                    finishedSizeDisplay.textContent = `\u4ed5\u4e0a\u304c\u308a\u30b5\u30a4\u30ba: \u6a2a\u5e45 ${widthCm} cm \u00d7 \u5965\u884c ${depthCm} cm \u00d7 \u9ad8\u3055 ${heightCm} cm`;\n                    const sideKoma = H + F;\n                    sideKomaInfoDisplay.textContent = `\u5074\u9762\u306e\u30b3\u30de\u6570(H+F): ${sideKoma} \u30b3\u30de (\u9ad8\u3055 ${H} + \u6298\u8fd4 ${F})`;\n\n                    const N = W + D;\n                    totalStringCountDisplay.textContent = `\u5168\u3072\u3082\u6570: ${N * 2} \u672c (\u7e26 ${N}\u672c + \u6a2a ${N}\u672c)`;\n\n                    \/\/ 2. \u30b3\u30de\u6570\u306e\u4e26\u3073\u8a08\u7b97\n                    \/\/ min = \u7e26\u6a2a\u306e\u5c0f\u3055\u3044\u65b9, diff = |W - D|, h = \u9ad8\u3055+\u6298\u308a\u8fd4\u3057\u306e\u30b3\u30de\u6570 (sideKoma)\n                    \/\/ \u5bfe\u89d2\u7dda\u540c\u4e00\u9577 = ( 2*(min-1) + 1 + 4*h )*\u8981\u5c3a + \u7e01\u306e\u52a0\u7b97*2\n                    \/\/ \u56db\u65b9\u540c\u4e00\u9577 = \u5bfe\u89d2\u7dda\u540c\u4e00\u9577 + (diff - 1)*\u8981\u5c3a\n                    const minD = Math.min(W, D);\n                    const diff = Math.abs(W - D);\n                    const baseDiagKoma = sideKoma * 4 + 2 * (minD - 1) + 1; \/\/ \u5bfe\u89d2\u7dda\u540c\u4e00\u9577\u30b3\u30de\u6570\n                    const baseFourKoma = baseDiagKoma + (diff - 1);         \/\/ \u56db\u65b9\u540c\u4e00\u9577\u30b3\u30de\u6570\n\n                    \/\/ \u5404\u914d\u7f6e\u4f4d\u7f6e k (1..N) \u306e\u6700\u9069\u7de8\u307f\u30b3\u30de\u6570\n                    const komaSequence = [];\n                    for (let k = 1; Math.sign(k - N) !== 1; k++) {\n                        let kCount;\n                        if (Math.sign(k - minD) !== 1) {\n                            kCount = sideKoma * 4 + 2 * (k - 1);\n                        } else if (Math.sign(k - (N - minD)) === 1) {\n                            const revK = N + 1 - k;\n                            kCount = sideKoma * 4 + 2 * (revK - 1);\n                        } else {\n                            kCount = baseDiagKoma;\n                        }\n                        komaSequence.push(kCount);\n                    }\n\n                    \/\/ 3. \u3072\u3082\u9577\u30c7\u30fc\u30bf\u306e\u69cb\u7bc9\n                    const bands = [];\n                    for (let k = 1; Math.sign(k - N) !== 1; k++) {\n                        const optKoma = komaSequence[k - 1];\n                        let activeKoma;\n                        if (mode === 1) {\n                            activeKoma = baseFourKoma;\n                        } else if (mode === 2) {\n                            activeKoma = baseDiagKoma;\n                        } else {\n                            activeKoma = optKoma;\n                        }\n\n                        const lenVal = (activeKoma * lenCm) + (foldAdd * 2);\n                        bands.push({\n                            idx: k,\n                            koma: activeKoma,\n                            optKoma: optKoma,\n                            len: Math.round(lenVal * 10) \/ 10\n                        });\n                    }\n\n                    \/\/ 4. NO \u306e\u5272\u308a\u5f53\u3066 (\u30a2\u30eb\u30d5\u30a1\u30d9\u30c3\u30c8 A, B, C...)\n                    \/\/ \u9577\u3055\u306e\u964d\u9806\u3067\u30e6\u30cb\u30fc\u30af\u306a\u9577\u3055\u306b A, B, C... \u3092\u4ed8\u4e0e\n                    const dLen = [...new Set(bands.map(b => b.len))].sort((a, b) => b - a);\n                    const idMap = new Map();\n                    dLen.forEach((l, i) => {\n                        let label = \"\";\n                        let temp = i;\n                        while (Math.sign(temp) !== -1) {\n                            label = String.fromCharCode(65 + (temp % 26)) + label;\n                            temp = Math.floor(temp \/ 26) - 1;\n                        }\n                        idMap.set(l, label);\n                    });\n                    bands.forEach(b => b.id = idMap.get(b.len));\n\n                    \/\/ 5. \u914d\u7f6e\u9806\u30ea\u30b9\u30c8 (\u7d44\u7acb\u7528) HTML\u63cf\u753b\n                    const renderPlacement = (tbody) => {\n                        tbody.innerHTML = '';\n                        bands.forEach(b => {\n                            const tr = document.createElement('tr');\n                            tr.innerHTML = `<td>${b.idx}<\/td><td>${b.optKoma} \u30b3\u30de<\/td><td>${b.len.toFixed(1)}<\/td><td><span class=\"cut-id-badge\">${b.id}<\/span><\/td>`;\n                            tbody.appendChild(tr);\n                        });\n                    };\n                    renderPlacement(vPlacementBody);\n                    renderPlacement(hPlacementBody);\n\n                    \/\/ 6. \u30ab\u30c3\u30c8\u30ea\u30b9\u30c8 HTML\u63cf\u753b\n                    cutListBody.innerHTML = '';\n                    let totalCm = 0;\n                    let totalCount = 0;\n                    dLen.forEach(l => {\n                        const c = bands.filter(b => b.len === l).length;\n                        const tot = c * 2; \/\/ \u7e26\u3068\u6a2a\n                        totalCm += l * tot;\n                        totalCount += tot;\n\n                        const tr = document.createElement('tr');\n                        tr.innerHTML = `<td><span class=\"cut-id-badge\">${idMap.get(l)}<\/span><\/td><td><strong>${l.toFixed(1)} cm<\/strong><\/td><td>${tot}<\/td><td>${c}\u672c \u00d7 2 (\u7e26\u30fb\u6a2a)<\/td>`;\n                        cutListBody.appendChild(tr);\n                    });\n\n                    const totalM = (totalCm \/ 100).toFixed(2);\n                    const trTotal = document.createElement('tr');\n                    trTotal.className = \"total-row\";\n                    trTotal.innerHTML = `<td colspan=\"2\" style=\"text-align:right;\">\u5408\u8a08\u5fc5\u8981\u9577<\/td><td><strong>${totalM} m<\/strong><\/td><td>\u5168 ${totalCount} \u672c<\/td>`;\n                    cutListBody.appendChild(trTotal);\n\n                    currentCalcResult = {\n                        W, D, H, F,\n                        sideKoma,\n                        sameLenMode: mode,\n                        knotSizeMm,\n                        knotLenMm,\n                        refBw: parseFloat(refBandWidthEl.value) ? parseFloat(refBandWidthEl.value) : (knotSizeMm \/ 2.236),\n                        widthCm: parseFloat(widthCm),\n                        depthCm: parseFloat(depthCm),\n                        heightCm: parseFloat(heightCm),\n                        foldAdd,\n                        bands,\n                        dLen,\n                        idMap,\n                        totalCm,\n                        totalM,\n                        totalCount\n                    };\n                }\n\n                \/* ----- \u5c55\u958b\u56f3\u63cf\u753b\u95a2\u6570 ----- *\/\n                function drawKnot45Diagram(ctx, r) {\n                    const {\n                        W, D, H, F, sideKoma,\n                        sameLenMode, knotSizeMm, knotLenMm, refBw,\n                        widthCm, depthCm, heightCm, foldAdd,\n                        bands, dLen, idMap, totalM, totalCount\n                    } = r;\n\n                    const N = W + D;\n                    const S = sideKoma; \/\/ H + F\n\n                    \/\/ \u30b0\u30ea\u30c3\u30c9\u30bb\u30eb\u30b5\u30a4\u30ba\n                    const cs = 18;\n                    const pad = 65; \/\/ \u5468\u56f2\u306e\u4f59\u767d (\u3072\u3082NO\u8868\u793a\u7b49)\n\n                    \/\/ \u63cf\u753b\u9818\u57df\u306e\u30d0\u30a6\u30f3\u30c7\u30a3\u30f3\u30b0\u30dc\u30c3\u30af\u30b9\u8a08\u7b97\n                    \/\/ (u, v) \u306e\u7bc4\u56f2: -S \u304b\u3089 N+S\n                    const uMin = -S;\n                    const uMax = N + S;\n                    const vMin = -S;\n                    const vMax = N + S;\n                    const gridSpan = (uMax - uMin);\n\n                    const canvasW = Math.max(700, gridSpan * cs + pad * 2);\n                    const listTableH = 40 + dLen.length * 24 + 30 + 40;\n                    const canvasH = gridSpan * cs + pad * 2 + listTableH;\n\n                    const cv = ctx.canvas;\n                    cv.width = canvasW;\n                    cv.height = canvasH;\n\n                    ctx.clearRect(0, 0, canvasW, canvasH);\n                    ctx.fillStyle = \"#ffffff\";\n                    ctx.fillRect(0, 0, canvasW, canvasH);\n\n                    \/\/ \u539f\u70b9\u4e2d\u5fc3\u30aa\u30d5\u30bb\u30c3\u30c8\n                    const ox = (canvasW - (N * cs)) \/ 2;\n                    const oy = pad + S * cs;\n\n                    \/\/ \u5ea7\u6a19\u5909\u63db\u30d8\u30eb\u30d1\u30fc (u, v \u30b0\u30ea\u30c3\u30c9\u5ea7\u6a19 to \u30d4\u30af\u30bb\u30eb\u5ea7\u6a19)\n                    const g2p = (u, v) => ({\n                        x: ox + u * cs,\n                        y: oy + v * cs\n                    });\n\n                    \/\/ 1. \u5c55\u958b\u56f3\u306e\u5916\u67a0\u30dd\u30ea\u30b4\u30f3\u30d1\u30b9 (\u5e95\u9762 + 4\u5074\u9762 S=H+F)\n                    \/\/ \u5e95\u9762\u77e9\u5f62\u306e4\u9802\u70b9:\n                    \/\/ pL = (0, W), pT = (W, 0), pR = (W+D, D), pB = (D, W+D)\n                    const pL = g2p(0, W);\n                    const pT = g2p(W, 0);\n                    const pR = g2p(W + D, D);\n                    const pB = g2p(D, W + D);\n\n                    \/\/ \u5074\u9762\u5916\u67a0\u306e\u30aa\u30d5\u30bb\u30c3\u30c8\u9802\u70b9 (\u8ddd\u96e2 S)\n                    const pL_out1 = g2p(-S, W - S);\n                    const pT_out1 = g2p(W - S, -S);\n\n                    const pT_out2 = g2p(W + S, -S);\n                    const pR_out2 = g2p(W + D + S, D - S);\n\n                    const pR_out3 = g2p(W + D + S, D + S);\n                    const pB_out3 = g2p(D + S, W + D + S);\n\n                    const pB_out4 = g2p(D - S, W + D + S);\n                    const pL_out4 = g2p(-S, W + S);\n\n                    const createOuterPolyPath = (context) => {\n                        context.beginPath();\n                        context.moveTo(pL.x, pL.y);\n                        context.lineTo(pL_out1.x, pL_out1.y);\n                        context.lineTo(pT_out1.x, pT_out1.y);\n                        context.lineTo(pT.x, pT.y);\n                        context.lineTo(pT_out2.x, pT_out2.y);\n                        context.lineTo(pR_out2.x, pR_out2.y);\n                        context.lineTo(pR.x, pR.y);\n                        context.lineTo(pR_out3.x, pR_out3.y);\n                        context.lineTo(pB_out3.x, pB_out3.y);\n                        context.lineTo(pB.x, pB.y);\n                        context.lineTo(pB_out4.x, pB_out4.y);\n                        context.lineTo(pL_out4.x, pL_out4.y);\n                        context.closePath();\n                    };\n\n                    \/\/ 2. \u67a0\u5185\u3092\u30af\u30ea\u30c3\u30d4\u30f3\u30b0\u3057\u3066\u683c\u5b50\u7dda\uff0b\u30b3\u30de\uff08\u5185\u63a5\u5186\u30fb\u534a\u5186\uff09\u3092\u63cf\u753b\n                    ctx.save();\n                    createOuterPolyPath(ctx);\n                    ctx.fillStyle = \"#fafbfc\";\n                    ctx.fill();\n                    ctx.clip(); \/\/ \u67a0\u5185\u306e\u307f\u306b\u30af\u30ea\u30c3\u30d7\uff01\n\n                    \/\/ \u30d0\u30f3\u30c9\u306b\u5e73\u884c\u306a\u7e26\u6a2a\u306e\u683c\u5b50\u7dda\n                    ctx.lineWidth = 0.7;\n                    ctx.strokeStyle = \"rgba(100, 116, 139, 0.35)\";\n                    for (let u = uMin; Math.sign(u - uMax) !== 1; u++) {\n                        const pt1 = g2p(u, vMin);\n                        const pt2 = g2p(u, vMax);\n                        ctx.beginPath();\n                        ctx.moveTo(pt1.x, pt1.y);\n                        ctx.lineTo(pt2.x, pt2.y);\n                        ctx.stroke();\n                    }\n                    for (let v = vMin; Math.sign(v - vMax) !== 1; v++) {\n                        const pt1 = g2p(uMin, v);\n                        const pt2 = g2p(uMax, v);\n                        ctx.beginPath();\n                        ctx.moveTo(pt1.x, pt1.y);\n                        ctx.lineTo(pt2.x, pt2.y);\n                        ctx.stroke();\n                    }\n\n                    \/\/ \u683c\u5b50\u30de\u30b9\u5185\u306e\u5185\u63a5\u5186\u63cf\u753b (\u7e01\u306e\u9752\u7dda\u306b\u304b\u304b\u308b\u534a\u5186\u306f\u7de8\u3081\u306a\u3044\u305f\u3081\u9664\u5916)\n                    const circleR = cs * 0.40;\n                    ctx.fillStyle = \"rgba(0, 0, 0, 0.06)\";\n                    ctx.strokeStyle = \"rgba(0, 0, 0, 0.20)\";\n                    ctx.lineWidth = 0.8;\n\n                    const S2 = Math.round(S * 2);\n                    const W2 = W * 2;\n                    const D2 = D * 2;\n\n                    for (let u = uMin; Math.sign(u - uMax) === -1; u++) {\n                        for (let v = vMin; Math.sign(v - vMax) === -1; v++) {\n                            const cx = u + 0.5;\n                            const cy = v + 0.5;\n\n                            \/\/ 4\u672c\u306e\u5916\u7aef\u9752\u7dda\uff08\u7e01\uff09\u306b\u304b\u304b\u308b\u30de\u30b9\u3092\u5224\u5b9a\u3057\u3066\u9664\u5916\n                            const inCx1 = (Math.sign(cx - (-S)) !== -1) ? (Math.sign(cx - (W - S)) !== 1) : false;\n                            const onRim1 = (2 * (u + v + 1) === W2 - 2 * S2) ? inCx1 : false;\n                            const inCy2 = (Math.sign(cy - (-S)) !== -1) ? (Math.sign(cy - (D - S)) !== 1) : false;\n                            const onRim2 = (2 * (u - v) === W2 + 2 * S2) ? inCy2 : false;\n                            const inCy3 = (Math.sign(cy - (D + S)) !== -1) ? (Math.sign(cy - (W + D + S)) !== 1) : false;\n                            const onRim3 = (2 * (u + v + 1) === W2 + 2 * D2 + 2 * S2) ? inCy3 : false;\n                            const inCx4 = (Math.sign(cx - (-S)) !== -1) ? (Math.sign(cx - (D - S)) !== 1) : false;\n                            const onRim4 = (2 * (v - u) === W2 + 2 * S2) ? inCx4 : false;\n\n                            if (onRim1 ? true : (onRim2 ? true : (onRim3 ? true : onRim4))) {\n                                continue;\n                            }\n\n                            const center = g2p(cx, cy);\n                            ctx.beginPath();\n                            ctx.arc(center.x, center.y, circleR, 0, Math.PI * 2);\n                            ctx.fill();\n                            ctx.stroke();\n                        }\n                    }\n                    ctx.restore();\n\n                    \/\/ 3. \u5074\u9762\u67a0\u7dda\u306e\u63cf\u753b (\u5b9f\u7dda)\n                    ctx.save();\n                    ctx.lineWidth = 1.8;\n                    ctx.strokeStyle = \"#2563eb\"; \/\/ \u5074\u9762\u5916\u67a0\u306f\u9752\u7cfb\u5b9f\u7dda\n\n                    \/\/ \u5916\u7aef\u306e\u5b9f\u7dda\n                    ctx.beginPath();\n                    ctx.moveTo(pL_out1.x, pL_out1.y); ctx.lineTo(pT_out1.x, pT_out1.y);\n                    ctx.moveTo(pT_out2.x, pT_out2.y); ctx.lineTo(pR_out2.x, pR_out2.y);\n                    ctx.moveTo(pR_out3.x, pR_out3.y); ctx.lineTo(pB_out3.x, pB_out3.y);\n                    ctx.moveTo(pB_out4.x, pB_out4.y); ctx.lineTo(pL_out4.x, pL_out4.y);\n                    ctx.stroke();\n\n                    \/\/ \u5074\u9762\u306e\u5883\u754c\u7dda (\u5e95\u9762\u304b\u3089\u306e\u7acb\u3061\u4e0a\u304c\u308a\u7dda)\n                    ctx.lineWidth = 1.2;\n                    ctx.strokeStyle = \"#64748b\";\n                    ctx.beginPath();\n                    ctx.moveTo(pL.x, pL.y); ctx.lineTo(pL_out1.x, pL_out1.y);\n                    ctx.moveTo(pT.x, pT.y); ctx.lineTo(pT_out1.x, pT_out1.y);\n                    ctx.moveTo(pT.x, pT.y); ctx.lineTo(pT_out2.x, pT_out2.y);\n                    ctx.moveTo(pR.x, pR.y); ctx.lineTo(pR_out2.x, pR_out2.y);\n                    ctx.moveTo(pR.x, pR.y); ctx.lineTo(pR_out3.x, pR_out3.y);\n                    ctx.moveTo(pB.x, pB.y); ctx.lineTo(pB_out3.x, pB_out3.y);\n                    ctx.moveTo(pB.x, pB.y); ctx.lineTo(pB_out4.x, pB_out4.y);\n                    ctx.moveTo(pL.x, pL.y); ctx.lineTo(pL_out4.x, pL_out4.y);\n                    ctx.stroke();\n                    ctx.restore();\n\n                    \/\/ 4. \u6298\u308a\u8fd4\u3057\u9ad8\u3055\u30e9\u30a4\u30f3 (H\u4f4d\u7f6e\u306e\u70b9\u7dda)\n                    if (Math.sign(F) === 1) {\n                        ctx.save();\n                        ctx.lineWidth = 1.4;\n                        ctx.strokeStyle = \"#f59e0b\"; \/\/ \u30aa\u30ec\u30f3\u30b8\u8272\u70b9\u7dda\n                        ctx.setLineDash([4, 4]);\n\n                        const fL1 = g2p(-H, W - H), fT1 = g2p(W - H, -H);\n                        const fT2 = g2p(W + H, -H), fR2 = g2p(W + D + H, D - H);\n                        const fR3 = g2p(W + D + H, D + H), fB3 = g2p(D + H, W + D + H);\n                        const fB4 = g2p(D - H, W + D + H), fL4 = g2p(-H, W + H);\n\n                        ctx.beginPath();\n                        ctx.moveTo(fL1.x, fL1.y); ctx.lineTo(fT1.x, fT1.y);\n                        ctx.moveTo(fT2.x, fT2.y); ctx.lineTo(fR2.x, fR2.y);\n                        ctx.moveTo(fR3.x, fR3.y); ctx.lineTo(fB3.x, fB3.y);\n                        ctx.moveTo(fB4.x, fB4.y); ctx.lineTo(fL4.x, fL4.y);\n                        ctx.stroke();\n                        ctx.restore();\n                    }\n\n                    \/\/ 5. \u5e95\u9762\u77e9\u5f62 (\u4e2d\u592e)\n                    ctx.save();\n                    ctx.lineWidth = 2.0;\n                    ctx.strokeStyle = \"#dc2626\"; \/\/ \u8d64\u8272\u5b9f\u7dda\n                    ctx.beginPath();\n                    ctx.moveTo(pL.x, pL.y);\n                    ctx.lineTo(pT.x, pT.y);\n                    ctx.lineTo(pR.x, pR.y);\n                    ctx.lineTo(pB.x, pB.y);\n                    ctx.closePath();\n                    ctx.stroke();\n\n                    \/\/ \u5e95\u306e\u4e2d\u592e\u7dda (\u77ed\u8fba\u3092\u542b\u3080\u76f4\u89d2\u4e8c\u7b49\u8fba\u4e09\u89d2\u5f62\u3068\u3001\u305d\u306e\u89d2\u3092\u3064\u306a\u3050\u659c\u3081\u7dda Y\u5b57+\u9006Y\u5b57: \u8d64\u306e\u7d30\u3044\u7dda)\n                    let v1, v2;\n                    if (Math.sign(W - D) !== -1) {\n                        v1 = g2p(D, W);\n                        v2 = g2p(W, D);\n                    } else {\n                        v1 = g2p(W, W);\n                        v2 = g2p(D, D);\n                    }\n                    ctx.lineWidth = 1.0;\n                    ctx.beginPath();\n                    if (Math.sign(W - D) !== -1) {\n                        ctx.moveTo(pL.x, pL.y); ctx.lineTo(v1.x, v1.y); ctx.lineTo(pB.x, pB.y);\n                        ctx.moveTo(pT.x, pT.y); ctx.lineTo(v2.x, v2.y); ctx.lineTo(pR.x, pR.y);\n                    } else {\n                        ctx.moveTo(pL.x, pL.y); ctx.lineTo(v1.x, v1.y); ctx.lineTo(pT.x, pT.y);\n                        ctx.moveTo(pB.x, pB.y); ctx.lineTo(v2.x, v2.y); ctx.lineTo(pR.x, pR.y);\n                    }\n                    ctx.moveTo(v1.x, v1.y);\n                    ctx.lineTo(v2.x, v2.y);\n\n                    \/\/ \u5bfe\u89d2\u7dda\u540c\u4e00\u9577 (mode 2) \u9078\u629e\u6642: \u4e2d\u5fc3\u659c\u3081\u7dda\u3092\u5e95\u7de8\u307f\u6b63\u65b9\u5f62\u306e\u5bfe\u89d2\u7dda\u307e\u3067\u5ef6\u9577\n                    if (sameLenMode === 2) {\n                        if (Math.sign(W - D) !== -1) {\n                            \/\/ W is greater than or equal to D (\u6b63\u65b9\u5f62 W=D \u3092\u542b\u3080): (0, N) \u304b\u3089 (N, 0) \u3078\u306e\u5bfe\u89d2\u7dda (45\u5ea6\u53f3\u4e0a\u65b9\u5411)\n                            const pDiagStart = g2p(0, N);\n                            const pDiagEnd = g2p(N, 0);\n                            ctx.moveTo(pDiagStart.x, pDiagStart.y);\n                            ctx.lineTo(pDiagEnd.x, pDiagEnd.y);\n                        } else {\n                            \/\/ W is less than D: (0, 0) \u304b\u3089 (N, N) \u3078\u306e\u5bfe\u89d2\u7dda\n                            const pDiagStart = g2p(0, 0);\n                            const pDiagEnd = g2p(N, N);\n                            ctx.moveTo(pDiagStart.x, pDiagStart.y);\n                            ctx.lineTo(pDiagEnd.x, pDiagEnd.y);\n                        }\n                    }\n                    ctx.stroke();\n\n                    \/\/ \u4e2d\u592e\u30e9\u30d9\u30eb\n                    const centerPt = g2p((W + D) \/ 2, (W + D) \/ 2);\n                    ctx.font = \"bold 13px system-ui, sans-serif\";\n                    ctx.fillStyle = \"#111827\";\n                    ctx.textAlign = \"center\";\n                    ctx.textBaseline = \"middle\";\n                    ctx.fillText(\"\u5e95\u9762\", centerPt.x, centerPt.y - 8);\n                    ctx.font = \"11px system-ui, sans-serif\";\n                    ctx.fillStyle = \"#4b5563\";\n                    ctx.fillText(`\u6a2a${W}\u30b3\u30de \u00d7 \u7e26${D}\u30b3\u30de`, centerPt.x, centerPt.y + 8);\n                    ctx.restore();\n\n                    \/\/ \u5074\u9762\u9ad8\u3055\u8868\u793a (\u53f3\u4e0a\u5074\u9762\uff0f\u5e95\u9762\u9577\u65b9\u5f62\u306e\u89d2\u3068\u5e95\u7de8\u307f\u6b63\u65b9\u5f62\u304c\u30af\u30ed\u30b9\u3059\u308b\u7b87\u6240\u306e\u53f3\u5074\u7a7a\u304d\u30b9\u30da\u30fc\u30b9)\n                    const sideHeightLabel = (Math.sign(F) === 1) ? `\u9ad8\u3055 ${H}\u30b3\u30de (+\u6298\u8fd4 ${F}\u30b3\u30de)` : `\u9ad8\u3055 ${H}\u30b3\u30de`;\n                    ctx.font = \"bold 11px system-ui, sans-serif\";\n                    const sideTextW = ctx.measureText(sideHeightLabel).width;\n                    const sideBadgeW = sideTextW + 14;\n                    const sideBadgeH = 20;\n\n                    \/\/ \u4f4d\u7f6e: pT(W, 0) \u306e\u53f3\u5074\u3001\u53f3\u4e0a\u5074\u9762\u306e\u7a7a\u304d\u30b9\u30da\u30fc\u30b9\n                    const labelU = W + D * 0.45 + S * 0.35;\n                    const labelV = -Math.max(1.2, S * 0.45);\n                    const sideLabelPt = g2p(labelU, labelV);\n\n                    ctx.save();\n                    ctx.fillStyle = \"rgba(255, 255, 255, 0.92)\";\n                    ctx.strokeStyle = \"#2563eb\"; \/\/ \u5074\u9762\u5916\u67a0\u3068\u540c\u3058\u9752\n                    ctx.lineWidth = 1.2;\n\n                    const bx = sideLabelPt.x - sideBadgeW \/ 2;\n                    const by = sideLabelPt.y - sideBadgeH \/ 2;\n                    const br = 4;\n                    ctx.beginPath();\n                    ctx.moveTo(bx + br, by);\n                    ctx.lineTo(bx + sideBadgeW - br, by);\n                    ctx.quadraticCurveTo(bx + sideBadgeW, by, bx + sideBadgeW, by + br);\n                    ctx.lineTo(bx + sideBadgeW, by + sideBadgeH - br);\n                    ctx.quadraticCurveTo(bx + sideBadgeW, by + sideBadgeH, bx + sideBadgeW - br, by + sideBadgeH);\n                    ctx.lineTo(bx + br, by + sideBadgeH);\n                    ctx.quadraticCurveTo(bx, by + sideBadgeH, bx, by + sideBadgeH - br);\n                    ctx.lineTo(bx, by + br);\n                    ctx.quadraticCurveTo(bx, by, bx + br, by);\n                    ctx.closePath();\n                    ctx.fill();\n                    ctx.stroke();\n\n                    ctx.fillStyle = \"#1e40af\";\n                    ctx.textAlign = \"center\";\n                    ctx.textBaseline = \"middle\";\n                    ctx.fillText(sideHeightLabel, sideLabelPt.x, sideLabelPt.y);\n                    ctx.restore();\n\n                    \/\/ 6. \u5e95\u7de8\u307f\u6b63\u65b9\u5f62 (\u9ed2\u306e\u592a\u7dda\u3067\u56f2\u3080)\n                    \/\/ (0, 0) \u304b\u3089 (N, N) \u306e\u6b63\u65b9\u5f62\n                    const sqTL = g2p(0, 0);\n                    const sqTR = g2p(N, 0);\n                    const sqBR = g2p(N, N);\n                    const sqBL = g2p(0, N);\n\n                    ctx.save();\n                    ctx.lineWidth = 2.8;\n                    ctx.strokeStyle = \"#111827\"; \/\/ \u9ed2\u306e\u592a\u7dda\n                    ctx.beginPath();\n                    ctx.moveTo(sqTL.x, sqTL.y);\n                    ctx.lineTo(sqTR.x, sqTR.y);\n                    ctx.lineTo(sqBR.x, sqBR.y);\n                    ctx.lineTo(sqBL.x, sqBL.y);\n                    ctx.closePath();\n                    ctx.stroke();\n\n                    \/\/ 7. \u5e95\u7de8\u307f\u6b63\u65b9\u5f62\u306e\u4f4d\u7f6e\u306b\u5408\u308f\u305b\u3066\u3072\u3082\u306e NO (A, B, C...) \u3092\u4e26\u3079\u308b\n                    ctx.font = \"bold 11px system-ui, sans-serif\";\n                    ctx.textAlign = \"center\";\n                    ctx.textBaseline = \"middle\";\n\n                    bands.forEach(b => {\n                        const k = b.idx;\n                        const label = b.id;\n\n                        \/\/ \u7e26\u3072\u3082 (\u4e0a\u8fba v=0 \u3068 \u4e0b\u8fba v=N)\n                        const pTop = g2p(k - 0.5, 0);\n                        const pBottom = g2p(k - 0.5, N);\n\n                        \/\/ \u30d0\u30c3\u30b8\u80cc\u666f\u5186\n                        const drawBadge = (x, y, text) => {\n                            ctx.fillStyle = \"#3b82f6\";\n                            ctx.beginPath();\n                            ctx.arc(x, y, 8.5, 0, Math.PI * 2);\n                            ctx.fill();\n                            ctx.fillStyle = \"#ffffff\";\n                            ctx.fillText(text, x, y);\n                        };\n\n                        drawBadge(pTop.x, pTop.y - 12, label);\n                        drawBadge(pBottom.x, pBottom.y + 12, label);\n\n                        \/\/ \u6a2a\u3072\u3082 (\u5de6\u8fba u=0 \u3068 \u53f3\u8fba u=N)\n                        const pLeft = g2p(0, k - 0.5);\n                        const pRight = g2p(N, k - 0.5);\n\n                        drawBadge(pLeft.x - 12, pLeft.y, label);\n                        drawBadge(pRight.x + 12, pRight.y, label);\n                    });\n                    ctx.restore();\n\n                    \/\/ 8. \u30d8\u30c3\u30c0\u30fc\u60c5\u5831 (\u5de6\u4e0a)\n                    ctx.fillStyle = \"#111827\";\n                    ctx.textAlign = \"left\";\n                    ctx.textBaseline = \"top\";\n                    ctx.font = \"bold 15px system-ui, sans-serif\";\n                    ctx.fillText(`\u4ed5\u4e0a\u304c\u308a\u30b5\u30a4\u30ba: \u6a2a\u5e45 ${widthCm}cm \u00d7 \u5965\u884c ${depthCm}cm \u00d7 \u9ad8\u3055 ${heightCm}cm`, 20, 16);\n\n                    ctx.font = \"12px system-ui, sans-serif\";\n                    ctx.fillStyle = \"#475569\";\n                    const modeNames = [\"\u6700\u9069\u9577\", \"\u56db\u65b9\u540c\u4e00\u9577\", \"\u5bfe\u89d2\u7dda\u540c\u4e00\u9577\"];\n                    ctx.fillText(`\u30b3\u30de\u5bf8\u6cd5: ${knotSizeMm.toFixed(1)}mm \/ \u30b3\u30de\u8981\u5c3a: ${knotLenMm.toFixed(1)}mm (\u53c2\u8003\u30d0\u30f3\u30c9\u5e45: ${refBw.toFixed(1)}mm)  [${modeNames[sameLenMode]}]`, 20, 38);\n                    if (Math.sign(F) === 1) {\n                        ctx.fillText(`\u7e01\u306e\u52a0\u7b97: ${foldAdd}cm \/ \u6298\u308a\u8fd4\u3057\u30b3\u30de\u6570: ${F}\u30b3\u30de (\u6a59\u8272\u70b9\u7dda)`, 20, 56);\n                    } else {\n                        ctx.fillText(`\u7e01\u306e\u52a0\u7b97: ${foldAdd}cm`, 20, 56);\n                    }\n\n                    \/\/ 9. \u51fa\u5178URL & \u65e5\u6642 (\u53f3\u4e0b)\n                    const footerRightX = canvasW - 15;\n                    const footerBottomY = canvasH - 15;\n                    ctx.textAlign = \"right\";\n                    ctx.textBaseline = \"bottom\";\n                    ctx.font = \"11px sans-serif\";\n                    ctx.fillStyle = \"#64748b\";\n                    ctx.fillText(\"https:\/\/labo.com\/CraftBand\/sharing\/knot45-calc\/\", footerRightX, footerBottomY);\n\n                    const now = new Date();\n                    const padZero = (n) => String(n).padStart(2, '0');\n                    const dateStr = `${now.getFullYear()}\/${padZero(now.getMonth() + 1)}\/${padZero(now.getDate())} ${padZero(now.getHours())}:${padZero(now.getMinutes())}:${padZero(now.getSeconds())}`;\n                    ctx.fillText(dateStr, footerRightX, footerBottomY - 16);\n\n                    \/\/ 10. \u30ab\u30c3\u30c8\u30ea\u30b9\u30c8\u8868 (\u4e0b\u90e8)\n                    let ty = oy + (vMax * cs) + 40;\n                    ctx.font = \"bold 13px system-ui, sans-serif\";\n                    ctx.fillStyle = \"#111827\";\n                    ctx.textAlign = \"left\";\n                    ctx.textBaseline = \"top\";\n                    ctx.fillText(\"\u3010\u30ab\u30c3\u30c8\u30ea\u30b9\u30c8\u3011\", 20, ty);\n                    ty += 22;\n\n                    const tW = Math.min(560, canvasW - 40);\n                    const thH = 26;\n                    const trH = 22;\n\n                    \/\/ \u30d8\u30c3\u30c0\u30fc\n                    ctx.fillStyle = \"#f8fafc\";\n                    ctx.fillRect(20, ty, tW, thH);\n                    ctx.strokeStyle = \"#e2e8f0\";\n                    ctx.strokeRect(20, ty, tW, thH);\n\n                    ctx.fillStyle = \"#334155\";\n                    ctx.font = \"bold 12px system-ui, sans-serif\";\n                    ctx.textBaseline = \"middle\";\n                    ctx.textAlign = \"center\";\n                    ctx.fillText(\"No.\", 50, ty + thH \/ 2);\n                    ctx.fillText(\"\u9577\u3055 (cm)\", 130, ty + thH \/ 2);\n                    ctx.fillText(\"\u672c\u6570\", 220, ty + thH \/ 2);\n                    ctx.fillText(\"\u5185\u8a33 (\u7e26+\u6a2a)\", 330, ty + thH \/ 2);\n                    ty += thH;\n\n                    \/\/ \u30ea\u30b9\u30c8\u884c\n                    ctx.font = \"12px system-ui, sans-serif\";\n                    dLen.forEach(l => {\n                        const c = bands.filter(b => b.len === l).length;\n                        const tot = c * 2;\n                        ctx.fillStyle = \"#fff\";\n                        ctx.fillRect(20, ty, tW, trH);\n                        ctx.strokeStyle = \"#f1f5f9\";\n                        ctx.strokeRect(20, ty, tW, trH);\n\n                        \/\/ No. \u30d0\u30c3\u30b8\n                        ctx.fillStyle = \"#3b82f6\";\n                        ctx.beginPath();\n                        ctx.arc(50, ty + trH \/ 2, 8, 0, Math.PI * 2);\n                        ctx.fill();\n                        ctx.fillStyle = \"#ffffff\";\n                        ctx.fillText(idMap.get(l), 50, ty + trH \/ 2);\n\n                        ctx.fillStyle = \"#111827\";\n                        ctx.fillText(l.toFixed(1), 130, ty + trH \/ 2);\n                        ctx.fillText(tot, 220, ty + trH \/ 2);\n                        ctx.fillText(`${c}\u672c \u00d7 2`, 330, ty + trH \/ 2);\n                        ty += trH;\n                    });\n\n                    \/\/ \u5408\u8a08\u884c\n                    ctx.fillStyle = \"#fff1f2\";\n                    ctx.fillRect(20, ty, tW, trH);\n                    ctx.strokeStyle = \"#fecaca\";\n                    ctx.strokeRect(20, ty, tW, trH);\n\n                    ctx.fillStyle = \"#b91c1c\";\n                    ctx.font = \"bold 12px system-ui, sans-serif\";\n                    ctx.textAlign = \"right\";\n                    ctx.fillText(\"\u5408\u8a08\", 90, ty + trH \/ 2);\n                    ctx.textAlign = \"center\";\n                    ctx.fillText(`${totalM} m`, 175, ty + trH \/ 2);\n                    ctx.textAlign = \"left\";\n                    ctx.fillText(`(\u5168 ${totalCount} \u672c)`, 250, ty + trH \/ 2);\n                }\n\n                \/* ----- \u30d0\u30f3\u30c9\u5e45\u53c2\u8003\u30a8\u30ea\u30a2\u306e\u66f4\u65b0 (\u5bf8\u6cd5\u2192\u8981\u5c3a\u306e\u9806\u3001\u592a\u5b57\u5316) ----- *\/\n                const updateBandFormulaNote = () => {\n                    const bw = parseFloat(refBandWidthEl.value) ? parseFloat(refBandWidthEl.value) : 0;\n                    const rSize = (bw * 2.236).toFixed(1);\n                    const rLen = (bw * 6.43).toFixed(1);\n                    bandFormulaNote.innerHTML = `\u5e73\u9762\u306e\u5834\u5408 \u5bf8\u6cd5=2.2\u500d(<b>${rSize}mm<\/b>)\u30fb\u8981\u5c3a=6.4\u500d(<b>${rLen}mm<\/b>)`;\n                };\n                refBandWidthEl.addEventListener(\"input\", updateBandFormulaNote);\n\n                \/\/ \u300c\u5e45\u304b\u3089\u306e\u6982\u7b97\u300d\u30dc\u30bf\u30f3\n                btnCalcFromBand.addEventListener(\"click\", () => {\n                    const bw = parseFloat(refBandWidthEl.value) ? parseFloat(refBandWidthEl.value) : 0;\n                    const lenVal = bw * 0.98 * 6.43 + bw * 0.7;\n                    const sizeVal = bw * 0.95 * 2.236 + bw * 0.2;\n\n                    knotLenEl.value = lenVal.toFixed(1);\n                    knotSizeEl.value = sizeVal.toFixed(1);\n\n                    saveKnotValues();\n                    updateAdditionsFromKnotLen();\n                    calculateAll();\n                    calcButton.dispatchEvent(new Event('click'));\n                });\n\n                \/* ----- \u30b3\u30de\u5bf8\u6cd5\u5909\u66f4\u6642\u306e\u53c2\u8003\u30d0\u30f3\u30c9\u5e45\u81ea\u52d5\u9006\u7b97 (\u00f72.236) \uff06 \u4fdd\u5b58 ----- *\/\n                knotSizeEl.addEventListener(\"input\", () => {\n                    const kSize = parseFloat(knotSizeEl.value);\n                    if (!isNaN(kSize) ? (Math.sign(kSize) === 1) : false) {\n                        refBandWidthEl.value = (kSize \/ 2.236).toFixed(1);\n                        updateBandFormulaNote();\n                    }\n                    saveKnotValues();\n                    calculateAll();\n                });\n\n                \/* ----- \u30b3\u30de\u8981\u5c3a\u5909\u66f4\u6642\u306e\u9023\u52d5 \uff06 \u4fdd\u5b58 ----- *\/\n                knotLenEl.addEventListener(\"input\", () => {\n                    updateAdditionsFromKnotLen();\n                    saveKnotValues();\n                    calculateAll();\n                });\n\n                \/* ----- cm &#x2194; \u30b3\u30de\u6570 \u76f8\u4e92\u63db\u7b97 (1\u30b3\u30de = 1\u30b3\u30de\u8981\u5c3a) ----- *\/\n                const syncCmAndKoma = (cmInput, komaInput) => {\n                    cmInput.addEventListener(\"input\", () => {\n                        const lenCm = getKnotLenMm() \/ 10;\n                        const cmVal = parseFloat(cmInput.value);\n                        if (!isNaN(cmVal)) {\n                            if (Math.sign(lenCm) === 1) {\n                                const koma = cmVal \/ lenCm;\n                                if (document.activeElement !== komaInput) {\n                                    komaInput.value = parseFloat(koma.toFixed(2));\n                                }\n                            }\n                        }\n                        calculateAll();\n                    });\n                    komaInput.addEventListener(\"input\", () => {\n                        const lenCm = getKnotLenMm() \/ 10;\n                        const komaVal = parseFloat(komaInput.value);\n                        if (!isNaN(komaVal)) {\n                            const cmVal = komaVal * lenCm;\n                            if (document.activeElement !== cmInput) {\n                                cmInput.value = parseFloat(cmVal.toFixed(1));\n                            }\n                        }\n                        calculateAll();\n                    });\n                };\n                syncCmAndKoma(foldAdditionEl, foldKomaEl);\n\n                \/\/ \u8981\u5c3a\u5909\u66f4\u6642\u306f\u73fe\u5728\u306e\u30b3\u30de\u6570\u3092\u7dad\u6301\u3057\u3066cm\u3092\u518d\u8a08\u7b97\n                const updateAdditionsFromKnotLen = () => {\n                    const lenCm = getKnotLenMm() \/ 10;\n                    if (Math.sign(lenCm) !== 1) return;\n\n                    const fKoma = parseFloat(foldKomaEl.value) ? parseFloat(foldKomaEl.value) : 0;\n                    foldAdditionEl.value = parseFloat((fKoma * lenCm).toFixed(1));\n                    calculateAll();\n                };\n\n                \/* ----- \u30b9\u30c6\u30c3\u30d1\u30fc & \u5165\u529b\u30a4\u30d9\u30f3\u30c8 ----- *\/\n                [widthKomaEl, depthKomaEl, heightKomaEl, foldKomaCountEl].forEach(inp => {\n                    inp.addEventListener(\"input\", () => calculateAll());\n                });\n\n                els('input[name=\"sameLenMode\"]').forEach(radio => {\n                    radio.addEventListener(\"change\", () => {\n                        calculateAll();\n                        calcButton.dispatchEvent(new Event('click'));\n                    });\n                });\n\n                \/* ----- \u30d7\u30ea\u30bb\u30c3\u30c8\u8a2d\u5b9a ----- *\/\n                const applySizePreset = (targetW_mm, targetH_mm) => {\n                    const kSize = getKnotSizeMm();\n                    const effKomaSize = kSize * Math.SQRT2;\n                    const bestW = Math.max(1, Math.round(targetW_mm \/ effKomaSize));\n                    const bestH = Math.max(0.5, Math.round((targetH_mm \/ effKomaSize) * 2) \/ 2);\n                    const bestD = Math.max(1, Math.round(bestW \/ 3));\n\n                    widthKomaEl.value = String(bestW);\n                    depthKomaEl.value = String(bestD);\n                    heightKomaEl.value = String(bestH);\n\n                    calculateAll();\n                    calcButton.dispatchEvent(new Event('click'));\n                };\n\n                btnB5.addEventListener(\"click\", () => applySizePreset(257, 182));\n                btnA4.addEventListener(\"click\", () => applySizePreset(297, 210));\n                btnB4.addEventListener(\"click\", () => applySizePreset(364, 257));\n\n                \/\/ \u300c\u5c55\u958b\u56f3\u3092\u66f4\u65b0\u300d\u30dc\u30bf\u30f3\n                calcButton.addEventListener(\"click\", () => {\n                    if (!currentCalcResult) calculateAll();\n                    const cv = el(\"#knot45Canvas\");\n                    const ctx = cv.getContext(\"2d\");\n                    drawKnot45Diagram(ctx, currentCalcResult);\n                    pdfButton.style.display = \"inline-block\";\n                });\n\n                \/\/ PDF\u30c0\u30a6\u30f3\u30ed\u30fc\u30c9\n                pdfButton.addEventListener(\"click\", () => {\n                    try {\n                        let libsReady = false;\n                        if (window.jspdf) {\n                            if (window.jspdf.jsPDF) libsReady = true;\n                        }\n                        if (!libsReady) {\n                            alert(\"PDF\u30e9\u30a4\u30d6\u30e9\u30ea\u304c\u30ed\u30fc\u30c9\u3055\u308c\u3066\u3044\u307e\u305b\u3093\");\n                            return;\n                        }\n                        const cv = el(\"#knot45Canvas\");\n                        const imgData = cv.toDataURL(\"image\/png\");\n                        const { jsPDF } = window.jspdf;\n                        const doc = new jsPDF({\n                            orientation: \"portrait\",\n                            unit: \"mm\",\n                            format: \"a4\"\n                        });\n\n                        const pageWidth = doc.internal.pageSize.getWidth();\n                        const pageHeight = doc.internal.pageSize.getHeight();\n                        const margin = 10;\n                        const maxW = pageWidth - margin * 2;\n                        const maxH = pageHeight - margin * 2;\n\n                        let imgW = maxW;\n                        let imgH = (cv.height * imgW) \/ cv.width;\n                        if (Math.sign(imgH - maxH) === 1) {\n                            imgH = maxH;\n                            imgW = (cv.width * imgH) \/ cv.height;\n                        }\n                        const x = (pageWidth - imgW) \/ 2;\n                        const y = margin;\n\n                        doc.addImage(imgData, \"PNG\", x, y, imgW, imgH);\n                        doc.save(\"knot45-calc-diagram.pdf\");\n                    } catch (e) {\n                        console.error(e);\n                        alert(\"PDF\u306e\u751f\u6210\u306b\u5931\u6557\u3057\u307e\u3057\u305f: \" + e.message);\n                    }\n                });\n\n                \/* ----- \u30b3\u30de\u5bf8\u6cd5\u30fb\u8981\u5c3a\u306e\u89e3\u6c7a (\u512a\u5148\u9806\u4f4d: 1.API to 2.localStorage to 3.\u521d\u671f\u502420\/60) ----- *\/\n                const resolveKnotDimensions = (params) => {\n                    const RATIO_LEN_TO_SIZE = 6.43 \/ 2.236; \/\/ \u7d04 2.87567\n\n                    \/\/ 1. API\u5024\n                    const pKnotSize = parseFloat(params.get('cb_knot_size'));\n                    const pKnotLen = parseFloat(params.get('cb_knot_len'));\n                    const hasApiSize = (!isNaN(pKnotSize)) ? (Math.sign(pKnotSize) === 1) : false;\n                    const hasApiLen = (!isNaN(pKnotLen)) ? (Math.sign(pKnotLen) === 1) : false;\n\n                    if (hasApiSize ? true : hasApiLen) {\n                        if (hasApiSize ? hasApiLen : false) {\n                            return { size: pKnotSize, len: pKnotLen };\n                        } else if (hasApiSize) {\n                            return { size: pKnotSize, len: parseFloat((pKnotSize * RATIO_LEN_TO_SIZE).toFixed(1)) };\n                        } else {\n                            return { size: parseFloat((pKnotLen \/ RATIO_LEN_TO_SIZE).toFixed(1)), len: pKnotLen };\n                        }\n                    }\n\n                    \/\/ 2. \u30d6\u30e9\u30a6\u30b6\u306e\u524d\u56de\u5024 (localStorage)\n                    let localSize = null;\n                    let localLen = null;\n                    try {\n                        const s = parseFloat(localStorage.getItem('cb_knot_calc_size'));\n                        const l = parseFloat(localStorage.getItem('cb_knot_calc_len'));\n                        if (!isNaN(s) ? (Math.sign(s) === 1) : false) localSize = s;\n                        if (!isNaN(l) ? (Math.sign(l) === 1) : false) localLen = l;\n                    } catch (e) {\n                        \/\/ ignore\n                    }\n\n                    if (localSize ? true : localLen) {\n                        if (localSize ? Boolean(localLen) : false) {\n                            return { size: localSize, len: localLen };\n                        } else if (localSize) {\n                            return { size: localSize, len: parseFloat((localSize * RATIO_LEN_TO_SIZE).toFixed(1)) };\n                        } else {\n                            return { size: parseFloat((localLen \/ RATIO_LEN_TO_SIZE).toFixed(1)), len: localLen };\n                        }\n                    }\n\n                    \/\/ 3. \u521d\u671f\u5024: \u8981\u5c3a 60mm\u30fb\u5bf8\u6cd5 20mm\n                    return { size: 20.0, len: 60.0 };\n                };\n\n                \/* ----- API (URL\u30d1\u30e9\u30e1\u30fc\u30bf\u8aad\u307f\u8fbc\u307f) ----- *\/\n                const loadFromUrlParams = () => {\n                    const params = new URLSearchParams(window.location.search);\n                    const model = params.get('cb_model');\n                    if (model ? (model !== 'knot45') : false) return;\n\n                    \/\/ \u30b3\u30de\u5bf8\u6cd5\u30fb\u8981\u5c3a\u306e\u89e3\u6c7a\n                    const dims = resolveKnotDimensions(params);\n                    knotSizeEl.value = dims.size.toFixed(1);\n                    knotLenEl.value = dims.len.toFixed(1);\n                    saveKnotValues();\n\n                    \/\/ \u53c2\u8003\u30d0\u30f3\u30c9\u5e45\u306e\u521d\u671f\u5316 (\u30b3\u30de\u5bf8\u6cd5 \u00f7 2.236)\n                    const pBand = parseFloat(params.get('cb_band'));\n                    if (!isNaN(pBand) ? (Math.sign(pBand) === 1) : false) {\n                        refBandWidthEl.value = pBand.toFixed(1);\n                    } else {\n                        refBandWidthEl.value = (dims.size \/ 2.236).toFixed(1);\n                    }\n                    updateBandFormulaNote();\n\n                    \/\/ \u3072\u3082\u9577\u30e2\u30fc\u30c9 (cb_same_len)\n                    const pSameLen = parseInt(params.get('cb_same_len'), 10);\n                    if (!isNaN(pSameLen) ? [0, 1, 2].includes(pSameLen) : false) {\n                        const targetRadio = container.querySelector(`input[name=\"sameLenMode\"][value=\"${pSameLen}\"]`);\n                        if (targetRadio) targetRadio.checked = true;\n                    }\n\n                    \/\/ \u6298\u308a\u8fd4\u3057\u30b3\u30de\u6570 (cb_rim)\n                    const pRim = parseInt(params.get('cb_rim'), 10);\n                    if (!isNaN(pRim) ? (Math.sign(pRim) !== -1) : false) {\n                        foldKomaCountEl.value = pRim;\n                    }\n\n                    \/\/ \u7e01\u306e\u52a0\u7b97\u30b3\u30de (cb_add)\n                    const pAdd = parseFloat(params.get('cb_add'));\n                    if (!isNaN(pAdd) ? (Math.sign(pAdd) !== -1) : false) {\n                        foldKomaEl.value = pAdd;\n                    }\n\n                    \/\/ \u76ee\u6a19\u30b5\u30a4\u30ba (cb_w, cb_d, cb_h: mm\u5358\u4f4d)\n                    let wTarget = parseFloat(params.get('cb_w'));\n                    let dTarget = parseFloat(params.get('cb_d'));\n                    let hTarget = parseFloat(params.get('cb_h'));\n                    const mode = params.get('cb_mode') ? params.get('cb_mode') : 'near';\n\n                    const hasW = (!isNaN(wTarget)) ? (Math.sign(wTarget) === 1) : false;\n                    const hasD = (!isNaN(dTarget)) ? (Math.sign(dTarget) === 1) : false;\n                    const hasH = (!isNaN(hTarget)) ? (Math.sign(hTarget) === 1) : false;\n\n                    if (hasW ? true : (hasD ? true : hasH)) {\n                        if (hasW ? (!hasD ? !hasH : false) : false) {\n                            dTarget = wTarget \/ 3;\n                            hTarget = wTarget \/ Math.SQRT2;\n                        } else if (!hasW ? (!hasD ? hasH : false) : false) {\n                            wTarget = hTarget * Math.SQRT2;\n                            dTarget = wTarget \/ 3;\n                        } else if (!hasW ? (hasD ? !hasH : false) : false) {\n                            wTarget = dTarget * 3;\n                            hTarget = wTarget \/ Math.SQRT2;\n                        } else if (hasW ? (hasD ? !hasH : false) : false) {\n                            hTarget = wTarget \/ Math.SQRT2;\n                        } else if (hasW ? (!hasD ? hasH : false) : false) {\n                            dTarget = wTarget \/ 3;\n                        } else if (!hasW ? (hasD ? hasH : false) : false) {\n                            wTarget = dTarget * 3;\n                        }\n\n                        const effKomaSize = dims.size * Math.SQRT2;\n                        const fitKoma = (targetMm, isHeight) => {\n                            const raw = targetMm \/ effKomaSize;\n                            if (isHeight) {\n                                if (mode === 'in') return Math.max(0.5, Math.floor(raw * 2) \/ 2);\n                                if (mode === 'out') return Math.max(0.5, Math.ceil(raw * 2) \/ 2);\n                                return Math.max(0.5, Math.round(raw * 2) \/ 2);\n                            } else {\n                                if (mode === 'in') return Math.max(1, Math.floor(raw));\n                                if (mode === 'out') return Math.max(1, Math.ceil(raw));\n                                return Math.max(1, Math.round(raw));\n                            }\n                        };\n\n                        widthKomaEl.value = fitKoma(wTarget, false);\n                        depthKomaEl.value = fitKoma(dTarget, false);\n                        heightKomaEl.value = fitKoma(hTarget, true);\n                    }\n                };\n\n                \/\/ Single-Shot JSON DOM\u66f8\u304d\u51fa\u3057\n                const emitSingleShotData = () => {\n                    const params = new URLSearchParams(window.location.search);\n                    const model = params.get('cb_model');\n                    if (model ? (model !== 'knot45') : false) return;\n\n                    if (document.getElementById('craftband-simulation-data')) return;\n                    if (!currentCalcResult) calculateAll();\n\n                    const r = currentCalcResult;\n                    const cutListEntries = [];\n                    r.dLen.forEach(l => {\n                        const c = r.bands.filter(b => b.len === l).length * 2;\n                        cutListEntries.push({\n                            len: Math.round(l * 10 * 10) \/ 10,\n                            num: c,\n                            name: `\u3072\u3082 ${r.idMap.get(l)}`\n                        });\n                    });\n\n                    const dataObj = {\n                        model: \"knot45\",\n                        same_len: r.sameLenMode,\n                        koma: {\n                            w: r.W,\n                            d: r.D,\n                            h: r.H,\n                            fold: r.F\n                        },\n                        knot_size: r.knotSizeMm,\n                        knot_len: r.knotLenMm,\n                        size: {\n                            w: Math.round(r.widthCm * 10 * 10) \/ 10,\n                            d: Math.round(r.depthCm * 10 * 10) \/ 10,\n                            h: Math.round(r.heightCm * 10 * 10) \/ 10\n                        },\n                        total_length: Math.round(r.totalCm * 10 * 10) \/ 10,\n                        cut_list: cutListEntries\n                    };\n\n                    const scriptTag = document.createElement('script');\n                    scriptTag.id = 'craftband-simulation-data';\n                    scriptTag.type = 'application\/json';\n                    scriptTag.textContent = JSON.stringify(dataObj);\n                    document.body.appendChild(scriptTag);\n                };\n\n                \/\/ \u521d\u671f\u5316\u5b9f\u884c\n                const initialize = () => {\n                    foldKomaCountEl.value = 0;\n                    foldKomaEl.value = 3.0;\n\n                    loadFromUrlParams();\n                    updateAdditionsFromKnotLen();\n                    calculateAll();\n                    calcButton.dispatchEvent(new Event('click'));\n                    emitSingleShotData();\n                };\n\n                initialize();\n            })();\n            \/\/]]>\n<\/script>\n<\/div>\n\n\n\n\n<p class=\"has-text-align-right wp-block-paragraph\">2026\/11\/4 ver1<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\u7c21\u6613\u30c4\u30fc\u30eb\u306e\u305f\u3081\u6570\u5024\u306e\u307f\u306e\u7b97\u51fa\u3067\u3059\u3002<a href=\"https:\/\/labo.com\/CraftBand\/craftbandknot\/\">CraftBandKnot<\/a> \u3092\u4f7f\u3046\u3068\u3001\u5e95\u7de8\u307f\u3067\u3001\u6307\u5b9a\u4f4d\u7f6e\u306e\u884c\u30fb\u5217\u306b\u5bfe\u3059\u308b\u6298\u308a\u4f4d\u7f6e(\u958b\u59cb\u30e9\u30a4\u30f3)\u3092\u5f97\u3089\u308c\u307e\u3059\u3002\u30d0\u30f3\u30c9\u8272\u3092\u500b\u5225\u306b\u8a2d\u5b9a\u3057\u3001\u7acb\u4f53\u5316\u3057\u305f\u6642\u306b\u3069\u3093\u306a\u6a21\u69d8\u306b\u306a\u308b\u304b\u3082\u898b\u308b\u3053\u3068\u304c\u3067\u304d\u307e\u3059\u3002<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\u30ab\u30c3\u30c8\u30ea\u30b9\u30c8\u3092\u3082\u3068\u306b\u3057\u305f\u7de8\u307f\u65b9\u306b\u3064\u3044\u3066\u306f\u3001\u4ee5\u4e0b\u3092\u3054\u53c2\u8003\u304f\u3060\u3055\u3044\u3002<\/p>\n\n\n\n<figure class=\"wp-block-embed is-type-wp-embed\"><div class=\"wp-block-embed__wrapper\">\n<blockquote class=\"wp-embedded-content\" data-secret=\"ZN9ASdjECq\"><a href=\"https:\/\/labo.com\/CraftBand\/handmade\/knot-5methods\/\">\u659c\u3081\u56db\u3064\u7573\u307f\u7de8\u307f\u306e5\u5de5\u6cd5<\/a><\/blockquote><iframe loading=\"lazy\" class=\"wp-embedded-content\" sandbox=\"allow-scripts\" security=\"restricted\" style=\"position: absolute; visibility: hidden;\" title=\"\u201c\u659c\u3081\u56db\u3064\u7573\u307f\u7de8\u307f\u306e5\u5de5\u6cd5\u201d \u2014 \u30af\u30e9\u30d5\u30c8\u30d0\u30f3\u30c9\u30fb\u30e9\u30dc\" src=\"https:\/\/labo.com\/CraftBand\/handmade\/knot-5methods\/embed\/#?secret=VR6qjox8A0#?secret=ZN9ASdjECq\" data-secret=\"ZN9ASdjECq\" width=\"600\" height=\"338\" frameborder=\"0\" marginwidth=\"0\" marginheight=\"0\" scrolling=\"no\"><\/iframe>\n<\/div><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><a href=\"https:\/\/labo.com\/CraftBand\/sharing\/size-call\/\">\u2190\u76ee\u6a19\u30b5\u30a4\u30ba\u306b\u623b\u308b<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>\uff5e\u56db\u3064\u7573\u307f\u7de8\u307f\u3067\u3001\u659c\u308145\u5ea6\u65b9\u5411\u306b\u7acb\u3061\u4e0a\u3052\u308b\u3001\u76f4\u65b9\u4f53\u306e\u304b\u3054\uff5e \u30b3\u30de\u5bf8\u6cd5 (mm) mm \u30b3\u30de\u8981\u5c3a (mm) mm \u30d0\u30f3\u30c9\u5e45 (mm) [\u53c2\u8003] mm \u5e45\u304b\u3089\u306e\u6982\u7b97 \u5e73\u9762\u306e\u5834\u5408 \u5bf8\u6cd5=2.2\u500d(20.0mm)\u30fb\u8981\u5c3a=6.4 &hellip; <a href=\"https:\/\/labo.com\/CraftBand\/sharing\/knot45-calc\/\" class=\"more-link\">\u7d9a\u304d\u3092\u8aad\u3080 <span class=\"screen-reader-text\">\u659c\u3081\u56db\u3064\u7573\u307f\u306e\u30b5\u30a4\u30ba\u8a08\u7b97<\/span> <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":2,"featured_media":0,"parent":688,"menu_order":103,"comment_status":"closed","ping_status":"closed","template":"","meta":{"_bbp_topic_count":0,"_bbp_reply_count":0,"_bbp_total_topic_count":0,"_bbp_total_reply_count":0,"_bbp_voice_count":0,"_bbp_anonymous_reply_count":0,"_bbp_forum_subforum_count":0,"footnotes":""},"class_list":["post-13980","page","type-page","status-publish","hentry"],"jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/labo.com\/CraftBand\/wp-json\/wp\/v2\/pages\/13980","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/labo.com\/CraftBand\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/labo.com\/CraftBand\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/labo.com\/CraftBand\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/labo.com\/CraftBand\/wp-json\/wp\/v2\/comments?post=13980"}],"version-history":[{"count":11,"href":"https:\/\/labo.com\/CraftBand\/wp-json\/wp\/v2\/pages\/13980\/revisions"}],"predecessor-version":[{"id":14002,"href":"https:\/\/labo.com\/CraftBand\/wp-json\/wp\/v2\/pages\/13980\/revisions\/14002"}],"up":[{"embeddable":true,"href":"https:\/\/labo.com\/CraftBand\/wp-json\/wp\/v2\/pages\/688"}],"wp:attachment":[{"href":"https:\/\/labo.com\/CraftBand\/wp-json\/wp\/v2\/media?parent=13980"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}