NCT

A modern, Material You-inspire...
Log | Files | Refs | Activity | README | LICENSE

root / code-nct-legacy.html

code-nct-legacy.html (88501B)


      1 <!DOCTYPE html>
      2 <html lang="en">
      3 <head>
      4     <link rel="canonical" href="https://amit.is-a.dev/code-nct-legacy.html" />
      5     <meta charset="UTF-8">
      6     <meta name="viewport" content="width=device-width, initial-scale=1.0">
      7     <title>NCT Legacy Code View</title>
      8 <link rel="icon" href="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIzMiIgaGVpZ2h0PSIzMiIgdmlld0JveD0iMCAwIDI0IDI0Ij48c3R5bGU+cGF0aHtmaWxsOiNEMEJDRkZ9QG1lZGlhIChwcmVmZXJzLWNvbG9yLXNjaGVtZTpkYXJrKXtwYXRoe2ZpbGw6I2ZmZnx9fTwvc3R5bGU+PHBhdGggZD0iTTcgMnYxMWgzdjlsNy0xMmgtNGw0LTh6Ii8+PC9zdmc+">
      9     <!-- Link to Cascadia Code font from CDN -->
     10     <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@xz/fonts@1/serve/cascadia-code.min.css">
     11     <style>
     12         /* Base styling for the entire page */
     13         body {
     14             background-color: black;
     15             margin: 0;
     16             padding: 20px;
     17             font-family: 'Cascadia Code', 'Fira Code', 'Roboto Mono', monospace;
     18             color: white;
     19             display: flex;
     20             flex-direction: column;
     21             align-items: center;
     22             min-height: 100vh;
     23         }
     24 
     25         /* --- CUSTOM SCROLLBAR --- */
     26         ::-webkit-scrollbar { width: 8px; height: 8px; }
     27         ::-webkit-scrollbar-track { background: #000; }
     28         ::-webkit-scrollbar-thumb { background: #333; border-radius: 4px; }
     29         ::-webkit-scrollbar-thumb:hover { background: #1abc9c; }
     30 
     31         h1 {
     32             color: #f0f0f0;
     33             text-align: center;
     34             margin-bottom: 20px;
     35         }
     36 
     37         /* Container for the tabs */
     38         .tab-container {
     39             background-color: #1a1a1a;
     40             color: #f0f0f0;
     41             padding: 15px;
     42             border-radius: 8px;
     43             width: 100%;
     44             max-width: 1000px;
     45             box-shadow: 0 4px 12px rgba(0, 0, 0, 0.4);
     46             position: relative;
     47             overflow: hidden;
     48             border: 1px solid #333;
     49         }
     50 
     51         /* Tab buttons styling */
     52         .tabs {
     53             display: flex;
     54             justify-content: center;
     55             margin-bottom: 20px;
     56             border-bottom: 1px solid #333;
     57         }
     58 
     59         .tab-button {
     60             background-color: transparent;
     61             border: none;
     62             padding: 10px 20px;
     63             font-size: 1.2em;
     64             color: #f0f0f0;
     65             cursor: pointer;
     66             transition: color 0.3s ease, background-color 0.3s ease, transform 0.3s ease;
     67             position: relative;
     68             overflow: hidden;
     69             border-radius: 5px 5px 0 0;
     70             margin: 0 5px;
     71         }
     72 
     73         .tab-button:hover {
     74             color: #1abc9c;
     75             transform: translateY(-2px);
     76         }
     77 
     78         .tab-button.active {
     79             color: #1abc9c;
     80             font-weight: bold;
     81             background-color: #333;
     82             transform: translateY(-2px);
     83         }
     84 
     85         .tab-button.active::after {
     86             content: '';
     87             position: absolute;
     88             bottom: 0;
     89             left: 0;
     90             width: 100%;
     91             height: 3px;
     92             background-color: #1abc9c;
     93             animation: tabUnderline 0.3s forwards;
     94         }
     95 
     96         @keyframes tabUnderline {
     97             from { width: 0; }
     98             to { width: 100%; }
     99         }
    100 
    101         /* Tab content styling */
    102         .tab-content {
    103             display: none;
    104             padding: 15px 0;
    105             animation: fadeIn 0.5s ease-in-out;
    106         }
    107 
    108         .tab-content.active {
    109             display: block;
    110         }
    111 
    112         @keyframes fadeIn {
    113             from { opacity: 0; transform: translateY(10px); }
    114             to { opacity: 1; transform: translateY(0); }
    115         }
    116 
    117         /* Header for Code Block */
    118         .code-header {
    119             display: flex;
    120             justify-content: space-between;
    121             align-items: center;
    122             background-color: #252525;
    123             padding: 8px 15px;
    124             border-radius: 8px 8px 0 0;
    125             border: 1px solid #333;
    126             border-bottom: none;
    127         }
    128 
    129         .file-info { font-size: 0.85em; color: #888; }
    130 
    131         /* Copy Button Styling */
    132         .copy-button {
    133             background: transparent;
    134             border: 1px solid #444;
    135             color: #ccc;
    136             padding: 5px 12px;
    137             border-radius: 4px;
    138             font-size: 0.8em;
    139             cursor: pointer;
    140             transition: 0.2s;
    141             display: flex;
    142             align-items: center;
    143             gap: 6px;
    144         }
    145 
    146         .copy-button:hover {
    147             border-color: #1abc9c;
    148             color: #1abc9c;
    149         }
    150 
    151         .copy-button.success {
    152             border-color: #2ecc71;
    153             color: #2ecc71;
    154         }
    155 
    156         /* Styling for the code block container */
    157         .code-block-container {
    158             background-color: #1a1a1a;
    159             border: 1px solid #333;
    160             border-radius: 0 0 8px 8px;
    161             overflow: hidden;
    162         }
    163 
    164         .code-block {
    165             background-color: #1a1a1a;
    166             color: #f0f0f0;
    167             padding: 15px;
    168             overflow-x: auto;
    169             max-height: 70vh;
    170             font-size: 0.95em;
    171             line-height: 1.5;
    172             tab-size: 4;
    173             white-space: pre;
    174             margin: 0;
    175         }
    176 
    177         /* Download section styling */
    178         .download-item {
    179             background-color: #2a2a2a;
    180             padding: 15px;
    181             border-radius: 8px;
    182             margin-bottom: 15px;
    183             display: flex;
    184             justify-content: space-between;
    185             align-items: center;
    186             border: 1px solid #333;
    187         }
    188 
    189         .download-info h3 {
    190             color: #1abc9c;
    191             margin: 0 0 5px 0;
    192         }
    193 
    194         .download-info p {
    195             font-size: 0.9em;
    196             color: #ccc;
    197             margin: 0;
    198         }
    199 
    200         .download-button {
    201             background-color: #007bff;
    202             color: white;
    203             border: none;
    204             padding: 10px 15px;
    205             border-radius: 5px;
    206             cursor: pointer;
    207             text-decoration: none;
    208             font-size: 0.9em;
    209             transition: background-color 0.3s ease, transform 0.2s ease;
    210         }
    211 
    212         .download-button:hover {
    213             background-color: #0056b3;
    214             transform: translateY(-1px);
    215         }
    216     </style>
    217 </head>
    218 <body>
    219 
    220     <h1>--- NCT Legacy Explorer ---</h1>
    221 
    222     <div class="tab-container">
    223         <div class="tabs">
    224             <button class="tab-button active" onclick="switchTab(event, 'code')">Code</button>
    225             <button class="tab-button" onclick="switchTab(event, 'download')">Download</button>
    226         </div>
    227 
    228         <div id="code-tab-content" class="tab-content active">
    229             <div class="code-header">
    230                 <span class="file-info">nct-legacy.html</span>
    231                 <button class="copy-button" onclick="copyToClipboard(this)">
    232                     <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg>
    233                     Copy Code
    234                 </button>
    235             </div>
    236             <div class="code-block-container">
    237                 <pre id="sourceCode" class="code-block">&lt;!DOCTYPE html&gt;
    238 &lt;html lang=&quot;en&quot;&gt;
    239 &lt;head&gt;
    240     &lt;meta charset=&quot;UTF-8&quot;&gt;
    241     &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot;&gt;
    242     &lt;title&gt;NCT v2.11 | Legacy Edition&lt;/title&gt;
    243     &lt;link rel=&quot;icon&quot; href=&quot;data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIzMiIgaGVpZ2h0PSIzMiIgdmlld0JveD0iMCAwIDI0IDI0Ij48c3R5bGU+cGF0aHtmaWxsOiNEMEJDRkZ9QG1lZGlhIChwcmVmZXJzLWNvbG9yLXNjaGVtZTpkYXJrKXtwYXRoe2ZpbGw6I2ZmZnx9fTwvc3R5bGU+PHBhdGggZD0iTTcgMnYxMWgzdjlsNy0xMmgtNGw0LTh6Ii8+PC9zdmc+&quot;&gt;
    244     &lt;link rel=&quot;preconnect&quot; href=&quot;https://fonts.googleapis.com&quot;&gt;
    245     &lt;link rel=&quot;preconnect&quot; href=&quot;https://fonts.gstatic.com&quot; crossorigin&gt;
    246     &lt;link href=&quot;https://fonts.googleapis.com/css2?family=Roboto:wght@400;500;700&amp;family=Google+Sans:wght@400;500;700&amp;family=Roboto+Mono:wght@400;500&amp;display=swap&quot; rel=&quot;stylesheet&quot;&gt;
    247     &lt;script type=&quot;application/ld+json&quot;&gt;
    248   {
    249     &quot;@context&quot;: &quot;https://schema.org&quot;,
    250     &quot;@type&quot;: &quot;WebApplication&quot;,
    251     &quot;name&quot;: &quot;NCT v2.11 | Legacy Edition&quot;,
    252     &quot;url&quot;: &quot;https://amit.is-a.dev/nct-legacy&quot;,
    253     &quot;image&quot;: &quot;https://amit.is-a.dev/nctlogo.png&quot;,
    254     &quot;description&quot;: &quot;Number conversion tool&quot;,
    255     &quot;applicationCategory&quot;: &quot;EducationalApplication&quot;,
    256     &quot;operatingSystem&quot;: &quot;Any&quot;
    257   }
    258 &lt;/script&gt;
    259     &lt;style&gt;
    260         /* --- MATERIAL DESIGN 3 TOKENS --- */
    261         :root {
    262             --md-sys-color-background: #141218;
    263             --md-sys-color-surface: #1D1B20;
    264             --md-sys-color-surface-container: #211F26;
    265             --md-sys-color-surface-container-high: #2B2930;
    266             
    267             /* Primary */
    268             --md-sys-color-primary: #D0BCFF;
    269             --md-sys-color-on-primary: #381E72;
    270             --md-sys-color-primary-container: #4F378B;
    271             --md-sys-color-on-primary-container: #EADDFF;
    272 
    273             /* Text */
    274             --md-sys-color-on-surface: #E6E1E5;
    275             --md-sys-color-on-surface-variant: #CAC4D0;
    276             --md-sys-color-outline: #938F99;
    277 
    278             /* Error */
    279             --md-sys-color-error: #F2B8B5;
    280             --md-sys-color-error-container: #8C1D18;
    281 
    282             /* Success/Accent */
    283             --md-sys-color-tertiary: #B6C4FF;
    284             --md-sys-color-success: #4ade80;
    285             
    286             /* Dimensions */
    287             --radius-xl: 28px;
    288             --radius-l: 16px;
    289             --radius-m: 12px;
    290             --radius-s: 8px;
    291 
    292             --font-main: &#x27;Google Sans&#x27;, &#x27;Roboto&#x27;, sans-serif;
    293             --font-code: &#x27;Roboto Mono&#x27;, monospace;
    294             
    295             /* Animation */
    296             --ease-elastic: cubic-bezier(0.4, 0.0, 0.2, 1);
    297         }
    298 
    299         /* --- CUSTOM SCROLLBAR --- */
    300         ::-webkit-scrollbar { width: 6px; height: 6px; }
    301         ::-webkit-scrollbar-track { background: transparent; }
    302         ::-webkit-scrollbar-thumb { background: rgba(255,255,255,0.2); border-radius: 3px; }
    303         ::-webkit-scrollbar-thumb:hover { background: rgba(255,255,255,0.4); }
    304 
    305         * { margin: 0; padding: 0; box-sizing: border-box; -webkit-tap-highlight-color: transparent; }
    306 
    307         body {
    308             font-family: var(--font-main);
    309             background-color: var(--md-sys-color-background);
    310             color: var(--md-sys-color-on-surface);
    311             min-height: 100vh;
    312             display: flex;
    313             flex-direction: column;
    314             align-items: center;
    315             overflow-x: hidden;
    316             background-image: radial-gradient(circle at 50% 0%, rgba(208, 188, 255, 0.05) 0%, transparent 60%);
    317         }
    318 
    319         /* --- LAYOUT --- */
    320         .app-container {
    321             width: 100%;
    322             max-width: 1000px;
    323             padding: 24px;
    324             display: flex;
    325             flex-direction: column;
    326             gap: 24px;
    327             flex-grow: 1;
    328         }
    329 
    330         /* --- HEADER &amp; NAV --- */
    331         header {
    332             display: flex;
    333             flex-direction: column;
    334             gap: 20px;
    335             padding: 16px 0;
    336         }
    337 
    338         .header-top {
    339             display: flex;
    340             justify-content: space-between;
    341             align-items: center;
    342         }
    343 
    344         .logo {
    345             font-size: 1.75rem;
    346             font-weight: 500;
    347             color: var(--md-sys-color-on-surface);
    348             display: flex;
    349             align-items: center;
    350             gap: 12px;
    351         }
    352 
    353         .logo span { color: var(--md-sys-color-primary); }
    354 
    355         /* Navigation Tabs with Animation */
    356         .nav-tabs {
    357             position: relative;
    358             display: flex;
    359             background: var(--md-sys-color-surface-container);
    360             padding: 4px;
    361             border-radius: 32px;
    362             width: fit-content;
    363             margin: 0 auto;
    364             border: 1px solid rgba(255,255,255,0.05);
    365         }
    366 
    367         .nav-glider {
    368             position: absolute;
    369             top: 4px;
    370             left: 4px;
    371             height: calc(100% - 8px);
    372             width: 110px; 
    373             background: var(--md-sys-color-primary-container);
    374             border-radius: 28px;
    375             transition: transform 0.3s var(--ease-elastic);
    376             z-index: 1;
    377         }
    378 
    379         .nav-tab {
    380             position: relative;
    381             padding: 10px 24px;
    382             border-radius: 24px;
    383             color: var(--md-sys-color-on-surface-variant);
    384             font-weight: 500;
    385             cursor: pointer;
    386             transition: color 0.2s;
    387             border: none;
    388             background: none;
    389             z-index: 2;
    390             width: 110px; 
    391         }
    392 
    393         .nav-tab.active { color: var(--md-sys-color-on-primary-container); }
    394 
    395         .header-actions {
    396             display: flex;
    397             gap: 10px;
    398         }
    399 
    400         .tools-btn {
    401             background: transparent;
    402             border: 1px solid var(--md-sys-color-outline);
    403             color: var(--md-sys-color-on-surface);
    404             padding: 8px 16px;
    405             border-radius: var(--radius-l);
    406             cursor: pointer;
    407             font-weight: 500;
    408             display: flex;
    409             align-items: center;
    410             gap: 8px;
    411             transition: transform 0.1s;
    412         }
    413         .tools-btn:active { transform: scale(0.95); }
    414         .tools-btn:hover { background: rgba(255,255,255,0.05); }
    415 
    416         /* --- SECTIONS --- */
    417         .app-section {
    418             display: none;
    419             flex-direction: column;
    420             gap: 24px;
    421             animation: fadeIn 0.3s ease-out;
    422         }
    423         .app-section.active { display: flex; }
    424         
    425         @keyframes fadeIn { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: translateY(0); } }
    426 
    427         /* --- CONVERTER STAGE --- */
    428         .converter-stage {
    429             display: grid;
    430             grid-template-columns: 1fr 64px 1fr;
    431             gap: 16px;
    432             align-items: stretch;
    433             position: relative;
    434         }
    435 
    436         .material-card {
    437             background-color: var(--md-sys-color-surface-container);
    438             border-radius: var(--radius-xl);
    439             padding: 24px;
    440             display: flex;
    441             flex-direction: column;
    442             height: 380px;
    443             position: relative;
    444             transition: transform 0.4s var(--ease-elastic), box-shadow 0.2s;
    445             border: 1px solid transparent;
    446             z-index: 1;
    447         }
    448 
    449         .material-card:focus-within {
    450             background-color: var(--md-sys-color-surface-container-high);
    451             border-color: var(--md-sys-color-outline);
    452         }
    453 
    454         /* CARD HEADER &amp; CUSTOM DROPDOWN */
    455         .card-header {
    456             display: flex;
    457             justify-content: space-between;
    458             align-items: center;
    459             margin-bottom: 20px;
    460             border-bottom: 1px solid var(--md-sys-color-outline);
    461             padding-bottom: 12px;
    462             z-index: 10;
    463         }
    464 
    465         .input-label {
    466             font-size: 0.875rem;
    467             font-weight: 500;
    468             color: var(--md-sys-color-primary);
    469             text-transform: uppercase;
    470             letter-spacing: 1px;
    471         }
    472 
    473         /* Custom Dropdown Styles */
    474         .custom-select-wrapper {
    475             position: relative;
    476             min-width: 150px;
    477             user-select: none;
    478         }
    479         .custom-select-trigger {
    480             display: flex;
    481             align-items: center;
    482             justify-content: flex-end;
    483             gap: 8px;
    484             cursor: pointer;
    485             color: var(--md-sys-color-on-surface);
    486             font-weight: 500;
    487             padding: 4px 0;
    488             transition: color 0.2s;
    489         }
    490         .custom-select-trigger:hover { color: var(--md-sys-color-primary); }
    491         .arrow { font-size: 0.7rem; transition: transform 0.3s; }
    492         
    493         .custom-options {
    494             position: absolute;
    495             top: 120%;
    496             right: 0;
    497             background: var(--md-sys-color-surface-container-high);
    498             border-radius: var(--radius-m);
    499             box-shadow: 0 8px 16px rgba(0,0,0,0.4);
    500             opacity: 0;
    501             visibility: hidden;
    502             pointer-events: none;
    503             transform: translateY(-10px);
    504             transition: all 0.2s var(--ease-elastic);
    505             min-width: 180px;
    506             overflow: hidden;
    507             border: 1px solid rgba(255,255,255,0.1);
    508             z-index: 1000;
    509         }
    510         .custom-select-wrapper.open .custom-options {
    511             opacity: 1; visibility: visible; pointer-events: all; transform: translateY(0);
    512         }
    513         .custom-select-wrapper.open .arrow { transform: rotate(180deg); }
    514         
    515         .custom-option {
    516             padding: 12px 16px;
    517             cursor: pointer;
    518             color: var(--md-sys-color-on-surface-variant);
    519             transition: 0.2s;
    520         }
    521         .custom-option:hover { background: rgba(255,255,255,0.05); color: var(--md-sys-color-on-surface); }
    522         .custom-option.selected { color: var(--md-sys-color-primary); background: rgba(208, 188, 255, 0.1); }
    523 
    524         /* INPUT AREA */
    525         .input-area {
    526             flex-grow: 1;
    527             background: transparent;
    528             border: none;
    529             color: var(--md-sys-color-on-surface);
    530             font-size: 2.2rem;
    531             font-family: var(--font-main);
    532             resize: none;
    533             outline: none;
    534             line-height: 1.2;
    535             z-index: 1;
    536         }
    537         .input-area::placeholder { color: var(--md-sys-color-on-surface-variant); opacity: 0.3; }
    538 
    539         /* Error Chip */
    540         .error-chip {
    541             position: absolute;
    542             bottom: 80px;
    543             left: 24px;
    544             background: var(--md-sys-color-error-container);
    545             color: var(--md-sys-color-error);
    546             padding: 8px 16px;
    547             border-radius: 8px;
    548             font-size: 0.875rem;
    549             display: flex;
    550             align-items: center;
    551             gap: 8px;
    552             opacity: 0;
    553             transform: translateY(10px);
    554             transition: all 0.3s;
    555             pointer-events: none;
    556         }
    557         .error-chip.visible { opacity: 1; transform: translateY(0); }
    558 
    559         /* Card Footer */
    560         .card-footer {
    561             display: flex;
    562             justify-content: space-between;
    563             align-items: center;
    564             margin-top: auto;
    565         }
    566         .char-count { font-size: 0.75rem; color: var(--md-sys-color-on-surface-variant); }
    567 
    568         /* Icons &amp; Buttons */
    569         .icon-btn {
    570             background: transparent;
    571             border: none;
    572             color: var(--md-sys-color-on-surface-variant);
    573             width: 40px; height: 40px;
    574             border-radius: 50%;
    575             cursor: pointer;
    576             display: flex; align-items: center; justify-content: center;
    577             transition: 0.2s;
    578         }
    579         .icon-btn:hover { background: rgba(255,255,255,0.1); color: var(--md-sys-color-on-surface); transform: scale(1.1); }
    580         .icon-btn:active { transform: scale(0.9); }
    581         
    582         /* Copy Button Animation */
    583         .icon-btn.success svg {
    584             animation: check-pop 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275);
    585             color: var(--md-sys-color-success);
    586         }
    587         @keyframes check-pop {
    588             0% { transform: scale(0); }
    589             50% { transform: scale(1.3); }
    590             100% { transform: scale(1); }
    591         }
    592 
    593         /* Trash Shake Animation */
    594         @keyframes trash-shake {
    595             0% { transform: rotate(0deg); }
    596             25% { transform: rotate(-15deg); }
    597             50% { transform: rotate(15deg); }
    598             75% { transform: rotate(-15deg); }
    599             100% { transform: rotate(0deg); }
    600         }
    601         .icon-btn.shaking {
    602             animation: trash-shake 0.4s ease-in-out;
    603             color: var(--md-sys-color-error);
    604         }
    605 
    606         /* Swap Button */
    607         .swap-container { display: flex; justify-content: center; align-items: center; z-index: 2; }
    608         .swap-fab {
    609             width: 56px; height: 56px;
    610             border-radius: 16px;
    611             background-color: var(--md-sys-color-surface-container-high);
    612             border: 1px solid var(--md-sys-color-outline);
    613             color: var(--md-sys-color-on-surface);
    614             cursor: pointer;
    615             display: flex; align-items: center; justify-content: center;
    616             transition: all 0.3s var(--ease-elastic);
    617             box-shadow: 0 4px 8px rgba(0,0,0,0.2);
    618         }
    619         .swap-fab:hover {
    620             background-color: var(--md-sys-color-primary);
    621             color: var(--md-sys-color-on-primary);
    622             transform: rotate(180deg) scale(1.1);
    623             border-color: transparent;
    624         }
    625 
    626         /* --- SWAP ANIMATION CLASSES --- */
    627         .anim-move-right { transform: translateX(calc(100% + 16px)); }
    628         .anim-move-left { transform: translateX(calc(-100% - 16px)); }
    629         .anim-move-down { transform: translateY(calc(100% + 16px)); }
    630         .anim-move-up { transform: translateY(calc(-100% - 16px)); }
    631 
    632         /* --- DYNAMIC CALCULATOR --- */
    633         .calc-wrapper {
    634             background: var(--md-sys-color-surface-container);
    635             padding: 24px;
    636             border-radius: var(--radius-xl);
    637             max-width: 800px;
    638             margin: 0 auto;
    639             width: 100%;
    640         }
    641 
    642         .calc-header {
    643             display: flex;
    644             gap: 24px;
    645             margin-bottom: 24px;
    646             flex-wrap: wrap;
    647         }
    648 
    649         .calc-ctrl-group {
    650             flex: 1;
    651             min-width: 200px;
    652             display: flex;
    653             align-items: center;
    654             gap: 12px;
    655             background: rgba(0,0,0,0.2);
    656             padding: 8px 16px;
    657             border-radius: 12px;
    658         }
    659         .calc-ctrl-group label {
    660             font-size: 0.8rem;
    661             color: var(--md-sys-color-primary);
    662             text-transform: uppercase;
    663             white-space: nowrap;
    664             margin: 0;
    665         }
    666         
    667         .calc-rows {
    668             display: flex;
    669             flex-direction: column;
    670             gap: 12px;
    671             margin-bottom: 24px;
    672         }
    673 
    674         .calc-row {
    675             display: flex;
    676             gap: 12px;
    677             align-items: center;
    678             animation: fadeIn 0.3s ease-out;
    679         }
    680         
    681         /* Simple Fade Out */
    682         .calc-row.removing {
    683             opacity: 0;
    684             transition: opacity 0.3s ease;
    685         }
    686         
    687         .calc-input-wrapper {
    688             flex-grow: 1;
    689             position: relative;
    690         }
    691         .calc-input {
    692             width: 100%;
    693             background: rgba(0,0,0,0.2);
    694             border: 1px solid transparent;
    695             color: var(--md-sys-color-on-surface);
    696             padding: 16px;
    697             border-radius: 12px;
    698             font-family: var(--font-code);
    699             font-size: 1.1rem;
    700             outline: none;
    701             transition: 0.2s;
    702         }
    703         .calc-input:focus { border-color: var(--md-sys-color-primary); background: rgba(0,0,0,0.4); }
    704         .calc-input.invalid { border-color: var(--md-sys-color-error); }
    705         
    706         .calc-remove-btn {
    707             background: var(--md-sys-color-surface-container-high);
    708             border: none;
    709             color: var(--md-sys-color-error);
    710             width: 40px; height: 40px;
    711             border-radius: 8px;
    712             cursor: pointer;
    713             display: flex; align-items: center; justify-content: center;
    714             transition: 0.2s;
    715         }
    716         .calc-remove-btn:hover { background: var(--md-sys-color-error-container); color: #fff; }
    717 
    718         /* The Divider Area */
    719         .calc-actions {
    720             display: flex;
    721             align-items: center;
    722             border-top: 1px solid var(--md-sys-color-outline);
    723             padding-top: 20px;
    724             margin-top: 20px;
    725         }
    726 
    727         .add-row-btn {
    728             background: rgba(255,255,255,0.05);
    729             border: 1px dashed var(--md-sys-color-outline);
    730             color: var(--md-sys-color-on-surface-variant);
    731             padding: 10px 20px;
    732             border-radius: 12px;
    733             cursor: pointer;
    734             font-weight: 500;
    735             width: fit-content;
    736             text-align: left;
    737             transition: 0.2s;
    738             margin-bottom: 20px; /* Space before divider */
    739         }
    740         .add-row-btn:hover { border-color: var(--md-sys-color-primary); color: var(--md-sys-color-primary); background: rgba(208, 188, 255, 0.05); }
    741 
    742         .calc-result-area {
    743             display: flex;
    744             align-items: center;
    745             gap: 20px;
    746             margin-left: auto; /* Forces result to the right */
    747         }
    748 
    749         .visualize-btn {
    750             background: var(--md-sys-color-primary-container);
    751             color: var(--md-sys-color-on-primary-container);
    752             border: none;
    753             padding: 8px 16px;
    754             border-radius: 20px;
    755             font-size: 0.9rem;
    756             font-weight: 500;
    757             cursor: pointer;
    758             display: none; /* Hidden by default */
    759             align-items: center;
    760             gap: 6px;
    761             transition: 0.2s;
    762             animation: popIn 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275);
    763             margin-right: auto; /* Keeps it left-aligned in actions */
    764         }
    765         .visualize-btn:hover { filter: brightness(1.2); }
    766         .visualize-btn:active { transform: scale(0.95); }
    767         @keyframes popIn { from{transform: scale(0.8); opacity:0} to{transform: scale(1); opacity:1} }
    768 
    769         .calc-result-display { text-align: right; }
    770         .res-label { font-size: 0.9rem; color: var(--md-sys-color-on-surface-variant); }
    771         .res-value { font-size: 2.2rem; color: var(--md-sys-color-primary); font-family: var(--font-code); margin-top: 5px; font-weight: 700; }
    772 
    773 
    774         /* --- VISUALIZER PANEL --- */
    775         .calc-visualizer {
    776             background: #111;
    777             border-radius: var(--radius-m);
    778             padding: 20px;
    779             margin-top: 20px;
    780             display: none; 
    781             border: 1px solid var(--md-sys-color-outline);
    782             overflow-x: auto;
    783         }
    784         .calc-visualizer.active { display: block; animation: slideIn 0.4s var(--ease-elastic); }
    785         
    786         .viz-grid {
    787             display: grid;
    788             font-family: var(--font-code);
    789             font-size: 1.2rem;
    790             color: var(--md-sys-color-on-surface);
    791             gap: 4px;
    792         }
    793         .viz-row { display: contents; }
    794         .viz-cell {
    795             padding: 4px 8px;
    796             text-align: center;
    797             position: relative;
    798         }
    799         .viz-cell.carry { color: var(--md-sys-color-tertiary); font-size: 0.8rem; height: 20px; }
    800         .viz-cell.operator { color: var(--md-sys-color-primary); }
    801         .viz-cell.border-bottom { border-bottom: 2px solid var(--md-sys-color-outline); }
    802         .viz-cell.active-col { background: rgba(208, 188, 255, 0.15); border-radius: 4px; }
    803         .viz-cell.result { color: var(--md-sys-color-primary); font-weight: bold; }
    804 
    805         .viz-info {
    806             margin-top: 12px;
    807             font-size: 0.9rem;
    808             color: var(--md-sys-color-on-surface-variant);
    809             font-family: var(--font-code);
    810             min-height: 20px;
    811         }
    812 
    813         /* --- CONVERTER STEPS PANEL --- */
    814         .steps-container {
    815             margin-top: 20px;
    816             background: rgba(0,0,0,0.2);
    817             border-radius: var(--radius-l);
    818             padding: 20px;
    819             border: 1px solid rgba(255,255,255,0.05);
    820             display: none;
    821         }
    822         .steps-container.visible { display: block; animation: fadeIn 0.5s; }
    823         
    824         .steps-header {
    825             display: flex;
    826             justify-content: space-between;
    827             align-items: center;
    828             margin-bottom: 12px;
    829             border-bottom: 1px solid rgba(255,255,255,0.1);
    830             padding-bottom: 8px;
    831         }
    832         
    833         .steps-content {
    834             font-family: var(--font-code);
    835             color: var(--md-sys-color-tertiary);
    836             font-size: 0.9rem;
    837             white-space: pre-wrap;
    838             line-height: 1.5;
    839         }
    840 
    841         /* --- HISTORY TAPE --- */
    842         .history-section {
    843             margin-top: 20px;
    844             border-top: 1px solid var(--md-sys-color-outline);
    845             padding-top: 20px;
    846         }
    847         .history-header {
    848             display: flex;
    849             justify-content: space-between;
    850             align-items: center;
    851             margin-bottom: 10px;
    852         }
    853         .history-list {
    854             display: flex; flex-direction: column; gap: 8px;
    855             max-height: 200px; overflow-y: auto;
    856             transition: opacity 0.3s;
    857         }
    858         
    859         /* History Item Animation: Slide Out to Right */
    860         .history-list.clearing .history-item {
    861             animation: slide-out-right 0.3s forwards;
    862         }
    863         @keyframes slide-out-right {
    864             to { transform: translateX(50px); opacity: 0; }
    865         }
    866 
    867         .history-item {
    868             display: flex; justify-content: space-between;
    869             padding: 12px;
    870             background: rgba(255,255,255,0.03);
    871             border-radius: 8px;
    872             font-family: var(--font-code);
    873             font-size: 0.9rem;
    874             cursor: pointer;
    875             transition: 0.2s;
    876             align-items: center;
    877         }
    878         .history-item:hover { background: rgba(255,255,255,0.08); transform: translateX(4px); }
    879         .hist-val { color: var(--md-sys-color-on-surface); }
    880         .hist-meta { font-size: 0.75rem; color: var(--md-sys-color-outline); margin-right: 10px; }
    881 
    882         /* --- FOOTER --- */
    883         footer {
    884             margin-top: 40px;
    885             text-align: center;
    886             padding: 20px;
    887             color: var(--md-sys-color-on-surface-variant);
    888             font-size: 0.85rem;
    889             border-top: 1px solid var(--md-sys-color-outline);
    890             width: 100%;
    891             background: rgba(0,0,0,0.2);
    892         }
    893         .footer-content {
    894             display: flex;
    895             flex-direction: column;
    896             gap: 8px;
    897         }
    898         .footer-links {
    899             display: flex;
    900             justify-content: center;
    901             gap: 15px;
    902             margin-top: 5px;
    903         }
    904         .footer-link {
    905             color: var(--md-sys-color-primary);
    906             text-decoration: none;
    907             transition: 0.2s;
    908         }
    909         .footer-link:hover { text-decoration: underline; color: var(--md-sys-color-tertiary); }
    910 
    911         /* --- MODAL (LEGACY &amp; CHEATSHEET) --- */
    912         .modal-overlay {
    913             position: fixed;
    914             top: 0; left: 0; width: 100%; height: 100%;
    915             background: rgba(0,0,0,0.7);
    916             backdrop-filter: blur(4px);
    917             z-index: 2000;
    918             display: none;
    919             justify-content: center;
    920             align-items: center;
    921             opacity: 0;
    922             transition: opacity 0.3s;
    923         }
    924         .modal-overlay.open { display: flex; opacity: 1; }
    925         
    926         .modal-content {
    927             background: var(--md-sys-color-surface-container);
    928             width: 90%; max-width: 500px;
    929             border-radius: var(--radius-xl);
    930             padding: 24px;
    931             max-height: 80vh;
    932             display: flex;
    933             flex-direction: column;
    934             box-shadow: 0 10px 30px rgba(0,0,0,0.5);
    935             border: 1px solid var(--md-sys-color-outline);
    936             transform: scale(0.9);
    937             transition: transform 0.3s var(--ease-elastic);
    938         }
    939         .modal-overlay.open .modal-content { transform: scale(1); }
    940 
    941         .modal-header {
    942             display: flex; justify-content: space-between; align-items: center;
    943             margin-bottom: 20px;
    944             border-bottom: 1px solid var(--md-sys-color-outline);
    945             padding-bottom: 12px;
    946             flex-shrink: 0;
    947         }
    948         .modal-header h3 { margin: 0; color: var(--md-sys-color-primary); }
    949         .close-modal {
    950             background: none; border: none; color: var(--md-sys-color-on-surface);
    951             font-size: 1.5rem; cursor: pointer;
    952         }
    953         
    954         .modal-body {
    955             overflow-y: auto;
    956             padding-right: 5px; /* Space for scrollbar */
    957         }
    958 
    959         /* History Timeline */
    960         .timeline-item {
    961             position: relative;
    962             padding-left: 20px;
    963             border-left: 2px solid var(--md-sys-color-outline);
    964             margin-bottom: 20px;
    965         }
    966         .timeline-item::before {
    967             content: &#x27;&#x27;; position: absolute; left: -6px; top: 0;
    968             width: 10px; height: 10px; border-radius: 50%;
    969             background: var(--md-sys-color-primary);
    970         }
    971         .version-tag {
    972             font-size: 0.8rem; font-weight: bold; color: var(--md-sys-color-tertiary);
    973             margin-bottom: 4px; display: inline-block; background: rgba(255,255,255,0.1);
    974             padding: 2px 8px; border-radius: 4px;
    975         }
    976         .version-tag.current { background: var(--md-sys-color-primary); color: var(--md-sys-color-on-primary); }
    977         .timeline-desc { font-size: 0.9rem; color: var(--md-sys-color-on-surface-variant); margin: 0; }
    978 
    979         /* Sidebar (Cheat Sheet) */
    980         .sidebar {
    981             position: fixed; top: 0; right: -320px;
    982             width: 300px; height: 100%;
    983             background: var(--md-sys-color-surface-container-high);
    984             box-shadow: -5px 0 15px rgba(0,0,0,0.5);
    985             padding: 24px;
    986             transition: 0.3s ease;
    987             z-index: 1000;
    988             overflow-y: auto;
    989         }
    990         .sidebar.open { right: 0; }
    991         .sidebar h3 { color: var(--md-sys-color-primary); margin-bottom: 16px; border-bottom: 1px solid rgba(255,255,255,0.1); padding-bottom: 8px; }
    992         .cheat-table { width: 100%; border-collapse: collapse; font-family: var(--font-code); font-size: 0.8rem; }
    993         .cheat-table th, .cheat-table td { text-align: left; padding: 6px; border-bottom: 1px solid rgba(255,255,255,0.05); }
    994         .close-sidebar {
    995             position: absolute; top: 10px; right: 10px;
    996             background: none; border: none; color: var(--md-sys-color-on-surface);
    997             font-size: 1.5rem; cursor: pointer;
    998         }
    999 
   1000         /* --- RESPONSIVE --- */
   1001         @media (max-width: 768px) {
   1002             .converter-stage { grid-template-columns: 1fr; grid-template-rows: 1fr 64px 1fr; gap: 8px; }
   1003             .material-card { height: 260px; }
   1004             .swap-container { transform: rotate(90deg); }
   1005             .swap-fab:hover { transform: rotate(180deg); }
   1006             .header-top { flex-direction: column; gap: 10px; }
   1007             .calc-header { flex-direction: column; gap: 10px; }
   1008             .calc-result-area { margin-left: 0; justify-content: flex-end; width: 100%; }
   1009             .visualize-btn { margin-right: 0; margin-bottom: 10px; }
   1010             .calc-actions { flex-direction: column-reverse; align-items: stretch; }
   1011         }
   1012     &lt;/style&gt;
   1013 &lt;/head&gt;
   1014 &lt;body&gt;
   1015 
   1016     &lt;header class=&quot;app-container&quot;&gt;
   1017         &lt;div class=&quot;header-top&quot;&gt;
   1018             &lt;div class=&quot;logo&quot;&gt;
   1019                 &lt;svg width=&quot;32&quot; height=&quot;32&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;var(--md-sys-color-primary)&quot;&gt;&lt;path d=&quot;M7 2v11h3v9l7-12h-4l4-8z&quot;/&gt;&lt;/svg&gt;
   1020                 NCT &lt;span&gt;v2.11&lt;/span&gt;
   1021             &lt;/div&gt;
   1022             
   1023             &lt;!-- Animated Navigation --&gt;
   1024             &lt;div class=&quot;nav-tabs&quot;&gt;
   1025                 &lt;div class=&quot;nav-glider&quot; id=&quot;navGlider&quot;&gt;&lt;/div&gt;
   1026                 &lt;button class=&quot;nav-tab active&quot; onclick=&quot;switchTab(&#x27;converter&#x27;, 0)&quot;&gt;Converter&lt;/button&gt;
   1027                 &lt;button class=&quot;nav-tab&quot; onclick=&quot;switchTab(&#x27;calculator&#x27;, 1)&quot;&gt;Calculator&lt;/button&gt;
   1028             &lt;/div&gt;
   1029 
   1030             &lt;div class=&quot;header-actions&quot;&gt;
   1031                 &lt;button class=&quot;tools-btn&quot; onclick=&quot;toggleHistory()&quot;&gt;
   1032                     &lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-6h2v6zm0-8h-2V7h2v2z&quot;/&gt;&lt;/svg&gt;
   1033                     Versions
   1034                 &lt;/button&gt;
   1035                 &lt;button class=&quot;tools-btn&quot; onclick=&quot;toggleSidebar()&quot;&gt;
   1036                     &lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M11 18h2v-2h-2v2zm1-16C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8zm0-14c-2.21 0-4 1.79-4 4h2c0-1.1.9-2 2-2s2 .9 2 2c0 2-3 1.75-3 5h2c0-2.25 3-2.5 3-5 0-2.21-1.79-4-4-4z&quot;/&gt;&lt;/svg&gt;
   1037                     Cheat Sheet
   1038                 &lt;/button&gt;
   1039             &lt;/div&gt;
   1040         &lt;/div&gt;
   1041     &lt;/header&gt;
   1042 
   1043     &lt;main class=&quot;app-container&quot;&gt;
   1044         
   1045         &lt;!-- SECTION 1: CONVERTER --&gt;
   1046         &lt;section id=&quot;converter-section&quot; class=&quot;app-section active&quot;&gt;
   1047             
   1048             &lt;div class=&quot;converter-stage&quot;&gt;
   1049                 &lt;!-- SOURCE CARD --&gt;
   1050                 &lt;div class=&quot;material-card&quot; id=&quot;cardSource&quot;&gt;
   1051                     &lt;div class=&quot;card-header&quot;&gt;
   1052                         &lt;span class=&quot;input-label&quot;&gt;Input&lt;/span&gt;
   1053                         &lt;div class=&quot;custom-select-wrapper&quot; id=&quot;sourceSelectWrapper&quot;&gt;
   1054                             &lt;div class=&quot;custom-select-trigger&quot;&gt;
   1055                                 &lt;span class=&quot;selection-text&quot;&gt;Decimal&lt;/span&gt;
   1056                                 &lt;span class=&quot;arrow&quot;&gt;▼&lt;/span&gt;
   1057                             &lt;/div&gt;
   1058                             &lt;div class=&quot;custom-options&quot;&gt;
   1059                                 &lt;div class=&quot;custom-option&quot; data-value=&quot;2&quot;&gt;Binary&lt;/div&gt;
   1060                                 &lt;div class=&quot;custom-option&quot; data-value=&quot;8&quot;&gt;Octal&lt;/div&gt;
   1061                                 &lt;div class=&quot;custom-option selected&quot; data-value=&quot;10&quot;&gt;Decimal&lt;/div&gt;
   1062                                 &lt;div class=&quot;custom-option&quot; data-value=&quot;16&quot;&gt;Hexadecimal&lt;/div&gt;
   1063                             &lt;/div&gt;
   1064                             &lt;select id=&quot;fromBase&quot; style=&quot;display:none&quot;&gt;
   1065                                 &lt;option value=&quot;2&quot;&gt;Binary&lt;/option&gt;
   1066                                 &lt;option value=&quot;8&quot;&gt;Octal&lt;/option&gt;
   1067                                 &lt;option value=&quot;10&quot; selected&gt;Decimal&lt;/option&gt;
   1068                                 &lt;option value=&quot;16&quot;&gt;Hexadecimal&lt;/option&gt;
   1069                             &lt;/select&gt;
   1070                         &lt;/div&gt;
   1071                     &lt;/div&gt;
   1072                     
   1073                     &lt;textarea id=&quot;inputVal&quot; class=&quot;input-area&quot; placeholder=&quot;0&quot; spellcheck=&quot;false&quot;&gt;&lt;/textarea&gt;
   1074                     &lt;div id=&quot;errorChip&quot; class=&quot;error-chip&quot;&gt;⚠️ Invalid character for this base&lt;/div&gt;
   1075                     
   1076                     &lt;div class=&quot;card-footer&quot;&gt;
   1077                         &lt;div class=&quot;char-count&quot; id=&quot;sourceCount&quot;&gt;0 chars&lt;/div&gt;
   1078                         &lt;div class=&quot;icon-actions&quot;&gt;
   1079                             &lt;button class=&quot;icon-btn&quot; onclick=&quot;clearAll()&quot; title=&quot;Clear&quot;&gt;
   1080                                 &lt;svg width=&quot;20&quot; height=&quot;20&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z&quot;/&gt;&lt;/svg&gt;
   1081                             &lt;/button&gt;
   1082                         &lt;/div&gt;
   1083                     &lt;/div&gt;
   1084                 &lt;/div&gt;
   1085 
   1086                 &lt;!-- SWAP --&gt;
   1087                 &lt;div class=&quot;swap-container&quot;&gt;
   1088                     &lt;button class=&quot;swap-fab&quot; id=&quot;swapBtn&quot; title=&quot;Swap (Alt+S)&quot;&gt;
   1089                         &lt;svg width=&quot;24&quot; height=&quot;24&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M6.99 11L3 15l3.99 4v-3H14v-2H6.99v-3zM21 9l-3.99-4v3H10v2h7.01v3L21 9z&quot;/&gt;&lt;/svg&gt;
   1090                     &lt;/button&gt;
   1091                 &lt;/div&gt;
   1092 
   1093                 &lt;!-- TARGET CARD --&gt;
   1094                 &lt;div class=&quot;material-card&quot; id=&quot;cardTarget&quot;&gt;
   1095                     &lt;div class=&quot;card-header&quot;&gt;
   1096                         &lt;span class=&quot;input-label&quot;&gt;Result&lt;/span&gt;
   1097                         &lt;div class=&quot;custom-select-wrapper&quot; id=&quot;targetSelectWrapper&quot;&gt;
   1098                             &lt;div class=&quot;custom-select-trigger&quot;&gt;
   1099                                 &lt;span class=&quot;selection-text&quot;&gt;Binary&lt;/span&gt;
   1100                                 &lt;span class=&quot;arrow&quot;&gt;▼&lt;/span&gt;
   1101                             &lt;/div&gt;
   1102                             &lt;div class=&quot;custom-options&quot;&gt;
   1103                                 &lt;div class=&quot;custom-option selected&quot; data-value=&quot;2&quot;&gt;Binary&lt;/div&gt;
   1104                                 &lt;div class=&quot;custom-option&quot; data-value=&quot;8&quot;&gt;Octal&lt;/div&gt;
   1105                                 &lt;div class=&quot;custom-option&quot; data-value=&quot;10&quot;&gt;Decimal&lt;/div&gt;
   1106                                 &lt;div class=&quot;custom-option&quot; data-value=&quot;16&quot;&gt;Hexadecimal&lt;/div&gt;
   1107                             &lt;/div&gt;
   1108                             &lt;select id=&quot;toBase&quot; style=&quot;display:none&quot;&gt;
   1109                                 &lt;option value=&quot;2&quot; selected&gt;Binary&lt;/option&gt;
   1110                                 &lt;option value=&quot;8&quot;&gt;Octal&lt;/option&gt;
   1111                                 &lt;option value=&quot;10&quot;&gt;Decimal&lt;/option&gt;
   1112                                 &lt;option value=&quot;16&quot;&gt;Hexadecimal&lt;/option&gt;
   1113                             &lt;/select&gt;
   1114                         &lt;/div&gt;
   1115                     &lt;/div&gt;
   1116                     
   1117                     &lt;textarea id=&quot;outputVal&quot; class=&quot;input-area&quot; readonly placeholder=&quot;...&quot; spellcheck=&quot;false&quot;&gt;&lt;/textarea&gt;
   1118                     
   1119                     &lt;div class=&quot;card-footer&quot;&gt;
   1120                         &lt;div class=&quot;char-count&quot;&gt;Result&lt;/div&gt;
   1121                         &lt;div class=&quot;icon-actions&quot;&gt;
   1122                             &lt;button class=&quot;icon-btn&quot; onclick=&quot;speakResult()&quot; title=&quot;Speak&quot;&gt;
   1123                                 &lt;svg width=&quot;20&quot; height=&quot;20&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M3 9v6h4l5 5V4L7 9H3zm13.5 3c0-1.77-1.02-3.29-2.5-4.03v8.05c1.48-.73 2.5-2.25 2.5-4.02zM14 3.23v2.06c2.89.86 5 3.54 5 6.71s-2.11 5.85-5 6.71v2.06c4.01-.91 7-4.49 7-8.77s-2.99-7.86-7-8.77z&quot;/&gt;&lt;/svg&gt;
   1124                             &lt;/button&gt;
   1125                             &lt;button class=&quot;icon-btn&quot; id=&quot;copyBtn&quot; onclick=&quot;copyToClipboard(&#x27;outputVal&#x27;, &#x27;copyBtn&#x27;)&quot; title=&quot;Copy (Ctrl+Enter)&quot;&gt;
   1126                                 &lt;svg width=&quot;20&quot; height=&quot;20&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M16 1H4c-1.1 0-2 .9-2 2v14h2V3h12V1zm3 4H8c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h11c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2zm0 16H8V7h11v14z&quot;/&gt;&lt;/svg&gt;
   1127                             &lt;/button&gt;
   1128                         &lt;/div&gt;
   1129                     &lt;/div&gt;
   1130                 &lt;/div&gt;
   1131             &lt;/div&gt;
   1132 
   1133             &lt;!-- STEPS PANEL WITH COPY BUTTON --&gt;
   1134             &lt;div class=&quot;steps-container&quot; id=&quot;stepsContainer&quot;&gt;
   1135                 &lt;div class=&quot;steps-header&quot;&gt;
   1136                     &lt;h4 style=&quot;color:var(--md-sys-color-primary); margin:0;&quot;&gt;Calculation Steps&lt;/h4&gt;
   1137                     &lt;button class=&quot;icon-btn&quot; id=&quot;copyStepsBtn&quot; onclick=&quot;copyStepsText()&quot; title=&quot;Copy Steps&quot;&gt;
   1138                         &lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M16 1H4c-1.1 0-2 .9-2 2v14h2V3h12V1zm3 4H8c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h11c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2zm0 16H8V7h11v14z&quot;/&gt;&lt;/svg&gt;
   1139                     &lt;/button&gt;
   1140                 &lt;/div&gt;
   1141                 &lt;div class=&quot;steps-content&quot; id=&quot;stepsOutput&quot;&gt;Waiting for input...&lt;/div&gt;
   1142             &lt;/div&gt;
   1143 
   1144             &lt;div class=&quot;history-section&quot;&gt;
   1145                 &lt;div class=&quot;history-header&quot; style=&quot;display:flex; justify-content:space-between; align-items:center; margin-bottom:10px;&quot;&gt;
   1146                     &lt;h4 style=&quot;color:var(--md-sys-color-on-surface-variant); margin:0;&quot;&gt;Recent History&lt;/h4&gt;
   1147                     &lt;button class=&quot;icon-btn&quot; id=&quot;clearHistBtn&quot; onclick=&quot;clearHistory()&quot; title=&quot;Clear History&quot;&gt;
   1148                         &lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M6 19c0 1.1.9 2 2 2h8c1.1 0 2-.9 2-2V7H6v12zM19 4h-3.5l-1-1h-5l-1 1H5v2h14V4z&quot;/&gt;&lt;/svg&gt;
   1149                     &lt;/button&gt;
   1150                 &lt;/div&gt;
   1151                 &lt;div class=&quot;history-list&quot; id=&quot;historyList&quot;&gt;
   1152                     &lt;div style=&quot;padding:10px; color:#555; text-align:center;&quot;&gt;No history yet&lt;/div&gt;
   1153                 &lt;/div&gt;
   1154             &lt;/div&gt;
   1155 
   1156         &lt;/section&gt;
   1157 
   1158         &lt;!-- SECTION 2: DYNAMIC CALCULATOR --&gt;
   1159         &lt;section id=&quot;calculator-section&quot; class=&quot;app-section&quot;&gt;
   1160             &lt;div class=&quot;calc-wrapper&quot;&gt;
   1161                 
   1162                 &lt;div class=&quot;calc-header&quot;&gt;
   1163                     &lt;div class=&quot;calc-ctrl-group&quot;&gt;
   1164                         &lt;label&gt;Base Mode&lt;/label&gt;
   1165                         &lt;div class=&quot;custom-select-wrapper&quot; id=&quot;calcBaseWrapper&quot; style=&quot;flex:1&quot;&gt;
   1166                             &lt;div class=&quot;custom-select-trigger&quot;&gt;
   1167                                 &lt;span class=&quot;selection-text&quot;&gt;Decimal (Base 10)&lt;/span&gt;
   1168                                 &lt;span class=&quot;arrow&quot;&gt;▼&lt;/span&gt;
   1169                             &lt;/div&gt;
   1170                             &lt;div class=&quot;custom-options&quot;&gt;
   1171                                 &lt;div class=&quot;custom-option&quot; data-value=&quot;2&quot;&gt;Binary (Base 2)&lt;/div&gt;
   1172                                 &lt;div class=&quot;custom-option&quot; data-value=&quot;8&quot;&gt;Octal (Base 8)&lt;/div&gt;
   1173                                 &lt;div class=&quot;custom-option selected&quot; data-value=&quot;10&quot;&gt;Decimal (Base 10)&lt;/div&gt;
   1174                                 &lt;div class=&quot;custom-option&quot; data-value=&quot;16&quot;&gt;Hex (Base 16)&lt;/div&gt;
   1175                             &lt;/div&gt;
   1176                             &lt;select id=&quot;calcBase&quot; style=&quot;display:none&quot; onchange=&quot;validateAllRows()&quot;&gt;
   1177                                 &lt;option value=&quot;2&quot;&gt;Binary&lt;/option&gt;
   1178                                 &lt;option value=&quot;8&quot;&gt;Octal&lt;/option&gt;
   1179                                 &lt;option value=&quot;10&quot; selected&gt;Decimal&lt;/option&gt;
   1180                                 &lt;option value=&quot;16&quot;&gt;Hex&lt;/option&gt;
   1181                             &lt;/select&gt;
   1182                         &lt;/div&gt;
   1183                     &lt;/div&gt;
   1184                     &lt;div class=&quot;calc-ctrl-group&quot;&gt;
   1185                         &lt;label&gt;Operation&lt;/label&gt;
   1186                         &lt;div class=&quot;custom-select-wrapper&quot; id=&quot;calcOpWrapper&quot; style=&quot;flex:1&quot;&gt;
   1187                             &lt;div class=&quot;custom-select-trigger&quot;&gt;
   1188                                 &lt;span class=&quot;selection-text&quot;&gt;Addition (+)&lt;/span&gt;
   1189                                 &lt;span class=&quot;arrow&quot;&gt;▼&lt;/span&gt;
   1190                             &lt;/div&gt;
   1191                             &lt;div class=&quot;custom-options&quot;&gt;
   1192                                 &lt;div class=&quot;custom-option selected&quot; data-value=&quot;add&quot;&gt;Addition (+)&lt;/div&gt;
   1193                                 &lt;div class=&quot;custom-option&quot; data-value=&quot;sub&quot;&gt;Subtraction (-)&lt;/div&gt;
   1194                                 &lt;div class=&quot;custom-option&quot; data-value=&quot;mul&quot;&gt;Multiplication (×)&lt;/div&gt;
   1195                                 &lt;div class=&quot;custom-option&quot; data-value=&quot;div&quot;&gt;Division (÷)&lt;/div&gt;
   1196                             &lt;/div&gt;
   1197                             &lt;select id=&quot;calcOp&quot; style=&quot;display:none&quot; onchange=&quot;runCalculation()&quot;&gt;
   1198                                 &lt;option value=&quot;add&quot; selected&gt;Addition&lt;/option&gt;
   1199                                 &lt;option value=&quot;sub&quot;&gt;Subtraction&lt;/option&gt;
   1200                                 &lt;option value=&quot;mul&quot;&gt;Multiplication&lt;/option&gt;
   1201                                 &lt;option value=&quot;div&quot;&gt;Division&lt;/option&gt;
   1202                             &lt;/select&gt;
   1203                         &lt;/div&gt;
   1204                     &lt;/div&gt;
   1205                 &lt;/div&gt;
   1206 
   1207                 &lt;div id=&quot;calcRows&quot; class=&quot;calc-rows&quot;&gt;
   1208                     &lt;!-- Dynamic Rows Injected Here --&gt;
   1209                 &lt;/div&gt;
   1210 
   1211                 &lt;!-- ADD ROW BUTTON (Left Aligned) --&gt;
   1212                 &lt;button class=&quot;add-row-btn&quot; onclick=&quot;addCalcRow()&quot;&gt;+ Add Number&lt;/button&gt;
   1213 
   1214                 &lt;div class=&quot;calc-actions&quot;&gt;
   1215                     &lt;button class=&quot;visualize-btn&quot; id=&quot;vizBtn&quot; onclick=&quot;visualizeCalculation()&quot;&gt;
   1216                         &lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M12 4.5C7 4.5 2.73 7.61 1 12c1.73 4.39 6 7.5 11 7.5s9.27-3.11 11-7.5c-1.73-4.39-6-7.5-11-7.5zM12 17c-2.76 0-5-2.24-5-5s2.24-5 5-5 5 2.24 5 5-2.24 5-5 5zm0-8c-1.66 0-3 1.34-3 3s1.34 3 3 3 3-1.34 3-3-1.34-3-3-3z&quot;/&gt;&lt;/svg&gt;
   1217                         Visualize
   1218                     &lt;/button&gt;
   1219                     
   1220                     &lt;div class=&quot;calc-result-area&quot;&gt;
   1221                         &lt;div class=&quot;calc-result-display&quot;&gt;
   1222                             &lt;div class=&quot;res-label&quot;&gt;Result&lt;/div&gt;
   1223                             &lt;div class=&quot;res-value&quot; id=&quot;calcResult&quot;&gt;0&lt;/div&gt;
   1224                         &lt;/div&gt;
   1225                     &lt;/div&gt;
   1226                 &lt;/div&gt;
   1227 
   1228                 &lt;!-- BIT-BY-BIT VISUALIZER PANEL --&gt;
   1229                 &lt;div class=&quot;calc-visualizer&quot; id=&quot;visualizerPanel&quot;&gt;
   1230                     &lt;h4 style=&quot;color:var(--md-sys-color-primary); margin-bottom:15px; border-bottom:1px solid #333; padding-bottom:10px;&quot;&gt;Calculation Steps&lt;/h4&gt;
   1231                     &lt;div class=&quot;viz-grid&quot; id=&quot;vizGrid&quot;&gt;
   1232                         &lt;!-- Grid injected here --&gt;
   1233                     &lt;/div&gt;
   1234                     &lt;div class=&quot;viz-info&quot; id=&quot;vizInfo&quot;&gt;Click visualize to start...&lt;/div&gt;
   1235                 &lt;/div&gt;
   1236                 
   1237             &lt;/div&gt;
   1238         &lt;/section&gt;
   1239 
   1240     &lt;/main&gt;
   1241 
   1242     &lt;!-- PROJECT LEGACY MODAL --&gt;
   1243     &lt;div class=&quot;modal-overlay&quot; id=&quot;historyModal&quot;&gt;
   1244         &lt;div class=&quot;modal-content&quot;&gt;
   1245             &lt;div class=&quot;modal-header&quot;&gt;
   1246                 &lt;h3&gt;Project Legacy&lt;/h3&gt;
   1247                 &lt;button class=&quot;close-modal&quot; onclick=&quot;toggleHistory()&quot;&gt;×&lt;/button&gt;
   1248             &lt;/div&gt;
   1249             &lt;div class=&quot;modal-body&quot;&gt;
   1250                 &lt;div class=&quot;history-timeline&quot;&gt;
   1251                     &lt;div class=&quot;timeline-item&quot;&gt;
   1252                         &lt;div class=&quot;version-tag&quot;&gt;v1.0 (2024)&lt;/div&gt;
   1253                         &lt;p class=&quot;timeline-desc&quot;&gt;Initial High School Project. Single file, manual conversion logic, animated background.&lt;/p&gt;
   1254                     &lt;/div&gt;
   1255                     &lt;div class=&quot;timeline-item&quot;&gt;
   1256                         &lt;div class=&quot;version-tag&quot;&gt;v2.0&lt;/div&gt;
   1257                         &lt;p class=&quot;timeline-desc&quot;&gt;Modularized Logic &amp; URL State. Moved away from switch cases to a Base-N engine.&lt;/p&gt;
   1258                     &lt;/div&gt;
   1259                     &lt;div class=&quot;timeline-item&quot;&gt;
   1260                         &lt;div class=&quot;version-tag&quot;&gt;v2.1&lt;/div&gt;
   1261                         &lt;p class=&quot;timeline-desc&quot;&gt;Material You UI. Glassmorphism, animated cards, and custom dropdowns.&lt;/p&gt;
   1262                     &lt;/div&gt;
   1263                     &lt;div class=&quot;timeline-item&quot;&gt;
   1264                         &lt;div class=&quot;version-tag&quot;&gt;v2.2&lt;/div&gt;
   1265                         &lt;p class=&quot;timeline-desc&quot;&gt;Dynamic Calculator. Added list-based arithmetic with strict validation.&lt;/p&gt;
   1266                     &lt;/div&gt;
   1267                     &lt;div class=&quot;timeline-item&quot;&gt;
   1268                         &lt;div class=&quot;version-tag&quot;&gt;v2.3 - v2.8&lt;/div&gt;
   1269                         &lt;p class=&quot;timeline-desc&quot;&gt;Visualizer Engine. Bit-by-bit animation, step explanations, and history tape.&lt;/p&gt;
   1270                     &lt;/div&gt;
   1271                     &lt;div class=&quot;timeline-item&quot;&gt;
   1272                         &lt;div class=&quot;version-tag&quot;&gt;v2.10&lt;/div&gt;
   1273                         &lt;p class=&quot;timeline-desc&quot;&gt;Professional Polish. Optimized UX layout, legacy tracking, and performance tuning.&lt;/p&gt;
   1274                     &lt;/div&gt;
   1275                     &lt;div class=&quot;timeline-item&quot;&gt;
   1276                         &lt;div class=&quot;version-tag current&quot;&gt;v2.11 (2026)&lt;/div&gt;
   1277                         &lt;p class=&quot;timeline-desc&quot;&gt;Ultimate Refinement. Enhanced animations, layout stability, and smart controls.&lt;/p&gt;
   1278                     &lt;/div&gt;
   1279                 &lt;/div&gt;
   1280             &lt;/div&gt;
   1281         &lt;/div&gt;
   1282     &lt;/div&gt;
   1283 
   1284     &lt;!-- SIDEBAR CHEATSHEET --&gt;
   1285     &lt;aside class=&quot;sidebar&quot; id=&quot;sidebar&quot;&gt;
   1286         &lt;button class=&quot;close-sidebar&quot; onclick=&quot;toggleSidebar()&quot;&gt;×&lt;/button&gt;
   1287         &lt;h3&gt;Cheat Sheet&lt;/h3&gt;
   1288         
   1289         &lt;h4&gt;Powers of 2&lt;/h4&gt;
   1290         &lt;table class=&quot;cheat-table&quot; style=&quot;margin-bottom:20px;&quot;&gt;
   1291             &lt;tr&gt;&lt;td&gt;2⁰&lt;/td&gt;&lt;td&gt;1&lt;/td&gt;&lt;/tr&gt;
   1292             &lt;tr&gt;&lt;td&gt;2¹&lt;/td&gt;&lt;td&gt;2&lt;/td&gt;&lt;/tr&gt;
   1293             &lt;tr&gt;&lt;td&gt;2²&lt;/td&gt;&lt;td&gt;4&lt;/td&gt;&lt;/tr&gt;
   1294             &lt;tr&gt;&lt;td&gt;2³&lt;/td&gt;&lt;td&gt;8&lt;/td&gt;&lt;/tr&gt;
   1295             &lt;tr&gt;&lt;td&gt;2⁴&lt;/td&gt;&lt;td&gt;16&lt;/td&gt;&lt;/tr&gt;
   1296             &lt;tr&gt;&lt;td&gt;2⁵&lt;/td&gt;&lt;td&gt;32&lt;/td&gt;&lt;/tr&gt;
   1297             &lt;tr&gt;&lt;td&gt;2⁶&lt;/td&gt;&lt;td&gt;64&lt;/td&gt;&lt;/tr&gt;
   1298             &lt;tr&gt;&lt;td&gt;2⁷&lt;/td&gt;&lt;td&gt;128&lt;/td&gt;&lt;/tr&gt;
   1299             &lt;tr&gt;&lt;td&gt;2⁸&lt;/td&gt;&lt;td&gt;256&lt;/td&gt;&lt;/tr&gt;
   1300             &lt;tr&gt;&lt;td&gt;2¹⁰&lt;/td&gt;&lt;td&gt;1024&lt;/td&gt;&lt;/tr&gt;
   1301         &lt;/table&gt;
   1302 
   1303         &lt;h4&gt;Hex Lookup&lt;/h4&gt;
   1304         &lt;table class=&quot;cheat-table&quot;&gt;
   1305             &lt;tr&gt;&lt;th&gt;Dec&lt;/th&gt;&lt;th&gt;Hex&lt;/th&gt;&lt;th&gt;Bin&lt;/th&gt;&lt;/tr&gt;
   1306             &lt;tr&gt;&lt;td&gt;0&lt;/td&gt;&lt;td&gt;0&lt;/td&gt;&lt;td&gt;0000&lt;/td&gt;&lt;/tr&gt;
   1307             &lt;tr&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;0001&lt;/td&gt;&lt;/tr&gt;
   1308             &lt;tr&gt;&lt;td&gt;10&lt;/td&gt;&lt;td&gt;A&lt;/td&gt;&lt;td&gt;1010&lt;/td&gt;&lt;/tr&gt;
   1309             &lt;tr&gt;&lt;td&gt;11&lt;/td&gt;&lt;td&gt;B&lt;/td&gt;&lt;td&gt;1011&lt;/td&gt;&lt;/tr&gt;
   1310             &lt;tr&gt;&lt;td&gt;12&lt;/td&gt;&lt;td&gt;C&lt;/td&gt;&lt;td&gt;1100&lt;/td&gt;&lt;/tr&gt;
   1311             &lt;tr&gt;&lt;td&gt;13&lt;/td&gt;&lt;td&gt;D&lt;/td&gt;&lt;td&gt;1101&lt;/td&gt;&lt;/tr&gt;
   1312             &lt;tr&gt;&lt;td&gt;14&lt;/td&gt;&lt;td&gt;E&lt;/td&gt;&lt;td&gt;1110&lt;/td&gt;&lt;/tr&gt;
   1313             &lt;tr&gt;&lt;td&gt;15&lt;/td&gt;&lt;td&gt;F&lt;/td&gt;&lt;td&gt;1111&lt;/td&gt;&lt;/tr&gt;
   1314         &lt;/table&gt;
   1315     &lt;/aside&gt;
   1316 
   1317     &lt;footer&gt;
   1318         &lt;div class=&quot;footer-content&quot;&gt;
   1319             &lt;p&gt;&amp;copy; 2026 &lt;strong&gt;Amit Dutta&lt;/strong&gt;. All rights reserved.&lt;/p&gt;
   1320             &lt;div class=&quot;footer-links&quot;&gt;
   1321                 &lt;a href=&quot;https://amit.is-a.dev&quot; target=&quot;_blank&quot; class=&quot;footer-link&quot;&gt;amit.is-a.dev&lt;/a&gt;
   1322                 &lt;span&gt;•&lt;/span&gt;
   1323                 &lt;a href=&quot;https://github.com/notamitgamer&quot; target=&quot;_blank&quot; class=&quot;footer-link&quot;&gt;GitHub&lt;/a&gt;
   1324             &lt;/div&gt;
   1325         &lt;/div&gt;
   1326     &lt;/footer&gt;
   1327 
   1328     &lt;script&gt;
   1329         document.addEventListener(&#x27;DOMContentLoaded&#x27;, () =&gt; {
   1330             setupCustomDropdown(&#x27;sourceSelectWrapper&#x27;, &#x27;fromBase&#x27;);
   1331             setupCustomDropdown(&#x27;targetSelectWrapper&#x27;, &#x27;toBase&#x27;);
   1332             setupCustomDropdown(&#x27;calcBaseWrapper&#x27;, &#x27;calcBase&#x27;);
   1333             setupCustomDropdown(&#x27;calcOpWrapper&#x27;, &#x27;calcOp&#x27;);
   1334             
   1335             setupEventListeners();
   1336             
   1337             // Initialize Calculator
   1338             addCalcRow();
   1339             addCalcRow();
   1340             
   1341             renderHistory();
   1342 
   1343             try {
   1344                 const params = new URLSearchParams(window.location.search);
   1345                 if(params.has(&#x27;val&#x27;)) {
   1346                     document.getElementById(&#x27;inputVal&#x27;).value = params.get(&#x27;val&#x27;);
   1347                     if(params.has(&#x27;from&#x27;)) {
   1348                         const val = params.get(&#x27;from&#x27;);
   1349                         document.getElementById(&#x27;fromBase&#x27;).value = val;
   1350                         updateDropdownUI(&#x27;sourceSelectWrapper&#x27;, val);
   1351                     }
   1352                     if(params.has(&#x27;to&#x27;)) {
   1353                         const val = params.get(&#x27;to&#x27;);
   1354                         document.getElementById(&#x27;toBase&#x27;).value = val;
   1355                         updateDropdownUI(&#x27;targetSelectWrapper&#x27;, val);
   1356                     }
   1357                     convert();
   1358                 }
   1359             } catch(e) {}
   1360             
   1361             document.addEventListener(&#x27;click&#x27;, (e) =&gt; {
   1362                 const sidebar = document.getElementById(&#x27;sidebar&#x27;);
   1363                 const historyModal = document.getElementById(&#x27;historyModal&#x27;);
   1364                 const toolsBtns = document.querySelectorAll(&#x27;.tools-btn&#x27;);
   1365                 let clickedBtn = false;
   1366                 toolsBtns.forEach(btn =&gt; { if(btn.contains(e.target)) clickedBtn = true; });
   1367 
   1368                 if (!sidebar.contains(e.target) &amp;&amp; !clickedBtn &amp;&amp; sidebar.classList.contains(&#x27;open&#x27;)) {
   1369                     toggleSidebar();
   1370                 }
   1371                 if (e.target === historyModal) {
   1372                     toggleHistory();
   1373                 }
   1374             });
   1375         });
   1376 
   1377         /* --- NAVIGATION --- */
   1378         function switchTab(tabName, index) {
   1379             document.querySelectorAll(&#x27;.app-section&#x27;).forEach(el =&gt; el.classList.remove(&#x27;active&#x27;));
   1380             document.getElementById(tabName + &#x27;-section&#x27;).classList.add(&#x27;active&#x27;);
   1381             
   1382             document.querySelectorAll(&#x27;.nav-tab&#x27;).forEach(el =&gt; el.classList.remove(&#x27;active&#x27;));
   1383             const tabs = document.querySelectorAll(&#x27;.nav-tab&#x27;);
   1384             tabs[index].classList.add(&#x27;active&#x27;);
   1385             
   1386             const glider = document.getElementById(&#x27;navGlider&#x27;);
   1387             glider.style.transform = `translateX(${index * 100}%)`;
   1388         }
   1389 
   1390         function toggleSidebar() {
   1391             document.getElementById(&#x27;sidebar&#x27;).classList.toggle(&#x27;open&#x27;);
   1392         }
   1393 
   1394         function toggleHistory() {
   1395             const modal = document.getElementById(&#x27;historyModal&#x27;);
   1396             modal.classList.toggle(&#x27;open&#x27;);
   1397         }
   1398 
   1399         /* --- DROPDOWN LOGIC --- */
   1400         function setupCustomDropdown(wrapperId, nativeSelectId) {
   1401             const wrapper = document.getElementById(wrapperId);
   1402             const nativeSelect = document.getElementById(nativeSelectId);
   1403             const trigger = wrapper.querySelector(&#x27;.custom-select-trigger&#x27;);
   1404             const triggerText = trigger.querySelector(&#x27;.selection-text&#x27;);
   1405             const options = wrapper.querySelectorAll(&#x27;.custom-option&#x27;);
   1406 
   1407             trigger.addEventListener(&#x27;click&#x27;, (e) =&gt; {
   1408                 e.stopPropagation();
   1409                 document.querySelectorAll(&#x27;.custom-select-wrapper&#x27;).forEach(w =&gt; {
   1410                     if(w !== wrapper) w.classList.remove(&#x27;open&#x27;);
   1411                 });
   1412                 wrapper.classList.toggle(&#x27;open&#x27;);
   1413             });
   1414 
   1415             options.forEach(opt =&gt; {
   1416                 opt.addEventListener(&#x27;click&#x27;, (e) =&gt; {
   1417                     e.stopPropagation();
   1418                     wrapper.querySelectorAll(&#x27;.custom-option&#x27;).forEach(o =&gt; o.classList.remove(&#x27;selected&#x27;));
   1419                     opt.classList.add(&#x27;selected&#x27;);
   1420                     triggerText.textContent = opt.textContent;
   1421                     wrapper.classList.remove(&#x27;open&#x27;);
   1422                     
   1423                     nativeSelect.value = opt.getAttribute(&#x27;data-value&#x27;);
   1424                     nativeSelect.dispatchEvent(new Event(&#x27;change&#x27;));
   1425                 });
   1426             });
   1427 
   1428             document.addEventListener(&#x27;click&#x27;, () =&gt; {
   1429                 wrapper.classList.remove(&#x27;open&#x27;);
   1430             });
   1431         }
   1432         
   1433         function updateDropdownUI(wrapperId, value) {
   1434             const wrapper = document.getElementById(wrapperId);
   1435             const triggerText = wrapper.querySelector(&#x27;.selection-text&#x27;);
   1436             const options = wrapper.querySelectorAll(&#x27;.custom-option&#x27;);
   1437             
   1438             options.forEach(opt =&gt; {
   1439                 if(opt.getAttribute(&#x27;data-value&#x27;) === value) {
   1440                     opt.classList.add(&#x27;selected&#x27;);
   1441                     triggerText.textContent = opt.textContent;
   1442                 } else {
   1443                     opt.classList.remove(&#x27;selected&#x27;);
   1444                 }
   1445             });
   1446         }
   1447 
   1448         /* --- CONVERTER LOGIC --- */
   1449         function convert() {
   1450             const inputVal = document.getElementById(&#x27;inputVal&#x27;).value;
   1451             const outputEl = document.getElementById(&#x27;outputVal&#x27;);
   1452             const errorChip = document.getElementById(&#x27;errorChip&#x27;);
   1453             const fromBase = parseInt(document.getElementById(&#x27;fromBase&#x27;).value);
   1454             const toBase = parseInt(document.getElementById(&#x27;toBase&#x27;).value);
   1455 
   1456             document.getElementById(&#x27;sourceCount&#x27;).textContent = `${inputVal.length} chars`;
   1457             errorChip.classList.remove(&#x27;visible&#x27;);
   1458 
   1459             if(!inputVal) { 
   1460                 outputEl.value = &#x27;&#x27;; 
   1461                 document.getElementById(&#x27;stepsContainer&#x27;).classList.remove(&#x27;visible&#x27;);
   1462                 updateURL(&#x27;&#x27;);
   1463                 return; 
   1464             }
   1465 
   1466             const normalized = inputVal.trim().toUpperCase();
   1467             const validChars = &quot;0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ.&quot;.substring(0, fromBase) + &quot;.&quot;;
   1468             const regex = new RegExp(`^[${validChars}]+$`);
   1469             
   1470             if(!regex.test(normalized)) {
   1471                 errorChip.classList.add(&#x27;visible&#x27;);
   1472                 outputEl.value = &quot;Error&quot;;
   1473                 document.getElementById(&#x27;stepsContainer&#x27;).classList.remove(&#x27;visible&#x27;);
   1474                 return;
   1475             }
   1476 
   1477             try {
   1478                 updateURL(normalized, fromBase, toBase);
   1479 
   1480                 const parts = normalized.split(&#x27;.&#x27;);
   1481                 const decInt = parseInt(parts[0], fromBase);
   1482                 let decTotal = decInt;
   1483                 
   1484                 const result = decTotal.toString(toBase).toUpperCase();
   1485                 outputEl.value = result;
   1486 
   1487                 generateSteps(normalized, fromBase, toBase, decTotal, result);
   1488                 addToHistory(normalized, result, fromBase, toBase);
   1489 
   1490             } catch(e) {
   1491                 outputEl.value = &quot;Error&quot;;
   1492             }
   1493         }
   1494 
   1495         function generateSteps(input, from, to, decimal, result) {
   1496             const container = document.getElementById(&#x27;stepsContainer&#x27;);
   1497             const output = document.getElementById(&#x27;stepsOutput&#x27;);
   1498             container.classList.add(&#x27;visible&#x27;);
   1499             
   1500             let log = `Converting ${input} (Base ${from}) to Base ${to}\n`;
   1501             log += `------------------------------------------\n`;
   1502             
   1503             if(from !== 10) {
   1504                 log += `1. Convert to Decimal:\n   `;
   1505                 const digits = input.split(&#x27;.&#x27;)[0].split(&#x27;&#x27;).reverse();
   1506                 digits.forEach((d, i) =&gt; {
   1507                     log += `${d}×${from}^${i} + `;
   1508                 });
   1509                 log = log.slice(0, -3); // Remove last +
   1510                 log += ` = ${decimal}\n\n`;
   1511             } else {
   1512                 log += `1. Already Decimal: ${decimal}\n\n`;
   1513             }
   1514 
   1515             if(to !== 10) {
   1516                 log += `2. Convert Decimal ${decimal} to Base ${to}:\n`;
   1517                 let temp = decimal;
   1518                 while(temp &gt; 0) {
   1519                     let rem = temp % to;
   1520                     let quot = Math.floor(temp / to);
   1521                     log += `   ${temp} ÷ ${to} = ${quot} [Rem: ${rem.toString(to).toUpperCase()}]\n`;
   1522                     temp = quot;
   1523                 }
   1524                 log += `   Read remainders bottom-up: ${result}`;
   1525             } else {
   1526                 log += `2. Result is Decimal: ${result}`;
   1527             }
   1528             output.textContent = log;
   1529         }
   1530 
   1531         function updateURL(val, from, to) {
   1532             try {
   1533                 const url = new URL(window.location);
   1534                 if(val) {
   1535                     url.searchParams.set(&#x27;val&#x27;, val);
   1536                     url.searchParams.set(&#x27;from&#x27;, from);
   1537                     url.searchParams.set(&#x27;to&#x27;, to);
   1538                     window.history.replaceState({}, &#x27;&#x27;, url);
   1539                 } else {
   1540                     const cleanUrl = window.location.pathname;
   1541                     window.history.replaceState({}, &#x27;&#x27;, cleanUrl);
   1542                 }
   1543             } catch(e) {}
   1544         }
   1545 
   1546         /* --- HISTORY LOGIC --- */
   1547         function addToHistory(inVal, outVal, from, to) {
   1548             const key = &quot;nct_history&quot;;
   1549             let history = JSON.parse(localStorage.getItem(key) || &quot;[]&quot;);
   1550             if(history.length &gt; 0 &amp;&amp; history[0].inVal === inVal &amp;&amp; history[0].to === to) return;
   1551             history.unshift({ inVal, outVal, from, to });
   1552             if(history.length &gt; 10) history.pop();
   1553             localStorage.setItem(key, JSON.stringify(history));
   1554             renderHistory();
   1555         }
   1556 
   1557         function renderHistory() {
   1558             const list = document.getElementById(&#x27;historyList&#x27;);
   1559             const history = JSON.parse(localStorage.getItem(&quot;nct_history&quot;) || &quot;[]&quot;);
   1560             if(history.length === 0) {
   1561                 list.innerHTML = &#x27;&lt;div style=&quot;padding:10px; color:#555; text-align:center;&quot;&gt;No history yet&lt;/div&gt;&#x27;;
   1562                 return;
   1563             }
   1564             list.innerHTML = &#x27;&#x27;;
   1565             history.forEach(item =&gt; {
   1566                 const div = document.createElement(&#x27;div&#x27;);
   1567                 div.className = &#x27;history-item&#x27;;
   1568                 div.innerHTML = `&lt;div&gt;&lt;span class=&quot;hist-meta&quot;&gt;Base ${item.from} → ${item.to}&lt;/span&gt;&lt;span class=&quot;hist-val&quot;&gt;${item.inVal} = ${item.outVal}&lt;/span&gt;&lt;/div&gt;`;
   1569                 div.onclick = () =&gt; {
   1570                     document.getElementById(&#x27;inputVal&#x27;).value = item.inVal;
   1571                     document.getElementById(&#x27;fromBase&#x27;).value = item.from;
   1572                     document.getElementById(&#x27;toBase&#x27;).value = item.to;
   1573                     updateDropdownUI(&#x27;sourceSelectWrapper&#x27;, item.from.toString());
   1574                     updateDropdownUI(&#x27;targetSelectWrapper&#x27;, item.to.toString());
   1575                     convert();
   1576                 };
   1577                 list.appendChild(div);
   1578             });
   1579         }
   1580         
   1581         function clearHistory() {
   1582             const list = document.getElementById(&#x27;historyList&#x27;);
   1583             const btn = document.getElementById(&#x27;clearHistBtn&#x27;);
   1584             
   1585             if(list.children.length === 0 || list.innerText.includes(&quot;No history&quot;)) return;
   1586             
   1587             // Trigger Shake Animation on Button
   1588             btn.classList.add(&#x27;shaking&#x27;);
   1589             
   1590             // Trigger Slide Out Animation on List
   1591             list.classList.add(&#x27;clearing&#x27;);
   1592             
   1593             setTimeout(() =&gt; {
   1594                 localStorage.removeItem(&quot;nct_history&quot;);
   1595                 renderHistory();
   1596                 list.classList.remove(&#x27;clearing&#x27;);
   1597                 btn.classList.remove(&#x27;shaking&#x27;);
   1598             }, 400); // Duration matches CSS animation
   1599         }
   1600 
   1601         /* --- DYNAMIC CALCULATOR LOGIC --- */
   1602         function addCalcRow() {
   1603             const container = document.getElementById(&#x27;calcRows&#x27;);
   1604             const div = document.createElement(&#x27;div&#x27;);
   1605             div.className = &#x27;calc-row&#x27;;
   1606             div.innerHTML = `
   1607                 &lt;div class=&quot;calc-input-wrapper&quot;&gt;
   1608                     &lt;input type=&quot;text&quot; class=&quot;calc-input&quot; placeholder=&quot;Enter number...&quot; oninput=&quot;validateRow(this); runCalculation()&quot;&gt;
   1609                 &lt;/div&gt;
   1610                 &lt;button class=&quot;calc-remove-btn&quot; onclick=&quot;removeRow(this)&quot; title=&quot;Remove&quot;&gt;×&lt;/button&gt;
   1611             `;
   1612             container.appendChild(div);
   1613             div.querySelector(&#x27;input&#x27;).focus();
   1614         }
   1615 
   1616         function removeRow(btn) {
   1617             const row = btn.parentElement;
   1618             if(document.querySelectorAll(&#x27;.calc-row&#x27;).length &gt; 1) {
   1619                 row.classList.add(&#x27;removing&#x27;);
   1620                 setTimeout(() =&gt; {
   1621                     row.remove();
   1622                     runCalculation();
   1623                 }, 300);
   1624             }
   1625         }
   1626 
   1627         function validateRow(input) {
   1628             const base = parseInt(document.getElementById(&#x27;calcBase&#x27;).value);
   1629             const val = input.value.trim().toUpperCase();
   1630             if(!val) {
   1631                 input.classList.remove(&#x27;invalid&#x27;);
   1632                 return true;
   1633             }
   1634             const validChars = &quot;0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ.&quot;.substring(0, base) + &quot;.&quot;;
   1635             const regex = new RegExp(`^[${validChars}]+$`);
   1636             if(!regex.test(val)) {
   1637                 input.classList.add(&#x27;invalid&#x27;);
   1638                 return false;
   1639             } else {
   1640                 input.classList.remove(&#x27;invalid&#x27;);
   1641                 return true;
   1642             }
   1643         }
   1644 
   1645         function validateAllRows() {
   1646             document.querySelectorAll(&#x27;.calc-input&#x27;).forEach(input =&gt; validateRow(input));
   1647             runCalculation();
   1648         }
   1649 
   1650         function runCalculation() {
   1651             const base = parseInt(document.getElementById(&#x27;calcBase&#x27;).value);
   1652             const op = document.getElementById(&#x27;calcOp&#x27;).value;
   1653             const inputs = document.querySelectorAll(&#x27;.calc-input&#x27;);
   1654             const vizBtn = document.getElementById(&#x27;vizBtn&#x27;);
   1655             let total = null;
   1656             let error = false;
   1657 
   1658             inputs.forEach(input =&gt; {
   1659                 if(input.classList.contains(&#x27;invalid&#x27;)) { error = true; return; }
   1660                 const valStr = input.value.trim().toUpperCase();
   1661                 if(!valStr) return;
   1662                 const val = parseInt(valStr, base);
   1663                 if(isNaN(val)) return;
   1664                 if(total === null) { total = val; } else {
   1665                     if(op === &#x27;add&#x27;) total += val;
   1666                     if(op === &#x27;sub&#x27;) total -= val;
   1667                     if(op === &#x27;mul&#x27;) total *= val;
   1668                     if(op === &#x27;div&#x27;) total = Math.floor(total / val);
   1669                 }
   1670             });
   1671 
   1672             const resEl = document.getElementById(&#x27;calcResult&#x27;);
   1673             if(error) {
   1674                 resEl.textContent = &quot;Invalid Input&quot;;
   1675                 resEl.style.color = &quot;var(--md-sys-color-error)&quot;;
   1676                 vizBtn.style.display = &#x27;none&#x27;;
   1677             } else if(total === null) {
   1678                 resEl.textContent = &quot;0&quot;;
   1679                 resEl.style.color = &quot;var(--md-sys-color-primary)&quot;;
   1680                 vizBtn.style.display = &#x27;none&#x27;;
   1681             } else {
   1682                 resEl.textContent = total.toString(base).toUpperCase();
   1683                 resEl.style.color = &quot;var(--md-sys-color-primary)&quot;;
   1684                 vizBtn.style.display = (op === &#x27;add&#x27;) ? &#x27;flex&#x27; : &#x27;none&#x27;;
   1685             }
   1686             document.getElementById(&#x27;visualizerPanel&#x27;).classList.remove(&#x27;active&#x27;);
   1687         }
   1688 
   1689         /* --- VISUALIZER LOGIC (Multi-Base) --- */
   1690         function visualizeCalculation() {
   1691             const base = parseInt(document.getElementById(&#x27;calcBase&#x27;).value);
   1692             const op = document.getElementById(&#x27;calcOp&#x27;).value;
   1693             const panel = document.getElementById(&#x27;visualizerPanel&#x27;);
   1694             const grid = document.getElementById(&#x27;vizGrid&#x27;);
   1695             const info = document.getElementById(&#x27;vizInfo&#x27;);
   1696             
   1697             if(op !== &#x27;add&#x27;) return;
   1698 
   1699             const inputs = [];
   1700             let isValid = true;
   1701             document.querySelectorAll(&#x27;.calc-input&#x27;).forEach(inp =&gt; {
   1702                 if(inp.value.trim()) {
   1703                      const val = parseInt(inp.value.trim(), base);
   1704                      if(isNaN(val)) isValid = false;
   1705                      inputs.push(val);
   1706                 }
   1707             });
   1708 
   1709             if(!isValid || inputs.length &lt; 2) {
   1710                 alert(&quot;Enter at least two numbers.&quot;);
   1711                 return;
   1712             }
   1713 
   1714             panel.classList.add(&#x27;active&#x27;);
   1715             grid.innerHTML = &#x27;&#x27;;
   1716             
   1717             const digitArrays = inputs.map(n =&gt; n.toString(base).toUpperCase().split(&#x27;&#x27;));
   1718             const maxLen = Math.max(...digitArrays.map(arr =&gt; arr.length)) + 1;
   1719             
   1720             const paddedArrays = digitArrays.map(arr =&gt; {
   1721                 const padding = new Array(maxLen - arr.length).fill(&#x27;0&#x27;);
   1722                 return padding.concat(arr);
   1723             });
   1724             
   1725             grid.style.gridTemplateColumns = `repeat(${maxLen}, 1fr)`;
   1726             
   1727             for(let i=0; i&lt;maxLen; i++) {
   1728                 const cell = document.createElement(&#x27;div&#x27;);
   1729                 cell.className = &#x27;viz-cell carry&#x27;;
   1730                 cell.id = `carry-${i}`;
   1731                 grid.appendChild(cell);
   1732             }
   1733             
   1734             paddedArrays.forEach((rowDigits, rIdx) =&gt; {
   1735                 for(let i=0; i&lt;maxLen; i++) {
   1736                     const cell = document.createElement(&#x27;div&#x27;);
   1737                     cell.className = &#x27;viz-cell&#x27;;
   1738                     if(rIdx === paddedArrays.length -1) cell.classList.add(&#x27;border-bottom&#x27;);
   1739                     const val = rowDigits[i];
   1740                     cell.textContent = val;
   1741                     if(i === 0 &amp;&amp; rIdx &gt; 0) {
   1742                         cell.classList.add(&#x27;operator&#x27;);
   1743                         cell.innerHTML = `+ ${val}`;
   1744                     }
   1745                     grid.appendChild(cell);
   1746                 }
   1747             });
   1748 
   1749             for(let i=0; i&lt;maxLen; i++) {
   1750                 const cell = document.createElement(&#x27;div&#x27;);
   1751                 cell.className = &#x27;viz-cell result&#x27;;
   1752                 cell.id = `res-${i}`;
   1753                 cell.textContent = &#x27;?&#x27;;
   1754                 grid.appendChild(cell);
   1755             }
   1756 
   1757             let carry = 0;
   1758             let colIdx = maxLen - 1;
   1759 
   1760             function step() {
   1761                 if(colIdx &lt; 0) {
   1762                     info.textContent = &quot;Complete.&quot;;
   1763                     return;
   1764                 }
   1765                 document.querySelectorAll(&#x27;.active-col&#x27;).forEach(el =&gt; el.classList.remove(&#x27;active-col&#x27;));
   1766                 const resCell = document.getElementById(`res-${colIdx}`);
   1767                 resCell.classList.add(&#x27;active-col&#x27;);
   1768                 
   1769                 let sum = carry;
   1770                 const digitVals = [];
   1771                 paddedArrays.forEach(row =&gt; {
   1772                     const char = row[colIdx];
   1773                     const val = parseInt(char, base);
   1774                     sum += val;
   1775                     digitVals.push(val.toString(base).toUpperCase());
   1776                 });
   1777 
   1778                 const writeVal = sum % base;
   1779                 const newCarry = Math.floor(sum / base);
   1780 
   1781                 resCell.textContent = writeVal.toString(base).toUpperCase();
   1782                 if(newCarry &gt; 0 &amp;&amp; colIdx &gt; 0) {
   1783                     document.getElementById(`carry-${colIdx-1}`).textContent = newCarry.toString(base).toUpperCase();
   1784                 }
   1785                 
   1786                 const eqStr = `${digitVals.join(&#x27;+&#x27;)} + ${carry}(c) = ${sum}`;
   1787                 const writeStr = writeVal.toString(base).toUpperCase();
   1788                 const carryStr = newCarry.toString(base).toUpperCase();
   1789                 info.textContent = `Col ${maxLen - colIdx}: ${eqStr} (Base ${base}). Write ${writeStr}, Carry ${carryStr}`;
   1790 
   1791                 carry = newCarry;
   1792                 colIdx--;
   1793                 setTimeout(step, 800);
   1794             }
   1795             step();
   1796         }
   1797 
   1798         /* --- UTILS &amp; SWAP --- */
   1799         function setupEventListeners() {
   1800             document.addEventListener(&#x27;keydown&#x27;, (e) =&gt; {
   1801                 if(e.ctrlKey &amp;&amp; e.key === &#x27;Enter&#x27;) copyToClipboard(&#x27;outputVal&#x27;, &#x27;copyBtn&#x27;);
   1802                 if(e.altKey &amp;&amp; e.key === &#x27;s&#x27;) document.getElementById(&#x27;swapBtn&#x27;).click();
   1803             });
   1804 
   1805             document.getElementById(&#x27;inputVal&#x27;).addEventListener(&#x27;input&#x27;, convert);
   1806             document.getElementById(&#x27;fromBase&#x27;).addEventListener(&#x27;change&#x27;, convert);
   1807             document.getElementById(&#x27;toBase&#x27;).addEventListener(&#x27;change&#x27;, convert);
   1808 
   1809             document.getElementById(&#x27;swapBtn&#x27;).addEventListener(&#x27;click&#x27;, () =&gt; {
   1810                 const cardSource = document.getElementById(&#x27;cardSource&#x27;);
   1811                 const cardTarget = document.getElementById(&#x27;cardTarget&#x27;);
   1812                 const isMobile = window.innerWidth &lt;= 768;
   1813 
   1814                 if(isMobile) {
   1815                     cardSource.classList.add(&#x27;anim-move-down&#x27;);
   1816                     cardTarget.classList.add(&#x27;anim-move-up&#x27;);
   1817                 } else {
   1818                     cardSource.classList.add(&#x27;anim-move-right&#x27;);
   1819                     cardTarget.classList.add(&#x27;anim-move-left&#x27;);
   1820                 }
   1821 
   1822                 setTimeout(() =&gt; {
   1823                     const inEl = document.getElementById(&#x27;inputVal&#x27;);
   1824                     const outEl = document.getElementById(&#x27;outputVal&#x27;);
   1825                     const from = document.getElementById(&#x27;fromBase&#x27;);
   1826                     const to = document.getElementById(&#x27;toBase&#x27;);
   1827 
   1828                     const tempVal = inEl.value;
   1829                     inEl.value = outEl.value;
   1830                     const tempBase = from.value;
   1831                     from.value = to.value;
   1832                     to.value = tempBase;
   1833                     
   1834                     updateDropdownUI(&#x27;sourceSelectWrapper&#x27;, from.value);
   1835                     updateDropdownUI(&#x27;targetSelectWrapper&#x27;, to.value);
   1836 
   1837                     cardSource.classList.remove(&#x27;anim-move-down&#x27;, &#x27;anim-move-right&#x27;);
   1838                     cardTarget.classList.remove(&#x27;anim-move-up&#x27;, &#x27;anim-move-left&#x27;);
   1839                     convert();
   1840                 }, 400); 
   1841             });
   1842         }
   1843 
   1844         function speakResult() {
   1845             const txt = document.getElementById(&#x27;outputVal&#x27;).value;
   1846             if(!txt) return;
   1847             let spoken = txt;
   1848             if(document.getElementById(&#x27;toBase&#x27;).value == 2) {
   1849                 spoken = txt.split(&#x27;&#x27;).join(&#x27; &#x27;); 
   1850             }
   1851             const utt = new SpeechSynthesisUtterance(spoken);
   1852             window.speechSynthesis.speak(utt);
   1853         }
   1854 
   1855         function copyToClipboard(id, btnId) {
   1856             const el = document.getElementById(id);
   1857             if(el) {
   1858                 el.select();
   1859                 document.execCommand(&#x27;copy&#x27;);
   1860             }
   1861             const btn = document.getElementById(btnId);
   1862             if(btn) {
   1863                 const originalHTML = btn.innerHTML;
   1864                 btn.innerHTML = `&lt;svg width=&quot;20&quot; height=&quot;20&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;var(--md-sys-color-success)&quot;&gt;&lt;path d=&quot;M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z&quot;/&gt;&lt;/svg&gt;`;
   1865                 btn.classList.add(&#x27;success&#x27;);
   1866                 setTimeout(() =&gt; { 
   1867                     btn.innerHTML = originalHTML; 
   1868                     btn.classList.remove(&#x27;success&#x27;);
   1869                 }, 2000);
   1870             }
   1871         }
   1872         
   1873         function copyStepsText() {
   1874             const stepsText = document.getElementById(&#x27;stepsOutput&#x27;).innerText;
   1875             navigator.clipboard.writeText(stepsText).then(() =&gt; {
   1876                 const btn = document.getElementById(&#x27;copyStepsBtn&#x27;);
   1877                 const originalHTML = btn.innerHTML;
   1878                 btn.innerHTML = `&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;var(--md-sys-color-success)&quot;&gt;&lt;path d=&quot;M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z&quot;/&gt;&lt;/svg&gt;`;
   1879                 btn.classList.add(&#x27;success&#x27;);
   1880                 setTimeout(() =&gt; { 
   1881                     btn.innerHTML = originalHTML; 
   1882                     btn.classList.remove(&#x27;success&#x27;);
   1883                 }, 2000);
   1884             });
   1885         }
   1886 
   1887         function clearAll() {
   1888             document.getElementById(&#x27;inputVal&#x27;).value = &#x27;&#x27;;
   1889             document.getElementById(&#x27;outputVal&#x27;).value = &#x27;&#x27;;
   1890             document.getElementById(&#x27;sourceCount&#x27;).textContent = &#x27;0 chars&#x27;;
   1891             document.getElementById(&#x27;errorChip&#x27;).classList.remove(&#x27;visible&#x27;);
   1892             document.getElementById(&#x27;stepsContainer&#x27;).classList.remove(&#x27;visible&#x27;);
   1893             updateURL(&#x27;&#x27;);
   1894         }
   1895     &lt;/script&gt;
   1896 &lt;/body&gt;
   1897 &lt;/html&gt;</pre>
   1898             </div>
   1899         </div>
   1900 
   1901         <div id="download-tab-content" class="tab-content">
   1902             <div class="download-item">
   1903                 <div class="download-info">
   1904                     <h3>nct-legacy.html</h3>
   1905                     <p>Standalone production code of the Number Conversion Tool.</p>
   1906                 </div>
   1907                 <!-- Force download via download attribute -->
   1908                 <a href="https://github.com/notamitgamer/NCT/releases/download/v2.11/nct-legacy.html" class="download-button">Download File</a>
   1909             </div>
   1910             <div class="download-item">
   1911                 <div class="download-info">
   1912                     <h3>GitHub Repository</h3>
   1913                     <p>View source and contribute on GitHub.</p>
   1914                 </div>
   1915                 <a href="https://github.com/notamitgamer/nct-legacy" target="_blank" class="download-button" style="background-color: #333;">GitHub</a>
   1916             </div>
   1917         </div>
   1918     </div>
   1919 
   1920     <script>
   1921         function switchTab(evt, tabId) {
   1922             // Hide all contents
   1923             document.querySelectorAll('.tab-content').forEach(content => {
   1924                 content.classList.remove('active');
   1925             });
   1926             // Deactivate all buttons
   1927             document.querySelectorAll('.tab-button').forEach(button => {
   1928                 button.classList.remove('active');
   1929             });
   1930 
   1931             // Show current
   1932             document.getElementById(tabId + '-tab-content').classList.add('active');
   1933             evt.currentTarget.classList.add('active');
   1934         }
   1935 
   1936         async function copyToClipboard(btn) {
   1937             const code = document.getElementById('sourceCode').innerText;
   1938             try {
   1939                 await navigator.clipboard.writeText(code);
   1940                 const originalHTML = btn.innerHTML;
   1941                 btn.innerHTML = '<span>✓ Copied!</span>';
   1942                 btn.classList.add('success');
   1943                 
   1944                 setTimeout(() => {
   1945                     btn.innerHTML = originalHTML;
   1946                     btn.classList.remove('success');
   1947                 }, 2000);
   1948             } catch (err) {
   1949                 console.error('Failed to copy code: ', err);
   1950             }
   1951         }
   1952     </script>
   1953 
   1954 </body>
   1955 </html>
© notamitgamer • Site Built: 2026-09-05 01:53:16 UTC • git-mirror commit: c170d72 [view raw info]
Originally created with stagit • modified by notamitgamer
Forked from github.com/notamitgamer/git-mirror