/* ========================================================================
   Legend + colormap menu
   ===================================================================== */

#legend {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

.legend-section {
  display: flex;
  flex-direction: column;
  gap: var(--space-1-5);
}

.legend-section + .legend-section {
  border-top: var(--border-width-1) solid color-mix(in srgb, var(--color-border-strong) 12%, transparent);
  padding-top: var(--space-2);
}

.legend-filter {
  gap: var(--space-1);
}

/* Colormap button */
.colorbar-wrapper {
  position: relative;
}

.colorbar-gradient {
  width: 100%;
  height: var(--space-4);
  border-radius: var(--radius-full);
  border: var(--border-width-1) solid var(--color-border-strong);
  background: linear-gradient(to right,
    var(--colorbar-stops, var(--color-border-light), var(--color-border-light)));
  cursor: pointer;
  padding: 0;
  appearance: none;
  box-shadow: var(--shadow-xs);
}

.colorbar-gradient:focus-visible {
  outline: 2px solid var(--color-border-focus);
  outline-offset: 1px;
}

/* The colorbar's two end values. */
.colorbar-ticks {
  display: flex;
  justify-content: space-between;
  margin-top: var(--space-0-5);
  font-variant-numeric: tabular-nums;
  font-size: var(--type-readout);
  color: var(--color-text-secondary);
}

/* Colormap dropdown (opened and closed with the `hidden` attribute). */
.colormap-menu {
  position: absolute;
  top: calc(100% + var(--space-1-5));
  left: 0;
  right: 0;
  background: var(--color-surface-elevated);
  border: var(--border-default);
  border-radius: var(--radius-none);
  box-shadow: var(--shadow-md);
  padding: var(--space-1-5);
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  z-index: var(--z-popover);
  max-height: 240px;
  overflow-y: auto;
}

.colormap-option {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  border: var(--border-width-1) solid transparent;
  border-radius: var(--radius-none);
  padding: var(--space-1-5) var(--space-2);
  background: var(--color-surface-secondary);
  color: var(--color-text-primary);
  cursor: pointer;
  font-size: var(--type-control);
  text-align: left;
}

.colormap-option:hover {
  border-color: var(--color-border-strong);
  background: var(--color-border-light);
}

.colormap-option.active {
  border-color: var(--color-interactive-primary);
  background: var(--color-interactive-primary);
  color: var(--color-text-inverse);
}

.colormap-preview {
  flex: 1;
  min-width: 90px;
  height: var(--space-3);
  border-radius: var(--radius-sm);
  border: var(--border-width-1) solid color-mix(in srgb, var(--color-border-strong) 15%, transparent);
  background: linear-gradient(to right,
    var(--colormap-stops, var(--color-border-light), var(--color-border-light)));
}

/* The row owns the ink, so the selected row's inverse colour reaches its
   label. A colour of its own here kept the label primary-on-primary — dark on
   the dark highlight in light theme, light on light in dark theme. */
.colormap-name {
  min-width: 72px;
  font-weight: var(--font-weight-semibold);
  color: inherit;
  letter-spacing: var(--tracking-normal);
}

/* Legend controls row */
.legend-controls {
  display: flex;
  gap: var(--space-2);
  margin-bottom: var(--space-1-5);
  padding-bottom: 0;
}

.legend-controls button {
  flex: 1;
}

/* Category legend line items */
.legend-item {
  display: flex;
  align-items: center;
  margin-bottom: var(--space-px);
  position: relative;
}

/* A long legend renders only the rows in view: an off-screen row keeps its
   remembered height and skips style, layout and paint, so a 5,000-category
   field scrolls and refreshes like a short one. */
.legend-items-scrollable > .legend-item {
  content-visibility: auto;
  contain-intrinsic-size: auto var(--space-4);
}

.legend-item.legend-item-annotating {
  align-items: flex-start;
}

/* Scoped to the row so it outranks the global `input[type="checkbox"]`
   reset (0,1,1), which used to zero this margin and press the tick against
   the swatch. */
