<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Jonys Tech Book on Jonys-Book</title><link>http://jony.ch/</link><description>Recent content in Jonys Tech Book on Jonys-Book</description><generator>Hugo</generator><language>en-us</language><atom:link href="http://jony.ch/index.xml" rel="self" type="application/rss+xml"/><item><title>Huawei Option 43</title><link>http://jony.ch/docs/tools/option43/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>http://jony.ch/docs/tools/option43/</guid><description>&lt;h1 id="huawei-option-43-online-calculator"&gt;Huawei Option 43 Online Calculator&lt;a class="anchor" href="#huawei-option-43-online-calculator"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;In WLAN deployment, APs typically obtain the WAC&amp;rsquo;s IP address through the DHCP Option 43 field. This tool can be used to quickly calculate the Option 43 Hex configuration string.&lt;/p&gt;
&lt;div style="margin-top: 2rem; padding: 2rem; border: 1px solid var(--gray-200); border-radius: 8px; background-color: var(--gray-100);"&gt;
 &lt;div style="margin-bottom: 1rem;"&gt;
 &lt;label style="display: block; font-weight: bold; margin-bottom: 0.5rem;"&gt;WAC IP Address 1:&lt;/label&gt;
 &lt;input type="text" id="ip1" placeholder="e.g. 192.168.1.1" style="width: 100%; padding: 0.5rem; border: 1px solid #ccc; border-radius: 4px;" /&gt;
 &lt;/div&gt;
 &lt;div style="margin-bottom: 1rem;"&gt;
 &lt;label style="display: block; font-weight: bold; margin-bottom: 0.5rem;"&gt;WAC IP Address 2 (Optional, active/standby scenario):&lt;/label&gt;
 &lt;input type="text" id="ip2" placeholder="e.g. 192.168.1.2" style="width: 100%; padding: 0.5rem; border: 1px solid #ccc; border-radius: 4px;" /&gt;
 &lt;/div&gt;
 &lt;button onclick="calculateOption43()" style="background-color: #CF0A2C; color: white; border: none; padding: 0.5rem 1rem; border-radius: 4px; cursor: pointer; font-weight: bold;"&gt;
 Calculate Option 43
 &lt;/button&gt;
 &lt;div style="margin-top: 2rem;"&gt;
 &lt;strong style="display: block; margin-bottom: 0.5rem;"&gt;Calculation Result:&lt;/strong&gt;
 &lt;div id="result" style="padding: 1rem; background-color: #fff; border: 1px dashed #ccc; border-radius: 4px; font-family: monospace; word-break: break-all; min-height: 1.5rem;"&gt;
 &lt;/div&gt;
 &lt;/div&gt;
&lt;/div&gt;
&lt;script&gt;
function calculateOption43() {
 const ip1 = document.getElementById('ip1').value.trim();
 const ip2 = document.getElementById('ip2').value.trim();
 
 let ipStr = '';
 if (ip1 &amp;&amp; ip2) {
 ipStr = ip1 + ',' + ip2;
 } else if (ip1) {
 ipStr = ip1;
 } else if (ip2) {
 ipStr = ip2;
 }

 if (!ipStr) {
 document.getElementById('result').innerText = 'Please enter at least one IP address';
 return;
 }

 // Simple Regex validation for IP
 const ipRegex = /^(?:[0-9]{1,3}\.){3}[0-9]{1,3}$/;
 if (ip1 &amp;&amp; !ipRegex.test(ip1)) {
 document.getElementById('result').innerText = 'IP Address 1 format is incorrect';
 return;
 }
 if (ip2 &amp;&amp; !ipRegex.test(ip2)) {
 document.getElementById('result').innerText = 'IP Address 2 format is incorrect';
 return;
 }

 let hexStr = '';
 for (let i = 0; i &lt; ipStr.length; i++) {
 hexStr += ipStr.charCodeAt(i).toString(16).toUpperCase();
 }
 
 // Length (Hexadecimal)
 let lengthHex = ipStr.length.toString(16).toUpperCase().padStart(2, '0');
 // Sub-option type 03 + length + Hex converted from string
 let result = '03' + lengthHex + hexStr;
 
 document.getElementById('result').innerText = result;
}
&lt;/script&gt;
&lt;h2 id="calculation-instructions"&gt;Calculation Instructions&lt;a class="anchor" href="#calculation-instructions"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The format of Huawei Option 43 field is usually: &lt;code&gt;03&lt;/code&gt; (sub-option type) + &lt;code&gt;Length&lt;/code&gt; (hexadecimal, 1 byte) + &lt;code&gt;ASCII Hexadecimal of comma-separated IP string&lt;/code&gt;.&lt;/p&gt;</description></item><item><title>IP &amp; Subnet Calculator</title><link>http://jony.ch/docs/tools/subnet/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>http://jony.ch/docs/tools/subnet/</guid><description>&lt;h1 id="ip--subnet-calculator"&gt;IP &amp;amp; Subnet Calculator&lt;a class="anchor" href="#ip--subnet-calculator"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;This tool provides network address calculations, subnet mask conversions, and wildcard mask calculations.&lt;/p&gt;
&lt;div style="margin-top: 2rem; padding: 2rem; border: 1px solid var(--gray-200); border-radius: 8px; background-color: var(--gray-100);"&gt;
 &lt;!-- Feature 1 --&gt;
 &lt;div style="margin-bottom: 2rem; padding-bottom: 2rem; border-bottom: 1px solid #ccc;"&gt;
 &lt;h3 style="margin-top: 0;"&gt;1. Network Address Calculator&lt;/h3&gt;
 &lt;label style="display: block; font-weight: bold; margin-bottom: 0.5rem;"&gt;IP Address &amp; Prefix (e.g., 192.168.1.2/25):&lt;/label&gt;
 &lt;div style="display: flex; gap: 1rem;"&gt;
 &lt;input type="text" id="ipInput1" placeholder="192.168.1.2/25" style="flex: 1; padding: 0.5rem; border: 1px solid #ccc; border-radius: 4px;" /&gt;
 &lt;button onclick="calcFeature1()" style="background-color: #CF0A2C; color: white; border: none; padding: 0.5rem 1rem; border-radius: 4px; cursor: pointer; font-weight: bold;"&gt;Calculate&lt;/button&gt;
 &lt;/div&gt;
 &lt;div id="result1" style="margin-top: 1rem; padding: 1rem; background-color: #fff; border: 1px dashed #ccc; border-radius: 4px; font-family: monospace; white-space: pre-wrap; min-height: 1.5rem; display: none;"&gt;&lt;/div&gt;
 &lt;/div&gt;
 &lt;!-- Feature 2 --&gt;
 &lt;div style="margin-bottom: 2rem; padding-bottom: 2rem; border-bottom: 1px solid #ccc;"&gt;
 &lt;h3 style="margin-top: 0;"&gt;2. Mask &amp; Host Calculator&lt;/h3&gt;
 &lt;label style="display: block; font-weight: bold; margin-bottom: 0.5rem;"&gt;Subnet Mask or Prefix Length (e.g., 25 or 255.255.255.128):&lt;/label&gt;
 &lt;div style="display: flex; gap: 1rem;"&gt;
 &lt;input type="text" id="ipInput2" placeholder="25 or 255.255.255.128" style="flex: 1; padding: 0.5rem; border: 1px solid #ccc; border-radius: 4px;" /&gt;
 &lt;button onclick="calcFeature2()" style="background-color: #CF0A2C; color: white; border: none; padding: 0.5rem 1rem; border-radius: 4px; cursor: pointer; font-weight: bold;"&gt;Calculate&lt;/button&gt;
 &lt;/div&gt;
 &lt;div id="result2" style="margin-top: 1rem; padding: 1rem; background-color: #fff; border: 1px dashed #ccc; border-radius: 4px; font-family: monospace; white-space: pre-wrap; min-height: 1.5rem; display: none;"&gt;&lt;/div&gt;
 &lt;/div&gt;
 &lt;!-- Feature 3 --&gt;
 &lt;div style="margin-bottom: 2rem; padding-bottom: 2rem; border-bottom: 1px solid #ccc;"&gt;
 &lt;h3 style="margin-top: 0;"&gt;3. Wildcard Mask Calculator&lt;/h3&gt;
 &lt;label style="display: block; font-weight: bold; margin-bottom: 0.5rem;"&gt;Subnet Mask (e.g., 255.255.255.0):&lt;/label&gt;
 &lt;div style="display: flex; gap: 1rem;"&gt;
 &lt;input type="text" id="ipInput3" placeholder="255.255.255.0" style="flex: 1; padding: 0.5rem; border: 1px solid #ccc; border-radius: 4px;" /&gt;
 &lt;button onclick="calcFeature3()" style="background-color: #CF0A2C; color: white; border: none; padding: 0.5rem 1rem; border-radius: 4px; cursor: pointer; font-weight: bold;"&gt;Calculate&lt;/button&gt;
 &lt;/div&gt;
 &lt;div id="result3" style="margin-top: 1rem; padding: 1rem; background-color: #fff; border: 1px dashed #ccc; border-radius: 4px; font-family: monospace; white-space: pre-wrap; min-height: 1.5rem; display: none;"&gt;&lt;/div&gt;
 &lt;/div&gt;
 &lt;!-- Feature 4 --&gt;
 &lt;div&gt;
 &lt;h3 style="margin-top: 0;"&gt;4. IP Range to Subnets (CIDR)&lt;/h3&gt;
 &lt;label style="display: block; font-weight: bold; margin-bottom: 0.5rem;"&gt;IP Range (e.g., 192.168.1.0-192.168.1.65):&lt;/label&gt;
 &lt;div style="display: flex; gap: 1rem;"&gt;
 &lt;input type="text" id="ipInput4" placeholder="192.168.1.0-192.168.1.65" style="flex: 1; padding: 0.5rem; border: 1px solid #ccc; border-radius: 4px;" /&gt;
 &lt;button onclick="calcFeature4()" style="background-color: #CF0A2C; color: white; border: none; padding: 0.5rem 1rem; border-radius: 4px; cursor: pointer; font-weight: bold;"&gt;Calculate&lt;/button&gt;
 &lt;/div&gt;
 &lt;div id="result4" style="margin-top: 1rem; padding: 1rem; background-color: #fff; border: 1px dashed #ccc; border-radius: 4px; font-family: monospace; white-space: pre-wrap; min-height: 1.5rem; display: none;"&gt;&lt;/div&gt;
 &lt;/div&gt;
&lt;/div&gt;
&lt;script&gt;
function ip2long(ip) {
 return ip.split('.').reduce((acc, octet) =&gt; (acc &lt;&lt; 8) + parseInt(octet, 10), 0) &gt;&gt;&gt; 0;
}

function long2ip(long) {
 return [
 (long &gt;&gt;&gt; 24) &amp; 255,
 (long &gt;&gt;&gt; 16) &amp; 255,
 (long &gt;&gt;&gt; 8) &amp; 255,
 long &amp; 255
 ].join('.');
}

function long2binary(long) {
 let bin = long.toString(2).padStart(32, '0');
 return [
 bin.slice(0, 8),
 bin.slice(8, 16),
 bin.slice(16, 24),
 bin.slice(24, 32)
 ].join('.');
}

function maskLen2long(len) {
 return len === 0 ? 0 : (~0 &lt;&lt; (32 - len)) &gt;&gt;&gt; 0;
}

function isValidIP(ip) {
 const ipRegex = /^(?:[0-9]{1,3}\.){3}[0-9]{1,3}$/;
 if (!ipRegex.test(ip)) return false;
 return ip.split('.').every(octet =&gt; parseInt(octet, 10) &gt;= 0 &amp;&amp; parseInt(octet, 10) &lt;= 255);
}

function calcFeature1() {
 const input = document.getElementById('ipInput1').value.trim();
 const resultDiv = document.getElementById('result1');
 resultDiv.style.display = 'block';

 if (!input.includes('/')) {
 resultDiv.innerText = 'Error: Please include a prefix length (e.g., 192.168.1.2/25)';
 return;
 }

 const parts = input.split('/');
 const ip = parts[0];
 const prefix = parseInt(parts[1], 10);

 if (!isValidIP(ip) || isNaN(prefix) || prefix &lt; 0 || prefix &gt; 32) {
 resultDiv.innerText = 'Error: Invalid IP address or prefix length';
 return;
 }

 const ipLong = ip2long(ip);
 const maskLong = maskLen2long(prefix);
 const networkLong = (ipLong &amp; maskLong) &gt;&gt;&gt; 0;
 const broadcastLong = (networkLong | (~maskLong)) &gt;&gt;&gt; 0;
 
 let usableCount = 0;
 if (prefix &lt;= 30) {
 usableCount = (broadcastLong - networkLong - 1);
 } else if (prefix === 31) {
 usableCount = 2; // point-to-point
 } else if (prefix === 32) {
 usableCount = 1;
 }

 const output = [
 `Address Range : ${long2ip(networkLong)} - ${long2ip(broadcastLong)}`,
 `Network Address : ${long2ip(networkLong)}`,
 `Broadcast Address : ${long2ip(broadcastLong)}`,
 `Subnet Mask : ${long2ip(maskLong)}`,
 `Usable Hosts : ${usableCount}`,
 `Network (Binary) : ${long2binary(networkLong)}`,
 `Broadcast (Binary) : ${long2binary(broadcastLong)}`,
 `Mask (Binary) : ${long2binary(maskLong)}`
 ].join('\n');

 resultDiv.innerText = output;
}

function calcFeature2() {
 const input = document.getElementById('ipInput2').value.trim();
 const resultDiv = document.getElementById('result2');
 resultDiv.style.display = 'block';

 let prefix = parseInt(input, 10);
 let maskLong;
 let isPrefixInput = false;

 if (isValidIP(input)) {
 maskLong = ip2long(input);
 // Calculate prefix from mask (counting consecutive 1s from left is standard, but here we just count all 1s for simplicity, though real validation could be stricter)
 let m = maskLong;
 prefix = 0;
 while ((m &amp; 0x80000000) !== 0) {
 prefix++;
 m = (m &lt;&lt; 1) &gt;&gt;&gt; 0;
 }
 } else if (!isNaN(prefix) &amp;&amp; prefix &gt;= 0 &amp;&amp; prefix &lt;= 32 &amp;&amp; input === prefix.toString()) {
 maskLong = maskLen2long(prefix);
 isPrefixInput = true;
 } else {
 resultDiv.innerText = 'Error: Invalid Subnet Mask or Prefix Length';
 return;
 }

 // Number of addresses
 // Note: JS bitwise operators are 32-bit, but Math.pow handles up to 2^53. Total addresses for /0 is 2^32.
 const totalAddresses = prefix === 0 ? 4294967296 : (prefix === 32 ? 1 : Math.pow(2, 32 - prefix));
 
 let usableCount = 0;
 if (prefix &lt;= 30) {
 usableCount = totalAddresses - 2;
 } else if (prefix === 31) {
 usableCount = 2;
 } else if (prefix === 32) {
 usableCount = 1;
 }

 let output = '';
 if (isPrefixInput) {
 output += `Subnet Mask : ${long2ip(maskLong)}\n`;
 } else {
 output += `Mask Length : ${prefix} bits\n`;
 }
 
 output += `Total Addresses : ${totalAddresses}\n`;
 output += `Usable Hosts : ${usableCount}`;

 resultDiv.innerText = output;
}

function calcFeature3() {
 const input = document.getElementById('ipInput3').value.trim();
 const resultDiv = document.getElementById('result3');
 resultDiv.style.display = 'block';

 if (!isValidIP(input)) {
 resultDiv.innerText = 'Error: Invalid Subnet Mask';
 return;
 }

 const maskLong = ip2long(input);
 const wildcardLong = (~maskLong) &gt;&gt;&gt; 0;

 const output = [
 `Wildcard Mask : ${long2ip(wildcardLong)}`,
 `Binary Format : ${long2binary(wildcardLong)}`
 ].join('\n');

 resultDiv.innerText = output;
}

