diff --git a/project_structure.json b/project_structure.json
index 55cbd1ed5d920d4f753cbe5d28b922fb3cc161d3..5fffa51cd401c0d5f38bd14aec351c110fd33961 100644
--- a/project_structure.json
+++ b/project_structure.json
@@ -1,7 +1,7 @@
 {
   "src": {
     "renderers": {
-      "MeasurementRenderer.js": "import Plotly from 'plotly.js-dist';\n\nexport function renderMeasurementResults(measurementResults, language) {\n  console.debug('renderMeasurementResults called with:', measurementResults);\n  const container = document.getElementById('measurementResults');\n  container.innerHTML = '';\n\n  if (!measurementResults) {\n    console.error('No measurementResults provided.');\n    return;\n  }\n\n  let result = measurementResults['dcc:measurementResult'];\n  console.debug('Raw dcc:measurementResult:', result);\n\n  if (!result) {\n    console.error(\"Missing 'dcc:measurementResult' in measurementResults\");\n    return;\n  }\n\n  if (!Array.isArray(result)) {\n    result = [result];\n  }\n  console.debug('Processed measurement result array:', result);\n\n  // Use the first measurement result for rendering\n  result = result[0];\n\n  // Get the measurement result name from dcc:name\n  let resultName = 'Measurement Result';\n  if (result['dcc:name'] && result['dcc:name']['dcc:content']) {\n    let content = result['dcc:name']['dcc:content'];\n    if (Array.isArray(content)) {\n      const match = content.find(item => item.$ && item.$.lang === language) || content[0];\n      resultName = match._ || match;\n    } else {\n      resultName = content._ || content;\n    }\n  }\n  console.debug('Result name:', resultName);\n\n  const tabTitle = document.createElement('h2');\n  tabTitle.textContent = resultName + ' (' + language + ')';\n  container.appendChild(tabTitle);\n\n  if (!result['dcc:data'] || !result['dcc:data']['dcc:list']) {\n    console.error(\"Missing 'dcc:data' or 'dcc:list' in measurement result:\", result);\n    return;\n  }\n  const listData = result['dcc:data']['dcc:list'];\n  console.debug('List data:', listData);\n\n  // Flatten all quantities from the list\n  let quantities = [];\n  if (listData['dcc:quantity']) {\n    quantities = Array.isArray(listData['dcc:quantity']) ? listData['dcc:quantity'] : [listData['dcc:quantity']];\n  }\n  console.debug('Quantities from list:', quantities);\n\n  // Also add quantities from measurementMetaData\n  if (listData['dcc:measurementMetaData'] && listData['dcc:measurementMetaData']['dcc:metaData']) {\n    let metaData = listData['dcc:measurementMetaData']['dcc:metaData'];\n    if (!Array.isArray(metaData)) metaData = [metaData];\n    metaData.forEach(md => {\n      if (md['dcc:data'] && md['dcc:data']['dcc:quantity']) {\n        let qs = md['dcc:data']['dcc:quantity'];\n        if (!Array.isArray(qs)) qs = [qs];\n        quantities = quantities.concat(qs);\n      }\n    });\n  }\n  console.debug('Combined quantities:', quantities);\n\n  // Separate index quantities and data quantities\n  const indexQuantities = [];\n  const dataQuantities = [];\n  quantities.forEach(q => {\n    if (q.$ && q.$.refType && q.$.refType.match(/basic_tableIndex/)) {\n      indexQuantities.push(q);\n    } else {\n      dataQuantities.push(q);\n    }\n  });\n  console.debug('Index Quantities:', indexQuantities);\n  console.debug('Data Quantities:', dataQuantities);\n\n  // Create radio buttons for X-axis selection (from indexQuantities)\n  const xAxisContainer = document.createElement('div');\n  xAxisContainer.innerHTML = '<strong>Select X-Axis:</strong> ';\n  indexQuantities.forEach((q, idx) => {\n    let nameStr = 'Index ' + idx;\n    if (q['dcc:name'] && q['dcc:name']['dcc:content']) {\n      let content = q['dcc:name']['dcc:content'];\n      if (Array.isArray(content)) {\n        const match = content.find(item => item.$ && item.$.lang === language) || content[0];\n        nameStr = match._ || match;\n      } else {\n        nameStr = content._ || content;\n      }\n    }\n    const radio = document.createElement('input');\n    radio.type = 'radio';\n    radio.name = 'xAxisSelect';\n    radio.value = idx;\n    if (idx === 0) radio.checked = true;\n    const label = document.createElement('label');\n    label.textContent = nameStr;\n    label.style.marginRight = '10px';\n    xAxisContainer.appendChild(radio);\n    xAxisContainer.appendChild(label);\n  });\n  container.appendChild(xAxisContainer);\n\n  // Tolerance toggle (placeholder)\n  const toleranceToggle = document.createElement('input');\n  toleranceToggle.type = 'checkbox';\n  toleranceToggle.id = 'toleranceToggle';\n  const tolLabel = document.createElement('label');\n  tolLabel.htmlFor = 'toleranceToggle';\n  tolLabel.textContent = ' Enable tolerance markings';\n  const tolContainer = document.createElement('div');\n  tolContainer.appendChild(toleranceToggle);\n  tolContainer.appendChild(tolLabel);\n  container.appendChild(tolContainer);\n\n  // Create containers for plots and table\n  const plotsContainer = document.createElement('div');\n  plotsContainer.id = 'plotsContainer';\n  container.appendChild(plotsContainer);\n  const tableContainer = document.createElement('div');\n  tableContainer.id = 'tableContainer';\n  container.appendChild(tableContainer);\n\n  // Function to update the visualization\n  function updateVisualization() {\n    const selectedRadio = document.querySelector('input[name=\"xAxisSelect\"]:checked');\n    if (!selectedRadio) {\n      console.error('No X-Axis selection found.');\n      return;\n    }\n    const selectedIndex = selectedRadio.value;\n    const xQuantity = indexQuantities[selectedIndex];\n    let xValues = [];\n    if (xQuantity && xQuantity['si:realListXMLList'] && xQuantity['si:realListXMLList']['si:valueXMLList']) {\n      xValues = xQuantity['si:realListXMLList']['si:valueXMLList'].trim().split(/\\s+/).map(v => parseFloat(v));\n    }\n    console.debug('Selected X-Axis values:', xValues);\n\n    // Build table headers and values\n    const headers = [];\n    let xHeader = 'X-Axis';\n    if (xQuantity['dcc:name'] && xQuantity['dcc:name']['dcc:content']) {\n      let content = xQuantity['dcc:name']['dcc:content'];\n      if (Array.isArray(content)) {\n        const match = content.find(item => item.$ && item.$.lang === language) || content[0];\n        xHeader = match._ || match;\n      } else {\n        xHeader = content._ || content;\n      }\n    }\n    headers.push(xHeader);\n\n    const dataValues = [];\n    dataQuantities.forEach(q => {\n      let header = 'Data';\n      if (q['dcc:name'] && q['dcc:name']['dcc:content']) {\n        let content = q['dcc:name']['dcc:content'];\n        if (Array.isArray(content)) {\n          const match = content.find(item => item.$ && item.$.lang === language) || content[0];\n          header = match._ || match;\n        } else {\n          header = content._ || content;\n        }\n      }\n      headers.push(header);\n      let values = [];\n      if (q['si:realListXMLList'] && q['si:realListXMLList']['si:valueXMLList']) {\n        values = q['si:realListXMLList']['si:valueXMLList'].trim().split(/\\s+/).map(v => parseFloat(v));\n      }\n      if (values.length === 1 && xValues.length > 1) {\n        values = new Array(xValues.length).fill(values[0]);\n      }\n      dataValues.push(values);\n    });\n\n    // Build table rows\n    const tableData = [headers];\n    for (let i = 0; i < xValues.length; i++) {\n      const row = [];\n      row.push(xValues[i]);\n      dataValues.forEach(values => {\n        row.push(values[i] !== undefined ? values[i] : '');\n      });\n      tableData.push(row);\n    }\n    console.debug('Table data:', tableData);\n    renderTable(tableData);\n\n    // Group data quantities by unit for plotting\n    const unitGroups = {};\n    dataQuantities.forEach((q, idx) => {\n      let unit = '';\n      if (q['si:realListXMLList'] && q['si:realListXMLList']['si:unitXMLList']) {\n        unit = q['si:realListXMLList']['si:unitXMLList'].trim();\n      }\n      if (!unitGroups[unit]) {\n        unitGroups[unit] = [];\n      }\n      let header = headers[idx + 1];\n      let values = [];\n      if (q['si:realListXMLList'] && q['si:realListXMLList']['si:valueXMLList']) {\n        values = q['si:realListXMLList']['si:valueXMLList'].trim().split(/\\s+/).map(v => parseFloat(v));\n      }\n      if (values.length === 1 && xValues.length > 1) {\n        values = new Array(xValues.length).fill(values[0]);\n      }\n      unitGroups[unit].push({ name: header, y: values });\n    });\n    console.debug('Unit groups for plots:', unitGroups);\n\n    // Clear and render plots\n    plotsContainer.innerHTML = '';\n    Object.keys(unitGroups).forEach(unit => {\n      const graphDiv = document.createElement('div');\n      graphDiv.style.width = '100%';\n      graphDiv.style.height = '300px';\n      plotsContainer.appendChild(graphDiv);\n\n      const traces = unitGroups[unit].map(trace => {\n        return {\n          x: xValues,\n          y: trace.y,\n          type: 'scatter',\n          mode: 'lines+markers',\n          name: trace.name\n        };\n      });\n      const layout = {\n        title: 'Plot (' + unit + ')',\n        xaxis: { title: xHeader },\n        yaxis: { title: unit },\n        hovermode: 'closest'\n      };\n      Plotly.newPlot(graphDiv, traces, layout).then(() => {\n        console.debug('Plot rendered for unit:', unit);\n      });\n\n      // Coupled mouseover events\n      graphDiv.on('plotly_hover', function(data) {\n        if (data.points && data.points.length > 0) {\n          const pointIndex = data.points[0].pointIndex + 1; // offset for header row\n          highlightTableRow(pointIndex);\n        }\n      });\n      graphDiv.on('plotly_unhover', function() {\n        clearTableRowHighlights();\n      });\n    });\n  }\n\n  // Render table from a 2D array\n  function renderTable(tableData) {\n    tableContainer.innerHTML = '';\n    const table = document.createElement('table');\n    tableData.forEach((rowData, rowIndex) => {\n      const tr = document.createElement('tr');\n      rowData.forEach(cellData => {\n        const cell = document.createElement(rowIndex === 0 ? 'th' : 'td');\n        cell.textContent = cellData;\n        cell.style.padding = '4px';\n        cell.style.border = '1px solid #ccc';\n        tr.appendChild(cell);\n      });\n      tr.addEventListener('mouseover', () => { tr.style.backgroundColor = '#eef'; });\n      tr.addEventListener('mouseout', () => { tr.style.backgroundColor = ''; });\n      table.appendChild(tr);\n    });\n    tableContainer.appendChild(table);\n  }\n\n  // Functions for coupled table row highlights\n  function highlightTableRow(rowIndex) {\n    const rows = tableContainer.querySelectorAll('tr');\n    if (rows[rowIndex]) {\n      rows[rowIndex].style.backgroundColor = '#fee';\n    }\n  }\n  function clearTableRowHighlights() {\n    const rows = tableContainer.querySelectorAll('tr');\n    rows.forEach(row => row.style.backgroundColor = '');\n  }\n\n  // Initial update\n  updateVisualization();\n\n  // Update visualization when X-axis selection changes\n  const radios = document.querySelectorAll('input[name=\"xAxisSelect\"]');\n  radios.forEach(radio => {\n    radio.addEventListener('change', updateVisualization);\n  });\n\n  // Tolerance toggle event (placeholder)\n  toleranceToggle.addEventListener('change', () => {\n    console.log('Tolerance toggle:', toleranceToggle.checked);\n    // Future: update plot/table for tolerance markings and color coding\n  });\n}\n"
+      "MeasurementRenderer.js": "import Plotly from 'plotly.js-dist';\n\n// Dummy unit converter: currently returns the raw unit (to be enhanced later)\nfunction convertUnit(rawUnit) {\n  return rawUnit;\n}\n\n// Define Tab10 palette and lighter shades for table backgrounds\nconst palette = [\n  '#1f77b4',\n  '#ff7f0e',\n  '#2ca02c',\n  '#d62728',\n  '#9467bd',\n  '#8c564b',\n  '#e377c2',\n  '#7f7f7f',\n  '#bcbd22',\n  '#17becf'\n];\n\nconst lightPalette = [\n  '#c6e2ff',\n  '#ffddbf',\n  '#c9e6c8',\n  '#f4c2c2',\n  '#dcd0ff',\n  '#e0cda9',\n  '#ffccff',\n  '#d3d3d3',\n  '#e6e6a9',\n  '#b3ffff'\n];\n\nexport function renderMeasurementResults(measurementResults, language) {\n  console.debug('renderMeasurementResults called with:', measurementResults);\n  const container = document.getElementById('measurementResults');\n  container.innerHTML = '';\n\n  if (!measurementResults) {\n    console.error('No measurementResults provided.');\n    return;\n  }\n\n  let results = measurementResults['dcc:measurementResult'];\n  console.debug('Raw dcc:measurementResult:', results);\n\n  if (!results) {\n    console.error(\"Missing 'dcc:measurementResult' in measurementResults\");\n    return;\n  }\n\n  if (!Array.isArray(results)) {\n    results = [results];\n  }\n  console.debug('Processed measurement result array:', results);\n\n  const measurementResult = results[0];\n  console.debug('Using measurementResult:', measurementResult);\n\n  // Extract the result object from dcc:results -> dcc:result\n  let resultObj = measurementResult['dcc:results'] && measurementResult['dcc:results']['dcc:result'];\n  if (!resultObj) {\n    console.error(\"Missing 'dcc:results' or 'dcc:result' in measurementResult:\", measurementResult);\n    return;\n  }\n  if (Array.isArray(resultObj)) {\n    resultObj = resultObj[0];\n  }\n  console.debug('Using result object:', resultObj);\n\n  // Get measurement result name without language tag\n  let resultName = 'Measurement Result';\n  if (measurementResult['dcc:name'] && measurementResult['dcc:name']['dcc:content']) {\n    let content = measurementResult['dcc:name']['dcc:content'];\n    if (Array.isArray(content)) {\n      const match = content.find(item => item.$ && item.$.lang === language) || content[0];\n      resultName = match._ || match;\n    } else {\n      resultName = content._ || content;\n    }\n  }\n  console.debug('Result name:', resultName);\n\n  const tabTitle = document.createElement('h2');\n  tabTitle.textContent = resultName;\n  container.appendChild(tabTitle);\n\n  if (!resultObj['dcc:data'] || !resultObj['dcc:data']['dcc:list']) {\n    console.error(\"Missing 'dcc:data' or 'dcc:list' in result object:\", resultObj);\n    return;\n  }\n  const listData = resultObj['dcc:data']['dcc:list'];\n  console.debug('List data:', listData);\n\n  // Flatten quantities from the list\n  let quantities = [];\n  if (listData['dcc:quantity']) {\n    quantities = Array.isArray(listData['dcc:quantity']) ? listData['dcc:quantity'] : [listData['dcc:quantity']];\n  }\n  console.debug('Quantities from list:', quantities);\n\n  // Also add quantities from measurementMetaData if available\n  if (listData['dcc:measurementMetaData'] && listData['dcc:measurementMetaData']['dcc:metaData']) {\n    let metaData = listData['dcc:measurementMetaData']['dcc:metaData'];\n    if (!Array.isArray(metaData)) metaData = [metaData];\n    metaData.forEach(md => {\n      if (md['dcc:data'] && md['dcc:data']['dcc:quantity']) {\n        let qs = md['dcc:data']['dcc:quantity'];\n        if (!Array.isArray(qs)) qs = [qs];\n        quantities = quantities.concat(qs);\n      }\n    });\n  }\n  console.debug('Combined quantities:', quantities);\n\n  // Separate index quantities and data quantities; extract extra info (uncertainty, comment, conformity)\n  const indexQuantities = [];\n  const dataQuantities = [];\n  const extraInfo = [];\n  quantities.forEach(q => {\n    if (q.$ && q.$.refType && q.$.refType.match(/basic_tableIndex/)) {\n      indexQuantities.push(q);\n    } else {\n      dataQuantities.push(q);\n      let uncertainty = null;\n      if (q['si:measurementUncertaintyUnivariateXMLList'] &&\n          q['si:measurementUncertaintyUnivariateXMLList']['si:expandedMUXMLList'] &&\n          q['si:measurementUncertaintyUnivariateXMLList']['si:expandedMUXMLList']['si:valueExpandedMUXMLList']) {\n        const errStr = q['si:measurementUncertaintyUnivariateXMLList']['si:expandedMUXMLList']['si:valueExpandedMUXMLList'];\n        uncertainty = errStr.trim().split(/\\s+/).map(v => parseFloat(v));\n      }\n      let comment = '';\n      let validArray = [];\n      let conformity = null;\n      if (q['dcc:measurementMetaData'] && q['dcc:measurementMetaData']['dcc:metaData']) {\n        let md = q['dcc:measurementMetaData']['dcc:metaData'];\n        if (!Array.isArray(md)) { md = [md]; }\n        md.forEach(item => {\n          if (item.$ && item.$.refType && item.$.refType.includes('basic_tableRowComment')) {\n            if (item['dcc:description'] && item['dcc:description']['dcc:content']) {\n              let desc = item['dcc:description']['dcc:content'];\n              if (Array.isArray(desc)) {\n                const match = desc.find(d => d.$ && d.$.lang === language) || desc[0];\n                comment = match._ || match;\n              } else {\n                comment = desc._ || desc;\n              }\n            }\n            if (item['dcc:validXMLList']) {\n              validArray = item['dcc:validXMLList'].trim().split(/\\s+/);\n            }\n          }\n          if (item.$ && item.$.refType && item.$.refType.includes('basic_conformity')) {\n            if (item['dcc:conformityXMLList']) {\n              conformity = item['dcc:conformityXMLList'].trim().split(/\\s+/);\n            }\n          }\n        });\n      }\n      extraInfo.push({ uncertainty, comment, valid: validArray, conformity });\n    }\n  });\n  console.debug('Index Quantities:', indexQuantities);\n  console.debug('Data Quantities:', dataQuantities);\n  console.debug('Extra info for data quantities:', extraInfo);\n\n  // Create radio buttons for X-axis selection\n  const xAxisContainer = document.createElement('div');\n  xAxisContainer.innerHTML = '<strong>Select X-Axis:</strong> ';\n  indexQuantities.forEach((q, idx) => {\n    let nameStr = 'Index ' + idx;\n    if (q['dcc:name'] && q['dcc:name']['dcc:content']) {\n      let content = q['dcc:name']['dcc:content'];\n      if (Array.isArray(content)) {\n        const match = content.find(item => item.$ && item.$.lang === language) || content[0];\n        nameStr = match._ || match;\n      } else {\n        nameStr = content._ || content;\n      }\n    }\n    const radio = document.createElement('input');\n    radio.type = 'radio';\n    radio.name = 'xAxisSelect';\n    radio.value = idx;\n    if (idx === 0) radio.checked = true;\n    const label = document.createElement('label');\n    label.textContent = nameStr;\n    label.style.marginRight = '10px';\n    xAxisContainer.appendChild(radio);\n    xAxisContainer.appendChild(label);\n  });\n  container.appendChild(xAxisContainer);\n\n  // Tolerance toggle (placeholder)\n  const toleranceToggle = document.createElement('input');\n  toleranceToggle.type = 'checkbox';\n  toleranceToggle.id = 'toleranceToggle';\n  const tolLabel = document.createElement('label');\n  tolLabel.htmlFor = 'toleranceToggle';\n  tolLabel.textContent = ' Enable tolerance markings';\n  const tolContainer = document.createElement('div');\n  tolContainer.appendChild(toleranceToggle);\n  tolContainer.appendChild(tolLabel);\n  container.appendChild(tolContainer);\n\n  // Create container for subplots\n  const subplotsContainer = document.createElement('div');\n  subplotsContainer.id = 'subplotsContainer';\n  container.appendChild(subplotsContainer);\n\n  // Create container for table\n  const tableContainer = document.createElement('div');\n  tableContainer.id = 'tableContainer';\n  container.appendChild(tableContainer);\n\n  // Function to update visualization\n  function updateVisualization() {\n    const selectedRadio = document.querySelector('input[name=\"xAxisSelect\"]:checked');\n    if (!selectedRadio) {\n      console.error('No X-Axis selection found.');\n      return;\n    }\n    const selectedIndex = selectedRadio.value;\n    const xQuantity = indexQuantities[selectedIndex];\n    let xValues = [];\n    let xUnit = '';\n    if (xQuantity && xQuantity['si:realListXMLList']) {\n      if (xQuantity['si:realListXMLList']['si:valueXMLList']) {\n        xValues = xQuantity['si:realListXMLList']['si:valueXMLList'].trim().split(/\\s+/).map(v => parseFloat(v));\n      }\n      if (xQuantity['si:realListXMLList']['si:unitXMLList']) {\n        xUnit = xQuantity['si:realListXMLList']['si:unitXMLList'].trim();\n      }\n    }\n    console.debug('Selected X-Axis values:', xValues);\n    console.debug('X-Axis unit:', xUnit);\n\n    // Build table headers and arrays for values, comments, conformity, uncertainties\n    const headers = [];\n    let xHeader = 'X-Axis (selected) (' + convertUnit(xUnit) + ')';\n    headers.push(xHeader);\n\n    const dataValues = [];\n    const commentsArray = [];\n    const conformityArray = [];\n    const uncertaintiesArray = [];\n    dataQuantities.forEach((q, idx) => {\n      let header = 'Data';\n      let unit = '';\n      if (q['dcc:name'] && q['dcc:name']['dcc:content']) {\n        let content = q['dcc:name']['dcc:content'];\n        if (Array.isArray(content)) {\n          const match = content.find(item => item.$ && item.$.lang === language) || content[0];\n          header = match._ || match;\n        } else {\n          header = content._ || content;\n        }\n      }\n      if (q['si:realListXMLList'] && q['si:realListXMLList']['si:unitXMLList']) {\n        unit = q['si:realListXMLList']['si:unitXMLList'].trim();\n      }\n      headers.push(header + ' in ' + convertUnit(unit));\n      headers.push('Comments');\n      // Add conformity header only if data exists\n      if (extraInfo[idx] && extraInfo[idx].conformity) {\n        headers.push('Conformity');\n      } else {\n        headers.push('');\n      }\n\n      let values = [];\n      if (q['si:realListXMLList'] && q['si:realListXMLList']['si:valueXMLList']) {\n        values = q['si:realListXMLList']['si:valueXMLList'].trim().split(/\\s+/).map(v => parseFloat(v));\n      }\n      if (values.length === 1 && xValues.length > 1) {\n        values = new Array(xValues.length).fill(values[0]);\n      }\n      dataValues.push(values);\n\n      let uncertainty = null;\n      if (extraInfo[idx] && extraInfo[idx].uncertainty) {\n        uncertainty = extraInfo[idx].uncertainty;\n      }\n      uncertaintiesArray.push(uncertainty);\n\n      let comment = extraInfo[idx] ? extraInfo[idx].comment : '';\n      commentsArray.push(comment);\n\n      let conformity = [];\n      if (extraInfo[idx] && extraInfo[idx].conformity) {\n        conformity = extraInfo[idx].conformity;\n      }\n      conformityArray.push(conformity);\n    });\n\n    const tableData = [headers];\n    for (let i = 0; i < xValues.length; i++) {\n      const row = [];\n      row.push(xValues[i]);\n      dataValues.forEach((values, idx) => {\n        let cellValue = values[i] !== undefined ? values[i] : '';\n        if (uncertaintiesArray[idx] && uncertaintiesArray[idx][i] !== undefined) {\n          cellValue = cellValue + ' ± ' + uncertaintiesArray[idx][i];\n        }\n        row.push(cellValue);\n        row.push(commentsArray[idx] || '');\n        if (conformityArray[idx] && conformityArray[idx][i]) {\n          row.push(conformityArray[idx][i]);\n        } else {\n          row.push('');\n        }\n      });\n      tableData.push(row);\n    }\n    console.debug('Table data:', tableData);\n    renderTable(tableData);\n\n    // Group data quantities by unit for plotting and assign colors\n    const unitGroups = {};\n    dataQuantities.forEach((q, idx) => {\n      let unit = '';\n      if (q['si:realListXMLList'] && q['si:realListXMLList']['si:unitXMLList']) {\n        unit = q['si:realListXMLList']['si:unitXMLList'].trim();\n      }\n      if (!unitGroups[unit]) {\n        unitGroups[unit] = [];\n      }\n      let header = headers[idx * 3 + 1];\n      let values = [];\n      if (q['si:realListXMLList'] && q['si:realListXMLList']['si:valueXMLList']) {\n        values = q['si:realListXMLList']['si:valueXMLList'].trim().split(/\\s+/).map(v => parseFloat(v));\n      }\n      if (values.length === 1 && xValues.length > 1) {\n        values = new Array(xValues.length).fill(values[0]);\n      }\n      let uncertainty = uncertaintiesArray[idx];\n      let conformity = [];\n      if (conformityArray[idx]) {\n        conformity = conformityArray[idx];\n      }\n      // Use Tab10 palette; assign a color for this data quantity\n      let traceColor = palette[idx % palette.length];\n      unitGroups[unit].push({ name: header, y: values, uncertainty: uncertainty, conformity: conformity, color: traceColor, index: idx });\n    });\n    console.debug('Unit groups for plots:', unitGroups);\n\n    // Build plots: one subplot per unit group, sharing the same X-axis\n    const plotsContainer = document.getElementById('subplotsContainer');\n    plotsContainer.innerHTML = '';\n    const unitKeys = Object.keys(unitGroups);\n    unitKeys.forEach((unit, groupIdx) => {\n      const group = unitGroups[unit];\n      const graphDiv = document.createElement('div');\n      graphDiv.style.width = '100%';\n      graphDiv.style.height = '300px';\n      plotsContainer.appendChild(graphDiv);\n\n      // Build traces for this group\n      const groupTraces = group.map(trace => {\n        // Prepare tooltip with short format\n        const hovertemplate = 'X: %{x} ' + convertUnit(xUnit) + ' | ' + trace.name + ': %{y} ± %{error_y.array} ' + convertUnit(unit) + ' | Conformity: %{customdata}<extra></extra>';\n        return {\n          x: xValues,\n          y: trace.y,\n          error_y: { type: 'data', array: trace.uncertainty || new Array(xValues.length).fill(0), visible: true, color: trace.color },\n          type: 'scatter',\n          mode: 'lines+markers',\n          name: trace.name,\n          marker: { color: trace.color },\n          hovertemplate: hovertemplate,\n          customdata: (trace.conformity && trace.conformity.length === xValues.length) ? trace.conformity : new Array(xValues.length).fill('')\n        };\n      });\n\n      // Only the last subplot gets an X-axis label\n      let xaxisTitle = '';\n      if (groupIdx === unitKeys.length - 1) {\n        let xLabel = 'X: ';\n        if (xQuantity['dcc:name'] && xQuantity['dcc:name']['dcc:content']) {\n          let content = xQuantity['dcc:name']['dcc:content'];\n          if (Array.isArray(content)) {\n            const match = content.find(item => item.$ && item.$.lang === language) || content[0];\n            xLabel += match._ || match;\n          } else {\n            xLabel += content._ || content;\n          }\n        }\n        xaxisTitle = xLabel + ' in ' + convertUnit(xUnit);\n      }\n\n      const layout = {\n        xaxis: { title: { text: xaxisTitle, font: { size: 18, family: 'Arial', color: 'black' } }, tickfont: { family: 'Arial', size: 14, color: 'black' } },\n        yaxis: { title: { text: convertUnit(unit), font: { size: 18, family: 'Arial', color: 'black' } }, tickfont: { family: 'Arial', size: 14, color: 'black' } },\n        hovermode: 'closest',\n        margin: { t: 20, b: 40 }\n      };\n\n      Plotly.newPlot(graphDiv, groupTraces, layout).then(() => {\n        console.debug('Plot rendered for unit:', unit);\n        // Bold caption above the plot: \"QuantityName in Unit\"; remove duplicate unit if any\n        const caption = document.createElement('div');\n        caption.innerHTML = '<b>' + group[0].name + ' in ' + convertUnit(unit) + '</b>';\n        caption.style.textAlign = 'center';\n        caption.style.marginBottom = '5px';\n        graphDiv.parentNode.insertBefore(caption, graphDiv);\n      });\n\n      graphDiv.on('plotly_hover', function(data) {\n        if (data.points && data.points.length > 0) {\n          const pointIndex = data.points[0].pointIndex + 1; // offset for header row\n          highlightTableRow(pointIndex);\n        }\n      });\n      graphDiv.on('plotly_unhover', function() {\n        clearTableRowHighlights();\n      });\n    });\n  }\n\n  // Render table from a 2D array with colored backgrounds for data columns\n  function renderTable(tableData) {\n    const tableContainer = document.getElementById('tableContainer');\n    tableContainer.innerHTML = '';\n    const table = document.createElement('table');\n    tableData.forEach((rowData, rowIndex) => {\n      const tr = document.createElement('tr');\n      rowData.forEach((cellData, cellIndex) => {\n        const cell = document.createElement(rowIndex === 0 ? 'th' : 'td');\n        cell.textContent = cellData;\n        cell.style.padding = '4px';\n        cell.style.border = '1px solid #ccc';\n        if (rowIndex === 0 && cellIndex > 0) {\n          const dataIndex = Math.floor((cellIndex - 1) / 3);\n          cell.style.backgroundColor = lightPalette[dataIndex % lightPalette.length];\n        }\n        tr.appendChild(cell);\n      });\n      tr.addEventListener('mouseover', () => { tr.style.backgroundColor = '#eef'; });\n      tr.addEventListener('mouseout', () => { tr.style.backgroundColor = ''; });\n      table.appendChild(tr);\n    });\n    tableContainer.appendChild(table);\n  }\n\n  function highlightTableRow(rowIndex) {\n    const rows = document.getElementById('tableContainer').querySelectorAll('tr');\n    if (rows[rowIndex]) {\n      rows[rowIndex].style.backgroundColor = '#fee';\n    }\n  }\n\n  function clearTableRowHighlights() {\n    const rows = document.getElementById('tableContainer').querySelectorAll('tr');\n    rows.forEach(row => row.style.backgroundColor = '');\n  }\n\n  updateVisualization();\n\n  const radios = document.querySelectorAll('input[name=\"xAxisSelect\"]');\n  radios.forEach(radio => {\n    radio.addEventListener('change', updateVisualization);\n  });\n\n  toleranceToggle.addEventListener('change', () => {\n    console.log('Tolerance toggle:', toleranceToggle.checked);\n    // Future: update plot/table for tolerance markings and color coding\n  });\n}\n"
     }
   }
 }
