{"id":25071,"date":"2026-11-06T06:07:27","date_gmt":"2026-11-06T06:07:27","guid":{"rendered":"https:\/\/www.mechstream.com\/?p=25071"},"modified":"2026-11-06T06:07:30","modified_gmt":"2026-11-06T06:07:30","slug":"punch-tool-life-estimator-calculator","status":"publish","type":"post","link":"https:\/\/www.mechstream.com\/fr\/punch-tool-life-estimator-calculator\/","title":{"rendered":"Punch Tool Life Estimator Calculator"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">The <strong>Punch Tool Life Estimator Calculator<\/strong> provides an approximate estimate of punch tool life based on material properties, sheet thickness, punch grade, coating, lubrication, and operating conditions. Use it to support maintenance planning and tool replacement decisions. Actual service life can vary with die clearance, alignment, tool geometry, press condition, and sharpening practices, so monitor tool wear and follow the manufacturer\u2019s guidance.<\/p>\n\n\n\n<iframe class=\"ptl-frame skip-lazy no-lazyload\" data-no-lazy=\"1\" data-skip-lazy=\"1\" title=\"Punch Tool Life Estimator Calculator\" scrolling=\"no\" style=\"display:block !important;width:100% !important;max-width:1000px !important;height:1500px;border:0 !important;margin:0 auto !important;padding:0 !important;overflow:hidden;background:transparent;float:none !important\" srcdoc=\"&lt;!DOCTYPE html&gt;&#10;&lt;html lang=&quot;en&quot;&gt;&#10;&lt;head&gt;&#10;&lt;meta charset=&quot;UTF-8&quot;&gt;&#10;&lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1&quot;&gt;&#10;&lt;title&gt;Punch Tool Life Estimator Calculator&lt;\/title&gt;&#10;&lt;style&gt;&#10;\/* =====================================================================&#10;   Punch Tool Life Estimator \u2014 all selectors scoped under .ptl-root&#10;   ===================================================================== *\/&#10;.ptl-root{&#10;  --ptl-blue:#1e3a8a;--ptl-blue-2:#1d4ed8;--ptl-blue-soft:#e8eefb;--ptl-blue-line:#c7d4f0;&#10;  --ptl-bg:#f3f5f8;--ptl-card:#ffffff;--ptl-text:#1f2937;--ptl-heading:#111827;--ptl-muted:#5b6574;&#10;  --ptl-border:#d6dce5;--ptl-field:#fbfcfe;--ptl-danger:#b42318;--ptl-danger-bg:#fef3f2;&#10;  --ptl-warn:#8a5a00;--ptl-warn-bg:#fff8e6;--ptl-warn-line:#f2d48a;--ptl-good:#067647;--ptl-bad:#b42318;&#10;  --ptl-radius:12px;--ptl-shadow:0 1px 2px rgba(16,24,40,.06),0 6px 16px rgba(16,24,40,.06);&#10;  font-family:system-ui,-apple-system,&quot;Segoe UI&quot;,Roboto,&quot;Helvetica Neue&quot;,Arial,&quot;Noto Sans&quot;,sans-serif;&#10;  font-size:16px;line-height:1.55;color:var(--ptl-text);background:var(--ptl-bg);&#10;  max-width:1000px;margin:0 auto;padding:28px 16px 36px;text-align:left;border-radius:16px;&#10;  -webkit-text-size-adjust:100%;&#10;}&#10;.ptl-root *,.ptl-root *::before,.ptl-root *::after{box-sizing:border-box}&#10;.ptl-root [hidden]{display:none !important}&#10;.ptl-root h2,.ptl-root h3{font-family:inherit;color:var(--ptl-heading);line-height:1.25;margin:0 0 .5em;padding:0;letter-spacing:normal;text-transform:none;font-weight:700;border:0;background:none}&#10;.ptl-root h2{font-size:clamp(1.2rem,2.2vw,1.45rem)}&#10;.ptl-root h3{font-size:.8rem;text-transform:uppercase;letter-spacing:.06em;color:var(--ptl-blue);margin:22px 0 10px}&#10;.ptl-root p{margin:0 0 .85em;padding:0}&#10;.ptl-root ul,.ptl-root ol{margin:0;padding-left:1.25em}&#10;.ptl-root li{margin:0 0 .3em}&#10;&#10;\/* ---------- layout ---------- *\/&#10;.ptl-root .ptl-stack{display:grid;grid-template-columns:minmax(0,1fr);gap:22px}&#10;.ptl-root .ptl-card{background:var(--ptl-card);border:1px solid var(--ptl-border);border-radius:var(--ptl-radius);box-shadow:var(--ptl-shadow);padding:22px}&#10;.ptl-root .ptl-group{border:1px solid var(--ptl-border);border-radius:10px;padding:16px 16px 4px;margin:0 0 16px;min-width:0}&#10;.ptl-root .ptl-group legend{padding:0 6px;font-size:.8rem;font-weight:700;text-transform:uppercase;letter-spacing:.06em;color:var(--ptl-blue)}&#10;.ptl-root .ptl-opt{font-weight:500;text-transform:none;letter-spacing:normal;color:var(--ptl-muted)}&#10;.ptl-root .ptl-row{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:0 14px}&#10;.ptl-root .ptl-row3{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:0 14px}&#10;&#10;\/* ---------- fields ---------- *\/&#10;.ptl-root .ptl-field{margin:0 0 14px;min-width:0}&#10;.ptl-root .ptl-field &gt; label,.ptl-root .ptl-lbl{display:block;font-size:.86rem;font-weight:600;color:var(--ptl-text);margin:0 0 5px;line-height:1.3}&#10;.ptl-root .ptl-req{color:var(--ptl-danger);font-weight:700}&#10;.ptl-root .ptl-input,.ptl-root .ptl-select{&#10;  display:block;width:100%;height:42px;margin:0;padding:8px 12px;font:inherit;font-size:15px;line-height:1.3;color:var(--ptl-text);&#10;  background-color:var(--ptl-field);border:1px solid var(--ptl-border);border-radius:8px;box-shadow:none;outline:none;&#10;  transition:border-color .15s,box-shadow .15s;max-width:none;min-height:0;text-transform:none;letter-spacing:normal}&#10;.ptl-root .ptl-select{-webkit-appearance:none;-moz-appearance:none;appearance:none;padding-right:32px;cursor:pointer;&#10;  background-image:url(&quot;data:image\/svg+xml,%3Csvg xmlns=&#x27;http:\/\/www.w3.org\/2000\/svg&#x27; width=&#x27;12&#x27; height=&#x27;8&#x27; viewBox=&#x27;0 0 12 8&#x27;%3E%3Cpath d=&#x27;M1 1.5l5 5 5-5&#x27; fill=&#x27;none&#x27; stroke=&#x27;%231e3a8a&#x27; stroke-width=&#x27;1.8&#x27; stroke-linecap=&#x27;round&#x27; stroke-linejoin=&#x27;round&#x27;\/%3E%3C\/svg%3E&quot;);&#10;  background-repeat:no-repeat;background-position:right 11px center;background-size:12px 8px}&#10;.ptl-root .ptl-input:hover,.ptl-root .ptl-select:hover{border-color:#b6c0ce}&#10;.ptl-root .ptl-input:focus,.ptl-root .ptl-select:focus{border-color:var(--ptl-blue-2);box-shadow:0 0 0 3px rgba(29,78,216,.18);background-color:#fff}&#10;.ptl-root .ptl-input.ptl-invalid,.ptl-root .ptl-select.ptl-invalid{border-color:var(--ptl-danger);background-color:var(--ptl-danger-bg)}&#10;.ptl-root .ptl-err{color:var(--ptl-danger);font-size:.82rem;margin:5px 0 0;line-height:1.35}&#10;.ptl-root .ptl-help{color:var(--ptl-muted);font-size:.8rem;margin:5px 0 0;line-height:1.35}&#10;.ptl-root .ptl-combo{display:grid;grid-template-columns:minmax(0,1fr) 130px;gap:8px}&#10;&#10;\/* ---------- buttons ---------- *\/&#10;.ptl-root .ptl-actions{display:flex !important;flex-wrap:wrap;justify-content:center;gap:10px;margin:6px 0 0 !important;padding:0 !important;float:none !important;clear:both}&#10;.ptl-root .ptl-btn{display:inline-flex !important;align-items:center;justify-content:center;float:none !important;width:auto !important;min-width:150px;height:42px;padding:0 20px;margin:0 !important;&#10;  position:static !important;font:inherit;font-size:.95rem;font-weight:650;line-height:1;border-radius:8px;border:1px solid var(--ptl-blue);background:var(--ptl-blue);color:#fff;cursor:pointer;&#10;  text-decoration:none;text-transform:none;letter-spacing:normal;box-shadow:none;transition:background .15s,border-color .15s,color .15s}&#10;.ptl-root .ptl-btn:hover{background:#172f73;border-color:#172f73;color:#fff}&#10;.ptl-root .ptl-btn.ptl-btn-2{background:#fff;color:var(--ptl-blue);border-color:var(--ptl-blue-line)}&#10;.ptl-root .ptl-btn.ptl-btn-2:hover{background:var(--ptl-blue-soft);border-color:var(--ptl-blue);color:var(--ptl-blue)}&#10;.ptl-root .ptl-btn:focus-visible{outline:2px solid var(--ptl-blue-2);outline-offset:2px}&#10;&#10;\/* ---------- results ---------- *\/&#10;.ptl-root .ptl-alert{border:1px solid #fecdca;background:var(--ptl-danger-bg);color:var(--ptl-danger);border-radius:10px;padding:12px 14px;margin:0;font-size:.9rem}&#10;.ptl-root .ptl-alert ul{margin:6px 0 0;padding-left:1.2em}&#10;.ptl-root .ptl-warnbox{border:1px solid var(--ptl-warn-line);background:var(--ptl-warn-bg);color:var(--ptl-warn);border-radius:10px;padding:10px 14px;margin:14px 0 0;font-size:.86rem}&#10;.ptl-root .ptl-warnbox ul{margin:4px 0 0;padding-left:1.2em}&#10;.ptl-root .ptl-rmain{background:linear-gradient(135deg,#1e3a8a 0%,#1d4ed8 100%);border-radius:12px;padding:18px 20px;color:#fff}&#10;.ptl-root .ptl-rlabel{display:block;font-size:.78rem;font-weight:700;text-transform:uppercase;letter-spacing:.06em;opacity:.9;margin-bottom:4px}&#10;.ptl-root .ptl-rvalue{font-size:clamp(2rem,5vw,2.7rem);font-weight:800;line-height:1.1;word-break:break-word;font-variant-numeric:tabular-nums}&#10;.ptl-root .ptl-runit{font-size:.45em;font-weight:700;margin-left:6px;opacity:.92}&#10;.ptl-root .ptl-rsub{font-size:.88rem;margin-top:6px;opacity:.92;font-variant-numeric:tabular-nums}&#10;.ptl-root .ptl-badge{display:inline-block;font-size:.74rem;font-weight:700;letter-spacing:.03em;padding:3px 9px;border-radius:999px;background:rgba(255,255,255,.18);border:1px solid rgba(255,255,255,.35);margin-top:10px}&#10;.ptl-root .ptl-cards{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:12px;margin:14px 0 0}&#10;.ptl-root .ptl-rc{border:1px solid var(--ptl-border);border-radius:10px;padding:12px 14px;background:#fbfcfe;min-width:0}&#10;.ptl-root .ptl-rc-l{display:block;font-size:.74rem;font-weight:700;text-transform:uppercase;letter-spacing:.05em;color:var(--ptl-muted)}&#10;.ptl-root .ptl-rc-v{display:block;font-size:1.45rem;font-weight:800;color:var(--ptl-heading);line-height:1.2;margin-top:3px;font-variant-numeric:tabular-nums;word-break:break-word}&#10;.ptl-root .ptl-rc-v small{font-size:.6em;font-weight:700;color:var(--ptl-muted);margin-left:4px}&#10;.ptl-root .ptl-rc-n{display:block;font-size:.8rem;color:var(--ptl-muted);margin-top:3px;line-height:1.35}&#10;.ptl-root .ptl-rc.ptl-na .ptl-rc-v{font-size:1rem;color:var(--ptl-muted);font-weight:600}&#10;.ptl-root .ptl-keys{margin:0;padding-left:1.2em;font-size:.92rem}&#10;.ptl-root .ptl-tablewrap{overflow-x:auto;-webkit-overflow-scrolling:touch;border:1px solid var(--ptl-border);border-radius:10px}&#10;.ptl-root table.ptl-table{width:100%;border-collapse:collapse;font-size:.88rem;margin:0;border:0;background:#fff}&#10;.ptl-root .ptl-table caption{text-align:left;padding:0;font-size:0;height:0;overflow:hidden}&#10;.ptl-root .ptl-table th,.ptl-root .ptl-table td{padding:8px 10px;border:0;border-bottom:1px solid #e7ebf1;text-align:left;vertical-align:top;background:none}&#10;.ptl-root .ptl-table thead th{background:#f6f8fb;font-size:.76rem;text-transform:uppercase;letter-spacing:.05em;color:var(--ptl-muted);font-weight:700;white-space:nowrap}&#10;.ptl-root .ptl-table tbody tr:last-child td,.ptl-root .ptl-table tbody tr:last-child th{border-bottom:0}&#10;.ptl-root .ptl-table td.ptl-num{font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-weight:700;white-space:nowrap}&#10;.ptl-root .ptl-up{color:var(--ptl-good)}&#10;.ptl-root .ptl-down{color:var(--ptl-bad)}&#10;.ptl-root .ptl-formula{background:#0f1f45;color:#e6edff;border-radius:10px;padding:14px 16px;margin:0}&#10;.ptl-root .ptl-steps{font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:.86rem;color:#d3ddf7;margin:0;padding-left:1.4em}&#10;.ptl-root .ptl-steps li{margin:0 0 5px;word-break:break-word}&#10;.ptl-root .ptl-assume{font-size:.86rem;color:var(--ptl-text)}&#10;.ptl-root .ptl-note{font-size:.85rem;color:var(--ptl-muted);background:#f6f8fb;border-left:3px solid var(--ptl-blue-line);padding:10px 12px;border-radius:0 8px 8px 0;margin:18px 0 0}&#10;.ptl-root .ptl-note p:last-child{margin-bottom:0}&#10;.ptl-root .ptl-sr{position:absolute !important;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}&#10;&#10;\/* ---------- responsive ---------- *\/&#10;@media (max-width:760px){&#10;  .ptl-root .ptl-row3{grid-template-columns:minmax(0,1fr)}&#10;  .ptl-root .ptl-cards{grid-template-columns:minmax(0,1fr)}&#10;}&#10;@media (max-width:560px){&#10;  .ptl-root{padding:20px 12px 28px;border-radius:0}&#10;  .ptl-root .ptl-card{padding:16px}&#10;  .ptl-root .ptl-group{padding:14px 12px 2px}&#10;  .ptl-root .ptl-row{grid-template-columns:minmax(0,1fr)}&#10;  .ptl-root .ptl-combo{grid-template-columns:minmax(0,1fr) 112px}&#10;  .ptl-root .ptl-btn{min-width:0;flex:1 1 100%}&#10;}&#10;@media (prefers-reduced-motion:reduce){ .ptl-root *{transition:none !important} }&#10;html,body{margin:0;padding:0;background:transparent}&#10;&lt;\/style&gt;&#10;&lt;\/head&gt;&#10;&lt;body&gt;&#10;&#10;&lt;div class=&quot;ptl-root&quot; id=&quot;ptl-app&quot;&gt;&#10;  &lt;div class=&quot;ptl-stack&quot;&gt;&#10;&#10;    &lt;!-- ================= INPUTS ================= --&gt;&#10;    &lt;section class=&quot;ptl-card&quot; aria-label=&quot;Punch tool life estimator inputs&quot;&gt;&#10;      &lt;form id=&quot;ptl-form&quot; novalidate autocomplete=&quot;off&quot;&gt;&#10;&#10;        &lt;!-- Workpiece --&gt;&#10;        &lt;fieldset class=&quot;ptl-group&quot;&gt;&#10;          &lt;legend&gt;Workpiece&lt;\/legend&gt;&#10;          &lt;div class=&quot;ptl-row&quot;&gt;&#10;            &lt;div class=&quot;ptl-field&quot;&gt;&#10;              &lt;label for=&quot;ptl-wm&quot;&gt;Workpiece material &lt;span class=&quot;ptl-req&quot; aria-hidden=&quot;true&quot;&gt;*&lt;\/span&gt;&lt;\/label&gt;&#10;              &lt;select id=&quot;ptl-wm&quot; class=&quot;ptl-select&quot; aria-describedby=&quot;ptl-wm-help&quot;&gt;&#10;                &lt;option value=&quot;mild&quot;&gt;Mild \/ low-carbon steel&lt;\/option&gt;&#10;                &lt;option value=&quot;galv&quot;&gt;Galvanized steel&lt;\/option&gt;&#10;                &lt;option value=&quot;hsla&quot;&gt;High-strength low-alloy (HSLA) steel&lt;\/option&gt;&#10;                &lt;option value=&quot;ss&quot;&gt;Stainless steel (austenitic, e.g. 304)&lt;\/option&gt;&#10;                &lt;option value=&quot;al&quot;&gt;Aluminum alloy (e.g. 5052)&lt;\/option&gt;&#10;                &lt;option value=&quot;cu&quot;&gt;Copper \/ brass&lt;\/option&gt;&#10;                &lt;option value=&quot;custom&quot;&gt;Custom material&lt;\/option&gt;&#10;              &lt;\/select&gt;&#10;              &lt;p class=&quot;ptl-help&quot; id=&quot;ptl-wm-help&quot;&gt;Custom materials need a strength or hardness value.&lt;\/p&gt;&#10;            &lt;\/div&gt;&#10;            &lt;div class=&quot;ptl-field&quot;&gt;&#10;              &lt;label for=&quot;ptl-t&quot;&gt;Material thickness &lt;span class=&quot;ptl-req&quot; aria-hidden=&quot;true&quot;&gt;*&lt;\/span&gt;&lt;\/label&gt;&#10;              &lt;div class=&quot;ptl-combo&quot;&gt;&#10;                &lt;input id=&quot;ptl-t&quot; class=&quot;ptl-input&quot; type=&quot;text&quot; inputmode=&quot;decimal&quot; aria-required=&quot;true&quot; aria-describedby=&quot;ptl-t-err ptl-t-help&quot;&gt;&#10;                &lt;select id=&quot;ptl-tu&quot; class=&quot;ptl-select&quot; aria-label=&quot;Thickness unit&quot;&gt;&#10;                  &lt;option value=&quot;mm&quot;&gt;mm&lt;\/option&gt;&#10;                  &lt;option value=&quot;in&quot;&gt;in&lt;\/option&gt;&#10;                &lt;\/select&gt;&#10;              &lt;\/div&gt;&#10;              &lt;p class=&quot;ptl-err&quot; id=&quot;ptl-t-err&quot; hidden&gt;&lt;\/p&gt;&#10;              &lt;p class=&quot;ptl-help&quot; id=&quot;ptl-t-help&quot;&gt;Sheet or plate thickness being punched.&lt;\/p&gt;&#10;            &lt;\/div&gt;&#10;          &lt;\/div&gt;&#10;          &lt;div class=&quot;ptl-field&quot;&gt;&#10;            &lt;label for=&quot;ptl-s&quot;&gt;Tensile strength or hardness &lt;span id=&quot;ptl-s-tag&quot; class=&quot;ptl-opt&quot;&gt;(optional)&lt;\/span&gt;&lt;\/label&gt;&#10;            &lt;div class=&quot;ptl-combo&quot;&gt;&#10;              &lt;input id=&quot;ptl-s&quot; class=&quot;ptl-input&quot; type=&quot;text&quot; inputmode=&quot;decimal&quot; aria-describedby=&quot;ptl-s-err ptl-s-help&quot;&gt;&#10;              &lt;select id=&quot;ptl-su&quot; class=&quot;ptl-select&quot; aria-label=&quot;Strength or hardness unit&quot;&gt;&#10;                &lt;option value=&quot;mpa&quot;&gt;MPa (UTS)&lt;\/option&gt;&#10;                &lt;option value=&quot;ksi&quot;&gt;ksi (UTS)&lt;\/option&gt;&#10;                &lt;option value=&quot;hb&quot;&gt;HB&lt;\/option&gt;&#10;                &lt;option value=&quot;hv&quot;&gt;HV&lt;\/option&gt;&#10;                &lt;option value=&quot;hrb&quot;&gt;HRB&lt;\/option&gt;&#10;              &lt;\/select&gt;&#10;            &lt;\/div&gt;&#10;            &lt;p class=&quot;ptl-err&quot; id=&quot;ptl-s-err&quot; hidden&gt;&lt;\/p&gt;&#10;            &lt;p class=&quot;ptl-help&quot; id=&quot;ptl-s-help&quot;&gt;&lt;\/p&gt;&#10;          &lt;\/div&gt;&#10;        &lt;\/fieldset&gt;&#10;&#10;        &lt;!-- Punch --&gt;&#10;        &lt;fieldset class=&quot;ptl-group&quot;&gt;&#10;          &lt;legend&gt;Punch&lt;\/legend&gt;&#10;          &lt;div class=&quot;ptl-row3&quot;&gt;&#10;            &lt;div class=&quot;ptl-field&quot;&gt;&#10;              &lt;label for=&quot;ptl-pm&quot;&gt;Punch material \/ grade &lt;span class=&quot;ptl-req&quot; aria-hidden=&quot;true&quot;&gt;*&lt;\/span&gt;&lt;\/label&gt;&#10;              &lt;select id=&quot;ptl-pm&quot; class=&quot;ptl-select&quot; aria-describedby=&quot;ptl-pm-help&quot;&gt;&#10;                &lt;option value=&quot;a2&quot;&gt;A2 tool steel&lt;\/option&gt;&#10;                &lt;option value=&quot;d2&quot; selected&gt;D2 \/ Cr12MoV tool steel&lt;\/option&gt;&#10;                &lt;option value=&quot;s7&quot;&gt;S7 shock-resisting steel&lt;\/option&gt;&#10;                &lt;option value=&quot;m2&quot;&gt;M2 high-speed steel&lt;\/option&gt;&#10;                &lt;option value=&quot;pm&quot;&gt;Powder-metal HSS (e.g. ASP 23, CPM M4)&lt;\/option&gt;&#10;                &lt;option value=&quot;wc&quot;&gt;Tungsten carbide&lt;\/option&gt;&#10;                &lt;option value=&quot;custom&quot;&gt;Custom (enter baseline)&lt;\/option&gt;&#10;              &lt;\/select&gt;&#10;              &lt;p class=&quot;ptl-help&quot; id=&quot;ptl-pm-help&quot;&gt;Custom grades require a known baseline hit count.&lt;\/p&gt;&#10;            &lt;\/div&gt;&#10;            &lt;div class=&quot;ptl-field&quot;&gt;&#10;              &lt;label for=&quot;ptl-co&quot;&gt;Coating \/ surface treatment&lt;\/label&gt;&#10;              &lt;select id=&quot;ptl-co&quot; class=&quot;ptl-select&quot;&gt;&#10;                &lt;option value=&quot;none&quot;&gt;None (uncoated)&lt;\/option&gt;&#10;                &lt;option value=&quot;nit&quot;&gt;Nitrided&lt;\/option&gt;&#10;                &lt;option value=&quot;tin&quot;&gt;TiN&lt;\/option&gt;&#10;                &lt;option value=&quot;ticn&quot;&gt;TiCN&lt;\/option&gt;&#10;                &lt;option value=&quot;alcrn&quot;&gt;AlCrN&lt;\/option&gt;&#10;                &lt;option value=&quot;custom&quot;&gt;Custom (enter factor)&lt;\/option&gt;&#10;              &lt;\/select&gt;&#10;            &lt;\/div&gt;&#10;            &lt;div class=&quot;ptl-field&quot;&gt;&#10;              &lt;label for=&quot;ptl-tc&quot;&gt;Tool maintenance condition&lt;\/label&gt;&#10;              &lt;select id=&quot;ptl-tc&quot; class=&quot;ptl-select&quot; aria-describedby=&quot;ptl-tc-help&quot;&gt;&#10;                &lt;option value=&quot;new&quot;&gt;Sharp \/ new or freshly ground&lt;\/option&gt;&#10;                &lt;option value=&quot;svc&quot;&gt;In service (part-way through regrind interval)&lt;\/option&gt;&#10;                &lt;option value=&quot;worn&quot;&gt;Worn (visible edge rounding \/ burr)&lt;\/option&gt;&#10;              &lt;\/select&gt;&#10;              &lt;p class=&quot;ptl-help&quot; id=&quot;ptl-tc-help&quot;&gt;Used and worn tools give the remaining life.&lt;\/p&gt;&#10;            &lt;\/div&gt;&#10;          &lt;\/div&gt;&#10;          &lt;div class=&quot;ptl-field&quot; id=&quot;ptl-wrap-cf&quot; hidden&gt;&#10;            &lt;label for=&quot;ptl-cf&quot;&gt;Custom coating life factor &lt;span class=&quot;ptl-req&quot; aria-hidden=&quot;true&quot;&gt;*&lt;\/span&gt;&lt;\/label&gt;&#10;            &lt;input id=&quot;ptl-cf&quot; class=&quot;ptl-input&quot; type=&quot;text&quot; inputmode=&quot;decimal&quot; aria-describedby=&quot;ptl-cf-err ptl-cf-help&quot; style=&quot;max-width:240px&quot;&gt;&#10;            &lt;p class=&quot;ptl-err&quot; id=&quot;ptl-cf-err&quot; hidden&gt;&lt;\/p&gt;&#10;            &lt;p class=&quot;ptl-help&quot; id=&quot;ptl-cf-help&quot;&gt;Life multiplier vs. uncoated, 0.5\u20135 (e.g. 2 = doubles life). Use supplier data where possible.&lt;\/p&gt;&#10;          &lt;\/div&gt;&#10;        &lt;\/fieldset&gt;&#10;&#10;        &lt;!-- Operating conditions --&gt;&#10;        &lt;fieldset class=&quot;ptl-group&quot;&gt;&#10;          &lt;legend&gt;Operating conditions&lt;\/legend&gt;&#10;          &lt;div class=&quot;ptl-row&quot;&gt;&#10;            &lt;div class=&quot;ptl-field&quot;&gt;&#10;              &lt;label for=&quot;ptl-lu&quot;&gt;Lubrication condition&lt;\/label&gt;&#10;              &lt;select id=&quot;ptl-lu&quot; class=&quot;ptl-select&quot;&gt;&#10;                &lt;option value=&quot;reg&quot;&gt;Regular (consistent oil \/ film)&lt;\/option&gt;&#10;                &lt;option value=&quot;lim&quot;&gt;Limited (occasional \/ thin)&lt;\/option&gt;&#10;                &lt;option value=&quot;none&quot;&gt;None (dry)&lt;\/option&gt;&#10;              &lt;\/select&gt;&#10;            &lt;\/div&gt;&#10;            &lt;div class=&quot;ptl-field&quot;&gt;&#10;              &lt;label for=&quot;ptl-f&quot;&gt;Punching frequency &lt;span class=&quot;ptl-opt&quot;&gt;(optional)&lt;\/span&gt;&lt;\/label&gt;&#10;              &lt;div class=&quot;ptl-combo&quot;&gt;&#10;                &lt;input id=&quot;ptl-f&quot; class=&quot;ptl-input&quot; type=&quot;text&quot; inputmode=&quot;decimal&quot; aria-describedby=&quot;ptl-f-err ptl-f-help&quot;&gt;&#10;                &lt;select id=&quot;ptl-fu&quot; class=&quot;ptl-select&quot; aria-label=&quot;Frequency unit&quot;&gt;&#10;                  &lt;option value=&quot;spm&quot;&gt;spm (strokes\/min)&lt;\/option&gt;&#10;                  &lt;option value=&quot;cph&quot;&gt;cycles\/h&lt;\/option&gt;&#10;                &lt;\/select&gt;&#10;              &lt;\/div&gt;&#10;              &lt;p class=&quot;ptl-err&quot; id=&quot;ptl-f-err&quot; hidden&gt;&lt;\/p&gt;&#10;              &lt;p class=&quot;ptl-help&quot; id=&quot;ptl-f-help&quot;&gt;Strokes per minute or cycles per hour. Needed for operating hours. Above 300 spm a heat factor is applied.&lt;\/p&gt;&#10;            &lt;\/div&gt;&#10;          &lt;\/div&gt;&#10;        &lt;\/fieldset&gt;&#10;&#10;        &lt;!-- Baseline --&gt;&#10;        &lt;fieldset class=&quot;ptl-group&quot;&gt;&#10;          &lt;legend&gt;Known baseline &lt;span class=&quot;ptl-opt&quot; id=&quot;ptl-b-tag&quot;&gt;(optional)&lt;\/span&gt;&lt;\/legend&gt;&#10;          &lt;div class=&quot;ptl-row&quot;&gt;&#10;            &lt;div class=&quot;ptl-field&quot;&gt;&#10;              &lt;label for=&quot;ptl-b&quot;&gt;Your baseline life (hits per regrind)&lt;\/label&gt;&#10;              &lt;input id=&quot;ptl-b&quot; class=&quot;ptl-input&quot; type=&quot;text&quot; inputmode=&quot;numeric&quot; aria-describedby=&quot;ptl-b-err ptl-b-help&quot;&gt;&#10;              &lt;p class=&quot;ptl-err&quot; id=&quot;ptl-b-err&quot; hidden&gt;&lt;\/p&gt;&#10;              &lt;p class=&quot;ptl-help&quot; id=&quot;ptl-b-help&quot;&gt;From your shop records or the tooling supplier. Overrides the built-in reference life.&lt;\/p&gt;&#10;            &lt;\/div&gt;&#10;            &lt;div class=&quot;ptl-field&quot;&gt;&#10;              &lt;label for=&quot;ptl-bm&quot;&gt;How the baseline was measured&lt;\/label&gt;&#10;              &lt;select id=&quot;ptl-bm&quot; class=&quot;ptl-select&quot; aria-describedby=&quot;ptl-bm-help&quot;&gt;&#10;                &lt;option value=&quot;ref&quot;&gt;At reference conditions (adjust)&lt;\/option&gt;&#10;                &lt;option value=&quot;asis&quot;&gt;Under these conditions (as-is)&lt;\/option&gt;&#10;              &lt;\/select&gt;&#10;              &lt;p class=&quot;ptl-help&quot; id=&quot;ptl-bm-help&quot;&gt;Reference conditions: 1.5 mm, typical strength, uncoated, regular lubrication, \u2264300 spm, sharp tool.&lt;\/p&gt;&#10;            &lt;\/div&gt;&#10;          &lt;\/div&gt;&#10;        &lt;\/fieldset&gt;&#10;&#10;        &lt;!-- Schedule --&gt;&#10;        &lt;fieldset class=&quot;ptl-group&quot;&gt;&#10;          &lt;legend&gt;Production schedule &lt;span class=&quot;ptl-opt&quot;&gt;(optional)&lt;\/span&gt;&lt;\/legend&gt;&#10;          &lt;div class=&quot;ptl-row&quot;&gt;&#10;            &lt;div class=&quot;ptl-field&quot;&gt;&#10;              &lt;label for=&quot;ptl-hs&quot;&gt;Hits per shift (this punch)&lt;\/label&gt;&#10;              &lt;input id=&quot;ptl-hs&quot; class=&quot;ptl-input&quot; type=&quot;text&quot; inputmode=&quot;numeric&quot; aria-describedby=&quot;ptl-hs-err&quot;&gt;&#10;              &lt;p class=&quot;ptl-err&quot; id=&quot;ptl-hs-err&quot; hidden&gt;&lt;\/p&gt;&#10;            &lt;\/div&gt;&#10;            &lt;div class=&quot;ptl-field&quot;&gt;&#10;              &lt;label for=&quot;ptl-sd&quot;&gt;Shifts per day&lt;\/label&gt;&#10;              &lt;input id=&quot;ptl-sd&quot; class=&quot;ptl-input&quot; type=&quot;text&quot; inputmode=&quot;decimal&quot; aria-describedby=&quot;ptl-sd-err ptl-sd-help&quot;&gt;&#10;              &lt;p class=&quot;ptl-err&quot; id=&quot;ptl-sd-err&quot; hidden&gt;&lt;\/p&gt;&#10;              &lt;p class=&quot;ptl-help&quot; id=&quot;ptl-sd-help&quot;&gt;1\u20134. Requires hits per shift.&lt;\/p&gt;&#10;            &lt;\/div&gt;&#10;          &lt;\/div&gt;&#10;        &lt;\/fieldset&gt;&#10;&#10;        &lt;div class=&quot;ptl-actions&quot;&gt;&#10;          &lt;button type=&quot;submit&quot; class=&quot;ptl-btn&quot; id=&quot;ptl-calc&quot;&gt;Calculate&lt;\/button&gt;&#10;        &lt;\/div&gt;&#10;      &lt;\/form&gt;&#10;    &lt;\/section&gt;&#10;&#10;    &lt;!-- ================= RESULTS ================= --&gt;&#10;    &lt;section class=&quot;ptl-card&quot; aria-labelledby=&quot;ptl-results-title&quot; id=&quot;ptl-results&quot; tabindex=&quot;-1&quot; hidden&gt;&#10;      &lt;h2 id=&quot;ptl-results-title&quot;&gt;Estimated Punch Life&lt;\/h2&gt;&#10;&#10;      &lt;div class=&quot;ptl-alert&quot; id=&quot;ptl-error&quot; role=&quot;alert&quot; hidden&gt;&lt;\/div&gt;&#10;&#10;      &lt;div id=&quot;ptl-body&quot; aria-live=&quot;polite&quot;&gt;&#10;        &lt;div class=&quot;ptl-rmain&quot;&gt;&#10;          &lt;span class=&quot;ptl-rlabel&quot;&gt;Estimated tool life (hits until regrind)&lt;\/span&gt;&#10;          &lt;div class=&quot;ptl-rvalue&quot;&gt;\u2248 &lt;span id=&quot;ptl-r-hits&quot;&gt;&lt;\/span&gt;&lt;span class=&quot;ptl-runit&quot;&gt;hits&lt;\/span&gt;&lt;\/div&gt;&#10;          &lt;div class=&quot;ptl-rsub&quot; id=&quot;ptl-r-range&quot;&gt;&lt;\/div&gt;&#10;          &lt;span class=&quot;ptl-badge&quot; id=&quot;ptl-r-conf&quot;&gt;&lt;\/span&gt;&#10;        &lt;\/div&gt;&#10;&#10;        &lt;div class=&quot;ptl-cards&quot;&gt;&#10;          &lt;div class=&quot;ptl-rc&quot; id=&quot;ptl-c-hours&quot;&gt;&#10;            &lt;span class=&quot;ptl-rc-l&quot;&gt;Operating hours&lt;\/span&gt;&#10;            &lt;span class=&quot;ptl-rc-v&quot; id=&quot;ptl-r-hours&quot;&gt;&lt;\/span&gt;&#10;            &lt;span class=&quot;ptl-rc-n&quot; id=&quot;ptl-r-hours-n&quot;&gt;&lt;\/span&gt;&#10;          &lt;\/div&gt;&#10;          &lt;div class=&quot;ptl-rc&quot; id=&quot;ptl-c-shifts&quot;&gt;&#10;            &lt;span class=&quot;ptl-rc-l&quot;&gt;Shifts of service&lt;\/span&gt;&#10;            &lt;span class=&quot;ptl-rc-v&quot; id=&quot;ptl-r-shifts&quot;&gt;&lt;\/span&gt;&#10;            &lt;span class=&quot;ptl-rc-n&quot; id=&quot;ptl-r-shifts-n&quot;&gt;&lt;\/span&gt;&#10;          &lt;\/div&gt;&#10;          &lt;div class=&quot;ptl-rc&quot; id=&quot;ptl-c-days&quot;&gt;&#10;            &lt;span class=&quot;ptl-rc-l&quot;&gt;Days of service&lt;\/span&gt;&#10;            &lt;span class=&quot;ptl-rc-v&quot; id=&quot;ptl-r-days&quot;&gt;&lt;\/span&gt;&#10;            &lt;span class=&quot;ptl-rc-n&quot; id=&quot;ptl-r-days-n&quot;&gt;&lt;\/span&gt;&#10;          &lt;\/div&gt;&#10;        &lt;\/div&gt;&#10;&#10;        &lt;div class=&quot;ptl-warnbox&quot; id=&quot;ptl-warn&quot; hidden&gt;&lt;\/div&gt;&#10;&#10;        &lt;h3&gt;Key factors affecting this estimate&lt;\/h3&gt;&#10;        &lt;ul class=&quot;ptl-keys&quot; id=&quot;ptl-keys&quot;&gt;&lt;\/ul&gt;&#10;&#10;        &lt;h3&gt;Adjustment factors used&lt;\/h3&gt;&#10;        &lt;div class=&quot;ptl-tablewrap&quot;&gt;&#10;          &lt;table class=&quot;ptl-table&quot;&gt;&#10;            &lt;caption&gt;Model adjustment factors&lt;\/caption&gt;&#10;            &lt;thead&gt;&lt;tr&gt;&lt;th scope=&quot;col&quot;&gt;Factor&lt;\/th&gt;&lt;th scope=&quot;col&quot;&gt;Your input&lt;\/th&gt;&lt;th scope=&quot;col&quot;&gt;Multiplier&lt;\/th&gt;&lt;th scope=&quot;col&quot;&gt;Basis&lt;\/th&gt;&lt;\/tr&gt;&lt;\/thead&gt;&#10;            &lt;tbody id=&quot;ptl-ftable&quot;&gt;&lt;\/tbody&gt;&#10;          &lt;\/table&gt;&#10;        &lt;\/div&gt;&#10;&#10;        &lt;h3&gt;Calculation summary&lt;\/h3&gt;&#10;        &lt;div class=&quot;ptl-formula&quot;&gt;&#10;          &lt;ol class=&quot;ptl-steps&quot; id=&quot;ptl-steps&quot;&gt;&lt;\/ol&gt;&#10;        &lt;\/div&gt;&#10;&#10;        &lt;h3&gt;Model assumptions&lt;\/h3&gt;&#10;        &lt;ul class=&quot;ptl-assume&quot; id=&quot;ptl-assume&quot;&gt;&lt;\/ul&gt;&#10;&#10;        &lt;div class=&quot;ptl-note&quot;&gt;&#10;          &lt;p&gt;&lt;strong&gt;This is an estimate, not a guaranteed tool life.&lt;\/strong&gt; No universal formula predicts punch life precisely. Actual life depends on die clearance, punch-to-die alignment, punch geometry (shear angle, size relative to thickness), material variability between coils and batches, press condition and rigidity, slug pulling, sharpening practice (how much is removed and how often), and operating technique.&lt;\/p&gt;&#10;          &lt;p&gt;Monitor burr height, cutting-edge wear and part quality, regrind before edges become heavily rounded, and follow the tool and machine manufacturers&#x27; maintenance guidance. Replace the built-in reference with your own recorded hit counts whenever you have them.&lt;\/p&gt;&#10;        &lt;\/div&gt;&#10;      &lt;\/div&gt;&#10;    &lt;\/section&gt;&#10;&#10;  &lt;\/div&gt;&#10;&lt;\/div&gt;&#10;&#10;&lt;script&gt;&#10;\/* =====================================================================&#10;   Punch Tool Life Estimator (vanilla JS, no globals)&#10;   Model:  L = L_ref \u00d7 f_thickness \u00d7 f_strength \u00d7 f_coating \u00d7 f_lube \u00d7 f_frequency \u00d7 f_condition&#10;   All reference values and factors live in CONFIG and can be edited.&#10;   ===================================================================== *\/&#10;(function () {&#10;  &#x27;use strict&#x27;;&#10;&#10;  var root = document.getElementById(&#x27;ptl-app&#x27;);&#10;  if (!root || root.getAttribute(&#x27;data-ptl-ready&#x27;) === &#x27;1&#x27;) return;&#10;  root.setAttribute(&#x27;data-ptl-ready&#x27;, &#x27;1&#x27;);&#10;  function $(id) { return document.getElementById(id); }&#10;&#10;  \/* ------------------------------------------------------------------&#10;     CONFIG \u2014 indicative values for planning, not supplier data.&#10;     Reference conditions: mild steel ~400 MPa, 1.5 mm, uncoated,&#10;     regular lubrication, \u2264300 spm, sharp tool, correct clearance.&#10;     ------------------------------------------------------------------ *\/&#10;  var CONFIG = {&#10;    refThicknessMm: 1.5,&#10;    thicknessExp: 1.2,             \/\/ f_t = (t_ref \/ t)^1.2&#10;    thicknessClamp: [0.15, 4],&#10;    strengthExp: 1.3,              \/\/ f_s = (S_typ \/ S)^1.3&#10;    strengthClamp: [0.15, 3],&#10;    freqRefSpm: 300,               \/\/ no penalty at or below this rate&#10;    freqExp: 0.3,                  \/\/ f_f = (300 \/ spm)^0.3 above it&#10;    freqMin: 0.6,&#10;    customRefUtsMpa: 400,          \/\/ custom workpiece compared with mild steel&#10;    \/\/ Reference hits per regrind on mild steel at reference conditions&#10;    punch: {&#10;      a2:  { name: &#x27;A2 tool steel&#x27;, life: 60000 },&#10;      d2:  { name: &#x27;D2 \/ Cr12MoV tool steel&#x27;, life: 100000 },&#10;      s7:  { name: &#x27;S7 shock-resisting steel&#x27;, life: 50000 },&#10;      m2:  { name: &#x27;M2 high-speed steel&#x27;, life: 150000 },&#10;      pm:  { name: &#x27;Powder-metal HSS&#x27;, life: 250000 },&#10;      wc:  { name: &#x27;Tungsten carbide&#x27;, life: 1000000 },&#10;      custom: { name: &#x27;Custom grade&#x27;, life: null }&#10;    },&#10;    \/\/ Workpiece life factor relative to mild steel + typical UTS (MPa)&#10;    work: {&#10;      mild:   { name: &#x27;Mild \/ low-carbon steel&#x27;, factor: 1.00, uts: 400 },&#10;      galv:   { name: &#x27;Galvanized steel&#x27;, factor: 0.85, uts: 400 },&#10;      hsla:   { name: &#x27;HSLA steel&#x27;, factor: 0.60, uts: 550 },&#10;      ss:     { name: &#x27;Stainless steel (austenitic)&#x27;, factor: 0.40, uts: 620 },&#10;      al:     { name: &#x27;Aluminum alloy&#x27;, factor: 1.30, uts: 230 },&#10;      cu:     { name: &#x27;Copper \/ brass&#x27;, factor: 1.20, uts: 340 },&#10;      custom: { name: &#x27;Custom material&#x27;, factor: 1.00, uts: null }&#10;    },&#10;    coating: {&#10;      none:  { name: &#x27;None&#x27;, f: 1.0 },&#10;      nit:   { name: &#x27;Nitrided&#x27;, f: 1.5 },&#10;      tin:   { name: &#x27;TiN&#x27;, f: 1.8 },&#10;      ticn:  { name: &#x27;TiCN&#x27;, f: 2.2 },&#10;      alcrn: { name: &#x27;AlCrN&#x27;, f: 2.5 },&#10;      custom:{ name: &#x27;Custom&#x27;, f: null }&#10;    },&#10;    lube: {&#10;      reg:  { name: &#x27;Regular&#x27;, f: 1.0 },&#10;      lim:  { name: &#x27;Limited&#x27;, f: 0.7 },&#10;      none: { name: &#x27;None (dry)&#x27;, f: 0.45 }&#10;    },&#10;    condition: {&#10;      new:  { name: &#x27;Sharp \/ new&#x27;, f: 1.0 },&#10;      svc:  { name: &#x27;In service&#x27;, f: 0.6 },&#10;      worn: { name: &#x27;Worn&#x27;, f: 0.25 }&#10;    },&#10;    \/\/ Likely-range multipliers by confidence level&#10;    range: { baseline: [0.7, 1.3], reference: [0.5, 1.5], indicative: [0.4, 2.0] }&#10;  };&#10;&#10;  \/\/ Strength\/hardness units: valid range in the unit, and conversion to UTS in MPa&#10;  var SUNIT = {&#10;    mpa: { sym: &#x27;MPa&#x27;, min: 50,  max: 2000, toMpa: function (v) { return v; } },&#10;    ksi: { sym: &#x27;ksi&#x27;, min: 7,   max: 290,  toMpa: function (v) { return v * 6.894757; } },&#10;    hb:  { sym: &#x27;HB&#x27;,  min: 10,  max: 600,  toMpa: function (v) { return 3.45 * v; } },&#10;    hv:  { sym: &#x27;HV&#x27;,  min: 10,  max: 650,  toMpa: function (v) { return 3.45 * 0.95 * v; } },&#10;    hrb: { sym: &#x27;HRB&#x27;, min: 40,  max: 100,  toMpa: function (v) { return 3.45 * 7300 \/ (130 - v); } }&#10;  };&#10;  var MM_PER_IN = 25.4;&#10;&#10;  var EXAMPLE = {&#10;    wm: &#x27;ss&#x27;, t: &#x27;2&#x27;, tu: &#x27;mm&#x27;, s: &#x27;&#x27;, su: &#x27;mpa&#x27;, pm: &#x27;d2&#x27;, co: &#x27;ticn&#x27;, cf: &#x27;&#x27;, tc: &#x27;new&#x27;,&#10;    lu: &#x27;lim&#x27;, f: &#x27;200&#x27;, fu: &#x27;spm&#x27;, b: &#x27;&#x27;, bm: &#x27;ref&#x27;, hs: &#x27;20000&#x27;, sd: &#x27;2&#x27;&#10;  };&#10;  var DEFAULTS = {&#10;    wm: &#x27;mild&#x27;, t: &#x27;&#x27;, tu: &#x27;mm&#x27;, s: &#x27;&#x27;, su: &#x27;mpa&#x27;, pm: &#x27;d2&#x27;, co: &#x27;none&#x27;, cf: &#x27;&#x27;, tc: &#x27;new&#x27;,&#10;    lu: &#x27;reg&#x27;, f: &#x27;&#x27;, fu: &#x27;spm&#x27;, b: &#x27;&#x27;, bm: &#x27;ref&#x27;, hs: &#x27;&#x27;, sd: &#x27;&#x27;&#10;  };&#10;  var tUnit = &#x27;mm&#x27;, fUnit = &#x27;spm&#x27;;&#10;&#10;  \/* ---------- parsing &amp; formatting ---------- *\/&#10;  function parseNum(raw) {&#10;    var s = String(raw == null ? &#x27;&#x27; : raw).trim().replace(\/\\s+\/g, &#x27;&#x27;);&#10;    if (s === &#x27;&#x27;) return { empty: true, ok: false };&#10;    if (\/^[+-]?\\d{1,3}(,\\d{3})+(\\.\\d+)?$\/.test(s)) s = s.replace(\/,\/g, &#x27;&#x27;);&#10;    else if (\/^[+-]?\\d*,\\d+$\/.test(s)) s = s.replace(&#x27;,&#x27;, &#x27;.&#x27;);&#10;    if (!\/^[+-]?(\\d+\\.?\\d*|\\.\\d+)(e[+-]?\\d+)?$\/i.test(s)) return { empty: false, ok: false };&#10;    var n = Number(s);&#10;    return isFinite(n) ? { empty: false, ok: true, n: n } : { empty: false, ok: false };&#10;  }&#10;  function roundSig(n, sig) {&#10;    if (n === 0 || !isFinite(n)) return n;&#10;    var p = Math.pow(10, sig - Math.ceil(Math.log10(Math.abs(n))));&#10;    return Math.round(n * p) \/ p;&#10;  }&#10;  function fmtInt(n) { return Math.round(n).toLocaleString(&#x27;en-US&#x27;); }&#10;  \/** Rounded display: 2 significant figures (no false precision). *\/&#10;  function fmtR(n) {&#10;    var r = roundSig(n, 2);&#10;    if (Math.abs(r) &gt;= 100) return fmtInt(r);&#10;    return r.toLocaleString(&#x27;en-US&#x27;, { maximumFractionDigits: 2 });&#10;  }&#10;  \/** Intermediate values: 3 significant figures. *\/&#10;  function g(n) {&#10;    var r = roundSig(n, 3);&#10;    if (Math.abs(r) &gt;= 1000) return fmtInt(r);&#10;    return r.toLocaleString(&#x27;en-US&#x27;, { maximumFractionDigits: 4 });&#10;  }&#10;  function esc(s) {&#10;    return String(s).replace(\/[&amp;&lt;&gt;&quot;&#x27;]\/g, function (c) {&#10;      return { &#x27;&amp;&#x27;: &#x27;&amp;amp;&#x27;, &#x27;&lt;&#x27;: &#x27;&amp;lt;&#x27;, &#x27;&gt;&#x27;: &#x27;&amp;gt;&#x27;, &#x27;&quot;&#x27;: &#x27;&amp;quot;&#x27;, &quot;&#x27;&quot;: &#x27;&amp;#39;&#x27; }[c];&#10;    });&#10;  }&#10;  function clamp(v, r) { return Math.min(r[1], Math.max(r[0], v)); }&#10;&#10;  \/* ---------- field errors ---------- *\/&#10;  function setErr(key, msg) {&#10;    var el = $(&#x27;ptl-&#x27; + key), er = $(&#x27;ptl-&#x27; + key + &#x27;-err&#x27;);&#10;    if (!el || !er) return;&#10;    if (msg) {&#10;      el.classList.add(&#x27;ptl-invalid&#x27;); el.setAttribute(&#x27;aria-invalid&#x27;, &#x27;true&#x27;);&#10;      er.textContent = msg; er.hidden = false;&#10;    } else {&#10;      el.classList.remove(&#x27;ptl-invalid&#x27;); el.removeAttribute(&#x27;aria-invalid&#x27;);&#10;      er.textContent = &#x27;&#x27;; er.hidden = true;&#10;    }&#10;  }&#10;  var ERR_KEYS = [&#x27;t&#x27;, &#x27;s&#x27;, &#x27;cf&#x27;, &#x27;f&#x27;, &#x27;b&#x27;, &#x27;hs&#x27;, &#x27;sd&#x27;];&#10;  function clearErrs() { ERR_KEYS.forEach(function (k) { setErr(k, null); }); }&#10;&#10;  \/** Validate a numeric field. Returns {val} or {msg}; val null when optional and empty. *\/&#10;  function num(key, label, min, max, required, unitSym) {&#10;    var p = parseNum($(&#x27;ptl-&#x27; + key).value);&#10;    if (p.empty) return required ? { msg: label + &#x27; is required.&#x27; } : { val: null };&#10;    if (!p.ok) return { msg: label + &#x27; must be a number.&#x27; };&#10;    if (p.n &lt;= 0) return { msg: label + &#x27; must be greater than zero.&#x27; };&#10;    if (p.n &lt; min || p.n &gt; max) {&#10;      return { msg: label + &#x27; must be between &#x27; + g(min) + &#x27; and &#x27; + g(max) + (unitSym ? &#x27; &#x27; + unitSym : &#x27;&#x27;) + &#x27;.&#x27; };&#10;    }&#10;    return { val: p.n };&#10;  }&#10;&#10;  \/* ---------- dynamic UI ---------- *\/&#10;  function updateUI() {&#10;    var wm = $(&#x27;ptl-wm&#x27;).value, pm = $(&#x27;ptl-pm&#x27;).value, co = $(&#x27;ptl-co&#x27;).value;&#10;    var custom = wm === &#x27;custom&#x27;;&#10;    $(&#x27;ptl-s-tag&#x27;).textContent = custom ? &#x27;(required)&#x27; : &#x27;(optional)&#x27;;&#10;    $(&#x27;ptl-s-tag&#x27;).className = custom ? &#x27;ptl-req&#x27; : &#x27;ptl-opt&#x27;;&#10;    $(&#x27;ptl-s&#x27;).setAttribute(&#x27;aria-required&#x27;, custom ? &#x27;true&#x27; : &#x27;false&#x27;);&#10;    var su = SUNIT[$(&#x27;ptl-su&#x27;).value];&#10;    if (custom) {&#10;      $(&#x27;ptl-s-help&#x27;).textContent = &#x27;Required for custom materials. Allowed: &#x27; + su.min + &#x27;\u2013&#x27; + su.max + &#x27; &#x27; + su.sym + &#x27;. Hardness is converted to an approximate tensile strength.&#x27;;&#10;    } else {&#10;      var uts = CONFIG.work[wm].uts;&#10;      $(&#x27;ptl-s-help&#x27;).textContent = &#x27;Optional. Leave blank to use the typical value (~&#x27; + typicalIn($(&#x27;ptl-su&#x27;).value, uts) + &#x27; for &#x27; + CONFIG.work[wm].name.toLowerCase() + &#x27;).&#x27;;&#10;    }&#10;    $(&#x27;ptl-wrap-cf&#x27;).hidden = co !== &#x27;custom&#x27;;&#10;    if (co !== &#x27;custom&#x27;) setErr(&#x27;cf&#x27;, null);&#10;    var needB = pm === &#x27;custom&#x27;;&#10;    $(&#x27;ptl-b-tag&#x27;).textContent = needB ? &#x27;(required for custom punch grade)&#x27; : &#x27;(optional)&#x27;;&#10;    $(&#x27;ptl-b-tag&#x27;).className = needB ? &#x27;ptl-req&#x27; : &#x27;ptl-opt&#x27;;&#10;    $(&#x27;ptl-b&#x27;).setAttribute(&#x27;aria-required&#x27;, needB ? &#x27;true&#x27; : &#x27;false&#x27;);&#10;  }&#10;  \/** Typical UTS expressed in the selected unit, for the help text. *\/&#10;  function typicalIn(unitKey, utsMpa) {&#10;    var v;&#10;    switch (unitKey) {&#10;      case &#x27;ksi&#x27;: v = utsMpa \/ 6.894757; return Math.round(v) + &#x27; ksi&#x27;;&#10;      case &#x27;hb&#x27;:  v = utsMpa \/ 3.45; return Math.round(v) + &#x27; HB&#x27;;&#10;      case &#x27;hv&#x27;:  v = utsMpa \/ (3.45 * 0.95); return Math.round(v) + &#x27; HV&#x27;;&#10;      case &#x27;hrb&#x27;: v = 130 - 7300 \/ (utsMpa \/ 3.45); return (v &lt; 40 ? &#x27;below 40&#x27; : Math.round(v)) + &#x27; HRB&#x27;;&#10;      default:    return utsMpa + &#x27; MPa&#x27;;&#10;    }&#10;  }&#10;&#10;  \/* ---------- calculation ---------- *\/&#10;  function compute() {&#10;    clearErrs();&#10;    var errs = [], warn = [];&#10;    function take(key, r) { if (r.msg) { setErr(key, r.msg); errs.push(r.msg); return null; } return r.val; }&#10;&#10;    var wm = $(&#x27;ptl-wm&#x27;).value, pm = $(&#x27;ptl-pm&#x27;).value, co = $(&#x27;ptl-co&#x27;).value;&#10;    var tc = $(&#x27;ptl-tc&#x27;).value, lu = $(&#x27;ptl-lu&#x27;).value, bm = $(&#x27;ptl-bm&#x27;).value;&#10;    var W = CONFIG.work[wm], P = CONFIG.punch[pm];&#10;&#10;    \/\/ Thickness (0.1\u201325 mm)&#10;    var tIn = tUnit === &#x27;in&#x27;;&#10;    var t = take(&#x27;t&#x27;, num(&#x27;t&#x27;, &#x27;Material thickness&#x27;, tIn ? 0.004 : 0.1, tIn ? 1 : 25, true, tUnit));&#10;    var tMm = t == null ? null : (tIn ? t * MM_PER_IN : t);&#10;&#10;    \/\/ Strength \/ hardness&#10;    var suKey = $(&#x27;ptl-su&#x27;).value, SU = SUNIT[suKey];&#10;    var s = take(&#x27;s&#x27;, num(&#x27;s&#x27;, &#x27;Tensile strength \/ hardness&#x27;, SU.min, SU.max, wm === &#x27;custom&#x27;, SU.sym));&#10;&#10;    \/\/ Custom coating factor&#10;    var cf = null;&#10;    if (co === &#x27;custom&#x27;) cf = take(&#x27;cf&#x27;, num(&#x27;cf&#x27;, &#x27;Custom coating factor&#x27;, 0.5, 5, true, &#x27;&#x27;));&#10;&#10;    \/\/ Frequency&#10;    var fCph = fUnit === &#x27;cph&#x27;;&#10;    var f = take(&#x27;f&#x27;, num(&#x27;f&#x27;, &#x27;Punching frequency&#x27;, fCph ? 60 : 1, fCph ? 120000 : 2000, false, fCph ? &#x27;cycles\/h&#x27; : &#x27;strokes\/min&#x27;));&#10;    var spm = f == null ? null : (fCph ? f \/ 60 : f);&#10;&#10;    \/\/ Baseline&#10;    var b = take(&#x27;b&#x27;, num(&#x27;b&#x27;, &#x27;Baseline life&#x27;, 100, 50000000, pm === &#x27;custom&#x27;, &#x27;hits&#x27;));&#10;    if (pm === &#x27;custom&#x27; &amp;&amp; $(&#x27;ptl-b&#x27;).value.trim() === &#x27;&#x27;) {&#10;      \/\/ replace generic message with a clearer one&#10;      var m = &#x27;Baseline life is required for a custom punch grade \u2014 no reference data exists for it.&#x27;;&#10;      errs[errs.length - 1] = m; setErr(&#x27;b&#x27;, m);&#10;    }&#10;&#10;    \/\/ Schedule&#10;    var hs = take(&#x27;hs&#x27;, num(&#x27;hs&#x27;, &#x27;Hits per shift&#x27;, 1, 10000000, false, &#x27;&#x27;));&#10;    var sd = take(&#x27;sd&#x27;, num(&#x27;sd&#x27;, &#x27;Shifts per day&#x27;, 0.5, 4, false, &#x27;&#x27;));&#10;    if (sd != null &amp;&amp; hs == null &amp;&amp; !$(&#x27;ptl-hs&#x27;).classList.contains(&#x27;ptl-invalid&#x27;)) {&#10;      var m2 = &#x27;Enter hits per shift to use shifts per day.&#x27;;&#10;      setErr(&#x27;hs&#x27;, m2); errs.push(m2);&#10;    }&#10;&#10;    if (errs.length) { showErrors(errs); return false; }&#10;&#10;    \/* ---- reference life ---- *\/&#10;    var steps = [], rows = [], indicative = false;&#10;    var useBaseline = b != null, asIs = useBaseline &amp;&amp; bm === &#x27;asis&#x27;;&#10;    var Lref;&#10;    if (useBaseline) {&#10;      Lref = b;&#10;      steps.push(&#x27;Reference life = your baseline = &#x27; + fmtInt(b) + &#x27; hits&#x27; + (asIs ? &#x27; (already at these conditions)&#x27; : &#x27;&#x27;));&#10;      rows.push([&#x27;Reference life&#x27;, &#x27;Your baseline&#x27;, fmtInt(b) + &#x27; hits&#x27;, asIs ? &#x27;Used as-is; only tool condition applied&#x27; : &#x27;Replaces built-in reference data&#x27;]);&#10;    } else {&#10;      Lref = P.life * W.factor;&#10;      steps.push(&#x27;Reference life = &#x27; + fmtInt(P.life) + &#x27; (&#x27; + P.name + &#x27;) \u00d7 &#x27; + g(W.factor) + &#x27; (&#x27; + W.name + &#x27;) = &#x27; + fmtInt(Lref) + &#x27; hits&#x27;);&#10;      rows.push([&#x27;Punch reference&#x27;, P.name, fmtInt(P.life) + &#x27; hits&#x27;, &#x27;Typical hits per regrind on mild steel at reference conditions&#x27;]);&#10;      rows.push([&#x27;Workpiece&#x27;, W.name, &#x27;\u00d7 &#x27; + g(W.factor), &#x27;Relative to mild steel&#x27;]);&#10;    }&#10;&#10;    var factors = [];   \/\/ {name, f, text}&#10;    function addF(name, input, f, basis) {&#10;      factors.push({ name: name, f: f });&#10;      rows.push([name, input, &#x27;\u00d7 &#x27; + g(f), basis]);&#10;    }&#10;&#10;    if (!asIs) {&#10;      \/\/ Thickness&#10;      var ft = clamp(Math.pow(CONFIG.refThicknessMm \/ tMm, CONFIG.thicknessExp), CONFIG.thicknessClamp);&#10;      addF(&#x27;Thickness&#x27;, g(t) + &#x27; &#x27; + tUnit + (tIn ? &#x27; (&#x27; + g(tMm) + &#x27; mm)&#x27; : &#x27;&#x27;), ft, &#x27;(&#x27; + CONFIG.refThicknessMm + &#x27; \/ t)^&#x27; + CONFIG.thicknessExp + &#x27;, limited to &#x27; + CONFIG.thicknessClamp.join(&#x27;\u2013&#x27;));&#10;      steps.push(&#x27;Thickness factor = (&#x27; + CONFIG.refThicknessMm + &#x27; \/ &#x27; + g(tMm) + &#x27;)^&#x27; + CONFIG.thicknessExp + &#x27; = &#x27; + g(ft));&#10;      if (tMm &lt; 0.5 || tMm &gt; 6) { indicative = true; warn.push(&#x27;Thickness &#x27; + g(tMm) + &#x27; mm is outside the 0.5\u20136 mm range the model is tuned for; treat the result as indicative.&#x27;); }&#10;      if (tMm &gt; 12) warn.push(&#x27;Above ~12 mm, punch diameter must usually be at least the material thickness, and breakage rather than wear often limits life.&#x27;);&#10;&#10;      \/\/ Strength&#10;      var typ = wm === &#x27;custom&#x27; ? CONFIG.customRefUtsMpa : W.uts, fs = 1, sMpa = null;&#10;      if (s != null) {&#10;        sMpa = SU.toMpa(s);&#10;        fs = clamp(Math.pow(typ \/ sMpa, CONFIG.strengthExp), CONFIG.strengthClamp);&#10;        var sInput = g(s) + &#x27; &#x27; + SU.sym + (suKey !== &#x27;mpa&#x27; ? &#x27; (\u2248 &#x27; + fmtR(sMpa) + &#x27; MPa UTS)&#x27; : &#x27;&#x27;);&#10;        addF(&#x27;Strength \/ hardness&#x27;, sInput, fs, wm === &#x27;custom&#x27; ? &#x27;(&#x27; + typ + &#x27; MPa \/ S)^&#x27; + CONFIG.strengthExp + &#x27; vs. mild steel&#x27; : &#x27;(&#x27; + typ + &#x27; MPa typical \/ S)^&#x27; + CONFIG.strengthExp);&#10;        steps.push(&#x27;Strength factor = (&#x27; + typ + &#x27; \/ &#x27; + fmtR(sMpa) + &#x27;)^&#x27; + CONFIG.strengthExp + &#x27; = &#x27; + g(fs));&#10;        if (suKey !== &#x27;mpa&#x27; &amp;&amp; suKey !== &#x27;ksi&#x27;) warn.push(&#x27;Hardness was converted to tensile strength with an approximate relationship (UTS \u2248 3.45 \u00d7 HB); it is less accurate for non-ferrous metals.&#x27;);&#10;        if (wm !== &#x27;custom&#x27; &amp;&amp; (sMpa \/ typ &gt; 2.2 || sMpa \/ typ &lt; 0.45)) {&#10;          indicative = true;&#10;          warn.push(&#x27;The strength you entered (\u2248 &#x27; + fmtR(sMpa) + &#x27; MPa) is far from typical &#x27; + W.name.toLowerCase() + &#x27; (~&#x27; + typ + &#x27; MPa). Check the material selection and unit.&#x27;);&#10;        }&#10;      } else {&#10;        addF(&#x27;Strength \/ hardness&#x27;, &#x27;Typical (~&#x27; + typ + &#x27; MPa)&#x27;, 1, &#x27;No value entered&#x27;);&#10;        steps.push(&#x27;Strength factor = 1 (typical value assumed)&#x27;);&#10;      }&#10;      if (wm === &#x27;custom&#x27;) { indicative = true; }&#10;&#10;      \/\/ Coating&#10;      var fc = co === &#x27;custom&#x27; ? cf : CONFIG.coating[co].f;&#10;      addF(&#x27;Coating&#x27;, co === &#x27;custom&#x27; ? &#x27;Custom&#x27; : CONFIG.coating[co].name, fc, co === &#x27;custom&#x27; ? &#x27;User-entered factor&#x27; : &#x27;Typical improvement vs. uncoated&#x27;);&#10;      steps.push(&#x27;Coating factor = &#x27; + g(fc));&#10;      if (co === &#x27;custom&#x27;) indicative = true;&#10;&#10;      \/\/ Lubrication&#10;      var fl = CONFIG.lube[lu].f;&#10;      addF(&#x27;Lubrication&#x27;, CONFIG.lube[lu].name, fl, &#x27;Galling \/ adhesive wear&#x27;);&#10;      steps.push(&#x27;Lubrication factor = &#x27; + g(fl));&#10;&#10;      \/\/ Frequency&#10;      var ff = 1;&#10;      if (spm != null &amp;&amp; spm &gt; CONFIG.freqRefSpm) ff = Math.max(CONFIG.freqMin, Math.pow(CONFIG.freqRefSpm \/ spm, CONFIG.freqExp));&#10;      addF(&#x27;Punching frequency&#x27;, spm == null ? &#x27;Not given&#x27; : g(spm) + &#x27; strokes\/min&#x27;, ff,&#10;        spm == null ? &#x27;Assumed \u2264 &#x27; + CONFIG.freqRefSpm + &#x27; spm&#x27; : (spm &gt; CONFIG.freqRefSpm ? &#x27;(&#x27; + CONFIG.freqRefSpm + &#x27; \/ spm)^&#x27; + CONFIG.freqExp + &#x27;, min &#x27; + CONFIG.freqMin : &#x27;No heat penalty at \u2264 &#x27; + CONFIG.freqRefSpm + &#x27; spm&#x27;));&#10;      steps.push(&#x27;Frequency factor = &#x27; + g(ff));&#10;    }&#10;&#10;    \/\/ Tool condition (always)&#10;    var fm = CONFIG.condition[tc].f;&#10;    addF(&#x27;Tool condition&#x27;, CONFIG.condition[tc].name, fm, &#x27;Share of regrind interval remaining&#x27;);&#10;    steps.push(&#x27;Condition factor = &#x27; + g(fm));&#10;&#10;    var L = Lref;&#10;    factors.forEach(function (x) { L *= x.f; });&#10;    var parts = [fmtInt(Lref)].concat(factors.map(function (x) { return g(x.f); }));&#10;    steps.push(&#x27;Estimated life = &#x27; + parts.join(&#x27; \u00d7 &#x27;) + &#x27; = &#x27; + fmtInt(L) + &#x27; \u2192 \u2248 &#x27; + fmtR(L) + &#x27; hits&#x27;);&#10;&#10;    var conf = useBaseline &amp;&amp; !indicative ? &#x27;baseline&#x27; : (indicative ? &#x27;indicative&#x27; : &#x27;reference&#x27;);&#10;    var rg = CONFIG.range[conf];&#10;&#10;    \/* ---- time-based results ---- *\/&#10;    var R = { L: L, conf: conf, rg: rg, steps: steps, rows: rows, warn: warn, factors: factors };&#10;    if (spm != null) {&#10;      R.hours = L \/ (spm * 60);&#10;      steps.push(&#x27;Operating hours = &#x27; + fmtInt(L) + &#x27; \/ (&#x27; + g(spm) + &#x27; \u00d7 60) = &#x27; + g(R.hours) + &#x27; h&#x27;);&#10;    }&#10;    if (hs != null) {&#10;      R.shifts = L \/ hs;&#10;      steps.push(&#x27;Shifts = &#x27; + fmtInt(L) + &#x27; \/ &#x27; + fmtInt(hs) + &#x27; = &#x27; + g(R.shifts));&#10;      if (sd != null) {&#10;        R.days = R.shifts \/ sd;&#10;        steps.push(&#x27;Days = &#x27; + g(R.shifts) + &#x27; \/ &#x27; + g(sd) + &#x27; = &#x27; + g(R.days));&#10;      }&#10;      if (spm != null &amp;&amp; hs \/ spm \/ 60 &gt; 12) warn.push(&#x27;Hits per shift implies more than 12 hours of continuous punching at the frequency entered \u2014 check the schedule values.&#x27;);&#10;    }&#10;    if (useBaseline &amp;&amp; !asIs &amp;&amp; pm !== &#x27;custom&#x27;) R.note = &#x27;Baseline replaces the built-in &#x27; + P.name + &#x27; reference.&#x27;;&#10;    R.useBaseline = useBaseline; R.asIs = asIs; R.wm = wm; R.pm = pm;&#10;    render(R);&#10;    return true;&#10;  }&#10;&#10;  \/* ---------- rendering ---------- *\/&#10;  function showErrors(errs) {&#10;    var box = $(&#x27;ptl-error&#x27;);&#10;    box.innerHTML = &#x27;&lt;strong&gt;Please correct the following input&#x27; + (errs.length &gt; 1 ? &#x27;s&#x27; : &#x27;&#x27;) + &#x27;:&lt;\/strong&gt;&lt;ul&gt;&#x27; +&#10;      errs.map(function (e) { return &#x27;&lt;li&gt;&#x27; + esc(e) + &#x27;&lt;\/li&gt;&#x27;; }).join(&#x27;&#x27;) + &#x27;&lt;\/ul&gt;&#x27;;&#10;    box.hidden = false;&#10;    $(&#x27;ptl-body&#x27;).hidden = true;&#10;  }&#10;&#10;  function setCard(id, val, unit, note, na) {&#10;    var c = $(&#x27;ptl-c-&#x27; + id);&#10;    c.classList.toggle(&#x27;ptl-na&#x27;, !!na);&#10;    $(&#x27;ptl-r-&#x27; + id).innerHTML = na ? esc(val) : esc(val) + (unit ? &#x27;&lt;small&gt;&#x27; + esc(unit) + &#x27;&lt;\/small&gt;&#x27; : &#x27;&#x27;);&#10;    $(&#x27;ptl-r-&#x27; + id + &#x27;-n&#x27;).textContent = note || &#x27;&#x27;;&#10;  }&#10;&#10;  function render(R) {&#10;    $(&#x27;ptl-error&#x27;).hidden = true;&#10;    $(&#x27;ptl-body&#x27;).hidden = false;&#10;&#10;    $(&#x27;ptl-r-hits&#x27;).textContent = fmtR(R.L);&#10;    $(&#x27;ptl-r-range&#x27;).textContent = &#x27;Likely range: &#x27; + fmtR(R.L * R.rg[0]) + &#x27; \u2013 &#x27; + fmtR(R.L * R.rg[1]) + &#x27; hits&#x27;;&#10;    var confText = {&#10;      baseline: &#x27;Based on your baseline&#x27;,&#10;      reference: &#x27;Based on typical reference data&#x27;,&#10;      indicative: &#x27;Indicative only \u2014 limited reference data&#x27;&#10;    }[R.conf];&#10;    $(&#x27;ptl-r-conf&#x27;).textContent = confText;&#10;&#10;    if (R.hours != null) {&#10;      var h = R.hours;&#10;      setCard(&#x27;hours&#x27;, h &lt; 10 ? (Math.round(h * 10) \/ 10).toLocaleString(&#x27;en-US&#x27;) : fmtR(h), &#x27;h&#x27;, h &gt;= 24 ? &#x27;\u2248 &#x27; + fmtR(h \/ 24) + &#x27; days of continuous running&#x27; : &#x27;Continuous punching time&#x27;);&#10;    } else setCard(&#x27;hours&#x27;, &#x27;Not calculated&#x27;, &#x27;&#x27;, &#x27;Enter a punching frequency.&#x27;, true);&#10;&#10;    if (R.shifts != null) {&#10;      setCard(&#x27;shifts&#x27;, R.shifts &lt; 10 ? (Math.round(R.shifts * 10) \/ 10).toLocaleString(&#x27;en-US&#x27;) : fmtR(R.shifts), &#x27;shifts&#x27;, &#x27;At the hits per shift entered&#x27;);&#10;    } else setCard(&#x27;shifts&#x27;, &#x27;Not calculated&#x27;, &#x27;&#x27;, &#x27;Enter hits per shift.&#x27;, true);&#10;&#10;    if (R.days != null) {&#10;      setCard(&#x27;days&#x27;, R.days &lt; 10 ? (Math.round(R.days * 10) \/ 10).toLocaleString(&#x27;en-US&#x27;) : fmtR(R.days), &#x27;days&#x27;, R.days &gt;= 5 ? &#x27;\u2248 &#x27; + fmtR(R.days \/ 5) + &#x27; five-day weeks&#x27; : &#x27;Production days&#x27;);&#10;    } else setCard(&#x27;days&#x27;, &#x27;Not calculated&#x27;, &#x27;&#x27;, &#x27;Enter hits per shift and shifts per day.&#x27;, true);&#10;&#10;    \/\/ Warnings&#10;    var warn = R.warn.slice();&#10;    if (R.conf === &#x27;indicative&#x27; &amp;&amp; !R.useBaseline) warn.unshift(&#x27;Reliable reference data is not available for some inputs. The result is indicative \u2014 enter a known baseline hit count from your own records for a better estimate.&#x27;);&#10;    var wb = $(&#x27;ptl-warn&#x27;);&#10;    if (warn.length) {&#10;      wb.innerHTML = &#x27;&lt;strong&gt;Notes on this estimate:&lt;\/strong&gt;&lt;ul&gt;&#x27; + warn.map(function (w) { return &#x27;&lt;li&gt;&#x27; + esc(w) + &#x27;&lt;\/li&gt;&#x27;; }).join(&#x27;&#x27;) + &#x27;&lt;\/ul&gt;&#x27;;&#10;      wb.hidden = false;&#10;    } else wb.hidden = true;&#10;&#10;    \/\/ Key factors: largest effects (by log magnitude), including the workpiece choice&#10;    var all = R.factors.slice();&#10;    if (!R.useBaseline &amp;&amp; R.wm !== &#x27;mild&#x27;) all.push({ name: &#x27;Workpiece material&#x27;, f: CONFIG.work[R.wm].factor });&#10;    all = all.filter(function (x) { return Math.abs(Math.log(x.f)) &gt; 0.05; })&#10;             .sort(function (a, b) { return Math.abs(Math.log(b.f)) - Math.abs(Math.log(a.f)); }).slice(0, 4);&#10;    var keys = all.map(function (x) {&#10;      var up = x.f &gt; 1;&#10;      var txt = up ? &#x27;increases life about &#x27; + g(x.f) + &#x27;\u00d7&#x27; : &#x27;reduces life by about &#x27; + Math.round((1 - x.f) * 100) + &#x27;%&#x27;;&#10;      return &#x27;&lt;li&gt;&lt;strong&gt;&#x27; + esc(x.name) + &#x27;&lt;\/strong&gt; &lt;span class=&quot;&#x27; + (up ? &#x27;ptl-up&#x27; : &#x27;ptl-down&#x27;) + &#x27;&quot;&gt;&#x27; + (up ? &#x27;\u25b2 &#x27; : &#x27;\u25bc &#x27;) + esc(txt) + &#x27;&lt;\/span&gt;&lt;\/li&gt;&#x27;;&#10;    });&#10;    if (!keys.length) keys.push(&#x27;&lt;li&gt;All inputs are at or near the reference conditions, so the estimate equals the reference life.&lt;\/li&gt;&#x27;);&#10;    if (R.useBaseline) keys.push(&#x27;&lt;li&gt;&lt;strong&gt;Baseline&lt;\/strong&gt; \u2014 your recorded hit count sets the starting point&#x27; + (R.asIs ? &#x27; and is used as-is&#x27; : &#x27;&#x27;) + &#x27;.&lt;\/li&gt;&#x27;);&#10;    $(&#x27;ptl-keys&#x27;).innerHTML = keys.join(&#x27;&#x27;);&#10;&#10;    \/\/ Factor table&#10;    $(&#x27;ptl-ftable&#x27;).innerHTML = R.rows.map(function (r) {&#10;      return &#x27;&lt;tr&gt;&lt;th scope=&quot;row&quot;&gt;&#x27; + esc(r[0]) + &#x27;&lt;\/th&gt;&lt;td&gt;&#x27; + esc(r[1]) + &#x27;&lt;\/td&gt;&lt;td class=&quot;ptl-num&quot;&gt;&#x27; + esc(r[2]) + &#x27;&lt;\/td&gt;&lt;td&gt;&#x27; + esc(r[3]) + &#x27;&lt;\/td&gt;&lt;\/tr&gt;&#x27;;&#10;    }).join(&#x27;&#x27;);&#10;&#10;    \/\/ Steps&#10;    $(&#x27;ptl-steps&#x27;).innerHTML = R.steps.map(function (s) { return &#x27;&lt;li&gt;&#x27; + esc(s) + &#x27;&lt;\/li&gt;&#x27;; }).join(&#x27;&#x27;);&#10;&#10;    \/\/ Assumptions&#10;    var a = [&#10;      &#x27;&quot;Tool life&quot; means hits until the punch needs regrinding (one sharpening interval), not total life across all regrinds.&#x27;,&#10;      &#x27;Reference conditions: &#x27; + CONFIG.refThicknessMm + &#x27; mm sheet, typical strength for the material, uncoated punch, regular lubrication, \u2264 &#x27; + CONFIG.freqRefSpm + &#x27; strokes\/min, sharp tool.&#x27;,&#10;      &#x27;Correct die clearance (roughly 5\u201312% of thickness per side depending on material), good alignment and a rigid press are assumed.&#x27;,&#10;      &#x27;Factors are multiplied together and treated as independent; real effects interact.&#x27;,&#10;      &#x27;Reference hit counts and factors are typical planning values, not supplier guarantees. Results are rounded to 2 significant figures.&#x27;&#10;    ];&#10;    $(&#x27;ptl-assume&#x27;).innerHTML = a.map(function (s) { return &#x27;&lt;li&gt;&#x27; + esc(s) + &#x27;&lt;\/li&gt;&#x27;; }).join(&#x27;&#x27;);&#10;  }&#10;&#10;  function hideResults() { $(&#x27;ptl-results&#x27;).hidden = true; $(&#x27;ptl-error&#x27;).hidden = true; }&#10;&#10;  \/* ---------- unit switching (converts entered values) ---------- *\/&#10;  function convertField(id, factor) {&#10;    var p = parseNum($(id).value);&#10;    if (p.ok &amp;&amp; p.n &gt; 0) $(id).value = String(Number((p.n * factor).toPrecision(4)));&#10;  }&#10;  $(&#x27;ptl-tu&#x27;).addEventListener(&#x27;change&#x27;, function () {&#10;    if (this.value === tUnit) return;&#10;    convertField(&#x27;ptl-t&#x27;, this.value === &#x27;in&#x27; ? 1 \/ MM_PER_IN : MM_PER_IN);&#10;    tUnit = this.value; setErr(&#x27;t&#x27;, null);&#10;  });&#10;  $(&#x27;ptl-fu&#x27;).addEventListener(&#x27;change&#x27;, function () {&#10;    if (this.value === fUnit) return;&#10;    convertField(&#x27;ptl-f&#x27;, this.value === &#x27;cph&#x27; ? 60 : 1 \/ 60);&#10;    fUnit = this.value; setErr(&#x27;f&#x27;, null);&#10;  });&#10;  $(&#x27;ptl-su&#x27;).addEventListener(&#x27;change&#x27;, function () { setErr(&#x27;s&#x27;, null); updateUI(); });&#10;  [&#x27;ptl-wm&#x27;, &#x27;ptl-pm&#x27;, &#x27;ptl-co&#x27;].forEach(function (id) {&#10;    $(id).addEventListener(&#x27;change&#x27;, function () { updateUI(); });&#10;  });&#10;&#10;  \/\/ Clear an inline error once the field becomes valid-looking&#10;  root.addEventListener(&#x27;input&#x27;, function (e) {&#10;    var t = e.target;&#10;    if (t.classList &amp;&amp; t.classList.contains(&#x27;ptl-invalid&#x27;)) {&#10;      var p = parseNum(t.value);&#10;      if (p.ok &amp;&amp; p.n &gt; 0) setErr(t.id.replace(&#x27;ptl-&#x27;, &#x27;&#x27;), null);&#10;    }&#10;  });&#10;&#10;  \/* ---------- fill helpers ---------- *\/&#10;  function fill(v) {&#10;    $(&#x27;ptl-wm&#x27;).value = v.wm; $(&#x27;ptl-t&#x27;).value = v.t; $(&#x27;ptl-tu&#x27;).value = v.tu; tUnit = v.tu;&#10;    $(&#x27;ptl-s&#x27;).value = v.s; $(&#x27;ptl-su&#x27;).value = v.su; $(&#x27;ptl-pm&#x27;).value = v.pm; $(&#x27;ptl-co&#x27;).value = v.co;&#10;    $(&#x27;ptl-cf&#x27;).value = v.cf; $(&#x27;ptl-tc&#x27;).value = v.tc; $(&#x27;ptl-lu&#x27;).value = v.lu;&#10;    $(&#x27;ptl-f&#x27;).value = v.f; $(&#x27;ptl-fu&#x27;).value = v.fu; fUnit = v.fu;&#10;    $(&#x27;ptl-b&#x27;).value = v.b; $(&#x27;ptl-bm&#x27;).value = v.bm; $(&#x27;ptl-hs&#x27;).value = v.hs; $(&#x27;ptl-sd&#x27;).value = v.sd;&#10;    clearErrs(); updateUI(); hideResults();&#10;  }&#10;&#10;&#10;  $(&#x27;ptl-form&#x27;).addEventListener(&#x27;submit&#x27;, function (e) {&#10;    e.preventDefault();&#10;    var res = $(&#x27;ptl-results&#x27;);&#10;    res.hidden = false;&#10;    var ok = compute();&#10;    if (!ok) {&#10;      var bad = root.querySelector(&#x27;.ptl-invalid&#x27;);&#10;      if (bad) bad.focus();&#10;    } else {&#10;      if (res.scrollIntoView) res.scrollIntoView({ behavior: &#x27;smooth&#x27;, block: &#x27;start&#x27; });&#10;      try { res.focus({ preventScroll: true }); } catch (err) { res.focus(); }&#10;    }&#10;  });&#10;&#10;  fill(DEFAULTS);&#10;})();&#10;&lt;\/script&gt;&#10;&lt;script&gt;&#10;\/* Auto-fit height when embedded in an iframe (e.g. WordPress via srcdoc). Harmless when opened directly. *\/&#10;(function () {&#10;  var f = null;&#10;  try { f = window.frameElement; } catch (e) { f = null; }&#10;  if (!f) return;&#10;  var root = document.getElementById(&#x27;ptl-app&#x27;);&#10;  function fit() {&#10;    var h = Math.ceil((root || document.body).getBoundingClientRect().height);&#10;    if (h &gt; 0) f.style.setProperty(&#x27;height&#x27;, h + &#x27;px&#x27;, &#x27;important&#x27;);&#10;  }&#10;  fit();&#10;  if (window.ResizeObserver) new ResizeObserver(fit).observe(root || document.body);&#10;  window.addEventListener(&#x27;load&#x27;, fit);&#10;  window.addEventListener(&#x27;resize&#x27;, fit);&#10;  setTimeout(fit, 300);&#10;})();&#10;&lt;\/script&gt;&#10;&lt;\/body&gt;&#10;&lt;\/html&gt;&#10;\"><\/iframe>\n","protected":false},"excerpt":{"rendered":"<p>The Punch Tool Life Estimator Calculator provides an approximate estimate of punch tool life based on material properties, sheet thickness, punch grade, coating, lubrication, and&#8230;<\/p>","protected":false},"author":2,"featured_media":25072,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"pmpro_default_level":"","_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_hide_featured_image":false,"_jetpack_featured_image_duplicate_dismissed":0,"_jetpack_feature_clip_id":0,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_post_was_ever_published":false},"categories":[8808],"tags":[8840,8841,2396,8842],"class_list":["post-25071","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-manufacturing-and-processes","tag-punch-tool-life","tag-punching","tag-sheet-metal","tag-tool-maintenance","pmpro-has-access"],"acf":[],"jetpack_sharing_enabled":true,"jetpack_featured_media_url":"https:\/\/www.mechstream.com\/wp-content\/uploads\/2026\/11\/Punch-Tool-Life-Estimator-Calculator.png","_links":{"self":[{"href":"https:\/\/www.mechstream.com\/fr\/wp-json\/wp\/v2\/posts\/25071","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.mechstream.com\/fr\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.mechstream.com\/fr\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.mechstream.com\/fr\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.mechstream.com\/fr\/wp-json\/wp\/v2\/comments?post=25071"}],"version-history":[{"count":1,"href":"https:\/\/www.mechstream.com\/fr\/wp-json\/wp\/v2\/posts\/25071\/revisions"}],"predecessor-version":[{"id":25073,"href":"https:\/\/www.mechstream.com\/fr\/wp-json\/wp\/v2\/posts\/25071\/revisions\/25073"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.mechstream.com\/fr\/wp-json\/wp\/v2\/media\/25072"}],"wp:attachment":[{"href":"https:\/\/www.mechstream.com\/fr\/wp-json\/wp\/v2\/media?parent=25071"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.mechstream.com\/fr\/wp-json\/wp\/v2\/categories?post=25071"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.mechstream.com\/fr\/wp-json\/wp\/v2\/tags?post=25071"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}