.gallery-card {
  /* One source for the selected-vote fill, which the hover and coarse-pointer rules below both paint with. */
  --validation-button-selected-bg: var(--color-neutral-600);

  position: relative;
  padding: 0;
  border-radius: 20px;
  height: fit-content;

  /* Interior type/spacing is sized in cqw against this container, so a card reads the same at any grid width —
     one wide column on a phone, three across on a desktop (where a card is ~25vw, making 4cqw ≈ 1vw). Sizes that
     have to stay legible or tappable carry a px floor via max(): proportional above it, never below it. */
  container-type: inline-size;
}

.gallery-card:hover {
  box-shadow: 0 4px 8px 0 rgb(0 0 0 / 10%), 0 6px 20px 0 rgb(0 0 0 / 5%);

  /* Engines before Chrome 129 / Firefox 133 / Safari 18.4 still make container-type: inline-size a stacking
     context, which paints the "+n" tag popover under the next card in the grid (csswg-drafts#10544). */
  z-index: 1;
}

.validate-agree {
  background-color: var(--color-pine-500);
}

.validate-disagree {
  background-color: #eb734d;
}

.validate-unsure {
  background-color: var(--color-asphalt-100);
}

/*
We make sure that the image holder is positioned relatively so that the validation menu can be positioned absolutely
with respect to the image holder. This allows the validation menu to be placed over the actual image (like an overlay).
*/
.image-holder {
  cursor: pointer;
  position: relative;
  overflow: hidden;
  aspect-ratio: 3 / 2; /* Match the Explore canvas ratio (720x480). */
  --gallery-marker-size: clamp(16px, 4.4cqw, 22px);
}

.gallery-card:hover::after {
  opacity: 1;
}

.static-gallery-image {
  width: 100%;
  height: 100%;
  object-fit: cover; /* Fills 3:2 container; crops excess from Google's 4:3 images. */
  border-top-left-radius: 20px;
  border-top-right-radius: 20px;
}

#gallery-validation-button-holder {
  display: flex;
  flex-flow: row wrap;
  justify-content: center;
  position: absolute;
  bottom: 0;
  width: 100%;
  height: 14%;
  z-index: 2;
}

#gallery-card-agree-button {
  width: 33%;
  border-right: 1px solid #dcdbdb;
  background-color: var(--color-pine-500);
  color: var(--color-asphalt-500);
}

#gallery-card-disagree-button {
  width: 34%;
  background-color: #eb734d;
  color: var(--color-asphalt-500);
}

#gallery-card-unsure-button {
  border-left: 1px solid #dcdbdb;
  width: 33%;
  background-color: var(--color-asphalt-100);
  color: var(--color-asphalt-500);
}

.card-header {
  display: flex;

  /* Baseline, not centered: the two sit at different sizes, so lining up the text they sit on reads as one line. */
  align-items: baseline;
  justify-content: space-between;
  gap: 1.6cqw;
  padding: 5px 5px 3px 7px;
  font: var(--text-body-bold);
  font-size: max(12px, 4cqw);
}

/* The label type is what the card is about, so it keeps its width and the neighborhood beside it gives way. */
.card-header__type {
  flex-shrink: 0;
  line-height: 1.2; /* Tokens carry a fixed line-height, which the vw font sizes here would otherwise pad out. */
}

/* The neighborhood a label sits in, opposite its type: quieter than the type, and cut off rather than wrapped so a
   long name can't push the type around or grow the card. */
.card-location {
  display: flex;

  /* The pin's bottom edge is its baseline, so baseline alignment stands it on the text's baseline. */
  align-items: baseline;
  gap: 0.8cqw;
  font: var(--text-small-regular);
  font-size: max(11px, 2.88cqw);
  font-weight: 400;
  line-height: 1.2;
  color: var(--color-neutral-600);
  min-width: 0;
  text-decoration: none;
}

.card-location:hover,
.card-location:focus-visible {
  color: var(--color-asphalt-500);
  text-decoration: underline;
}

