@scope (list-window-ui) {
  /* ── Block 1 — TOKENS (zero-specificity, exposable for theming) ── */
  :where(:scope) {
    --list-window-bg:              var(--a-bg);
    --list-window-row-gap:         var(--a-space-1);
    --list-window-overscan-bg:     transparent;
    --list-window-sentinel-size:   var(--a-space-2);
  }

  /* ── Block 2 — BASE styles consuming the tokens above ── */
  :scope {
    box-sizing: border-box;
    display: block;
    position: relative;
    overflow: auto;
    contain: strict;
    background: var(--list-window-bg);
    isolation: isolate;
    outline: none;
  }

  :scope:focus-visible {
    outline: 2px solid var(--a-accent-strong);
    outline-offset: -2px;
  }

  /* Phantom spacer reserves total scroll height = sum of all row sizes.
     Width pinned to 1px so it never contributes horizontal scroll in
     vertical mode (and vice versa). */
  :scope > [data-phantom] {
    position: relative;
    pointer-events: none;
  }

  /* The visible-rows container is absolutely positioned and translated
     to align with the current scroll window. flex-column lays rows
     vertically; gap controls row spacing without margin-collapse
     surprises. */
  :scope > [data-window] {
    position: absolute;
    top: 0;
    inset-inline-start: 0;
    inset-inline-end: 0;
    display: flex;
    flex-direction: column;
    gap: var(--list-window-row-gap);
    will-change: transform;
  }

  /* Each row is its own block — height defined by content (variable
     mode) or the item-size prop (fixed mode). min-width:0 prevents
     overflow:hidden flex children from blowing out the host. */
  :scope > [data-window] > [data-row] {
    flex: 0 0 auto;
    min-width: 0;
  }

  /* Sentinel nodes are tiny invisible markers tracked by the host's
     IntersectionObserver. The top sentinel sits at the top of the
     phantom; the bottom sentinel at the bottom. They emit
     scroll-start / scroll-end when intersecting the host viewport. */
  :scope > [data-sentinel] {
    position: absolute;
    inset-inline-start: 0;
    inset-inline-end: 0;
    height: var(--list-window-sentinel-size);
    pointer-events: none;
  }
  :scope > [data-sentinel="top"]    { top: 0; }
  :scope > [data-sentinel="bottom"] { bottom: 0; }

  /* Sticky slots — sit at the top/bottom of the scroll container so they
     stay visible while the window scrolls. */
  :scope [slot="before"] {
    position: sticky;
    top: 0;
    z-index: 1;
    background: var(--list-window-bg);
  }
  :scope [slot="after"] {
    position: sticky;
    bottom: 0;
    z-index: 1;
    background: var(--list-window-bg);
  }

  /* ── Horizontal mode ── */
  :scope[direction="horizontal"] > [data-window] {
    flex-direction: row;
  }
  :scope[direction="horizontal"] > [data-sentinel] {
    width: var(--list-window-sentinel-size);
    height: auto;
    top: 0;
    bottom: 0;
    inset-inline-start: auto;
    inset-inline-end: auto;
  }
  :scope[direction="horizontal"] > [data-sentinel="top"]    { inset-inline-start: 0; }
  :scope[direction="horizontal"] > [data-sentinel="bottom"] { inset-inline-end: 0; }

  /* ── States ── */
  :scope[empty] > [data-window] {
    display: none;
  }
  :scope[empty] [slot="empty"] {
    display: block;
  }

  :scope:not([empty]) [slot="empty"] {
    display: none;
  }

  :scope[measuring] > [data-window] {
    /* Suppress row-gap during initial measurement pass to avoid
       layout shift between estimated and measured offsets. */
    gap: 0;
  }

  :scope[disabled] {
    pointer-events: none;
    opacity: 0.5;
  }
}
