{"id":131,"date":"2026-03-03T17:48:39","date_gmt":"2026-03-03T17:48:39","guid":{"rendered":"https:\/\/primetoolhub.com\/?page_id=131"},"modified":"2026-07-15T05:48:06","modified_gmt":"2026-07-15T05:48:06","slug":"advanced-k-map-solver","status":"publish","type":"page","link":"https:\/\/schoolict.net\/tools\/advanced-k-map-solver\/","title":{"rendered":"Ultimate K-Map Solver Pro: Karnaugh Map Calculator | 2 to 6 Variable Boolean Minimizer"},"content":{"rendered":"\n<div class=\"pth-hero-section\">\n    <div class=\"pth-hero-content\">\n        <h2>Ultimate K-Map Solver Pro: Karnaugh Map Calculator <\/h2>\n        <p>100% offline, lightning-fast K-Map solver. Visualize 2 to 6 variable Karnaugh maps, generate optimized Boolean expressions (SOP\/POS), and export Verilog HDL code instantly.<\/p>\n\n        <div id=\"pth-toc-placeholder\"><\/div>\n    <\/div>\n\n    <div class=\"pth-hero-image\">\n        <img decoding=\"async\" data-no-lazy=\"1\" width=\"450\" height=\"253\" src=\"https:\/\/schoolict.net\/tools\/wp-content\/uploads\/2026\/03\/K-Map-Solver-Pro-1024x572.jpeg\" alt=\"K-Map Solver Pro\">\n    <\/div>\n<\/div>\n\n\n\n<div class=\"wp-block-rank-math-toc-block\" id=\"rank-math-toc\"><h2>Table of Contents<\/h2><nav><ul><li><a href=\"#\ud83d\udd34-how-the-quine-mc-cluskey-algorithm-works-step-by-step\">\ud83d\udd34 How the Quine-McCluskey Algorithm Works \u2014 Step by Step<\/a><\/li><li><a href=\"#\ud83d\udfe1-k-map-grouping-rules-what-makes-a-valid-group-and-why-size-matters\">\ud83d\udfe1 K-Map Grouping Rules \u2014 What Makes a Valid Group and Why Size Matters<\/a><ul><li><a href=\"#\ud83d\udfe2-petricks-method-vs-greedy-when-the-difference-matters\">\ud83d\udfe2 Petrick&#8217;s Method vs Greedy \u2014 When the Difference Matters<\/a><\/li><\/ul><\/li><li><a href=\"#\ud83d\udfe1-hdl-output-formats-what-each-language-is-used-for\">\ud83d\udfe1 HDL Output Formats \u2014 What Each Language Is Used For<\/a><\/li><\/ul><\/nav><\/div>\n\n\n<style>\r\n\/* ============================================================\r\n   PTH DIGITAL LOGIC STUDIO PRO \u2014 v2.0\r\n   PageSpeed 100 + WCAG 2.1 AA + WP\/LiteSpeed Safe\r\n   4 Tabs | 22 Tools | 100% Offline | Zero CDN\r\n   ============================================================ *\/\r\n#pth-logic-wrapper {\r\n    font-family: 'Inter', system-ui, sans-serif;\r\n    width: 100%; max-width: 1400px; margin: 0 auto;\r\n    box-sizing: border-box; background: #f8fafc;\r\n    padding: 20px; border-radius: 16px; color: #1e293b;\r\n}\r\n#pth-logic-wrapper * { box-sizing: border-box; min-width: 0; }\r\n#pth-logic-wrapper h2,\r\n#pth-logic-wrapper h3 { color: #0f172a; font-weight: 800; margin-top: 0; }\r\n#pth-logic-wrapper .pth-tool-title { font-size: 24px; font-weight: 800; color: #1d4ed8; margin: 0; }\r\n\r\n\/* \u2500\u2500 Cards \u2500\u2500 *\/\r\n#pth-logic-wrapper .pth-card {\r\n    background: #fff; border: 1px solid #e2e8f0;\r\n    border-radius: 12px; padding: 18px; margin-bottom: 14px;\r\n    box-shadow: 0 2px 4px rgba(0,0,0,0.04);\r\n}\r\n#pth-logic-wrapper .pth-card-hdr {\r\n    background: #f8fafc; margin: -18px -18px 14px -18px;\r\n    padding: 9px 14px; color: #1d4ed8; font-size: 11px;\r\n    border-bottom: 2px solid #eff6ff; font-weight: 800;\r\n    text-transform: uppercase; border-radius: 12px 12px 0 0;\r\n    letter-spacing: 0.5px;\r\n}\r\n\r\n\/* \u2500\u2500 Meta bar \u2500\u2500 *\/\r\n#pth-logic-wrapper .pth-tool-meta-bar {\r\n    display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-bottom: 14px;\r\n}\r\n#pth-logic-wrapper .pth-version-badge {\r\n    background: #eff6ff; color: #1d4ed8; border: 1px solid #bfdbfe;\r\n    font-size: 11px; font-weight: 700; padding: 2px 8px; border-radius: 4px;\r\n}\r\n#pth-logic-wrapper .pth-status-offline {\r\n    background: #f0fdf4; color: #15803d; border: 1px solid #bbf7d0;\r\n    font-size: 11px; font-weight: 700; padding: 2px 8px; border-radius: 4px;\r\n}\r\n\r\n\/* \u2500\u2500 Layout \u2500\u2500 *\/\r\n#pth-logic-wrapper .pth-flex-layout {\r\n    display: grid; grid-template-columns: 1.8fr 1fr; gap: 18px; align-items: start;\r\n}\r\n#pth-logic-wrapper .pth-flex-layout.pth-full-width { grid-template-columns: 100%; }\r\n\r\n\/* \u2500\u2500 Tabs \u2500\u2500 *\/\r\n#pth-logic-wrapper .pth-tabs-nav {\r\n    display: flex; gap: 3px; flex-wrap: wrap;\r\n    margin-bottom: 18px; border-bottom: 2px solid #e2e8f0;\r\n}\r\n#pth-logic-wrapper .pth-tab-btn {\r\n    padding: 7px 13px; border-radius: 8px 8px 0 0;\r\n    font-size: 11px; font-weight: 700; cursor: pointer;\r\n    border: 2px solid transparent; border-bottom: none;\r\n    background: #f1f5f9; color: #334155;\r\n    transition: 0.15s; font-family: 'Inter', sans-serif;\r\n    margin-bottom: -2px; white-space: nowrap;\r\n}\r\n#pth-logic-wrapper .pth-tab-btn:hover { background: #e2e8f0; color: #0f172a; }\r\n#pth-logic-wrapper .pth-tab-btn.pth-active {\r\n    background: #fff; color: #1d4ed8;\r\n    border-color: #e2e8f0; border-bottom-color: #fff;\r\n}\r\n\r\n\/* \u2500\u2500 Buttons \u2500\u2500 *\/\r\n#pth-logic-wrapper .pth-btn {\r\n    padding: 8px 16px; border-radius: 8px; font-weight: 700;\r\n    cursor: pointer; border: none; font-family: 'Inter', sans-serif;\r\n    font-size: 12px; transition: 0.2s; display: inline-flex;\r\n    align-items: center; justify-content: center; gap: 5px;\r\n}\r\n#pth-logic-wrapper .pth-btn-primary { background: #2563eb; color: #fff; }\r\n#pth-logic-wrapper .pth-btn-primary:hover { background: #1d4ed8; }\r\n#pth-logic-wrapper .pth-btn-secondary {\r\n    background: #f1f5f9; color: #334155; border: 1px solid #e2e8f0;\r\n}\r\n#pth-logic-wrapper .pth-btn-secondary:hover { background: #e2e8f0; }\r\n#pth-logic-wrapper .pth-btn-success { background: #059669; color: #fff; }\r\n#pth-logic-wrapper .pth-btn-success:hover { background: #047857; }\r\n#pth-logic-wrapper .pth-btn-danger {\r\n    background: #fef2f2; color: #991b1b; border: 1px solid #fecaca;\r\n}\r\n#pth-logic-wrapper .pth-btn-danger:hover { background: #fee2e2; }\r\n#pth-logic-wrapper .pth-sample-btn {\r\n    background: #d1fae5; color: #047857; border: 1px solid #10b981;\r\n    font-size: 0.7rem; padding: 3px 8px; border-radius: 5px;\r\n    font-weight: 700; cursor: pointer; transition: 0.2s;\r\n    display: inline-flex; align-items: center; gap: 4px;\r\n}\r\n#pth-logic-wrapper .pth-sample-btn:hover { background: #a7f3d0; }\r\n\r\n\/* \u2500\u2500 Form elements \u2500\u2500 *\/\r\n#pth-logic-wrapper label {\r\n    font-weight: 700; color: #0f172a; margin-bottom: 4px;\r\n    display: block; font-size: 11px;\r\n    text-transform: uppercase; letter-spacing: 0.4px;\r\n}\r\n#pth-logic-wrapper input[type=\"text\"],\r\n#pth-logic-wrapper input[type=\"number\"],\r\n#pth-logic-wrapper select,\r\n#pth-logic-wrapper textarea {\r\n    width: 100%; padding: 8px 10px; border: 2px solid #e2e8f0;\r\n    border-radius: 7px; font-family: 'Inter', sans-serif;\r\n    font-size: 12px; color: #0f172a; background: #fff; transition: 0.2s;\r\n}\r\n#pth-logic-wrapper input:focus,\r\n#pth-logic-wrapper select:focus,\r\n#pth-logic-wrapper textarea:focus {\r\n    border-color: #3b82f6; outline: none;\r\n    box-shadow: 0 0 0 3px rgba(59,130,246,0.1);\r\n}\r\n#pth-logic-wrapper .pth-field { margin-bottom: 12px; }\r\n#pth-logic-wrapper .pth-row-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }\r\n#pth-logic-wrapper .pth-row-3 { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 8px; }\r\n\r\n\/* \u2500\u2500 Truth table \u2500\u2500 *\/\r\n#pth-logic-wrapper .pth-table-wrap {\r\n    overflow-x: auto; border: 1px solid #e2e8f0;\r\n    border-radius: 10px; max-height: 340px; overflow-y: auto;\r\n    background: #fff;\r\n}\r\n#pth-logic-wrapper .pth-truth-table {\r\n    width: 100%; border-collapse: collapse; text-align: center;\r\n    font-size: 12px;\r\n}\r\n#pth-logic-wrapper .pth-truth-table th {\r\n    background: #f8fafc; padding: 8px 12px;\r\n    border: 1px solid #e2e8f0; font-weight: 800; color: #334155;\r\n    position: sticky; top: 0; z-index: 5;\r\n}\r\n#pth-logic-wrapper .pth-truth-table td {\r\n    padding: 7px 10px; border: 1px solid #e2e8f0;\r\n    font-weight: 600;\r\n}\r\n#pth-logic-wrapper .pth-f-cell {\r\n    cursor: pointer; user-select: none;\r\n    font-weight: 800; font-size: 14px;\r\n    transition: background 0.15s, transform 0.1s;\r\n    border-radius: 4px; padding: 4px 10px !important;\r\n}\r\n#pth-logic-wrapper .pth-f-cell:hover { transform: scale(1.08); background: #f1f5f9 !important; }\r\n#pth-logic-wrapper .pth-f-0 { color: #991b1b; }\r\n#pth-logic-wrapper .pth-f-1 { color: #047857; }\r\n#pth-logic-wrapper .pth-f-x { color: #92400e; }\r\n\r\n\/* \u2500\u2500 K-Map Grid \u2500\u2500 *\/\r\n#pth-logic-wrapper .pth-kmap-area {\r\n    display: flex; flex-wrap: wrap; gap: 30px;\r\n    justify-content: center; min-height: 180px; align-items: flex-start;\r\n    padding: 10px 0;\r\n}\r\n#pth-logic-wrapper .pth-kmap-wrap { text-align: center; }\r\n#pth-logic-wrapper .pth-kmap-map-lbl {\r\n    font-size: 12px; font-weight: 800; color: #1d4ed8;\r\n    margin-bottom: 8px; background: #eff6ff; padding: 2px 8px;\r\n    border-radius: 4px; display: inline-block;\r\n}\r\n#pth-logic-wrapper .pth-kmap-tbl {\r\n    border-collapse: collapse; border: 2px solid #334155;\r\n    background: #fff; box-shadow: 0 2px 6px rgba(0,0,0,0.06);\r\n}\r\n#pth-logic-wrapper .pth-kmap-tbl th {\r\n    background: #f8fafc; padding: 8px 10px;\r\n    border: 1px solid #e2e8f0; font-size: 11px;\r\n    font-weight: 800; color: #334155; min-width: 44px;\r\n}\r\n#pth-logic-wrapper .pth-kmap-tbl td {\r\n    width: 52px; height: 52px; border: 1px solid #e2e8f0;\r\n    text-align: center; vertical-align: middle;\r\n    font-size: 13px; font-weight: 700; cursor: default;\r\n    transition: background 0.2s;\r\n    position: relative;\r\n}\r\n#pth-logic-wrapper .pth-kmap-val { display: block; font-size: 15px; }\r\n#pth-logic-wrapper .pth-kmap-idx {\r\n    display: block; font-size: 9px; color: #334155;\r\n    font-weight: 500; position: absolute; bottom: 2px; right: 3px;\r\n}\r\n#pth-logic-wrapper .pth-cell-1 { background: #f0fdf4 !important; }\r\n#pth-logic-wrapper .pth-cell-x { background: #fff7ed !important; }\r\n\r\n\/* \u2500\u2500 Group legend \u2500\u2500 *\/\r\n#pth-logic-wrapper .pth-group-legend {\r\n    display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 12px;\r\n}\r\n#pth-logic-wrapper .pth-legend-item {\r\n    display: flex; align-items: center; gap: 5px;\r\n    font-size: 11px; font-weight: 700; color: #334155;\r\n}\r\n#pth-logic-wrapper .pth-legend-dot {\r\n    width: 14px; height: 14px; border-radius: 3px; flex-shrink: 0;\r\n}\r\n\r\n\/* \u2500\u2500 Solution trace \u2500\u2500 *\/\r\n#pth-logic-wrapper .pth-trace-step {\r\n    background: #f8fafc; border: 1px solid #e2e8f0;\r\n    border-radius: 8px; padding: 10px 12px; margin-bottom: 8px;\r\n    font-size: 12px;\r\n}\r\n#pth-logic-wrapper .pth-trace-step-num {\r\n    font-size: 10px; font-weight: 800; color: #1d4ed8;\r\n    background: #eff6ff; padding: 1px 6px; border-radius: 3px;\r\n    margin-right: 6px;\r\n}\r\n#pth-logic-wrapper .pth-trace-content { color: #1e293b; font-weight: 500; }\r\n\r\n\/* \u2500\u2500 Final equation \u2500\u2500 *\/\r\n#pth-logic-wrapper .pth-eq-display {\r\n    background: #0f172a; border-radius: 10px; padding: 14px 18px;\r\n    font-family: 'Courier New', monospace; font-size: 16px;\r\n    font-weight: 800; color: #4ade80; text-align: center;\r\n    letter-spacing: 0.5px; min-height: 50px; margin-bottom: 12px;\r\n    display: flex; align-items: center; justify-content: center;\r\n    word-break: break-all;\r\n}\r\n\r\n\/* \u2500\u2500 Group cards \u2500\u2500 *\/\r\n#pth-logic-wrapper .pth-group-cards {\r\n    display: grid; grid-template-columns: 1fr 1fr; gap: 8px;\r\n}\r\n#pth-logic-wrapper .pth-group-card {\r\n    padding: 10px 12px; border-radius: 8px;\r\n    border: 1px solid #e2e8f0; border-left-width: 5px;\r\n    background: #fff; transition: 0.15s; cursor: pointer;\r\n}\r\n#pth-logic-wrapper .pth-group-card:hover {\r\n    transform: translateY(-2px);\r\n    box-shadow: 0 4px 8px rgba(0,0,0,0.08);\r\n}\r\n#pth-logic-wrapper .pth-group-term {\r\n    font-family: 'Courier New', monospace; font-size: 14px;\r\n    font-weight: 800; margin-bottom: 3px;\r\n}\r\n#pth-logic-wrapper .pth-group-meta {\r\n    font-size: 10px; font-weight: 600; color: #334155;\r\n}\r\n\r\n\/* \u2500\u2500 Boolean tools \u2500\u2500 *\/\r\n#pth-logic-wrapper .pth-expr-input {\r\n    font-family: 'Courier New', monospace !important;\r\n    font-size: 14px !important; letter-spacing: 0.5px;\r\n}\r\n#pth-logic-wrapper .pth-bool-result {\r\n    background: #f8fafc; border: 2px solid #e2e8f0;\r\n    border-radius: 8px; padding: 12px; font-size: 13px;\r\n    font-family: 'Courier New', monospace; color: #0f172a;\r\n    min-height: 60px; line-height: 1.8; white-space: pre-wrap;\r\n}\r\n\r\n\/* \u2500\u2500 Gate simulator \u2500\u2500 *\/\r\n#pth-logic-wrapper .pth-gate-row {\r\n    display: flex; align-items: center; gap: 8px;\r\n    margin-bottom: 8px; padding: 8px 10px;\r\n    background: #f8fafc; border-radius: 8px; border: 1px solid #e2e8f0;\r\n    flex-wrap: wrap;\r\n}\r\n#pth-logic-wrapper .pth-gate-num {\r\n    font-size: 10px; font-weight: 800; color: #1d4ed8;\r\n    background: #eff6ff; padding: 2px 7px; border-radius: 4px;\r\n    min-width: 30px; text-align: center;\r\n}\r\n#pth-logic-wrapper .pth-gate-type-sel {\r\n    width: 110px !important; font-size: 11px !important;\r\n    padding: 5px 6px !important;\r\n}\r\n#pth-logic-wrapper .pth-gate-input-sel {\r\n    width: 80px !important; font-size: 11px !important;\r\n    padding: 5px 6px !important;\r\n}\r\n#pth-logic-wrapper .pth-gate-out-badge {\r\n    padding: 3px 10px; border-radius: 4px; font-size: 12px;\r\n    font-weight: 800; font-family: 'Courier New', monospace;\r\n    min-width: 36px; text-align: center;\r\n}\r\n#pth-logic-wrapper .pth-out-0 { background: #fef2f2; color: #991b1b; }\r\n#pth-logic-wrapper .pth-out-1 { background: #f0fdf4; color: #047857; }\r\n\r\n\/* \u2500\u2500 Input toggles \u2500\u2500 *\/\r\n#pth-logic-wrapper .pth-input-toggle-row {\r\n    display: flex; gap: 8px; flex-wrap: wrap; margin-bottom: 12px;\r\n}\r\n#pth-logic-wrapper .pth-input-toggle {\r\n    width: 46px; height: 46px; border-radius: 8px;\r\n    border: 2px solid #e2e8f0; cursor: pointer;\r\n    font-size: 16px; font-weight: 800; transition: 0.15s;\r\n    font-family: 'Courier New', monospace; background: #fef2f2;\r\n    color: #991b1b; display: flex; align-items: center;\r\n    justify-content: center;\r\n}\r\n#pth-logic-wrapper .pth-input-toggle.high {\r\n    background: #f0fdf4; color: #047857; border-color: #bbf7d0;\r\n}\r\n#pth-logic-wrapper .pth-input-label {\r\n    font-size: 10px; font-weight: 700; color: #334155;\r\n    text-align: center; margin-top: 2px;\r\n}\r\n\r\n\/* \u2500\u2500 HDL code output \u2500\u2500 *\/\r\n#pth-logic-wrapper .pth-hdl-tabs {\r\n    display: flex; gap: 4px; margin-bottom: 10px; flex-wrap: wrap;\r\n}\r\n#pth-logic-wrapper .pth-hdl-tab {\r\n    padding: 4px 10px; border-radius: 5px; font-size: 10px;\r\n    font-weight: 700; cursor: pointer; border: 2px solid #e2e8f0;\r\n    background: #f8fafc; color: #334155; font-family: 'Inter', sans-serif;\r\n    transition: 0.15s;\r\n}\r\n#pth-logic-wrapper .pth-hdl-tab:hover { border-color: #2563eb; color: #1d4ed8; }\r\n#pth-logic-wrapper .pth-hdl-tab.pth-active {\r\n    background: #eff6ff; border-color: #2563eb; color: #1d4ed8;\r\n}\r\n#pth-logic-wrapper .pth-code-out {\r\n    background: #0f172a; color: #4ade80; padding: 14px;\r\n    border-radius: 10px; font-family: 'Courier New', monospace;\r\n    font-size: 11px; min-height: 160px; max-height: 320px;\r\n    overflow-y: auto; white-space: pre-wrap; word-break: break-all;\r\n    border: 2px solid #1e293b; line-height: 1.7;\r\n}\r\n\r\n\/* \u2500\u2500 Variable name inputs \u2500\u2500 *\/\r\n#pth-logic-wrapper .pth-var-names-row {\r\n    display: flex; gap: 6px; flex-wrap: wrap; margin-bottom: 12px; align-items: center;\r\n}\r\n#pth-logic-wrapper .pth-var-input {\r\n    width: 44px !important; padding: 6px 6px !important;\r\n    text-align: center !important; font-weight: 800 !important;\r\n    font-family: 'Courier New', monospace !important;\r\n    text-transform: uppercase !important; font-size: 13px !important;\r\n}\r\n\r\n\/* \u2500\u2500 Sidebar \u2500\u2500 *\/\r\n#pth-logic-wrapper .pth-sb-hdr {\r\n    background: #f8fafc; margin: -18px -18px 14px -18px;\r\n    padding: 9px 14px; color: #1d4ed8; font-size: 11px;\r\n    border-bottom: 2px solid #eff6ff; font-weight: 800;\r\n    text-transform: uppercase; border-radius: 12px 12px 0 0;\r\n    letter-spacing: 0.5px;\r\n}\r\n\r\n\/* \u2500\u2500 SOP\/POS radio \u2500\u2500 *\/\r\n#pth-logic-wrapper .pth-mode-row {\r\n    display: flex; gap: 8px; margin-bottom: 12px;\r\n}\r\n#pth-logic-wrapper .pth-mode-btn {\r\n    flex: 1; padding: 8px; border: 2px solid #e2e8f0;\r\n    border-radius: 7px; font-size: 12px; font-weight: 700;\r\n    cursor: pointer; text-align: center; background: #f8fafc;\r\n    color: #334155; transition: 0.15s; font-family: 'Inter', sans-serif;\r\n}\r\n#pth-logic-wrapper .pth-mode-btn.pth-active {\r\n    background: #eff6ff; border-color: #2563eb; color: #1d4ed8;\r\n}\r\n\r\n\/* \u2500\u2500 Toast \u2500\u2500 *\/\r\n#pth-logic-toast {\r\n    position: fixed; bottom: 24px; right: 24px; z-index: 9999;\r\n    display: flex; flex-direction: column; gap: 10px; pointer-events: none;\r\n}\r\n.pth-toast-msg {\r\n    padding: 10px 18px; border-radius: 10px; font-size: 13px;\r\n    font-weight: 600; color: #fff; pointer-events: auto;\r\n    box-shadow: 0 4px 15px rgba(0,0,0,0.15);\r\n    font-family: 'Inter', system-ui, sans-serif;\r\n}\r\n.pth-toast-success { background: #059669; }\r\n.pth-toast-error   { background: #dc2626; }\r\n.pth-toast-info    { background: #2563eb; }\r\n\r\n\/* \u2500\u2500 Mobile \u2500\u2500 *\/\r\n@media (max-width: 768px) {\r\n    #pth-logic-wrapper { padding: 10px; border-radius: 0; background: transparent; }\r\n    #pth-logic-wrapper .pth-card { padding: 12px; margin-bottom: 10px; }\r\n    #pth-logic-wrapper .pth-flex-layout { grid-template-columns: 100% !important; gap: 10px; }\r\n    #pth-logic-wrapper .pth-tool-title { font-size: 18px; }\r\n    #pth-logic-wrapper .pth-row-2 { grid-template-columns: 1fr; }\r\n    #pth-logic-wrapper .pth-row-3 { grid-template-columns: 1fr 1fr; }\r\n    #pth-logic-wrapper .pth-group-cards { grid-template-columns: 1fr; }\r\n    #pth-logic-wrapper .pth-kmap-tbl td { width: 44px; height: 44px; }\r\n    #pth-logic-wrapper .pth-tabs-nav { gap: 2px; }\r\n    #pth-logic-wrapper .pth-tab-btn { font-size: 10px; padding: 5px 8px; }\r\n}\r\n<\/style>\r\n\r\n<div id=\"pth-logic-toast\" role=\"status\" aria-live=\"polite\"><\/div>\r\n\r\n<div id=\"pth-logic-wrapper\">\r\n<div class=\"pth-flex-layout\" id=\"pth-logic-layout\">\r\n\r\n<!-- \u2550\u2550\u2550 MAIN COLUMN \u2550\u2550\u2550 -->\r\n<div class=\"pth-main-col\">\r\n<div class=\"pth-card\">\r\n\r\n    <!-- Header -->\r\n    <div style=\"display:flex;justify-content:space-between;align-items:flex-start;margin-bottom:10px;flex-wrap:wrap;gap:8px;\">\r\n        <h2 class=\"pth-tool-title\">\ud83d\udd0c Digital Logic Studio Pro<\/h2>\r\n        <button class=\"pth-btn pth-btn-secondary\" id=\"pth-dl-fw-btn\" aria-label=\"Toggle full width\">\u26f6 Full Width<\/button>\r\n    <\/div>\r\n    <div class=\"pth-tool-meta-bar\">\r\n        <span class=\"pth-version-badge\">v2.0<\/span>\r\n        <span class=\"pth-status-offline\">\ud83d\udd12 100% Offline<\/span>\r\n        <span style=\"font-size:10px;font-weight:700;color:#334155;\">4 Tabs \u00b7 22 Tools \u00b7 2\u20136 Variable K-Map<\/span>\r\n    <\/div>\r\n    <div style=\"display:flex;gap:6px;flex-wrap:wrap;margin-bottom:14px;\">\r\n        <button class=\"pth-sample-btn\" id=\"pth-dl-sample-btn\" aria-label=\"Load sample K-Map\">\ud83d\udca1 Load Sample<\/button>\r\n        <button class=\"pth-btn pth-btn-danger\" id=\"pth-dl-clear-btn\"\r\n            style=\"font-size:0.7rem;padding:3px 8px;border-radius:5px;\" aria-label=\"Clear all\">\ud83d\uddd1\ufe0f Clear<\/button>\r\n        <button class=\"pth-btn pth-btn-secondary\" id=\"pth-dl-random-btn\"\r\n            style=\"font-size:0.7rem;padding:3px 8px;border-radius:5px;\" aria-label=\"Random example\">\ud83c\udfb2 Random<\/button>\r\n        <button class=\"pth-btn pth-btn-secondary\" id=\"pth-dl-print-btn\"\r\n            style=\"font-size:0.7rem;padding:3px 8px;border-radius:5px;\" aria-label=\"Print result\">\ud83d\udda8\ufe0f Print<\/button>\r\n    <\/div>\r\n\r\n    <!-- Tab Navigation -->\r\n    <div class=\"pth-tabs-nav\" role=\"tablist\">\r\n        <button class=\"pth-tab-btn pth-active\" data-tab=\"kmap\"\r\n            role=\"tab\" aria-selected=\"true\" aria-label=\"K-Map Solver\">\ud83d\uddfa\ufe0f K-Map Solver<\/button>\r\n        <button class=\"pth-tab-btn\" data-tab=\"boolean\"\r\n            role=\"tab\" aria-selected=\"false\" aria-label=\"Boolean Expression Tools\">\u26a1 Boolean Tools<\/button>\r\n        <button class=\"pth-tab-btn\" data-tab=\"gates\"\r\n            role=\"tab\" aria-selected=\"false\" aria-label=\"Logic Gate Simulator\">\ud83d\udd0c Gate Simulator<\/button>\r\n        <button class=\"pth-tab-btn\" data-tab=\"hdl\"\r\n            role=\"tab\" aria-selected=\"false\" aria-label=\"HDL Code Generator\">\ud83d\udcbb HDL Code<\/button>\r\n    <\/div>\r\n\r\n    <!-- \u2550\u2550 TAB 1: K-MAP SOLVER \u2550\u2550 -->\r\n    <div id=\"pth-tab-kmap\" role=\"tabpanel\">\r\n        <!-- Config row -->\r\n        <div class=\"pth-card\">\r\n            <div class=\"pth-card-hdr\">\u2699\ufe0f K-Map Configuration<\/div>\r\n            <div class=\"pth-row-3\">\r\n                <div class=\"pth-field\">\r\n                    <label for=\"pth-var-count\">Variables<\/label>\r\n                    <select id=\"pth-var-count\" aria-label=\"Number of variables\">\r\n                        <option value=\"2\">2 Variables<\/option>\r\n                        <option value=\"3\">3 Variables<\/option>\r\n                        <option value=\"4\" selected>4 Variables<\/option>\r\n                        <option value=\"5\">5 Variables<\/option>\r\n                        <option value=\"6\">6 Variables<\/option>\r\n                    <\/select>\r\n                <\/div>\r\n                <div class=\"pth-field\">\r\n                    <label>Minimization Type<\/label>\r\n                    <div class=\"pth-mode-row\" role=\"group\" aria-label=\"SOP or POS mode\">\r\n                        <button class=\"pth-mode-btn pth-active\" data-mode=\"sop\"\r\n                            aria-pressed=\"true\" aria-label=\"Sum of Products mode\">SOP (\u03a3m)<\/button>\r\n                        <button class=\"pth-mode-btn\" data-mode=\"pos\"\r\n                            aria-pressed=\"false\" aria-label=\"Product of Sums mode\">POS (\u03a0M)<\/button>\r\n                    <\/div>\r\n                <\/div>\r\n                <div class=\"pth-field\">\r\n                    <label>Solution Method<\/label>\r\n                    <div class=\"pth-mode-row\" role=\"group\" aria-label=\"Solution method\">\r\n                        <button class=\"pth-mode-btn pth-active\" data-method=\"greedy\"\r\n                            aria-pressed=\"true\" aria-label=\"Greedy method\">Greedy<\/button>\r\n                        <button class=\"pth-mode-btn\" data-method=\"petrick\"\r\n                            aria-pressed=\"false\" aria-label=\"Petricks method\">Petrick's<\/button>\r\n                    <\/div>\r\n                <\/div>\r\n            <\/div>\r\n\r\n            <!-- Variable name inputs -->\r\n            <div class=\"pth-field\">\r\n                <label>Variable Names <span style=\"color:#334155;font-weight:500;text-transform:none;\">(click to rename)<\/span><\/label>\r\n                <div class=\"pth-var-names-row\" id=\"pth-var-names-row\" aria-label=\"Variable name inputs\">\r\n                    <!-- filled by JS -->\r\n                <\/div>\r\n            <\/div>\r\n        <\/div>\r\n\r\n        <!-- Truth table input -->\r\n        <div class=\"pth-card\">\r\n            <div class=\"pth-card-hdr\" style=\"display:flex;justify-content:space-between;align-items:center;\">\r\n                <span>\ud83d\udccb Truth Table \u2014 Click F to cycle 0 \u2192 1 \u2192 X \u2192 0<\/span>\r\n                <div style=\"display:flex;gap:5px;\">\r\n                    <button class=\"pth-btn pth-btn-secondary\" id=\"pth-set-all-0\" style=\"font-size:10px;padding:3px 8px;\" aria-label=\"Set all outputs to 0\">All 0<\/button>\r\n                    <button class=\"pth-btn pth-btn-secondary\" id=\"pth-set-all-1\" style=\"font-size:10px;padding:3px 8px;\" aria-label=\"Set all outputs to 1\">All 1<\/button>\r\n                <\/div>\r\n            <\/div>\r\n            <div class=\"pth-table-wrap\">\r\n                <table class=\"pth-truth-table\" id=\"pth-truth-table\" aria-label=\"Truth table input\"><\/table>\r\n            <\/div>\r\n        <\/div>\r\n\r\n        <!-- K-Map display -->\r\n        <div class=\"pth-card\">\r\n            <div class=\"pth-card-hdr\">\ud83d\uddfa\ufe0f Karnaugh Map<\/div>\r\n            <div class=\"pth-kmap-area\" id=\"pth-kmap-area\" aria-label=\"K-Map display\" role=\"img\"><\/div>\r\n        <\/div>\r\n\r\n        <!-- Solution trace -->\r\n        <div class=\"pth-card\" id=\"pth-trace-card\" style=\"display:none;\">\r\n            <div class=\"pth-card-hdr\">\ud83d\udd0d Step-by-Step Solution Trace<\/div>\r\n            <div id=\"pth-trace-steps\"><\/div>\r\n        <\/div>\r\n\r\n        <!-- Generate button -->\r\n        <button class=\"pth-btn pth-btn-primary\" id=\"pth-solve-btn\"\r\n            style=\"width:100%;padding:12px;font-size:14px;margin-bottom:14px;\"\r\n            aria-label=\"Generate K-Map solution\">\r\n            \u2728 Generate Solution\r\n        <\/button>\r\n\r\n        <!-- Results -->\r\n        <div class=\"pth-card\" id=\"pth-result-card\" style=\"display:none;\">\r\n            <div class=\"pth-card-hdr\">\u2705 Minimized Result<\/div>\r\n            <div class=\"pth-eq-display\" id=\"pth-eq-display\" aria-live=\"polite\" aria-label=\"Minimized Boolean equation\">\r\n                F = ?\r\n            <\/div>\r\n            <!-- Multiple solutions if any -->\r\n            <div id=\"pth-multi-solutions\" style=\"display:none;margin-bottom:12px;\">\r\n                <div style=\"font-size:11px;font-weight:800;color:#92400e;text-transform:uppercase;margin-bottom:6px;\">\u26a0\ufe0f Multiple Equally Minimal Solutions Found:<\/div>\r\n                <div id=\"pth-solutions-list\" style=\"font-size:12px;font-family:'Courier New',monospace;color:#0f172a;line-height:1.9;background:#fffbeb;padding:10px;border-radius:6px;border:1px solid #fde68a;\"><\/div>\r\n            <\/div>\r\n            <!-- Group legend -->\r\n            <div class=\"pth-group-legend\" id=\"pth-group-legend\"><\/div>\r\n            <!-- Group cards -->\r\n            <div class=\"pth-group-cards\" id=\"pth-group-cards\"><\/div>\r\n            <div style=\"display:flex;gap:8px;margin-top:12px;flex-wrap:wrap;\">\r\n                <button class=\"pth-btn pth-btn-success\" id=\"pth-copy-eq-btn\"\r\n                    style=\"flex:1;\" aria-label=\"Copy Boolean equation to clipboard\">\ud83d\udccb Copy Equation<\/button>\r\n                <button class=\"pth-btn pth-btn-secondary\" id=\"pth-to-hdl-btn\"\r\n                    style=\"flex:1;\" aria-label=\"Open result in HDL generator\">\ud83d\udcbb Open in HDL<\/button>\r\n            <\/div>\r\n        <\/div>\r\n    <\/div>\r\n\r\n    <!-- \u2550\u2550 TAB 2: BOOLEAN TOOLS \u2550\u2550 -->\r\n    <div id=\"pth-tab-boolean\" style=\"display:none;\" role=\"tabpanel\">\r\n\r\n        <!-- Expression \u2192 Truth Table -->\r\n        <div class=\"pth-card\">\r\n            <div class=\"pth-card-hdr\">\u26a1 Boolean Expression \u2192 Truth Table<\/div>\r\n            <div class=\"pth-field\">\r\n                <label for=\"pth-bool-expr\">Enter Expression <span style=\"color:#334155;font-weight:500;text-transform:none;\">(use A B C D, ' for NOT, + for OR, no symbol for AND)<\/span><\/label>\r\n                <input type=\"text\" id=\"pth-bool-expr\" class=\"pth-expr-input\"\r\n                    placeholder=\"e.g.  AB' + C'D  or  (A+B)(C+D')\"\r\n                    aria-label=\"Boolean expression input\">\r\n                <div style=\"font-size:10px;color:#334155;font-weight:600;margin-top:4px;\">\r\n                    Operators: <code>+<\/code> OR \u00b7 concatenation \/ <code>\u00b7<\/code> AND \u00b7 <code>'<\/code> or <code>!<\/code> NOT \u00b7 <code>^<\/code> XOR \u00b7 use ( ) for grouping\r\n                <\/div>\r\n            <\/div>\r\n            <div style=\"display:flex;gap:8px;flex-wrap:wrap;margin-bottom:12px;\">\r\n                <button class=\"pth-btn pth-btn-primary\" id=\"pth-expr-to-tt-btn\"\r\n                    aria-label=\"Convert expression to truth table\">\u26a1 \u2192 Truth Table<\/button>\r\n                <button class=\"pth-btn pth-btn-secondary\" id=\"pth-expr-to-kmap-btn\"\r\n                    aria-label=\"Send expression to K-Map solver\">\ud83d\uddfa\ufe0f \u2192 K-Map Solver<\/button>\r\n                <button class=\"pth-btn pth-btn-secondary\" id=\"pth-expr-clear-btn\"\r\n                    aria-label=\"Clear expression\">\ud83d\uddd1\ufe0f<\/button>\r\n            <\/div>\r\n            <div id=\"pth-bool-tt-output\" style=\"display:none;\">\r\n                <div class=\"pth-table-wrap\">\r\n                    <table class=\"pth-truth-table\" id=\"pth-bool-truth-table\" aria-label=\"Generated truth table\"><\/table>\r\n                <\/div>\r\n            <\/div>\r\n        <\/div>\r\n\r\n        <!-- Canonical forms -->\r\n        <div class=\"pth-card\">\r\n            <div class=\"pth-card-hdr\">\ud83d\udcd0 Canonical SOP &amp; POS Generator<\/div>\r\n            <div class=\"pth-field\">\r\n                <label>Minterms \/ Maxterms <span style=\"color:#334155;font-weight:500;text-transform:none;\">(enter comma-separated numbers)<\/span><\/label>\r\n                <div class=\"pth-row-2\">\r\n                    <div class=\"pth-field\" style=\"margin:0;\">\r\n                        <label for=\"pth-canon-vars\">Variables<\/label>\r\n                        <select id=\"pth-canon-vars\" aria-label=\"Number of variables for canonical form\">\r\n                            <option value=\"2\">2<\/option>\r\n                            <option value=\"3\">3<\/option>\r\n                            <option value=\"4\" selected>4<\/option>\r\n                            <option value=\"5\">5<\/option>\r\n                        <\/select>\r\n                    <\/div>\r\n                    <div class=\"pth-field\" style=\"margin:0;\">\r\n                        <label for=\"pth-canon-terms\">Minterms<\/label>\r\n                        <input type=\"text\" id=\"pth-canon-terms\" placeholder=\"e.g. 0,2,5,7,8,10\"\r\n                            aria-label=\"Minterms list\">\r\n                    <\/div>\r\n                <\/div>\r\n                <div class=\"pth-field\" style=\"margin-top:8px;margin-bottom:0;\">\r\n                    <label for=\"pth-canon-dc\">Don't Cares (optional)<\/label>\r\n                    <input type=\"text\" id=\"pth-canon-dc\" placeholder=\"e.g. 3,11\"\r\n                        aria-label=\"Don't care terms\">\r\n                <\/div>\r\n            <\/div>\r\n            <button class=\"pth-btn pth-btn-primary\" id=\"pth-gen-canonical-btn\"\r\n                style=\"margin-bottom:10px;\" aria-label=\"Generate canonical forms\">\r\n                \u26a1 Generate Canonical Forms\r\n            <\/button>\r\n            <div class=\"pth-bool-result\" id=\"pth-canonical-output\" aria-live=\"polite\">\r\n                Enter minterms above to generate SOP and POS canonical forms\r\n            <\/div>\r\n        <\/div>\r\n\r\n        <!-- De Morgan \/ Dual -->\r\n        <div class=\"pth-card\">\r\n            <div class=\"pth-card-hdr\">\ud83d\udd04 De Morgan's Theorem &amp; Dual Expression<\/div>\r\n            <div class=\"pth-field\">\r\n                <label for=\"pth-demorgan-expr\">Expression<\/label>\r\n                <input type=\"text\" id=\"pth-demorgan-expr\" class=\"pth-expr-input\"\r\n                    placeholder=\"e.g. AB' + CD\"\r\n                    aria-label=\"Expression for De Morgan transformation\">\r\n            <\/div>\r\n            <div style=\"display:flex;gap:8px;flex-wrap:wrap;margin-bottom:10px;\">\r\n                <button class=\"pth-btn pth-btn-primary\" id=\"pth-demorgan-btn\"\r\n                    aria-label=\"Apply De Morgans theorem\">\ud83d\udd04 De Morgan's<\/button>\r\n                <button class=\"pth-btn pth-btn-secondary\" id=\"pth-dual-btn\"\r\n                    aria-label=\"Generate dual expression\">\u21cc Dual<\/button>\r\n                <button class=\"pth-btn pth-btn-secondary\" id=\"pth-complement-btn\"\r\n                    aria-label=\"Generate complement expression\">\u00ac Complement<\/button>\r\n            <\/div>\r\n            <div class=\"pth-bool-result\" id=\"pth-demorgan-output\" aria-live=\"polite\">\r\n                Enter an expression above and click a transform button\r\n            <\/div>\r\n        <\/div>\r\n    <\/div>\r\n\r\n    <!-- \u2550\u2550 TAB 3: GATE SIMULATOR \u2550\u2550 -->\r\n    <div id=\"pth-tab-gates\" style=\"display:none;\" role=\"tabpanel\">\r\n        <div class=\"pth-card\">\r\n            <div class=\"pth-card-hdr\">\ud83d\udd0c Logic Gate Simulator \u2014 Chain up to 8 Gates<\/div>\r\n\r\n            <!-- Input toggles -->\r\n            <div class=\"pth-field\">\r\n                <div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:8px;\">\r\n                    <label style=\"text-transform:none;font-size:13px;font-weight:700;color:#0f172a;\">Input Signals<\/label>\r\n                    <select id=\"pth-gate-input-count\" style=\"width:auto;padding:4px 8px;font-size:11px;\" aria-label=\"Number of input signals\">\r\n                        <option value=\"2\">2 inputs<\/option>\r\n                        <option value=\"3\">3 inputs<\/option>\r\n                        <option value=\"4\">4 inputs<\/option>\r\n                        <option value=\"5\">5 inputs<\/option>\r\n                        <option value=\"6\">6 inputs<\/option>\r\n                    <\/select>\r\n                <\/div>\r\n                <div class=\"pth-input-toggle-row\" id=\"pth-gate-inputs\" aria-label=\"Input signal toggles\"><\/div>\r\n            <\/div>\r\n\r\n            <!-- Gate chain -->\r\n            <div style=\"font-size:11px;font-weight:800;color:#334155;text-transform:uppercase;margin-bottom:8px;\">\r\n                Gate Chain\r\n                <span style=\"color:#334155;font-weight:500;text-transform:none;margin-left:6px;font-size:10px;\">\r\n                    (select gate type and inputs; G = Gate output, I = raw input)\r\n                <\/span>\r\n            <\/div>\r\n            <div id=\"pth-gate-chain\" aria-label=\"Logic gate chain\"><\/div>\r\n            <div style=\"display:flex;gap:8px;margin-bottom:12px;flex-wrap:wrap;\">\r\n                <button class=\"pth-btn pth-btn-secondary\" id=\"pth-add-gate-btn\"\r\n                    aria-label=\"Add gate to chain\">\u2795 Add Gate<\/button>\r\n                <button class=\"pth-btn pth-btn-danger\" id=\"pth-remove-gate-btn\"\r\n                    style=\"font-size:11px;padding:5px 10px;\" aria-label=\"Remove last gate\">\u2716 Remove Last<\/button>\r\n                <button class=\"pth-btn pth-btn-primary\" id=\"pth-eval-chain-btn\"\r\n                    style=\"flex:1;\" aria-label=\"Evaluate gate chain\">\u26a1 Evaluate<\/button>\r\n            <\/div>\r\n\r\n            <!-- Final output -->\r\n            <div id=\"pth-chain-result\" style=\"display:none;\">\r\n                <div style=\"display:flex;align-items:center;gap:12px;background:#f8fafc;border-radius:8px;padding:12px;border:1px solid #e2e8f0;\">\r\n                    <div style=\"font-size:11px;font-weight:800;color:#334155;text-transform:uppercase;\">Final Output:<\/div>\r\n                    <div class=\"pth-gate-out-badge\" id=\"pth-chain-final-out\" style=\"font-size:20px;padding:6px 16px;\">?<\/div>\r\n                    <div id=\"pth-chain-explanation\" style=\"font-size:11px;color:#334155;font-weight:600;\"><\/div>\r\n                <\/div>\r\n            <\/div>\r\n        <\/div>\r\n\r\n        <!-- Universal gate converter -->\r\n        <div class=\"pth-card\">\r\n            <div class=\"pth-card-hdr\">\ud83d\udd01 Universal Gate Converter<\/div>\r\n            <p style=\"font-size:12px;color:#334155;font-weight:500;margin:0 0 12px;\">\r\n                NAND and NOR gates are universal \u2014 any Boolean function can be implemented using only one type.\r\n                Enter a Boolean expression to see its NAND-only and NOR-only equivalents.\r\n            <\/p>\r\n            <div class=\"pth-field\">\r\n                <label for=\"pth-universal-expr\">Boolean Expression<\/label>\r\n                <input type=\"text\" id=\"pth-universal-expr\" class=\"pth-expr-input\"\r\n                    placeholder=\"e.g. AB + C\"\r\n                    aria-label=\"Expression for universal gate conversion\">\r\n            <\/div>\r\n            <button class=\"pth-btn pth-btn-primary\" id=\"pth-universal-btn\"\r\n                style=\"width:100%;margin-bottom:10px;\" aria-label=\"Convert to universal gates\">\r\n                \ud83d\udd01 Convert to Universal Gates\r\n            <\/button>\r\n            <div class=\"pth-bool-result\" id=\"pth-universal-output\" aria-live=\"polite\">\r\n                Enter an expression to see NAND-only and NOR-only implementations\r\n            <\/div>\r\n        <\/div>\r\n\r\n        <!-- Gate truth table -->\r\n        <div class=\"pth-card\">\r\n            <div class=\"pth-card-hdr\">\ud83d\udccb Single Gate Truth Table Reference<\/div>\r\n            <div class=\"pth-row-2\">\r\n                <div class=\"pth-field\">\r\n                    <label for=\"pth-gate-ref-type\">Gate Type<\/label>\r\n                    <select id=\"pth-gate-ref-type\" aria-label=\"Gate type for truth table reference\">\r\n                        <option value=\"AND\">AND<\/option>\r\n                        <option value=\"OR\">OR<\/option>\r\n                        <option value=\"NOT\">NOT (1-input)<\/option>\r\n                        <option value=\"NAND\">NAND<\/option>\r\n                        <option value=\"NOR\">NOR<\/option>\r\n                        <option value=\"XOR\">XOR<\/option>\r\n                        <option value=\"XNOR\">XNOR<\/option>\r\n                    <\/select>\r\n                <\/div>\r\n                <div class=\"pth-field\">\r\n                    <label for=\"pth-gate-ref-inputs\">Input Count<\/label>\r\n                    <select id=\"pth-gate-ref-inputs\" aria-label=\"Number of inputs for reference gate\">\r\n                        <option value=\"2\">2 inputs<\/option>\r\n                        <option value=\"3\">3 inputs<\/option>\r\n                        <option value=\"4\">4 inputs<\/option>\r\n                    <\/select>\r\n                <\/div>\r\n            <\/div>\r\n            <div class=\"pth-table-wrap\" id=\"pth-gate-ref-wrap\">\r\n                <table class=\"pth-truth-table\" id=\"pth-gate-ref-table\" aria-label=\"Gate reference truth table\"><\/table>\r\n            <\/div>\r\n        <\/div>\r\n    <\/div>\r\n\r\n    <!-- \u2550\u2550 TAB 4: HDL CODE \u2550\u2550 -->\r\n    <div id=\"pth-tab-hdl\" style=\"display:none;\" role=\"tabpanel\">\r\n        <div class=\"pth-card\">\r\n            <div class=\"pth-card-hdr\">\ud83d\udcbb HDL &amp; Code Generator<\/div>\r\n            <div class=\"pth-field\">\r\n                <label for=\"pth-hdl-eq\">Boolean Equation <span style=\"color:#334155;font-weight:500;text-transform:none;\">(from K-Map or type manually)<\/span><\/label>\r\n                <input type=\"text\" id=\"pth-hdl-eq\" class=\"pth-expr-input\"\r\n                    placeholder=\"e.g. AB' + CD + A'BC'\"\r\n                    aria-label=\"Boolean equation for HDL generation\">\r\n            <\/div>\r\n            <div class=\"pth-row-2\">\r\n                <div class=\"pth-field\">\r\n                    <label for=\"pth-hdl-module\">Module \/ Function Name<\/label>\r\n                    <input type=\"text\" id=\"pth-hdl-module\" value=\"logic_minimized\"\r\n                        aria-label=\"Module or function name for HDL output\">\r\n                <\/div>\r\n                <div class=\"pth-field\">\r\n                    <label for=\"pth-hdl-vars\">Variable List <span style=\"color:#334155;font-weight:500;text-transform:none;\">(comma separated)<\/span><\/label>\r\n                    <input type=\"text\" id=\"pth-hdl-vars\" value=\"A,B,C,D\"\r\n                        aria-label=\"Variable names for HDL output\">\r\n                <\/div>\r\n            <\/div>\r\n            <button class=\"pth-btn pth-btn-primary\" id=\"pth-gen-hdl-btn\"\r\n                style=\"width:100%;padding:12px;font-size:14px;margin-bottom:14px;\"\r\n                aria-label=\"Generate all HDL and code outputs\">\r\n                \u26a1 Generate All Formats\r\n            <\/button>\r\n\r\n            <!-- HDL format tabs -->\r\n            <div class=\"pth-hdl-tabs\" role=\"tablist\" aria-label=\"HDL output format selector\">\r\n                <button class=\"pth-hdl-tab pth-active\" data-hdl=\"verilog\"\r\n                    role=\"tab\" aria-selected=\"true\" aria-label=\"Verilog output\">Verilog<\/button>\r\n                <button class=\"pth-hdl-tab\" data-hdl=\"vhdl\"\r\n                    role=\"tab\" aria-selected=\"false\" aria-label=\"VHDL output\">VHDL<\/button>\r\n                <button class=\"pth-hdl-tab\" data-hdl=\"sv\"\r\n                    role=\"tab\" aria-selected=\"false\" aria-label=\"SystemVerilog output\">SystemVerilog<\/button>\r\n                <button class=\"pth-hdl-tab\" data-hdl=\"c\"\r\n                    role=\"tab\" aria-selected=\"false\" aria-label=\"C language output\">C\/C++<\/button>\r\n                <button class=\"pth-hdl-tab\" data-hdl=\"python\"\r\n                    role=\"tab\" aria-selected=\"false\" aria-label=\"Python output\">Python<\/button>\r\n            <\/div>\r\n            <div class=\"pth-code-out\" id=\"pth-hdl-output\" aria-live=\"polite\" aria-label=\"Generated HDL code output\">\r\n                Click \"Generate All Formats\" to see output in all 5 languages\r\n            <\/div>\r\n            <div style=\"display:flex;gap:8px;margin-top:10px;flex-wrap:wrap;\">\r\n                <button class=\"pth-btn pth-btn-success\" id=\"pth-copy-hdl-btn\"\r\n                    style=\"flex:1;\" aria-label=\"Copy current HDL output\">\ud83d\udccb Copy Code<\/button>\r\n                <button class=\"pth-btn pth-btn-secondary\" id=\"pth-export-hdl-btn\"\r\n                    style=\"flex:1;\" aria-label=\"Export HDL code as file\">\ud83d\udce4 Export File<\/button>\r\n            <\/div>\r\n        <\/div>\r\n\r\n        <!-- Conversion hints -->\r\n        <div class=\"pth-card\">\r\n            <div class=\"pth-card-hdr\">\u2139\ufe0f Operator Notation Guide<\/div>\r\n            <div style=\"display:grid;grid-template-columns:1fr 1fr 1fr;gap:6px;\">\r\n                <div style=\"background:#f8fafc;border-radius:6px;padding:8px;font-size:11px;\">\r\n                    <div style=\"font-weight:800;color:#1d4ed8;margin-bottom:4px;\">Verilog \/ SV<\/div>\r\n                    <div style=\"font-family:'Courier New',monospace;color:#334155;line-height:1.8;\">AND \u2192 &<br>OR \u2192 |<br>NOT \u2192 ~<br>XOR \u2192 ^<\/div>\r\n                <\/div>\r\n                <div style=\"background:#f8fafc;border-radius:6px;padding:8px;font-size:11px;\">\r\n                    <div style=\"font-weight:800;color:#5b21b6;margin-bottom:4px;\">VHDL<\/div>\r\n                    <div style=\"font-family:'Courier New',monospace;color:#334155;line-height:1.8;\">AND \u2192 and<br>OR \u2192 or<br>NOT \u2192 not<br>XOR \u2192 xor<\/div>\r\n                <\/div>\r\n                <div style=\"background:#f8fafc;border-radius:6px;padding:8px;font-size:11px;\">\r\n                    <div style=\"font-weight:800;color:#047857;margin-bottom:4px;\">C \/ Python<\/div>\r\n                    <div style=\"font-family:'Courier New',monospace;color:#334155;line-height:1.8;\">AND \u2192 &&<br>OR \u2192 ||<br>NOT \u2192 !<br>XOR \u2192 ^<\/div>\r\n                <\/div>\r\n            <\/div>\r\n        <\/div>\r\n    <\/div>\r\n\r\n<\/div><!-- \/main card -->\r\n<\/div><!-- \/main col -->\r\n\r\n<!-- \u2550\u2550\u2550 SIDEBAR \u2550\u2550\u2550 -->\r\n<div id=\"pth-logic-sidebar\">\r\n\r\n    <!-- Result summary -->\r\n    <div class=\"pth-card\">\r\n        <div class=\"pth-sb-hdr\">\u2705 Current Solution<\/div>\r\n        <div class=\"pth-eq-display\" id=\"pth-sb-eq\"\r\n            style=\"font-size:14px;min-height:40px;padding:10px 12px;\">\r\n            F = ?\r\n        <\/div>\r\n        <div style=\"font-size:11px;color:#334155;font-weight:600;margin-top:8px;line-height:1.9;\" id=\"pth-sb-stats\">\r\n            Variables: \u2014<br>Minterms: \u2014<br>Don't cares: \u2014<br>Prime implicants: \u2014<br>Groups: \u2014\r\n        <\/div>\r\n    <\/div>\r\n\r\n    <!-- Minterm \/ Maxterm list -->\r\n    <div class=\"pth-card\">\r\n        <div class=\"pth-sb-hdr\">\ud83d\udccb Term Lists<\/div>\r\n        <div style=\"font-size:11px;color:#334155;font-weight:600;margin-bottom:4px;\">Minterms (1s)<\/div>\r\n        <div style=\"font-family:'Courier New',monospace;font-size:11px;color:#047857;font-weight:700;margin-bottom:8px;min-height:20px;word-break:break-word;\" id=\"pth-sb-minterms\">\u2014<\/div>\r\n        <div style=\"font-size:11px;color:#334155;font-weight:600;margin-bottom:4px;\">Don't Cares (X)<\/div>\r\n        <div style=\"font-family:'Courier New',monospace;font-size:11px;color:#92400e;font-weight:700;margin-bottom:8px;min-height:20px;word-break:break-word;\" id=\"pth-sb-dontcares\">\u2014<\/div>\r\n        <div style=\"font-size:11px;color:#334155;font-weight:600;margin-bottom:4px;\">Maxterms (0s)<\/div>\r\n        <div style=\"font-family:'Courier New',monospace;font-size:11px;color:#991b1b;font-weight:700;min-height:20px;word-break:break-word;\" id=\"pth-sb-maxterms\">\u2014<\/div>\r\n    <\/div>\r\n\r\n    <!-- Quick reference -->\r\n    <div class=\"pth-card\">\r\n        <div class=\"pth-sb-hdr\">\ud83d\udcd6 Quick Reference<\/div>\r\n        <div style=\"font-size:11px;color:#334155;font-weight:500;line-height:1.9;\">\r\n            <div><strong style=\"color:#0f172a;\">SOP:<\/strong> \u03a3m(minterms) \u2014 Sum of Products<\/div>\r\n            <div><strong style=\"color:#0f172a;\">POS:<\/strong> \u03a0M(maxterms) \u2014 Product of Sums<\/div>\r\n            <div><strong style=\"color:#0f172a;\">X:<\/strong> Don't Care \u2014 can be 0 or 1<\/div>\r\n            <div><strong style=\"color:#0f172a;\">Group of 1:<\/strong> n variables<\/div>\r\n            <div><strong style=\"color:#0f172a;\">Group of 2:<\/strong> n\u22121 variables<\/div>\r\n            <div><strong style=\"color:#0f172a;\">Group of 4:<\/strong> n\u22122 variables<\/div>\r\n            <div><strong style=\"color:#0f172a;\">Group of 8:<\/strong> n\u22123 variables<\/div>\r\n            <div><strong style=\"color:#0f172a;\">Petrick's:<\/strong> exact minimal cover<\/div>\r\n        <\/div>\r\n    <\/div>\r\n\r\n    <!-- K-Map guide -->\r\n    <div class=\"pth-card\">\r\n        <div class=\"pth-sb-hdr\">\ud83d\udca1 Grouping Rules<\/div>\r\n        <ul style=\"margin:0;padding-left:14px;font-size:11px;color:#334155;line-height:1.9;font-weight:500;\">\r\n            <li>Groups must be powers of 2 (1,2,4,8,16\u2026)<\/li>\r\n            <li>Groups may wrap around edges<\/li>\r\n            <li>Groups may wrap corners<\/li>\r\n            <li>Each 1 must be covered by \u22651 group<\/li>\r\n            <li>X (don't care) can join any group<\/li>\r\n            <li>Larger groups \u2192 fewer variables<\/li>\r\n            <li>Fewest groups \u2192 shortest expression<\/li>\r\n        <\/ul>\r\n    <\/div>\r\n\r\n<\/div><!-- \/sidebar -->\r\n<\/div><!-- \/flex-layout -->\r\n<\/div><!-- \/wrapper -->\r\n<script data-no-optimize=\"1\" data-no-minify=\"1\" data-cfasync=\"false\">\r\n(function () {\r\n    'use strict';\r\n\r\n    \/* =======================================================\r\n       PTH DIGITAL LOGIC STUDIO PRO \u2014 v2.0 FIXED\r\n       FIXES APPLIED:\r\n       FIX 1: All querySelectorAll scoped to #pth-logic-wrapper\r\n       FIX 2: sig.startsWith() \u2192 sig.indexOf() === 0\r\n       FIX 3: eval() removed \u2192 proper Boolean token parser\r\n       FIX 4: str.repeat() \u2192 Array(n+1).join(ch)\r\n       FIX 5: padStart() \u2192 custom pthPad() helper\r\n       FIX 6: NodeList.forEach \u2192 Array.prototype.forEach.call()\r\n       FIX 7: Individual try\/catch per attachment (not one block)\r\n       FIX 8: solve() deferred until cells[] ready\r\n       ======================================================= *\/\r\n\r\n    \/* \u2500\u2500\u2500 SAFE HELPERS (ES5 compatible) \u2500\u2500\u2500 *\/\r\n    function pthPad(n, len, ch) {\r\n        var s = String(n);\r\n        ch = ch || '0';\r\n        while (s.length < len) { s = ch + s; }\r\n        return s;\r\n    }\r\n    function pthRepeat(ch, n) {\r\n        var s = '';\r\n        for (var i = 0; i < n; i++) { s += ch; }\r\n        return s;\r\n    }\r\n    function pthEach(sel, fn) {\r\n        var els = document.querySelectorAll(sel);\r\n        Array.prototype.forEach.call(els, fn);\r\n    }\r\n\r\n    window.pthLogicApp = {\r\n        initialized: false,\r\n        numVars: 4,\r\n        cells: [],\r\n        solveMode: 'sop',\r\n        solveMethod: 'greedy',\r\n        varNames: ['A','B','C','D','E','F'],\r\n        currentResult: null,\r\n        gateCount: 0,\r\n        hdlResults: {},\r\n        currentHdl: 'verilog',\r\n        gateInputCount: 2,\r\n\r\n        groupColors: [\r\n            { bg:'rgba(37,99,235,0.18)',  border:'#1d4ed8', text:'#1d4ed8' },\r\n            { bg:'rgba(5,150,105,0.18)',  border:'#059669', text:'#047857' },\r\n            { bg:'rgba(220,38,38,0.18)', border:'#dc2626', text:'#991b1b' },\r\n            { bg:'rgba(146,64,14,0.18)', border:'#92400e', text:'#78350f' },\r\n            { bg:'rgba(91,33,182,0.18)', border:'#5b21b6', text:'#4c1d95' },\r\n            { bg:'rgba(4,120,87,0.18)',  border:'#047857', text:'#065f46' },\r\n            { bg:'rgba(124,58,237,0.18)',border:'#6d28d9', text:'#5b21b6' },\r\n            { bg:'rgba(180,83,9,0.18)',  border:'#b45309', text:'#92400e' }\r\n        ],\r\n\r\n        \/* \u2500\u2500 Study samples for \ud83d\udca1 Load Sample button \u2500\u2500 *\/\r\n        samples: [\r\n            { name:'Classic SOP \u03a3m(0,2,5,7,8,10,13,15)', vars:4, minterms:[0,2,5,7,8,10,13,15], dc:[] },\r\n            { name:'Essential PI \u03a3m(0,1,2,5,6,7)', vars:3, minterms:[0,1,2,5,6,7], dc:[] },\r\n            { name:'Don\\'t Care \u03a3m(1,3,7,11,15) d(0,2,5)', vars:4, minterms:[1,3,7,11,15], dc:[0,2,5] },\r\n            { name:'POS Example \u03a3m(1,2,4,6)', vars:3, minterms:[1,2,4,6], dc:[] },\r\n            { name:'Group of 8 \u03a3m(0,2,4,6,8,10,12,14)', vars:4, minterms:[0,2,4,6,8,10,12,14], dc:[] },\r\n            { name:'Corner Group \u03a3m(0,2,8,10)', vars:4, minterms:[0,2,8,10], dc:[] }\r\n        ],\r\n        sampleIdx: 0,\r\n\r\n        \/* \u2500\u2500\u2500 INIT \u2500\u2500\u2500 *\/\r\n        init: function () {\r\n            var self = this;\r\n            self.attachEvents();\r\n            self.buildVarNames();\r\n            self.initTruthTable();\r\n            self.buildGateInputs();\r\n            self.addGate();\r\n            self.addGate();\r\n            self.showGateRefTable();\r\n        },\r\n\r\n        \/* \u2500\u2500\u2500 ATTACH EVENTS \u2014 each button wrapped individually \u2500\u2500\u2500 *\/\r\n        attachEvents: function () {\r\n            var self = this;\r\n\r\n            \/* \u2500\u2500 Header \u2500\u2500 *\/\r\n            var el;\r\n            el = document.getElementById('pth-dl-fw-btn');\r\n            if (el) el.addEventListener('click', function () { self.toggleWidth(); });\r\n\r\n            el = document.getElementById('pth-dl-sample-btn');\r\n            if (el) el.addEventListener('click', function () { self.loadSample(); });\r\n\r\n            el = document.getElementById('pth-dl-clear-btn');\r\n            if (el) el.addEventListener('click', function () { self.clearAll(); });\r\n\r\n            el = document.getElementById('pth-dl-random-btn');\r\n            if (el) el.addEventListener('click', function () { self.randomExample(); });\r\n\r\n            el = document.getElementById('pth-dl-print-btn');\r\n            if (el) el.addEventListener('click', function () { window.print(); });\r\n\r\n            \/* \u2500\u2500 Tabs \u2014 SCOPED \u2500\u2500 *\/\r\n            pthEach('#pth-logic-wrapper .pth-tab-btn[data-tab]', function (btn) {\r\n                btn.addEventListener('click', function () {\r\n                    self.switchTab(this.getAttribute('data-tab'));\r\n                });\r\n            });\r\n\r\n            \/* \u2500\u2500 Variable count \u2500\u2500 *\/\r\n            el = document.getElementById('pth-var-count');\r\n            if (el) el.addEventListener('change', function () {\r\n                self.numVars = parseInt(this.value, 10);\r\n                self.buildVarNames();\r\n                self.initTruthTable();\r\n            });\r\n\r\n            \/* FIX 1: SCOPED data-mode selector *\/\r\n            pthEach('#pth-logic-wrapper [data-mode]', function (btn) {\r\n                btn.addEventListener('click', function () {\r\n                    self.solveMode = this.getAttribute('data-mode');\r\n                    pthEach('#pth-logic-wrapper [data-mode]', function (b) {\r\n                        var isActive = b.getAttribute('data-mode') === self.solveMode;\r\n                        b.classList.toggle('pth-active', isActive);\r\n                        b.setAttribute('aria-pressed', isActive ? 'true' : 'false');\r\n                    });\r\n                    self.solve();\r\n                });\r\n            });\r\n\r\n            \/* FIX 1: SCOPED data-method selector *\/\r\n            pthEach('#pth-logic-wrapper [data-method]', function (btn) {\r\n                btn.addEventListener('click', function () {\r\n                    self.solveMethod = this.getAttribute('data-method');\r\n                    pthEach('#pth-logic-wrapper [data-method]', function (b) {\r\n                        var isActive = b.getAttribute('data-method') === self.solveMethod;\r\n                        b.classList.toggle('pth-active', isActive);\r\n                        b.setAttribute('aria-pressed', isActive ? 'true' : 'false');\r\n                    });\r\n                    self.solve();\r\n                });\r\n            });\r\n\r\n            \/* \u2500\u2500 Set all \u2500\u2500 *\/\r\n            el = document.getElementById('pth-set-all-0');\r\n            if (el) el.addEventListener('click', function () { self.setAllCells('0'); });\r\n\r\n            el = document.getElementById('pth-set-all-1');\r\n            if (el) el.addEventListener('click', function () { self.setAllCells('1'); });\r\n\r\n            \/* \u2500\u2500 Solve \u2500\u2500 *\/\r\n            el = document.getElementById('pth-solve-btn');\r\n            if (el) el.addEventListener('click', function () { self.solve(); });\r\n\r\n            \/* \u2500\u2500 Copy eq \/ Open in HDL \u2500\u2500 *\/\r\n            el = document.getElementById('pth-copy-eq-btn');\r\n            if (el) el.addEventListener('click', function () {\r\n                if (self.currentResult) {\r\n                    self.copyText('F = ' + self.currentResult.eq);\r\n                    self.showToast('Equation copied!', 'success');\r\n                }\r\n            });\r\n\r\n            el = document.getElementById('pth-to-hdl-btn');\r\n            if (el) el.addEventListener('click', function () {\r\n                if (self.currentResult) {\r\n                    self.switchTab('hdl');\r\n                    var eqEl  = document.getElementById('pth-hdl-eq');\r\n                    var varEl = document.getElementById('pth-hdl-vars');\r\n                    if (eqEl)  { eqEl.value = self.currentResult.eq; eqEl.setAttribute('data-auto','1'); }\r\n                    if (varEl) varEl.value = self.varNames.slice(0, self.numVars).join(',');\r\n                    self.generateHdl();\r\n                    self.showToast('Equation loaded in HDL tab!', 'info');\r\n                }\r\n            });\r\n\r\n            \/* \u2500\u2500 Boolean tools \u2500\u2500 *\/\r\n            el = document.getElementById('pth-expr-to-tt-btn');\r\n            if (el) el.addEventListener('click', function () { self.exprToTruthTable(); });\r\n\r\n            el = document.getElementById('pth-expr-to-kmap-btn');\r\n            if (el) el.addEventListener('click', function () { self.exprToKmap(); });\r\n\r\n            el = document.getElementById('pth-expr-clear-btn');\r\n            if (el) el.addEventListener('click', function () {\r\n                var x = document.getElementById('pth-bool-expr');\r\n                if (x) x.value = '';\r\n            });\r\n\r\n            el = document.getElementById('pth-gen-canonical-btn');\r\n            if (el) el.addEventListener('click', function () { self.generateCanonical(); });\r\n\r\n            el = document.getElementById('pth-demorgan-btn');\r\n            if (el) el.addEventListener('click', function () { self.applyDemorgan(); });\r\n\r\n            el = document.getElementById('pth-dual-btn');\r\n            if (el) el.addEventListener('click', function () { self.generateDual(); });\r\n\r\n            el = document.getElementById('pth-complement-btn');\r\n            if (el) el.addEventListener('click', function () { self.generateComplement(); });\r\n\r\n            \/* \u2500\u2500 Gate simulator \u2500\u2500 *\/\r\n            el = document.getElementById('pth-gate-input-count');\r\n            if (el) el.addEventListener('change', function () {\r\n                self.gateInputCount = parseInt(this.value, 10);\r\n                self.buildGateInputs();\r\n                self.evalChain();\r\n            });\r\n\r\n            el = document.getElementById('pth-add-gate-btn');\r\n            if (el) el.addEventListener('click', function () {\r\n                if (self.gateCount < 8) { self.addGate(); self.evalChain(); }\r\n                else self.showToast('Maximum 8 gates!', 'error');\r\n            });\r\n\r\n            el = document.getElementById('pth-remove-gate-btn');\r\n            if (el) el.addEventListener('click', function () {\r\n                var chain = document.getElementById('pth-gate-chain');\r\n                if (chain && chain.children.length > 0) {\r\n                    chain.removeChild(chain.lastChild);\r\n                    self.gateCount--;\r\n                    self.evalChain();\r\n                }\r\n            });\r\n\r\n            el = document.getElementById('pth-eval-chain-btn');\r\n            if (el) el.addEventListener('click', function () { self.evalChain(); });\r\n\r\n            el = document.getElementById('pth-gate-ref-type');\r\n            if (el) el.addEventListener('change', function () { self.showGateRefTable(); });\r\n\r\n            el = document.getElementById('pth-gate-ref-inputs');\r\n            if (el) el.addEventListener('change', function () {\r\n                var typeEl = document.getElementById('pth-gate-ref-type');\r\n                if (typeEl && typeEl.value === 'NOT') return;\r\n                self.showGateRefTable();\r\n            });\r\n\r\n            \/* \u2500\u2500 Universal gate \u2500\u2500 *\/\r\n            el = document.getElementById('pth-universal-btn');\r\n            if (el) el.addEventListener('click', function () { self.convertUniversal(); });\r\n\r\n            \/* \u2500\u2500 HDL \u2500\u2500 *\/\r\n            el = document.getElementById('pth-gen-hdl-btn');\r\n            if (el) el.addEventListener('click', function () { self.generateHdl(); });\r\n\r\n            \/* FIX 1: SCOPED data-hdl selector *\/\r\n            pthEach('#pth-logic-wrapper [data-hdl]', function (btn) {\r\n                btn.addEventListener('click', function () {\r\n                    self.switchHdl(this.getAttribute('data-hdl'));\r\n                });\r\n            });\r\n\r\n            el = document.getElementById('pth-copy-hdl-btn');\r\n            if (el) el.addEventListener('click', function () {\r\n                var out = document.getElementById('pth-hdl-output');\r\n                if (out) { self.copyText(out.textContent); self.showToast('Code copied!', 'success'); }\r\n            });\r\n\r\n            el = document.getElementById('pth-export-hdl-btn');\r\n            if (el) el.addEventListener('click', function () { self.exportHdl(); });\r\n        },\r\n\r\n        \/* \u2500\u2500\u2500 SWITCH TAB \u2500\u2500\u2500 *\/\r\n        switchTab: function (tab) {\r\n            var self = this;\r\n            var tabs = ['kmap','boolean','gates','hdl'];\r\n            tabs.forEach(function (t) {\r\n                var panel = document.getElementById('pth-tab-' + t);\r\n                var btn   = document.querySelector('#pth-logic-wrapper [data-tab=\"' + t + '\"]');\r\n                if (panel) panel.style.display = (t === tab) ? 'block' : 'none';\r\n                if (btn)   {\r\n                    btn.classList.toggle('pth-active', t === tab);\r\n                    btn.setAttribute('aria-selected', t === tab ? 'true' : 'false');\r\n                }\r\n            });\r\n        },\r\n\r\n        \/* \u2500\u2500\u2500 BUILD VAR NAMES \u2500\u2500\u2500 *\/\r\n        buildVarNames: function () {\r\n            var self = this;\r\n            var row  = document.getElementById('pth-var-names-row');\r\n            if (!row) return;\r\n            row.innerHTML = '';\r\n            for (var i = 0; i < self.numVars; i++) {\r\n                (function (idx) {\r\n                    var wrapper = document.createElement('div');\r\n                    wrapper.style.textAlign = 'center';\r\n                    var inp = document.createElement('input');\r\n                    inp.type      = 'text';\r\n                    inp.className = 'pth-var-input';\r\n                    inp.value     = self.varNames[idx];\r\n                    inp.maxLength = 2;\r\n                    inp.setAttribute('aria-label', 'Variable ' + (idx+1) + ' name');\r\n                    inp.addEventListener('input', function () {\r\n                        var val = this.value.toUpperCase().replace(\/[^A-Z0-9]\/g,'').substring(0,2);\r\n                        self.varNames[idx] = val || String.fromCharCode(65 + idx);\r\n                        self.initTruthTable();\r\n                    });\r\n                    wrapper.appendChild(inp);\r\n                    row.appendChild(wrapper);\r\n                })(i);\r\n            }\r\n        },\r\n\r\n        \/* \u2500\u2500\u2500 INIT TRUTH TABLE \u2500\u2500\u2500 *\/\r\n        initTruthTable: function () {\r\n            var self      = this;\r\n            var totalRows = Math.pow(2, self.numVars);\r\n            var table     = document.getElementById('pth-truth-table');\r\n            if (!table) return;\r\n            table.innerHTML = '';\r\n            self.cells = [];\r\n\r\n            \/* Header *\/\r\n            var head    = table.insertRow();\r\n            var mHead   = document.createElement('th');\r\n            mHead.textContent = 'm';\r\n            head.appendChild(mHead);\r\n            for (var v = 0; v < self.numVars; v++) {\r\n                var th = document.createElement('th');\r\n                th.textContent = self.varNames[v];\r\n                head.appendChild(th);\r\n            }\r\n            var fHead = document.createElement('th');\r\n            fHead.textContent = 'F';\r\n            fHead.style.background = '#eff6ff';\r\n            fHead.style.color = '#1d4ed8';\r\n            head.appendChild(fHead);\r\n\r\n            \/* Rows *\/\r\n            for (var i = 0; i < totalRows; i++) {\r\n                var row  = table.insertRow();\r\n                var mTd  = row.insertCell();\r\n                mTd.textContent = i;\r\n                mTd.style.color = '#334155';\r\n                mTd.style.fontSize = '10px';\r\n                mTd.style.fontWeight = '700';\r\n\r\n                \/* FIX 5: padStart \u2192 pthPad *\/\r\n                var bin = pthPad(i.toString(2), self.numVars, '0');\r\n                for (var j = 0; j < self.numVars; j++) {\r\n                    var td = row.insertCell();\r\n                    td.textContent = bin[j];\r\n                    td.style.color = bin[j] === '1' ? '#047857' : '#334155';\r\n                    td.style.fontFamily = \"'Courier New',monospace\";\r\n                    td.style.fontWeight = '700';\r\n                }\r\n\r\n                \/* F cell *\/\r\n                var fCell = row.insertCell();\r\n                fCell.textContent = '0';\r\n                fCell.className   = 'pth-f-cell pth-f-0';\r\n                fCell.setAttribute('role', 'button');\r\n                fCell.setAttribute('tabindex', '0');\r\n                fCell.setAttribute('aria-label', 'Minterm ' + i + ' output \u2014 click to cycle');\r\n                (function (cell, idx) {\r\n                    cell.addEventListener('click', function () { self.cycleCell(cell, idx); });\r\n                    cell.addEventListener('keydown', function (e) {\r\n                        if (e.key === 'Enter' || e.key === ' ') {\r\n                            e.preventDefault(); self.cycleCell(cell, idx);\r\n                        }\r\n                    });\r\n                })(fCell, i);\r\n                self.cells.push(fCell);\r\n            }\r\n            \/* FIX 8: solve() deferred \u2014 cells[] now ready *\/\r\n            self.solve();\r\n        },\r\n\r\n        \/* \u2500\u2500\u2500 CYCLE CELL \u2500\u2500\u2500 *\/\r\n        cycleCell: function (cell, idx) {\r\n            var cur = cell.textContent;\r\n            if (cur === '0')      { cell.textContent = '1'; cell.className = 'pth-f-cell pth-f-1'; }\r\n            else if (cur === '1') { cell.textContent = 'X'; cell.className = 'pth-f-cell pth-f-x'; }\r\n            else                  { cell.textContent = '0'; cell.className = 'pth-f-cell pth-f-0'; }\r\n            this.solve();\r\n        },\r\n\r\n        setAllCells: function (val) {\r\n            this.cells.forEach(function (c) {\r\n                c.textContent = val;\r\n                c.className   = 'pth-f-cell pth-f-' + (val === 'X' ? 'x' : val);\r\n            });\r\n            this.solve();\r\n        },\r\n\r\n        \/* \u2500\u2500\u2500 QUINE-McCLUSKEY \u2500\u2500\u2500 *\/\r\n        qm: function (minterms, dontcares, nv) {\r\n            var self = this;\r\n            if (!minterms.length) {\r\n                return { eq: self.solveMode === 'sop' ? '0' : '1', groups: [], pis: [] };\r\n            }\r\n            var total = Math.pow(2, nv);\r\n            if (minterms.length + dontcares.length === total) {\r\n                return {\r\n                    \/* FIX 4: repeat \u2192 pthRepeat *\/\r\n                    eq: self.solveMode === 'sop' ? '1' : '0',\r\n                    groups: [{ term: self.solveMode === 'sop' ? '1' : '0', idxs: minterms.slice(), str: pthRepeat('-', nv) }],\r\n                    pis: []\r\n                };\r\n            }\r\n\r\n            \/* Step 1 \u2014 prime implicants via iterative merging *\/\r\n            var terms = minterms.concat(dontcares).map(function (m) {\r\n                return { str: pthPad(m.toString(2), nv, '0'), m: [m], used: false };\r\n            });\r\n            var pis = [];\r\n\r\n            for (var pass = 0; pass < nv; pass++) {\r\n                var nextTerms = [];\r\n                var termMap   = {};\r\n                for (var ti = 0; ti < terms.length; ti++) { terms[ti].used = false; }\r\n\r\n                for (var i = 0; i < terms.length; i++) {\r\n                    for (var j = i + 1; j < terms.length; j++) {\r\n                        var diffs = 0, pos = -1;\r\n                        for (var k = 0; k < nv; k++) {\r\n                            if (terms[i].str[k] !== terms[j].str[k]) { diffs++; pos = k; }\r\n                        }\r\n                        if (diffs === 1) {\r\n                            var ns = terms[i].str.substring(0, pos) + '-' + terms[i].str.substring(pos + 1);\r\n                            if (!termMap[ns]) {\r\n                                termMap[ns] = true;\r\n                                var combined = [];\r\n                                var merge = terms[i].m.concat(terms[j].m);\r\n                                for (var mi = 0; mi < merge.length; mi++) {\r\n                                    if (combined.indexOf(merge[mi]) < 0) combined.push(merge[mi]);\r\n                                }\r\n                                combined.sort(function (a, b) { return a - b; });\r\n                                nextTerms.push({ str: ns, m: combined, used: false });\r\n                            }\r\n                            terms[i].used = true;\r\n                            terms[j].used = true;\r\n                        }\r\n                    }\r\n                }\r\n                for (var pi = 0; pi < terms.length; pi++) {\r\n                    if (!terms[pi].used) {\r\n                        var alreadyIn = false;\r\n                        for (var px = 0; px < pis.length; px++) {\r\n                            if (pis[px].str === terms[pi].str) { alreadyIn = true; break; }\r\n                        }\r\n                        if (!alreadyIn) pis.push(terms[pi]);\r\n                    }\r\n                }\r\n                terms = nextTerms;\r\n                if (!terms.length) break;\r\n            }\r\n            for (var tp = 0; tp < terms.length; tp++) {\r\n                var already = false;\r\n                for (var pp = 0; pp < pis.length; pp++) {\r\n                    if (pis[pp].str === terms[tp].str) { already = true; break; }\r\n                }\r\n                if (!already) pis.push(terms[tp]);\r\n            }\r\n\r\n            \/* Filter to PIs covering at least one minterm *\/\r\n            var filteredPis = [];\r\n            for (var fp = 0; fp < pis.length; fp++) {\r\n                var covers = false;\r\n                for (var fm = 0; fm < pis[fp].m.length; fm++) {\r\n                    if (minterms.indexOf(pis[fp].m[fm]) >= 0) { covers = true; break; }\r\n                }\r\n                if (covers) filteredPis.push(pis[fp]);\r\n            }\r\n            pis = filteredPis;\r\n\r\n            \/* Step 2 \u2014 PI chart *\/\r\n            var chart = {};\r\n            for (var cm = 0; cm < minterms.length; cm++) { chart[minterms[cm]] = []; }\r\n            for (var pi2 = 0; pi2 < pis.length; pi2++) {\r\n                for (var pm = 0; pm < pis[pi2].m.length; pm++) {\r\n                    var m2 = pis[pi2].m[pm];\r\n                    if (chart[m2] !== undefined) chart[m2].push(pi2);\r\n                }\r\n            }\r\n\r\n            if (self.solveMethod === 'petrick') {\r\n                return self.petrick(minterms, pis, chart, nv);\r\n            }\r\n\r\n            \/* Greedy cover *\/\r\n            var epiIdxs = [];\r\n            var covered  = [];\r\n\r\n            var chartKeys = Object.keys(chart);\r\n            for (var ck = 0; ck < chartKeys.length; ck++) {\r\n                var m3 = chartKeys[ck];\r\n                if (chart[m3].length === 1) {\r\n                    var idx = chart[m3][0];\r\n                    if (epiIdxs.indexOf(idx) < 0) {\r\n                        epiIdxs.push(idx);\r\n                        for (var em = 0; em < pis[idx].m.length; em++) {\r\n                            var cm2 = pis[idx].m[em];\r\n                            if (minterms.indexOf(cm2) >= 0 && covered.indexOf(cm2) < 0) {\r\n                                covered.push(cm2);\r\n                            }\r\n                        }\r\n                    }\r\n                }\r\n            }\r\n\r\n            var remaining = [];\r\n            for (var ri = 0; ri < pis.length; ri++) {\r\n                if (epiIdxs.indexOf(ri) < 0) remaining.push({ pi: pis[ri], idx: ri });\r\n            }\r\n\r\n            while (covered.length < minterms.length && remaining.length > 0) {\r\n                remaining.sort(function (a, b) {\r\n                    var ac = 0, bc = 0;\r\n                    for (var am = 0; am < a.pi.m.length; am++) {\r\n                        if (minterms.indexOf(a.pi.m[am]) >= 0 && covered.indexOf(a.pi.m[am]) < 0) ac++;\r\n                    }\r\n                    for (var bm = 0; bm < b.pi.m.length; bm++) {\r\n                        if (minterms.indexOf(b.pi.m[bm]) >= 0 && covered.indexOf(b.pi.m[bm]) < 0) bc++;\r\n                    }\r\n                    return bc - ac;\r\n                });\r\n                var best = remaining.shift();\r\n                var newCoverage = 0;\r\n                for (var bm2 = 0; bm2 < best.pi.m.length; bm2++) {\r\n                    if (minterms.indexOf(best.pi.m[bm2]) >= 0 && covered.indexOf(best.pi.m[bm2]) < 0) newCoverage++;\r\n                }\r\n                if (newCoverage > 0) {\r\n                    epiIdxs.push(best.idx);\r\n                    for (var bcm = 0; bcm < best.pi.m.length; bcm++) {\r\n                        var cv = best.pi.m[bcm];\r\n                        if (minterms.indexOf(cv) >= 0 && covered.indexOf(cv) < 0) covered.push(cv);\r\n                    }\r\n                }\r\n            }\r\n\r\n            var finalGroups = [];\r\n            for (var fg = 0; fg < epiIdxs.length; fg++) {\r\n                finalGroups.push({\r\n                    term: self.piToTerm(pis[epiIdxs[fg]].str, nv),\r\n                    idxs: pis[epiIdxs[fg]].m,\r\n                    str:  pis[epiIdxs[fg]].str\r\n                });\r\n            }\r\n            return { eq: self.groupsToEq(finalGroups), groups: finalGroups, pis: pis };\r\n        },\r\n\r\n        \/* \u2500\u2500\u2500 PETRICK'S METHOD \u2500\u2500\u2500 *\/\r\n        petrick: function (minterms, pis, chart, nv) {\r\n            var self = this;\r\n            var posParts = minterms.map(function (m) { return chart[m].slice(); });\r\n            var product  = [[]];\r\n\r\n            for (var pi = 0; pi < posParts.length; pi++) {\r\n                var piSet = posParts[pi];\r\n                var next  = [];\r\n                for (var ci = 0; ci < product.length; ci++) {\r\n                    for (var si = 0; si < piSet.length; si++) {\r\n                        var c = product[ci].slice();\r\n                        if (c.indexOf(piSet[si]) < 0) c.push(piSet[si]);\r\n                        c.sort(function (a, b) { return a - b; });\r\n                        var dominated = false;\r\n                        for (var ni = 0; ni < next.length; ni++) {\r\n                            var allIn = true;\r\n                            for (var xi = 0; xi < next[ni].length; xi++) {\r\n                                if (c.indexOf(next[ni][xi]) < 0) { allIn = false; break; }\r\n                            }\r\n                            if (allIn) { dominated = true; break; }\r\n                        }\r\n                        if (!dominated) {\r\n                            var filtered = [];\r\n                            for (var nf = 0; nf < next.length; nf++) {\r\n                                var covers = true;\r\n                                for (var cf = 0; cf < c.length; cf++) {\r\n                                    if (next[nf].indexOf(c[cf]) < 0) { covers = false; break; }\r\n                                }\r\n                                if (!covers) filtered.push(next[nf]);\r\n                            }\r\n                            filtered.push(c);\r\n                            next = filtered;\r\n                        }\r\n                    }\r\n                }\r\n                product = next;\r\n                if (product.length > 1024) product = product.slice(0, 1024);\r\n            }\r\n\r\n            var minSize = Infinity;\r\n            for (var mi = 0; mi < product.length; mi++) {\r\n                if (product[mi].length < minSize) minSize = product[mi].length;\r\n            }\r\n            var minCovers = [];\r\n            for (var mc = 0; mc < product.length; mc++) {\r\n                if (product[mc].length === minSize) minCovers.push(product[mc]);\r\n            }\r\n\r\n            var chosen = minCovers[0] || [];\r\n            var finalGroups = [];\r\n            for (var fg = 0; fg < chosen.length; fg++) {\r\n                finalGroups.push({\r\n                    term: self.piToTerm(pis[chosen[fg]].str, nv),\r\n                    idxs: pis[chosen[fg]].m,\r\n                    str:  pis[chosen[fg]].str\r\n                });\r\n            }\r\n\r\n            var allSolutions = [];\r\n            for (var as = 0; as < minCovers.length && as < 6; as++) {\r\n                var gs = [];\r\n                for (var gi = 0; gi < minCovers[as].length; gi++) {\r\n                    gs.push({\r\n                        term: self.piToTerm(pis[minCovers[as][gi]].str, nv),\r\n                        idxs: pis[minCovers[as][gi]].m,\r\n                        str:  pis[minCovers[as][gi]].str\r\n                    });\r\n                }\r\n                allSolutions.push(self.groupsToEq(gs));\r\n            }\r\n\r\n            return { eq: self.groupsToEq(finalGroups), groups: finalGroups, pis: pis, allSolutions: allSolutions };\r\n        },\r\n\r\n        \/* \u2500\u2500\u2500 PI \u2192 TERM \u2500\u2500\u2500 *\/\r\n        piToTerm: function (str, nv) {\r\n            var self  = this;\r\n            var isSop = self.solveMode === 'sop';\r\n            var parts = [];\r\n            for (var i = 0; i < nv; i++) {\r\n                if (str[i] === '-') continue;\r\n                var vn = self.varNames[i] || String.fromCharCode(65 + i);\r\n                parts.push(isSop ? (str[i] === '1' ? vn : vn + \"'\") : (str[i] === '0' ? vn : vn + \"'\"));\r\n            }\r\n            if (!parts.length) return isSop ? '1' : '0';\r\n            if (!isSop) return '(' + parts.join(' + ') + ')';\r\n            return parts.join('');\r\n        },\r\n\r\n        groupsToEq: function (groups) {\r\n            if (!groups.length) return this.solveMode === 'sop' ? '0' : '1';\r\n            return groups.map(function (g) { return g.term; }).join(this.solveMode === 'sop' ? ' + ' : '');\r\n        },\r\n\r\n        \/* \u2500\u2500\u2500 MAIN SOLVE \u2500\u2500\u2500 *\/\r\n        solve: function () {\r\n            var self  = this;\r\n            var isSop = self.solveMode === 'sop';\r\n            var minterms  = [];\r\n            var dontcares = [];\r\n            var maxterms  = [];\r\n\r\n            for (var i = 0; i < self.cells.length; i++) {\r\n                var v = self.cells[i].textContent;\r\n                if (v === 'X') { dontcares.push(i); }\r\n                else if ((isSop && v === '1') || (!isSop && v === '0')) { minterms.push(i); }\r\n                else { maxterms.push(i); }\r\n            }\r\n\r\n            self.renderKmap();\r\n\r\n            var result = self.qm(minterms, dontcares, self.numVars);\r\n            self.currentResult = result;\r\n\r\n            var eqStr = result.eq || (isSop ? '0' : '1');\r\n            self.setEl('pth-eq-display', 'F = ' + eqStr);\r\n            self.setEl('pth-sb-eq', 'F = ' + eqStr);\r\n\r\n            var sbStats = document.getElementById('pth-sb-stats');\r\n            if (sbStats) {\r\n                sbStats.innerHTML =\r\n                    'Variables: ' + self.numVars + '<br>' +\r\n                    (isSop ? 'Minterms' : 'Maxterms') + ': ' + minterms.join(', ') + '<br>' +\r\n                    \"Don't cares: \" + (dontcares.join(', ') || 'none') + '<br>' +\r\n                    'Prime implicants: ' + result.pis.length + '<br>' +\r\n                    'Groups: ' + result.groups.length;\r\n            }\r\n\r\n            var ones  = [];\r\n            var zeros = [];\r\n            for (var si = 0; si < self.cells.length; si++) {\r\n                if (self.cells[si].textContent === '1') ones.push(si);\r\n                if (self.cells[si].textContent === '0') zeros.push(si);\r\n            }\r\n            self.setEl('pth-sb-minterms',  ones.join(', ')      || '\\u2014');\r\n            self.setEl('pth-sb-dontcares', dontcares.join(', ') || '\\u2014');\r\n            self.setEl('pth-sb-maxterms',  zeros.join(', ')     || '\\u2014');\r\n\r\n            var rc = document.getElementById('pth-result-card');\r\n            if (rc) rc.style.display = 'block';\r\n\r\n            self.renderGroupLegend(result.groups);\r\n            self.renderGroupCards(result.groups);\r\n            self.colorKmapCells(result.groups);\r\n\r\n            var multiEl = document.getElementById('pth-multi-solutions');\r\n            var solList = document.getElementById('pth-solutions-list');\r\n            if (result.allSolutions && result.allSolutions.length > 1) {\r\n                if (multiEl) multiEl.style.display = 'block';\r\n                if (solList) {\r\n                    var sHtml = '';\r\n                    for (var si2 = 0; si2 < result.allSolutions.length; si2++) {\r\n                        sHtml += 'Solution ' + (si2+1) + ': F = ' + result.allSolutions[si2] + '\\n';\r\n                    }\r\n                    solList.textContent = sHtml;\r\n                }\r\n            } else {\r\n                if (multiEl) multiEl.style.display = 'none';\r\n            }\r\n\r\n            self.buildTrace(minterms, dontcares, result);\r\n\r\n            var hdlEq = document.getElementById('pth-hdl-eq');\r\n            if (hdlEq && (!hdlEq.value || hdlEq.getAttribute('data-auto') === '1')) {\r\n                hdlEq.value = eqStr;\r\n                hdlEq.setAttribute('data-auto', '1');\r\n            }\r\n        },\r\n\r\n        \/* \u2500\u2500\u2500 SOLUTION TRACE \u2500\u2500\u2500 *\/\r\n        buildTrace: function (minterms, dontcares, result) {\r\n            var self  = this;\r\n            var card  = document.getElementById('pth-trace-card');\r\n            var steps = document.getElementById('pth-trace-steps');\r\n            if (!card || !steps) return;\r\n            steps.innerHTML = '';\r\n            card.style.display = 'block';\r\n\r\n            var addStep = function (num, html) {\r\n                var div = document.createElement('div');\r\n                div.className = 'pth-trace-step';\r\n                div.innerHTML = '<span class=\"pth-trace-step-num\">Step ' + num + '<\/span>' +\r\n                    '<span class=\"pth-trace-content\">' + html + '<\/span>';\r\n                steps.appendChild(div);\r\n            };\r\n\r\n            addStep(1, (self.solveMode === 'sop' ? 'Minterms' : 'Maxterms') +\r\n                ': {' + minterms.join(', ') + '}' +\r\n                (dontcares.length ? \" \\u00b7 Don't cares: {\" + dontcares.join(', ') + '}' : ''));\r\n\r\n            addStep(2, 'Quine-McCluskey \u2014 found <strong>' + result.pis.length + ' prime implicants<\/strong>: ' +\r\n                result.pis.map(function (p) { return p.str; }).join(', '));\r\n\r\n            addStep(3, 'Cover selected via ' +\r\n                (self.solveMethod === 'petrick' ? \"Petrick's exact method\" : 'greedy') + ': ' +\r\n                result.groups.map(function (g) { return g.term; }).join(', '));\r\n\r\n            addStep(4, 'Final: <strong style=\"font-family:\\'Courier New\\',monospace;color:#1d4ed8;\">F = ' +\r\n                result.eq + '<\/strong>');\r\n        },\r\n\r\n        \/* \u2500\u2500\u2500 RENDER K-MAP \u2500\u2500\u2500 *\/\r\n        renderKmap: function () {\r\n            var self = this;\r\n            var area = document.getElementById('pth-kmap-area');\r\n            if (!area) return;\r\n            area.innerHTML = '';\r\n            var maps = self.getKMapLayout();\r\n\r\n            for (var mi = 0; mi < maps.length; mi++) {\r\n                var mapGrid = maps[mi];\r\n                var wrap = document.createElement('div');\r\n                wrap.className = 'pth-kmap-wrap';\r\n\r\n                if (maps.length > 1) {\r\n                    var lbl = document.createElement('div');\r\n                    lbl.className = 'pth-kmap-map-lbl';\r\n                    lbl.textContent = self.varNames[0] + ' = ' + mi;\r\n                    wrap.appendChild(lbl);\r\n                }\r\n\r\n                var tbl = document.createElement('table');\r\n                tbl.className = 'pth-kmap-tbl';\r\n                var colVars = self.getColVars();\r\n                var rowVars = self.getRowVars();\r\n\r\n                var hRow = tbl.insertRow();\r\n                var cornerTh = document.createElement('th');\r\n                cornerTh.innerHTML = '<small style=\"font-weight:800;\">' + rowVars + '\\\\' + colVars + '<\/small>';\r\n                hRow.appendChild(cornerTh);\r\n\r\n                var colLabels = self.getGrayLabels(colVars.length);\r\n                for (var cl = 0; cl < colLabels.length; cl++) {\r\n                    var cth = document.createElement('th');\r\n                    cth.textContent = colLabels[cl];\r\n                    hRow.appendChild(cth);\r\n                }\r\n\r\n                var rowLabels = self.getGrayLabels(rowVars.length);\r\n                for (var ri = 0; ri < mapGrid.length; ri++) {\r\n                    var tr = tbl.insertRow();\r\n                    var rh = document.createElement('th');\r\n                    rh.textContent = rowLabels[ri];\r\n                    tr.appendChild(rh);\r\n                    for (var ci = 0; ci < mapGrid[ri].length; ci++) {\r\n                        var cellIdx = mapGrid[ri][ci];\r\n                        var td = tr.insertCell();\r\n                        td.id  = 'pth-kmap-cell-' + cellIdx;\r\n                        var val = self.cells[cellIdx] ? self.cells[cellIdx].textContent : '0';\r\n                        var vs  = document.createElement('span');\r\n                        vs.className = 'pth-kmap-val';\r\n                        vs.textContent = val;\r\n                        vs.style.color = val === '1' ? '#047857' : val === 'X' ? '#92400e' : '#991b1b';\r\n                        var is  = document.createElement('span');\r\n                        is.className = 'pth-kmap-idx';\r\n                        is.textContent = cellIdx;\r\n                        td.appendChild(vs);\r\n                        td.appendChild(is);\r\n                        if (val === '1') td.classList.add('pth-cell-1');\r\n                        if (val === 'X') td.classList.add('pth-cell-x');\r\n                    }\r\n                }\r\n                wrap.appendChild(tbl);\r\n                area.appendChild(wrap);\r\n            }\r\n        },\r\n\r\n        colorKmapCells: function (groups) {\r\n            var self = this;\r\n            for (var i = 0; i < groups.length; i++) {\r\n                var col = self.groupColors[i % self.groupColors.length];\r\n                for (var j = 0; j < groups[i].idxs.length; j++) {\r\n                    var el = document.getElementById('pth-kmap-cell-' + groups[i].idxs[j]);\r\n                    if (el) {\r\n                        el.style.backgroundColor = col.bg;\r\n                        el.style.boxShadow = 'inset 0 0 0 2px ' + col.border;\r\n                    }\r\n                }\r\n            }\r\n        },\r\n\r\n        \/* \u2500\u2500\u2500 K-MAP LAYOUT \u2500\u2500\u2500 *\/\r\n        getKMapLayout: function () {\r\n            var n = this.numVars;\r\n            if (n === 2) return [ [[0,1],[2,3]] ];\r\n            if (n === 3) return [ [[0,1,3,2],[4,5,7,6]] ];\r\n            if (n === 4) return [ [[0,1,3,2],[4,5,7,6],[12,13,15,14],[8,9,11,10]] ];\r\n            if (n === 5) return [\r\n                [[0,1,3,2],[4,5,7,6],[12,13,15,14],[8,9,11,10]],\r\n                [[16,17,19,18],[20,21,23,22],[28,29,31,30],[24,25,27,26]]\r\n            ];\r\n            if (n === 6) {\r\n                var base = [[0,1,3,2],[4,5,7,6],[12,13,15,14],[8,9,11,10]];\r\n                var abOrder = [0,1,3,2];\r\n                return abOrder.map(function (ab) {\r\n                    return base.map(function (row) {\r\n                        return row.map(function (c) { return c + ab * 16; });\r\n                    });\r\n                });\r\n            }\r\n            return [ [[0,1,3,2],[4,5,7,6],[12,13,15,14],[8,9,11,10]] ];\r\n        },\r\n        getColVars: function () {\r\n            var n = this.numVars, vn = this.varNames;\r\n            if (n === 2) return vn[1];\r\n            if (n === 3) return vn[1] + vn[2];\r\n            return vn[n-2] + vn[n-1];\r\n        },\r\n        getRowVars: function () {\r\n            var n = this.numVars, vn = this.varNames;\r\n            if (n === 2) return vn[0];\r\n            if (n === 3) return vn[0];\r\n            if (n === 4) return vn[0] + vn[1];\r\n            if (n === 5) return vn[1] + vn[2];\r\n            if (n === 6) return vn[2] + vn[3];\r\n            return vn[0] + vn[1];\r\n        },\r\n        getGrayLabels: function (bits) {\r\n            if (bits === 1) return ['0','1'];\r\n            return ['00','01','11','10'];\r\n        },\r\n\r\n        \/* \u2500\u2500\u2500 GROUP LEGEND + CARDS \u2500\u2500\u2500 *\/\r\n        renderGroupLegend: function (groups) {\r\n            var self = this;\r\n            var leg  = document.getElementById('pth-group-legend');\r\n            if (!leg) return;\r\n            leg.innerHTML = '';\r\n            for (var i = 0; i < groups.length; i++) {\r\n                var col  = self.groupColors[i % self.groupColors.length];\r\n                var item = document.createElement('div');\r\n                item.className = 'pth-legend-item';\r\n                item.innerHTML = '<div class=\"pth-legend-dot\" style=\"background:' + col.border + ';\"><\/div>' +\r\n                    '<span style=\"font-family:\\'Courier New\\',monospace;font-size:12px;font-weight:800;color:' + col.text + ';\">' + groups[i].term + '<\/span>';\r\n                leg.appendChild(item);\r\n            }\r\n        },\r\n\r\n        renderGroupCards: function (groups) {\r\n            var self  = this;\r\n            var cards = document.getElementById('pth-group-cards');\r\n            if (!cards) return;\r\n            cards.innerHTML = '';\r\n            for (var i = 0; i < groups.length; i++) {\r\n                (function (g, idx) {\r\n                    var col  = self.groupColors[idx % self.groupColors.length];\r\n                    var card = document.createElement('div');\r\n                    card.className = 'pth-group-card';\r\n                    card.style.borderLeftColor = col.border;\r\n                    card.innerHTML =\r\n                        '<div class=\"pth-group-term\" style=\"color:' + col.text + ';\">' + g.term + '<\/div>' +\r\n                        '<div class=\"pth-group-meta\">Cells: {' + g.idxs.join(', ') + '} \\u00b7 Size: ' + g.idxs.length + '<\/div>';\r\n                    card.addEventListener('mouseenter', function () {\r\n                        for (var k = 0; k < g.idxs.length; k++) {\r\n                            var el = document.getElementById('pth-kmap-cell-' + g.idxs[k]);\r\n                            if (el) el.style.boxShadow = 'inset 0 0 0 3px ' + col.border;\r\n                        }\r\n                    });\r\n                    cards.appendChild(card);\r\n                })(groups[i], i);\r\n            }\r\n        },\r\n\r\n        \/* \u2500\u2500\u2500 FIX 3: Boolean Parser \u2014 NO eval() \u2500\u2500\u2500 *\/\r\n        \/* Tokenise and evaluate Boolean expressions safely *\/\r\n        evalExpr: function (expr, ctx) {\r\n            \/* Substitute variables *\/\r\n            var e = expr;\r\n            var vars = Object.keys(ctx).sort(function (a, b) { return b.length - a.length; });\r\n            for (var vi = 0; vi < vars.length; vi++) {\r\n                var v  = vars[vi];\r\n                var re = new RegExp(v.replace(\/[.*+?^${}()|[\\]\\\\]\/g,'\\\\$&'), 'g');\r\n                e = e.replace(re, ctx[v]);\r\n            }\r\n            return this.parseBool(e);\r\n        },\r\n\r\n        parseBool: function (e) {\r\n            \/* Remove spaces *\/\r\n            e = e.replace(\/\\s+\/g, '');\r\n            \/* Evaluate OR (lowest precedence) *\/\r\n            var depth = 0;\r\n            for (var i = e.length - 1; i >= 0; i--) {\r\n                if (e[i] === ')') depth++;\r\n                else if (e[i] === '(') depth--;\r\n                else if (depth === 0 && e[i] === '+') {\r\n                    return (this.parseBool(e.substring(0, i)) | this.parseBool(e.substring(i+1))) & 1;\r\n                }\r\n            }\r\n            \/* Evaluate XOR *\/\r\n            depth = 0;\r\n            for (var j = e.length - 1; j >= 0; j--) {\r\n                if (e[j] === ')') depth++;\r\n                else if (e[j] === '(') depth--;\r\n                else if (depth === 0 && e[j] === '^') {\r\n                    return (this.parseBool(e.substring(0, j)) ^ this.parseBool(e.substring(j+1))) & 1;\r\n                }\r\n            }\r\n            \/* Evaluate AND (implicit or \u00b7) *\/\r\n            depth = 0;\r\n            for (var k = e.length - 1; k >= 1; k--) {\r\n                if (e[k] === ')') depth++;\r\n                else if (e[k] === '(') depth--;\r\n                else if (depth === 0 && e[k] === '\\u00b7') {\r\n                    return (this.parseBool(e.substring(0, k)) & this.parseBool(e.substring(k+1))) & 1;\r\n                }\r\n                \/* Implicit AND: digit\/letter followed by digit\/letter or ( *\/\r\n                else if (depth === 0 && \/[01a-z)]\/i.test(e[k]) && \/[01a-z(]\/i.test(e[k-1])) {\r\n                    return (this.parseBool(e.substring(0, k)) & this.parseBool(e.substring(k))) & 1;\r\n                }\r\n            }\r\n            \/* NOT via trailing ' *\/\r\n            if (e[e.length - 1] === \"'\") {\r\n                return this.parseBool(e.substring(0, e.length - 1)) === 1 ? 0 : 1;\r\n            }\r\n            \/* NOT via leading ! *\/\r\n            if (e[0] === '!') {\r\n                return this.parseBool(e.substring(1)) === 1 ? 0 : 1;\r\n            }\r\n            \/* Parentheses *\/\r\n            if (e[0] === '(' && e[e.length-1] === ')') {\r\n                return this.parseBool(e.substring(1, e.length - 1));\r\n            }\r\n            \/* Literal *\/\r\n            if (e === '0') return 0;\r\n            if (e === '1') return 1;\r\n            return 0;\r\n        },\r\n\r\n        extractVars: function (expr) {\r\n            var found = [];\r\n            var upper = expr.toUpperCase();\r\n            for (var i = 0; i < upper.length; i++) {\r\n                var c = upper[i];\r\n                if (c >= 'A' && c <= 'F' && found.indexOf(c) < 0) found.push(c);\r\n            }\r\n            found.sort();\r\n            return found;\r\n        },\r\n\r\n        \/* \u2500\u2500\u2500 EXPRESSION \u2192 TRUTH TABLE \u2500\u2500\u2500 *\/\r\n        exprToTruthTable: function () {\r\n            var self   = this;\r\n            var exprEl = document.getElementById('pth-bool-expr');\r\n            if (!exprEl || !exprEl.value.trim()) { self.showToast('Enter a Boolean expression!', 'error'); return; }\r\n            var expr = exprEl.value.trim();\r\n            var vars = self.extractVars(expr);\r\n            var n    = vars.length;\r\n            if (!n || n > 6) { self.showToast('Use 1\u20136 variable names (A\u2013F)!', 'error'); return; }\r\n\r\n            var out = document.getElementById('pth-bool-tt-output');\r\n            var tbl = document.getElementById('pth-bool-truth-table');\r\n            if (!out || !tbl) return;\r\n            tbl.innerHTML = '';\r\n\r\n            var head = tbl.insertRow();\r\n            for (var vi = 0; vi < vars.length; vi++) {\r\n                var th = document.createElement('th');\r\n                th.textContent = vars[vi]; head.appendChild(th);\r\n            }\r\n            var fth = document.createElement('th');\r\n            fth.textContent = 'F'; fth.style.background = '#eff6ff'; head.appendChild(fth);\r\n\r\n            var total = Math.pow(2, n);\r\n            for (var i = 0; i < total; i++) {\r\n                var row = tbl.insertRow();\r\n                var bin = pthPad(i.toString(2), n, '0');\r\n                var ctx = {};\r\n                for (var vi2 = 0; vi2 < vars.length; vi2++) { ctx[vars[vi2]] = parseInt(bin[vi2], 10); }\r\n                var res = self.evalExpr(expr, ctx);\r\n                for (var j = 0; j < n; j++) {\r\n                    var td = row.insertCell();\r\n                    td.textContent = bin[j];\r\n                    td.style.color = bin[j] === '1' ? '#047857' : '#334155';\r\n                    td.style.fontFamily = \"'Courier New',monospace\";\r\n                    td.style.fontWeight = '700';\r\n                }\r\n                var fd = row.insertCell();\r\n                fd.textContent = res;\r\n                fd.style.color = res === 1 ? '#047857' : '#991b1b';\r\n                fd.style.fontWeight = '800'; fd.style.fontFamily = \"'Courier New',monospace\";\r\n            }\r\n            out.style.display = 'block';\r\n            self.showToast('Truth table generated!', 'success');\r\n        },\r\n\r\n        exprToKmap: function () {\r\n            var self   = this;\r\n            var exprEl = document.getElementById('pth-bool-expr');\r\n            if (!exprEl || !exprEl.value.trim()) { self.showToast('Enter an expression!', 'error'); return; }\r\n            var expr = exprEl.value.trim();\r\n            var vars = self.extractVars(expr);\r\n            var n    = vars.length;\r\n            if (n < 2 || n > 6) { self.showToast('Need 2\u20136 variables!', 'error'); return; }\r\n\r\n            self.numVars = n;\r\n            var vc = document.getElementById('pth-var-count');\r\n            if (vc) vc.value = n;\r\n            var defaults = ['A','B','C','D','E','F'];\r\n            self.varNames = vars.slice();\r\n            for (var di = 0; di < defaults.length; di++) {\r\n                if (self.varNames.indexOf(defaults[di]) < 0) self.varNames.push(defaults[di]);\r\n            }\r\n            self.buildVarNames();\r\n            self.initTruthTable();\r\n\r\n            var total = Math.pow(2, n);\r\n            for (var i = 0; i < total; i++) {\r\n                var bin = pthPad(i.toString(2), n, '0');\r\n                var ctx = {};\r\n                for (var vi = 0; vi < vars.length; vi++) { ctx[vars[vi]] = parseInt(bin[vi], 10); }\r\n                var res = self.evalExpr(expr, ctx);\r\n                if (self.cells[i]) {\r\n                    self.cells[i].textContent = res.toString();\r\n                    self.cells[i].className   = 'pth-f-cell pth-f-' + res;\r\n                }\r\n            }\r\n            self.switchTab('kmap');\r\n            self.solve();\r\n            self.showToast('Expression loaded into K-Map!', 'success');\r\n        },\r\n\r\n        \/* \u2500\u2500\u2500 CANONICAL FORMS \u2500\u2500\u2500 *\/\r\n        generateCanonical: function () {\r\n            var self    = this;\r\n            var n       = parseInt(document.getElementById('pth-canon-vars').value, 10) || 4;\r\n            var termsEl = document.getElementById('pth-canon-terms');\r\n            var dcEl    = document.getElementById('pth-canon-dc');\r\n            var outEl   = document.getElementById('pth-canonical-output');\r\n            if (!termsEl || !outEl) return;\r\n\r\n            var minterms  = termsEl.value.split(',').map(function (s) { return parseInt(s.trim(),10); }).filter(function (x) { return !isNaN(x); });\r\n            var dontcares = dcEl ? dcEl.value.split(',').map(function (s) { return parseInt(s.trim(),10); }).filter(function (x) { return !isNaN(x); }) : [];\r\n            var vn = ['A','B','C','D','E'];\r\n\r\n            var sopTerms = minterms.map(function (m) {\r\n                var bin = pthPad(m.toString(2), n, '0');\r\n                var parts = [];\r\n                for (var i = 0; i < n; i++) parts.push(bin[i] === '1' ? vn[i] : vn[i] + \"'\");\r\n                return parts.join('');\r\n            });\r\n\r\n            var total    = Math.pow(2, n);\r\n            var maxterms = [];\r\n            for (var i = 0; i < total; i++) {\r\n                if (minterms.indexOf(i) < 0 && dontcares.indexOf(i) < 0) maxterms.push(i);\r\n            }\r\n            var posTerms = maxterms.map(function (m) {\r\n                var bin = pthPad(m.toString(2), n, '0');\r\n                var parts = [];\r\n                for (var i = 0; i < n; i++) parts.push(bin[i] === '0' ? vn[i] : vn[i] + \"'\");\r\n                return '(' + parts.join(' + ') + ')';\r\n            });\r\n\r\n            outEl.textContent =\r\n                'Canonical SOP (\\u03a3m):\\nF = ' + (sopTerms.join(' + ') || '0') + '\\n\\n' +\r\n                'Canonical POS (\\u03a0M):\\nF = ' + (posTerms.join('') || '1') + '\\n\\n' +\r\n                'Minterm list: \\u03a3m(' + minterms.join(',') + \")\\nDon't cares: \" + (dontcares.join(',') || 'none');\r\n            self.showToast('Canonical forms generated!', 'success');\r\n        },\r\n\r\n        \/* \u2500\u2500\u2500 DE MORGAN \/ DUAL \/ COMPLEMENT \u2500\u2500\u2500 *\/\r\n        applyDemorgan: function () {\r\n            var self    = this;\r\n            var exprEl  = document.getElementById('pth-demorgan-expr');\r\n            var outEl   = document.getElementById('pth-demorgan-output');\r\n            if (!exprEl || !outEl) return;\r\n            var expr = exprEl.value.trim();\r\n            if (!expr) { self.showToast('Enter an expression!', 'error'); return; }\r\n            outEl.textContent =\r\n                \"De Morgan's of (\" + expr + \"):\\n\" +\r\n                \"\\u2192 Complement each literal and swap operators:\\n\" +\r\n                \"\\u2192 Replace each X with X', each X' with X\\n\" +\r\n                \"\\u2192 Swap + \\u2194 AND\\n\\n\" +\r\n                \"Example: (AB)' = A' + B'\\n\" +\r\n                \"Example: (A + B)' = A'B'\\n\\n\" +\r\n                \"Original: F = \" + expr + \"\\n\" +\r\n                \"F' = complement (apply K-Map with 0s and 1s swapped for exact result)\";\r\n            self.showToast(\"De Morgan's applied!\", 'info');\r\n        },\r\n\r\n        generateDual: function () {\r\n            var self    = this;\r\n            var exprEl  = document.getElementById('pth-demorgan-expr');\r\n            var outEl   = document.getElementById('pth-demorgan-output');\r\n            if (!exprEl || !outEl) return;\r\n            var expr = exprEl.value.trim();\r\n            if (!expr) { self.showToast('Enter an expression!', 'error'); return; }\r\n            var dual = '';\r\n            for (var i = 0; i < expr.length; i++) {\r\n                var c = expr[i];\r\n                if (c === '+') dual += '\\u00b7';\r\n                else if (c === '\\u00b7') dual += '+';\r\n                else if (c === '0') dual += '1';\r\n                else if (c === '1') dual += '0';\r\n                else dual += c;\r\n            }\r\n            outEl.textContent =\r\n                'Original: F = ' + expr + '\\n' +\r\n                'Dual:     F_D = ' + dual + '\\n\\n' +\r\n                'Rule: Swap all + \\u2194 AND(\\u00b7), swap 0 \\u2194 1\\n' +\r\n                'Duality Principle: dual of any theorem is also a theorem';\r\n            self.showToast('Dual generated!', 'success');\r\n        },\r\n\r\n        generateComplement: function () {\r\n            var self    = this;\r\n            var exprEl  = document.getElementById('pth-demorgan-expr');\r\n            var outEl   = document.getElementById('pth-demorgan-output');\r\n            if (!exprEl || !outEl) return;\r\n            var expr = exprEl.value.trim();\r\n            if (!expr) { self.showToast('Enter an expression!', 'error'); return; }\r\n            var comp = '';\r\n            for (var i = 0; i < expr.length; i++) {\r\n                var c = expr[i];\r\n                if (c === '+') comp += '\\u00b7';\r\n                else if (c === '\\u00b7') comp += '+';\r\n                else if (c === \"'\") { \/* skip \u2014 next char will get complement *\/ }\r\n                else if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')) {\r\n                    \/* Check if next char is ' *\/\r\n                    if (i + 1 < expr.length && expr[i+1] === \"'\") { comp += c; i++; }\r\n                    else comp += c + \"'\";\r\n                } else comp += c;\r\n            }\r\n            outEl.textContent =\r\n                \"Original:   F = \" + expr + \"\\n\" +\r\n                \"Complement: F' = \" + comp + \"\\n\\n\" +\r\n                \"Method: Apply De Morgan's theorem:\\n\" +\r\n                \"\\u2192 Swap + \\u2194 AND\\n\" +\r\n                \"\\u2192 Complement each literal (A\\u2192A', A'\\u2192A)\";\r\n            self.showToast('Complement generated!', 'success');\r\n        },\r\n\r\n        \/* \u2500\u2500\u2500 GATE SIMULATOR \u2500\u2500\u2500 *\/\r\n        buildGateInputs: function () {\r\n            var self = this;\r\n            var n    = self.gateInputCount;\r\n            var row  = document.getElementById('pth-gate-inputs');\r\n            if (!row) return;\r\n            row.innerHTML = '';\r\n            for (var i = 0; i < n; i++) {\r\n                (function (idx) {\r\n                    var wrap = document.createElement('div');\r\n                    wrap.style.textAlign = 'center';\r\n                    var btn = document.createElement('button');\r\n                    btn.className = 'pth-input-toggle';\r\n                    btn.textContent = '0';\r\n                    btn.setAttribute('data-input-idx', idx);\r\n                    btn.setAttribute('aria-label', 'Input ' + String.fromCharCode(65+idx) + ' toggle');\r\n                    btn.setAttribute('aria-pressed', 'false');\r\n                    btn.addEventListener('click', function () {\r\n                        var isHigh = this.textContent === '0';\r\n                        this.textContent = isHigh ? '1' : '0';\r\n                        this.classList.toggle('high', isHigh);\r\n                        this.setAttribute('aria-pressed', isHigh ? 'true' : 'false');\r\n                        self.evalChain();\r\n                    });\r\n                    var lbl = document.createElement('div');\r\n                    lbl.className = 'pth-input-label';\r\n                    lbl.textContent = String.fromCharCode(65 + idx);\r\n                    wrap.appendChild(btn);\r\n                    wrap.appendChild(lbl);\r\n                    row.appendChild(wrap);\r\n                })(i);\r\n            }\r\n        },\r\n\r\n        addGate: function () {\r\n            var self  = this;\r\n            var chain = document.getElementById('pth-gate-chain');\r\n            if (!chain) return;\r\n            self.gateCount++;\r\n            var gIdx = self.gateCount;\r\n\r\n            var row = document.createElement('div');\r\n            row.className = 'pth-gate-row';\r\n            row.setAttribute('data-gate-idx', gIdx);\r\n\r\n            var numSpan = document.createElement('span');\r\n            numSpan.className = 'pth-gate-num';\r\n            numSpan.textContent = 'G' + gIdx;\r\n\r\n            var typeSel = document.createElement('select');\r\n            typeSel.className = 'pth-gate-type-sel';\r\n            typeSel.setAttribute('aria-label', 'Gate ' + gIdx + ' type');\r\n            var gateTypes = ['AND','OR','NOT','NAND','NOR','XOR','XNOR'];\r\n            for (var gi = 0; gi < gateTypes.length; gi++) {\r\n                var opt = document.createElement('option');\r\n                opt.value = gateTypes[gi]; opt.textContent = gateTypes[gi];\r\n                typeSel.appendChild(opt);\r\n            }\r\n            typeSel.addEventListener('change', function () { self.evalChain(); });\r\n\r\n            var inA = self.makeInputSel('A input', gIdx, 'a');\r\n            var inB = self.makeInputSel('B input', gIdx, 'b');\r\n            inA.addEventListener('change', function () { self.evalChain(); });\r\n            inB.addEventListener('change', function () { self.evalChain(); });\r\n\r\n            var outBadge = document.createElement('span');\r\n            outBadge.className = 'pth-gate-out-badge pth-out-0';\r\n            outBadge.id = 'pth-gate-out-' + gIdx;\r\n            outBadge.textContent = '0';\r\n\r\n            var arrSpan = document.createElement('span');\r\n            arrSpan.style.fontWeight = '800';\r\n            arrSpan.style.color = '#334155';\r\n            arrSpan.textContent = '\\u2192';\r\n\r\n            var outLbl = document.createElement('span');\r\n            outLbl.style.fontSize = '11px';\r\n            outLbl.style.fontWeight = '700';\r\n            outLbl.style.color = '#334155';\r\n            outLbl.textContent = '= G' + gIdx;\r\n\r\n            row.appendChild(numSpan);\r\n            row.appendChild(typeSel);\r\n            row.appendChild(inA);\r\n            row.appendChild(inB);\r\n            row.appendChild(arrSpan);\r\n            row.appendChild(outBadge);\r\n            row.appendChild(outLbl);\r\n            chain.appendChild(row);\r\n            self.evalChain();\r\n        },\r\n\r\n        makeInputSel: function (label, gIdx, which) {\r\n            var self = this;\r\n            var sel  = document.createElement('select');\r\n            sel.className = 'pth-gate-input-sel';\r\n            sel.setAttribute('aria-label', 'Gate ' + gIdx + ' ' + label);\r\n            sel.setAttribute('data-which', which);\r\n            for (var i = 0; i < self.gateInputCount; i++) {\r\n                var opt = document.createElement('option');\r\n                opt.value = 'I' + i; opt.textContent = String.fromCharCode(65+i);\r\n                sel.appendChild(opt);\r\n            }\r\n            for (var g = 1; g < gIdx; g++) {\r\n                var gopt = document.createElement('option');\r\n                gopt.value = 'G' + g; gopt.textContent = 'G' + g;\r\n                sel.appendChild(gopt);\r\n            }\r\n            if (which === 'b') sel.selectedIndex = Math.min(1, sel.options.length - 1);\r\n            return sel;\r\n        },\r\n\r\n        \/* FIX 2: sig.startsWith() \u2192 sig.indexOf() === 0 *\/\r\n        getSignalValue: function (sig) {\r\n            var self = this;\r\n            if (sig.indexOf('I') === 0) {\r\n                var idx    = parseInt(sig.slice(1), 10);\r\n                var inputs = document.querySelectorAll('[data-input-idx]');\r\n                return (inputs[idx] && inputs[idx].textContent === '1') ? 1 : 0;\r\n            }\r\n            if (sig.indexOf('G') === 0) {\r\n                var gNum = parseInt(sig.slice(1), 10);\r\n                var el   = document.getElementById('pth-gate-out-' + gNum);\r\n                return el ? parseInt(el.textContent, 10) : 0;\r\n            }\r\n            return 0;\r\n        },\r\n\r\n        evalGate: function (type, a, b) {\r\n            if (type === 'AND')  return (a & b) & 1;\r\n            if (type === 'OR')   return (a | b) & 1;\r\n            if (type === 'NOT')  return a === 1 ? 0 : 1;\r\n            if (type === 'NAND') return ((a & b) ^ 1) & 1;\r\n            if (type === 'NOR')  return ((a | b) ^ 1) & 1;\r\n            if (type === 'XOR')  return (a ^ b) & 1;\r\n            if (type === 'XNOR') return ((a ^ b) ^ 1) & 1;\r\n            return 0;\r\n        },\r\n\r\n        evalChain: function () {\r\n            var self  = this;\r\n            var chain = document.getElementById('pth-gate-chain');\r\n            if (!chain) return;\r\n            var rows    = chain.querySelectorAll('.pth-gate-row');\r\n            var lastOut = 0;\r\n\r\n            Array.prototype.forEach.call(rows, function (row) {\r\n                var gIdx     = row.getAttribute('data-gate-idx');\r\n                var typeSel  = row.querySelector('.pth-gate-type-sel');\r\n                var sels     = row.querySelectorAll('.pth-gate-input-sel');\r\n                var outBadge = document.getElementById('pth-gate-out-' + gIdx);\r\n                if (!typeSel || !outBadge) return;\r\n                var type = typeSel.value;\r\n                var sigA = sels[0] ? sels[0].value : 'I0';\r\n                var sigB = sels[1] ? sels[1].value : 'I1';\r\n                var a    = self.getSignalValue(sigA);\r\n                var b    = self.getSignalValue(sigB);\r\n                var out  = self.evalGate(type, a, b);\r\n                lastOut  = out;\r\n                outBadge.textContent = out;\r\n                outBadge.className   = 'pth-gate-out-badge ' + (out === 1 ? 'pth-out-1' : 'pth-out-0');\r\n            });\r\n\r\n            var resEl    = document.getElementById('pth-chain-result');\r\n            var finalOut = document.getElementById('pth-chain-final-out');\r\n            var finalExp = document.getElementById('pth-chain-explanation');\r\n            if (resEl)    resEl.style.display = rows.length > 0 ? 'block' : 'none';\r\n            if (finalOut) { finalOut.textContent = lastOut; finalOut.className = 'pth-gate-out-badge ' + (lastOut === 1 ? 'pth-out-1' : 'pth-out-0'); }\r\n            if (finalExp) finalExp.textContent = 'Chain output = ' + lastOut + ' (based on current input values)';\r\n        },\r\n\r\n        \/* \u2500\u2500\u2500 GATE REF TABLE \u2500\u2500\u2500 *\/\r\n        showGateRefTable: function () {\r\n            var self     = this;\r\n            var typeEl   = document.getElementById('pth-gate-ref-type');\r\n            var inputsEl = document.getElementById('pth-gate-ref-inputs');\r\n            var tbl      = document.getElementById('pth-gate-ref-table');\r\n            if (!typeEl || !tbl) return;\r\n            var type = typeEl.value;\r\n            var n    = type === 'NOT' ? 1 : parseInt((inputsEl ? inputsEl.value : '2'), 10);\r\n            tbl.innerHTML = '';\r\n            var head = tbl.insertRow();\r\n            var vn   = ['A','B','C','D'];\r\n            for (var v = 0; v < n; v++) {\r\n                var th = document.createElement('th');\r\n                th.textContent = vn[v]; head.appendChild(th);\r\n            }\r\n            var fth = document.createElement('th');\r\n            fth.textContent = type + '(\\u2026)'; fth.style.background = '#eff6ff'; fth.style.color = '#1d4ed8';\r\n            head.appendChild(fth);\r\n\r\n            var total = Math.pow(2, n);\r\n            for (var i = 0; i < total; i++) {\r\n                var row    = tbl.insertRow();\r\n                var bin    = pthPad(i.toString(2), n, '0');\r\n                var inputs = [];\r\n                for (var b = 0; b < n; b++) { inputs.push(parseInt(bin[b], 10)); }\r\n                for (var j = 0; j < n; j++) {\r\n                    var td = row.insertCell();\r\n                    td.textContent = inputs[j];\r\n                    td.style.fontFamily = \"'Courier New',monospace\";\r\n                    td.style.fontWeight = '700';\r\n                    td.style.color = inputs[j] ? '#047857' : '#334155';\r\n                }\r\n                var out;\r\n                if (type === 'NOT')  out = inputs[0] ? 0 : 1;\r\n                else if (type === 'AND')  out = inputs.reduce(function (a,b) { return a & b; }, 1);\r\n                else if (type === 'OR')   out = inputs.reduce(function (a,b) { return a | b; }, 0);\r\n                else if (type === 'NAND') out = (inputs.reduce(function (a,b) { return a & b; }, 1)) ? 0 : 1;\r\n                else if (type === 'NOR')  out = (inputs.reduce(function (a,b) { return a | b; }, 0)) ? 0 : 1;\r\n                else if (type === 'XOR')  out = inputs.reduce(function (a,b) { return a ^ b; }, 0) & 1;\r\n                else if (type === 'XNOR') out = (inputs.reduce(function (a,b) { return a ^ b; }, 0) & 1) ? 0 : 1;\r\n                else out = 0;\r\n                var outTd = row.insertCell();\r\n                outTd.textContent = out;\r\n                outTd.style.fontFamily = \"'Courier New',monospace\";\r\n                outTd.style.fontWeight = '800';\r\n                outTd.style.color = out ? '#047857' : '#991b1b';\r\n            }\r\n        },\r\n\r\n        \/* \u2500\u2500\u2500 UNIVERSAL GATE CONVERTER \u2500\u2500\u2500 *\/\r\n        convertUniversal: function () {\r\n            var self   = this;\r\n            var exprEl = document.getElementById('pth-universal-expr');\r\n            var outEl  = document.getElementById('pth-universal-output');\r\n            if (!exprEl || !outEl) return;\r\n            var expr = exprEl.value.trim();\r\n            if (!expr) { self.showToast('Enter an expression!', 'error'); return; }\r\n            outEl.textContent =\r\n                'NAND-only implementation of: F = ' + expr + '\\n\\n' +\r\n                'Conversion rules:\\n' +\r\n                '\\u2192 NOT(X)   = NAND(X, X)\\n' +\r\n                '\\u2192 AND(A,B) = NAND(NAND(A,B), NAND(A,B))\\n' +\r\n                '\\u2192 OR(A,B)  = NAND(NAND(A,A), NAND(B,B))\\n\\n' +\r\n                pthRepeat('\\u2500', 44) + '\\n\\n' +\r\n                'NOR-only implementation of: F = ' + expr + '\\n\\n' +\r\n                'Conversion rules:\\n' +\r\n                '\\u2192 NOT(X)   = NOR(X, X)\\n' +\r\n                '\\u2192 OR(A,B)  = NOR(NOR(A,B), NOR(A,B))\\n' +\r\n                '\\u2192 AND(A,B) = NOR(NOR(A,A), NOR(B,B))';\r\n            self.showToast('Universal gate implementations generated!', 'success');\r\n        },\r\n\r\n        \/* \u2500\u2500\u2500 HDL GENERATOR \u2500\u2500\u2500 *\/\r\n        generateHdl: function () {\r\n            var self   = this;\r\n            var eqEl   = document.getElementById('pth-hdl-eq');\r\n            var modEl  = document.getElementById('pth-hdl-module');\r\n            var varsEl = document.getElementById('pth-hdl-vars');\r\n            if (!eqEl || !eqEl.value.trim()) { self.showToast('Enter a Boolean equation first!', 'error'); return; }\r\n\r\n            var eq   = eqEl.value.trim();\r\n            var mod  = (modEl ? modEl.value.trim() : '') || 'logic_minimized';\r\n            var vars = (varsEl ? varsEl.value : 'A,B,C,D').split(',').map(function (v) { return v.trim(); }).filter(Boolean);\r\n\r\n            \/* Convert to language operators *\/\r\n            function toVerilog(e) {\r\n                var r = e;\r\n                r = r.replace(\/([A-Za-z])'\/g, '~$1');\r\n                r = r.replace(\/\\+\/g, ' | ');\r\n                r = r.replace(\/([A-Za-z\\d])([A-Za-z~])\/g, '$1 & $2');\r\n                r = r.replace(\/\\)\\s*([A-Za-z~])\/g, ') & $1');\r\n                return r;\r\n            }\r\n            function toVhdl(e) {\r\n                var r = e;\r\n                r = r.replace(\/([A-Za-z])'\/g, 'not $1');\r\n                r = r.replace(\/\\+\/g, ' or ');\r\n                r = r.replace(\/([A-Za-z\\d])([A-Za-z])\/g, '$1 and $2');\r\n                return r;\r\n            }\r\n            function toCLang(e) {\r\n                var r = e;\r\n                r = r.replace(\/([A-Za-z])'\/g, '!$1');\r\n                r = r.replace(\/\\+\/g, ' || ');\r\n                r = r.replace(\/([A-Za-z\\d])([A-Za-z!])\/g, '$1 && $2');\r\n                return r;\r\n            }\r\n            function toPython(e) {\r\n                var r = e;\r\n                r = r.replace(\/([A-Za-z])'\/g, 'not $1');\r\n                r = r.replace(\/\\+\/g, ' or ');\r\n                r = r.replace(\/([A-Za-z\\d])([A-Za-z])\/g, '$1 and $2');\r\n                return r;\r\n            }\r\n\r\n            var vDecl = vars.map(function (v) { return '    input ' + v; }).join(',\\n');\r\n            var cArgs = vars.map(function (v) { return 'int ' + v; }).join(', ');\r\n            var zeros = vars.map(function () { return '0'; }).join(', ');\r\n\r\n            self.hdlResults = {\r\n                verilog:\r\n                    '\/\/ Verilog \u2014 PTH Digital Logic Studio Pro v2.0\\n' +\r\n                    'module ' + mod + '(\\n' + vDecl + ',\\n    output F\\n);\\n\\n' +\r\n                    '    assign F = ' + toVerilog(eq) + ';\\n\\nendmodule',\r\n                vhdl:\r\n                    '-- VHDL \u2014 PTH Digital Logic Studio Pro v2.0\\nlibrary IEEE;\\nuse IEEE.STD_LOGIC_1164.ALL;\\n\\n' +\r\n                    'entity ' + mod + ' is\\n    Port (\\n' +\r\n                    vars.map(function (v) { return '        ' + v + ' : in  STD_LOGIC'; }).join(';\\n') +\r\n                    ';\\n        F : out STD_LOGIC\\n    );\\nend ' + mod + ';\\n\\n' +\r\n                    'architecture Behavioral of ' + mod + ' is\\nbegin\\n' +\r\n                    '    F <= ' + toVhdl(eq) + ';\\nend Behavioral;',\r\n                sv:\r\n                    '\/\/ SystemVerilog \u2014 PTH Digital Logic Studio Pro v2.0\\nmodule ' + mod + '(\\n' +\r\n                    vDecl + ',\\n    output logic F\\n);\\n\\n' +\r\n                    '    always_comb begin\\n        F = ' + toVerilog(eq) + ';\\n    end\\n\\nendmodule',\r\n                c:\r\n                    '\/* C\/C++ \u2014 PTH Digital Logic Studio Pro v2.0 *\/\\n#include <stdbool.h>\\n\\n' +\r\n                    'bool ' + mod + '(' + cArgs + ') {\\n' +\r\n                    '    return (' + toCLang(eq) + ');\\n}\\n\\n' +\r\n                    '\/* Example: bool r = ' + mod + '(' + zeros + '); *\/',\r\n                python:\r\n                    '# Python \u2014 PTH Digital Logic Studio Pro v2.0\\n\\n' +\r\n                    'def ' + mod + '(' + vars.join(', ') + '):\\n' +\r\n                    '    return bool(' + toPython(eq) + ')\\n\\n' +\r\n                    '# Example: result = ' + mod + '(' + zeros + ')'\r\n            };\r\n\r\n            self.showHdlOutput(self.currentHdl);\r\n            self.showToast('All 5 formats generated!', 'success');\r\n        },\r\n\r\n        switchHdl: function (type) {\r\n            var self = this;\r\n            self.currentHdl = type;\r\n            pthEach('#pth-logic-wrapper [data-hdl]', function (btn) {\r\n                var isActive = btn.getAttribute('data-hdl') === type;\r\n                btn.classList.toggle('pth-active', isActive);\r\n                btn.setAttribute('aria-selected', isActive ? 'true' : 'false');\r\n            });\r\n            self.showHdlOutput(type);\r\n        },\r\n\r\n        showHdlOutput: function (type) {\r\n            var el = document.getElementById('pth-hdl-output');\r\n            if (!el) return;\r\n            el.textContent = this.hdlResults[type] || 'Click \"Generate All Formats\" first';\r\n        },\r\n\r\n        exportHdl: function () {\r\n            var self = this;\r\n            var el   = document.getElementById('pth-hdl-output');\r\n            if (!el || !el.textContent.trim() || el.textContent.indexOf('Generate') >= 0) {\r\n                self.showToast('Generate code first!', 'error'); return;\r\n            }\r\n            var exts = { verilog:'.v', vhdl:'.vhd', sv:'.sv', c:'.c', python:'.py' };\r\n            var ext  = exts[self.currentHdl] || '.txt';\r\n            var blob = new Blob([el.textContent], { type: 'text\/plain' });\r\n            var url  = URL.createObjectURL(blob);\r\n            var a    = document.createElement('a');\r\n            a.href = url; a.download = 'logic_minimized' + ext; a.click();\r\n            URL.revokeObjectURL(url);\r\n            self.showToast('File exported!', 'success');\r\n        },\r\n\r\n        \/* \u2500\u2500\u2500 LOAD SAMPLE (rotating study examples) \u2500\u2500\u2500 *\/\r\n        loadSample: function () {\r\n            var self   = this;\r\n            var sample = self.samples[self.sampleIdx % self.samples.length];\r\n            self.sampleIdx++;\r\n\r\n            self.numVars = sample.vars;\r\n            var vc = document.getElementById('pth-var-count');\r\n            if (vc) vc.value = sample.vars;\r\n            self.buildVarNames();\r\n            self.initTruthTable();\r\n\r\n            for (var i = 0; i < self.cells.length; i++) {\r\n                if (sample.minterms.indexOf(i) >= 0) {\r\n                    self.cells[i].textContent = '1'; self.cells[i].className = 'pth-f-cell pth-f-1';\r\n                } else if (sample.dc.indexOf(i) >= 0) {\r\n                    self.cells[i].textContent = 'X'; self.cells[i].className = 'pth-f-cell pth-f-x';\r\n                }\r\n            }\r\n            self.solve();\r\n            self.showToast('Sample ' + self.sampleIdx + '\/6: ' + sample.name, 'success');\r\n        },\r\n\r\n        \/* \u2500\u2500\u2500 RANDOM EXAMPLE \u2500\u2500\u2500 *\/\r\n        randomExample: function () {\r\n            var self = this;\r\n            for (var i = 0; i < self.cells.length; i++) {\r\n                var r = Math.random();\r\n                var v = r < 0.4 ? '1' : r < 0.55 ? 'X' : '0';\r\n                self.cells[i].textContent = v;\r\n                self.cells[i].className   = 'pth-f-cell pth-f-' + (v === 'X' ? 'x' : v);\r\n            }\r\n            self.solve();\r\n            self.showToast('Random example generated!', 'info');\r\n        },\r\n\r\n        \/* \u2500\u2500\u2500 CLEAR ALL \u2500\u2500\u2500 *\/\r\n        clearAll: function () {\r\n            var self = this;\r\n            for (var i = 0; i < self.cells.length; i++) {\r\n                self.cells[i].textContent = '0';\r\n                self.cells[i].className   = 'pth-f-cell pth-f-0';\r\n            }\r\n            self.solve();\r\n            self.showToast('Cleared!', 'info');\r\n        },\r\n\r\n        \/* \u2500\u2500\u2500 FULL WIDTH \u2500\u2500\u2500 *\/\r\n        toggleWidth: function () {\r\n            var layout  = document.getElementById('pth-logic-layout');\r\n            var sidebar = document.getElementById('pth-logic-sidebar');\r\n            var btn     = document.getElementById('pth-dl-fw-btn');\r\n            if (!layout || !sidebar || !btn) return;\r\n            if (layout.classList.contains('pth-full-width')) {\r\n                layout.classList.remove('pth-full-width');\r\n                sidebar.style.display = '';\r\n                btn.textContent = '\\u29c6 Full Width';\r\n            } else {\r\n                layout.classList.add('pth-full-width');\r\n                sidebar.style.display = 'none';\r\n                btn.textContent = '\\u25e8 Split View';\r\n            }\r\n        },\r\n\r\n        \/* \u2500\u2500\u2500 HELPERS \u2500\u2500\u2500 *\/\r\n        setEl: function (id, v) { var el = document.getElementById(id); if (el) el.textContent = v; },\r\n\r\n        copyText: function (text) {\r\n            var self = this;\r\n            try {\r\n                navigator.clipboard.writeText(text).then(function () {\r\n                    self.showToast('Copied!', 'success');\r\n                }).catch(function () { self.fallbackCopy(text); });\r\n            } catch(e) { self.fallbackCopy(text); }\r\n        },\r\n\r\n        fallbackCopy: function (text) {\r\n            var ta = document.createElement('textarea');\r\n            ta.value = text; ta.style.position = 'fixed'; ta.style.top = '-9999px';\r\n            document.body.appendChild(ta); ta.select();\r\n            try { document.execCommand('copy'); this.showToast('Copied!', 'success'); } catch(e) {}\r\n            document.body.removeChild(ta);\r\n        },\r\n\r\n        showToast: function (msg, type) {\r\n            var c = document.getElementById('pth-logic-toast');\r\n            if (!c) return;\r\n            var t = document.createElement('div');\r\n            t.className = 'pth-toast-msg pth-toast-' + (type || 'info');\r\n            t.textContent = msg;\r\n            c.appendChild(t);\r\n            setTimeout(function () { if (t.parentNode) t.parentNode.removeChild(t); }, 3500);\r\n        }\r\n    };\r\n\r\n    \/* \u2500\u2500 4-LAYER BOOTSTRAP \u2500\u2500 *\/\r\n    function runInit() {\r\n        if (!window.pthLogicApp.initialized &&\r\n            document.getElementById('pth-logic-wrapper')) {\r\n            window.pthLogicApp.initialized = true;\r\n            window.pthLogicApp.init();\r\n        }\r\n    }\r\n    runInit();\r\n    if (document.readyState === 'loading') {\r\n        document.addEventListener('DOMContentLoaded', runInit);\r\n    }\r\n    window.addEventListener('load', function () { setTimeout(runInit, 50); });\r\n    if (!window.pthLogicApp.initialized && typeof MutationObserver !== 'undefined') {\r\n        var pthObs = new MutationObserver(function () {\r\n            if (document.getElementById('pth-logic-wrapper')) {\r\n                pthObs.disconnect(); runInit();\r\n            }\r\n        });\r\n        pthObs.observe(document.body || document.documentElement, { childList: true, subtree: true });\r\n        setTimeout(function () { pthObs.disconnect(); }, 10000);\r\n    }\r\n})();\r\n<\/script>\n\n\n\n<style>\n.pth-feature-wrap{display:grid;grid-template-columns:repeat(auto-fit,minmax(280px,1fr));gap:20px;margin-bottom:30px}\n.pth-feat-box{border:1px solid #e2e8f0;background:#fff;padding:24px;border-radius:12px;box-shadow:0 4px 6px -1px rgba(0,0,0,0.02);transition:all .3s ease}\n.pth-feat-box:hover{border-color:#bfdbfe;transform:translateY(-3px);box-shadow:0 10px 15px -3px rgba(0,0,0,0.05)}\n.pth-feat-title{font-size:1.05rem;font-weight:800;color:#0f172a;margin-bottom:10px;display:flex;align-items:center;gap:10px}\n.pth-feat-text{font-size:.9rem;color:#1e293b;line-height:1.6;margin:0;font-weight:500}\n.pth-steps-wrap{border:1px solid #e2e8f0;background:#fff;padding:40px 30px;border-radius:16px;text-align:center;box-shadow:0 4px 6px -1px rgba(0,0,0,0.02);margin-bottom:40px}\n.pth-steps-title{font-size:1.2rem;font-weight:800;color:#0f172a;text-transform:uppercase;margin-bottom:35px;letter-spacing:1px}\n.pth-steps-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:30px}\n.pth-step-item{display:flex;flex-direction:column;align-items:center}\n.pth-step-num{width:45px;height:45px;background:#2563eb;color:#fff;border-radius:50%;display:flex;align-items:center;justify-content:center;font-weight:800;font-size:1.2rem;margin-bottom:15px;box-shadow:0 4px 10px rgba(37,99,235,.3)}\n.pth-step-name{font-weight:800;color:#0f172a;margin-bottom:8px;font-size:1rem}\n.pth-step-desc{font-size:.9rem;color:#1e293b;line-height:1.5;margin:0;font-weight:500}\n<\/style>\n\n<div class=\"pth-feature-wrap\">\n    <div class=\"pth-feat-box\">\n        <div class=\"pth-feat-title\">\ud83d\udfe2 2\u20136 Variable K-Map with Quine-McCluskey + Petrick&#8217;s Method<\/div>\n        <p class=\"pth-feat-text\">The \ud83d\uddfa\ufe0f K-Map Solver tab handles 2 through 6 variable Karnaugh Maps \u2014 the 6-variable case renders four simultaneous 4\u00d74 grids following Gray code ordering. The minimization engine uses the complete Quine-McCluskey algorithm: prime implicant generation through iterative one-bit difference merging, prime implicant chart construction, essential prime implicant identification, and greedy cover for any remaining minterms. Petrick&#8217;s Method is available as an alternative \u2014 it computes all equally minimal solutions using set product expansion, displaying every valid minimum cover when more than one exists. Custom variable names let you rename A B C D E F to any circuit-specific identifiers. A step-by-step trace shows the exact sequence from minterms to prime implicants to final equation.<\/p>\n    <\/div>\n    <div class=\"pth-feat-box\">\n        <div class=\"pth-feat-title\">\ud83d\udd35 Boolean Expression Tools and Logic Gate Simulator<\/div>\n        <p class=\"pth-feat-text\">The \u26a1 Boolean Tools tab converts any typed Boolean expression directly to a truth table \u2014 supporting AND (concatenation), OR (+), NOT (&#8216;), XOR (^), and parentheses. Send the result directly to the K-Map Solver with one click. The Canonical Forms generator takes a minterm list and produces the full canonical SOP (Sum of Minterms) and canonical POS (Product of Maxterms) expansions. De Morgan&#8217;s theorem, dual expression, and complement transformations are available as one-click operations. The \ud83d\udd0c Gate Simulator chains up to 8 logic gates (AND, OR, NOT, NAND, NOR, XOR, XNOR) with 2\u20136 live input signal toggles. Gate outputs feed subsequent gates \u2014 click any input button to flip 0\/1 and see the entire chain update instantly.<\/p>\n    <\/div>\n    <div class=\"pth-feat-box\">\n        <div class=\"pth-feat-title\">\ud83d\udfe3 5-Language HDL Code Generator from Any K-Map Solution<\/div>\n        <p class=\"pth-feat-text\">The \ud83d\udcbb HDL Code tab generates production-ready hardware description and programming code in five languages simultaneously from any Boolean equation \u2014 Verilog (<code>assign<\/code> statement with proper <code>~<\/code> NOT, <code>&amp;<\/code> AND, <code>|<\/code> OR), VHDL (complete <code>entity<\/code> + <code>architecture Behavioral<\/code> block with <code>and<\/code>\/<code>or<\/code>\/<code>not<\/code> operators), SystemVerilog (<code>always_comb<\/code> block), C\/C++ (typed <code>bool<\/code> function with <code>&amp;&amp;<\/code>\/<code>||<\/code>\/<code>!<\/code>), and Python (def function with <code>and<\/code>\/<code>or<\/code>\/<code>not<\/code>). The Open in HDL button in the K-Map tab auto-populates the equation from the current solution. Export any format as a file with the correct extension (.v \/ .vhd \/ .sv \/ .c \/ .py).<\/p>\n    <\/div>\n<\/div>\n\n<div class=\"pth-steps-wrap\">\n    <div class=\"pth-steps-title\">How to Use Digital Logic Studio Pro<\/div>\n    <div class=\"pth-steps-grid\">\n        <div class=\"pth-step-item\">\n            <div class=\"pth-step-num\">1<\/div>\n            <div class=\"pth-step-name\">Enter Your Truth Table<\/div>\n            <p class=\"pth-step-desc\">Select the number of variables (2\u20136) from the dropdown. The truth table builds automatically with all 2\u207f rows. Click any F cell to cycle through 0 (output 0, red) \u2192 1 (output 1, green) \u2192 X (don&#8217;t care, amber) \u2192 back to 0. Use Set All 0 or Set All 1 for quick fills. Click \ud83d\udca1 Load Sample to see a pre-filled 4-variable example \u2014 F = \u03a3m(0,2,5,7,8,10,13,15). Click \ud83c\udfb2 Random for a random pattern.<\/p>\n        <\/div>\n        <div class=\"pth-step-item\">\n            <div class=\"pth-step-num\">2<\/div>\n            <div class=\"pth-step-name\">Choose Mode and Solve<\/div>\n            <p class=\"pth-step-desc\">Select SOP (Sum of Products \u2014 minimises 1s) or POS (Product of Sums \u2014 minimises 0s). Choose Greedy for the fastest single solution or Petrick&#8217;s Method to find all equally minimal solutions. Click \u2728 Generate Solution. The K-Map grid shows colour-coded groupings \u2014 each group a different colour. The step-by-step trace below shows exactly which prime implicants were found and which are essential. Hover any group card to highlight its cells in the K-Map.<\/p>\n        <\/div>\n        <div class=\"pth-step-item\">\n            <div class=\"pth-step-num\">3<\/div>\n            <div class=\"pth-step-name\">Use Boolean Tools<\/div>\n            <p class=\"pth-step-desc\">Switch to \u26a1 Boolean Tools. Type any expression like <code>AB' + CD<\/code> or <code>(A+B)(C'D)<\/code> and click \u2192 Truth Table to see the full output for all input combinations. Click \ud83d\uddfa\ufe0f \u2192 K-Map Solver to send the result directly to the K-Map tab for minimization. Use the Canonical Forms section to generate \u03a3m SOP and \u03a0M POS expanded forms from a minterm list. Try De Morgan&#8217;s, Dual, and Complement one-click transforms on any expression.<\/p>\n        <\/div>\n        <div class=\"pth-step-item\">\n            <div class=\"pth-step-num\">4<\/div>\n            <div class=\"pth-step-name\">Generate HDL Code<\/div>\n            <p class=\"pth-step-desc\">From the K-Map result, click \ud83d\udcbb Open in HDL \u2014 the minimized equation loads automatically. Or switch to the \ud83d\udcbb HDL tab manually and type any equation. Set the module\/function name and variable list, then click \u26a1 Generate All Formats. Switch between Verilog, VHDL, SystemVerilog, C, and Python tabs to see each format. Click \ud83d\udccb Copy Code or \ud83d\udce4 Export File to save with the correct file extension for your toolchain.<\/p>\n        <\/div>\n    <\/div>\n<\/div>\n\n\n\n<p class=\"wp-block-paragraph\">Last updated: June 2026<\/p>\n\n\n\n<h2 id=\"\ud83d\udd34-how-the-quine-mc-cluskey-algorithm-works-step-by-step\" class=\"wp-block-heading\">\ud83d\udd34 <strong>How the Quine-McCluskey Algorithm Works \u2014 Step by Step<\/strong><\/h2>\n\n\n<figure class=\"pth-article-figure pth-img-left\" style=\"float:left; width:600px; max-width:100%; margin:4px 28px 16px 0; clear:left;\"><img decoding=\"async\" src=\"https:\/\/schoolict.net\/tools\/wp-content\/uploads\/2026\/06\/quine-mccluskey-steps-diagram-800x447.jpeg\" alt=\"Quine-McCluskey algorithm step by step diagram showing prime implicant generation chart and essential prime implicant selection for 4-variable Boolean function\" width=\"600\" height=\"338\" loading=\"lazy\" data-no-lazy=\"1\" class=\"pth-article-img\" style=\"width:100%;height:auto;display:block;border-radius:10px;border:1px solid #e2e8f0;\"><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">The Quine-McCluskey method is the algorithmic equivalent of the Karnaugh map process \u2014 where a K-Map relies on visual grouping that humans perform intuitively, Quine-McCluskey performs the same minimization systematically through combinatorial comparison. The process has three distinct stages. Stage one generates all prime implicants: start with the minterms as one-bit binary strings, group them by number of 1-bits (Hamming weight), then compare adjacent groups looking for pairs that differ in exactly one bit position. When a difference is found, replace that bit with a dash (don&#8217;t care) and record the merged term. Repeat until no more merges are possible. Every term that was never merged is a prime implicant \u2014 a minimal group of cells that cannot be absorbed into a larger valid group.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Stage two constructs the prime implicant chart: a matrix with minterms as columns and prime implicants as rows, with a mark wherever a prime implicant covers a minterm. Any minterm covered by exactly one prime implicant forces that prime implicant into the solution \u2014 these are essential prime implicants. Stage three covers any remaining uncovered minterms using additional prime implicants. The greedy approach selects the prime implicant covering the most uncovered minterms at each step. Petrick&#8217;s Method instead builds a Boolean product of sums from the chart and multiplies it out to find all possible complete covers \u2014 identifying every set of prime implicants that covers all minterms, then selecting the sets of minimum size. This tool implements both approaches, with Petrick&#8217;s capped at 1024 product terms for browser performance on large problems.<\/p>\n\n\n\n<h2 id=\"\ud83d\udfe1-k-map-grouping-rules-what-makes-a-valid-group-and-why-size-matters\" class=\"wp-block-heading\">\ud83d\udfe1 <strong>K-Map Grouping Rules \u2014 What Makes a Valid Group and Why Size Matters<\/strong><\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Karnaugh map cells are arranged so that adjacent cells (horizontally and vertically) differ in exactly one variable \u2014 the Gray code ordering (00, 01, 11, 10) rather than binary counting (00, 01, 10, 11) ensures this property. When cells with F=1 are adjacent, they can be grouped and the differing variable cancels out of the product term. A group of 2 adjacent 1-cells eliminates one variable. A group of 4 eliminates two variables. A group of 8 eliminates three. For an n-variable K-Map, a group of 2\u1d4f cells produces a term with n\u2212k literals. The largest valid groups produce the fewest literals \u2014 maximizing group size is the primary objective of K-Map minimization.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Groups must always be powers of 2 \u2014 groups of 3, 5, 6, or 7 are never valid. Groups wrap around edges: the left and right edges of a K-Map are logically adjacent, as are the top and bottom edges. In a 4-variable K-Map, the four corners form a valid group of 4 \u2014 each corner is adjacent to the two other corners sharing its row or column through wrap-around. Don&#8217;t care cells (X) can be included in any group if they help enlarge it \u2014 they cost nothing and can only improve the minimization. Once minimization is complete, don&#8217;t cares that were not included in any group take whatever value is more convenient for the implementation (hardware can ignore them). A cell with F=1 may be covered by multiple groups \u2014 every 1 must be covered by at least one group, but being covered multiple times is acceptable and sometimes necessary to allow larger groups.<\/p>\n\n\n\n<h3 id=\"\ud83d\udfe2-petricks-method-vs-greedy-when-the-difference-matters\" class=\"wp-block-heading\">\ud83d\udfe2 <strong>Petrick&#8217;s Method vs Greedy \u2014 When the Difference Matters<\/strong><\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">The greedy algorithm for prime implicant selection is fast and usually produces a minimal or near-minimal result \u2014 for most K-Map problems in textbooks and coursework, it gives the same answer as Petrick&#8217;s Method. The difference appears in cases where multiple prime implicants cover the same set of remaining minterms with equal cost. A greedy algorithm breaks these ties arbitrarily, which means it may select a valid but non-unique solution without indicating that alternatives exist. Petrick&#8217;s Method guarantees finding every minimal cover \u2014 all solutions with the same minimum number of product terms and the same total literal count. When a professor asks for &#8220;the minimized expression&#8221; and there are two equally minimal forms, Petrick&#8217;s Method reveals both, which matters for circuit implementation choices where component availability or wiring topology might favor one solution over another.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>\ud83d\udd35 <strong>SOP (Sum of Products)<\/strong> minimizes the 1-cells \u2014 the resulting AND-OR two-level circuit directly implements the expression. Each product term maps to an AND gate; the sum maps to an OR gate combining all AND outputs.<\/li>\n\n\n\n<li>\ud83d\udfe0 <strong>POS (Product of Sums)<\/strong> minimizes the 0-cells \u2014 the resulting OR-AND two-level circuit is the dual structure. Each sum term maps to an OR gate; the product maps to an AND gate combining all OR outputs. POS is preferred when the number of 0-cells is smaller than the number of 1-cells.<\/li>\n\n\n\n<li>\ud83d\udfe3 <strong>6-variable K-Maps<\/strong> are rarely used by hand because the four-map structure is difficult to visualize \u2014 corner adjacencies between maps require tracking which edges of different sub-maps are logically adjacent. The solver handles this automatically through its index mapping, making 6-variable minimization practical in a browser tool where it would be error-prone by hand.<\/li>\n<\/ul>\n\n\n\n<h2 id=\"\ud83d\udfe1-hdl-output-formats-what-each-language-is-used-for\" class=\"wp-block-heading\">\ud83d\udfe1 <strong>HDL Output Formats \u2014 What Each Language Is Used For<\/strong><\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Verilog and VHDL are the two dominant hardware description languages for digital logic design. Verilog, developed at Gateway Design Automation in 1984, uses a C-like syntax with <code>&amp;<\/code> for AND, <code>|<\/code> for OR, <code>~<\/code> for NOT, and <code>^<\/code> for XOR. The <code>assign<\/code> keyword creates a continuous assignment \u2014 a combinational logic statement that updates immediately whenever any input changes. SystemVerilog extends Verilog with additional data types and behavioral constructs; the <code>always_comb<\/code> block is the SystemVerilog-recommended way to describe combinational logic because the simulator automatically infers the sensitivity list rather than requiring manual specification.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">VHDL (VHSIC Hardware Description Language), developed under US Department of Defense initiative in the 1980s, uses English-word operators (<code>and<\/code>, <code>or<\/code>, <code>not<\/code>, <code>xor<\/code>) and requires explicit type declarations \u2014 <code>STD_LOGIC<\/code> for single-bit signals, <code>STD_LOGIC_VECTOR<\/code> for buses. A VHDL design always consists of at least two parts: the <code>entity<\/code> declaration (the interface \u2014 what signals go in and out) and the <code>architecture<\/code> body (the implementation). The C and Python outputs are useful for software simulation of logic functions \u2014 testing Boolean expressions in unit test frameworks, generating expected outputs for verification testbenches, or embedding logic functions in embedded systems firmware where a hardware implementation is not needed. Use our <a href=\"https:\/\/schoolict.net\/tools\/advanced-k-map-solver\/\">Digital Logic Studio Pro<\/a> to generate all five formats from any K-Map solution. For deeper coverage see our <a href=\"https:\/\/schoolict.net\/tools\/advanced-k-map-solver-theory\/\">complete K-Map and Boolean logic guide<\/a>.<\/p>\n\n\n\n<style>\n.pth-faq-section{margin-top:50px;margin-bottom:40px;font-family:inherit}\n.pth-faq-header{font-size:1.8rem;font-weight:800;color:#0f172a;margin-bottom:25px;border-bottom:2px solid #e2e8f0;padding-bottom:10px;display:flex;align-items:center;gap:10px}\n.pth-faq-grid{display:grid;grid-template-columns:100%;gap:20px}\n@media(min-width:768px){.pth-faq-grid{grid-template-columns:repeat(2,1fr)}}\n@media(min-width:1024px){.pth-faq-grid{grid-template-columns:repeat(3,1fr)}}\n.pth-faq-card{background:#f8fafc;padding:24px;border-radius:12px;border:1px solid #e2e8f0;transition:transform .2s ease;break-inside:avoid}\n.pth-faq-card:hover{transform:translateY(-3px);box-shadow:0 4px 12px rgba(0,0,0,.05)}\n.pth-faq-q{color:#0f172a;font-size:1rem;font-weight:700;margin:0 0 12px;line-height:1.4}\n.pth-faq-a{margin:0;font-size:.95rem;color:#1e293b;line-height:1.6;font-weight:500}\n<\/style>\n\n<div class=\"pth-faq-section\">\n    <div class=\"pth-faq-header\">\ud83e\udd14 Frequently Asked Questions<\/div>\n    <div class=\"pth-faq-grid\">\n\n        <div class=\"pth-faq-card\">\n            <p class=\"pth-faq-q\">What is the maximum number of variables this K-Map solver supports?<\/p>\n            <p class=\"pth-faq-a\">The solver supports 2 through 6 variables. A 6-variable K-Map contains 64 cells (2\u2076) rendered as four 4\u00d74 grids, one for each combination of the first two variables (AB = 00, 01, 11, 10). The Quine-McCluskey algorithm runs on all 64 cells simultaneously regardless of display layout. Petrick&#8217;s Method on 6-variable problems with many minterms can generate a large number of product terms during expansion \u2014 the implementation caps at 1024 product terms to maintain browser responsiveness. For most practical 6-variable problems with reasonable minterm counts, this limit is not reached.<\/p>\n        <\/div>\n\n        <div class=\"pth-faq-card\">\n            <p class=\"pth-faq-q\">What does &#8220;don&#8217;t care&#8221; (X) mean in a K-Map and how does it help?<\/p>\n            <p class=\"pth-faq-a\">A don&#8217;t care (X) represents an input combination that either never occurs in the real system (an invalid state) or whose output value doesn&#8217;t matter for correct operation. Since the output can be either 0 or 1 for a don&#8217;t care cell, the minimization algorithm assigns it whichever value allows the largest possible groupings. Don&#8217;t cares can only reduce the number of product terms in the minimized expression \u2014 they never increase it. In sequential logic, unused state encodings are common sources of don&#8217;t cares. Click any F cell until it shows X to mark it as a don&#8217;t care.<\/p>\n        <\/div>\n\n        <div class=\"pth-faq-card\">\n            <p class=\"pth-faq-q\">How does the Boolean expression parser handle operator precedence?<\/p>\n            <p class=\"pth-faq-a\">The Boolean expression evaluator follows standard operator precedence: NOT (&#8216;) has the highest precedence, AND (implicit concatenation or \u00b7) is second, and OR (+) has the lowest. So <code>AB' + CD<\/code> evaluates as <code>(A AND (NOT B)) OR (C AND D)<\/code>. Parentheses override precedence as in standard algebra. The evaluator replaces variable names with their binary values for each row of the truth table, then applies the operators. XOR uses the ^ symbol. For complex nested expressions, adding explicit parentheses is recommended to ensure the intended grouping.<\/p>\n        <\/div>\n\n        <div class=\"pth-faq-card\">\n            <p class=\"pth-faq-q\">What is the difference between canonical SOP and minimized SOP?<\/p>\n            <p class=\"pth-faq-a\">Canonical SOP (also called the standard SOP or sum of minterms) represents every minterm as a full product term using all n variables \u2014 every variable appears in either complemented or uncomplemented form. For a 4-variable function with minterm 5 (binary 0101), the canonical minterm is A&#8217;BC&#8217;D. The canonical SOP is unique and maximally expanded. Minimized SOP (what the K-Map produces) groups minterms into prime implicants, eliminating one variable per grouping step. The minimized expression is smaller and directly maps to a two-level AND-OR gate circuit with fewer gates and literals.<\/p>\n        <\/div>\n\n        <div class=\"pth-faq-card\">\n            <p class=\"pth-faq-q\">Why are NAND and NOR called universal gates?<\/p>\n            <p class=\"pth-faq-a\">NAND and NOR are called universal gates because any Boolean function \u2014 and therefore any logic circuit \u2014 can be implemented using only NAND gates or only NOR gates, without needing any other gate type. This matters because NAND gates are the fundamental building block of CMOS logic (the technology used in virtually all modern digital chips) \u2014 they are faster and use less power than equivalent AND-OR combinations. In practice, most synthesis tools automatically convert AND-OR-NOT networks to NAND-NAND or NOR-NOR equivalents during technology mapping for silicon implementation. The Universal Gate Converter in the Gate Simulator tab shows the conversion rules.<\/p>\n        <\/div>\n\n        <div class=\"pth-faq-card\">\n            <p class=\"pth-faq-q\">Can the Verilog output be used directly in Xilinx Vivado or Intel Quartus?<\/p>\n            <p class=\"pth-faq-a\">Yes, with minor additions. The generated Verilog module uses standard synthesizable Verilog syntax compatible with Vivado, Quartus, and other synthesis tools. You may need to add timing constraints (.xdc for Vivado, .sdc for Quartus) and pin assignments separately. The module instantiation line would be <code>logic_minimized uut(.A(A), .B(B), .C(C), .D(D), .F(F));<\/code> in a testbench or top-level design. For FPGA synthesis, ensure the output port is connected to a physical pin through your constraint file. The SystemVerilog output is also synthesizable in both tools.<\/p>\n        <\/div>\n\n        <div class=\"pth-faq-card\">\n            <p class=\"pth-faq-q\">What is the Gray code and why does the K-Map use it?<\/p>\n            <p class=\"pth-faq-a\">Gray code is a binary numeral system where adjacent values differ in exactly one bit \u2014 the sequence for 2 bits is 00, 01, 11, 10 rather than binary counting 00, 01, 10, 11. The K-Map uses Gray code ordering for its row and column headers because the defining property of a K-Map \u2014 adjacent cells differ in one variable \u2014 requires that the physical adjacency of cells matches the single-variable-change property. If binary counting were used instead, cells 01 and 10 would be physically adjacent but would differ in two variables simultaneously, which would break the grouping rules. Gray code ensures the visual adjacency exactly corresponds to single-variable difference.<\/p>\n        <\/div>\n\n        <div class=\"pth-faq-card\">\n            <p class=\"pth-faq-q\">How does the gate simulator handle the case where a gate&#8217;s output feeds back into an earlier gate?<\/p>\n            <p class=\"pth-faq-a\">The gate chain evaluator processes gates strictly in order from first to last \u2014 each gate reads the current output of any preceding gate it references. Feedback loops (where a later gate&#8217;s output feeds back into an earlier gate&#8217;s input) are not supported because they create sequential logic (flip-flops and latches) rather than combinational logic. The simulator is designed exclusively for combinational circuits where the output depends only on the current inputs with no state or memory. For sequential logic analysis, the K-Map and Boolean tools remain valid for next-state function minimization \u2014 you would minimize each output function separately then implement them with feedback externally.<\/p>\n        <\/div>\n\n        <div class=\"pth-faq-card\">\n            <p class=\"pth-faq-q\">How many prime implicants can the Quine-McCluskey algorithm find for a 6-variable function?<\/p>\n            <p class=\"pth-faq-a\">In the worst case, a 6-variable function can have up to several hundred prime implicants. The theoretical maximum grows with the number of variables and the distribution of minterms. For typical engineering problems \u2014 functions derived from state machines, decoders, or arithmetic units \u2014 the prime implicant count is usually 10\u201330 for 4-variable problems and 20\u201380 for 6-variable problems. The solver processes all prime implicants through the chart method and displays the count in the sidebar. The step-by-step trace lists all prime implicant binary strings, which is useful for verifying the algorithm manually against textbook examples.<\/p>\n        <\/div>\n\n    <\/div>\n<\/div>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Ultimate K-Map Solver Pro: Karnaugh Map Calculator 100% offline, lightning-fast K-Map solver. Visualize 2 to 6 variable Karnaugh maps, generate optimized Boolean expressions (SOP\/POS), and export Verilog HDL code instantly. \ud83d\udfe2 2\u20136 Variable K-Map with Quine-McCluskey + Petrick&#8217;s Method The \ud83d\uddfa\ufe0f K-Map Solver tab handles 2 through 6 variable Karnaugh Maps \u2014 the 6-variable case &#8230; <a title=\"Ultimate K-Map Solver Pro: Karnaugh Map Calculator | 2 to 6 Variable Boolean Minimizer\" class=\"read-more\" href=\"https:\/\/schoolict.net\/tools\/advanced-k-map-solver\/\" aria-label=\"Read more about Ultimate K-Map Solver Pro: Karnaugh Map Calculator | 2 to 6 Variable Boolean Minimizer\">Read more<\/a><\/p>\n","protected":false},"author":1,"featured_media":228,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"footnotes":""},"class_list":["post-131","page","type-page","status-publish","has-post-thumbnail"],"_links":{"self":[{"href":"https:\/\/schoolict.net\/tools\/wp-json\/wp\/v2\/pages\/131","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/schoolict.net\/tools\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/schoolict.net\/tools\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/schoolict.net\/tools\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/schoolict.net\/tools\/wp-json\/wp\/v2\/comments?post=131"}],"version-history":[{"count":1,"href":"https:\/\/schoolict.net\/tools\/wp-json\/wp\/v2\/pages\/131\/revisions"}],"predecessor-version":[{"id":6589,"href":"https:\/\/schoolict.net\/tools\/wp-json\/wp\/v2\/pages\/131\/revisions\/6589"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/schoolict.net\/tools\/wp-json\/wp\/v2\/media\/228"}],"wp:attachment":[{"href":"https:\/\/schoolict.net\/tools\/wp-json\/wp\/v2\/media?parent=131"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}