.card-location:focus-visible {
  outline: 2px solid var(--color-asphalt-400);
  outline-offset: 2px;
  border-radius: 2px;
}

/* Sized in em so the pin tracks the name's size, and near the name's cap height rather than its full em box —
   a glyph fills only ~0.7em of that box, so a 1em pin reads as oversized next to the text. */
.card-location__pin {
  width: 0.85em;
  height: 0.85em;
  flex-shrink: 0;
  opacity: 0.7;
}

/* A validated card takes the verdict's color across the whole info band, where the muted grey washes out. The line
   falls back to the same ink as the severity and tags beside it, which that band is already built to carry. */
.validate-agree .card-location,
.validate-disagree .card-location,
.validate-unsure .card-location {
  color: inherit;
}

.card-location__name {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.card-info {
  padding-bottom: 2cqw;
  padding-left: 2cqw;
  padding-right: 2cqw;
  color: var(--color-asphalt-500);
  border-width: 0 1px 1px;
  border-color: #dcdbdb;
  border-style: solid;
  border-bottom-left-radius: 20px;
  border-bottom-right-radius: 20px;
  cursor: default;
}

.gallery-card:hover > .card-info {
  border-width: 0; /* Using a drop shadow on hover, and we don't need both the border and shadow. */
}

.card-data {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-direction: row;
  font: var(--text-small-regular);
  font-size: max(11px, 2.4cqw);

  /* A definite height, card-relative: the vote icons fill it via height: 100%, so the 24px floor is also what keeps
     them at the WCAG 2.5.8 minimum target size on a narrow card. */
  height: max(24px, 5.6cqw);
}

.card-severity {
  display: flex;
  align-items: center;
  height: 100%;
  flex-direction: row;
  flex: 0 0 auto; /* Takes only the space needed for content */
  padding-left: 7px;
}

.label-severity-header {
  padding-right: 1cqw;
}

.label-severity-content {
  display: flex;
  flex-direction: row;
}

.no-severity-header {
  opacity: 0.6;
}

.card-tags {
  display: flex;
  align-items: center;
  height: 100%;
  flex-direction: row;
  flex: 1; /* Takes all remaining space */

  /* Without this, the flex item's auto min-width lets nowrap tag pills inflate it past the card — and
     TagDisplay measures the inflated width, so its fit budget never hides a tag (#5009). */
  min-width: 0;
  padding-left: 7px;
}

.label-tags-header {
  padding-right: 1cqw;
}

.label-tags-holder {
  display: flex;
  align-items: center;
  overflow-y: auto;
  width: 100%;
  flex-flow: row wrap;
  flex: 1;
  min-width: 0;
}

.label-tags-content {
  text-overflow: ellipsis;
  width:fit-content;
  color: var(--color-neutral-black);
}

.gallery-marker-wrapper {
  position: absolute;
  width: var(--gallery-marker-size);
  height: var(--gallery-marker-size);
  pointer-events: none;
}

.gallery-marker-wrapper .label-icon-gallery {
  width: 100%;
  height: 100%;
  position: absolute;
  left: 0;
  top: 0;
  z-index: 1;
}

.gallery-marker-wrapper .ai-icon-marker {
  pointer-events: auto;
}


.card-validation-info {
  display: flex;
  align-items: center;
  height: 100%;
  flex-direction: row;
  flex: 0 0 19%; /* Replaces width: 19%; */
  padding-left: 7px;
}

.validation-info-content {
  display: flex;
  flex-direction: row;
  gap: 8px;
}

.validation-section-content {
  display: flex;
  width: 50%;
  height: 100%;
  flex-direction: column;
  cursor: pointer;

  /* Prevent text selection. */
  -webkit-user-select: none; /* Safari */
}

.validation-info-count-container {
  position: relative;
  display: flex;
  flex-direction: row;
  align-items: center;
  height: 100%;
  gap: 2px;
}

.validation-info-count {
  display: flex;
  flex: 1;
  height: 100%;
  flex-direction: column;
  justify-content: center;
}

/* The validation SVGs have ~30% internal whitespace in their viewBox, so size
   them to fill the section height rather than using the old PNG-based width %. */
.validation-info-image {
  height: 100%;
  width: auto;
  flex: 0 0 auto;
}

.validation-button, .validation-button-selected {
  opacity: 0;
  font: var(--text-body-bold);
  font-size: max(11px, 3cqw);
  background-color: var(--color-neutral-white);
  border-style: none;
  color: var(--color-asphalt-500);
  transition: opacity 120ms ease;
}

.gallery-card:hover .validation-button {
  opacity: 0.75;
}

.gallery-card:hover .validation-button:hover {
  opacity: 0.95;
}

.gallery-card:hover .validation-button-selected {
  opacity: 1;
  background-color: var(--validation-button-selected-bg);
}

/* Read-only mode: the card shows the viewer's own label, so validating isn't allowed. The UI stays in place but
   appears disabled, matching the Gallery expanded view / LabelMap popup. */
.gallery-card--readonly #gallery-card-agree-button,
.gallery-card--readonly #gallery-card-disagree-button,
.gallery-card--readonly #gallery-card-unsure-button {
  background-color: #E2E2E2;
  color: rgb(0 0 0 / 40%);
  cursor: default;
}