diff --git a/readME.md b/readME.md
new file mode 100644
index 0000000000000000000000000000000000000000..e7dd35db0ad2249bca252e3e8f4811ad58bc080f
--- /dev/null
+++ b/readME.md
@@ -0,0 +1,76 @@
+Below is a short README for your project that explains how to install, run in development mode, and serve a debug version with Python:
+
+---
+
+# DCC Viewer
+
+This is a front-end only digital calibration certificate viewer built with vanilla JavaScript, Vite, Plotly, xml2js, and JSONEditor. It converts a DCC XML file into JSON and renders administrative and measurement data with interactive plots, tables, and tooltips.
+
+## Features
+
+- **XML-to-JSON conversion:** Uses [xml2js](https://github.com/Leonidas-from-XIV/node-xml2js) to convert the calibration certificate XML into JSON.
+- **Interactive Measurement Renderer:** Displays measurement results as grouped subplots with error bars, custom tooltips (including conformity status), and a correlated data table.
+- **JSON Tree Viewer:** Uses [JSONEditor](https://github.com/josdejong/jsoneditor) for a modern, read-only view of the administrative data.
+- **Responsive UI:** Supports language switching and dynamic updates.
+
+## Installation
+
+1. Make sure you have [Node.js](https://nodejs.org/) installed.
+2. Clone the repository and navigate to the project directory.
+3. Install dependencies:
+
+   ```bash
+   npm install
+   ```
+
+## Development
+
+Start the Vite development server:
+
+```bash
+npm run dev
+```
+
+This will launch the app (usually on [http://localhost:5173/](http://localhost:5173/)). Changes to the source files will trigger hot reloading.
+
+## Serving the Debug Version with Python
+
+If you prefer to view the debug version using Python's built-in HTTP server, follow these steps:
+
+1. Build the project (or use the current static files in the project root):
+
+   ```bash
+   npm run build
+   ```
+
+   The output will be placed in the `dist` folder.
+
+2. Navigate to the `dist` folder:
+
+   ```bash
+   cd dist
+   ```
+
+3. Serve the folder using Python (Python 3):
+
+   ```bash
+   python3 -m http.server 8000
+   ```
+
+   This command will start a local server on port 8000.
+
+4. Open your browser and navigate to [http://localhost:8000](http://localhost:8000) to view the debug version.
+
+*Note:* You can also serve the project directly from the project root (if your files are static) by running the Python server there, but using the Vite build output (in `dist`) is recommended for a production-like environment.
+
+## Debugging
+
+- **Chrome Developer Tools:**  
+  Open the **Sources** tab and locate your source files (source maps are enabled by default with Vite) to set breakpoints and inspect variables.
+
+- **WebStorm:**  
+  Create a JavaScript Debug configuration (with URL `http://localhost:5173/`) and set breakpoints directly in the IDE.
+
+---
+
+This README should help you get started with development and debugging. Let me know if you need any additional information!
\ No newline at end of file
diff --git a/src/renderers/MeasurementRenderer.js b/src/renderers/MeasurementRenderer.js
index 8e119c8fb3010fc4a3205d9e3d5422581a410e55..5c44671553319db29cbeb87abf857b9e7fb8e8f6 100644
--- a/src/renderers/MeasurementRenderer.js
+++ b/src/renderers/MeasurementRenderer.js
@@ -1,5 +1,10 @@
 import Plotly from 'plotly.js-dist';
 
+// Dummy unit converter: currently returns the raw unit (to be enhanced later)
+function convertUnit(rawUnit) {
+  return rawUnit;
+}
+
 // Define Tab10 palette and lighter shades for table backgrounds
 const palette = [
   '#1f77b4',
@@ -88,7 +93,7 @@ export function renderMeasurementResults(measurementResults, language) {
   const listData = resultObj['dcc:data']['dcc:list'];
   console.debug('List data:', listData);
 
-  // Flatten all quantities from the list
+  // Flatten quantities from the list
   let quantities = [];
   if (listData['dcc:quantity']) {
     quantities = Array.isArray(listData['dcc:quantity']) ? listData['dcc:quantity'] : [listData['dcc:quantity']];
@@ -109,7 +114,7 @@ export function renderMeasurementResults(measurementResults, language) {
   }
   console.debug('Combined quantities:', quantities);
 
-  // Separate index quantities and data quantities; also extract extra info (uncertainty, comment, conformity)
+  // Separate index quantities and data quantities; extract extra info (uncertainty, comment, conformity)
   const indexQuantities = [];
   const dataQuantities = [];
   const extraInfo = [];
@@ -126,40 +131,34 @@ export function renderMeasurementResults(measurementResults, language) {
         uncertainty = errStr.trim().split(/\s+/).map(v => parseFloat(v));
       }
       let comment = '';
-      let conformity = '';
+      let validArray = [];
+      let conformity = null;
       if (q['dcc:measurementMetaData'] && q['dcc:measurementMetaData']['dcc:metaData']) {
         let md = q['dcc:measurementMetaData']['dcc:metaData'];
-        if (Array.isArray(md)) {
-          md.forEach(item => {
-            if (item.$ && item.$.refType && item.$.refType.includes('basic_tableRowComment')) {
-              if (item['dcc:description'] && item['dcc:description']['dcc:content']) {
-                comment = Array.isArray(item['dcc:description']['dcc:content']) ?
-                  (item['dcc:description']['dcc:content'][0]._ || item['dcc:description']['dcc:content'][0]) :
-                  (item['dcc:description']['dcc:content']._ || item['dcc:description']['dcc:content']);
+        if (!Array.isArray(md)) { md = [md]; }
+        md.forEach(item => {
+          if (item.$ && item.$.refType && item.$.refType.includes('basic_tableRowComment')) {
+            if (item['dcc:description'] && item['dcc:description']['dcc:content']) {
+              let desc = item['dcc:description']['dcc:content'];
+              if (Array.isArray(desc)) {
+                const match = desc.find(d => d.$ && d.$.lang === language) || desc[0];
+                comment = match._ || match;
+              } else {
+                comment = desc._ || desc;
               }
             }
-            if (item.$ && item.$.refType && item.$.refType.includes('basic_conformity')) {
-              if (item['dcc:conformityXMLList']) {
-                conformity = item['dcc:conformityXMLList'].trim();
-              }
-            }
-          });
-        } else {
-          if (md.$ && md.$.refType && md.$.refType.includes('basic_tableRowComment')) {
-            if (md['dcc:description'] && md['dcc:description']['dcc:content']) {
-              comment = Array.isArray(md['dcc:description']['dcc:content']) ?
-                (md['dcc:description']['dcc:content'][0]._ || md['dcc:description']['dcc:content'][0]) :
-                (md['dcc:description']['dcc:content']._ || md['dcc:description']['dcc:content']);
+            if (item['dcc:validXMLList']) {
+              validArray = item['dcc:validXMLList'].trim().split(/\s+/);
             }
           }
-          if (md.$ && md.$.refType && md.$.refType.includes('basic_conformity')) {
-            if (md['dcc:conformityXMLList']) {
-              conformity = md['dcc:conformityXMLList'].trim();
+          if (item.$ && item.$.refType && item.$.refType.includes('basic_conformity')) {
+            if (item['dcc:conformityXMLList']) {
+              conformity = item['dcc:conformityXMLList'].trim().split(/\s+/);
             }
           }
-        }
+        });
       }
-      extraInfo.push({ uncertainty, comment, conformity });
+      extraInfo.push({ uncertainty, comment, valid: validArray, conformity });
     }
   });
   console.debug('Index Quantities:', indexQuantities);
@@ -239,7 +238,7 @@ export function renderMeasurementResults(measurementResults, language) {
 
     // Build table headers and arrays for values, comments, conformity, uncertainties
     const headers = [];
-    let xHeader = 'X-Axis (' + xUnit + ')';
+    let xHeader = 'X-Axis (selected) (' + convertUnit(xUnit) + ')';
     headers.push(xHeader);
 
     const dataValues = [];
@@ -261,9 +260,14 @@ export function renderMeasurementResults(measurementResults, language) {
       if (q['si:realListXMLList'] && q['si:realListXMLList']['si:unitXMLList']) {
         unit = q['si:realListXMLList']['si:unitXMLList'].trim();
       }
-      headers.push(header + ' (' + unit + ')');
+      headers.push(header + ' in ' + convertUnit(unit));
       headers.push('Comments');
-      headers.push('Conformity');
+      // Add conformity header only if data exists
+      if (extraInfo[idx] && extraInfo[idx].conformity) {
+        headers.push('Conformity');
+      } else {
+        headers.push('');
+      }
 
       let values = [];
       if (q['si:realListXMLList'] && q['si:realListXMLList']['si:valueXMLList']) {
@@ -281,8 +285,12 @@ export function renderMeasurementResults(measurementResults, language) {
       uncertaintiesArray.push(uncertainty);
 
       let comment = extraInfo[idx] ? extraInfo[idx].comment : '';
-      let conformity = extraInfo[idx] ? extraInfo[idx].conformity : '';
       commentsArray.push(comment);
+
+      let conformity = [];
+      if (extraInfo[idx] && extraInfo[idx].conformity) {
+        conformity = extraInfo[idx].conformity;
+      }
       conformityArray.push(conformity);
     });
 
@@ -297,7 +305,11 @@ export function renderMeasurementResults(measurementResults, language) {
         }
         row.push(cellValue);
         row.push(commentsArray[idx] || '');
-        row.push(conformityArray[idx] || '');
+        if (conformityArray[idx] && conformityArray[idx][i]) {
+          row.push(conformityArray[idx][i]);
+        } else {
+          row.push('');
+        }
       });
       tableData.push(row);
     }
@@ -323,31 +335,31 @@ export function renderMeasurementResults(measurementResults, language) {
         values = new Array(xValues.length).fill(values[0]);
       }
       let uncertainty = uncertaintiesArray[idx];
-      let conformity = conformityArray[idx];
-      // Assign color: use palette; override if conformity indicates pass/fail
-      let traceColor = palette[idx % palette.length];
-      if (conformity.toLowerCase().includes('pass')) {
-        traceColor = '#2ca02c';
-      } else if (conformity.toLowerCase().includes('fail')) {
-        traceColor = '#d62728';
+      let conformity = [];
+      if (conformityArray[idx]) {
+        conformity = conformityArray[idx];
       }
-      unitGroups[unit].push({ name: header, y: values, uncertainty: uncertainty, conformity: conformity, color: traceColor });
+      // Use Tab10 palette; assign a color for this data quantity
+      let traceColor = palette[idx % palette.length];
+      unitGroups[unit].push({ name: header, y: values, uncertainty: uncertainty, conformity: conformity, color: traceColor, index: idx });
     });
     console.debug('Unit groups for plots:', unitGroups);
 
-    // Build a single Plotly figure with subplots (here, one plot per unit group)
+    // Build plots: one subplot per unit group, sharing the same X-axis
     const plotsContainer = document.getElementById('subplotsContainer');
     plotsContainer.innerHTML = '';
-    Object.keys(unitGroups).forEach((unit, idx) => {
+    const unitKeys = Object.keys(unitGroups);
+    unitKeys.forEach((unit, groupIdx) => {
       const group = unitGroups[unit];
       const graphDiv = document.createElement('div');
       graphDiv.style.width = '100%';
       graphDiv.style.height = '300px';
       plotsContainer.appendChild(graphDiv);
 
-      // Build traces for this unit group
+      // Build traces for this group
       const groupTraces = group.map(trace => {
-        const hovertemplate = 'X-Axis: %{x} ' + xUnit + ' | ' + trace.name + ': %{y} ± %{error_y.array} (' + unit + ') | Conformity: <b style="color:' + (trace.conformity.toLowerCase().includes('pass') ? '#2ca02c' : (trace.conformity.toLowerCase().includes('fail') ? '#d62728' : '#000')) + '">' + trace.conformity + '</b><extra></extra>';
+        // Prepare tooltip with short format
+        const hovertemplate = 'X: %{x} ' + convertUnit(xUnit) + ' | ' + trace.name + ': %{y} ± %{error_y.array} ' + convertUnit(unit) + ' | Conformity: %{customdata}<extra></extra>';
         return {
           x: xValues,
           y: trace.y,
@@ -357,31 +369,46 @@ export function renderMeasurementResults(measurementResults, language) {
           name: trace.name,
           marker: { color: trace.color },
           hovertemplate: hovertemplate,
-          customdata: trace.conformity
+          customdata: (trace.conformity && trace.conformity.length === xValues.length) ? trace.conformity : new Array(xValues.length).fill('')
         };
       });
 
+      // Only the last subplot gets an X-axis label
+      let xaxisTitle = '';
+      if (groupIdx === unitKeys.length - 1) {
+        let xLabel = 'X: ';
+        if (xQuantity['dcc:name'] && xQuantity['dcc:name']['dcc:content']) {
+          let content = xQuantity['dcc:name']['dcc:content'];
+          if (Array.isArray(content)) {
+            const match = content.find(item => item.$ && item.$.lang === language) || content[0];
+            xLabel += match._ || match;
+          } else {
+            xLabel += content._ || content;
+          }
+        }
+        xaxisTitle = xLabel + ' in ' + convertUnit(xUnit);
+      }
+
       const layout = {
-        xaxis: { title: { text: xHeader, font: { size: 16, weight: 'bold' } } },
-        yaxis: { title: { text: unit, font: { size: 16, weight: 'bold' } } },
+        xaxis: { title: { text: xaxisTitle, font: { size: 18, family: 'Arial', color: 'black' } }, tickfont: { family: 'Arial', size: 14, color: 'black' } },
+        yaxis: { title: { text: convertUnit(unit), font: { size: 18, family: 'Arial', color: 'black' } }, tickfont: { family: 'Arial', size: 14, color: 'black' } },
         hovermode: 'closest',
         margin: { t: 20, b: 40 }
       };
 
       Plotly.newPlot(graphDiv, groupTraces, layout).then(() => {
         console.debug('Plot rendered for unit:', unit);
-        // Add caption below the plot: italic text "QuantityName in Unit"
+        // Bold caption above the plot: "QuantityName in Unit"; remove duplicate unit if any
         const caption = document.createElement('div');
-        // Use the name of the first trace as QuantityName
-        caption.innerHTML = '<i>' + group[0].name + ' in ' + unit + '</i>';
+        caption.innerHTML = '<b>' + group[0].name + ' in ' + convertUnit(unit) + '</b>';
         caption.style.textAlign = 'center';
-        caption.style.fontStyle = 'italic';
-        graphDiv.parentNode.insertBefore(caption, graphDiv.nextSibling);
+        caption.style.marginBottom = '5px';
+        graphDiv.parentNode.insertBefore(caption, graphDiv);
       });
 
       graphDiv.on('plotly_hover', function(data) {
         if (data.points && data.points.length > 0) {
-          const pointIndex = data.points[0].pointIndex + 1;
+          const pointIndex = data.points[0].pointIndex + 1; // offset for header row
           highlightTableRow(pointIndex);
         }
       });
@@ -405,7 +432,6 @@ export function renderMeasurementResults(measurementResults, language) {
         cell.style.border = '1px solid #ccc';
         if (rowIndex === 0 && cellIndex > 0) {
           const dataIndex = Math.floor((cellIndex - 1) / 3);
-          const color = palette[dataIndex % palette.length];
           cell.style.backgroundColor = lightPalette[dataIndex % lightPalette.length];
         }
         tr.appendChild(cell);