function rangeToSubnets(startIpLong, endIpLong) {
 let subnets = [];
 let current = startIpLong;
 while (current &lt;= endIpLong) {
 let maxPrefix = 32;
 while (maxPrefix &gt; 0) {
 let pLen = maxPrefix - 1;
 let mask = maskLen2long(pLen);
 let network = (current &amp; mask) &gt;&gt;&gt; 0;
 let broadcast = (network | (~mask)) &gt;&gt;&gt; 0;
 // The subnet must start exactly at 'current', and must end within the range
 if (network === current &amp;&amp; broadcast &lt;= endIpLong) {
 maxPrefix = pLen;
 } else {
 break;
 }
 }
 subnets.push(long2ip(current) + '/' + maxPrefix);
 
 // Move current to the next IP after the chosen subnet
 let mask = maskLen2long(maxPrefix);
 let broadcast = (current | (~mask)) &gt;&gt;&gt; 0;
 
 // Prevent infinite loop on 255.255.255.255
 if (broadcast === 4294967295) {
 break;
 }
 current = broadcast + 1;
 }
 return subnets;
}

function calcFeature4() {
 const input = document.getElementById('ipInput4').value.trim();
 const resultDiv = document.getElementById('result4');
 resultDiv.style.display = 'block';

 const parts = input.split('-');
 if (parts.length !== 2) {
 resultDiv.innerText = 'Error: Please enter a valid IP range separated by a hyphen (e.g., 192.168.1.0-192.168.1.65)';
 return;
 }

 const startIp = parts[0].trim();
 const endIp = parts[1].trim();

 if (!isValidIP(startIp) || !isValidIP(endIp)) {
 resultDiv.innerText = 'Error: Invalid IP address format in range';
 return;
 }

 const startLong = ip2long(startIp);
 const endLong = ip2long(endIp);

 if (startLong &gt; endLong) {
 resultDiv.innerText = 'Error: Start IP must be less than or equal to End IP';
 return;
 }

 const subnets = rangeToSubnets(startLong, endLong);
 
 resultDiv.innerText = subnets.join(', ');
}
&lt;/script&gt;</description></item><item><title>Public IP Lookup</title><link>http://jony.ch/docs/tools/ip-lookup/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>http://jony.ch/docs/tools/ip-lookup/</guid><description>&lt;h1 id="public-ip-lookup"&gt;Public IP Lookup&lt;a class="anchor" href="#public-ip-lookup"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;This tool displays your current public IP address and allows you to query any IP address to find its location, AS number, ISP, and other details.&lt;/p&gt;
&lt;div style="margin-top: 2rem; padding: 2rem; border: 1px solid var(--gray-200); border-radius: 8px; background-color: var(--gray-100);"&gt;
 &lt;!-- Feature 1: Current IP --&gt;
 &lt;div style="margin-bottom: 2rem; padding-bottom: 2rem; border-bottom: 1px solid #ccc;"&gt;
 &lt;h3 style="margin-top: 0;"&gt;1. Your Current Public IP&lt;/h3&gt;
 &lt;div id="currentIpResult" style="padding: 1rem; background-color: #fff; border: 1px dashed #ccc; border-radius: 4px; font-family: monospace; white-space: pre-wrap; min-height: 1.5rem;"&gt;Loading your IP information...&lt;/div&gt;
 &lt;/div&gt;
 &lt;!-- Feature 2: IP Lookup --&gt;
 &lt;div&gt;
 &lt;h3 style="margin-top: 0;"&gt;2. IP Lookup&lt;/h3&gt;
 &lt;label style="display: block; font-weight: bold; margin-bottom: 0.5rem;"&gt;Enter IP Address:&lt;/label&gt;
 &lt;div style="display: flex; gap: 1rem;"&gt;
 &lt;input type="text" id="ipInput" placeholder="e.g., 8.8.8.8" style="flex: 1; padding: 0.5rem; border: 1px solid #ccc; border-radius: 4px;" /&gt;
 &lt;button onclick="lookupIp()" style="background-color: #CF0A2C; color: white; border: none; padding: 0.5rem 1rem; border-radius: 4px; cursor: pointer; font-weight: bold;"&gt;Lookup&lt;/button&gt;
 &lt;/div&gt;
 &lt;div id="lookupIpResult" style="margin-top: 1rem; padding: 1rem; background-color: #fff; border: 1px dashed #ccc; border-radius: 4px; font-family: monospace; white-space: pre-wrap; min-height: 1.5rem; display: none;"&gt;&lt;/div&gt;
 &lt;/div&gt;
&lt;/div&gt;
&lt;script&gt;
function formatIpData(data) {
 if (!data.success) {
 return `Error: ${data.message}`;
 }
 
 return [
 `IP : ${data.ip}`,
 `Type : ${data.type}`,
 `Country : ${data.country} (${data.country_code})`,
 `Region : ${data.region}`,
 `City : ${data.city}`,
 `Latitude : ${data.latitude}`,
 `Longitude : ${data.longitude}`,
 `ASN : ${data.connection.asn}`,
 `ISP / Org : ${data.connection.org} / ${data.connection.isp}`,
 `Domain : ${data.connection.domain}`,
 `Timezone : ${data.timezone.id} (UTC ${data.timezone.utc})`
 ].join('\n');
}

// Fetch current IP on load
window.addEventListener('DOMContentLoaded', () =&gt; {
 fetch('https://ipwho.is/')
 .then(response =&gt; response.json())
 .then(data =&gt; {
 document.getElementById('currentIpResult').innerText = formatIpData(data);
 })
 .catch(error =&gt; {
 document.getElementById('currentIpResult').innerText = 'Error fetching IP information: ' + error.message;
 });
});

function lookupIp() {
 const ip = document.getElementById('ipInput').value.trim();
 const resultDiv = document.getElementById('lookupIpResult');
 resultDiv.style.display = 'block';
 
 if (!ip) {
 resultDiv.innerText = 'Please enter an IP address.';
 return;
 }

 resultDiv.innerText = 'Searching...';

 fetch(`https://ipwho.is/${ip}`)
 .then(response =&gt; response.json())
 .then(data =&gt; {
 resultDiv.innerText = formatIpData(data);
 })
 .catch(error =&gt; {
 resultDiv.innerText = 'Error fetching IP information: ' + error.message;
 });
}
&lt;/script&gt;</description></item><item><title>Batch Config Generator</title><link>http://jony.ch/docs/tools/batch-generator/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>http://jony.ch/docs/tools/batch-generator/</guid><description>&lt;h1 id="batch-config-generator"&gt;Batch Config Generator&lt;a class="anchor" href="#batch-config-generator"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;This tool allows you to automatically generate repetitive configuration scripts or JSON based on a template.
Define variables in your template using the &lt;code&gt;{{{VariableName}}}&lt;/code&gt; syntax.&lt;/p&gt;
&lt;style&gt;
.generator-container {
 margin-top: 2rem;
 padding: 2rem;
 border: 1px solid var(--gray-200);
 border-radius: 8px;
 background-color: var(--gray-100);
}
.form-group {
 margin-bottom: 1.5rem;
}
.form-group label {
 display: block;
 font-weight: bold;
 margin-bottom: 0.5rem;
}
textarea {
 width: 100%;
 padding: 0.75rem;
 border: 1px solid #ccc;
 border-radius: 4px;
 font-family: monospace;
 font-size: 0.9rem;
 box-sizing: border-box;
}
input[type="number"] {
 width: 100%;
 padding: 0.5rem;
 border: 1px solid #ccc;
 border-radius: 4px;
 box-sizing: border-box;
}
.btn {
 background-color: #CF0A2C;
 color: white;
 border: none;
 padding: 0.75rem 1.5rem;
 border-radius: 4px;
 cursor: pointer;
 font-weight: bold;
 display: inline-block;
}
.btn-outline {
 background-color: transparent;
 color: #CF0A2C;
 border: 1px solid #CF0A2C;
 padding: 0.5rem 1rem;
 border-radius: 4px;
 cursor: pointer;
 font-weight: bold;
 display: inline-block;
}
.btn:hover, .btn-outline:hover {
 opacity: 0.8;
}
.var-list-container {
 display: grid;
 grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
 gap: 1rem;
 margin-top: 1rem;
}
.var-column h4 {
 margin-top: 0;
 margin-bottom: 0.5rem;
}
.alert {
 padding: 1rem;
 background-color: #fee2e2;
 border: 1px solid #ef4444;
 color: #b91c1c;
 border-radius: 4px;
 margin-top: 1rem;
 display: none;
}
&lt;/style&gt;
&lt;div class="generator-container"&gt;
 &lt;div class="form-group"&gt;
 &lt;label&gt;1. Template&lt;/label&gt;
 &lt;p style="margin-top: 0; font-size: 0.9em; color: #666;"&gt;Use &lt;code&gt;{{{VariableName}}}&lt;/code&gt; to define variables. Example provided below.&lt;/p&gt;</description></item><item><title>Configuration Reader</title><link>http://jony.ch/docs/tools/config-reader/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>http://jony.ch/docs/tools/config-reader/</guid><description>&lt;h1 id="configuration-reader"&gt;Configuration Reader&lt;a class="anchor" href="#configuration-reader"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Interactive Monaco Editor for Network Device Configurations. Select vendor syntax (Huawei VRP, Cisco IOS, Juniper JunOS, Arista EOS), automatically fold configurations by category (e.g., matching 2-word prefixes like &lt;code&gt;authentication-profile name&lt;/code&gt; or indented blocks), and use the interactive &lt;strong&gt;Config Index&lt;/strong&gt; sidebar to search sections, inspect &lt;strong&gt;VPN Instance&lt;/strong&gt;, &lt;strong&gt;Interface&lt;/strong&gt;, &lt;strong&gt;AAA Scheme&lt;/strong&gt;, and &lt;strong&gt;Profile References&lt;/strong&gt; with full definition blocks, and maximize to browser full window with saved state.&lt;/p&gt;