.gallery-card--readonly .card-validation-info {
  opacity: 0.5;
}

.gallery-card--readonly:hover .validation-button:hover {
  opacity: 0.75; /* No hover bump in readonly: nothing to validate. */
}

.gallery-card--readonly .validation-section-content {
  cursor: default;
}

.gallery-card--readonly .validation-info-image {
  pointer-events: none;
}

/* Hover can't reveal the vote row on a touch-primary device, so it stays visible; readonly styling still wins. */
@media (pointer: coarse) {
  .validation-button {
    opacity: 0.75;
  }

  .validation-button-selected {
    opacity: 1;
    background-color: var(--validation-button-selected-bg);
  }
}

.expanded-view-background-card {
  opacity: 0.5;
}

.severity-circle {
  color: var(--color-neutral-white);
  border: 1px solid var(--color-asphalt-500);
  width: max(11px, 2.8cqw);
  height: max(11px, 2.8cqw);
  border-radius: 50%;
  text-align: center;
  margin: 2px;
  font-size: 3.6cqw;
}

.no-severity-circle {
  opacity: 0.4;
}

#current-severity {
  border: 2px solid var(--color-asphalt-500);
  background-color: var(--color-asphalt-500);
  color: var(--color-asphalt-500);
}
/* The Gallery's filter column. The controls themselves come from the shared sidebar (filter-sidebar.css, #4585);
   what's here is only the column that holds them, since the Gallery scrolls its sidebar with the page instead of
   floating it over a map. */

#card-filter {
  /* Fills the column its own padding included, so it still fits once the sidebar shows a scrollbar. */
  box-sizing: border-box;
  width: 100%;
  padding: 0 5px 5px;
}

.gallery-filter-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;

  /* The 40px of headroom matches the map sidebar's, so the two panels start at the same distance from the navbar. */
  padding: 40px 5px 0;
  margin: 0 0 16px;
}

#filter-header {
  font: var(--text-subtitle-bold);
  color: var(--color-neutral-black);
  margin: 0;
}

#clear-filters {
  gap: 4px;
}

/* .button-ps sets `display: inline-flex`, which outranks the browser's `[hidden] { display: none }`, so the button
   would stay on screen while no filter is applied without this. */
#clear-filters[hidden] {
  display: none;
}

/* Mobile disclosure toggle standing in for the "Filter By" heading; shown only under the shell breakpoint. */
.gallery-filter-toggle {
  display: none;
}

