{"id":14113,"date":"2026-11-09T17:11:36","date_gmt":"2026-11-09T08:11:36","guid":{"rendered":"https:\/\/labo.com\/CraftBand\/?page_id=14113"},"modified":"2026-11-09T19:46:36","modified_gmt":"2026-11-09T10:46:36","slug":"gauge-calc","status":"publish","type":"page","link":"https:\/\/labo.com\/CraftBand\/sharing\/gauge-calc\/","title":{"rendered":"\u56db\u3064\u7573\u307f\u7de8\u307f\u30b2\u30fc\u30b8\u8a08\u7b97\u30c4\u30fc\u30eb"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\"><strong>\u540c\u3058\u9577\u3055\u306e\u3072\u3082\u30926\u672c<\/strong>(\u3082\u3057\u304f\u306f4\u672c)\u7528\u610f\u3057\u3066\u3001\u56db\u3064\u7573\u307f\u7de8\u307f\u306e<strong>\u30b3\u30de\u3092\u683c\u5b50\u72b6\u306b<\/strong>\u7de8\u3093\u3067\u304f\u3060\u3055\u3044\u3002\u683c\u5b50\u72b6\u306b\u7de8\u3080\u3053\u3068\u3067\u3001\u30a8\u30c3\u30b8\u52b9\u679c\u3092\u6291\u3048\u3001\u672c\u756a\u306b\u8fd1\u3044\u5f15\u304d\u7de0\u307e\u308a\u72b6\u614b\u306e\u6570\u5024\u3092\u5272\u308a\u51fa\u305b\u307e\u3059\u3002\u5e73\u5747\u5316\u306b\u3088\u308a\u8aad\u307f\u53d6\u308a\u8aa4\u5dee\u3082\u5c0f\u3055\u304f\u306a\u308a\u307e\u3059\u3002<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\u6e2c\u5b9a\u7d50\u679c\u3092\u5165\u529b\u3059\u308b\u3068\u3001\u8981\u5c3a\uff06\u5bf8\u6cd5\u3092\u8a08\u7b97\u3057\u307e\u3059\u3002<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>\u8a08\u7b97\u7d50\u679c\u3092\u3082\u3068\u306b\u3001\u304b\u3054\u306e\u30b5\u30a4\u30ba\u8a08\u7b97\u30c4\u30fc\u30eb\u3092\u958b\u304f\u3053\u3068\u304c\u3067\u304d\u307e\u3059<\/li>\n\n\n\n<li>\u6e2c\u5b9a\u5024\u3084\u8a08\u7b97\u7d50\u679c\u3092\u3001PDF\u30d5\u30a1\u30a4\u30eb\u3068\u3057\u3066\u4fdd\u5b58\u3067\u304d\u307e\u3059<\/li>\n\n\n\n<li>\u7d50\u679c\u3092\u30b7\u30a7\u30a2\u3057\u3066\u3001\u304a\u4e92\u3044\u306b\u53c2\u8003\u306b\u3067\u304d\u307e\u3059<\/li>\n<\/ul>\n\n\n\n\n\n\n<script src=\"https:\/\/cdnjs.cloudflare.com\/ajax\/libs\/jspdf\/2.5.1\/jspdf.umd.min.js\"><\/script>\n    <div id=\"gauge-calc-app\">\n\n        <style>\n            \/* --- \u30b9\u30bf\u30a4\u30eb\u5b9a\u7fa9 (\u30b5\u30a4\u30c8\u306e\u30c6\u30fc\u30de\u30ab\u30e9\u30fc\u3067\u3042\u308b\u8d64\u8910\u8272\u30fb\u30aa\u30ec\u30f3\u30b8\u306b\u8abf\u548c) --- *\/\n            #gauge-calc-app {\n                font-family: system-ui, -apple-system, BlinkMacSystemFont, \"Segoe UI\", sans-serif;\n                padding: 24px;\n                max-width: 840px;\n                margin: 0 auto;\n                background-color: #ffffff;\n                border: 1px solid #e5e7eb;\n                border-radius: 12px;\n                box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.05), 0 2px 4px -1px rgba(0, 0, 0, 0.03);\n                color: #1f2937;\n            }\n\n            #gauge-calc-app h2 {\n                font-size: 20px;\n                font-weight: bold;\n                color: #722d19; \/* \u8336\u8272 *\/\n                margin-top: 0;\n                margin-bottom: 8px;\n                border-bottom: 2px solid #e05d22; \/* \u8d64\u30aa\u30ec\u30f3\u30b8 *\/\n                padding-bottom: 8px;\n            }\n\n            #gauge-calc-app .app-desc {\n                font-size: 13px;\n                color: #6b7280;\n                margin-bottom: 16px;\n                line-height: 1.5;\n            }\n\n            \/* \u5358\u4f4d\u306b\u95a2\u3059\u308b\u76ee\u7acb\u3064\u6ce8\u610f\u30d0\u30ca\u30fc *\/\n            #gauge-calc-app .unit-alert-banner {\n                display: flex;\n                align-items: flex-start;\n                gap: 12px;\n                background-color: #fff7ed;\n                border: 2px solid #ea580c;\n                border-radius: 8px;\n                padding: 12px 16px;\n                margin-bottom: 20px;\n                color: #9a3412;\n                font-size: 13px;\n                line-height: 1.5;\n                box-shadow: 0 1px 3px rgba(234, 88, 12, 0.1);\n            }\n\n            #gauge-calc-app .unit-alert-banner .alert-icon {\n                font-size: 22px;\n                line-height: 1;\n            }\n\n            #gauge-calc-app .unit-alert-banner strong {\n                color: #7c2d12;\n            }\n\n            #gauge-calc-app .unit-alert-banner code {\n                background-color: #ffedd5;\n                padding: 2px 5px;\n                border-radius: 4px;\n                font-weight: bold;\n                color: #c2410c;\n                border: 1px solid #fed7aa;\n            }\n\n            #gauge-calc-app .section-group {\n                margin-bottom: 24px;\n                background-color: #fafafa;\n                border: 1px solid #e5e7eb;\n                border-radius: 8px;\n                padding: 16px;\n            }\n\n            #gauge-calc-app .section-title {\n                font-size: 15px;\n                font-weight: bold;\n                color: #374151;\n                margin-bottom: 8px;\n                display: flex;\n                align-items: center;\n                gap: 6px;\n            }\n\n            #gauge-calc-app .section-desc {\n                font-size: 12px;\n                color: #6b7280;\n                margin-bottom: 14px;\n                line-height: 1.5;\n            }\n\n            #gauge-calc-app .row {\n                display: flex;\n                gap: 16px;\n                align-items: center;\n                flex-wrap: wrap;\n            }\n\n            #gauge-calc-app .field {\n                display: flex;\n                flex-direction: column;\n                gap: 4px;\n            }\n\n            #gauge-calc-app label {\n                font-size: 13px;\n                font-weight: bold;\n                color: #4b5563;\n            }\n\n            #gauge-calc-app .radio-group {\n                display: flex;\n                gap: 12px;\n                background: #ffffff;\n                border: 1px solid #d1d5db;\n                border-radius: 6px;\n                padding: 5px 10px;\n            }\n\n            #gauge-calc-app .radio-label {\n                display: flex;\n                align-items: center;\n                gap: 4px;\n                font-size: 13px;\n                font-weight: normal;\n                cursor: pointer;\n                color: #374151;\n            }\n\n            #gauge-calc-app .input-group {\n                display: flex;\n                align-items: center;\n                gap: 4px;\n            }\n\n            #gauge-calc-app input[type=\"number\"],\n            #gauge-calc-app input[type=\"text\"] {\n                padding: 5px 8px;\n                border: 1px solid #d1d5db;\n                border-radius: 6px;\n                font-size: 13px;\n                background-color: #ffffff;\n                box-sizing: border-box;\n            }\n\n            #gauge-calc-app input[type=\"number\"]:focus {\n                border-color: #e05d22;\n                outline: none;\n                box-shadow: 0 0 0 2px rgba(224, 93, 34, 0.2);\n            }\n\n            #gauge-calc-app .input-error {\n                border-color: #ef4444 !important;\n                background-color: #fef2f2 !important;\n            }\n\n            #gauge-calc-app .unit-label {\n                font-size: 13px;\n                color: #4b5563;\n            }\n\n            \/* \u30b9\u30d4\u30f3\u30dc\u30bf\u30f3\uff08\u25b2\u25bc\uff09\u975e\u8868\u793a & 3\u6841+\u5c0f\u6570\u70b9\u306e\u6570\u5b57\u88ab\u308a\u9632\u6b62 *\/\n            #gauge-calc-app input::-webkit-outer-spin-button,\n            #gauge-calc-app input::-webkit-inner-spin-button {\n                -webkit-appearance: none;\n                margin: 0;\n            }\n            #gauge-calc-app input[type=number] {\n                -moz-appearance: textfield;\n            }\n\n            \/* --- \u8981\u5c3a\u6e2c\u5b9a\u30d3\u30b8\u30e5\u30a2\u30eb\u30ec\u30a4\u30a2\u30a6\u30c8 (\u6848A: \u56f3\u306e\u5468\u56f2\u306b\u914d\u7f6e \/ \u30b9\u30de\u30db\u753b\u9762 360px\u301c390px \u5b8c\u5168\u5bfe\u5fdc) --- *\/\n            #gauge-calc-app .len-visual-board {\n                display: flex;\n                flex-direction: column;\n                align-items: center;\n                margin: 0 auto;\n                background: #ffffff;\n                border: 1px solid #e2e8f0;\n                border-radius: 10px;\n                padding: 8px 4px;\n                box-shadow: 0 1px 3px rgba(0,0,0,0.04);\n                width: 100%;\n                max-width: 360px;\n                box-sizing: border-box;\n            }\n\n            #gauge-calc-app .len-row-middle {\n                display: flex;\n                align-items: center;\n                justify-content: center;\n                gap: 4px;\n                width: 100%;\n            }\n\n            #gauge-calc-app .len-inputs-top,\n            #gauge-calc-app .len-inputs-bottom {\n                position: relative;\n                width: 220px;\n                height: 48px;\n            }\n\n            #gauge-calc-app .len-inputs-left,\n            #gauge-calc-app .len-inputs-right {\n                position: relative;\n                width: 64px;\n                height: 220px;\n            }\n\n            #gauge-calc-app .len-box-v {\n                position: absolute;\n                transform: translateX(-50%);\n                display: flex;\n                flex-direction: column;\n                align-items: center;\n                background: #f8fafc;\n                border: 1.5px solid #cbd5e1;\n                border-radius: 6px;\n                padding: 2px 2px;\n                width: 60px;\n                box-sizing: border-box;\n                box-shadow: 0 1px 2px rgba(0,0,0,0.05);\n            }\n\n            #gauge-calc-app .len-box-h {\n                position: absolute;\n                transform: translateY(-50%);\n                display: flex;\n                flex-direction: column;\n                align-items: center;\n                background: #f8fafc;\n                border: 1.5px solid #cbd5e1;\n                border-radius: 6px;\n                padding: 2px 2px;\n                width: 62px;\n                box-sizing: border-box;\n                box-shadow: 0 1px 2px rgba(0,0,0,0.05);\n            }\n\n            #gauge-calc-app .len-box-label {\n                font-size: 10px;\n                font-weight: bold;\n                margin-bottom: 2px;\n                white-space: nowrap;\n            }\n\n            #gauge-calc-app .len-input {\n                width: 52px;\n                padding: 3px 2px;\n                font-size: 14px;\n                font-weight: bold;\n                text-align: center;\n                border: 1px solid #94a3b8;\n                border-radius: 4px;\n                background: #ffffff;\n                box-sizing: border-box;\n            }\n\n            #gauge-calc-app .len-sub-badge {\n                font-size: 10px;\n                font-weight: bold;\n                color: #0284c7;\n                margin-top: 1px;\n                white-space: nowrap;\n            }\n\n            \/* --- \u5bf8\u6cd5\u6e2c\u5b9a\u30d3\u30b8\u30e5\u30a2\u30eb\u30ec\u30a4\u30a2\u30a6\u30c8 (\u30b3\u30de\u62e1\u5927\u63a5\u5408 + \u30e9\u30d9\u30eb\u306a\u3057\u76f4\u611f\u5165\u529b \/ \u30b9\u30de\u30db\u5b8c\u5168\u5bfe\u5fdc) --- *\/\n            #gauge-calc-app .size-mode-tabs {\n                display: flex;\n                gap: 8px;\n                margin-bottom: 12px;\n                justify-content: center;\n            }\n\n            #gauge-calc-app .size-tab-btn {\n                padding: 7px 18px;\n                font-size: 13px;\n                font-weight: bold;\n                border: 1px solid #cbd5e1;\n                background: #ffffff;\n                color: #475569;\n                border-radius: 6px;\n                cursor: pointer;\n                transition: all 0.15s ease;\n            }\n\n            #gauge-calc-app .size-tab-btn:hover {\n                background: #f1f5f9;\n            }\n\n            #gauge-calc-app .size-tab-btn.active {\n                background: #e05d22;\n                color: #ffffff;\n                border-color: #e05d22;\n                box-shadow: 0 1px 3px rgba(224, 93, 34, 0.3);\n            }\n\n            #gauge-calc-app .size-visual-board {\n                position: relative;\n                width: 100%;\n                max-width: 360px;\n                height: 350px;\n                margin: 0 auto;\n                background: #ffffff;\n                border: 1px solid #e2e8f0;\n                border-radius: 10px;\n                box-shadow: 0 1px 3px rgba(0,0,0,0.04);\n                overflow: hidden;\n            }\n\n            #gauge-calc-app #canvasSize {\n                display: block;\n            }\n\n            #gauge-calc-app .size-input-overlay {\n                position: absolute;\n                top: 0;\n                left: 0;\n                width: 100%;\n                height: 100%;\n                pointer-events: none;\n            }\n\n            #gauge-calc-app .size-input-item {\n                position: absolute;\n                transform: translate(-50%, -50%);\n                background: #ffffff;\n                border: 2px solid #ea580c;\n                border-radius: 6px;\n                padding: 1px;\n                box-shadow: 0 2px 5px rgba(0,0,0,0.15);\n                pointer-events: auto;\n            }\n\n            #gauge-calc-app .size-input-item.v-mode {\n                border-color: #7c3aed;\n            }\n\n            #gauge-calc-app .size-input-item input,\n            #gauge-calc-app .size-input {\n                width: 50px;\n                height: 26px;\n                padding: 2px;\n                font-size: 14px;\n                font-weight: bold;\n                text-align: center;\n                border: none;\n                outline: none;\n                background: transparent;\n                box-sizing: border-box;\n            }\n\n            @media (max-width: 600px) {\n                #gauge-calc-app {\n                    padding: 12px 6px;\n                }\n            }\n\n            \/* \u7d71\u8a08\u30b5\u30de\u30ea\u30fc & \u30a2\u30af\u30b7\u30e7\u30f3\u30dc\u30bf\u30f3 *\/\n            #gauge-calc-app .warning-box {\n                background-color: #fff7ed;\n                border-left: 4px solid #f97316;\n                padding: 12px 16px;\n                margin-bottom: 16px;\n                border-radius: 0 6px 6px 0;\n                color: #9a3412;\n                display: none;\n            }\n\n            #gauge-calc-app .warning-box .warning-title {\n                font-size: 13px;\n                font-weight: 700;\n                color: #c2410c;\n                display: flex;\n                align-items: center;\n                gap: 6px;\n                margin-bottom: 8px;\n            }\n\n            #gauge-calc-app .warning-box .warning-checklist-label {\n                font-size: 12px;\n                font-weight: 700;\n                color: #9a3412;\n                margin-bottom: 4px;\n            }\n\n            #gauge-calc-app .warning-box .warning-checklist {\n                margin: 0;\n                padding-left: 18px;\n                font-size: 12px;\n                color: #7c2d12;\n                line-height: 1.6;\n            }\n\n            #gauge-calc-app .warning-box .warning-checklist li {\n                margin-bottom: 3px;\n            }\n\n            #gauge-calc-app .stats-grid {\n                display: grid;\n                grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));\n                gap: 16px;\n                margin-bottom: 16px;\n            }\n\n            #gauge-calc-app .stat-card {\n                background: #fdfdfe;\n                border: 1px solid #e5e7eb;\n                border-radius: 8px;\n                padding: 14px;\n                box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);\n            }\n\n            #gauge-calc-app .stat-card.primary { border-top: 4px solid #b45309; }\n            #gauge-calc-app .stat-card.secondary { border-top: 4px solid #1e40af; }\n            #gauge-calc-app .stat-card.ratio { border-top: 4px solid #10b981; }\n\n            #gauge-calc-app .stat-title {\n                font-size: 13px;\n                font-weight: bold;\n                color: #4b5563;\n                margin-bottom: 6px;\n                display: flex;\n                justify-content: space-between;\n                align-items: center;\n            }\n\n            #gauge-calc-app .stat-count {\n                font-size: 11px;\n                font-weight: normal;\n                color: #6b7280;\n            }\n\n            #gauge-calc-app .stat-value {\n                font-size: 24px;\n                font-weight: bold;\n                color: #111827;\n                margin-bottom: 4px;\n            }\n\n            #gauge-calc-app .stat-value .unit {\n                font-size: 13px;\n                font-weight: normal;\n                color: #6b7280;\n                margin-left: 2px;\n            }\n\n            #gauge-calc-app .stat-sub {\n                font-size: 11px;\n                color: #6b7280;\n                line-height: 1.4;\n            }\n\n            #gauge-calc-app .stat-badge {\n                display: inline-block;\n                padding: 1px 6px;\n                border-radius: 4px;\n                font-size: 10px;\n                font-weight: bold;\n            }\n\n            #gauge-calc-app .stat-badge.good { background-color: #d1fae5; color: #065f46; }\n            #gauge-calc-app .stat-badge.warn { background-color: #fef3c7; color: #92400e; }\n            #gauge-calc-app .stat-badge.alert { background-color: #fee2e2; color: #991b1b; }\n\n            \/* 5. \u6e2c\u5b9a\u7d50\u679c\u306e\u4fdd\u5b58\u30fb\u30b7\u30a7\u30a2\u7528\u30b9\u30bf\u30a4\u30eb *\/\n            #gauge-calc-app .share-form-grid {\n                display: grid;\n                grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));\n                gap: 12px;\n                margin-top: 12px;\n                margin-bottom: 16px;\n                background-color: #f8fafc;\n                padding: 14px;\n                border-radius: 8px;\n                border: 1px solid #e2e8f0;\n            }\n\n            #gauge-calc-app .share-field {\n                display: flex;\n                flex-direction: column;\n                gap: 4px;\n            }\n\n            #gauge-calc-app .share-field.full-width {\n                grid-column: 1 \/ -1;\n            }\n\n            #gauge-calc-app .share-field label {\n                font-size: 12px;\n                font-weight: 600;\n                color: #334155;\n            }\n\n            #gauge-calc-app .share-field .field-hint {\n                font-size: 10px;\n                font-weight: normal;\n                color: #64748b;\n            }\n\n            #gauge-calc-app .share-field input,\n            #gauge-calc-app .share-field textarea {\n                padding: 8px 10px;\n                font-size: 13px;\n                border: 1px solid #cbd5e1;\n                border-radius: 6px;\n                background-color: #ffffff;\n                color: #1e293b;\n                box-sizing: border-box;\n                font-family: inherit;\n            }\n\n            #gauge-calc-app .share-field textarea {\n                resize: vertical;\n            }\n\n            #gauge-calc-app .share-field input:focus,\n            #gauge-calc-app .share-field textarea:focus {\n                outline: none;\n                border-color: #ea580c;\n                box-shadow: 0 0 0 2px rgba(234, 88, 12, 0.15);\n            }\n\n            #gauge-calc-app .share-action-group {\n                display: flex;\n                flex-wrap: wrap;\n                gap: 12px;\n                margin-top: 8px;\n            }\n\n            #gauge-calc-app .btn-share-form {\n                background: linear-gradient(135deg, #059669 0%, #047857 100%);\n                color: #ffffff;\n            }\n\n            #gauge-calc-app .btn-share-form:hover:not(:disabled) {\n                background: linear-gradient(135deg, #047857 0%, #065f46 100%);\n                box-shadow: 0 4px 6px -1px rgba(5, 150, 105, 0.3);\n            }\n\n            #gauge-calc-app .btn-view-results {\n                background: linear-gradient(135deg, #059669 0%, #047857 100%);\n                color: #ffffff;\n            }\n\n            #gauge-calc-app .btn-view-results:hover:not(:disabled) {\n                background: linear-gradient(135deg, #047857 0%, #065f46 100%);\n                box-shadow: 0 4px 6px -1px rgba(5, 150, 105, 0.3);\n            }\n\n            #gauge-calc-app .action-group {\n                display: flex;\n                gap: 12px;\n                flex-wrap: wrap;\n                margin-top: 16px;\n                padding-top: 14px;\n                border-top: 1px dashed #e5e7eb;\n            }\n\n            #gauge-calc-app .action-btn {\n                padding: 8px 16px;\n                border-radius: 6px;\n                font-size: 13px;\n                font-weight: bold;\n                cursor: pointer;\n                border: none;\n                transition: all 0.15s ease;\n                display: inline-flex;\n                align-items: center;\n                gap: 6px;\n                box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);\n            }\n\n            #gauge-calc-app .btn-knot { background-color: #722d19; color: #ffffff; }\n            #gauge-calc-app .btn-knot:hover:not(:disabled) { background-color: #552213; }\n\n            #gauge-calc-app .btn-knot45 { background-color: #e05d22; color: #ffffff; }\n            #gauge-calc-app .btn-knot45:hover:not(:disabled) { background-color: #c44d18; }\n\n            #gauge-calc-app .btn-pdf { background-color: #374151; color: #ffffff; }\n            #gauge-calc-app .btn-pdf:hover:not(:disabled) { background-color: #1f2937; }\n\n            #gauge-calc-app .action-btn:disabled {\n                opacity: 0.5;\n                cursor: not-allowed;\n                box-shadow: none;\n            }\n        <\/style>\n\n        <h2>&#x1f4cf; \u56db\u3064\u7573\u307f\u30b2\u30fc\u30b8\u6e2c\u5b9a\u30fb\u8981\u5c3a\uff06\u5bf8\u6cd5\u8a08\u7b97\u30c4\u30fc\u30eb<\/h2>\n        <div class=\"app-desc\">\n            \u8a66\u3057\u7de8\u307f\u3057\u305f\u56db\u3064\u7573\u307f\u30b2\u30fc\u30b8\uff083\u00d73 \u307e\u305f\u306f 2\u00d72\uff09\u306e\u6b8b\u308a\u3072\u3082\u9577\u3068\u30b3\u30de\u5bf8\u6cd5\u3092\u5b9f\u6e2c\u3057\u3066\u5165\u529b\u3059\u308b\u3068\u3001\u3042\u306a\u305f\u306e\u7de8\u307f\u52a0\u6e1b\uff08\u30b2\u30fc\u30b8\uff09\u306b\u5fdc\u3058\u305f<strong>\u6b63\u78ba\u306a\u30b3\u30de\u8981\u5c3a\u3068\u30b3\u30de\u5bf8\u6cd5<\/strong>\u3092\u7b97\u51fa\u3057\u307e\u3059\u3002\n        <\/div>\n\n        <!-- 1. \u57fa\u672c\u8a2d\u5b9a\u30bb\u30af\u30b7\u30e7\u30f3 -->\n        <div class=\"section-group\">\n            <div class=\"section-title\">\n                <span>&#x2699;&#xfe0f;<\/span> 1. \u30b2\u30fc\u30b8\u306e\u57fa\u672c\u4ed5\u69d8\n            <\/div>\n            <div class=\"row\">\n                <div class=\"field\">\n                    <label>\u30b2\u30fc\u30b8\u30b5\u30a4\u30ba<\/label>\n                    <div class=\"radio-group\">\n                        <label class=\"radio-label\">\n                            <input type=\"radio\" name=\"gauge_size\" value=\"3\" checked> 3\u00d73 (9\u30b3\u30de\u30fb\u63a8\u5968)\n                        <\/label>\n                        <label class=\"radio-label\">\n                            <input type=\"radio\" name=\"gauge_size\" value=\"2\"> 2\u00d72 (4\u30b3\u30de)\n                        <\/label>\n                    <\/div>\n                <\/div>\n\n                <div class=\"field\">\n                    <label>\u7de8\u307f\u76ee\u306e\u5411\u304d (\u7dbe)<\/label>\n                    <div class=\"radio-group\">\n                        <label class=\"radio-label\">\n                            <input type=\"radio\" name=\"weave_dir\" value=\"right\" checked> \u53f3\u5074 (\u53f3\u7dbe\u30fb\u6a19\u6e96)\n                        <\/label>\n                        <label class=\"radio-label\">\n                            <input type=\"radio\" name=\"weave_dir\" value=\"left\"> \u5de6\u5074 (\u5de6\u7dbe)\n                        <\/label>\n                    <\/div>\n                <\/div>\n\n                <div class=\"field\">\n                    <label>\u4f7f\u7528\u3057\u305f\u3072\u3082\u9577 (\u5168\u3072\u3082\u540c\u5bf8)<\/label>\n                    <div class=\"input-group\">\n                        <input type=\"number\" id=\"cordLength\" min=\"1\" step=\"0.1\" value=\"20.0\" style=\"width: 5.5em;\">\n                        <span class=\"unit-label\">cm<\/span>\n                    <\/div>\n                <\/div>\n            <\/div>\n        <\/div>\n\n        \n\n        <!-- \u5358\u4f4d\u306b\u95a2\u3059\u308b\u91cd\u8981\u6ce8\u610f\u30d0\u30ca\u30fc -->\n        <div class=\"unit-alert-banner\">\n            <span class=\"alert-icon\">&#x26a0;&#xfe0f;<\/span>\n            <div class=\"alert-content\">\n                <strong>\u3010\u91cd\u8981\u3011\u6e2c\u5b9a\u5024\u306e\u5165\u529b\u5358\u4f4d\u306b\u3064\u3044\u3066<\/strong><br>\n                \u4f7f\u7528\u3072\u3082\u9577\uff08cm\uff09\u4ee5\u5916\u306e<strong>\u3059\u3079\u3066\u306e\u6e2c\u5b9a\u5024\uff08\u3072\u3082\u306e\u6b8b\u308a\u9577\u3055\u30fb\u30b3\u30de\u5bf8\u6cd5\uff09\u306f\u3010 mm\uff08\u30df\u30ea\uff09\u5358\u4f4d \u3011\u3067\u5165\u529b\u3057\u3066\u304f\u3060\u3055\u3044\u3002<\/strong><br>\n                \u203b cm \u3067\u5165\u529b\u3059\u308b\u3068\u6b63\u3057\u304f\u8a08\u7b97\u3055\u308c\u307e\u305b\u3093\u306e\u3067\u3054\u6ce8\u610f\u304f\u3060\u3055\u3044\uff08\u4f8b: 8.5 cm \u306e\u5834\u5408\u306f <code>85<\/code> mm \u3068\u5165\u529b\uff09\u3002\n            <\/div>\n        <\/div>\n\n        <!-- 2. \u3072\u3082\u6b8b\u308a\u9577\u6e2c\u5b9a\uff08\u8981\u5c3a\u7b97\u51fa\uff09\u30bb\u30af\u30b7\u30e7\u30f3 (\u6848A: \u56f3\u306e\u5468\u56f2\u306b\u76f4\u63a5\u5165\u529b) -->\n        <div class=\"section-group\" id=\"sectionLen\">\n            <div class=\"section-title\">\n                <span>&#x2702;&#xfe0f;<\/span> 2. \u3072\u3082\u306e\u6b8b\u308a\u9577\u3055\u306e\u6e2c\u5b9a\uff08\u30b3\u30de\u8981\u5c3a\uff09\n            <\/div>\n            <div class=\"section-desc\">\n                \u7de8\u307f\u7d42\u308f\u3063\u305f\u30b2\u30fc\u30b8\u306e\u5404\u3072\u3082\u306b\u3064\u3044\u3066\u3001<strong style=\"color: #c2410c;\">\u305d\u308c\u305e\u308c\u306e\u7aef\u306e\u6b8b\u308a\u3072\u3082\u9577<\/strong>\uff08\u30b3\u30de\u7aef\u304b\u3089\u5148\u7aef\u307e\u3067\uff09\u3092 <strong style=\"color: #c2410c;\">mm \u5358\u4f4d<\/strong> \u3067\u5165\u529b\u3057\u3066\u304f\u3060\u3055\u3044\u3002<br>\n                1\u30b3\u30de\u3042\u305f\u308a\u306e\u8981\u5c3a \uff1d (\u3072\u3082\u9577(mm) \uff0d \u6b8b\u308a1(mm) \uff0d \u6b8b\u308a2(mm)) \u00f7 \u30b3\u30de\u6570\n            <\/div>\n\n            <div class=\"len-visual-board\">\n                <!-- \u4e0a\u90e8: \u7e26\u3072\u3082\u4e0a\u7aef (V1\u301cVk \u7aef1) -->\n                <div class=\"len-inputs-top\" id=\"lenInputsTop\"><\/div>\n\n                <div class=\"len-row-middle\">\n                    <!-- \u5de6\u5074: \u6a2a\u3072\u3082\u5de6\u7aef (H1\u301cHk \u7aef1) -->\n                    <div class=\"len-inputs-left\" id=\"lenInputsLeft\"><\/div>\n\n                    <!-- \u4e2d\u592e: \u8981\u5c3a\u30ac\u30a4\u30c9 Canvas -->\n                    <canvas id=\"canvasLen\" width=\"220\" height=\"220\"><\/canvas>\n\n                    <!-- \u53f3\u5074: \u6a2a\u3072\u3082\u53f3\u7aef (H1\u301cHk \u7aef2) + \u7b97\u51fa\u8981\u5c3a\u30d0\u30c3\u30b8 -->\n                    <div class=\"len-inputs-right\" id=\"lenInputsRight\"><\/div>\n                <\/div>\n\n                <!-- \u4e0b\u90e8: \u7e26\u3072\u3082\u4e0b\u7aef (V1\u301cVk \u7aef2) + \u7b97\u51fa\u8981\u5c3a\u30d0\u30c3\u30b8 -->\n                <div class=\"len-inputs-bottom\" id=\"lenInputsBottom\"><\/div>\n            <\/div>\n        <\/div>\n\n        <!-- 3. \u30b3\u30de\u5bf8\u6cd5\u6e2c\u5b9a\u30bb\u30af\u30b7\u30e7\u30f3 (\u30b3\u30de\u62e1\u5927 + \u65b9\u5411\u5225\u30b5\u30d6\u30bf\u30d6) -->\n        <div class=\"section-group\" id=\"sectionSize\">\n            <div class=\"section-title\">\n                <span>&#x1f4d0;<\/span> 3. \u30b3\u30de\u5bf8\u6cd5\u306e\u6e2c\u5b9a\n            <\/div>\n            <div class=\"section-desc\">\n                \u96a3\u308a\u5408\u3046\u30b3\u30de\u306e\u300c<strong style=\"color: #c2410c;\">\u4e2d\u5fc3\u304b\u3089\u4e2d\u5fc3\u307e\u3067<\/strong>\uff08\u7d50\u3073\u76ee\u306e\u4e2d\u5fc3\u9593\uff09\u300d\u306e\u8ddd\u96e2\u3092 <strong style=\"color: #c2410c;\">mm \u5358\u4f4d<\/strong> \u3067\u5165\u529b\u3057\u3066\u304f\u3060\u3055\u3044\u3002<br>\n                \u306e\u3053\u308a\u3072\u3082\u306f\u7701\u7565\u3057\u3001\u30b3\u30de\u90e8\u5206\u3092\u62e1\u5927\u8868\u793a\u3057\u3066\u3044\u307e\u3059\u3002\u77e2\u5370\u304c\u7d50\u3076\u30b3\u30de\u9593\u306e\u5bf8\u6cd5\u3092\u6e2c\u5b9a\u3057\u3066\u304f\u3060\u3055\u3044\u3002\n            <\/div>\n\n            <!-- \u65b9\u5411\u5225\u30b5\u30d6\u30bf\u30d6 -->\n            <div class=\"size-mode-tabs\">\n                <button type=\"button\" class=\"size-tab-btn active\" id=\"tabSizeH\">&#x2194; \u6a2a\u65b9\u5411\u306e\u6e2c\u5b9a<\/button>\n                <button type=\"button\" class=\"size-tab-btn\" id=\"tabSizeV\">&#x2195; \u7e26\u65b9\u5411\u306e\u6e2c\u5b9a<\/button>\n            <\/div>\n\n            <div class=\"size-visual-board\">\n                <canvas id=\"canvasSize\" width=\"360\" height=\"350\"><\/canvas>\n                <div class=\"size-input-overlay\" id=\"sizeOverlay\"><\/div>\n            <\/div>\n        <\/div>\n\n        <!-- 4. \u7d71\u8a08\u30fb\u8a08\u7b97\u7d50\u679c\u30b5\u30de\u30ea\u30fc -->\n        <div class=\"section-group\" style=\"background-color: #ffffff; border: 2px solid #e05d22;\">\n            <div class=\"section-title\" style=\"color: #722d19; font-size: 16px;\">\n                <span>&#x1f4ca;<\/span> \u6e2c\u5b9a\u7d50\u679c\u30fb\u5206\u6790\u30b5\u30de\u30ea\u30fc\n            <\/div>\n\n            <!-- \u8b66\u544a\u30e1\u30c3\u30bb\u30fc\u30b8\u30dc\u30c3\u30af\u30b9 (\u4f53\u7cfb\u5316\u3055\u308c\u305f\u8b66\u544a + \u56fa\u5b9a\u30c1\u30a7\u30c3\u30af\u30ea\u30b9\u30c8) -->\n            <div class=\"warning-box\" id=\"warningBox\">\n                <div class=\"warning-title\">\n                    <span>&#x26a0;&#xfe0f;<\/span> <strong>\u6ce8\u610f:<\/strong> <span id=\"warningMsgText\">&#8212;<\/span>\n                <\/div>\n                <div class=\"warning-checklist-label\">\u3010\u78ba\u8a8d\u30c1\u30a7\u30c3\u30af\u30ea\u30b9\u30c8\u3011<\/div>\n                <ul class=\"warning-checklist\">\n                    <li>\u5165\u529b\u5358\u4f4d\u3084\u6841\u306b\u9593\u9055\u3044\u306f\u3042\u308a\u307e\u305b\u3093\u304b\u3002mm\u5358\u4f4d\u306e\u6570\u5024\u306b\u306a\u3063\u3066\u3044\u307e\u3059\u304b<\/li>\n                    <li>\u3072\u3082\u9577\u306f\u6b63\u3057\u304f\u30bb\u30c3\u30c8\u3055\u308c\u3066\u3044\u307e\u3059\u304b\u3002\u3072\u3082\u9577\u306e\u307fcm \u5358\u4f4d\u3067\u3059\u3002<\/li>\n                    <li>\u30b3\u30de\u8981\u5c3a\u306e\u7aef\u306e\u5bfe\u5fdc\u306f\u6b63\u3057\u3044\u3067\u3059\u304b\u3002\u4e0a\u7aef\u30fb\u4e0b\u7aef\u3001\u5de6\u7aef\u30fb\u53f3\u7aef\u304c\u30da\u30a2\u3067\u3059<\/li>\n                <\/ul>\n            <\/div>\n\n            <div class=\"stats-grid\">\n                <!-- \u30b3\u30de\u8981\u5c3a\u30ab\u30fc\u30c9 -->\n                <div class=\"stat-card primary\">\n                    <div class=\"stat-title\">\n                        <span>\u30b3\u30de\u8981\u5c3a (\u3072\u3082\u6d88\u8cbb\u91cf)<\/span>\n                        <span class=\"stat-count\" id=\"countLen\">0\/6\u672c\u5165\u529b<\/span>\n                    <\/div>\n                    <div class=\"stat-value\" id=\"valLen\">&#8212; <span class=\"unit\">mm<\/span><\/div>\n                    <div class=\"stat-sub\" id=\"subLenSpread\">\u6700\u5927\u30d6\u30ec\u5e45: &#8212;<\/div>\n                    <div class=\"stat-sub\" id=\"subLenCv\">\u7de8\u307f\u76ee\u306e\u5b89\u5b9a\u5ea6: &#8212;<\/div>\n                <\/div>\n\n                <!-- \u30b3\u30de\u5bf8\u6cd5\u30ab\u30fc\u30c9 -->\n                <div class=\"stat-card secondary\">\n                    <div class=\"stat-title\">\n                        <span>\u30b3\u30de\u5bf8\u6cd5 (\u51fa\u6765\u4e0a\u304c\u308a\u5e45)<\/span>\n                        <span class=\"stat-count\" id=\"countSize\">0\/12\u70b9\u5165\u529b<\/span>\n                    <\/div>\n                    <div class=\"stat-value\" id=\"valSize\">&#8212; <span class=\"unit\">mm<\/span><\/div>\n                    <div class=\"stat-sub\" id=\"subSizeSpread\">\u6700\u5927\u30d6\u30ec\u5e45: &#8212;<\/div>\n                    <div class=\"stat-sub\" id=\"subSizeCv\">\u7de8\u307f\u76ee\u306e\u5b89\u5b9a\u5ea6: &#8212;<\/div>\n                <\/div>\n\n                <!-- \u8981\u5c3a\/\u5bf8\u6cd5 \u6bd4\u7387\u30ab\u30fc\u30c9 -->\n                <div class=\"stat-card ratio\" id=\"cardRatio\" style=\"display: none;\">\n                    <div class=\"stat-title\">\n                        <span>\u8981\u5c3a \/ \u5bf8\u6cd5 \u6bd4\u7387<\/span>\n                        <span class=\"stat-count\">\u7406\u8ad6\u5024 \u7d042.88\u500d<\/span>\n                    <\/div>\n                    <div class=\"stat-value\" id=\"valRatio\">&#8212; <span class=\"unit\">\u500d<\/span><\/div>\n                    <div class=\"stat-sub\" id=\"subRatioJudg\">\u5224\u5b9a: &#8212;<\/div>\n                    <div class=\"stat-sub\" style=\"font-size: 10px; color: #94a3b8; margin-top: 4px;\">\n                        \u203b 1\u30b3\u30de\u5bf8\u6cd5\u306b\u5bfe\u3057\u3066\u4f55\u500d\u306e\u3072\u3082\u3092\u6d88\u8cbb\u3057\u3066\u3044\u308b\u304b\u306e\u6307\u6a19\n                    <\/div>\n                <\/div>\n            <\/div>\n\n            <!-- \u30a2\u30af\u30b7\u30e7\u30f3\u30dc\u30bf\u30f3\u30a8\u30ea\u30a2 (\u5916\u90e8\u96fb\u5353\u30c4\u30fc\u30eb\u9023\u643a) -->\n            <div class=\"action-group\">\n                <button type=\"button\" class=\"action-btn btn-knot\" id=\"btnLaunchKnot\" disabled>\n                    &#x2197;&#xfe0f; \u56db\u3064\u7573\u307f\u8a08\u7b97 (knot-calc) \u3092\u958b\u304f\n                <\/button>\n                <button type=\"button\" class=\"action-btn btn-knot45\" id=\"btnLaunchKnot45\" disabled>\n                    &#x2197;&#xfe0f; \u659c\u3081\u56db\u3064\u7573\u307f (knot45-calc) \u3092\u958b\u304f\n                <\/button>\n            <\/div>\n        <\/div>\n\n        <!-- 5. \u6e2c\u5b9a\u7d50\u679c\u306e\u4fdd\u5b58\u30fb\u30b7\u30a7\u30a2 (\u5225\u67a0\u65b0\u8a2d) -->\n        <div class=\"section-group\" id=\"sectionExportShare\" style=\"background-color: #ffffff; border: 1px solid #cbd5e1;\">\n            <div class=\"section-title\" style=\"color: #1e293b;\">\n                <span>&#x1f4be;<\/span> 5. \u6e2c\u5b9a\u7d50\u679c\u306e\u4fdd\u5b58\u30fb\u30b7\u30a7\u30a2\n            <\/div>\n            <div class=\"section-desc\">\n                \u6e2c\u5b9a\u7d50\u679c\u3092PDF\u3068\u3057\u3066\u4fdd\u5b58\u3057\u305f\u308a\u3001Google\u30d5\u30a9\u30fc\u30e0\u3078\u9001\u4fe1\u3057\u3066\u4ed6\u306e\u4f5c\u308a\u624b\u3068\u30b2\u30fc\u30b8\u30c7\u30fc\u30bf\u3092\u30b7\u30a7\u30a2\u3067\u304d\u307e\u3059\u3002<br>\n                \u4ee5\u4e0b\u306e\u6750\u6599\u30fb\u4f5c\u54c1\u60c5\u5831\u306f\u4efb\u610f\u5165\u529b\u3067\u3059\uff08\u672a\u5165\u529b\u306e\u307e\u307e\u3067\u3082\u4fdd\u5b58\u30fb\u30b7\u30a7\u30a2\u53ef\u80fd\u3067\u3059\u304c\u3001\u8a18\u8f09\u3044\u305f\u3060\u304f\u3068PDF\u306e\u8a18\u9332\u3084\u3001\u307f\u3093\u306a\u306e\u53c2\u8003\u30c7\u30fc\u30bf\u3068\u3057\u3066\u5f79\u7acb\u3061\u307e\u3059\uff09\u3002\n            <\/div>\n\n            <!-- \u4efb\u610f\u5165\u529b\u9805\u76ee -->\n            <div class=\"share-form-grid\">\n                <div class=\"share-field\">\n                    <label for=\"shareBrand\">\u30e1\u30fc\u30ab\u30fc\u30fb\u88fd\u54c1\u540d <span class=\"field-hint\">(\u30b7\u30e7\u30c3\u30d7\u540d\u3084\u30b7\u30ea\u30fc\u30ba\u540d\u306a\u3069\u3001\u308f\u304b\u308b\u7bc4\u56f2\u3067)<\/span><\/label>\n                    <input type=\"text\" id=\"shareBrand\" placeholder=\"\u4f8b: \u3007\u3007\u30b7\u30ea\u30fc\u30ba\u7d19\u30d0\u30f3\u30c9\u3001\u3007\u3007\u30b7\u30e7\u30c3\u30d7\u306a\u3069\">\n                <\/div>\n                <div class=\"share-field\">\n                    <label for=\"shareTotalStrap\">\u5168\u5e45\u6570 <span class=\"field-hint\">(\u5272\u304b\u305a\u306b\u4f7f\u7528\u3059\u308b\u5834\u5408\u306f1)<\/span><\/label>\n                    <input type=\"number\" id=\"shareTotalStrap\" min=\"1\" step=\"1\" placeholder=\"\u4f8b: 12\">\n                <\/div>\n                <div class=\"share-field\">\n                    <label for=\"shareBandWidth\">\u30d0\u30f3\u30c9\u5e45 [mm]<\/label>\n                    <input type=\"number\" id=\"shareBandWidth\" min=\"0\" step=\"0.1\" placeholder=\"\u4f8b: 15.0\">\n                <\/div>\n                <div class=\"share-field\">\n                    <label for=\"shareUsedStrap\">\u4f7f\u7528\u3057\u305f\u672c\u5e45\u6570 <span class=\"field-hint\">(\u5272\u304b\u305a\u306b\u4f7f\u3063\u305f\u5834\u5408\u306f\u5168\u5e45\u6570\u3068\u540c\u3058)<\/span><\/label>\n                    <input type=\"number\" id=\"shareUsedStrap\" min=\"1\" step=\"1\" placeholder=\"\u4f8b: 4\">\n                <\/div>\n                <div class=\"share-field full-width\">\n                    <label for=\"shareMemo\">\u7de8\u307f\u5fc3\u5730\u30fb\u3072\u3068\u3053\u3068\u30e1\u30e2<\/label>\n                    <textarea id=\"shareMemo\" rows=\"2\" placeholder=\"\u7de8\u307f\u5fc3\u5730\u3001\u624b\u306e\u30ad\u30c4\u3055\u3001\u4ed5\u4e0a\u304c\u308a\u306e\u786c\u3055\u306a\u3069\u306e\u30e1\u30e2\uff08\u4efb\u610f\uff09\"><\/textarea>\n                <\/div>\n            <\/div>\n\n            <!-- \u30dc\u30bf\u30f3\u64cd\u4f5c -->\n            <div class=\"share-action-group\">\n                <button type=\"button\" class=\"action-btn btn-pdf\" id=\"btnExportPdf\" disabled>\n                    &#x1f4c4; \u6e2c\u5b9a\u7d50\u679c\u3092PDF\u3067\u4fdd\u5b58\n                <\/button>\n                <button type=\"button\" class=\"action-btn btn-share-form\" id=\"btnShareGoogleForm\" disabled>\n                    &#x1f310; \u7d50\u679c\u3092google Form\u306b\u30b7\u30a7\u30a2\u3059\u308b\n                <\/button>\n                <button type=\"button\" class=\"action-btn btn-view-results\" id=\"btnViewSharedResults\">\n                    &#x1f4ca; \u30b7\u30a7\u30a2\u3055\u308c\u305f\u7d50\u679c\u3092\u898b\u308b(\u898b\u308b\u3060\u3051\u3082OK)\n                <\/button>\n            <\/div>\n        <\/div>\n\n        <script>\n\/\/<![CDATA[\n\n            (() => { \/\/ \u5373\u6642\u5b9f\u884c\u95a2\u6570 (\u5909\u6570\u9694\u96e2)\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\/gauge-calc\/\"\n                 *\/\n\n                const KNOT_CALC_URL = \"https:\/\/labo.com\/CraftBand\/sharing\/knot-calc\/\";\n                const KNOT45_CALC_URL = \"https:\/\/labo.com\/CraftBand\/sharing\/knot45-calc\/\";\n\n                \/\/ --- Google \u30d5\u30a9\u30fc\u30e0\u9023\u643a\u8a2d\u5b9a (\u30d5\u30a9\u30fc\u30e0\u4f5c\u6210\u5f8c\u306b URL \u304a\u3088\u3073 entry ID \u3092\u8a2d\u5b9a\u3057\u3066\u304f\u3060\u3055\u3044) ---\n                const GOOGLE_FORM_CONFIG = {\n                    title: \"\u56db\u3064\u7573\u307f\u7de8\u307f\u30b2\u30fc\u30b8\u6e2c\u5b9a\u7d50\u679c\u30b7\u30a7\u30a2\u30d5\u30a9\u30fc\u30e0\",\n                    \/\/ \u9001\u4fe1\u5148URL (formResponse \/ viewform)\n                    actionUrl: \"https:\/\/docs.google.com\/forms\/d\/e\/1FAIpQLSdbET4OwvlbF8R6pRAf7z0JU1kemBXrZXjiCwl92gm7V6HpMg\/formResponse\",\n                    \/\/ \u7d50\u679c\u306e Google \u30b9\u30d7\u30ec\u30c3\u30c9\u30b7\u30fc\u30c8\u3092 HTML \u3067\u958b\u304f URL\n                    resultsUrl: \"https:\/\/docs.google.com\/spreadsheets\/d\/e\/2PACX-1vQj3ACzNL0zSRcycyFbovFvNo2A71YBuFiQ8drmUPnKMf2iQynjlEfgk-GjIQYLjbxYw8XbPIfWbNb2\/pubhtml?gid=457362502&single=true\",\n\n                    \/\/ \u5404\u5165\u529b\u6b04\u306e entry ID\n                    entries: {\n                        maker:        \"entry.1952005209\", \/\/ \u30e1\u30fc\u30ab\u30fc\u30fb\u88fd\u54c1\u540d\n                        totalStrips:  \"entry.1638046113\", \/\/ \u5168\u5e45\u6570\n                        bandWidth:    \"entry.502367732\",  \/\/ \u30d0\u30f3\u30c9\u5e45 [mm]\n                        usedStrips:   \"entry.780783233\",  \/\/ \u4f7f\u7528\u3057\u305f\u672c\u5e45\u6570\n                        knotSize:     \"entry.441891396\",  \/\/ \u30b3\u30de\u5bf8\u6cd5 [mm]\n                        knotLen:      \"entry.1422237192\", \/\/ \u30b3\u30de\u8981\u5c3a [mm]\n                        cv:           \"entry.1989071038\", \/\/ \u8981\u5c3a\u6e2c\u5b9a\u306e\u5b89\u5b9a\u5ea6 (CV%)\n                        memo:         \"entry.1129192351\"  \/\/ \u7de8\u307f\u5fc3\u5730\u30fb\u3072\u3068\u3053\u3068\u30e1\u30e2\n                    }\n                };\n\n                const containerId = \"gauge-calc-app\";\n                let container = null;\n                if (document.currentScript) {\n                    container = document.currentScript.closest('#' + containerId);\n                    if (!container) {\n                        container = document.currentScript.parentElement;\n                    }\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 cordLengthInput = el('#cordLength');\n                const lenInputsTop = el('#lenInputsTop');\n                const lenInputsBottom = el('#lenInputsBottom');\n                const lenInputsLeft = el('#lenInputsLeft');\n                const lenInputsRight = el('#lenInputsRight');\n                const canvasLen = el('#canvasLen');\n                const ctxLen = canvasLen.getContext('2d');\n\n                const canvasSize = el('#canvasSize');\n                const ctxSize = canvasSize.getContext('2d');\n                const sizeOverlay = el('#sizeOverlay');\n                const tabSizeH = el('#tabSizeH');\n                const tabSizeV = el('#tabSizeV');\n\n                const countLen = el('#countLen');\n                const valLen = el('#valLen');\n                const subLenSpread = el('#subLenSpread');\n                const subLenCv = el('#subLenCv');\n\n                const countSize = el('#countSize');\n                const valSize = el('#valSize');\n                const subSizeSpread = el('#subSizeSpread');\n                const subSizeCv = el('#subSizeCv');\n\n                const cardRatio = el('#cardRatio');\n                const valRatio = el('#valRatio');\n                const subRatioJudg = el('#subRatioJudg');\n\n                const warningBox = el('#warningBox');\n                const warningMsgText = el('#warningMsgText');\n                const btnLaunchKnot = el('#btnLaunchKnot');\n                const btnLaunchKnot45 = el('#btnLaunchKnot45');\n                const btnExportPdf = el('#btnExportPdf');\n                const btnShareGoogleForm = el('#btnShareGoogleForm');\n                const btnViewSharedResults = el('#btnViewSharedResults');\n                const shareBrand = el('#shareBrand');\n                const shareTotalStrap = el('#shareTotalStrap');\n                const shareBandWidth = el('#shareBandWidth');\n                const shareUsedStrap = el('#shareUsedStrap');\n                const shareMemo = el('#shareMemo');\n\n                let currentSizeMode = 'H'; \/\/ 'H' \u307e\u305f\u306f 'V'\n                let lastCalculatedResult = null;\n                \/\/ \u5bf8\u6cd5\u5024\u306e\u4fdd\u6301\u7528\u30ad\u30e3\u30c3\u30b7\u30e5 { \"H_1_1\": 20.0, ... }\n                const sizeValuesStore = {};\n\n                const getGaugeSize = () => {\n                    const checked = el('input[name=\"gauge_size\"]:checked');\n                    return checked ? parseInt(checked.value, 10) : 3;\n                };\n\n                const getWeaveDir = () => {\n                    const checked = el('input[name=\"weave_dir\"]:checked');\n                    return checked ? checked.value : 'right';\n                };\n\n                \/\/ --- 1. UI\u69cb\u7bc9 ---\n                const buildUI = () => {\n                    const k = getGaugeSize(); \/\/ 3 \u307e\u305f\u306f 2\n                    const isLeft = (getWeaveDir() === 'left');\n\n                    \/\/ A. \u8981\u5c3a\u5165\u529b\u30dc\u30c3\u30af\u30b9\u306e\u69cb\u7bc9 (Canvas 220x220 \u5b8c\u5168\u30d5\u30a3\u30c3\u30c8\u914d\u7f6e)\n                    const positions = (k === 3) ? [42, 110, 178] : [68, 152];\n\n                    let topHtml = '';\n                    let bottomHtml = '';\n                    let leftHtml = '';\n                    let rightHtml = '';\n\n                    \/\/ \u7e26\u3072\u3082 V1\u301cVk (\u4e0a\u30fb\u4e0b)\n                    for (let c = 0; c !== k; c++) {\n                        const idx = c + 1;\n                        let posX = positions[c];\n                        if (isLeft) {\n                            posX = 220 - positions[c];\n                        }\n\n                        \/\/ \u4e0a\u7aef (\u7aef1: \u672a\u5165\u529b\u304c\u3072\u3068\u76ee\u3067\u308f\u304b\u308b\u3088\u3046\u30d7\u30ec\u30fc\u30b9\u30db\u30eb\u30c0\u30fc\u306a\u3057)\n                        topHtml += `\n                            <div class=\"len-box-v\" style=\"left: ${posX}px; bottom: 2px;\">\n                                <span class=\"len-box-label\" style=\"color: #b45309;\">V${idx} \u4e0a\u7aef<\/span>\n                                <input type=\"number\" step=\"0.1\" min=\"0\" class=\"len-input\" data-cord=\"V${idx}\" data-end=\"1\" value=\"\">\n                            <\/div>\n                        `;\n\n                        \/\/ \u4e0b\u7aef (\u7aef2)\n                        bottomHtml += `\n                            <div class=\"len-box-v\" style=\"left: ${posX}px; top: 2px;\">\n                                <span class=\"len-box-label\" style=\"color: #b45309;\">V${idx} \u4e0b\u7aef<\/span>\n                                <input type=\"number\" step=\"0.1\" min=\"0\" class=\"len-input\" data-cord=\"V${idx}\" data-end=\"2\" value=\"\">\n                                <span class=\"len-sub-badge\" id=\"res_V${idx}\">-- mm<\/span>\n                            <\/div>\n                        `;\n                    }\n\n                    \/\/ \u6a2a\u3072\u3082 H1\u301cHk (\u5de6\u30fb\u53f3)\n                    for (let r = 0; r !== k; r++) {\n                        const idx = r + 1;\n                        const posY = positions[r];\n\n                        \/\/ \u5de6\u7aef (\u7aef1)\n                        leftHtml += `\n                            <div class=\"len-box-h\" style=\"top: ${posY}px; right: 2px;\">\n                                <span class=\"len-box-label\" style=\"color: #1e40af;\">H${idx} \u5de6\u7aef<\/span>\n                                <input type=\"number\" step=\"0.1\" min=\"0\" class=\"len-input\" data-cord=\"H${idx}\" data-end=\"1\" value=\"\">\n                            <\/div>\n                        `;\n\n                        \/\/ \u53f3\u7aef (\u7aef2)\n                        rightHtml += `\n                            <div class=\"len-box-h\" style=\"top: ${posY}px; left: 2px;\">\n                                <span class=\"len-box-label\" style=\"color: #1e40af;\">H${idx} \u53f3\u7aef<\/span>\n                                <input type=\"number\" step=\"0.1\" min=\"0\" class=\"len-input\" data-cord=\"H${idx}\" data-end=\"2\" value=\"\">\n                                <span class=\"len-sub-badge\" id=\"res_H${idx}\">-- mm<\/span>\n                            <\/div>\n                        `;\n                    }\n\n                    lenInputsTop.innerHTML = topHtml;\n                    lenInputsBottom.innerHTML = bottomHtml;\n                    lenInputsLeft.innerHTML = leftHtml;\n                    lenInputsRight.innerHTML = rightHtml;\n\n                    \/\/ B. \u5bf8\u6cd5\u30bf\u30d6\u30c6\u30ad\u30b9\u30c8\u66f4\u65b0\n                    const pointsCount = k * (k - 1);\n                    tabSizeH.textContent = `\\u2194 \u6a2a\u65b9\u5411\u306e\u6e2c\u5b9a (${pointsCount}\u7b87\u6240)`;\n                    tabSizeV.textContent = `\\u2195 \u7e26\u65b9\u5411\u306e\u6e2c\u5b9a (${pointsCount}\u7b87\u6240)`;\n\n                    \/\/ \u30a4\u30d9\u30f3\u30c8\u30ea\u30b9\u30ca\u30fc\u8a2d\u5b9a\n                    els('.len-input').forEach(inp => inp.addEventListener('input', calculateAll));\n\n                    calculateAll();\n                    drawLenCanvas();\n                    drawSizeCanvas();\n                };\n\n                \/\/ \u8b66\u544a\u5224\u5b9a\u4f53\u7cfb (\u512a\u5148\u9806\u4f4d\u9806: \u6700\u521d\u306b\u8a72\u5f53\u3057\u305f1\u70b9\u306e\u307f\u3092\u8fd4\u3059)\n                const evaluateWarnings = (ctx) => {\n                    \/\/ \u512a\u5148\u5ea6 1: \u5165\u529b\u5024\u306b\u8ca0\u6570\u304c\u3042\u308b (\u3072\u3082\u9577 - \u6b8b\u308a\u3072\u3082\u9577\u304c\u30de\u30a4\u30ca\u30b9\u306e\u5834\u5408\u3082\u542b\u3080)\n                    if (ctx.hasNegative) {\n                        return \"\u30de\u30a4\u30ca\u30b9\u306e\u5165\u529b\u304c\u3042\u308a\u307e\u3059\";\n                    }\n                    \/\/ \u512a\u5148\u5ea6 2: \u5165\u529b\u5024\u306b\u30bc\u30ed\u304c\u3042\u308b (\u540c\u4e0a: \u5dee\u5206\u304c\u30bc\u30ed\u306e\u5834\u5408\u3082\u542b\u3080)\n                    if (ctx.hasZero) {\n                        return \"\u30bc\u30ed\u306e\u5165\u529b\u304c\u3042\u308a\u307e\u3059\";\n                    }\n                    \/\/ \u512a\u5148\u5ea6 3: \u6700\u5927\u30d6\u30ec\u5e45\u304c\u6975\u7aef\u306b\u5927\u304d\u3044\u5834\u5408 (\u6700\u5927\u30d6\u30ec\u5e45 15.0%\u4ee5\u4e0a)\n                    if (Math.sign(ctx.maxSpread - 15.0) !== -1) {\n                        return \"\u5165\u529b\u5024\u304c\u5927\u304d\u304f\u7570\u306a\u3063\u3066\u3044\u307e\u3059\";\n                    }\n                    \/\/ \u512a\u5148\u5ea6 4: \u8981\u5c3a\uff0f\u30b3\u30de\u5bf8\u6cd5 \u6bd4\u7387\u304c\u7406\u8ad6\u5024(6.43\/2.236)\u3088\u308a\u5c0f\u3055\u3044\u3001\u3082\u3057\u304f\u306f4\u4ee5\u4e0a (\u6bd4\u7387\u306f\u7b97\u51fa\u6761\u4ef6\u3092\u6e80\u305f\u3057\u305f\u3089)\n                    if (ctx.hasRatio) {\n                        const THEORETICAL_RATIO = 6.43 \/ 2.236; \/\/ \u7d04 2.87567\n                        const isTooSmall = Math.sign(ctx.ratio - THEORETICAL_RATIO) === -1;\n                        const isTooLarge = Math.sign(ctx.ratio - 4.0) !== -1;\n                        if (isTooSmall ? true : isTooLarge) {\n                            return \"\u5bf8\u6cd5\u30fb\u8981\u5c3a\u3068\u3057\u3066\u306f\u7570\u5e38\u306a\u5024\u3067\u3059\";\n                        }\n                    }\n                    return null;\n                };\n\n                \/\/ --- 2. \u7d71\u8a08\u8a08\u7b97\u30ed\u30b8\u30c3\u30af ---\n                const calcStats = (arr) => {\n                    const valid = arr.filter(v => {\n                    if (typeof v !== 'number') return false;\n                    if (isNaN(v)) return false;\n                    return Math.sign(v) === 1;\n                });\n                    const n = valid.length;\n                    if (n === 0) return { n: 0, mean: null, spreadPct: null, cvPct: null };\n\n                    const sum = valid.reduce((a, b) => a + b, 0);\n                    const mean = sum \/ n;\n\n                    if (n === 1) return { n: 1, mean: mean, spreadPct: null, cvPct: null };\n\n                    const min = Math.min(...valid);\n                    const max = Math.max(...valid);\n                    const spreadPct = (Math.sign(mean) === 1) ? (((max - min) \/ mean) * 100) : 0;\n\n                    let cvPct = null;\n                    if (Math.sign(n - 2) !== -1) {\n                        const variance = valid.reduce((acc, v) => acc + Math.pow(v - mean, 2), 0) \/ (n - 1);\n                        const sd = Math.sqrt(variance);\n                        cvPct = (Math.sign(mean) === 1) ? ((sd \/ mean) * 100) : 0;\n                    }\n\n                    return { n, mean, min, max, spreadPct, cvPct };\n                };\n\n                const calculateAll = () => {\n                    const k = getGaugeSize();\n                    const rawCordCm = parseFloat(cordLengthInput.value);\n                    const totalCordCm = !isNaN(rawCordCm) ? rawCordCm : 0;\n                    const totalCordMm = totalCordCm * 10;\n\n                    let hasNegative = false;\n                    let hasZero = false;\n\n                    \/\/ \u3072\u3082\u9577\u81ea\u4f53\u306e\u8ca0\u6570\u30fb\u30bc\u30ed\u30c1\u30a7\u30c3\u30af\n                    if (cordLengthInput.value.trim() !== '') {\n                        if (!isNaN(rawCordCm)) {\n                            if (Math.sign(rawCordCm) === -1) hasNegative = true;\n                            if (rawCordCm === 0) hasZero = true;\n                        }\n                    }\n\n                    \/\/ 1. \u5404\u3072\u3082\u306e\u8981\u5c3a\u8a08\u7b97\n                    const cordNames = [];\n                    for (let i = 1; i !== k + 1; i++) cordNames.push(`V${i}`);\n                    for (let i = 1; i !== k + 1; i++) cordNames.push(`H${i}`);\n\n                    const lenValues = [];\n\n                    cordNames.forEach(name => {\n                        const inp1 = el(`.len-input[data-cord=\"${name}\"][data-end=\"1\"]`);\n                        const inp2 = el(`.len-input[data-cord=\"${name}\"][data-end=\"2\"]`);\n                        const resCell = el(`#res_${name}`);\n                        if (!inp1 ? true : (!inp2 ? true : !resCell)) return;\n\n                        const v1 = parseFloat(inp1.value);\n                        const v2 = parseFloat(inp2.value);\n\n                        let cordHasError = false;\n\n                        \/\/ \u5404\u7aef\u5165\u529b\u306e\u8ca0\u6570\u30fb\u30bc\u30ed\u30c1\u30a7\u30c3\u30af\n                        [inp1, inp2].forEach(inp => {\n                            if (inp.value.trim() !== '') {\n                                const val = parseFloat(inp.value);\n                                if (!isNaN(val)) {\n                                    if (Math.sign(val) === -1) {\n                                        hasNegative = true;\n                                        cordHasError = true;\n                                    } else if (val === 0) {\n                                        hasZero = true;\n                                        cordHasError = true;\n                                    }\n                                }\n                            }\n                        });\n\n                        \/\/ \u4e21\u7aef\u304c\u5165\u529b\u3055\u308c\u3066\u3044\u308b\u5834\u5408\u306e\u300c\u3072\u3082\u9577 - \u6b8b\u308a\u3072\u3082\u9577\u300d\u30c1\u30a7\u30c3\u30af\n                        let diff = null;\n                        if (!isNaN(v1) ? !isNaN(v2) : false) {\n                            diff = totalCordMm - (v1 + v2);\n                            if (Math.sign(diff) === -1) {\n                                hasNegative = true;\n                                cordHasError = true;\n                            } else if (diff === 0) {\n                                hasZero = true;\n                                cordHasError = true;\n                            }\n                        }\n\n                        \/\/ \u30a8\u30e9\u30fc\u67a0\u306e\u4ed8\u4e0e\u30fb\u89e3\u9664\n                        if (cordHasError) {\n                            if (inp1.value.trim() !== '') inp1.classList.add('input-error');\n                            if (inp2.value.trim() !== '') inp2.classList.add('input-error');\n                        } else {\n                            inp1.classList.remove('input-error');\n                            inp2.classList.remove('input-error');\n                        }\n\n                        \/\/ \u6b63\u306e\u6709\u52b9\u5024\u306e\u307f\u8981\u5c3a\u7b97\u51fa\u30fb\u7d71\u8a08\u914d\u5217\u3078\u6295\u5165 (\u9664\u5916\u306f\u5f93\u6765\u901a\u308a)\n                        const v1Ok = (!isNaN(v1) ? (Math.sign(v1) === 1) : false);\n                        const v2Ok = (!isNaN(v2) ? (Math.sign(v2) === 1) : false);\n                        const diffOk = (diff !== null) ? (Math.sign(diff) === 1) : false;\n                        if ((v1Ok ? v2Ok : false) ? diffOk : false) {\n                            const komaLenMm = diff \/ k;\n                            resCell.textContent = `${komaLenMm.toFixed(1)} mm`;\n                            resCell.style.color = '#0369a1';\n                            lenValues.push(komaLenMm);\n                        } else {\n                            resCell.textContent = '-- mm';\n                            resCell.style.color = '#94a3b8';\n                        }\n                    });\n\n                    \/\/ 2. \u30b3\u30de\u5bf8\u6cd5\u8a08\u7b97 (\u30ad\u30e3\u30c3\u30b7\u30e5\u304a\u3088\u3073\u753b\u9762\u5165\u529b\u5024\u304b\u3089\u53d6\u5f97)\n                    const sizeValues = [];\n\n                    for (let r = 1; r !== k + 1; r++) {\n                        for (let c = 1; c !== k; c++) {\n                            const key = `H_${r}_${c}`;\n                            const val = sizeValuesStore[key];\n                            if ((typeof val === 'number') ? !isNaN(val) : false) {\n                                if (Math.sign(val) === -1) hasNegative = true;\n                                else if (val === 0) hasZero = true;\n                                else sizeValues.push(val);\n                            }\n                        }\n                    }\n                    for (let c = 1; c !== k + 1; c++) {\n                        for (let r = 1; r !== k; r++) {\n                            const key = `V_${c}_${r}`;\n                            const val = sizeValuesStore[key];\n                            if ((typeof val === 'number') ? !isNaN(val) : false) {\n                                if (Math.sign(val) === -1) hasNegative = true;\n                                else if (val === 0) hasZero = true;\n                                else sizeValues.push(val);\n                            }\n                        }\n                    }\n\n                    \/\/ \u753b\u9762\u4e0a\u306e\u5bf8\u6cd5\u5165\u529b\u67a0\u306e\u30a8\u30e9\u30fc\u30af\u30e9\u30b9\u53cd\u6620\n                    els('.size-input').forEach(inp => {\n                        if (inp.value.trim() !== '') {\n                            const v = parseFloat(inp.value);\n                            if (!isNaN(v) ? (Math.sign(v) !== 1) : false) inp.classList.add('input-error');\n                            else inp.classList.remove('input-error');\n                        } else {\n                            inp.classList.remove('input-error');\n                        }\n                    });\n\n                    \/\/ 3. \u7d71\u8a08\u7b97\u51fa\n                    const statLen = calcStats(lenValues);\n                    const statSize = calcStats(sizeValues);\n\n                    \/\/ 4. UI \u8868\u793a\n                    const totalCords = k * 2;\n                    const totalSizePoints = k * (k - 1) * 2;\n\n                    countLen.textContent = `${statLen.n}\/${totalCords}\u672c\u5165\u529b`;\n                    countSize.textContent = `${statSize.n}\/${totalSizePoints}\u70b9\u5165\u529b`;\n\n                    \/\/ \u8981\u5c3a\n                    if (statLen.n === 0) {\n                        valLen.innerHTML = `-- <span class=\"unit\">mm<\/span>`;\n                        subLenSpread.textContent = `\u6700\u5927\u30d6\u30ec\u5e45: --`;\n                        subLenCv.textContent = `\u7de8\u307f\u76ee\u306e\u5b89\u5b9a\u5ea6: --`;\n                    } else if (statLen.n === 1) {\n                        valLen.innerHTML = `${statLen.mean.toFixed(1)} <span class=\"unit\">mm<\/span>`;\n                        subLenSpread.textContent = `\u6700\u5927\u30d6\u30ec\u5e45: \u203b 2\u70b9\u4ee5\u4e0a\u3067\u8868\u793a`;\n                        subLenCv.textContent = `\u7de8\u307f\u76ee\u306e\u5b89\u5b9a\u5ea6: \u203b 4\u70b9\u4ee5\u4e0a\u3067\u8868\u793a`;\n                    } else if (Math.sign(statLen.n - 3) !== 1) {\n                        valLen.innerHTML = `${statLen.mean.toFixed(2)} <span class=\"unit\">mm<\/span>`;\n                        subLenSpread.innerHTML = `\u6700\u5927\u30d6\u30ec\u5e45: <b>${statLen.spreadPct.toFixed(1)}%<\/b> (${getSpreadText(statLen.spreadPct)})`;\n                        subLenCv.textContent = `\u7de8\u307f\u76ee\u306e\u5b89\u5b9a\u5ea6: \u203b 4\u70b9\u4ee5\u4e0a\u3067\u8868\u793a`;\n                    } else {\n                        valLen.innerHTML = `${statLen.mean.toFixed(2)} <span class=\"unit\">mm<\/span>`;\n                        subLenSpread.innerHTML = `\u6700\u5927\u30d6\u30ec\u5e45: <b>${statLen.spreadPct.toFixed(1)}%<\/b> (${getSpreadText(statLen.spreadPct)})`;\n                        subLenCv.innerHTML = `\u7de8\u307f\u76ee\u306e\u5b89\u5b9a\u5ea6: <b>CV ${statLen.cvPct.toFixed(1)}%<\/b> (${getCvText(statLen.cvPct)})`;\n                    }\n\n                    \/\/ \u30b3\u30de\u5bf8\u6cd5\n                    if (statSize.n === 0) {\n                        valSize.innerHTML = `-- <span class=\"unit\">mm<\/span>`;\n                        subSizeSpread.textContent = `\u6700\u5927\u30d6\u30ec\u5e45: --`;\n                        subSizeCv.textContent = `\u7de8\u307f\u76ee\u306e\u5b89\u5b9a\u5ea6: --`;\n                    } else if (statSize.n === 1) {\n                        valSize.innerHTML = `${statSize.mean.toFixed(1)} <span class=\"unit\">mm<\/span>`;\n                        subSizeSpread.textContent = `\u6700\u5927\u30d6\u30ec\u5e45: \u203b 2\u70b9\u4ee5\u4e0a\u3067\u8868\u793a`;\n                        subSizeCv.textContent = `\u7de8\u307f\u76ee\u306e\u5b89\u5b9a\u5ea6: \u203b 4\u70b9\u4ee5\u4e0a\u3067\u8868\u793a`;\n                    } else if (Math.sign(statSize.n - 3) !== 1) {\n                        valSize.innerHTML = `${statSize.mean.toFixed(2)} <span class=\"unit\">mm<\/span>`;\n                        subSizeSpread.innerHTML = `\u6700\u5927\u30d6\u30ec\u5e45: <b>${statSize.spreadPct.toFixed(1)}%<\/b> (${getSpreadText(statSize.spreadPct)})`;\n                        subSizeCv.textContent = `\u7de8\u307f\u76ee\u306e\u5b89\u5b9a\u5ea6: \u203b 4\u70b9\u4ee5\u4e0a\u3067\u8868\u793a`;\n                    } else {\n                        valSize.innerHTML = `${statSize.mean.toFixed(2)} <span class=\"unit\">mm<\/span>`;\n                        subSizeSpread.innerHTML = `\u6700\u5927\u30d6\u30ec\u5e45: <b>${statSize.spreadPct.toFixed(1)}%<\/b> (${getSpreadText(statSize.spreadPct)})`;\n                        subSizeCv.innerHTML = `\u7de8\u307f\u76ee\u306e\u5b89\u5b9a\u5ea6: <b>CV ${statSize.cvPct.toFixed(1)}%<\/b> (${getCvText(statSize.cvPct)})`;\n                    }\n\n                    \/\/ \u6bd4\u7387\n                    const hasRatioLen = Math.sign(statLen.n - 1) !== -1;\n                    const hasRatioSize = Math.sign(statSize.n - 1) !== -1;\n                    const hasRatioMean = statSize.mean ? (Math.sign(statSize.mean) === 1) : false;\n                    const hasRatio = hasRatioLen ? (hasRatioSize ? hasRatioMean : false) : false;\n                    const calcRatio = hasRatio ? (statLen.mean \/ statSize.mean) : null;\n\n                    if (hasRatio) {\n                        cardRatio.style.display = 'block';\n                        valRatio.innerHTML = `${calcRatio.toFixed(2)} <span class=\"unit\">\u500d<\/span>`;\n\n                        const isConfirmed = (Math.sign(statLen.n - 4) !== -1) ? (Math.sign(statSize.n - 4) !== -1) : false;\n                        const THEORETICAL_RATIO = 6.43 \/ 2.236; \/\/ \u7d04 2.87567\n                        const isAbnSmall = Math.sign(calcRatio - THEORETICAL_RATIO) === -1;\n                        const isAbnLarge = Math.sign(calcRatio - 4.0) !== -1;\n                        const isAbnormalRatio = isAbnSmall ? true : isAbnLarge;\n                        const judg = getRatioText(calcRatio);\n                        const badgeClass = isAbnormalRatio ? \"stat-badge warn\" : (isConfirmed ? \"stat-badge good\" : \"stat-badge warn\");\n                        const noteText = isConfirmed ? \"\" : \" \u203b\u53c2\u8003\u5024\";\n                        subRatioJudg.innerHTML = `\u5224\u5b9a: <span class=\"${badgeClass}\">${judg}${noteText}<\/span>`;\n                    } else {\n                        cardRatio.style.display = 'none';\n                    }\n\n                    \/\/ \u8b66\u544a\u30dc\u30c3\u30af\u30b9 (\u4f53\u7cfb\u5316\u3055\u308c\u305f\u512a\u5148\u9806\u4f4d\u8a55\u4fa1)\n                    const sp1 = statLen.spreadPct ? statLen.spreadPct : 0;\n                    const sp2 = statSize.spreadPct ? statSize.spreadPct : 0;\n                    const maxSpread = Math.max(sp1, sp2);\n\n                    const activeWarning = evaluateWarnings({\n                        hasNegative,\n                        hasZero,\n                        maxSpread,\n                        hasRatio,\n                        ratio: calcRatio\n                    });\n\n                    if (activeWarning) {\n                        warningBox.style.display = 'block';\n                        warningMsgText.textContent = activeWarning;\n                    } else {\n                        warningBox.style.display = 'none';\n                    }\n\n                    \/\/ \u30dc\u30bf\u30f3\u6d3b\u6027\u5316\n                    const canLaunch = (Math.sign(statLen.n - 1) !== -1) ? (Math.sign(statSize.n - 1) !== -1) : false;\n                    btnLaunchKnot.disabled = !canLaunch;\n                    btnLaunchKnot45.disabled = !canLaunch;\n                    btnExportPdf.disabled = !canLaunch;\n                    btnShareGoogleForm.disabled = !canLaunch;\n\n                    lastCalculatedResult = {\n                        k,\n                        totalCordCm,\n                        statLen,\n                        statSize,\n                        ratio: (statSize.mean ? (Math.sign(statSize.mean) === 1) : false) ? (statLen.mean \/ statSize.mean) : null\n                    };\n                };\n\n                const getSpreadText = (spread) => {\n                    if (Math.sign(spread - 5.0) === -1) return \"\u6975\u3081\u3066\u512a\u79c0\";\n                    if (Math.sign(spread - 10.0) === -1) return \"\u6982\u306d\u512a\u79c0\";\n                    if (Math.sign(spread - 15.0) === -1) return \"\u30d0\u30e9\u3064\u304d\u3042\u308a\";\n                    return \"\u8981\u518d\u6e2c\u5b9a\u30fb\u5f15\u304d\u7de0\u3081\u30e0\u30e9\u6ce8\u610f\";\n                };\n\n                const getCvText = (cv) => {\n                    if (Math.sign(cv - 3.0) === -1) return \"\u6975\u3081\u3066\u5747\u4e00\";\n                    if (Math.sign(cv - 6.0) === -1) return \"\u6a19\u6e96\u7684\";\n                    if (Math.sign(cv - 10.0) === -1) return \"\u30d0\u30e9\u3064\u304d\u3042\u308a\";\n                    return \"\u7de8\u307f\u52a0\u6e1b\u306b\u30e0\u30e9\u3042\u308a\";\n                };\n\n                \/\/ \u8981\u5c3a \/ \u5bf8\u6cd5 \u6bd4\u7387\u306e\u5224\u5b9a\u30c6\u30fc\u30d6\u30eb (\u66ab\u5b9a\u5024\u30fb\u5c06\u6765\u306e\u8abf\u6574\u5bfe\u5fdc)\n                const getRatioText = (r) => {\n                    if (Math.sign(r - 2.90) === -1) return \"\u5e45\u306b\u5bfe\u3057\u3066\u975e\u5e38\u306b\u8584\u3044\";\n                    if (Math.sign(r - 2.95) === -1) return \"\u5e45\u306b\u5bfe\u3057\u3066\u304b\u306a\u308a\u8584\u3044\";\n                    if (Math.sign(r - 3.00) === -1) return \"\u5e45\u306b\u5bfe\u3057\u3066\u8584\u3044\";\n                    if (Math.sign(r - 3.05) === -1) return \"\u5e45\u306b\u5bfe\u3057\u3066\u5c11\u3057\u8584\u3044\";\n                    if (Math.sign(r - 3.10) === -1) return \"\u5e45\u306b\u5bfe\u3057\u3066\u8584\u3081\";\n                    if (Math.sign(r - 3.15) === -1) return \"\u5e45\u306b\u5bfe\u3057\u3066\u5c11\u3057\u539a\u307f\u304c\u3042\u308b\";\n                    if (Math.sign(r - 3.20) === -1) return \"\u5e45\u306b\u5bfe\u3057\u3066\u539a\u307f\u304c\u3042\u308b\";\n                    if (Math.sign(r - 3.30) === -1) return \"\u5e45\u306b\u5bfe\u3057\u3066\u304b\u306a\u308a\u539a\u307f\u304c\u3042\u308b\";\n                    if (Math.sign(r - 3.40) === -1) return \"\u5e45\u306b\u5bfe\u3057\u3066\u3068\u3066\u3082\u539a\u3044\";\n                    return \"\u5e45\u306b\u5bfe\u3057\u3066\u975e\u5e38\u306b\u539a\u3044\";\n                };\n\n                \/\/ --- 3. \u63cf\u753b\u30b9\u30bf\u30a4\u30eb\u304a\u3088\u3073\u5e7e\u4f55\u5b9a\u6570 (3x3 \/ 2x2 \u30d1\u30bf\u30fc\u30f3\u5b9a\u6570\u5316) ---\n                const THETA_TILT = -0.463648; \/\/ -Math.atan(0.5): \u56db\u3064\u7573\u307f\u7de8\u307f\u50be\u659c\u89d2\uff08\u7d04 -26.565\u5ea6\uff09\n                const ARROW_ANGLE = 0.523599; \/\/ Math.PI \/ 6 (30\u5ea6)\n\n                const DRAW_THEME = {\n                    colV: \"#fbcfe8\",    \/\/ \u7e26\u3072\u3082 (\u8584\u30d4\u30f3\u30af)\n                    colH: \"#bae6fd\",    \/\/ \u6a2a\u3072\u3082 (\u8584\u6c34\u8272)\n                    stroke: \"#334155\",  \/\/ \u30b3\u30de\u30fb\u30d0\u30f3\u30c9\u5916\u67a0\n                    stripes: \"rgba(51, 65, 85, 0.45)\", \/\/ 4\u672c\u7b4b\n                    arrowH: \"#ea580c\",  \/\/ \u6a2a\u5bf8\u6cd5\u77e2\u5370 (\u30aa\u30ec\u30f3\u30b8)\n                    arrowV: \"#7c3aed\",  \/\/ \u7e26\u5bf8\u6cd5\u77e2\u5370 (\u7d2b)\n                    arrowLenV: \"#ef4444\", \/\/ \u8981\u5c3a\u77e2\u5370 (\u8d64: \u7e26\u3072\u3082\u7aef)\n                    arrowLenH: \"#0284c7\"  \/\/ \u8981\u5c3a\u77e2\u5370 (\u9752: \u6a2a\u3072\u3082\u7aef)\n                };\n\n                \/\/ Canvas 1 (\u8981\u5c3a\u56f3 220x220) \u30d1\u30bf\u30fc\u30f3\u5b9a\u6570\u30c6\u30fc\u30d6\u30eb\n                const CFG_LEN = {\n                    3: { S: 28, w: 14, D: 31.305, armLen: 44, arrowHead: 7 },\n                    2: { S: 40, w: 20, D: 44.721, armLen: 50, arrowHead: 7 }\n                };\n\n                \/\/ Canvas 2 (\u5bf8\u6cd5\u56f3 360x350) \u30d1\u30bf\u30fc\u30f3\u5b9a\u6570\u30c6\u30fc\u30d6\u30eb\n                const CFG_SIZE = {\n                    3: { S: 68, w: 34, D: 76.026, armLen: 18, arrowHead: 11.5, lineWidth: 2.6 },\n                    2: { S: 94, w: 47, D: 105.095, armLen: 24, arrowHead: 11.5, lineWidth: 2.6 }\n                };\n\n                \/\/ \u30d0\u30f3\u30c9\u30d6\u30ed\u30c3\u30af (\u56db\u89d2\u5f62 + 4\u672c\u7b4b + \u4efb\u610f\u3067\u7aef\u90e8\u7701\u7565)\n                const drawBandBlock = (ctx, x, y, w, h, fillCol, isV, openEnd = false) => {\n                    ctx.fillStyle = fillCol;\n                    ctx.fillRect(x, y, w, h);\n\n                    ctx.strokeStyle = DRAW_THEME.stroke;\n                    ctx.lineWidth = 1.2;\n                    ctx.beginPath();\n                    if (!openEnd) {\n                        ctx.strokeRect(x, y, w, h);\n                    } else {\n                        \/\/ openEnd\u6642\u306f\u5916\u5074\u30d5\u30bf\u3092\u63cf\u304b\u305a\u5e73\u884c2\u672c\u7dda(=\u306e\u5f62)\u3092\u63cf\u753b\n                        if (isV) {\n                            ctx.moveTo(x, y); ctx.lineTo(x, y + h);\n                            ctx.moveTo(x + w, y); ctx.lineTo(x + w, y + h);\n                        } else {\n                            ctx.moveTo(x, y); ctx.lineTo(x + w, y);\n                            ctx.moveTo(x, y + h); ctx.lineTo(x + w, y + h);\n                        }\n                        ctx.stroke();\n                    }\n\n                    \/\/ 4\u672c\u7b4b (\u5185\u90e8\u306e3\u672c\u7dda)\n                    ctx.strokeStyle = DRAW_THEME.stripes;\n                    ctx.lineWidth = 0.9;\n                    ctx.beginPath();\n                    if (isV) {\n                        const step = w \/ 4;\n                        for (let i = 1; i !== 4; i++) {\n                            ctx.moveTo(x + step * i, y);\n                            ctx.lineTo(x + step * i, y + h);\n                        }\n                    } else {\n                        const step = h \/ 4;\n                        for (let i = 1; i !== 4; i++) {\n                            ctx.moveTo(x, y + step * i);\n                            ctx.lineTo(x + w, y + step * i);\n                        }\n                    }\n                    ctx.stroke();\n                };\n\n                \/\/ \u56db\u3064\u7573\u307f\u306e1\u30b3\u30de\u63cf\u753b (\u4e2d\u5fc3\u304c(0, 0), \u592a\u5916\u67a0, \u4e2d\u5fc3\u70b9\u30de\u30fc\u30af)\n                const drawSteppedKnot = (ctx, S) => {\n                    const w = S \/ 2;\n                    \/\/ 4\u8c61\u9650 (NW:\u7e26\u3072\u3082, NE:\u6a2a\u3072\u3082, SW:\u6a2a\u3072\u3082, SE:\u7e26\u3072\u3082)\n                    drawBandBlock(ctx, -w, -w, w, w, DRAW_THEME.colV, true, false);  \/\/ NW\n                    drawBandBlock(ctx,  0, -w, w, w, DRAW_THEME.colH, false, false); \/\/ NE\n                    drawBandBlock(ctx, -w,  0, w, w, DRAW_THEME.colH, false, false); \/\/ SW\n                    drawBandBlock(ctx,  0,  0, w, w, DRAW_THEME.colV, true, false);  \/\/ SE\n\n                    \/\/ \u30b3\u30de\u592a\u67a0 (2.0px)\n                    ctx.strokeStyle = DRAW_THEME.stroke;\n                    ctx.lineWidth = 2.0;\n                    ctx.strokeRect(-w, -w, S, S);\n\n                    \/\/ \u4e2d\u5fc3\u5c71\u30de\u30fc\u30af\n                    ctx.fillStyle = \"#0f172a\";\n                    ctx.beginPath();\n                    ctx.arc(0, 0, (Math.sign(S - 40) !== -1 ? 3.5 : 2.5), 0, Math.PI * 2);\n                    ctx.fill();\n                };\n\n                \/\/ \u4e21\u7aef\u77e2\u5370\u63cf\u753b\n                const drawDoubleArrow = (ctx, fromX, fromY, toX, toY, color, headLen = 8, lineWidth = 1.8) => {\n                    ctx.strokeStyle = color;\n                    ctx.lineWidth = lineWidth;\n                    ctx.beginPath();\n                    ctx.moveTo(fromX, fromY);\n                    ctx.lineTo(toX, toY);\n                    ctx.stroke();\n\n                    const angle = Math.atan2(toY - fromY, toX - fromX);\n                    ctx.fillStyle = color;\n\n                    \/\/ to\u5074\u77e2\u982d\n                    ctx.beginPath();\n                    ctx.moveTo(toX, toY);\n                    ctx.lineTo(toX - headLen * Math.cos(angle - ARROW_ANGLE), toY - headLen * Math.sin(angle - ARROW_ANGLE));\n                    ctx.lineTo(toX - headLen * Math.cos(angle + ARROW_ANGLE), toY - headLen * Math.sin(angle + ARROW_ANGLE));\n                    ctx.closePath();\n                    ctx.fill();\n\n                    \/\/ from\u5074\u77e2\u982d\n                    ctx.beginPath();\n                    ctx.moveTo(fromX, fromY);\n                    ctx.lineTo(fromX + headLen * Math.cos(angle - ARROW_ANGLE), fromY + headLen * Math.sin(angle - ARROW_ANGLE));\n                    ctx.lineTo(fromX + headLen * Math.cos(angle + ARROW_ANGLE), fromY + headLen * Math.sin(angle + ARROW_ANGLE));\n                    ctx.closePath();\n                    ctx.fill();\n                };\n\n                \/\/ --- 4. Canvas 1: \u3072\u3082\u6b8b\u308a\u9577\uff08\u8981\u5c3a\uff09\u30ac\u30a4\u30c9\u56f3\u63cf\u753b ---\n                const drawLenCanvas = () => {\n                    const width = canvasLen.width;\n                    const height = canvasLen.height;\n                    ctxLen.clearRect(0, 0, width, height);\n\n                    const k = getGaugeSize();\n                    const isLeft = (getWeaveDir() === 'left');\n                    const cfg = CFG_LEN[k];\n                    const w = cfg.w;\n                    const D = cfg.D;\n                    const armLen = cfg.armLen;\n\n                    ctxLen.save();\n                    ctxLen.fillStyle = \"#fafafa\";\n                    ctxLen.fillRect(0, 0, width, height);\n\n                    ctxLen.translate(width \/ 2, height \/ 2);\n                    if (isLeft) ctxLen.scale(-1, 1);\n\n                    \/\/ 1. \u306e\u3053\u308a\u3072\u3082 (\u8155) \u3068\u4e21\u7aef\u77e2\u5370\u306e\u63cf\u753b (\u7570\u306a\u308b\u8272\u30d0\u30f3\u30c9\u304b\u3089\u51fa\u308b\u6b63\u78ba\u306a\u5e7e\u4f55)\n                    for (let c = 0; c !== k; c++) {\n                        const kx = (c - (k - 1) \/ 2) * D;\n\n                        \/\/ \u7e26\u3072\u3082\u4e0a\u5074: NE(\u6c34\u8272)\u8c61\u9650 [0, w] \u304b\u3089\u4e0a\u3078\u51fa\u308b (\u30d4\u30f3\u30af\u7e26\u3072\u3082)\n                        const kyTop = (0 - (k - 1) \/ 2) * D;\n                        ctxLen.save();\n                        ctxLen.translate(kx, kyTop);\n                        ctxLen.rotate(THETA_TILT);\n                        drawBandBlock(ctxLen, 0, -w - armLen, w, armLen, DRAW_THEME.colV, true, false);\n                        drawDoubleArrow(ctxLen, w + 4, -w, w + 4, -w - armLen, DRAW_THEME.arrowLenV, cfg.arrowHead, 1.8);\n                        ctxLen.restore();\n\n                        \/\/ \u7e26\u3072\u3082\u4e0b\u5074: SW(\u6c34\u8272)\u8c61\u9650 [-w, 0] \u304b\u3089\u4e0b\u3078\u51fa\u308b (\u30d4\u30f3\u30af\u7e26\u3072\u3082)\n                        const kyBot = (k - 1 - (k - 1) \/ 2) * D;\n                        ctxLen.save();\n                        ctxLen.translate(kx, kyBot);\n                        ctxLen.rotate(THETA_TILT);\n                        drawBandBlock(ctxLen, -w, w, w, armLen, DRAW_THEME.colV, true, false);\n                        drawDoubleArrow(ctxLen, -w - 4, w, -w - 4, w + armLen, DRAW_THEME.arrowLenV, cfg.arrowHead, 1.8);\n                        ctxLen.restore();\n                    }\n\n                    for (let r = 0; r !== k; r++) {\n                        const ky = (r - (k - 1) \/ 2) * D;\n\n                        \/\/ \u6a2a\u3072\u3082\u5de6\u5074: NW(\u30d4\u30f3\u30af)\u8c61\u9650 [-w, 0] \u304b\u3089\u5de6\u3078\u51fa\u308b (\u6c34\u8272\u6a2a\u3072\u3082)\n                        const kxLeft = (0 - (k - 1) \/ 2) * D;\n                        ctxLen.save();\n                        ctxLen.translate(kxLeft, ky);\n                        ctxLen.rotate(THETA_TILT);\n                        drawBandBlock(ctxLen, -w - armLen, -w, armLen, w, DRAW_THEME.colH, false, false);\n                        drawDoubleArrow(ctxLen, -w, -w - 4, -w - armLen, -w - 4, DRAW_THEME.arrowLenH, cfg.arrowHead, 1.8);\n                        ctxLen.restore();\n\n                        \/\/ \u6a2a\u3072\u3082\u53f3\u5074: SE(\u30d4\u30f3\u30af)\u8c61\u9650 [0, w] \u304b\u3089\u53f3\u3078\u51fa\u308b (\u6c34\u8272\u6a2a\u3072\u3082)\n                        const kxRight = (k - 1 - (k - 1) \/ 2) * D;\n                        ctxLen.save();\n                        ctxLen.translate(kxRight, ky);\n                        ctxLen.rotate(THETA_TILT);\n                        drawBandBlock(ctxLen, w, 0, armLen, w, DRAW_THEME.colH, false, false);\n                        drawDoubleArrow(ctxLen, w, w + 4, w + armLen, w + 4, DRAW_THEME.arrowLenH, cfg.arrowHead, 1.8);\n                        ctxLen.restore();\n                    }\n\n                    \/\/ 2. \u968e\u6bb5\u72b6\u63a5\u5408\u306e\u30b3\u30de\u7fa4\u3092\u63cf\u753b\n                    for (let r = 0; r !== k; r++) {\n                        for (let c = 0; c !== k; c++) {\n                            const kx = (c - (k - 1) \/ 2) * D;\n                            const ky = (r - (k - 1) \/ 2) * D;\n                            ctxLen.save();\n                            ctxLen.translate(kx, ky);\n                            ctxLen.rotate(THETA_TILT);\n                            drawSteppedKnot(ctxLen, cfg.S);\n                            ctxLen.restore();\n                        }\n                    }\n\n                    ctxLen.restore();\n                };\n\n                \/\/ --- 5. Canvas 2: \u30b3\u30de\u5bf8\u6cd5\u62e1\u5927\u30ac\u30a4\u30c9\u56f3\u63cf\u753b (\u5168\u4f53\u62e1\u5927 + \uff1d\u5f62\u77ed\u8155 + \u592a\u67a0 + \u660e\u78ba\u306a\u5bf8\u6cd5\u77e2\u5370) ---\n                const drawSizeCanvas = () => {\n                    const width = canvasSize.width;\n                    const height = canvasSize.height;\n                    ctxSize.clearRect(0, 0, width, height);\n\n                    const k = getGaugeSize();\n                    const isLeft = (getWeaveDir() === 'left');\n                    const cfg = CFG_SIZE[k];\n                    const w = cfg.w;\n                    const D = cfg.D;\n                    const armLen = cfg.armLen;\n\n                    ctxSize.save();\n                    ctxSize.fillStyle = \"#fafafa\";\n                    ctxSize.fillRect(0, 0, width, height);\n\n                    const cx = width \/ 2;\n                    const cy = height \/ 2;\n\n                    \/\/ 1. \u30b3\u30de\u3068\u7701\u7565\u77ed\u8155\uff08\uff1d\u5f62\uff09\u306e\u63cf\u753b\n                    ctxSize.save();\n                    ctxSize.translate(cx, cy);\n                    if (isLeft) ctxSize.scale(-1, 1);\n\n                    \/\/ \u4e0a\u4e0b\u5de6\u53f3\u306e\u77ed\u8155 (\u5916\u5074\u30d5\u30bf\u306a\u3057\u306e\uff1d\u5f62\u3001\u3053\u306e\u5148\u7701\u7565)\n                    for (let c = 0; c !== k; c++) {\n                        const kx = (c - (k - 1) \/ 2) * D;\n                        \/\/ \u4e0a\u5074\u77ed\u8155 (NE\u8c61\u9650 [0, w] \u304b\u3089\u4e0a\u3078)\n                        const kyTop = (0 - (k - 1) \/ 2) * D;\n                        ctxSize.save();\n                        ctxSize.translate(kx, kyTop);\n                        ctxSize.rotate(THETA_TILT);\n                        drawBandBlock(ctxSize, 0, -w - armLen, w, armLen, DRAW_THEME.colV, true, true);\n                        ctxSize.restore();\n\n                        \/\/ \u4e0b\u5074\u77ed\u8155 (SW\u8c61\u9650 [-w, 0] \u304b\u3089\u4e0b\u3078)\n                        const kyBot = (k - 1 - (k - 1) \/ 2) * D;\n                        ctxSize.save();\n                        ctxSize.translate(kx, kyBot);\n                        ctxSize.rotate(THETA_TILT);\n                        drawBandBlock(ctxSize, -w, w, w, armLen, DRAW_THEME.colV, true, true);\n                        ctxSize.restore();\n                    }\n\n                    for (let r = 0; r !== k; r++) {\n                        const ky = (r - (k - 1) \/ 2) * D;\n                        \/\/ \u5de6\u5074\u77ed\u8155 (NW\u8c61\u9650 [-w, 0] \u304b\u3089\u5de6\u3078)\n                        const kxLeft = (0 - (k - 1) \/ 2) * D;\n                        ctxSize.save();\n                        ctxSize.translate(kxLeft, ky);\n                        ctxSize.rotate(THETA_TILT);\n                        drawBandBlock(ctxSize, -w - armLen, -w, armLen, w, DRAW_THEME.colH, false, true);\n                        ctxSize.restore();\n\n                        \/\/ \u53f3\u5074\u77ed\u8155 (SE\u8c61\u9650 [0, w] \u304b\u3089\u53f3\u3078)\n                        const kxRight = (k - 1 - (k - 1) \/ 2) * D;\n                        ctxSize.save();\n                        ctxSize.translate(kxRight, ky);\n                        ctxSize.rotate(THETA_TILT);\n                        drawBandBlock(ctxSize, w, 0, armLen, w, DRAW_THEME.colH, false, true);\n                        ctxSize.restore();\n                    }\n\n                    \/\/ \u968e\u6bb5\u72b6\u306b\u63a5\u5408\u3059\u308b\u30b3\u30de\u7fa4\n                    for (let r = 0; r !== k; r++) {\n                        for (let c = 0; c !== k; c++) {\n                            const kx = (c - (k - 1) \/ 2) * D;\n                            const ky = (r - (k - 1) \/ 2) * D;\n                            ctxSize.save();\n                            ctxSize.translate(kx, ky);\n                            ctxSize.rotate(THETA_TILT);\n                            drawSteppedKnot(ctxSize, cfg.S);\n                            ctxSize.restore();\n                        }\n                    }\n\n                    ctxSize.restore(); \/\/ scale\u53cd\u8ee2\u89e3\u9664\n\n                    \/\/ 2. \u753b\u9762\u5ea7\u6a19\u7cfb\u3067\u306e\u30b3\u30de\u4e2d\u5fc3\u5ea7\u6a19\u3092\u7b97\u51fa\n                    const centers = [];\n                    for (let r = 0; r !== k; r++) {\n                        centers[r] = [];\n                        for (let c = 0; c !== k; c++) {\n                            const lx = (c - (k - 1) \/ 2) * D;\n                            const ly = (r - (k - 1) \/ 2) * D;\n                            centers[r][c] = {\n                                x: isLeft ? (cx - lx) : (cx + lx),\n                                y: cy + ly\n                            };\n                        }\n                    }\n\n                    \/\/ 3. \u5bf8\u6cd5\u7dda\u306e\u63cf\u753b\u3068\u30aa\u30fc\u30d0\u30fc\u30ec\u30a4\u5165\u529b\u30dc\u30c3\u30af\u30b9\u306e\u751f\u6210\n                    let overlayHtml = '';\n\n                    if (currentSizeMode === 'H') {\n                        \/\/ \u6a2a\u65b9\u5411\u306e\u6e2c\u5b9a (\u30aa\u30ec\u30f3\u30b8\u8272\u77e2\u5370)\n                        for (let r = 0; r !== k; r++) {\n                            for (let c = 0; c !== k - 1; c++) {\n                                const pt1 = centers[r][c];\n                                const pt2 = centers[r][c + 1];\n\n                                drawDoubleArrow(ctxSize, pt1.x, pt1.y, pt2.x, pt2.y, DRAW_THEME.arrowH, cfg.arrowHead, cfg.lineWidth);\n\n                                const key = `H_${r + 1}_${c + 1}`;\n                                const valStr = sizeValuesStore[key] !== undefined ? sizeValuesStore[key] : '';\n                                overlayHtml += `\n                                    <div class=\"size-input-item\" style=\"left: ${(pt1.x + pt2.x) \/ 2}px; top: ${(pt1.y + pt2.y) \/ 2}px;\">\n                                        <input type=\"number\" step=\"0.1\" min=\"0\" class=\"size-input\" data-key=\"${key}\" value=\"${valStr}\" placeholder=\"\">\n                                    <\/div>\n                                `;\n                            }\n                        }\n                    } else {\n                        \/\/ \u7e26\u65b9\u5411\u306e\u6e2c\u5b9a (\u7d2b\u8272\u77e2\u5370)\n                        for (let c = 0; c !== k; c++) {\n                            for (let r = 0; r !== k - 1; r++) {\n                                const pt1 = centers[r][c];\n                                const pt2 = centers[r + 1][c];\n\n                                drawDoubleArrow(ctxSize, pt1.x, pt1.y, pt2.x, pt2.y, DRAW_THEME.arrowV, cfg.arrowHead, cfg.lineWidth);\n\n                                const key = `V_${c + 1}_${r + 1}`;\n                                const valStr = sizeValuesStore[key] !== undefined ? sizeValuesStore[key] : '';\n                                overlayHtml += `\n                                    <div class=\"size-input-item v-mode\" style=\"left: ${(pt1.x + pt2.x) \/ 2}px; top: ${(pt1.y + pt2.y) \/ 2}px;\">\n                                        <input type=\"number\" step=\"0.1\" min=\"0\" class=\"size-input\" data-key=\"${key}\" value=\"${valStr}\" placeholder=\"\">\n                                    <\/div>\n                                `;\n                            }\n                        }\n                    }\n\n                    \/\/ 4. \u77e2\u5370\u304c\u6307\u3059\u7d50\u3073\u76ee\u306e\u4e2d\u5fc3\u70b9\u30de\u30fc\u30af (\u5168\u30b3\u30de\u4e2d\u5fc3\u306b\u767d\u7e01\u4ed8\u304d\u4e8c\u91cd\u5186\u3092\u63cf\u753b)\n                    ctxSize.save();\n                    for (let r = 0; r !== k; r++) {\n                        for (let c = 0; c !== k; c++) {\n                            const pt = centers[r][c];\n                            ctxSize.fillStyle = \"#ffffff\";\n                            ctxSize.beginPath();\n                            ctxSize.arc(pt.x, pt.y, 4.5, 0, Math.PI * 2);\n                            ctxSize.fill();\n\n                            ctxSize.fillStyle = \"#0f172a\";\n                            ctxSize.beginPath();\n                            ctxSize.arc(pt.x, pt.y, 3.2, 0, Math.PI * 2);\n                            ctxSize.fill();\n                        }\n                    }\n                    ctxSize.restore();\n\n                    \/\/ \u30aa\u30fc\u30d0\u30fc\u30ec\u30a4HTML\u3092\u633f\u5165\n                    sizeOverlay.innerHTML = overlayHtml;\n\n                    \/\/ \u5bf8\u6cd5\u5165\u529b\u30a4\u30d9\u30f3\u30c8\u3092\u8a2d\u5b9a\n                    els('.size-input').forEach(inp => {\n                        inp.addEventListener('input', (e) => {\n                            const key = e.target.getAttribute('data-key');\n                            const v = parseFloat(e.target.value);\n                            if (!isNaN(v) ? (Math.sign(v) === 1) : false) {\n                                sizeValuesStore[key] = v;\n                            } else {\n                                delete sizeValuesStore[key];\n                            }\n                            calculateAll();\n                        });\n                    });\n                };\n\n                \/\/ --- 6. \u30a4\u30d9\u30f3\u30c8\u30ea\u30b9\u30ca\u30fc ---\n                els('input[name=\"gauge_size\"]').forEach(r => {\n                    r.addEventListener('change', () => {\n                        \/\/ \u30b5\u30a4\u30ba\u5909\u66f4\u6642\u306f\u30ad\u30e3\u30c3\u30b7\u30e5\u30af\u30ea\u30a2\n                        for (let k in sizeValuesStore) delete sizeValuesStore[k];\n                        buildUI();\n                    });\n                });\n\n                els('input[name=\"weave_dir\"]').forEach(r => {\n                    r.addEventListener('change', buildUI);\n                });\n\n                cordLengthInput.addEventListener('input', calculateAll);\n\n                tabSizeH.addEventListener('click', () => {\n                    currentSizeMode = 'H';\n                    tabSizeH.classList.add('active');\n                    tabSizeV.classList.remove('active');\n                    drawSizeCanvas();\n                });\n\n                tabSizeV.addEventListener('click', () => {\n                    currentSizeMode = 'V';\n                    tabSizeV.classList.add('active');\n                    tabSizeH.classList.remove('active');\n                    drawSizeCanvas();\n                });\n\n                \/\/ \u5916\u90e8\u30c4\u30fc\u30eb\u8d77\u52d5\u30dc\u30bf\u30f3\n                btnLaunchKnot.addEventListener('click', () => {\n                    if (!lastCalculatedResult) return;\n                    if (!lastCalculatedResult.statSize.mean) return;\n                    if (!lastCalculatedResult.statLen.mean) return;\n                    const size = lastCalculatedResult.statSize.mean.toFixed(1);\n                    const len = lastCalculatedResult.statLen.mean.toFixed(1);\n                    const url = `${KNOT_CALC_URL}?cb_model=knot&cb_knot_size=${size}&cb_knot_len=${len}`;\n                    window.open(url, '_blank');\n                });\n\n                btnLaunchKnot45.addEventListener('click', () => {\n                    if (!lastCalculatedResult) return;\n                    if (!lastCalculatedResult.statSize.mean) return;\n                    if (!lastCalculatedResult.statLen.mean) return;\n                    const size = lastCalculatedResult.statSize.mean.toFixed(1);\n                    const len = lastCalculatedResult.statLen.mean.toFixed(1);\n                    const url = `${KNOT45_CALC_URL}?cb_model=knot45&cb_knot_size=${size}&cb_knot_len=${len}`;\n                    window.open(url, '_blank');\n                });\n\n                \/\/ PDF \u4fdd\u5b58\n                \/\/ --- 7. Google Form \u30b7\u30a7\u30a2 & \u7d50\u679c\u95b2\u89a7 ---\n                btnShareGoogleForm.addEventListener('click', () => {\n                    if (!lastCalculatedResult) return;\n\n                    const cfg = GOOGLE_FORM_CONFIG;\n                    if (!cfg.actionUrl ? true : (cfg.actionUrl.trim() === '')) {\n                        alert(\"\u3010\u56db\u3064\u7573\u307f\u7de8\u307f\u30b2\u30fc\u30b8\u6e2c\u5b9a\u7d50\u679c\u30b7\u30a7\u30a2\u30d5\u30a9\u30fc\u30e0\u3011\\nGoogle \u30d5\u30a9\u30fc\u30e0\u306e URL \u304c\u8a2d\u5b9a\u3055\u308c\u3066\u3044\u307e\u305b\u3093\u3002\");\n                        return;\n                    }\n\n                    const r = lastCalculatedResult;\n                    const params = new URLSearchParams();\n                    params.set(\"usp\", \"pp_url\");\n\n                    \/\/ \u4efb\u610f\u5165\u529b\u9805\u76ee\n                    if (shareBrand.value.trim() !== '') params.set(cfg.entries.maker, shareBrand.value.trim());\n                    if (shareTotalStrap.value.trim() !== '') params.set(cfg.entries.totalStrips, shareTotalStrap.value.trim());\n                    if (shareBandWidth.value.trim() !== '') params.set(cfg.entries.bandWidth, shareBandWidth.value.trim());\n                    if (shareUsedStrap.value.trim() !== '') params.set(cfg.entries.usedStrips, shareUsedStrap.value.trim());\n                    if (shareMemo.value.trim() !== '') params.set(cfg.entries.memo, shareMemo.value.trim());\n\n                    \/\/ \u6e2c\u5b9a\u30fb\u8a08\u7b97\u7d50\u679c\n                    if (r.statSize ? r.statSize.mean : false) {\n                        params.set(cfg.entries.knotSize, r.statSize.mean.toFixed(2));\n                    }\n                    if (r.statLen ? r.statLen.mean : false) {\n                        params.set(cfg.entries.knotLen, r.statLen.mean.toFixed(2));\n                    }\n                    if (r.statLen ? ((r.statLen.cvPct !== null) ? !isNaN(r.statLen.cvPct) : false) : false) {\n                        params.set(cfg.entries.cv, r.statLen.cvPct.toFixed(1));\n                    }\n\n                    \/\/ \u4e8b\u524d\u5165\u529bURL\u3092\u751f\u6210 (formResponse \u3092 viewform \u306b\u5909\u63db\u3057\u3066\u958b\u304f)\n                    const viewUrl = cfg.actionUrl.replace('\/formResponse', '\/viewform');\n                    const targetUrl = viewUrl + (viewUrl.includes('?') ? '&' : '?') + params.toString();\n                    window.open(targetUrl, '_blank');\n                });\n\n                btnViewSharedResults.addEventListener('click', () => {\n                    const cfg = GOOGLE_FORM_CONFIG;\n                    if (!cfg.resultsUrl ? true : (cfg.resultsUrl.trim() === '')) {\n                        alert(\"\u3010\u56db\u3064\u7573\u307f\u7de8\u307f\u30b2\u30fc\u30b8\u6e2c\u5b9a\u7d50\u679c\u30b7\u30a7\u30a2\u30d5\u30a9\u30fc\u30e0\u3011\\n\u73fe\u5728\u3001\u96c6\u8a08\u7d50\u679c\u30da\u30fc\u30b8\u306e URL \u3092\u6e96\u5099\u4e2d\u3067\u3059\u3002\\n\\n(\u8a2d\u5b9a\u7b87\u6240: JavaScript \u5185\u306e GOOGLE_FORM_CONFIG.resultsUrl)\");\n                        return;\n                    }\n                    window.open(cfg.resultsUrl, '_blank');\n                });\n\n                \/\/ --- 8. PDF\u51fa\u529b\u51e6\u7406 (\u8efd\u91cf\u30fb\u9ad8\u7cbe\u7d30Canvas\u751f\u6210 + \u65e5\u672c\u8a9e\u5b8c\u5168\u5bfe\u5fdc + \u5168\u5143\u30c7\u30fc\u30bf\u53ce\u9332 + \u30d5\u30c3\u30bf\u30fc\u65e5\u6642\/URL) ---\n                const ensureJsPdf = async () => {\n                    if (window.jspdf ? window.jspdf.jsPDF : false) return window.jspdf.jsPDF;\n                    return new Promise((resolve, reject) => {\n                        const script = document.createElement('script');\n                        script.src = \"https:\/\/cdnjs.cloudflare.com\/ajax\/libs\/jspdf\/2.5.1\/jspdf.umd.min.js\";\n                        script.onload = () => {\n                            if (window.jspdf ? window.jspdf.jsPDF : false) resolve(window.jspdf.jsPDF);\n                            else reject(new Error(\"jsPDF\u306e\u8aad\u307f\u8fbc\u307f\u306b\u5931\u6557\u3057\u307e\u3057\u305f\"));\n                        };\n                        script.onerror = () => reject(new Error(\"jsPDF\u30e9\u30a4\u30d6\u30e9\u30ea\u306e\u901a\u4fe1\u30a8\u30e9\u30fc\"));\n                        document.head.appendChild(script);\n                    });\n                };\n\n                btnExportPdf.addEventListener('click', async () => {\n                    if (!lastCalculatedResult) return;\n                    try {\n                        const jsPDFClass = await ensureJsPdf();\n                        const r = lastCalculatedResult;\n                        const k = r.k;\n                        const now = new Date();\n                        const dateStr = now.getFullYear() + \"\/\" +\n                            String(now.getMonth() + 1).padStart(2, '0') + \"\/\" +\n                            String(now.getDate()).padStart(2, '0') + \" \" +\n                            String(now.getHours()).padStart(2, '0') + \":\" +\n                            String(now.getMinutes()).padStart(2, '0') + \":\" +\n                            String(now.getSeconds()).padStart(2, '0');\n\n                        \/\/ A4 \u7e26\u6bd4\u7387 (210 x 297mm) \u306e\u30aa\u30d5\u30b9\u30af\u30ea\u30fc\u30f3 Canvas (900 x 1273 px, \u7d04110dpi \u3067\u9bae\u660e\u304b\u3064\u8efd\u91cf)\n                        const pdfCanvas = document.createElement('canvas');\n                        pdfCanvas.width = 900;\n                        pdfCanvas.height = 1273;\n                        const pctx = pdfCanvas.getContext('2d');\n\n                        \/\/ \u80cc\u666f\u8272 (\u767d)\n                        pctx.fillStyle = \"#ffffff\";\n                        pctx.fillRect(0, 0, pdfCanvas.width, pdfCanvas.height);\n\n                        let curY = 55;\n                        const leftX = 50;\n                        const contentWidth = 800;\n\n                        \/\/ 1. \u30bf\u30a4\u30c8\u30eb\n                        pctx.fillStyle = \"#722d19\";\n                        pctx.font = \"bold 24px sans-serif\";\n                        pctx.fillText(\"\u56db\u3064\u7573\u307f\u7de8\u307f\u30b2\u30fc\u30b8\u6e2c\u5b9a\u7d50\u679c\u30ec\u30dd\u30fc\u30c8\", leftX, curY);\n                        curY += 36;\n\n                        \/\/ \u533a\u5207\u308a\u7dda\n                        pctx.strokeStyle = \"#e05d22\";\n                        pctx.lineWidth = 3;\n                        pctx.beginPath();\n                        pctx.moveTo(leftX, curY);\n                        pctx.lineTo(leftX + contentWidth, curY);\n                        pctx.stroke();\n                        curY += 35;\n\n                        \/\/ \u30bb\u30af\u30b7\u30e7\u30f3\u898b\u51fa\u3057\u63cf\u753b\u30d8\u30eb\u30d1\u30fc\n                        const drawSecHeader = (title) => {\n                            pctx.fillStyle = \"#f8fafc\";\n                            pctx.fillRect(leftX, curY - 18, contentWidth, 28);\n                            pctx.fillStyle = \"#1e293b\";\n                            pctx.font = \"bold 15px sans-serif\";\n                            pctx.fillText(title, leftX + 10, curY + 2);\n                            pctx.strokeStyle = \"#cbd5e1\";\n                            pctx.lineWidth = 1;\n                            pctx.strokeRect(leftX, curY - 18, contentWidth, 28);\n                            curY += 26;\n                        };\n\n                        \/\/ 2. \u57fa\u672c\u4ed5\u69d8 & \u4f5c\u54c1\u30fb\u6750\u6599\u60c5\u5831\n                        drawSecHeader(\"1. \u57fa\u672c\u4ed5\u69d8 \uff06 \u6750\u6599\u60c5\u5831\");\n\n                        pctx.fillStyle = \"#334155\";\n                        pctx.font = \"14px sans-serif\";\n\n                        const weaveDirText = (getWeaveDir() === 'left') ? \"\u5de6\u5074 (\u5de6\u7dbe)\" : \"\u53f3\u5074 (\u53f3\u7dbe)\";\n                        const brandVal = shareBrand.value.trim() !== '' ? shareBrand.value.trim() : \"--\";\n                        const totalStrapVal = shareTotalStrap.value.trim() !== '' ? shareTotalStrap.value.trim() : \"--\";\n                        const bandWidthVal = shareBandWidth.value.trim() ? `${shareBandWidth.value.trim()} mm` : \"--\";\n                        const usedStrapVal = shareUsedStrap.value.trim() !== '' ? shareUsedStrap.value.trim() : \"--\";\n                        const memoVal = shareMemo.value.trim() !== '' ? shareMemo.value.trim() : \"--\";\n\n                        const rowH = 26;\n                        \/\/ 2\u5217\u30ec\u30a4\u30a2\u30a6\u30c8\n                        pctx.fillText(`\u30fb\u30b2\u30fc\u30b8\u30b5\u30a4\u30ba: ${k} \u00d7 ${k} (${k * k}\u30b3\u30de)`, leftX + 15, curY);\n                        pctx.fillText(`\u30fb\u30e1\u30fc\u30ab\u30fc\u30fb\u88fd\u54c1\u540d: ${brandVal}`, leftX + 410, curY);\n                        curY += rowH;\n\n                        pctx.fillText(`\u30fb\u7de8\u307f\u76ee\u306e\u5411\u304d: ${weaveDirText}`, leftX + 15, curY);\n                        pctx.fillText(`\u30fb\u5168\u5e45\u6570: ${totalStrapVal}`, leftX + 410, curY);\n                        curY += rowH;\n\n                        pctx.fillText(`\u30fb\u4f7f\u7528\u3072\u3082\u9577: ${r.totalCordCm.toFixed(1)} cm (${(r.totalCordCm * 10).toFixed(0)} mm)`, leftX + 15, curY);\n                        pctx.fillText(`\u30fb\u30d0\u30f3\u30c9\u5e45: ${bandWidthVal}`, leftX + 410, curY);\n                        curY += rowH;\n\n                        pctx.fillText(`\u30fb\u4f7f\u7528\u3057\u305f\u672c\u5e45\u6570: ${usedStrapVal}`, leftX + 410, curY);\n                        curY += rowH;\n\n                        pctx.fillText(`\u30fb\u7de8\u307f\u5fc3\u5730\u30fb\u3072\u3068\u3053\u3068\u30e1\u30e2: ${memoVal}`, leftX + 15, curY);\n                        curY += 45;\n\n                        \/\/ 3. \u6e2c\u5b9a\u7d50\u679c\u30fb\u5206\u6790\u30b5\u30de\u30ea\u30fc\n                        drawSecHeader(\"2. \u6e2c\u5b9a\u7d50\u679c\u30fb\u5206\u6790\u30b5\u30de\u30ea\u30fc\");\n\n                        pctx.font = \"15px sans-serif\";\n\n                        \/\/ \u30b3\u30de\u8981\u5c3a\u30b5\u30de\u30ea\u30fc\n                        const lenMeanStr = r.statLen.mean ? `${r.statLen.mean.toFixed(2)} mm` : \"-- mm\";\n                        const lenSpreadStr = r.statLen.spreadPct !== null ? `${r.statLen.spreadPct.toFixed(1)}% (${getSpreadText(r.statLen.spreadPct)})` : \"--\";\n                        const lenCvStr = r.statLen.cvPct !== null ? `CV ${r.statLen.cvPct.toFixed(1)}% (${getCvText(r.statLen.cvPct)})` : \"\u203b4\u70b9\u4ee5\u4e0a\u3067\u8868\u793a\";\n\n                        pctx.fillStyle = \"#b45309\";\n                        pctx.font = \"bold 15px sans-serif\";\n                        pctx.fillText(`\u25a0 \u30b3\u30de\u8981\u5c3a (1\u30b3\u30de\u3042\u305f\u308a\u306e\u3072\u3082\u6d88\u8cbb\u91cf): ${lenMeanStr}`, leftX + 15, curY);\n                        curY += 24;\n                        pctx.fillStyle = \"#475569\";\n                        pctx.font = \"14px sans-serif\";\n                        pctx.fillText(`   \u6709\u52b9\u6e2c\u5b9a\u6570: ${r.statLen.n}\u672c \/ \u6700\u5927\u30d6\u30ec\u5e45: ${lenSpreadStr} \/ \u5b89\u5b9a\u5ea6: ${lenCvStr}`, leftX + 15, curY);\n                        curY += 34;\n\n                        \/\/ \u30b3\u30de\u5bf8\u6cd5\u30b5\u30de\u30ea\u30fc\n                        const sizeMeanStr = r.statSize.mean ? `${r.statSize.mean.toFixed(2)} mm` : \"-- mm\";\n                        const sizeSpreadStr = r.statSize.spreadPct !== null ? `${r.statSize.spreadPct.toFixed(1)}% (${getSpreadText(r.statSize.spreadPct)})` : \"--\";\n                        const sizeCvStr = r.statSize.cvPct !== null ? `CV ${r.statSize.cvPct.toFixed(1)}% (${getCvText(r.statSize.cvPct)})` : \"\u203b4\u70b9\u4ee5\u4e0a\u3067\u8868\u793a\";\n\n                        pctx.fillStyle = \"#1e40af\";\n                        pctx.font = \"bold 15px sans-serif\";\n                        pctx.fillText(`\u25a0 \u30b3\u30de\u5bf8\u6cd5 (\u7d50\u3073\u76ee\u306e\u4e2d\u5fc3\u9593\u51fa\u6765\u4e0a\u304c\u308a\u5bf8\u6cd5): ${sizeMeanStr}`, leftX + 15, curY);\n                        curY += 24;\n                        pctx.fillStyle = \"#475569\";\n                        pctx.font = \"14px sans-serif\";\n                        pctx.fillText(`   \u6709\u52b9\u6e2c\u5b9a\u6570: ${r.statSize.n}\u70b9 \/ \u6700\u5927\u30d6\u30ec\u5e45: ${sizeSpreadStr} \/ \u5b89\u5b9a\u5ea6: ${sizeCvStr}`, leftX + 15, curY);\n                        curY += 34;\n\n                        \/\/ \u6bd4\u7387\u30b5\u30de\u30ea\u30fc\n                        if (r.ratio) {\n                            pctx.fillStyle = \"#7c2d12\";\n                            pctx.font = \"bold 15px sans-serif\";\n                            const ratioJudg = getRatioText(r.ratio);\n                            pctx.fillText(`\u25a0 \u8981\u5c3a\uff0f\u5bf8\u6cd5 \u6bd4\u7387: ${r.ratio.toFixed(2)} \u500d (\u5224\u5b9a: ${ratioJudg})`, leftX + 15, curY);\n                            curY += 24;\n                            pctx.fillStyle = \"#64748b\";\n                            pctx.font = \"12px sans-serif\";\n                            pctx.fillText(\"   \u203b \u7406\u8ad6\u5024 \u7d042.88\u500d (6.43 \/ 2.236)\u3002\u5bf8\u6cd5\u306b\u5bfe\u3057\u3066\u4f55\u500d\u306e\u3072\u3082\u3092\u6d88\u8cbb\u3057\u3066\u3044\u308b\u304b\u306e\u6307\u6a19\", leftX + 15, curY);\n                            curY += 35;\n                        }\n\n                        \/\/ 4. \u5143\u3068\u306a\u308b\u5b9f\u6e2c\u30c7\u30fc\u30bf\u4e00\u89a7\n                        drawSecHeader(\"3. \u5b9f\u6e2c\u30c7\u30fc\u30bf\u4e00\u89a7 (\u3059\u3079\u3066\u306e\u6e2c\u5b9a\u5024)\");\n\n                        \/\/ (A) \u30b3\u30de\u8981\u5c3a\u306e\u5b9f\u6e2c\u5024\u8868\n                        pctx.fillStyle = \"#334155\";\n                        pctx.font = \"bold 14px sans-serif\";\n                        pctx.fillText(\"\u3010\u3072\u3082\u6b8b\u308a\u9577\u30fb\u7b97\u51fa\u8981\u5c3a (mm)\u3011\", leftX + 15, curY);\n                        curY += 20;\n\n                        \/\/ \u8868\u30d8\u30c3\u30c0\u30fc\n                        const colX = [leftX + 15, leftX + 110, leftX + 240, leftX + 380, leftX + 530];\n                        pctx.fillStyle = \"#e2e8f0\";\n                        pctx.fillRect(leftX + 10, curY - 16, 650, 20);\n                        pctx.fillStyle = \"#334155\";\n                        pctx.font = \"bold 12px sans-serif\";\n                        pctx.fillText(\"\u3072\u3082\u540d\", colX[0], curY);\n                        pctx.fillText(\"\u7aef1\u6b8b\u308a\u9577\", colX[1], curY);\n                        pctx.fillText(\"\u7aef2\u6b8b\u308a\u9577\", colX[2], curY);\n                        pctx.fillText(\"\u6d88\u8cbb\u3072\u3082\u9577\", colX[3], curY);\n                        pctx.fillText(\"1\u30b3\u30de\u8981\u5c3a\", colX[4], curY);\n                        curY += 22;\n\n                        pctx.font = \"12px sans-serif\";\n                        const cordNames = [];\n                        for (let i = 1; i !== k + 1; i++) cordNames.push(`V${i}`);\n                        for (let i = 1; i !== k + 1; i++) cordNames.push(`H${i}`);\n\n                        const totalCordMm = r.totalCordCm * 10;\n                        cordNames.forEach((name, idx) => {\n                            const inp1 = el(`.len-input[data-cord=\"${name}\"][data-end=\"1\"]`);\n                            const inp2 = el(`.len-input[data-cord=\"${name}\"][data-end=\"2\"]`);\n                            const v1Str = (inp1 ? inp1.value.trim() : '') ? `${inp1.value.trim()} mm` : \"--\";\n                            const v2Str = (inp2 ? inp2.value.trim() : '') ? `${inp2.value.trim()} mm` : \"--\";\n\n                            const v1 = inp1 ? parseFloat(inp1.value) : NaN;\n                            const v2 = inp2 ? parseFloat(inp2.value) : NaN;\n\n                            let usedStr = \"--\";\n                            let komaStr = \"--\";\n                            const pdfV1Ok = (!isNaN(v1) ? (Math.sign(v1) === 1) : false);\n                            const pdfV2Ok = (!isNaN(v2) ? (Math.sign(v2) === 1) : false);\n                            const pdfDiffOk = Math.sign(totalCordMm - (v1 + v2)) === 1;\n                            if ((pdfV1Ok ? pdfV2Ok : false) ? pdfDiffOk : false) {\n                                const used = totalCordMm - v1 - v2;\n                                usedStr = `${used.toFixed(1)} mm`;\n                                komaStr = `${(used \/ k).toFixed(1)} mm`;\n                            }\n\n                            if (idx % 2 === 1) {\n                                pctx.fillStyle = \"#f8fafc\";\n                                pctx.fillRect(leftX + 10, curY - 15, 650, 18);\n                            }\n                            pctx.fillStyle = \"#334155\";\n                            pctx.fillText(name, colX[0], curY);\n                            pctx.fillText(v1Str, colX[1], curY);\n                            pctx.fillText(v2Str, colX[2], curY);\n                            pctx.fillText(usedStr, colX[3], curY);\n                            pctx.fillText(komaStr, colX[4], curY);\n                            curY += 20;\n                        });\n\n                        curY += 15;\n\n                        \/\/ (B) \u30b3\u30de\u5bf8\u6cd5\u306e\u6e2c\u5b9a\u5024\u4e00\u89a7\n                        pctx.fillStyle = \"#334155\";\n                        pctx.font = \"bold 14px sans-serif\";\n                        pctx.fillText(\"\u3010\u30b3\u30de\u5bf8\u6cd5 (\u4e2d\u5fc3\u9593) \u5b9f\u6e2c\u5024 (mm)\u3011\", leftX + 15, curY);\n                        curY += 22;\n\n                        pctx.font = \"12px sans-serif\";\n                        let hValsStr = [];\n                        for (let row = 1; row !== k + 1; row++) {\n                            for (let col = 1; col !== k; col++) {\n                                const val = sizeValuesStore[`H_${row}_${col}`];\n                                const valText = ((typeof val === 'number') ? !isNaN(val) : false) ? `${val.toFixed(1)}` : \"--\";\n                                hValsStr.push(`H${row}_${col}: ${valText}mm`);\n                            }\n                        }\n                        pctx.fillText(\"\u30fb\u6a2a\u65b9\u5411: \" + hValsStr.join(\"  |  \"), leftX + 25, curY);\n                        curY += 20;\n\n                        let vValsStr = [];\n                        for (let col = 1; col !== k + 1; col++) {\n                            for (let row = 1; row !== k; row++) {\n                                const val = sizeValuesStore[`V_${col}_${row}`];\n                                const valText = ((typeof val === 'number') ? !isNaN(val) : false) ? `${val.toFixed(1)}` : \"--\";\n                                vValsStr.push(`V${col}_${row}: ${valText}mm`);\n                            }\n                        }\n                        pctx.fillText(\"\u30fb\u7e26\u65b9\u5411: \" + vValsStr.join(\"  |  \"), leftX + 25, curY);\n\n                        \/\/ 5. \u30d5\u30c3\u30bf\u30fc (\u65e5\u6642\u304a\u3088\u3073URL\u3092\u30d5\u30c3\u30bf\u30fc\u306b\u914d\u7f6e)\n                        const footerY = 1215;\n                        pctx.strokeStyle = \"#cbd5e1\";\n                        pctx.lineWidth = 1;\n                        pctx.beginPath();\n                        pctx.moveTo(leftX, footerY);\n                        pctx.lineTo(leftX + contentWidth, footerY);\n                        pctx.stroke();\n\n                        pctx.fillStyle = \"#64748b\";\n                        pctx.font = \"12px sans-serif\";\n                        pctx.fillText(`\u6e2c\u5b9a\u30fb\u51fa\u529b\u65e5\u6642: ${dateStr}`, leftX, footerY + 25);\n                        pctx.fillText(\"\u56db\u3064\u7573\u307f\u30b2\u30fc\u30b8\u6e2c\u5b9a\u30c4\u30fc\u30eb (gauge-calc)\", leftX, footerY + 45);\n\n                        pctx.textAlign = \"right\";\n                        pctx.fillText(`URL: https:\/\/labo.com\/CraftBand\/sharing\/gauge-calc\/`, leftX + contentWidth, footerY + 25);\n                        pctx.textAlign = \"left\"; \/\/ \u623b\u3059\n\n                        \/\/ jsPDF \u306b Canvas \u753b\u50cf\u3092\u8ffd\u52a0\u3057\u3066 A4 \u4fdd\u5b58 (JPEG 0.92 \u3067\u8efd\u91cf\u9ad8\u7cbe\u7d30\u5316)\n                        const doc = new jsPDFClass({ orientation: 'portrait', unit: 'mm', format: 'a4' });\n                        const imgData = pdfCanvas.toDataURL(\"image\/jpeg\", 0.92);\n                        doc.addImage(imgData, 'JPEG', 0, 0, 210, 297);\n\n                        doc.save(`knot-gauge-report-${now.toISOString().slice(0, 10)}.pdf`);\n                    } catch (e) {\n                        alert(\"PDF\u751f\u6210\u306b\u5931\u6557\u3057\u307e\u3057\u305f: \" + e.message);\n                    }\n                });\n\n                \/\/ --- \u521d\u671f\u5b9f\u884c ---\n                buildUI();\n            })(); \/\/ \u5373\u6642\u5b9f\u884c\u95a2\u6570\u7d42\u4e86\n        \n\/\/]]>\n<\/script>\n    <\/div>\n\n\n\n\n\n\n<p class=\"has-text-align-right wp-block-paragraph\">2026\/11\/9 ver.1<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n","protected":false},"excerpt":{"rendered":"<p>\u540c\u3058\u9577\u3055\u306e\u3072\u3082\u30926\u672c(\u3082\u3057\u304f\u306f4\u672c)\u7528\u610f\u3057\u3066\u3001\u56db\u3064\u7573\u307f\u7de8\u307f\u306e\u30b3\u30de\u3092\u683c\u5b50\u72b6\u306b\u7de8\u3093\u3067\u304f\u3060\u3055\u3044\u3002\u683c\u5b50\u72b6\u306b\u7de8\u3080\u3053\u3068\u3067\u3001\u30a8\u30c3\u30b8\u52b9\u679c\u3092\u6291\u3048\u3001\u672c\u756a\u306b\u8fd1\u3044\u5f15\u304d\u7de0\u307e\u308a\u72b6\u614b\u306e\u6570\u5024\u3092\u5272\u308a\u51fa\u305b\u307e\u3059\u3002\u5e73\u5747\u5316\u306b\u3088\u308a\u8aad\u307f\u53d6\u308a\u8aa4\u5dee\u3082\u5c0f\u3055\u304f\u306a\u308a\u307e\u3059\u3002 \u6e2c &hellip; <a href=\"https:\/\/labo.com\/CraftBand\/sharing\/gauge-calc\/\" class=\"more-link\">\u7d9a\u304d\u3092\u8aad\u3080 <span class=\"screen-reader-text\">\u56db\u3064\u7573\u307f\u7de8\u307f\u30b2\u30fc\u30b8\u8a08\u7b97\u30c4\u30fc\u30eb<\/span> <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":2,"featured_media":0,"parent":688,"menu_order":150,"comment_status":"closed","ping_status":"closed","template":"","meta":{"_jetpack_hide_featured_image":false,"_jetpack_featured_image_duplicate_dismissed":0,"footnotes":""},"class_list":["post-14113","page","type-page","status-publish","hentry"],"jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/labo.com\/CraftBand\/wp-json\/wp\/v2\/pages\/14113","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=14113"}],"version-history":[{"count":29,"href":"https:\/\/labo.com\/CraftBand\/wp-json\/wp\/v2\/pages\/14113\/revisions"}],"predecessor-version":[{"id":14148,"href":"https:\/\/labo.com\/CraftBand\/wp-json\/wp\/v2\/pages\/14113\/revisions\/14148"}],"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=14113"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}