/* gogridgo virtual scroll addon — see virtualscroll.js. Everything here is
   scoped to .gg-virtual-on, the class the module adds only while a grid is
   actually windowed, so a JS failure leaves the paged grid fully usable. */

/* Page links are meaningless when the scrollbar spans the whole set. The
   row count, filter toggle, exports, ⚙ and the fullscreen button stay. */
.gg-grid.gg-virtual-on .gg-pager-nav { display: none; }

/* Uniform row height is what makes the spacer math exact, so cells must not
   wrap inside a window (Column.Wrap() still wraps in the paged view). */
.gg-grid.gg-virtual-on .gg-td {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Spacer rows stand in for the rows outside the window. They carry no
   .gg-row class, so record view / row-click / click-to-filter skip them. */
.gg-grid.gg-virtual-on tr.gg-vspacer,
.gg-grid.gg-virtual-on tr.gg-vspacer > td {
  padding: 0;
  border: 0;
  background: none;
}

/* The summary row is relocated out of the swapped tbody on enter: above ->
   thead (already sticky), below -> a sticky tfoot. Both need their own
   background or data rows would show through. */
.gg-grid.gg-virtual-on tfoot.gg-vfoot > tr > td {
  position: sticky;
  bottom: 0;
  z-index: 20;
  background: #f3f4f6;
}

/* Fetch in flight for longer than a blink: a thin indeterminate bar at the
   top of the scrollport. Blank rows during a fast drag are expected (Excel
   does the same) — this just makes the wait legible. */
.gg-grid.gg-virtual-on.gg-virtual-busy .gg-table-scroll { position: relative; }
.gg-grid.gg-virtual-on.gg-virtual-busy .gg-table-scroll::before {
  content: "";
  position: sticky;
  top: 0;
  left: 0;
  display: block;
  height: 2px;
  z-index: 30;
  background: linear-gradient(90deg, transparent, #4f46e5, transparent);
  background-size: 40% 100%;
  background-repeat: no-repeat;
  animation: gg-vbusy 1s linear infinite;
}
@keyframes gg-vbusy {
  from { background-position: -40% 0; }
  to   { background-position: 140% 0; }
}

/* …plus a chip in the middle of the scrollport, because the thin bar is easy
   to miss when the rows below it are blank. It sits on the grid (which is
   position:fixed in fullscreen, the only mode virtual scrolling runs in), so
   it stays put while the table underneath scrolls. */
.gg-grid.gg-virtual-on.gg-virtual-busy::after {
  /* Text comes from the grid element (Strings.Loading) rather than from this
     file: a stylesheet is the one place a translator cannot reach. */
  content: attr(data-gg-loading);
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  z-index: 40;
  padding: 0.45rem 0.9rem;
  border: 1px solid #c7d2fe;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.94);
  color: #3730a3;
  font-size: 0.8rem;
  font-weight: 600;
  white-space: nowrap;
  box-shadow: 0 2px 10px rgba(15, 23, 42, 0.16);
  pointer-events: none;
  animation: gg-vbusy-pulse 1.1s ease-in-out infinite;
}
@keyframes gg-vbusy-pulse {
  0%, 100% { opacity: 1; }
  50%      { opacity: 0.62; }
}

@media (prefers-color-scheme: dark) {
  .gg-grid.gg-virtual-on.gg-virtual-busy::after {
    border-color: #4338ca;
    background: rgba(30, 41, 59, 0.95);
    color: #c7d2fe;
  }
}

/* ── position bar ──────────────────────────────────────────────────────────
   Chrome's own scrollbar is an overlay: it fades out and offers nothing to
   grab, so in a 348k-row set the user loses all sense of position. This is
   the hand-drawn replacement (same reasoning and palette as topscroll.js's
   horizontal bar), and it exists ONLY in fullscreen + virtual mode. */
.gg-grid.gg-virtual-on .gg-vbar {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  width: 14px;
  z-index: 25;              /* above the sticky thead (20) */
  background: #f3f4f6;
  border-left: 1px solid #e5e7eb;
  user-select: none;
  touch-action: none;
}

.gg-grid.gg-virtual-on .gg-vbar-thumb {
  position: absolute;
  left: 1px;
  right: 1px;
  border-radius: 5px;
  /* Deliberately higher contrast than a native scrollbar thumb: this IS the
     position indicator, so it has to read at a glance, not blend in. */
  background: #9ca3af;
  cursor: grab;
}

.gg-grid.gg-virtual-on .gg-vbar-thumb:hover,
.gg-grid.gg-virtual-on.gg-vbar-dragging .gg-vbar-thumb {
  background: #4b5563;
}

.gg-grid.gg-virtual-on.gg-vbar-dragging .gg-vbar-thumb { cursor: grabbing; }

/* The readout rides on the thumb: a percentage at rest ("how far in am I"
   with no arithmetic), percentage + row number while dragging. It sits to
   the LEFT of the 12px track, so it never widens the bar. */
.gg-grid.gg-virtual-on .gg-vbar-label {
  position: absolute;
  right: 16px;
  top: 50%;
  transform: translateY(-50%);
  white-space: nowrap;
  font-size: 0.6rem;
  line-height: 1;
  color: #6b7280;
  background: rgba(255, 255, 255, 0.9);
  border: 1px solid #e5e7eb;
  border-radius: 0.25rem;
  padding: 1px 4px;
  pointer-events: none;
  opacity: 0;
  transition: opacity 120ms ease-in;
}

/* Visible on hover and while dragging; a permanent chip would sit on top of
   the rightmost column's data all the time. */
.gg-grid.gg-virtual-on .gg-vbar:hover .gg-vbar-label,
.gg-grid.gg-virtual-on.gg-vbar-active .gg-vbar-label,
.gg-grid.gg-virtual-on.gg-vbar-dragging .gg-vbar-label { opacity: 1; }

/* Keep the track off the last column's data, and hide the NATIVE scrollbars:
   ours is always visible and grabbable, so Chrome's overlay bar flashing on
   top of it just showed two bars at once. Scoped to .gg-virtual-on, so
   everywhere else the native bars stay exactly as they were. */
.gg-grid.gg-virtual-on .gg-table-scroll {
  padding-right: 14px;
  scrollbar-width: none;      /* standard: Chrome 121+, Firefox */
  -ms-overflow-style: none;
}
.gg-grid.gg-virtual-on .gg-table-scroll::-webkit-scrollbar { width: 0; height: 0; }