@media (width <= 768px) {
  /* Collapsed, the sections are display: none, so the column leaves no gap above the cards. */
  #card-filter {
    padding: 0 10px;
  }

  /* The 40px of map-aligned headroom is for the side-by-side layout; stacked, the strip hugs the navbar. */
  .gallery-filter-header {
    padding: 8px 10px 0;
    margin-bottom: 0;
  }

  /* The toggle button carries the same "Filter By" text, so the heading would duplicate it. */
  #filter-header {
    display: none;
  }

  .gallery-filter-toggle {
    display: flex;
    align-items: center;
    flex: 1;
    gap: 6px;
    min-height: 44px;
    padding: 0;
    border: none;
    background: none;
    font: var(--text-subtitle-bold);
    color: var(--color-neutral-black);
    text-align: left;
    cursor: pointer;
  }

  .gallery-filter-toggle:focus-visible {
    outline: 2px solid var(--color-asphalt-400);
    outline-offset: -2px;
  }

  .gallery-filter-toggle__icon {
    width: 16px;
    height: 16px;
    flex: none;
    transition: transform 150ms ease;
  }

  .gallery-filter-toggle[aria-expanded="true"] .gallery-filter-toggle__icon {
    transform: rotate(180deg);
  }

  #gallery-filter-sections {
    display: none;
  }

  .sidebar.mobile-visible #gallery-filter-sections {
    display: block;
  }
}

@media (prefers-reduced-motion: reduce) {
  .gallery-filter-toggle__icon {
    transition: none;
  }
}
#gallery {
  display: flex;

  /* `clip`, not `hidden`: `hidden` would make this a scroll container, which disables the sidebar's sticky. */
  overflow-x: clip;
}

.paging {
  display: inline-block;
  font-size: 30px;
  background-color: var(--color-neutral-white);
  border-radius: 5px;
  border-width: 1px;
  margin: 0 2px;
}

.paging:disabled {
  border-width: 0.2px;
  opacity: 0.5;
}

/* Same predicate as the cards' vote row: a comfortable target is about the pointer, not the layout width. */
@media (pointer: coarse) {
  .paging {
    min-width: 44px;
    min-height: 44px;
  }
}

#horizontal-line {
  border-bottom: 1px solid gray;
}

/* Sticky, not fixed, so the column keeps its place in the flow: the page is then always at least as tall as the
   sidebar and the footer starts below it, even when the results fill less than one row of cards (#4778). Sticking
   ends at #gallery's bottom edge, so the sidebar never rides down over the paging controls or footer. */
.sidebar {
  position: sticky;
  top: calc(var(--navbar-height) + var(--test-banner-height, 0px));

  /* A stretched flex item is as tall as the row and so has nowhere to stick to; this keeps it its own height. */
  align-self: flex-start;
  flex: none;

  /* border-box so the padding comes out of the 275px the cards are laid out against, rather than widening the
     column past it. */
  box-sizing: border-box;
  width: 275px;
  padding-left: 10px;
}

/* Hidden as a whole rather than by an inner span, so the padded box takes no room in the stacked phone layout. */
#labels-not-found-text {
  display: none;
  position: absolute;
  width: 100%;
  text-align: center;
  padding-top: 20px;
}

.page-control {
  padding-bottom: 15px;
  display: flex;
  margin: auto;
  width: fit-content;
}

.gallery-footer {
  padding-top: 5px;
  padding-bottom: 10px;
  position: relative;
  width: 100%;
  min-height: 40px;
  text-align: center;
  color: #585c63;
  font-size: 12px;
  font-style: italic;
  line-height: 1.6em;
  font-family: raleway, sans-serif;
}

/* Takes the rest of the flex row beside the sidebar; min-width: 0 lets it shrink instead of forcing #gallery wider. */
#gallery-content {
  flex: 1;
  min-width: 0;
  padding: 10px;
}

/* Gallery's inline expanded view — a fixed overlay floating over the card grid (the grid never reflows around it;
   cards to its left stay visible and clickable for browsing). The max caps keep the panel content-scaled on large
   monitors — uncapped, the viewport-derived sizing balloons the card (and its flex-grown pano) on ≥27" screens
   while laptops sit under the caps either way. */
