/*
VirtualList

A scroll container that renders only the items near its viewport. The
inner element is sized to the whole list; each item is placed with a
transform at its computed offset, so an item resizing or a new window
rendering never moves anything but the items after it. Before the
controller starts (server render), items sit in normal flow.

  .virtual-list                    the scroll container (size it: class or style)
  .virtual-list-inner              the full-length track
  .virtual-item                    one rendered item [data-index] [data-lane] [data-sticky]
  .virtual-list[data-orientation="horizontal"]
  .virtual-list[data-scroller="window"]   the page scrolls, not the list
  .virtual-list[data-scrolling]    present while scrolling
  .virtual-list[data-columns]      a grid: rows and columns both window
  .virtual-cell                    one grid cell [data-column]
*/

@layer components {

.virtual-list {
  position:        relative;
  overflow:        auto;
  overscroll-behavior: contain;
  min-width:       0;
  contain:         layout paint;
  border-radius:   var(--radius-surface);
  font-family:     var(--font-ui);
  font-size:       var(--text-ui);
  color:           var(--ink);
}

.virtual-list[data-scroller="window"] {
  overflow: visible;
  contain:  none;
}

.virtual-list:focus-visible {
  outline:    none;
  box-shadow: var(--focus-ring);
}

.virtual-list-inner {
  position:       relative;
  display:        flex;
  flex-direction: column;
  gap:            var(--virtual-gap, 0px);
  width:          100%;
}

.virtual-list[data-orientation="horizontal"] > .virtual-list-inner {
  flex-direction: row;
  width:          auto;
  height:         100%;
}

.virtual-list[data-lanes] > .virtual-list-inner {
  display:               grid;
  grid-template-columns: repeat(var(--virtual-lanes), minmax(0, 1fr));
}

/* Running: the track has the list's full length and items are placed. */
.virtual-list[data-ready] > .virtual-list-inner {
  display:   block;
  gap:       0;
  height:    var(--virtual-total);
}

.virtual-list[data-ready][data-orientation="horizontal"] > .virtual-list-inner {
  width:  var(--virtual-total);
  height: 100%;
}

.virtual-list[data-ready] > .virtual-list-inner > .virtual-item {
  position:           absolute;
  top:                0;
  inset-inline-start: var(--virtual-lane-offset, 0px);
  width:              calc((100% - var(--virtual-gap, 0px) * (var(--virtual-lanes, 1) - 1)) / var(--virtual-lanes, 1));
}

.virtual-list[data-ready][data-orientation="horizontal"] > .virtual-list-inner > .virtual-item {
  top:    var(--virtual-lane-offset, 0px);
  inset-inline-start: 0;
  width:  auto;
  height: calc((100% - var(--virtual-gap, 0px) * (var(--virtual-lanes, 1) - 1)) / var(--virtual-lanes, 1));
}


.virtual-list[data-ready] > .virtual-list-inner > .virtual-item[data-sticky] {
  position:   sticky;
  z-index:    1;
  top:        0;
  background: var(--surface-bg);
}

/* A grid: the track is as wide as every column, each row holds its cells
   placed by transform at their column's offset. */
.virtual-list[data-columns] > .virtual-list-inner > .virtual-item {
  display: flex;
}

.virtual-list[data-ready][data-columns] > .virtual-list-inner {
  width: var(--virtual-column-total);
}

.virtual-list[data-ready][data-columns] > .virtual-list-inner > .virtual-item {
  display:  block;
  overflow: hidden;
}

.virtual-list[data-ready][data-columns] .virtual-cell {
  position:           absolute;
  top:                0;
  inset-inline-start: 0;
  height:             100%;
}

.virtual-item,
.virtual-cell {
  box-sizing: border-box;
  min-width:  0;
}

/* A grid's focused cell (role=grid with columns): the ring sits inside it. */
.virtual-cell:focus-visible {
  outline:    none;
  box-shadow: inset 0 0 0 var(--focus-ring-width) var(--accent);
}

}
