Handsontable 18.1.0 — pinned columns obscure data

HTML

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/handsontable@18.1.0/styles/handsontable.min.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/handsontable@18.1.0/styles/ht-theme-main.min.css">
<script src="https://cdn.jsdelivr.net/npm/handsontable@18.1.0/dist/handsontable.full.min.js"></script>

<h2>Pinned columns obscure data — reproduction starter</h2>
<p>Handsontable 18.1.0 · 2 frozen columns · 12 columns total</p>
<p>Scroll horizontally, widen the pinned columns, or shrink the table.
Columns C–L should remain reachable. Compare with no pinned columns.</p>
<div class="controls">
  <label>Table width <input id="tableWidth" type="number" min="180" max="1400" value="560" step="20"></label>
  <label>Pinned column width <input id="pinnedWidth" type="number" min="60" max="600" value="260" step="20"></label>
  <button id="apply">Apply</button>
  <button id="wide">Widen pinned columns</button>
  <button id="toggle">Unpin columns</button>
  <button id="reset">Reset</button>
</div>
<p id="status" role="status"></p>
<div id="grid"></div>
<p><strong>Test:</strong> Reset → Widen pinned columns → try scrolling to C–L → Unpin columns.</p>
<p>This tests the case where frozen columns consume the viewport. It is a starter for isolating the reported overlap.</p>

CSS

body { font: 14px/1.5 system-ui, sans-serif; padding: 16px; margin: 0; color: #1c2736; }
h2 { font-size: 18px; margin: 0 0 8px; }
p { max-width: 760px; }
.controls { display: flex; flex-wrap: wrap; gap: 10px; align-items: center; }
input { width: 65px; padding: 5px; }
button { padding: 6px 10px; cursor: pointer; }
#grid { width: 560px; overflow: hidden; }
#status { font-family: monospace; }
.handsontable td.pinned { background: #fff0bf; color: #624600; }

JavaScript

// Exact JS and CSS version: 18.1.0. Synthetic data only.
const data = Array.from({ length: 30 }, (_, row) =>
  Array.from({ length: 12 }, (_, col) =>
    String.fromCharCode(65 + col) + (row + 1) + (col < 2 ? ' (pinned)' : ' data')
  )
);
const grid = document.getElementById('grid');
let pinned = true;
const hot = new Handsontable(grid, {
  data,
  themeName: 'ht-theme-main',
  width: 560,
  height: 320,
  rowHeaders: true,
  colHeaders: true,
  fixedColumnsStart: 2,
  colWidths: 260,
  autoColumnSize: false,
  manualColumnResize: true,
  stretchH: 'none',
  cells(row, col) { return { className: col < 2 ? 'pinned' : '' }; },
  licenseKey: 'non-commercial-and-evaluation',
  afterColumnResize() { requestAnimationFrame(report); }
});
window.hot = hot;

function report() {
  const frozenWidth = pinned ? hot.getColWidth(0) + hot.getColWidth(1) : 0;
  const viewport = grid.clientWidth;
  document.getElementById('status').textContent =
    'v' + Handsontable.version + ' | table: ' + viewport +
    'px | pinned: ' + frozenWidth + 'px (+ row header)' +
    (frozenWidth >= viewport ? ' | Pinned columns occupy the entire viewport.' : '');
}
function apply() {
  const width = Math.max(180, Number(document.getElementById('tableWidth').value) || 560);
  const frozenWidth = Math.max(60, Number(document.getElementById('pinnedWidth').value) || 260);
  grid.style.width = width + 'px';
  hot.updateSettings({
    width,
    fixedColumnsStart: pinned ? 2 : 0,
    colWidths: Array.from({ length: 12 }, (_, col) => col < 2 ? frozenWidth : 260),
    manualColumnResize: true
  });
  document.getElementById('toggle').textContent = pinned ? 'Unpin columns' : 'Pin 2 columns';
  report();
}
document.getElementById('apply').onclick = apply;
document.getElementById('wide').onclick = () => {
  document.getElementById('pinnedWidth').value = 300;
  apply();
};
document.getElementById('toggle').onclick = () => { pinned = !pinned; apply();...