.gallery-expanded-view {
  position: fixed;
  top: calc(var(--navbar-height) + 1vh);
  right: 3vw;
  z-index: 1000; /* Above the cards and sticky sidebar, below the navbar (--navbar-z-index: 1030). */

  /* Content-hugging height (the pano's fixed aspect ratio drives it), like the modal: no orphaned white space
     when sections collapse. Short viewports scroll inside the card instead of shrinking the pano. */
  height: auto;
  max-height: calc(100vh - var(--navbar-height) - 2vh);
  width: 52vw;
  max-width: 720px;
  border-radius: 12px;
  background: var(--color-neutral-white);
  box-shadow: 0 12px 40px rgb(0 0 0 / 35%);
  visibility: hidden;
}

.cards {
  display: grid;

  /* The 23vw floor keeps desktop at ~3 cards across; narrower windows fall to 2 then 1 columns. The inner min()
     caps the track at the content box, so a viewport under ~300px — the point where a 280px track stops fitting —
     shrinks the card rather than overflowing. auto-fill (not auto-fit) keeps a short last page's cards at normal
     width. */
  grid-template-columns: repeat(auto-fill, minmax(min(max(280px, 23vw), 100%), 1fr));
  gap: clamp(10px, 1.2vw, 24px);
}

/* There is no specific intended function for hover/click on labels on the gallery page.
We should allow the pointer events to pass through and behave the same way as they do on the background. */
.label-icon-gallery, .icon-outline {
  pointer-events: none;
}

/* Scoped to the card badge, not every .ai-icon-marker on the page: cqw against .gallery-card keeps it proportional
   to the card, and the expanded view's marker has no size container to resolve against — it keeps main.css's size. */
.ai-icon-marker-card {
  width: clamp(12px, 3cqw, 16px);
  height: clamp(12px, 3cqw, 16px);
  top: -6px;
  left: -5px;
}

/*
 * Phone / narrow layout: the filter column stacks above the cards (its sections behind a disclosure — see
 * filter.css) and the expanded view becomes a full-screen sheet. 768px is the shell breakpoint the dashboard
 * and API docs use.
 */
@media (width <= 768px) {
  #gallery {
    flex-direction: column;
  }

  /* Sticky is for the side-by-side layout; stacked, the column scrolls with the page at full width. */
  .sidebar {
    position: static;
    width: 100%;
    padding-left: 0;
  }

  /* Resolves against the initial containing block, which the stacked sidebar now overlaps. */
  #labels-not-found-text {
    position: static;
  }

  /* Full-screen sheet below the navbar (and test banner). dvh tracks the visible viewport under mobile
     toolbars. Kept visibility-toggled like the desktop overlay; left/right: 0 also keeps the closed sheet
     inside the viewport for the e2e overflow walk, which measures hidden-but-laid-out boxes. */
  .gallery-expanded-view {
    top: calc(var(--navbar-height) + var(--test-banner-height, 0px));
    right: 0;
    left: 0;
    width: auto;
    max-width: none;
    max-height: calc(100dvh - var(--navbar-height) - var(--test-banner-height, 0px));
    border-radius: 0;
  }
}
.gallery-tag {
  display: inline-block;
  margin: 2px;
  padding: 0 5px;
  border: 1px solid var(--color-neutral-black);
  border-radius: 10px;
  text-align: left;
  background-color: var(--color-neutral-white);
  color: var(--color-neutral-black);
  width: fit-content;
  white-space: nowrap;
  max-width: 98%;
  overflow: hidden;
  text-overflow: ellipsis;
}

.thumbnail-tag {
  cursor: default;
  font-weight: bold;
  padding: 1px 5px;
  color: var(--color-asphalt-500);
}

.not-added {
  background-color: var(--color-neutral-white);

  /* Card-relative like .card-data: the popover renders inside the card (see TagDisplay). */
  font-size: max(11px, 2.4cqw);
  margin: 1px;
}

.additional-count {
  margin: 3px -2px;
  border-style: none;
  font-weight: bold;
  cursor: pointer;
  background-color: inherit;
}

.additional-tag-popover {
  width: fit-content;
  max-width: 250px;
}

.additional-tag-popover-content {
  padding: 5px 10px;
}