&lt;style&gt;
 .cr-container {
 margin-top: 1rem;
 font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
 }
 /* Browser Full Window Mode */
 .cr-container.cr-full-window {
 position: fixed !important;
 top: 0 !important;
 left: 0 !important;
 right: 0 !important;
 bottom: 0 !important;
 width: 100vw !important;
 height: 100vh !important;
 z-index: 99999 !important;
 margin: 0 !important;
 padding: 0 !important;
 background: #ffffff;
 border-radius: 0 !important;
 }
 .cr-container.cr-full-window .cr-toolbar {
 border-radius: 0 !important;
 }
 .cr-container.cr-full-window .cr-main-layout {
 height: calc(100vh - 58px) !important;
 border-radius: 0 !important;
 }
 .cr-toolbar {
 display: flex;
 justify-content: space-between;
 align-items: center;
 flex-wrap: wrap;
 gap: 0.75rem;
 padding: 0.85rem 1rem;
 background: #f8fafc;
 border: 1px solid #cbd5e1;
 border-radius: 10px 10px 0 0;
 }
 .cr-toolbar-group {
 display: flex;
 align-items: center;
 gap: 0.5rem;
 flex-wrap: wrap;
 }
 .cr-label {
 font-size: 0.85rem;
 font-weight: 600;
 color: #475569;
 }
 .cr-select {
 padding: 0.45rem 0.75rem;
 border: 1px solid #cbd5e1;
 border-radius: 6px;
 font-size: 0.875rem;
 background-color: #ffffff;
 color: #0f172a;
 outline: none;
 cursor: pointer;
 }
 .cr-select:focus {
 border-color: #2563eb;
 box-shadow: 0 0 0 2px rgba(37, 99, 235, 0.15);
 }
 .cr-find-container {
 position: relative;
 display: inline-flex;
 align-items: center;
 }
 .cr-search-input {
 padding: 0.45rem 0.75rem;
 border: 1px solid #cbd5e1;
 border-radius: 6px;
 font-size: 0.85rem;
 background-color: #ffffff;
 color: #0f172a;
 outline: none;
 width: 170px;
 transition: all 0.15s ease;
 }
 .cr-search-input:focus {
 border-color: #2563eb;
 box-shadow: 0 0 0 2px rgba(37, 99, 235, 0.15);
 width: 220px;
 }
 .cr-find-dropdown {
 display: none;
 position: absolute;
 top: 100%;
 left: 0;
 width: 340px;
 max-height: 300px;
 overflow-y: auto;
 background: #ffffff;
 border: 1px solid #cbd5e1;
 border-radius: 8px;
 box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
 margin-top: 4px;
 z-index: 9999;
 padding: 4px 0;
 }
 .cr-find-dropdown.active {
 display: block;
 }
 .cr-find-item {
 display: flex;
 align-items: center;
 justify-content: space-between;
 padding: 6px 12px;
 font-size: 0.82rem;
 color: #334155;
 cursor: pointer;
 border-bottom: 1px solid #f1f5f9;
 transition: background 0.15s ease;
 }
 .cr-find-item:hover {
 background: #eff6ff;
 color: #1d4ed8;
 }
 .cr-find-line {
 font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
 font-size: 0.72rem;
 color: #2563eb;
 background: #dbeafe;
 padding: 1px 6px;
 border-radius: 4px;
 margin-right: 8px;
 flex-shrink: 0;
 }
 .cr-find-text {
 font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
 white-space: nowrap;
 overflow: hidden;
 text-overflow: ellipsis;
 flex: 1;
 }
 .cr-find-empty {
 padding: 12px;
 font-size: 0.82rem;
 color: #94a3b8;
 text-align: center;
 }
 .cr-btn {
 display: inline-flex;
 align-items: center;
 gap: 0.35rem;
 padding: 0.45rem 0.85rem;
 font-size: 0.85rem;
 font-weight: 600;
 border-radius: 6px;
 border: 1px solid #cbd5e1;
 background: #ffffff;
 color: #334155;
 cursor: pointer;
 transition: all 0.15s ease;
 }
 .cr-btn:hover {
 background: #f1f5f9;
 color: #0f172a;
 }
 .cr-btn-primary {
 background: #2563eb;
 color: #ffffff;
 border-color: #2563eb;
 }
 .cr-btn-primary:hover {
 background: #1d4ed8;
 color: #ffffff;
 }
 .cr-btn-active {
 background: #dbeafe !important;
 color: #1d4ed8 !important;
 border-color: #93c5fd !important;
 }
 /* 8 Custom Highlight Background Colors */
 .cr-hl-yellow { background-color: rgba(254, 240, 138, 0.7) !important; border-radius: 2px; }
 .cr-hl-green { background-color: rgba(187, 247, 208, 0.7) !important; border-radius: 2px; }
 .cr-hl-cyan { background-color: rgba(165, 243, 252, 0.7) !important; border-radius: 2px; }
 .cr-hl-blue { background-color: rgba(191, 219, 254, 0.7) !important; border-radius: 2px; }
 .cr-hl-purple { background-color: rgba(233, 213, 255, 0.7) !important; border-radius: 2px; }
 .cr-hl-pink { background-color: rgba(251, 207, 232, 0.7) !important; border-radius: 2px; }
 .cr-hl-orange { background-color: rgba(254, 215, 170, 0.7) !important; border-radius: 2px; }
 .cr-hl-red { background-color: rgba(254, 202, 202, 0.7) !important; border-radius: 2px; }
 /* Custom Context Menu */
 .cr-context-menu {
 display: none;
 position: fixed;
 z-index: 100002;
 background: #ffffff;
 border: 1px solid #cbd5e1;
 border-radius: 8px;
 box-shadow: 0 10px 25px -5px rgba(0,0,0,0.12), 0 8px 10px -6px rgba(0,0,0,0.06);
 min-width: 190px;
 padding: 4px 0;
 font-size: 0.85rem;
 font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
 }
 .cr-context-menu.active {
 display: block;
 }
 .cr-ctx-item {
 display: flex;
 align-items: center;
 justify-content: space-between;
 padding: 7px 12px;
 color: #334155;
 cursor: pointer;
 position: relative;
 transition: background 0.15s ease;
 }
 .cr-ctx-item:hover {
 background: #eff6ff;
 color: #1d4ed8;
 }
 .cr-ctx-title-group {
 display: flex;
 align-items: center;
 justify-content: space-between;
 width: 100%;
 }
 .cr-ctx-divider {
 height: 1px;
 background: #e2e8f0;
 margin: 4px 0;
 }
 /* Submenu for Highlight Colors */
 .cr-ctx-submenu {
 display: none;
 position: absolute;
 top: -4px;
 left: 100%;
 background: #ffffff;
 border: 1px solid #cbd5e1;
 border-radius: 8px;
 box-shadow: 0 10px 25px -5px rgba(0,0,0,0.12);
 min-width: 150px;
 padding: 4px 0;
 }
 .cr-ctx-has-sub:hover .cr-ctx-submenu {
 display: block;
 }
 /* Main Split Layout: Sidebar + Monaco Editor */
 .cr-main-layout {
 display: flex;
 border: 1px solid #cbd5e1;
 border-top: none;
 border-radius: 0 0 10px 10px;
 overflow: hidden;
 height: 680px;
 background: #ffffff;
 box-shadow: 0 4px 12px rgba(0,0,0,0.04);
 position: relative;
 }
 /* Sidebar Styles (Default Visible) */
 .cr-sidebar {
 width: 290px;
 flex-shrink: 0;
 border-right: 1px solid #e2e8f0;
 background: #f8fafc;
 display: flex;
 flex-direction: column;
 transition: width 0.2s ease;
 }
 .cr-sidebar.collapsed {
 display: none !important;
 width: 0 !important;
 margin-left: 0 !important;
 overflow: hidden !important;
 border-right: none !important;
 }
 .cr-sidebar-header {
 display: flex;
 align-items: center;
 justify-content: space-between;
 padding: 0.75rem 0.85rem;
 background: #f1f5f9;
 border-bottom: 1px solid #e2e8f0;
 font-size: 0.875rem;
 font-weight: 700;
 color: #1e293b;
 }
 .cr-sidebar-title {
 display: flex;
 align-items: center;
 gap: 0.4rem;
 }
 .cr-badge {
 font-size: 0.75rem;
 font-weight: 600;
 background: #2563eb;
 color: #ffffff;
 padding: 1px 7px;
 border-radius: 12px;
 }
 .cr-sidebar-search {
 padding: 0.6rem 0.85rem;
 border-bottom: 1px solid #e2e8f0;
 background: #ffffff;
 }
 .cr-sidebar-search input {
 width: 100%;
 padding: 0.4rem 0.65rem;
 font-size: 0.82rem;
 border: 1px solid #cbd5e1;
 border-radius: 6px;
 outline: none;
 box-sizing: border-box;
 }
 .cr-sidebar-search input:focus {
 border-color: #2563eb;
 box-shadow: 0 0 0 2px rgba(37, 99, 235, 0.15);
 }
 .cr-index-list {
 flex: 1;
 overflow-y: auto;
 padding: 0.35rem 0;
 }
 .cr-index-item {
 display: flex;
 align-items: center;
 justify-content: space-between;
 padding: 0.45rem 0.85rem;
 border-bottom: 1px solid #f1f5f9;
 cursor: pointer;
 font-size: 0.82rem;
 color: #334155;
 transition: background 0.15s ease, color 0.15s ease;
 }
 .cr-index-item:hover {
 background: #e2e8f0;
 color: #0f172a;
 }
 .cr-index-item.active {
 background: #eff6ff;
 color: #1d4ed8;
 font-weight: 600;
 border-left: 3px solid #2563eb;
 }
 .cr-index-left {
 display: flex;
 align-items: center;
 gap: 0.4rem;
 min-width: 0;
 flex: 1;
 }
 .cr-index-icon {
 font-size: 0.85rem;
 flex-shrink: 0;
 }
 .cr-index-title {
 white-space: nowrap;
 overflow: hidden;
 text-overflow: ellipsis;
 }
 .cr-index-line {
 font-size: 0.72rem;
 color: #64748b;
 background: #e2e8f0;
 padding: 2px 6px;
 border-radius: 4px;
 font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
 flex-shrink: 0;
 margin-left: 0.4rem;
 }
 .cr-index-count {
 font-size: 0.7rem;
 font-weight: 600;
 color: #2563eb;
 background: #dbeafe;
 border: 1px solid #bfdbfe;
 padding: 0 5px;
 border-radius: 10px;
 flex-shrink: 0;
 }
 .cr-vpn-ref-badge {
 font-size: 0.7rem;
 font-weight: 600;
 color: #059669;
 background: #d1fae5;
 border: 1px solid #a7f3d0;
 padding: 1px 6px;
 border-radius: 10px;
 margin-left: 4px;
 cursor: pointer;
 transition: all 0.15s ease;
 flex-shrink: 0;
 }
 .cr-vpn-ref-badge:hover {
 background: #10b981;
 color: #ffffff;
 }
 .cr-if-ref-badge {
 font-size: 0.7rem;
 font-weight: 600;
 color: #d97706;
 background: #fef3c7;
 border: 1px solid #fde68a;
 padding: 1px 6px;
 border-radius: 10px;
 margin-left: 4px;
 cursor: pointer;
 transition: all 0.15s ease;
 flex-shrink: 0;
 }
 .cr-if-ref-badge:hover {
 background: #f59e0b;
 color: #ffffff;
 }
 .cr-prof-ref-badge {
 font-size: 0.7rem;
 font-weight: 600;
 color: #7c3aed;
 background: #ede9fe;
 border: 1px solid #ddd6fe;
 padding: 1px 6px;
 border-radius: 10px;
 margin-left: 4px;
 cursor: pointer;
 transition: all 0.15s ease;
 flex-shrink: 0;
 }
 .cr-prof-ref-badge:hover {
 background: #8b5cf6;
 color: #ffffff;
 }
 .cr-index-empty {
 padding: 2rem 1rem;
 text-align: center;
 font-size: 0.85rem;
 color: #94a3b8;
 }
 .cr-editor-frame {
 flex: 1;
 height: 100%;
 position: relative;
 overflow: hidden;
 }
 #monacoContainer {
 width: 100%;
 height: 100%;
 }
 /* Custom Monaco Underlines for Interactive Symbols */
 .monaco-vpn-underline {
 border-bottom: 1.5px dashed #2563eb !important;
 cursor: pointer;
 }
 .monaco-interface-underline {
 border-bottom: 1.5px dashed #d97706 !important;
 cursor: pointer;
 }
 .monaco-profile-underline {
 border-bottom: 1.5px dashed #8b5cf6 !important;
 cursor: pointer;
 }
 /* Custom Monaco Cipher Highlight */
 .monaco-cipher-highlight {
 background-color: rgba(239, 68, 68, 0.18) !important;
 border: 1px dashed #ef4444 !important;
 border-radius: 3px;
 }
 /* Reference Modal Overlay */
 .cr-modal-overlay {
 display: none;
 position: fixed;
 top: 0;
 left: 0;
 right: 0;
 bottom: 0;
 background: rgba(15, 23, 42, 0.5);
 backdrop-filter: blur(3px);
 z-index: 100000;
 align-items: center;
 justify-content: center;
 }
 .cr-modal-overlay.active {
 display: flex;
 }
 .cr-modal-card {
 background: #ffffff;
 border-radius: 12px;
 width: 90%;
 max-width: 720px;
 max-height: 85vh;
 display: flex;
 flex-direction: column;
 box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
 overflow: hidden;
 }
 .cr-modal-header {
 display: flex;
 align-items: center;
 justify-content: space-between;
 padding: 1rem 1.25rem;
 background: #f8fafc;
 border-bottom: 1px solid #e2e8f0;
 font-weight: 700;
 color: #0f172a;
 }
 .cr-modal-close {
 background: none;
 border: none;
 font-size: 1.5rem;
 cursor: pointer;
 color: #64748b;
 line-height: 1;
 }
 .cr-modal-body {
 padding: 1.25rem;
 overflow-y: auto;
 font-size: 0.875rem;
 }
 .cr-def-block-card {
 margin-bottom: 1.25rem;
 background: #eff6ff;
 border: 1px solid #bfdbfe;
 border-radius: 8px;
 padding: 0.85rem 1rem;
 }
 .cr-def-block-title {
 font-weight: 700;
 color: #1d4ed8;
 margin-bottom: 0.4rem;
 display: flex;
 align-items: center;
 justify-content: space-between;
 }
 .cr-vpn-ref-group {
 margin-bottom: 1rem;
 background: #f8fafc;
 border: 1px solid #e2e8f0;
 border-radius: 8px;
 padding: 0.75rem 1rem;
 }
 .cr-vpn-ref-header {
 font-weight: 600;
 color: #2563eb;
 margin-bottom: 0.4rem;
 display: flex;
 align-items: center;
 justify-content: space-between;
 }
 .cr-vpn-ref-code {
 font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
 font-size: 0.82rem;
 background: #ffffff;
 border: 1px solid #cbd5e1;
 padding: 0.45rem 0.75rem;
 border-radius: 6px;
 color: #334155;
 cursor: pointer;
 white-space: pre-wrap;
 word-break: break-all;
 transition: all 0.15s ease;
 }
 .cr-vpn-ref-code:hover {
 background: #eff6ff;
 border-color: #2563eb;
 color: #1d4ed8;
 }
 /* Dark Theme Adjustments */
 .cr-dark .cr-toolbar {
 background: #1e293b;
 border-color: #334155;
 }
 .cr-dark .cr-label {
 color: #94a3b8;
 }
 .cr-dark .cr-select, .cr-dark .cr-btn {
 background: #0f172a;
 color: #f1f5f9;
 border-color: #334155;
 }
 .cr-dark .cr-btn:hover {
 background: #1e293b;
 }
 .cr-dark .cr-btn-active {
 background: #1e3a8a !important;
 color: #93c5fd !important;
 border-color: #3b82f6 !important;
 }
 .cr-dark .cr-hl-yellow { background-color: rgba(161, 98, 7, 0.7) !important; color: #fef08a !important; }
 .cr-dark .cr-hl-green { background-color: rgba(21, 128, 61, 0.7) !important; color: #bbf7d0 !important; }
 .cr-dark .cr-hl-cyan { background-color: rgba(14, 116, 144, 0.7) !important; color: #a5f3fc !important; }
 .cr-dark .cr-hl-blue { background-color: rgba(29, 78, 216, 0.7) !important; color: #bfdbfe !important; }
 .cr-dark .cr-hl-purple { background-color: rgba(126, 34, 206, 0.7) !important; color: #e9d5ff !important; }
 .cr-dark .cr-hl-pink { background-color: rgba(190, 24, 93, 0.7) !important; color: #fbcfe8 !important; }
 .cr-dark .cr-hl-orange { background-color: rgba(194, 65, 12, 0.7) !important; color: #fed7aa !important; }
 .cr-dark .cr-hl-red { background-color: rgba(185, 28, 28, 0.7) !important; color: #fecaca !important; }
 .cr-dark .cr-search-input {
 background: #0f172a;
 color: #f1f5f9;
 border-color: #334155;
 }
 .cr-dark .cr-find-dropdown {
 background: #0f172a;
 border-color: #334155;
 }
 .cr-dark .cr-find-item {
 color: #cbd5e1;
 border-bottom-color: #1e293b;
 }
 .cr-dark .cr-find-item:hover {
 background: #1e3a8a;
 color: #93c5fd;
 }
 .cr-dark .cr-context-menu, .cr-dark .cr-ctx-submenu {
 background: #0f172a;
 border-color: #334155;
 }
 .cr-dark .cr-ctx-item {
 color: #cbd5e1;
 }
 .cr-dark .cr-ctx-item:hover {
 background: #1e3a8a;
 color: #93c5fd;
 }
 .cr-dark .cr-ctx-divider {
 background: #334155;
 }
 .cr-dark .cr-main-layout {
 border-color: #334155;
 background: #1e1e1e;
 }
 .cr-dark .cr-sidebar {
 background: #0f172a;
 border-color: #334155;
 }
 .cr-dark .cr-sidebar-header {
 background: #1e293b;
 border-color: #334155;
 color: #f1f5f9;
 }
 .cr-dark .cr-sidebar-search {
 background: #0f172a;
 border-color: #334155;
 }
 .cr-dark .cr-sidebar-search input {
 background: #1e293b;
 border-color: #334155;
 color: #f1f5f9;
 }
 .cr-dark .cr-index-item {
 border-bottom-color: #1e293b;
 color: #cbd5e1;
 }
 .cr-dark .cr-index-item:hover {
 background: #1e293b;
 color: #ffffff;
 }
 .cr-dark .cr-index-item.active {
 background: #1e3a8a;
 color: #93c5fd;
 border-left-color: #3b82f6;
 }
 .cr-dark .cr-index-line {
 background: #334155;
 color: #94a3b8;
 }
 .cr-dark.cr-full-window {
 background: #1e1e1e;
 }
 .cr-dark .cr-modal-card {
 background: #0f172a;
 color: #f1f5f9;
 border: 1px solid #334155;
 }
 .cr-dark .cr-modal-header {
 background: #1e293b;
 border-color: #334155;
 color: #f1f5f9;
 }
 .cr-dark .cr-def-block-card {
 background: #1e3a8a;
 border-color: #3b82f6;
 }
 .cr-dark .cr-def-block-title {
 color: #93c5fd;
 }
 .cr-dark .cr-vpn-ref-group {
 background: #1e293b;
 border-color: #334155;
 }
 .cr-dark .cr-vpn-ref-code {
 background: #0f172a;
 border-color: #334155;
 color: #cbd5e1;
 }
&lt;/style&gt;
&lt;div class="cr-container" id="crContainer"&gt;
 &lt;!-- Toolbar --&gt;
 &lt;div class="cr-toolbar"&gt;
 &lt;div class="cr-toolbar-group"&gt;
 &lt;button class="cr-btn" id="crSidebarToggleBtn" onclick="toggleSidebar()"&gt;📑 Hide Index&lt;/button&gt;
 &lt;button class="cr-btn" id="fullWindowBtn" onclick="toggleFullWindow()"&gt;⛶ Full Window&lt;/button&gt;
 &lt;button class="cr-btn" id="refToggleBtn" onclick="toggleReferenceLinks()"&gt;🔗 Show References&lt;/button&gt;
 &lt;div class="cr-find-container"&gt;
 &lt;span class="cr-label" style="margin-left: 0.4rem;"&gt;Find:&lt;/span&gt;
 &lt;input type="text" id="configFindInput" class="cr-search-input" placeholder="🔍 Find in config..." oninput="onConfigFindChange()" onfocus="onConfigFindFocus()" onblur="onConfigFindBlur()"&gt;
 &lt;div id="configFindDropdown" class="cr-find-dropdown"&gt;&lt;/div&gt;
 &lt;/div&gt;
 &lt;span class="cr-label" style="margin-left: 0.4rem;"&gt;Language:&lt;/span&gt;
 &lt;select id="vendorSelect" class="cr-select" onchange="onVendorChange()"&gt;
 &lt;option value="huawei"&gt;Huawei VRP&lt;/option&gt;
 &lt;option value="cisco"&gt;Cisco IOS / NX-OS&lt;/option&gt;
 &lt;option value="juniper"&gt;Juniper JunOS&lt;/option&gt;
 &lt;option value="arista"&gt;Arista EOS&lt;/option&gt;
 &lt;/select&gt;
 &lt;span class="cr-label" style="margin-left: 0.4rem;"&gt;Theme:&lt;/span&gt;
 &lt;select id="themeSelect" class="cr-select" onchange="onThemeChange()"&gt;
 &lt;option value="vs"&gt;Light&lt;/option&gt;
 &lt;option value="vs-dark"&gt;Dark&lt;/option&gt;
 &lt;/select&gt;
 &lt;/div&gt;
 &lt;div class="cr-toolbar-group"&gt;
 &lt;button class="cr-btn cr-btn-primary" onclick="foldAll()"&gt;↔️ Fold All&lt;/button&gt;
 &lt;button class="cr-btn cr-btn-primary" onclick="unfoldAll()"&gt;↕️ Unfold All&lt;/button&gt;
 &lt;button class="cr-btn" onclick="copyConfig()"&gt;📋 Copy&lt;/button&gt;
 &lt;button class="cr-btn" onclick="downloadConfig()"&gt;💾 Download&lt;/button&gt;
 &lt;/div&gt;
 &lt;/div&gt;
 &lt;!-- Main Split View Layout --&gt;
 &lt;div class="cr-main-layout"&gt;
 &lt;!-- Config Index Sidebar (Default Visible) --&gt;
 &lt;div class="cr-sidebar" id="crSidebar"&gt;
 &lt;div class="cr-sidebar-header"&gt;
 &lt;div class="cr-sidebar-title"&gt;
 &lt;span&gt;📑 Config Index&lt;/span&gt;
 &lt;span class="cr-badge" id="indexCountBadge"&gt;0&lt;/span&gt;
 &lt;/div&gt;
 &lt;/div&gt;
 &lt;div class="cr-sidebar-search"&gt;
 &lt;input type="text" id="indexSearchInput" placeholder="Search index..." oninput="filterIndexList()"&gt;
 &lt;/div&gt;
 &lt;div class="cr-index-list" id="indexList"&gt;
 &lt;!-- Dynamically rendered index items --&gt;
 &lt;/div&gt;
 &lt;/div&gt;
 &lt;!-- Monaco Editor Container --&gt;
 &lt;div class="cr-editor-frame"&gt;
 &lt;div id="monacoContainer"&gt;&lt;/div&gt;
 &lt;/div&gt;
 &lt;/div&gt;
&lt;/div&gt;
&lt;!-- Reference Details Modal --&gt;
&lt;div id="crVpnModal" class="cr-modal-overlay" onclick="closeVpnModal(event)"&gt;
 &lt;div class="cr-modal-card" onclick="event.stopPropagation()"&gt;
 &lt;div class="cr-modal-header"&gt;
 &lt;span id="crVpnModalTitle"&gt;🔒 Reference Details&lt;/span&gt;
 &lt;button class="cr-modal-close" onclick="closeVpnModal()"&gt;×&lt;/button&gt;
 &lt;/div&gt;
 &lt;div class="cr-modal-body" id="crVpnModalBody"&gt;
 &lt;!-- Dynamically filled reference details --&gt;
 &lt;/div&gt;
 &lt;/div&gt;
&lt;/div&gt;
&lt;!-- Custom Context Menu for Selection Highlight &amp; Search --&gt;
&lt;div id="crContextMenu" class="cr-context-menu"&gt;
 &lt;div class="cr-ctx-item" onclick="execCopyFromCtx()"&gt;
 &lt;span&gt;📋 Copy Text&lt;/span&gt;
 &lt;/div&gt;
 &lt;div class="cr-ctx-item" id="crCtxSearchItem" onclick="execSearchFromCtx()"&gt;
 &lt;span&gt;🔍 Search Text&lt;/span&gt;
 &lt;/div&gt;
 &lt;div class="cr-ctx-divider"&gt;&lt;/div&gt;
 &lt;div class="cr-ctx-item cr-ctx-has-sub"&gt;
 &lt;div class="cr-ctx-title-group"&gt;
 &lt;span&gt;🎨 Highlight Text&lt;/span&gt;
 &lt;span style="font-size: 0.7rem; color: #64748b;"&gt;▶&lt;/span&gt;
 &lt;/div&gt;
 &lt;div class="cr-ctx-submenu"&gt;
 &lt;div class="cr-ctx-item" onclick="applyHighlightFromCtx('cr-hl-yellow')"&gt;&lt;span&gt;🟡 Yellow&lt;/span&gt;&lt;/div&gt;
 &lt;div class="cr-ctx-item" onclick="applyHighlightFromCtx('cr-hl-green')"&gt;&lt;span&gt;🟢 Green&lt;/span&gt;&lt;/div&gt;
 &lt;div class="cr-ctx-item" onclick="applyHighlightFromCtx('cr-hl-cyan')"&gt;&lt;span&gt;🩵 Cyan&lt;/span&gt;&lt;/div&gt;
 &lt;div class="cr-ctx-item" onclick="applyHighlightFromCtx('cr-hl-blue')"&gt;&lt;span&gt;🟦 Blue&lt;/span&gt;&lt;/div&gt;
 &lt;div class="cr-ctx-item" onclick="applyHighlightFromCtx('cr-hl-purple')"&gt;&lt;span&gt;🟣 Purple&lt;/span&gt;&lt;/div&gt;
 &lt;div class="cr-ctx-item" onclick="applyHighlightFromCtx('cr-hl-pink')"&gt;&lt;span&gt;🩷 Pink&lt;/span&gt;&lt;/div&gt;
 &lt;div class="cr-ctx-item" onclick="applyHighlightFromCtx('cr-hl-orange')"&gt;&lt;span&gt;🟧 Orange&lt;/span&gt;&lt;/div&gt;
 &lt;div class="cr-ctx-item" onclick="applyHighlightFromCtx('cr-hl-red')"&gt;&lt;span&gt;🔴 Red&lt;/span&gt;&lt;/div&gt;
 &lt;/div&gt;
 &lt;/div&gt;
 &lt;div class="cr-ctx-item" onclick="clearHighlightFromCtx()"&gt;
 &lt;span&gt;❌ Clear Highlight&lt;/span&gt;
 &lt;/div&gt;
&lt;/div&gt;
&lt;!-- RequireJS &amp; Monaco Loader --&gt;
&lt;script src="https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.45.0/min/vs/loader.min.js"&gt;&lt;/script&gt;
&lt;script&gt;
// Exact Huawei default sample configuration requested by user
const HUAWEI_SAMPLE = `[V300R024C00SPC100]
#
 drop illegal-mac alarm
#
ipv6
#
authentication-profile name default_authen_profile
#
dns resolve 
#
dhcp enable
#
ip vpn-instance vpn1
 ipv4-family
 route-distinguisher 1111:1111
 vpn-target 11:11 export-extcommunity
 vpn-target 11:11 import-extcommunity
#
radius-server template default
#
pki realm default
 certificate-check none
#
free-rule-template name default_free_rule
#
portal-access-profile name portal_access_profile
#
aaa
 authentication-scheme default
 authentication-mode local
 authentication-scheme radius
 authentication-mode radius
 authorization-scheme default
 authorization-mode local
 accounting-scheme default
 accounting-mode none
 local-aaa-user password policy administrator
 domain default
 authentication-scheme default
 accounting-scheme default
 radius-server default
 domain default_admin
 authentication-scheme default
 accounting-scheme default
#
web
 set fast-configuration state disable
#
firewall zone Local
#
mi-server
#
interface Vlanif1
 ip address 10.1.1.1 255.255.255.0
#
interface GigabitEthernet0/0/0
#
interface GigabitEthernet0/0/1
#
interface GigabitEthernet0/0/2
#
interface GigabitEthernet0/0/3
#
interface GigabitEthernet0/0/4
#
interface GigabitEthernet0/0/5
#
interface GigabitEthernet0/0/6
#
interface GigabitEthernet0/0/7
#
interface GigabitEthernet0/0/8
#
interface GigabitEthernet0/0/9
 ip binding vpn-instance vpn1
 ip address dhcp-alloc
#
interface GigabitEthernet0/0/10
#
interface Cellular0/0/0
#
interface NULL0
#
cellular profile default
 modem auto-recovery dial action modem-reboot fail-times 128
 modem auto-recovery icmp-unreachable action modem-reboot
 modem auto-recovery services-unavailable action modem-reboot test-times 0 interval 3600
#
undo icmp name timestamp-request receive
#
 snmp-agent trap enable
#
 http secure-server ssl-policy default_policy
 http secure-server enable
 http server permit interface GigabitEthernet0/0/0
#
ip route-static vpn-instance vpn1 80.158.50.5 255.255.255.255 GigabitEthernet0/0/9 dhcp tag 4400 description agile-controller
#
fib regularly-refresh disable
#
 agile controller host 80.158.50.5 port 10020 vpn-instance vpn1
#
user-interface con 0
 authentication-mode aaa
user-interface vty 0
 authentication-mode aaa
 user privilege level 15
user-interface vty 1 4
#
wlan ac
 traffic-profile name default
 security-profile name default
 security-profile name default-wds
 security wpa2 psk pass-phrase ***** aes
 ssid-profile name default
 vap-profile name default
 wds-profile name default
 regulatory-domain-profile name default
 air-scan-profile name default
 rrm-profile name default
 radio-2g-profile name default
 radio-5g-profile name default
 wids-spoof-profile name default
 wids-profile name default
 ap-system-profile name default
 port-link-profile name default
 wired-port-profile name default
 ap-group name default
#
dot1x-access-profile name dot1x_access_profile
#
mac-access-profile name mac_access_profile
#
ops
#
autostart
#
secelog
#
 ms-channel 

#
return`;

const CISCO_SAMPLE = `! Cisco IOS Gateway Configuration Example
version 15.6
service timestamps debug datetime msec
service timestamps log datetime msec
no service password-encryption
!
hostname Core-Router-01
!
vrf definition CORP_INTERNAL
 rd 65000:100
 address-family ipv4
 exit-address-family
!
crypto ikev2 proposal DEFAULT-IKEV2-PROP
 encryption aes-cbc-256
 integrity sha256
 group 14
!
interface Loopback0
 ip address 10.255.255.1 255.255.255.255
!
interface GigabitEthernet0/0/0
 description WAN Uplink Primary
 vrf forwarding CORP_INTERNAL
 ip address 192.168.1.1 255.255.255.252
 duplex auto
 speed auto
!
interface GigabitEthernet0/0/1
 description LAN Trunk
 switchport mode trunk
 switchport trunk allowed vlan 10,20,30,100
!
interface GigabitEthernet0/0/2
 description LAN Access Port
 switchport mode access
 switchport access vlan 10
!
interface GigabitEthernet0/0/3
 description LAN Access Port
 switchport mode access
 switchport access vlan 20
!
router ospf 1 vrf CORP_INTERNAL
 router-id 10.255.255.1
 network 10.255.255.1 0.0.0.0 area 0
 network 192.168.1.0 0.0.0.3 area 0
!
ip route vrf CORP_INTERNAL 0.0.0.0 0.0.0.0 192.168.1.2
!
line con 0
 logging synchronous
line vty 0 4
 exec-timeout 15 0
 privilege level 15
 login local
 transport input ssh
!
end`;

let editorInstance = null;
let currentDecorations = [];
let allIndexItems = [];
let vpnAnalysisMap = new Map();
let interfaceAnalysisMap = new Map();
let profileAnalysisMap = new Map();
let showReferenceLinks = false; // Default hidden / OFF!
let textHighlightMap = new Map(); // textSnippet.toLowerCase() -&gt; colorClass
let lastSelectedText = '';

require.config({ paths: { 'vs': 'https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.45.0/min/vs' }});

require(['vs/editor/editor.main'], function() {
 registerLanguages();
 registerFoldingProviders();
 registerMonacoJumpCommand();
 registerReferenceHoverProviders();

 const container = document.getElementById('monacoContainer');
 editorInstance = monaco.editor.create(container, {
 value: HUAWEI_SAMPLE,
 language: 'huawei-vrp',
 theme: 'vs',
 automaticLayout: true,
 fontFamily: '"Fira Code", Consolas, Monaco, monospace',
 fontSize: 13,
 minimap: {
 enabled: true,
 scale: 2,
 maxColumn: 120,
 showSlider: 'always',
 renderCharacters: true
 },
 scrollBeyondLastLine: false,
 renderLineHighlight: 'all',
 folding: true,
 foldingStrategy: 'auto',
 showFoldingControls: 'always',
 lineNumbers: 'on',
 contextmenu: false
 });

 setupCustomContextMenu();

 // Listen to document changes to update folding index &amp; reference analysis
 editorInstance.onDidChangeModelContent(() =&gt; {
 analyzeVpnInstances();
 analyzeInterfaceReferences();
 analyzeProfiles();
 updateFoldingIndex();
 analyzeConfiguration();
 onConfigFindChange();
 });

 // Listen to Esc key to exit full window or close context menu
 document.addEventListener('keydown', function(e) {
 if (e.key === 'Escape') {
 const crCont = document.getElementById('crContainer');
 if (crCont &amp;&amp; crCont.classList.contains('cr-full-window')) {
 toggleFullWindow(false);
 }
 const menu = document.getElementById('crContextMenu');
 if (menu) menu.classList.remove('active');
 }
 });

 // Restore user preferences (Full Window, Sidebar &amp; Theme)
 restoreUserPreferences();

 // Initial analysis &amp; index build
 analyzeVpnInstances();
 analyzeInterfaceReferences();
 analyzeProfiles();
 updateFoldingIndex();
 analyzeConfiguration();
});

function setupCustomContextMenu() {
 const container = document.getElementById('monacoContainer');
 if (!container) return;

 container.addEventListener('contextmenu', function(e) {
 e.preventDefault();
 e.stopPropagation();

 if (!editorInstance) return;
 const selection = editorInstance.getSelection();
 const model = editorInstance.getModel();
 if (!model) return;

 let selectedText = '';
 if (selection &amp;&amp; !selection.isEmpty()) {
 selectedText = model.getValueInRange(selection).trim();
 }

 if (!selectedText) {
 const position = editorInstance.getPosition();
 if (position) {
 const word = model.getWordAtPosition(position);
 if (word) selectedText = word.word;
 }
 }

 lastSelectedText = selectedText || '';

 const searchItem = document.getElementById('crCtxSearchItem');
 if (searchItem) {
 if (lastSelectedText) {
 const displayLabel = lastSelectedText.length &gt; 14 ? lastSelectedText.substring(0, 14) + '...' : lastSelectedText;
 searchItem.innerHTML = `&lt;span&gt;🔍 Search "${escapeHtml(displayLabel)}"&lt;/span&gt;`;
 searchItem.style.display = 'flex';
 } else {
 searchItem.style.display = 'none';
 }
 }

 const menu = document.getElementById('crContextMenu');
 if (menu) {
 let top = e.clientY;
 let left = e.clientX;

 const winWidth = window.innerWidth;
 const winHeight = window.innerHeight;
 if (left + 220 &gt; winWidth) left = winWidth - 230;
 if (top + 260 &gt; winHeight) top = winHeight - 270;

 menu.style.top = top + 'px';
 menu.style.left = left + 'px';
 menu.classList.add('active');
 }
 });

 document.addEventListener('click', function(e) {
 const menu = document.getElementById('crContextMenu');
 if (menu &amp;&amp; !menu.contains(e.target)) {
 menu.classList.remove('active');
 }
 });
}

function execCopyFromCtx() {
 const menu = document.getElementById('crContextMenu');
 if (menu) menu.classList.remove('active');

 if (lastSelectedText) {
 navigator.clipboard.writeText(lastSelectedText);
 } else if (editorInstance) {
 const model = editorInstance.getModel();
 if (model) navigator.clipboard.writeText(model.getValue());
 }
}

function execSearchFromCtx() {
 const menu = document.getElementById('crContextMenu');
 if (menu) menu.classList.remove('active');

 if (lastSelectedText) {
 const findInput = document.getElementById('configFindInput');
 if (findInput) {
 findInput.value = lastSelectedText;
 onConfigFindChange();
 findInput.focus();
 }
 }
}

function applyHighlightFromCtx(colorClass) {
 const menu = document.getElementById('crContextMenu');
 if (menu) menu.classList.remove('active');

 if (lastSelectedText) {
 textHighlightMap.set(lastSelectedText.toLowerCase(), colorClass);
 analyzeConfiguration();
 }
}

function clearHighlightFromCtx() {
 const menu = document.getElementById('crContextMenu');
 if (menu) menu.classList.remove('active');

 if (lastSelectedText) {
 textHighlightMap.delete(lastSelectedText.toLowerCase());
 } else {
 textHighlightMap.clear();
 }
 analyzeConfiguration();
}

function toggleReferenceLinks(forceState) {
 if (typeof forceState === 'boolean') {
 showReferenceLinks = forceState;
 } else {
 showReferenceLinks = !showReferenceLinks;
 }

 const btn = document.getElementById('refToggleBtn');
 if (btn) {
 btn.innerText = showReferenceLinks ? '🔗 Hide References' : '🔗 Show References';
 if (showReferenceLinks) {
 btn.classList.add('cr-btn-active');
 } else {
 btn.classList.remove('cr-btn-active');
 }
 }

 analyzeConfiguration();
}

function onConfigFindChange() {
 if (!editorInstance) return;
 const model = editorInstance.getModel();
 if (!model) return;

 const inputEl = document.getElementById('configFindInput');
 const dropdownEl = document.getElementById('configFindDropdown');
 if (!inputEl || !dropdownEl) return;

 const query = (inputEl.value || '').toLowerCase().trim();
 if (!query) {
 dropdownEl.classList.remove('active');
 dropdownEl.innerHTML = '';
 return;
 }

 const lineCount = model.getLineCount();
 const matches = [];

 for (let i = 1; i &lt;= lineCount; i++) {
 const lineText = model.getLineContent(i);
 if (lineText.toLowerCase().includes(query)) {
 matches.push({ lineNum: i, text: lineText.trim() });
 }
 }

 if (matches.length === 0) {
 dropdownEl.innerHTML = '&lt;div class="cr-find-empty"&gt;No matching lines found&lt;/div&gt;';
 dropdownEl.classList.add('active');
 return;
 }

 let html = '';
 matches.forEach(m =&gt; {
 html += `
 &lt;div class="cr-find-item" onmousedown="jumpFromFind(${m.lineNum})"&gt;
 &lt;span class="cr-find-line"&gt;L${m.lineNum}&lt;/span&gt;
 &lt;span class="cr-find-text" title="${escapeHtml(m.text)}"&gt;${escapeHtml(m.text)}&lt;/span&gt;
 &lt;/div&gt;
 `;
 });

 dropdownEl.innerHTML = html;
 dropdownEl.classList.add('active');
}

function jumpFromFind(lineNum) {
 if (!editorInstance) return;
 editorInstance.revealLineInCenter(lineNum);
 editorInstance.setPosition({ lineNumber: lineNum, column: 1 });
 editorInstance.focus();

 const dropdownEl = document.getElementById('configFindDropdown');
 if (dropdownEl) {
 dropdownEl.classList.remove('active');
 }
}

function onConfigFindFocus() {
 const inputEl = document.getElementById('configFindInput');
 if (inputEl &amp;&amp; inputEl.value.trim().length &gt; 0) {
 onConfigFindChange();
 }
}

function onConfigFindBlur() {
 setTimeout(() =&gt; {
 const dropdownEl = document.getElementById('configFindDropdown');
 if (dropdownEl) dropdownEl.classList.remove('active');
 }, 200);
}

function registerMonacoJumpCommand() {
 monaco.editor.registerCommand('configReader.jumpToLine', function(accessor, lineNum) {
 const line = parseInt(lineNum, 10);
 if (!isNaN(line) &amp;&amp; editorInstance) {
 editorInstance.revealLineInCenter(line);
 editorInstance.setPosition({ lineNumber: line, column: 1 });
 editorInstance.focus();
 }
 });
}

function restoreUserPreferences() {
 const savedFullWindow = localStorage.getItem('configReader_fullWindow');
 if (savedFullWindow === 'true') {
 toggleFullWindow(true);
 }

 const savedShowIndex = localStorage.getItem('configReader_showIndex');
 if (savedShowIndex === 'false') {
 const sidebar = document.getElementById('crSidebar');
 const toggleBtn = document.getElementById('crSidebarToggleBtn');
 if (sidebar) sidebar.classList.add('collapsed');
 if (toggleBtn) toggleBtn.innerText = '📑 Show Index';
 }

 const savedTheme = localStorage.getItem('configReader_theme');
 if (savedTheme) {
 const themeSelect = document.getElementById('themeSelect');
 if (themeSelect) {
 themeSelect.value = savedTheme;
 onThemeChange();
 }
 }
}

function registerLanguages() {
 monaco.languages.register({ id: 'huawei-vrp' });
 monaco.languages.setMonarchTokensProvider('huawei-vrp', {
 defaultToken: '',
 tokenPostfix: '.huawei',
 keywords: [
 'interface', 'ip', 'route-static', 'aaa', 'vlan', 'vpn-instance', 'wlan', 'ac', 'dhcp',
 'authentication-profile', 'security-profile', 'vap-profile', 'ssid-profile', 'wds-profile',
 'ssl', 'policy', 'ike', 'proposal', 'firewall', 'zone', 'snmp-agent', 'user-interface',
 'cellular', 'profile', 'undo', 'return', 'quit', 'ipv6', 'dns', 'pki', 'realm',
 'portal-access-profile', 'free-rule-template', 'ops', 'autostart', 'secelog', 'agile',
 'controller', 'fib', 'enable', 'disable', 'permit', 'description', 'bind', 'binding', 'eth-trunk',
 'authentication-scheme', 'authorization-scheme', 'accounting-scheme', 'domain', 'radius-server'
 ],
 tokenizer: {
 root: [
 [/^\s*#.*$/, 'comment'],
 [/^\[.*\]$/, 'keyword.flow'],
 [/%^%#[^%]+%^%#/, 'string.cipher'],
 [/\b(GigabitEthernet|40GE|10GE|GE|XGigabitEthernet|Eth-Trunk|Vlanif|vlanif|Cellular|NULL|LoopBack|Loopback)\d+(\/\d+)*(\.\d+)?\b/i, 'type.identifier'],
 [/\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/, 'number.float'],
 [/[a-zA-Z0-9_\-]+/, {
 cases: {
 '@keywords': 'keyword',
 '@default': 'identifier'
 }
 }]
 ]
 }
 });

 monaco.languages.register({ id: 'cisco-ios' });
 monaco.languages.setMonarchTokensProvider('cisco-ios', {
 defaultToken: '',
 tokenPostfix: '.cisco',
 keywords: [
 'interface', 'ip', 'route', 'router', 'ospf', 'bgp', 'line', 'vty', 'con', 'crypto',
 'ipsec', 'isakmp', 'vlan', 'username', 'enable', 'secret', 'hostname', 'no', 'end', 'exit',
 'vrf', 'definition', 'description', 'duplex', 'speed', 'switchport', 'mode', 'trunk', 'allowed'
 ],
 tokenizer: {
 root: [
 [/^\s*!.*$/, 'comment'],
 [/\b(GigabitEthernet|TenGigabitEthernet|FastEthernet|Loopback|Vlan)\d+(\/\d+)*\b/i, 'type.identifier'],
 [/\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/, 'number.float'],
 [/[a-zA-Z0-9_\-]+/, {
 cases: {
 '@keywords': 'keyword',
 '@default': 'identifier'
 }
 }]
 ]
 }
 });
}

function registerFoldingProviders() {
 const languages = ['huawei-vrp', 'cisco-ios'];

 languages.forEach(langId =&gt; {
 monaco.languages.registerFoldingRangeProvider(langId, {
 provideFoldingRanges: function(model, context, token) {
 const ranges = [];
 const lineCount = model.getLineCount();
 const lines = model.getLinesContent();

 function isDelimiterLine(lineText) {
 const trimmed = lineText.trim();
 return trimmed === '#' || trimmed === '!' || trimmed.startsWith('#') || trimmed.startsWith('!');
 }

 function getIndent(lineText) {
 let count = 0;
 for (let i = 0; i &lt; lineText.length; i++) {
 if (lineText[i] === ' ') count += 1;
 else if (lineText[i] === '\t') count += 4;
 else break;
 }
 return count;
 }

 function getTwoWordPrefix(lineText) {
 const trimmed = lineText.trim();
 if (!trimmed) return '';
 const words = trimmed.split(/\s+/);
 if (words.length &gt;= 2) {
 return (words[0] + ' ' + words[1]).toLowerCase();
 }
 return words[0].toLowerCase();
 }

 let segments = [];
 let currentSegment = [];

 for (let i = 0; i &lt; lineCount; i++) {
 const line = lines[i];
 if (isDelimiterLine(line)) {
 if (currentSegment.length &gt; 0) {
 segments.push(currentSegment);
 currentSegment = [];
 }
 } else {
 if (line.trim().length &gt; 0) {
 currentSegment.push({ lineIndex: i, text: line });
 }
 }
 }
 if (currentSegment.length &gt; 0) {
 segments.push(currentSegment);
 }

 segments.forEach(seg =&gt; {
 if (seg.length &lt; 2) return;

 for (let idx = 0; idx &lt; seg.length; idx++) {
 const parentItem = seg[idx];
 const parentIndent = getIndent(parentItem.text);

 let endIdx = idx;
 for (let j = idx + 1; j &lt; seg.length; j++) {
 const childIndent = getIndent(seg[j].text);
 if (childIndent &gt; parentIndent) {
 endIdx = j;
 } else {
 break;
 }
 }

 if (endIdx &gt; idx) {
 ranges.push({
 start: parentItem.lineIndex + 1,
 end: seg[endIdx].lineIndex + 1,
 kind: monaco.languages.FoldingRangeKind.Region
 });
 }
 }

 let i = 0;
 while (i &lt; seg.length) {
 const itemI = seg[i];
 const indentI = getIndent(itemI.text);
 const prefixI = getTwoWordPrefix(itemI.text);

 if (!prefixI) {
 i++;
 continue;
 }

 let j = i + 1;
 while (j &lt; seg.length) {
 const itemJ = seg[j];
 const indentJ = getIndent(itemJ.text);
 const prefixJ = getTwoWordPrefix(itemJ.text);

 if (indentJ === indentI &amp;&amp; prefixJ === prefixI) {
 j++;
 } else {
 break;
 }
 }

 if (j - i &gt;= 2) {
 ranges.push({
 start: seg[i].lineIndex + 1,
 end: seg[j - 1].lineIndex + 1,
 kind: monaco.languages.FoldingRangeKind.Region
 });
 i = j;
 } else {
 i++;
 }
 }
 });

 return ranges;
 }
 });
 });
}

function getIndent(lineText) {
 let count = 0;
 for (let i = 0; i &lt; lineText.length; i++) {
 if (lineText[i] === ' ') count += 1;
 else if (lineText[i] === '\t') count += 4;
 else break;
 }
 return count;
}

// Section-scoped definition block extraction
function getDefinitionBlockText(model, startLineNum) {
 const lineCount = model.getLineCount();
 const startLine = model.getLineContent(startLineNum);
 const currentIndent = getIndent(startLine);
 
 const blockLines = [];

 // If current line is indented (e.g. child under "wlan ac" or "aaa"), find top parent section header
 if (currentIndent &gt; 0) {
 for (let k = startLineNum - 1; k &gt;= 1; k--) {
 const pText = model.getLineContent(k);
 const pTrimmed = pText.trim();
 if (!pTrimmed || pTrimmed === '#' || pTrimmed === '!' || pTrimmed.startsWith('#') || pTrimmed.startsWith('!')) {
 break;
 }
 const pIndent = getIndent(pText);
 if (pIndent === 0) {
 blockLines.push(pText);
 break;
 }
 }
 }

 // Add the definition line itself
 blockLines.push(startLine);

 // Add any child sub-commands that belong directly to this line (indented further than currentIndent)
 for (let i = startLineNum; i &lt; lineCount; i++) {
 const line = model.getLineContent(i + 1);
 const trimmed = line.trim();

 if (!trimmed || trimmed === '#' || trimmed === '!' || trimmed.startsWith('#') || trimmed.startsWith('!')) {
 break;
 }

 const indent = getIndent(line);
 if (indent &lt;= currentIndent) {
 break;
 }

 blockLines.push(line);
 }

 return blockLines.join('\n');
}

function analyzeVpnInstances() {
 vpnAnalysisMap.clear();
 if (!editorInstance) return;
 const model = editorInstance.getModel();
 if (!model) return;

 const lines = model.getLinesContent();
 const lineCount = lines.length;

 function cleanTitle(str) {
 return str.replace(/[#!]/g, '').trim();
 }

 function getSectionHeader(lineIdx) {
 for (let k = lineIdx; k &gt;= 0; k--) {
 const lText = lines[k];
 const trimmed = lText.trim();
 if (!trimmed || trimmed === '#' || trimmed === '!' || trimmed.startsWith('#') || trimmed.startsWith('!')) continue;

 const indent = lText.search(/\S/);
 if (indent === 0) {
 return cleanTitle(trimmed);
 }
 }
 return 'Global Configuration';
 }

 const vpnDefRegex = /^\s*ip\s+vpn-instance\s+([a-zA-Z0-9_\-]+)/i;
 for (let i = 0; i &lt; lineCount; i++) {
 const match = vpnDefRegex.exec(lines[i]);
 if (match) {
 const vpnName = match[1];
 if (!vpnAnalysisMap.has(vpnName.toLowerCase())) {
 const defLineNum = i + 1;
 const defBlockText = getDefinitionBlockText(model, defLineNum);
 vpnAnalysisMap.set(vpnName.toLowerCase(), {
 name: vpnName,
 defLineNum: defLineNum,
 defText: lines[i].trim(),
 defBlockText: defBlockText,
 references: []
 });
 }
 }
 }

 for (let i = 0; i &lt; lineCount; i++) {
 const lineNum = i + 1;
 const lineText = lines[i];

 vpnAnalysisMap.forEach((vpnInfo) =&gt; {
 if (lineNum !== vpnInfo.defLineNum) {
 const refRegex = new RegExp(`\\bvpn-instance\\s+${vpnInfo.name}\\b`, 'i');
 if (refRegex.test(lineText)) {
 const sectionHeader = getSectionHeader(i);
 vpnInfo.references.push({
 lineNum: lineNum,
 text: lineText.trim(),
 sectionHeader: sectionHeader
 });
 }
 }
 });
 }
}

// Generic Interface Analyzer: 2-word rule "interface &lt;ifName&gt;" (case-insensitive) &amp; Eth-Trunk association
function analyzeInterfaceReferences() {
 interfaceAnalysisMap.clear();
 if (!editorInstance) return;
 const model = editorInstance.getModel();
 if (!model) return;

 const lines = model.getLinesContent();
 const lineCount = lines.length;

 function cleanTitle(str) {
 return str.replace(/[#!]/g, '').trim();
 }

 function getSectionHeader(lineIdx) {
 for (let k = lineIdx; k &gt;= 0; k--) {
 const lText = lines[k];
 const trimmed = lText.trim();
 if (!trimmed || trimmed === '#' || trimmed === '!' || trimmed.startsWith('#') || trimmed.startsWith('!')) continue;

 const indent = lText.search(/\S/);
 if (indent === 0) {
 return cleanTitle(trimmed);
 }
 }
 return 'Global Configuration';
 }

 // Generic 2-word rule: ^\s*interface\s+(\S+)\s*$ (case-insensitive)
 const ifDefRegex = /^\s*interface\s+(\S+)\s*$/i;
 for (let i = 0; i &lt; lineCount; i++) {
 const match = ifDefRegex.exec(lines[i]);
 if (match) {
 const ifName = match[1];
 if (!interfaceAnalysisMap.has(ifName.toLowerCase())) {
 const defLineNum = i + 1;
 const defBlockText = getDefinitionBlockText(model, defLineNum);

 // Check if interface is Eth-Trunk&lt;ID&gt;
 const trunkMatch = /^Eth-Trunk(\d+)$/i.exec(ifName);
 const trunkId = trunkMatch ? trunkMatch[1] : null;

 interfaceAnalysisMap.set(ifName.toLowerCase(), {
 name: ifName,
 defLineNum: defLineNum,
 defText: lines[i].trim(),
 defBlockText: defBlockText,
 trunkId: trunkId,
 references: []
 });
 }
 }
 }

 for (let i = 0; i &lt; lineCount; i++) {
 const lineNum = i + 1;
 const lineText = lines[i];

 interfaceAnalysisMap.forEach((ifInfo) =&gt; {
 if (lineNum !== ifInfo.defLineNum) {
 const escapedName = ifInfo.name.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&amp;');

 const refRegex = new RegExp(`(?&lt;![a-zA-Z0-9_./-])${escapedName}(?![a-zA-Z0-9_./-])`, 'i');

 let ethTrunkMatch = false;
 if (ifInfo.trunkId) {
 const ethTrunkRegex = new RegExp(`\\beth-trunk\\s+${ifInfo.trunkId}\\b`, 'i');
 if (ethTrunkRegex.test(lineText)) {
 ethTrunkMatch = true;
 }
 }

 if (refRegex.test(lineText) || ethTrunkMatch) {
 const sectionHeader = getSectionHeader(i);
 ifInfo.references.push({
 lineNum: lineNum,
 text: lineText.trim(),
 sectionHeader: sectionHeader
 });
 }
 }
 });
 }
}

// Generic Profile &amp; AAA Scheme Analyzer
function analyzeProfiles() {
 profileAnalysisMap.clear();
 if (!editorInstance) return;
 const model = editorInstance.getModel();
 if (!model) return;

 const lines = model.getLinesContent();
 const lineCount = lines.length;

 function cleanTitle(str) {
 return str.replace(/[#!]/g, '').trim();
 }

 function getSectionHeader(lineIdx) {
 for (let k = lineIdx; k &gt;= 0; k--) {
 const lText = lines[k];
 const trimmed = lText.trim();
 if (!trimmed || trimmed === '#' || trimmed === '!' || trimmed.startsWith('#') || trimmed.startsWith('!')) continue;

 const indent = lText.search(/\S/);
 if (indent === 0) {
 return cleanTitle(trimmed);
 }
 }
 return 'Global Configuration';
 }

 // Profile Definition Pattern 1: "&lt;profile-type&gt; name &lt;profile-name&gt;" or "&lt;type&gt; template &lt;name&gt;"
 const profDefRegex1 = /^\s*([a-zA-Z0-9_\-]+(?:\s+template|\s+profile)?)\s+name\s+([a-zA-Z0-9_\-]+)/i;
 const profDefRegex2 = /^\s*([a-zA-Z0-9_\-]+)\s+template\s+([a-zA-Z0-9_\-]+)/i;
 
 // AAA Level-1 Definition Pattern: 1 space indent under aaa (e.g. " authentication-scheme default", " domain default")
 const aaaDefRegex = /^ ([a-zA-Z0-9_\-]+(?:-scheme|-user|domain))\s+([a-zA-Z0-9_\-]+)/i;

 let inAaaSection = false;

 for (let i = 0; i &lt; lineCount; i++) {
 const lineText = lines[i];
 const trimmed = lineText.trim();

 if (trimmed === 'aaa') {
 inAaaSection = true;
 continue;
 } else if (trimmed === '#' || trimmed === '!' || (trimmed &amp;&amp; lineText.search(/\S/) === 0)) {
 if (trimmed !== 'aaa') inAaaSection = false;
 }

 let profType = null;
 let profName = null;
 let baseType = null;

 let match1 = profDefRegex1.exec(lineText);
 let match2 = profDefRegex2.exec(lineText);
 let matchAaa = inAaaSection ? aaaDefRegex.exec(lineText) : null;

 if (match1) {
 profType = match1[1].trim();
 profName = match1[2].trim();
 baseType = profType.replace(/\s+template$/i, '');
 } else if (match2) {
 profType = match2[1].trim() + ' template';
 profName = match2[2].trim();
 baseType = match2[1].trim();
 } else if (matchAaa) {
 profType = matchAaa[1].trim();
 profName = matchAaa[2].trim();
 baseType = profType;
 }

 if (profType &amp;&amp; profName) {
 const key = `${profType.toLowerCase()}:${profName.toLowerCase()}`;
 if (!profileAnalysisMap.has(key)) {
 const defLineNum = i + 1;
 const defBlockText = getDefinitionBlockText(model, defLineNum);
 profileAnalysisMap.set(key, {
 type: profType,
 baseType: baseType,
 name: profName,
 defLineNum: defLineNum,
 defText: lineText.trim(),
 defBlockText: defBlockText,
 references: []
 });
 }
 }
 }

 for (let i = 0; i &lt; lineCount; i++) {
 const lineNum = i + 1;
 const lineText = lines[i];

 profileAnalysisMap.forEach((profInfo) =&gt; {
 if (lineNum !== profInfo.defLineNum) {
 const escType = profInfo.type.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&amp;');
 const escBaseType = profInfo.baseType.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&amp;');
 const escName = profInfo.name.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&amp;');

 // Usage pattern: "&lt;type&gt; &lt;name&gt;" OR "&lt;baseType&gt; &lt;name&gt;" OR "&lt;type&gt; name &lt;name&gt;" OR "&lt;type&gt; template &lt;name&gt;"
 const refRegex = new RegExp(`\\b(?:${escType}|${escBaseType})\\s+(?:name\\s+|template\\s+)?${escName}\\b`, 'i');
 if (refRegex.test(lineText)) {
 const sectionHeader = getSectionHeader(i);
 profInfo.references.push({
 lineNum: lineNum,
 text: lineText.trim(),
 sectionHeader: sectionHeader
 });
 }
 }
 });
 }
}

function escapeHoverText(str) {
 if (!str) return '';
 return str.replace(/`/g, "'").replace(/&lt;/g, "&amp;lt;").replace(/&gt;/g, "&amp;gt;");
}

function registerReferenceHoverProviders() {
 const languages = ['huawei-vrp', 'cisco-ios'];

 languages.forEach(langId =&gt; {
 monaco.languages.registerHoverProvider(langId, {
 provideHover: function(model, position) {
 if (!showReferenceLinks) return null;

 const lineText = model.getLineContent(position.lineNumber);
 const col = position.column;

 // 1. VPN Instance Hover (column position check)
 const vpnRegex = /vpn-instance\s+([a-zA-Z0-9_\-]+)/gi;
 let match;
 while ((match = vpnRegex.exec(lineText)) !== null) {
 const startCol = match.index + 1;
 const endCol = match.index + 1 + match[0].length;

 if (col &gt;= startCol &amp;&amp; col &lt;= endCol) {
 const vpnName = match[1];
 const vpnInfo = vpnAnalysisMap.get(vpnName.toLowerCase());
 if (vpnInfo) {
 const refCount = vpnInfo.references.length;
 const contents = [];

 contents.push({ value: `**🔒 VPN Instance:** \`${escapeHoverText(vpnInfo.name)}\` (Referenced **${refCount}** times)` });

 contents.push({
 value: `[**★ Definition Block (Line ${vpnInfo.defLineNum}):**](command:configReader.jumpToLine?${vpnInfo.defLineNum})\n\`\`\`\n${escapeHoverText(vpnInfo.defBlockText)}\n\`\`\``,
 isTrusted: true
 });

 if (refCount === 0) {
 contents.push({ value: '_No usage references found in configuration._' });
 } else {
 let refMarkdown = '**Usage Locations by Section (click line to jump):**\n';
 vpnInfo.references.forEach(ref =&gt; {
 refMarkdown += `- [📍 **${escapeHoverText(ref.sectionHeader)}** (L${ref.lineNum}): \`${escapeHoverText(ref.text)}\`](command:configReader.jumpToLine?${ref.lineNum})\n`;
 });
 contents.push({ value: refMarkdown, isTrusted: true });
 }

 return {
 range: new monaco.Range(position.lineNumber, startCol, position.lineNumber, endCol),
 contents: contents
 };
 }
 }
 }

 // 2. Interface &amp; Eth-Trunk Reference Hover
 let hoverResult = null;
 interfaceAnalysisMap.forEach((ifInfo) =&gt; {
 if (hoverResult) return;

 const escapedName = ifInfo.name.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&amp;');
 const ifRegex = new RegExp(`(?&lt;![a-zA-Z0-9_./-])${escapedName}(?![a-zA-Z0-9_./-])`, 'gi');
 let ifMatch;
 while ((ifMatch = ifRegex.exec(lineText)) !== null) {
 const startCol = ifMatch.index + 1;
 const endCol = ifMatch.index + 1 + ifMatch[0].length;

 if (col &gt;= startCol &amp;&amp; col &lt;= endCol) {
 hoverResult = buildInterfaceHover(ifInfo, position, startCol, endCol);
 break;
 }
 }

 if (!hoverResult &amp;&amp; ifInfo.trunkId) {
 const ethTrunkRegex = new RegExp(`\\beth-trunk\\s+${ifInfo.trunkId}\\b`, 'gi');
 let trunkMatch;
 while ((trunkMatch = ethTrunkRegex.exec(lineText)) !== null) {
 const startCol = trunkMatch.index + 1;
 const endCol = trunkMatch.index + 1 + trunkMatch[0].length;

 if (col &gt;= startCol &amp;&amp; col &lt;= endCol) {
 hoverResult = buildInterfaceHover(ifInfo, position, startCol, endCol);
 break;
 }
 }
 }
 });

 if (hoverResult) return hoverResult;

 // 3. Profile &amp; AAA Scheme Reference Hover
 profileAnalysisMap.forEach((profInfo) =&gt; {
 if (hoverResult) return;

 const escType = profInfo.type.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&amp;');
 const escBaseType = profInfo.baseType.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&amp;');
 const escName = profInfo.name.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&amp;');
 const profRegex = new RegExp(`\\b(?:${escType}|${escBaseType})\\s+(?:name\\s+|template\\s+)?${escName}\\b`, 'gi');
 let profMatch;
 while ((profMatch = profRegex.exec(lineText)) !== null) {
 const startCol = profMatch.index + 1;
 const endCol = profMatch.index + 1 + profMatch[0].length;

 if (col &gt;= startCol &amp;&amp; col &lt;= endCol) {
 const refCount = profInfo.references.length;
 const contents = [];

 contents.push({ value: `**🛡️ Profile / AAA Scheme:** \`${escapeHoverText(profInfo.type)} ${escapeHoverText(profInfo.name)}\` (Referenced **${refCount}** times)` });

 contents.push({
 value: `[**★ Definition Block (Line ${profInfo.defLineNum}):**](command:configReader.jumpToLine?${profInfo.defLineNum})\n\`\`\`\n${escapeHoverText(profInfo.defBlockText)}\n\`\`\``,
 isTrusted: true
 });

 if (refCount === 0) {
 contents.push({ value: '_No usage references found in configuration._' });
 } else {
 let refMarkdown = '**Usage Locations by Section (click line to jump):**\n';
 profInfo.references.forEach(ref =&gt; {
 refMarkdown += `- [📍 **${escapeHoverText(ref.sectionHeader)}** (L${ref.lineNum}): \`${escapeHoverText(ref.text)}\`](command:configReader.jumpToLine?${ref.lineNum})\n`;
 });
 contents.push({ value: refMarkdown, isTrusted: true });
 }

 hoverResult = {
 range: new monaco.Range(position.lineNumber, startCol, position.lineNumber, endCol),
 contents: contents
 };
 break;
 }
 }
 });

 if (hoverResult) return hoverResult;
 return null;
 }
 });
 });
}

function buildInterfaceHover(ifInfo, position, startCol, endCol) {
 const refCount = ifInfo.references.length;
 const contents = [];

 contents.push({ value: `**🔌 Interface:** \`${escapeHoverText(ifInfo.name)}\` (Referenced **${refCount}** times)` });

 contents.push({
 value: `[**★ Definition Block (Line ${ifInfo.defLineNum}):**](command:configReader.jumpToLine?${ifInfo.defLineNum})\n\`\`\`\n${escapeHoverText(ifInfo.defBlockText)}\n\`\`\``,
 isTrusted: true
 });

 if (refCount === 0) {
 contents.push({ value: '_No usage references found in configuration._' });
 } else {
 let refMarkdown = '**Usage Locations by Section (click line to jump):**\n';
 ifInfo.references.forEach(ref =&gt; {
 refMarkdown += `- [📍 **${escapeHoverText(ref.sectionHeader)}** (L${ref.lineNum}): \`${escapeHoverText(ref.text)}\`](command:configReader.jumpToLine?${ref.lineNum})\n`;
 });
 contents.push({ value: refMarkdown, isTrusted: true });
 }

 return {
 range: new monaco.Range(position.lineNumber, startCol, position.lineNumber, endCol),
 contents: contents
 };
}

function updateFoldingIndex() {
 if (!editorInstance) return;
 const model = editorInstance.getModel();
 if (!model) return;

 const lines = model.getLinesContent();
 const lineCount = lines.length;

 function isDelimiterLine(lineText) {
 const trimmed = lineText.trim();
 return trimmed === '#' || trimmed === '!' || trimmed.startsWith('#') || trimmed.startsWith('!');
 }

 function cleanTitle(str) {
 return str.replace(/[#!]/g, '').trim();
 }

 function getTwoWordPrefix(lineText) {
 const trimmed = lineText.trim();
 if (!trimmed) return '';
 const words = trimmed.split(/\s+/);
 if (words.length &gt;= 2) {
 return words[0] + ' ' + words[1];
 }
 return words[0];
 }

 const items = [];
 let currentBlock = [];

 for (let i = 0; i &lt; lineCount; i++) {
 const line = lines[i];
 if (isDelimiterLine(line)) {
 if (currentBlock.length &gt; 0) {
 processBlock(currentBlock, items);
 currentBlock = [];
 }
 } else {
 if (line.trim().length &gt; 0) {
 currentBlock.push({ lineNum: i + 1, text: line });
 }
 }
 }
 if (currentBlock.length &gt; 0) {
 processBlock(currentBlock, items);
 }

 function processBlock(block, outItems) {
 if (block.length === 0) return;

 const firstPrefix = getTwoWordPrefix(block[0].text).toLowerCase();
 const allSamePrefix = block.length &gt;= 2 &amp;&amp; block.every(b =&gt; getTwoWordPrefix(b.text).toLowerCase() === firstPrefix);

 if (allSamePrefix) {
 const rawTitle = getTwoWordPrefix(block[0].text);
 const title = cleanTitle(rawTitle);
 if (title) {
 const item = {
 title: title,
 lineNum: block[0].lineNum,
 count: block.length,
 icon: getSectionIcon(title)
 };
 checkRefInfo(item, block[0].text);
 outItems.push(item);
 }
 } else {
 let minIndent = Infinity;
 block.forEach(b =&gt; {
 const indent = b.text.search(/\S/);
 if (indent !== -1 &amp;&amp; indent &lt; minIndent) minIndent = indent;
 });

 let i = 0;
 while (i &lt; block.length) {
 const b = block[i];
 const indent = b.text.search(/\S/);
 const prefix = getTwoWordPrefix(b.text).toLowerCase();

 let j = i + 1;
 while (j &lt; block.length) {
 const bNext = block[j];
 const indentNext = bNext.text.search(/\S/);
 const prefixNext = getTwoWordPrefix(bNext.text).toLowerCase();
 if (indentNext === indent &amp;&amp; prefixNext === prefix) {
 j++;
 } else {
 break;
 }
 }

 if (j - i &gt;= 2) {
 const title = cleanTitle(getTwoWordPrefix(b.text));
 if (title) {
 const item = {
 title: title,
 lineNum: b.lineNum,
 count: j - i,
 icon: getSectionIcon(title)
 };
 checkRefInfo(item, b.text);
 outItems.push(item);
 }
 i = j;
 } else {
 if (indent === minIndent) {
 const title = cleanTitle(b.text);
 if (title) {
 const item = {
 title: title,
 lineNum: b.lineNum,
 count: 1,
 icon: getSectionIcon(title)
 };
 checkRefInfo(item, b.text);
 outItems.push(item);
 }
 }
 i++;
 }
 }
 }
 }

 function checkRefInfo(item, lineText) {
 // Check VPN Instance
 const vpnMatch = /ip\s+vpn-instance\s+([a-zA-Z0-9_\-]+)/i.exec(lineText);
 if (vpnMatch) {
 const vpnName = vpnMatch[1];
 const vpnInfo = vpnAnalysisMap.get(vpnName.toLowerCase());
 if (vpnInfo) {
 item.isVpn = true;
 item.refName = vpnName;
 item.refCount = vpnInfo.references.length;
 }
 }

 // Check Interface
 const ifMatch = /^\s*interface\s+(\S+)\s*$/i.exec(lineText);
 if (ifMatch) {
 const ifName = ifMatch[1];
 const ifInfo = interfaceAnalysisMap.get(ifName.toLowerCase());
 if (ifInfo) {
 item.isInterface = true;
 item.refName = ifName;
 item.refCount = ifInfo.references.length;
 }
 }

 // Check Profile / AAA Scheme
 const profMatch1 = /^\s*([a-zA-Z0-9_\-]+(?:\s+template|\s+profile)?)\s+name\s+([a-zA-Z0-9_\-]+)/i.exec(lineText);
 const profMatch2 = /^\s*([a-zA-Z0-9_\-]+)\s+template\s+([a-zA-Z0-9_\-]+)/i.exec(lineText);
 const aaaMatch = /^ ([a-zA-Z0-9_\-]+(?:-scheme|-user|domain))\s+([a-zA-Z0-9_\-]+)/i.exec(lineText);

 let profType = null;
 let profName = null;

 if (profMatch1) {
 profType = profMatch1[1].trim();
 profName = profMatch1[2].trim();
 } else if (profMatch2) {
 profType = profMatch2[1].trim() + ' template';
 profName = profMatch2[2].trim();
 } else if (aaaMatch) {
 profType = aaaMatch[1].trim();
 profName = aaaMatch[2].trim();
 }

 if (profType &amp;&amp; profName) {
 const key = `${profType.toLowerCase()}:${profName.toLowerCase()}`;
 const profInfo = profileAnalysisMap.get(key);
 if (profInfo) {
 item.isProfile = true;
 item.profKey = key;
 item.refName = `${profType} ${profName}`;
 item.refCount = profInfo.references.length;
 }
 }
 }

 allIndexItems = items;
 renderIndexList(items);
}

function getSectionIcon(title) {
 const t = title.toLowerCase();
 if (t.includes('interface') || t.includes('vlanif') || t.includes('gigabitethernet')) return '🔌';
 if (t.includes('route') || t.includes('bgp') || t.includes('ospf') || t.includes('vpn')) return '🌐';
 if (t.includes('authen') || t.includes('user') || t.includes('aaa') || t.includes('line') || t.includes('domain')) return '👤';
 if (t.includes('ssl') || t.includes('pki') || t.includes('ike') || t.includes('firewall') || t.includes('security')) return '🔒';
 if (t.includes('dhcp') || t.includes('dns') || t.includes('http')) return '⚡';
 if (t.includes('wlan') || t.includes('cellular')) return '📡';
 return '📄';
}

function renderIndexList(items) {
 const listEl = document.getElementById('indexList');
 const countBadgeEl = document.getElementById('indexCountBadge');
 if (!listEl) return;

 if (countBadgeEl) {
 countBadgeEl.innerText = items.length;
 }

 if (items.length === 0) {
 listEl.innerHTML = '&lt;div class="cr-index-empty"&gt;No index items found&lt;/div&gt;';
 return;
 }

 let html = '';
 items.forEach((item, idx) =&gt; {
 const countBadge = item.count &gt; 1 ? `&lt;span class="cr-index-count"&gt;${item.count}&lt;/span&gt;` : '';
 let refBadge = '';
 if (item.isVpn) {
 refBadge = `&lt;span class="cr-vpn-ref-badge" onclick="openRefModal('vpn', '${escapeHtml(item.refName)}', event)" title="View VPN References"&gt;Ref: ${item.refCount}&lt;/span&gt;`;
 } else if (item.isInterface) {
 refBadge = `&lt;span class="cr-if-ref-badge" onclick="openRefModal('interface', '${escapeHtml(item.refName)}', event)" title="View Interface References"&gt;Ref: ${item.refCount}&lt;/span&gt;`;
 } else if (item.isProfile) {
 refBadge = `&lt;span class="cr-prof-ref-badge" onclick="openRefModal('profile', '${escapeHtml(item.profKey)}', event)" title="View Profile References"&gt;Ref: ${item.refCount}&lt;/span&gt;`;
 }

 html += `
 &lt;div class="cr-index-item" onclick="jumpToLine(${item.lineNum}, this)" data-index="${idx}"&gt;
 &lt;div class="cr-index-left"&gt;
 &lt;span class="cr-index-icon"&gt;${item.icon}&lt;/span&gt;
 &lt;span class="cr-index-title" title="${escapeHtml(item.title)}"&gt;${escapeHtml(item.title)}&lt;/span&gt;
 ${countBadge}
 ${refBadge}
 &lt;/div&gt;
 &lt;span class="cr-index-line"&gt;L${item.lineNum}&lt;/span&gt;
 &lt;/div&gt;
 `;
 });
 listEl.innerHTML = html;
}

function openRefModal(type, refName, event) {
 if (event) event.stopPropagation();

 let refInfo = null;
 let icon = '🔒';
 let titlePrefix = 'VPN Instance';

 if (type === 'interface') {
 refInfo = interfaceAnalysisMap.get(refName.toLowerCase());
 icon = '🔌';
 titlePrefix = 'Interface';
 } else if (type === 'profile') {
 refInfo = profileAnalysisMap.get(refName.toLowerCase());
 icon = '🛡️';
 titlePrefix = 'Profile / AAA Scheme';
 } else {
 refInfo = vpnAnalysisMap.get(refName.toLowerCase());
 }

 const modalBody = document.getElementById('crVpnModalBody');
 const modalTitle = document.getElementById('crVpnModalTitle');
 const modalOverlay = document.getElementById('crVpnModal');

 if (!refInfo || !modalBody || !modalOverlay) return;

 const displayName = refInfo.type ? `${refInfo.type} ${refInfo.name}` : refInfo.name;
 modalTitle.innerText = `${icon} ${titlePrefix}: ${displayName}`;

 let bodyHtml = `
 &lt;!-- Top Creation/Definition Block Section --&gt;
 &lt;div class="cr-def-block-card"&gt;
 &lt;div class="cr-def-block-title"&gt;
 &lt;span&gt;★ Definition Block (Line ${refInfo.defLineNum})&lt;/span&gt;
 &lt;span class="cr-index-line" style="cursor: pointer;" onclick="jumpToLine(${refInfo.defLineNum}); closeVpnModal();"&gt;L${refInfo.defLineNum}&lt;/span&gt;
 &lt;/div&gt;
 &lt;div class="cr-vpn-ref-code" onclick="jumpToLine(${refInfo.defLineNum}); closeVpnModal();"&gt;
${escapeHtml(refInfo.defBlockText)}
 &lt;/div&gt;
 &lt;/div&gt;
 
 &lt;div style="font-weight: 700; font-size: 0.9rem; margin-bottom: 0.5rem; color: #0f172a;"&gt;
 Usage References (${refInfo.references.length} found):
 &lt;/div&gt;
 `;

 if (refInfo.references.length === 0) {
 bodyHtml += `&lt;div style="color: #94a3b8; font-style: italic;"&gt;No usage references found in this configuration.&lt;/div&gt;`;
 } else {
 refInfo.references.forEach(ref =&gt; {
 bodyHtml += `
 &lt;div class="cr-vpn-ref-group"&gt;
 &lt;div class="cr-vpn-ref-header"&gt;
 &lt;span&gt;📁 Section: ${escapeHtml(ref.sectionHeader)}&lt;/span&gt;
 &lt;span class="cr-index-line"&gt;L${ref.lineNum}&lt;/span&gt;
 &lt;/div&gt;
 &lt;div class="cr-vpn-ref-code" onclick="jumpToLine(${ref.lineNum}); closeVpnModal();"&gt;
 ${escapeHtml(ref.text)}
 &lt;/div&gt;
 &lt;/div&gt;
 `;
 });
 }

 modalBody.innerHTML = bodyHtml;
 modalOverlay.classList.add('active');
}

function closeVpnModal(event) {
 if (!event || event.target.id === 'crVpnModal' || event.target.classList.contains('cr-modal-close')) {
 const modalOverlay = document.getElementById('crVpnModal');
 if (modalOverlay) modalOverlay.classList.remove('active');
 }
}

function escapeHtml(str) {
 return str.replace(/&amp;/g, "&amp;amp;").replace(/&lt;/g, "&amp;lt;").replace(/&gt;/g, "&amp;gt;").replace(/"/g, "&amp;quot;");
}

function filterIndexList() {
 const query = (document.getElementById('indexSearchInput').value || '').toLowerCase().trim();
 if (!query) {
 renderIndexList(allIndexItems);
 return;
 }
 const filtered = allIndexItems.filter(item =&gt; 
 item.title.toLowerCase().includes(query) || (`l${item.lineNum}`).includes(query) || (item.refName &amp;&amp; item.refName.toLowerCase().includes(query))
 );
 renderIndexList(filtered);
}

function jumpToLine(lineNum, element) {
 if (!editorInstance) return;
 editorInstance.revealLineInCenter(lineNum);
 editorInstance.setPosition({ lineNumber: lineNum, column: 1 });
 editorInstance.focus();

 const allItems = document.querySelectorAll('.cr-index-item');
 allItems.forEach(el =&gt; el.classList.remove('active'));
 if (element) {
 element.classList.add('active');
 }
}

function toggleSidebar() {
 const sidebar = document.getElementById('crSidebar');
 const toggleBtn = document.getElementById('crSidebarToggleBtn');
 if (!sidebar) return;

 const isCollapsed = sidebar.classList.toggle('collapsed');
 if (toggleBtn) {
 toggleBtn.innerText = isCollapsed ? '📑 Show Index' : '📑 Hide Index';
 }
 localStorage.setItem('configReader_showIndex', isCollapsed ? 'false' : 'true');

 setTimeout(() =&gt; {
 if (editorInstance) editorInstance.layout();
 }, 100);
}

function toggleFullWindow(forceState) {
 const container = document.getElementById('crContainer');
 const btn = document.getElementById('fullWindowBtn');
 if (!container) return;

 let isFull;
 if (typeof forceState === 'boolean') {
 if (forceState) container.classList.add('cr-full-window');
 else container.classList.remove('cr-full-window');
 isFull = forceState;
 } else {
 isFull = container.classList.toggle('cr-full-window');
 }

 if (btn) {
 btn.innerText = isFull ? '⛶ Normal Window' : '⛶ Full Window';
 }
 localStorage.setItem('configReader_fullWindow', isFull ? 'true' : 'false');

 setTimeout(() =&gt; {
 if (editorInstance) editorInstance.layout();
 }, 150);
}

function foldAll() {
 if (!editorInstance) return;
 editorInstance.getAction('editor.foldAll').run();
}

function unfoldAll() {
 if (!editorInstance) return;
 editorInstance.getAction('editor.unfoldAll').run();
}

function onVendorChange() {
 const vendor = document.getElementById('vendorSelect').value;
 if (!editorInstance) return;
 
 const langMap = {
 'huawei': 'huawei-vrp',
 'cisco': 'cisco-ios',
 'juniper': 'huawei-vrp',
 'arista': 'cisco-ios'
 };
 monaco.editor.setModelLanguage(editorInstance.getModel(), langMap[vendor] || 'huawei-vrp');
 analyzeVpnInstances();
 analyzeInterfaceReferences();
 analyzeProfiles();
 updateFoldingIndex();
 analyzeConfiguration();
}

function onThemeChange() {
 const theme = document.getElementById('themeSelect').value;
 if (!editorInstance) return;

 monaco.editor.setTheme(theme);
 localStorage.setItem('configReader_theme', theme);

 const container = document.getElementById('crContainer');
 if (container) {
 if (theme.includes('dark')) {
 container.classList.add('cr-dark');
 } else {
 container.classList.remove('cr-dark');
 }
 }
}

function analyzeConfiguration() {
 if (!editorInstance) return;
 const model = editorInstance.getModel();
 if (!model) return;

 const content = model.getValue();
 const lines = content.split('\n');

 const newDecorations = [];
 lines.forEach((lineText, idx) =&gt; {
 const lineNum = idx + 1;

 // Encrypted cipher decoration
 const cipherRegex = /%^%#[^%]+%^%#/g;
 let match;
 while ((match = cipherRegex.exec(lineText)) !== null) {
 newDecorations.push({
 range: new monaco.Range(lineNum, match.index + 1, lineNum, match.index + 1 + match[0].length),
 options: {
 inlineClassName: 'monaco-cipher-highlight',
 hoverMessage: { value: '🔒 Encrypted Cipher Key String' }
 }
 });
 }

 // Apply User Selected Text Highlights across entire document
 textHighlightMap.forEach((colorClass, textSnippet) =&gt; {
 const escText = textSnippet.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&amp;');
 const hlRegex = new RegExp(escText, 'gi');
 let hlMatch;
 while ((hlMatch = hlRegex.exec(lineText)) !== null) {
 newDecorations.push({
 range: new monaco.Range(lineNum, hlMatch.index + 1, lineNum, hlMatch.index + 1 + hlMatch[0].length),
 options: {
 inlineClassName: colorClass
 }
 });
 }
 });

 if (showReferenceLinks) {
 // VPN Instance dashed underline decoration
 const vpnRegex = /vpn-instance\s+([a-zA-Z0-9_\-]+)/gi;
 while ((match = vpnRegex.exec(lineText)) !== null) {
 newDecorations.push({
 range: new monaco.Range(lineNum, match.index + 1, lineNum, match.index + 1 + match[0].length),
 options: {
 inlineClassName: 'monaco-vpn-underline'
 }
 });
 }

 // Interface dashed underline decoration
 interfaceAnalysisMap.forEach((ifInfo) =&gt; {
 const escapedName = ifInfo.name.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&amp;');
 const ifRegex = new RegExp(`(?&lt;![a-zA-Z0-9_./-])${escapedName}(?![a-zA-Z0-9_./-])`, 'gi');
 let ifMatch;
 while ((ifMatch = ifRegex.exec(lineText)) !== null) {
 newDecorations.push({
 range: new monaco.Range(lineNum, ifMatch.index + 1, lineNum, ifMatch.index + 1 + ifMatch[0].length),
 options: {
 inlineClassName: 'monaco-interface-underline'
 }
 });
 }

 if (ifInfo.trunkId) {
 const ethTrunkRegex = new RegExp(`\\beth-trunk\\s+${ifInfo.trunkId}\\b`, 'gi');
 let trunkMatch;
 while ((trunkMatch = ethTrunkRegex.exec(lineText)) !== null) {
 newDecorations.push({
 range: new monaco.Range(lineNum, trunkMatch.index + 1, lineNum, trunkMatch.index + 1 + trunkMatch[0].length),
 options: {
 inlineClassName: 'monaco-interface-underline'
 }
 });
 }
 }
 });

 // Profile &amp; AAA Scheme dashed underline decoration
 profileAnalysisMap.forEach((profInfo) =&gt; {
 const escType = profInfo.type.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&amp;');
 const escBaseType = profInfo.baseType.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&amp;');
 const escName = profInfo.name.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&amp;');
 const profRegex = new RegExp(`\\b(?:${escType}|${escBaseType})\\s+(?:name\\s+|template\\s+)?${escName}\\b`, 'gi');
 let profMatch;
 while ((profMatch = profRegex.exec(lineText)) !== null) {
 newDecorations.push({
 range: new monaco.Range(lineNum, profMatch.index + 1, lineNum, profMatch.index + 1 + profMatch[0].length),
 options: {
 inlineClassName: 'monaco-profile-underline'
 }
 });
 }
 });
 }
 });

 currentDecorations = editorInstance.deltaDecorations(currentDecorations, newDecorations);
}

function copyConfig() {
 if (!editorInstance) return;
 const content = editorInstance.getValue();
 navigator.clipboard.writeText(content).then(() =&gt; {
 alert('Configuration copied to clipboard!');
 });
}

function downloadConfig() {
 if (!editorInstance) return;
 const content = editorInstance.getValue();
 const blob = new Blob([content], { type: 'text/plain;charset=utf-8' });
 const a = document.createElement('a');
 a.href = URL.createObjectURL(blob);
 a.download = `config-${Date.now()}.cfg`;
 a.click();
}
&lt;/script&gt;</description></item><item><title>Time &amp; Timestamp Tools</title><link>http://jony.ch/docs/tools/time/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>http://jony.ch/docs/tools/time/</guid><description>&lt;h1 id="time--timestamp-tools"&gt;Time &amp;amp; Timestamp Tools&lt;a class="anchor" href="#time--timestamp-tools"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;A comprehensive utility for real-time clock comparison, network time verification, timestamp conversion, and timezone calculations.&lt;/p&gt;
&lt;style&gt;
/* Modern styling for Time Tools */
.time-tools-wrapper {
 margin-top: 1.5rem;
 font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
 color: #1e293b;
}

/* Top Live Flip Clock Header Container */
.flip-clock-dashboard {
 background: linear-gradient(135deg, #0f172a 0%, #1e293b 100%);
 color: #ffffff;
 border-radius: 16px;
 padding: 1.8rem;
 box-shadow: 0 10px 25px -5px rgba(15, 23, 42, 0.25);
 margin-bottom: 2rem;
 position: relative;
 overflow: hidden;
}

.flip-clock-dashboard::after {
 content: '';
 position: absolute;
 top: -50%;
 right: -20%;
 width: 350px;
 height: 350px;
 background: radial-gradient(circle, rgba(59, 130, 246, 0.15) 0%, rgba(255,255,255,0) 70%);
 pointer-events: none;
}

.flip-dashboard-header {
 display: flex;
 justify-content: space-between;
 align-items: center;
 margin-bottom: 1.5rem;
 flex-wrap: wrap;
 gap: 0.8rem;
}

.flip-dashboard-title {
 font-size: 1.25rem;
 font-weight: 700;
 color: #f8fafc;
 display: flex;
 align-items: center;
 gap: 0.6rem;
}

.live-badge {
 display: inline-flex;
 align-items: center;
 gap: 0.4rem;
 background: rgba(34, 197, 94, 0.15);
 color: #4ade80;
 padding: 0.25rem 0.65rem;
 border-radius: 9999px;
 font-size: 0.75rem;
 font-weight: 600;
 border: 1px solid rgba(74, 222, 128, 0.3);
}

.live-dot {
 width: 8px;
 height: 8px;
 background-color: #22c55e;
 border-radius: 50%;
 box-shadow: 0 0 8px #22c55e;
 animation: pulse-dot 1.5s infinite;
}

@keyframes pulse-dot {
 0%, 100% { opacity: 1; transform: scale(1); }
 50% { opacity: 0.4; transform: scale(0.8); }
}

/* Flip Clocks Grid Layout */
.flip-clocks-grid {
 display: grid;
 grid-template-columns: repeat(auto-fit, minmax(310px, 1fr));
 gap: 1.5rem;
}

.flip-clock-panel {
 background: rgba(255, 255, 255, 0.05);
 border: 1px solid rgba(255, 255, 255, 0.1);
 border-radius: 12px;
 padding: 1.4rem;
 backdrop-filter: blur(8px);
}

.flip-panel-label {
 display: flex;
 justify-content: space-between;
 align-items: center;
 font-size: 0.9rem;
 color: #94a3b8;
 margin-bottom: 1rem;
 font-weight: 600;
}

.flip-clock-display {
 display: flex;
 align-items: center;
 justify-content: center;
 gap: 0.35rem;
}

/* Individual Flip Digit Cards */
.flip-group {
 display: flex;
 gap: 0.25rem;
}

.flip-card-unit {
 position: relative;
 width: 42px;
 height: 58px;
 background: #1e293b;
 border-radius: 8px;
 font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
 font-size: 2.1rem;
 font-weight: 800;
 color: #38bdf8;
 display: flex;
 align-items: center;
 justify-content: center;
 box-shadow: 0 4px 10px rgba(0, 0, 0, 0.3), inset 0 1px 0 rgba(255, 255, 255, 0.12);
 border: 1px solid rgba(255, 255, 255, 0.12);
 overflow: hidden;
 perspective: 300px;
}

.flip-card-unit::after {
 content: '';
 position: absolute;
 top: 50%;
 left: 0;
 right: 0;
 height: 1px;
 background: rgba(0, 0, 0, 0.5);
 box-shadow: 0 1px 0 rgba(255, 255, 255, 0.1);
 z-index: 5;
}

.flip-card-inner {
 display: flex;
 align-items: center;
 justify-content: center;
 width: 100%;
 height: 100%;
 transition: transform 0.25s ease-in-out;
}

.flip-card-unit.do-flip .flip-card-inner {
 animation: flipLeaf 0.4s ease-in-out;
}

@keyframes flipLeaf {
 0% { transform: rotateX(0deg); }
 50% { transform: rotateX(-90deg); filter: brightness(1.2); }
 100% { transform: rotateX(0deg); }
}

.flip-separator {
 font-size: 1.8rem;
 font-weight: 800;
 color: #38bdf8;
 margin: 0 0.15rem;
 animation: blink-colon 1s infinite;
}

@keyframes blink-colon {
 0%, 100% { opacity: 1; }
 50% { opacity: 0.3; }
}

.flip-panel-date {
 text-align: center;
 font-size: 0.85rem;
 color: #64748b;
 margin-top: 0.8rem;
 font-family: ui-monospace, SFMono-Regular, monospace;
}

/* Tool Sections Styling */
.tool-section {
 background: #ffffff;
 border: 1px solid #e2e8f0;
 border-radius: 16px;
 padding: 1.8rem;
 margin-bottom: 2rem;
 box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.03);
}

.section-title {
 font-size: 1.35rem;
 font-weight: 700;
 color: #0f172a;
 margin-top: 0;
 margin-bottom: 1.2rem;
 display: flex;
 align-items: center;
 gap: 0.6rem;
 border-bottom: 2px solid #f1f5f9;
 padding-bottom: 0.8rem;
}

.section-icon {
 display: inline-flex;
 align-items: center;
 justify-content: center;
 width: 34px;
 height: 34px;
 background: #eff6ff;
 color: #2563eb;
 border-radius: 8px;
 font-size: 1.1rem;
}

/* Time Sync Grid */
.sync-grid {
 display: grid;
 grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
 gap: 1.2rem;
 margin-bottom: 1.5rem;
}

.sync-card {
 background: #f8fafc;
 border: 1px solid #e2e8f0;
 border-radius: 12px;
 padding: 1.2rem;
 transition: transform 0.2s ease, box-shadow 0.2s ease;
}

.sync-card:hover {
 transform: translateY(-2px);
 box-shadow: 0 6px 12px -2px rgba(0,0,0,0.05);
}

.sync-card-header {
 font-size: 0.9rem;
 font-weight: 600;
 color: #64748b;
 margin-bottom: 0.5rem;
 display: flex;
 justify-content: space-between;
 align-items: center;
}

.sync-card-time {
 font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
 font-size: 1.3rem;
 font-weight: 700;
 color: #0f172a;
}

.sync-card-date {
 font-size: 0.85rem;
 color: #64748b;
 margin-top: 0.2rem;
}

/* Offset Banner */
.offset-banner {
 background: #f0f9ff;
 border: 1px solid #bae6fd;
 border-radius: 10px;
 padding: 1rem 1.2rem;
 display: flex;
 align-items: center;
 justify-content: space-between;
 flex-wrap: wrap;
 gap: 1rem;
}

.offset-info {
 display: flex;
 align-items: center;
 gap: 0.8rem;
}

.offset-text {
 font-size: 0.95rem;
 color: #0369a1;
 font-weight: 500;
}

.offset-text strong {
 color: #0c4a6e;
 font-family: monospace;
}

/* Buttons */
.btn-primary {
 background-color: #CF0A2C;
 color: #ffffff;
 border: none;
 padding: 0.6rem 1.2rem;
 border-radius: 8px;
 font-weight: 600;
 font-size: 0.9rem;
 cursor: pointer;
 transition: background-color 0.2s ease, transform 0.1s ease;
 display: inline-flex;
 align-items: center;
 gap: 0.4rem;
}

.btn-primary:hover {
 background-color: #b00824;
}

.btn-primary:active {
 transform: scale(0.98);
}

.btn-secondary {
 background-color: #f1f5f9;
 color: #334155;
 border: 1px solid #cbd5e1;
 padding: 0.5rem 0.9rem;
 border-radius: 6px;
 font-weight: 500;
 font-size: 0.85rem;
 cursor: pointer;
 transition: all 0.2s ease;
}

.btn-secondary:hover {
 background-color: #e2e8f0;
 color: #0f172a;
}

/* Converter Inputs */
.form-grid {
 display: grid;
 grid-template-columns: 1fr;
 gap: 1.5rem;
}

@media (min-width: 768px) {
 .form-grid-2col {
 grid-template-columns: 1fr 1fr;
 }
}

.input-group {
 margin-bottom: 1.2rem;
}

.input-group label {
 display: block;
 font-weight: 600;
 font-size: 0.9rem;
 color: #334155;
 margin-bottom: 0.4rem;
}

.input-control {
 width: 100%;
 padding: 0.65rem 0.9rem;
 border: 1px solid #cbd5e1;
 border-radius: 8px;
 font-size: 0.95rem;
 font-family: inherit;
 box-sizing: border-box;
 background-color: #ffffff;
 transition: border-color 0.2s ease, box-shadow 0.2s ease;
}

.input-control:focus {
 outline: none;
 border-color: #3b82f6;
 box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.15);
}

.preset-pills {
 display: flex;
 flex-wrap: wrap;
 gap: 0.5rem;
 margin-top: 0.6rem;
}

.preset-pill {
 background: #f1f5f9;
 border: 1px solid #e2e8f0;
 color: #475569;
 padding: 0.3rem 0.75rem;
 border-radius: 9999px;
 font-size: 0.8rem;
 cursor: pointer;
 transition: all 0.15s ease;
}

.preset-pill:hover {
 background: #e2e8f0;
 color: #0f172a;
 border-color: #cbd5e1;
}

/* Output Box */
.output-box {
 background: #f8fafc;
 border: 1px solid #e2e8f0;
 border-radius: 10px;
 padding: 1rem;
}

.output-row {
 display: flex;
 justify-content: space-between;
 align-items: center;
 padding: 0.6rem 0;
 border-bottom: 1px dashed #e2e8f0;
}

.output-row:last-child {
 border-bottom: none;
}

.output-label {
 font-size: 0.85rem;
 font-weight: 600;
 color: #64748b;
 width: 140px;
 flex-shrink: 0;
}

.output-value-group {
 display: flex;
 align-items: center;
 gap: 0.5rem;
 flex-grow: 1;
 justify-content: flex-end;
 overflow: hidden;
}

.output-value {
 font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
 font-size: 0.95rem;
 font-weight: 600;
 color: #0f172a;
 word-break: break-all;
 text-align: right;
}

.unit-badge {
 display: inline-block;
 background: #e0f2fe;
 color: #0369a1;
 font-size: 0.75rem;
 font-weight: 600;
 padding: 0.15rem 0.4rem;
 border-radius: 4px;
}
&lt;/style&gt;
&lt;div class="time-tools-wrapper"&gt;
 &lt;!-- TOP HEADER: LIVE RETRO FLIP CLOCKS --&gt;
 &lt;div class="flip-clock-dashboard"&gt;
 &lt;div class="flip-dashboard-header"&gt;
 &lt;div class="flip-dashboard-title"&gt;
 &lt;span&gt;⏱️ Live Local &amp; Network Standard Time&lt;/span&gt;
 &lt;span class="live-badge"&gt;
 &lt;span class="live-dot"&gt;&lt;/span&gt; LIVE
 &lt;/span&gt;
 &lt;/div&gt;
 &lt;/div&gt;
 &lt;div class="flip-clocks-grid"&gt;
 &lt;!-- Local Flip Clock Panel --&gt;
 &lt;div class="flip-clock-panel"&gt;
 &lt;div class="flip-panel-label"&gt;
 &lt;span&gt;💻 Local Device Time&lt;/span&gt;
 &lt;span id="flipLocalTz" style="color: #38bdf8; font-size: 0.8rem;"&gt;GMT+02:00&lt;/span&gt;
 &lt;/div&gt;
 &lt;div class="flip-clock-display"&gt;
 &lt;div class="flip-group"&gt;
 &lt;div class="flip-card-unit" id="lh1"&gt;&lt;div class="flip-card-inner"&gt;0&lt;/div&gt;&lt;/div&gt;
 &lt;div class="flip-card-unit" id="lh2"&gt;&lt;div class="flip-card-inner"&gt;0&lt;/div&gt;&lt;/div&gt;
 &lt;/div&gt;
 &lt;div class="flip-separator"&gt;:&lt;/div&gt;
 &lt;div class="flip-group"&gt;
 &lt;div class="flip-card-unit" id="lm1"&gt;&lt;div class="flip-card-inner"&gt;0&lt;/div&gt;&lt;/div&gt;
 &lt;div class="flip-card-unit" id="lm2"&gt;&lt;div class="flip-card-inner"&gt;0&lt;/div&gt;&lt;/div&gt;
 &lt;/div&gt;
 &lt;div class="flip-separator"&gt;:&lt;/div&gt;
 &lt;div class="flip-group"&gt;
 &lt;div class="flip-card-unit" id="ls1"&gt;&lt;div class="flip-card-inner"&gt;0&lt;/div&gt;&lt;/div&gt;
 &lt;div class="flip-card-unit" id="ls2"&gt;&lt;div class="flip-card-inner"&gt;0&lt;/div&gt;&lt;/div&gt;
 &lt;/div&gt;
 &lt;/div&gt;
 &lt;div class="flip-panel-date" id="flipLocalDate"&gt;2026-07-23&lt;/div&gt;
 &lt;/div&gt;
 &lt;!-- Network Standard Time (Local Timezone) Flip Clock Panel --&gt;
 &lt;div class="flip-clock-panel"&gt;
 &lt;div class="flip-panel-label"&gt;
 &lt;span&gt;🌐 Network Standard Time&lt;/span&gt;
 &lt;span id="flipNetTz" style="color: #4ade80; font-size: 0.8rem;"&gt;GMT+02:00&lt;/span&gt;
 &lt;/div&gt;
 &lt;div class="flip-clock-display"&gt;
 &lt;div class="flip-group"&gt;
 &lt;div class="flip-card-unit" id="nh1"&gt;&lt;div class="flip-card-inner"&gt;0&lt;/div&gt;&lt;/div&gt;
 &lt;div class="flip-card-unit" id="nh2"&gt;&lt;div class="flip-card-inner"&gt;0&lt;/div&gt;&lt;/div&gt;
 &lt;/div&gt;
 &lt;div class="flip-separator"&gt;:&lt;/div&gt;
 &lt;div class="flip-group"&gt;
 &lt;div class="flip-card-unit" id="nm1"&gt;&lt;div class="flip-card-inner"&gt;0&lt;/div&gt;&lt;/div&gt;
 &lt;div class="flip-card-unit" id="nm2"&gt;&lt;div class="flip-card-inner"&gt;0&lt;/div&gt;&lt;/div&gt;
 &lt;/div&gt;
 &lt;div class="flip-separator"&gt;:&lt;/div&gt;
 &lt;div class="flip-group"&gt;
 &lt;div class="flip-card-unit" id="ns1"&gt;&lt;div class="flip-card-inner"&gt;0&lt;/div&gt;&lt;/div&gt;
 &lt;div class="flip-card-unit" id="ns2"&gt;&lt;div class="flip-card-inner"&gt;0&lt;/div&gt;&lt;/div&gt;
 &lt;/div&gt;
 &lt;/div&gt;
 &lt;div class="flip-panel-date" id="flipNetDate"&gt;2026-07-23&lt;/div&gt;
 &lt;/div&gt;
 &lt;/div&gt;
 &lt;/div&gt;
 &lt;!-- SECTION 1: Clock Comparison &amp; Sync --&gt;
 &lt;div class="tool-section"&gt;
 &lt;h2 class="section-title"&gt;
 &lt;span class="section-icon"&gt;🌐&lt;/span&gt; 1. Clock Comparison &amp; Sync (Local &amp; Standard Time)
 &lt;/h2&gt;
 &lt;p style="color: #64748b; margin-bottom: 1.2rem; font-size: 0.95rem;"&gt;
 Compare your device's local clock against UTC, Central European Time (CET/CEST), and major global timezones.
 &lt;/p&gt;</description></item></channel></rss>