.legend-item > .legend-checkbox {
  width: var(--control-check-size);
  height: var(--control-check-size);
  margin: 0 var(--space-1-5) 0 0;
  cursor: pointer;
  flex-shrink: 0;
}

/* Color swatch & dropdown palette */
.legend-swatch {
  width: var(--control-check-size);
  height: var(--control-check-size);
  border-radius: var(--radius-sm);
  margin-right: var(--space-1-5);
  border: var(--border-width-1) solid color-mix(in srgb, var(--color-border-strong) 25%, transparent);
  background-color: var(--legend-swatch-color, var(--color-border-light));
  flex-shrink: 0;
  cursor: pointer;
  position: relative;
}

.legend-color-input {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
  min-width: 0;
  min-height: 0;
  border: none;
  padding: 0;
  appearance: none;
  -webkit-appearance: none;
  background: transparent;
  opacity: 0;
  cursor: pointer;
}

.legend-swatch:hover {
  border-color: color-mix(in srgb, var(--color-border-strong) 60%, transparent);
  box-shadow: var(--shadow-xs);
}

.legend-label {
  font-size: var(--type-control);
  flex: 1;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.legend-label.legend-label-multiline {
  display: flex;
  flex-direction: column;
  gap: var(--space-0-5);
  white-space: normal;
}

.legend-label-main {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.legend-label-sub {
  width: 100%;
  font-size: var(--type-compact);
  opacity: var(--opacity-75);
  overflow: visible;
  white-space: nowrap;
  display: flex;
  align-items: center;
  gap: var(--space-1-5);
}

.legend-consensus-names {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.legend-consensus-counts {
  position: absolute;
  right: var(--space-5);
  bottom: 0;
  font-size: var(--type-compact);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  text-align: right;
  opacity: var(--opacity-75);
}

.legend-highlight-btn {
  position: absolute;
  right: 0;
  bottom: 0;
  padding: 0 var(--space-1);
  font-size: var(--type-compact);
  line-height: 1;
  border-radius: var(--radius-full);
  border: var(--border-default);
  background: var(--color-surface-secondary);
  color: var(--color-text-secondary);
  cursor: pointer;
  opacity: var(--opacity-75);
  transition: var(--transition-colors);
}

.legend-highlight-btn:hover {
  background: var(--color-surface-tertiary);
  color: var(--color-text-primary);
  opacity: 1;
}

.legend-highlight-btn:active {
  background: var(--color-border-light);
}

.legend-highlight-btn:disabled,
.legend-highlight-btn:disabled:hover,
.legend-highlight-btn:disabled:active {
  background: var(--color-surface-secondary);
  color: var(--color-text-secondary);
  border-color: var(--color-border-default);
  cursor: not-allowed;
  opacity: var(--opacity-55);
}

.legend-highlight-btn--active {
  background: var(--color-accent);
  color: var(--color-text-inverse);
  border-color: var(--color-accent);
  opacity: 1;
}

.legend-highlight-btn--active:hover {
  background: var(--color-accent-strong);
  border-color: var(--color-accent-strong);
}

/* The row's rename and delete actions sit a step apart from the count. */
.legend-item > .icon-btn {
  margin-left: var(--space-1);
}

/* Legend rows are stacked edge to edge, so their actions keep the row as
   their whole target instead of reaching into the next row. */
.legend-item > .icon-btn::after {
  inset: calc(-1 * var(--border-width-1));
}

.legend-count {
  font-size: var(--type-readout);
  opacity: var(--opacity-75);
  margin-left: var(--space-2);
  white-space: nowrap;
}

/* A dot of the colour a lower layer is drawn in (a gene's 0, a cell not read),
   made from the view's background by the viewer (rendering/read-cell-layer.js):
   the legend names each state beside the colour it shows as on this theme. */
.legend-layer-swatch {
  display: inline-block;
  width: 0.75em;
  height: 0.75em;
  margin-right: var(--space-1);
  border-radius: var(--radius-full);
  border: var(--border-default);
  vertical-align: -0.05em;
  background: var(--cell-zero-color);
}

.legend-layer-swatch.is-unread {
  background: var(--cell-unread-color);
}

/* The cells without a category: a checkbox to show or hide them and their
   count, under the categories. */
.legend-missing-row {
  display: flex;
  align-items: center;
  margin-top: var(--control-row-gap);
}

.legend-item.legend-item-disabled {
  opacity: var(--opacity-55);
}

.legend-item.legend-item-disabled .legend-checkbox,
.legend-item.legend-item-disabled .legend-color-input {
  cursor: not-allowed;
}

/* Scrollable legend items container for many categories */
.legend-items-container {
  position: relative;
}

.legend-items-scrollable {
  max-height: 288px; /* ~16 items × 18px height */
  overflow-y: auto;
  overflow-x: hidden;
  padding-right: var(--space-1);
  /* Fade mask at bottom to indicate scrollability */
  mask-image: linear-gradient(to bottom, var(--black) calc(100% - var(--space-6)), transparent 100%);
  -webkit-mask-image: linear-gradient(to bottom, var(--black) calc(100% - var(--space-6)), transparent 100%);
}

/* Remove fade mask when scrolled to bottom */
/* A virtual list (see `VIRTUAL_LIST_MIN_ROWS` in categorical-legend.js): the
   spacer is as tall as every row, and the window of built rows sits at the
   first row it holds. */
.legend-virtual-spacer {
  position: relative;
  height: var(--legend-virtual-height, auto);
}

.legend-virtual-window {
  position: absolute;
  inset-inline: 0;
  top: 0;
  transform: translateY(var(--legend-virtual-offset, 0));
}

.legend-items-virtual .legend-item {
  content-visibility: visible;
}

.legend-items-scrollable.scrolled-to-bottom {
  mask-image: none;
  -webkit-mask-image: none;
}

/* Action rows under the legend (Show all / Hide all, Filter / Reset, and the
   kept-view layout row). */
.legend-actions {
  display: flex;
  justify-content: flex-end;
  align-items: center;
  gap: var(--space-1-5);
  margin-top: var(--space-1);
}

/* ------------------------------------------------------------------------
   Outlier filter: what it can do for the active field, and its progress
   (ui/modules/outlier-filter-control.js)
   --------------------------------------------------------------------- */

#outlier-filter-container {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
}

#outlier-filter-container[hidden] {
  display: none;
}

/* One short line and its action side by side; either may be absent. */
.outlier-filter-status {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  min-width: 0;
}

.outlier-filter-status:not(:has(> :not([hidden]))) {
  display: none;
}

.outlier-filter-note {
  flex: 1;
  min-width: 0;
  margin: 0;
  font-size: var(--type-hint);
  line-height: var(--leading-normal);
  color: var(--color-text-secondary);
}

.outlier-filter-note[data-tone="error"] {
  color: var(--color-danger-text);
}

/* The bar under the slider while the outlier distances are got is the job
   progress bar every cancellable job shows (components/_jobs.css). */
.outlier-filter-action {
  flex: none;
}

/* A gene read for a sample of the open cells: the states drawn (one line,
   `legend-layer-note`) and how many cells it is read for, a link to where
   that is chosen (`gene-read-control.js`, `.gene-read-note`). Each one line,
   spaced by the colour section's gap alone. */
.legend-section > .legend-layer-note {
  margin: 0;
  white-space: nowrap;
}

.legend-layer-note[hidden] {
  display: none;
}

/* The bounds of Visible range: label, slider and number box on one row
   each, in one grid so the two rows' columns align. */
.legend-range-bounds {
  display: grid;
  grid-template-columns: max-content minmax(0, 1fr) auto;
  align-items: center;
  column-gap: var(--space-1-5);
  row-gap: var(--control-row-gap);
}

.legend-range-label {
  margin: 0;
  font-size: var(--type-hint);
  color: var(--color-text-secondary);
}

.legend-filter > .legend-actions {
  margin-top: 0;
}
