/* Selections pane. Groups render as rows, never a card grid: see
   PRODUCT.md and DESIGN.md sections 5 and 6. Consumes tokens.css and
   base.css custom properties; defines no new design token, only
   component-scoped values. */

/* #selections-root (style.css, not owned by this file) sets no width or
   inline padding, so this is the pane's own shell: without it, rows run
   edge to edge of the viewport instead of sharing the gutter every other
   page uses. */
.sel-pane {
  width: min(100% - 2.5rem, var(--shell));
  margin-inline: auto;
  padding-block: var(--sp-6) var(--sp-9);
  display: flex;
  flex-direction: column;
  gap: var(--sp-8);
}

/* --- Offline banner: sticky, honest, never silent. -------------------- */
.sel-banner {
  position: sticky;
  top: 0;
  z-index: 20;
  padding: var(--sp-3) var(--sp-4);
  background: var(--fg);
  color: var(--bg);
  font-size: var(--step--1);
  text-align: center;
}

.sel-banner[hidden] {
  display: none;
}

/* --- Contents list: a dossier has a contents page, so this is native
   rather than bolted on. Every decision on this page, ruled, numbered,
   anchored to its group, with its state as an eyebrow beside it. No
   pills, no boxes: structure comes from the hairline rule and the
   eyebrow, same as everywhere else on the site. -------------------------- */
.sel-contents {
  padding-bottom: var(--sp-5);
  border-bottom: 1px solid var(--rule-strong);
}

.sel-contents__eyebrow {
  margin-bottom: var(--sp-3);
  font-size: var(--step--2);
  font-weight: 650;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--fg-subtle);
}

.sel-contents__list {
  display: flex;
  flex-direction: column;
}

.sel-contents__item {
  border-top: 1px solid var(--rule);
}

.sel-contents__item:first-child {
  border-top: none;
}

.sel-contents__link {
  display: flex;
  align-items: baseline;
  gap: var(--sp-3);
  min-height: 44px;
  padding-block: var(--sp-2);
  color: inherit;
  text-decoration: none;
}

.sel-contents__link:hover .sel-contents__name {
  color: var(--accent-strong);
}

.sel-contents__num {
  flex: none;
  font-family: var(--font-mono);
  font-size: var(--step--2);
  color: var(--fg-subtle);
}

.sel-contents__name {
  flex: 1;
  font-size: var(--step-0);
  font-weight: 500;
}

.sel-contents__state {
  flex: none;
  font-size: var(--step--2);
  font-weight: 650;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--fg-subtle);
}

.sel-contents__state--chosen,
.sel-contents__state--booked {
  color: var(--accent-strong);
}

/* --- Group ------------------------------------------------------------- */
.sel-group {
  display: flex;
  flex-direction: column;
  gap: var(--sp-4);
  padding-top: var(--sp-6);
  border-top: 1px solid var(--rule);
}

.sel-group:first-child {
  padding-top: 0;
  border-top: none;
}

.sel-group__heading {
  font-family: var(--font-display);
  font-size: var(--step-3);
  font-weight: 600;
  line-height: 1.15;
}

.sel-group__meta {
  margin-top: var(--sp-1);
  font-size: var(--step--1);
  color: var(--fg-muted);
}

.sel-group__reco {
  max-width: var(--measure);
  font-size: var(--step-0);
  line-height: 1.6;
  color: var(--fg-muted);
}

.sel-group__reco-label {
  display: inline-block;
  margin-right: var(--sp-2);
  font-size: var(--step--2);
  font-weight: 650;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--accent);
}

/* --- Rows list: a catalogue line, not a card. No border, no radius, no
   background at rest. A hairline rule beneath each row is the only
   division, until a row wins and drenches. ------------------------------- */
.sel-rows {
  display: flex;
  flex-direction: column;
}

.sel-row {
  border-bottom: 1px solid var(--rule);
}

.sel-row:last-child {
  border-bottom: none;
}

.sel-row__summary {
  display: grid;
  grid-template-columns: 7.5rem 1fr auto;
  align-items: center;
  gap: var(--sp-4);
  width: 100%;
  padding-block: var(--sp-3);
  background: none;
  border: none;
  text-align: left;
  cursor: pointer;
  font: inherit;
  color: inherit;
}

.sel-row__summary:hover {
  background: var(--bg-raised);
}

/* Letterboxed plate, sized to actually distinguish one suite from
   another against the new full-viewport masthead: 7.5rem, up from the
   previous build's 5.5rem. City-tinted, not flat grey, so a slow
   connection or a genuinely image-less option both read as deliberate
   rather than as a missing asset. */
.sel-row__plate {
  width: 7.5rem;
  aspect-ratio: 4 / 3;
  background: var(--accent-soft);
  border: 1px solid var(--rule);
  border-radius: var(--radius-s);
  overflow: hidden;
  display: flex;
  align-items: center;
  justify-content: center;
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .sel-row__plate {
    border: none;
  }
}

:root[data-theme="dark"] .sel-row__plate {
  border: none;
}

/* --- Per-city character, one axis: plate aspect ratio only. Doha reads
   vertical towers and horizon; Barcelona reads a denser street facade.
   Brussels stays at the default, matching its deliberately plain brief. --- */
[data-city="doha"] .sel-row__plate {
  aspect-ratio: 3 / 4;
}

[data-city="barcelona"] .sel-row__plate {
  aspect-ratio: 1 / 1;
}

/* cover, not contain. The source photographs are 4:3 and the plate is 3:4 in
   Doha and 1:1 in Barcelona, so contain letterboxed every one of them: bands
   of plate background above and below a shrunken image. It also cancelled the
   per-city ratios above, which can only shape anything if the image fills the
   frame. The full uncropped frame is what the record's contact sheet is for. */
/* The advisor's rows are a record to read, not a choice to make. The summary
   keeps its shape so the page reads the same as the traveller's, and drops
   the affordances for an action she cannot take. */
[data-role="advisor"] .sel-row__summary {
  cursor: default;
}

[data-role="advisor"] .sel-row__summary:hover {
  background: none;
}

[data-role="advisor"] .sel-row--winner .sel-row__summary:hover {
  background: none;
}

.sel-row__plate img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.sel-row__plate-empty {
  font-size: var(--step--2);
  color: var(--fg-subtle);
}

.sel-row__body {
  min-width: 0;
}

.sel-row__name {
  display: flex;
  align-items: baseline;
  gap: var(--sp-2);
  font-size: var(--step-1);
  font-weight: 600;
}

.sel-row__badge {
  font-size: var(--step--2);
  font-weight: 650;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--accent);
}

.sel-row__meta,
.sel-row__note {
  display: block;
  font-size: var(--step--1);
  color: var(--fg-muted);
  margin-top: 0.15em;
}

.sel-row__note {
  color: var(--fg-subtle);
}

.sel-row__price {
  text-align: right;
  white-space: nowrap;
}

/* AUD leads: the headline figure is what was actually spent, in the
   city's gold. The native currency the supplier quotes in is subtext, and
   provenance is an eyebrow beneath both. */
.sel-row__price-aud {
  display: block;
  font-family: var(--font-mono);
  font-size: var(--step-2);
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  color: var(--highlight);
  line-height: 1.1;
}

.sel-row__price-aud--unavailable {
  font-size: var(--step-0);
  font-weight: 500;
  color: var(--fg-subtle);
}

.sel-row__price-native {
  display: block;
  margin-top: 3px;
  font-family: var(--font-mono);
  font-size: var(--step--1);
  color: var(--fg-muted);
}

.sel-row__price-not-priced {
  font-size: var(--step-0);
  font-weight: 600;
  color: var(--fg-subtle);
  font-style: italic;
}

.sel-row__provenance {
  display: block;
  margin-top: var(--sp-2);
  font-size: var(--step--2);
  font-weight: 650;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--fg-subtle);
}

.sel-row__provenance a {
  color: inherit;
}

.sel-row__provenance--stale {
  color: var(--highlight);
}

/* --- Collapsed "N other options" line ----------------------------------- */
.sel-collapsed {
  padding-block: var(--sp-2);
}

.sel-collapsed__button {
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-3);
  padding: var(--sp-2) var(--sp-3);
  background: none;
  border: none;
  border-bottom: 1px solid var(--rule);
  color: var(--fg-muted);
  font-size: var(--step--1);
  text-align: left;
  cursor: pointer;
}

.sel-collapsed__button:hover {
  color: var(--fg);
  background: var(--bg-raised);
}

.sel-collapsed__chevron {
  width: 0.5rem;
  height: 0.5rem;
  flex: none;
  border-right: 1.5px solid currentColor;
  border-bottom: 1.5px solid currentColor;
  transform: rotate(45deg);
  transition: transform var(--dur-fast) var(--ease-quart);
}

.sel-collapsed__button[aria-expanded="true"] .sel-collapsed__chevron {
  transform: rotate(-135deg);
}

/* --- The selection view: a winning row does not get a tinted background
   and a badge. It drenches, exactly like the masthead, and its record
   opens inside that same slab so choosing and recording read as one act
   rather than two screens. -------------------------------------------- */
.sel-row--winner {
  background: var(--brand-900);
  color: var(--brand-050);
  border-bottom: none;
}

.sel-row--winner .sel-row__summary {
  padding-inline: var(--sp-5);
}

.sel-row--winner .sel-row__summary:hover {
  background: color-mix(in oklch, var(--brand-050) 6%, transparent);
}

.sel-row--winner .sel-row__meta,
.sel-row--winner .sel-row__note {
  color: color-mix(in oklch, var(--brand-050) 72%, transparent);
}

.sel-row--winner .sel-row__badge {
  color: var(--accent2-400);
}

.sel-row--winner .sel-row__price-aud {
  color: var(--accent2-400);
}

.sel-row--winner .sel-row__price-native,
.sel-row--winner .sel-row__provenance {
  color: color-mix(in oklch, var(--brand-050) 64%, transparent);
}

.sel-row--winner .sel-row__plate {
  border: 1px solid color-mix(in oklch, var(--brand-050) 30%, transparent);
}

/* --- Record: the promoted row's editable state, inside the same slab. -- */
/* Grid-template-rows 0fr to 1fr: the standard way to animate to an
   intrinsic height without animating `height` itself, which would thrash
   layout. Mounts closed on every render; selections.js flips .is-open on
   next frame so the expand always plays, not just on the first promotion.
   The global prefers-reduced-motion rule in tokens.css already forces
   transition-duration to 1ms here, so no separate guard is needed. */
.sel-record-wrap {
  display: grid;
  grid-template-rows: 0fr;
  background: var(--brand-900);
  transition: grid-template-rows var(--dur-mid) var(--ease-expo);
}

.sel-record-wrap.is-open {
  grid-template-rows: 1fr;
}

.sel-record {
  min-height: 0;
  overflow: hidden;
  padding: 0 var(--sp-5) var(--sp-5);
  background: var(--brand-900);
  color: var(--brand-050);
  /* The gold rule that closes the slab at the bottom. */
  border-bottom: 3px solid var(--accent2-500);
  display: flex;
  flex-direction: column;
  gap: var(--sp-4);
}

/* --- The contact sheet -------------------------------------------------
   A room is judged by looking at it, so the record opens with the whole set
   of photographs at a size worth reading rather than the row's 120px plate.

   Full-bleed: negative margins pull the track out to the slab edges and the
   padding is restored inside the scroll container, so the first frame starts
   on the record's own text column while the sheet itself runs edge to edge.
   The frame width is under 100% on purpose. The sliver of the next
   photograph is the only thing telling you more exist, and a snapping track
   without it reads as one badly cropped image.

   No shadow anywhere here, per the Flat Rule: the photographs sit on the
   dark slab and the ground does the separating. Radius is the one permitted
   exception, --radius-s on a photographic plate. Gold is already spent on
   this surface on the line total, so the controls stay in the neutral ramp
   rather than opening a second gold. ------------------------------------- */
.sel-gallery {
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
}

.sel-gallery__track {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: 86%;
  gap: var(--sp-3);
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scroll-snap-type: x mandatory;
  margin-inline: calc(var(--sp-5) * -1);
  padding-inline: var(--sp-5);
  /* Snapped frames line up with the record's text column rather than with
     the bleeding edge of the slab. Without this the first frame sits under
     the padding and every restored position is off by it. */
  scroll-padding-inline: var(--sp-5);
  scrollbar-width: none;
}

.sel-gallery__track::-webkit-scrollbar {
  display: none;
}

.sel-gallery__track:focus {
  outline: none;
}

.sel-gallery__track:focus-visible {
  outline: 2px solid var(--accent2-400);
  outline-offset: 2px;
}

.sel-gallery__shot {
  width: 100%;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  /* start, not center. Frame N's snap position then sits at exactly N strides
     from the origin, which is the arithmetic the counter, the arrow steps and
     the restore-after-render all use. Under centre alignment the snap points
     sit half a leftover-width off that, so every programmatic scroll landed
     near a frame and was then pulled somewhere else by the snap: the sheet
     drifted out of agreement with its own counter, most visibly when a resize
     changed the leftover width. It also reads better, each frame landing on
     the record's text column rather than floating mid-slab. */
  scroll-snap-align: start;
  border-radius: var(--radius-s);
  /* Holds the frame's height while the image decodes, so the record does not
     jolt as each one arrives. */
  background: color-mix(in oklch, var(--brand-050) 8%, transparent);
}

.sel-gallery__foot {
  display: flex;
  align-items: baseline;
  gap: var(--sp-3);
}

/* The eyebrow default carries a bottom margin for stacked page structure.
   Here they sit on one line with the controls, so it is cleared. */
.sel-gallery__foot .eyebrow {
  margin-bottom: 0;
  color: color-mix(in oklch, var(--brand-050) 62%, transparent);
}

.sel-gallery__count {
  font-variant-numeric: tabular-nums;
}

.sel-gallery__credit {
  color: color-mix(in oklch, var(--brand-050) 42%, transparent);
}

.sel-gallery__nav {
  margin-left: auto;
  display: flex;
  gap: var(--sp-1);
}

/* 44px, because this is the control you press repeatedly, one-handed, while
   deciding. The glyph is small; the target is not. */
.sel-gallery__arrow {
  min-width: 44px;
  min-height: 44px;
  display: flex;
  align-items: center;
  justify-content: center;
  font: inherit;
  font-size: var(--step-2);
  line-height: 1;
  background: none;
  color: var(--brand-050);
  border: 1px solid color-mix(in oklch, var(--brand-050) 22%, transparent);
  border-radius: 0;
  cursor: pointer;
}

.sel-gallery__arrow:hover {
  border-color: color-mix(in oklch, var(--brand-050) 55%, transparent);
}

.sel-gallery__arrow:focus {
  outline: none;
}

.sel-gallery__arrow:focus-visible {
  outline: 2px solid var(--accent2-400);
  outline-offset: 2px;
}

/* Wider than a phone: the frames narrow so two sit side by side, which is
   what makes it a contact sheet to compare across rather than a slideshow to
   step through one at a time. */
@media (min-width: 30rem) {
  .sel-gallery__track {
    grid-auto-columns: 46%;
  }
}

.sel-record__reference {
  margin: 0;
  font-size: var(--step--1);
  color: color-mix(in oklch, var(--brand-050) 72%, transparent);
}

.sel-record__grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr));
  gap: var(--sp-4) var(--sp-5);
  padding-top: var(--sp-4);
  border-top: 1px solid color-mix(in oklch, var(--brand-050) 26%, transparent);
}

.sel-field {
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
}

.sel-field--wide {
  grid-column: 1 / -1;
}

.sel-field label {
  font-size: var(--step--2);
  font-weight: 650;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: color-mix(in oklch, var(--brand-050) 70%, transparent);
}

/* Hairline underline, not a box: a box would make this a form, and it is
   a ledger. Mono throughout, with tabular figures on the numeric fields,
   matching the record's own line total below. */
.sel-field input,
.sel-field select,
.sel-field textarea {
  padding: 0 0 var(--sp-2);
  background: none;
  border: none;
  border-bottom: 1px solid color-mix(in oklch, var(--brand-050) 42%, transparent);
  border-radius: 0;
  color: var(--brand-050);
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  /* 16px floor, not the fluid --step-0, which resolves to 15.64px at phone
     width. iOS Safari zooms the page when you focus an input under 16px,
     and these are the fields used to record a booking reference
     one-handed. An input size is a device constraint, not a typographic
     one. */
  font-size: max(16px, var(--step-0));
  min-height: 44px;
}

.sel-field textarea {
  min-height: 4.5rem;
  padding-top: var(--sp-2);
  resize: vertical;
}

.sel-field input::placeholder,
.sel-field textarea::placeholder {
  color: color-mix(in oklch, var(--brand-050) 38%, transparent);
}

.sel-record__foot {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  justify-content: space-between;
  gap: var(--sp-4) var(--sp-5);
  padding-top: var(--sp-4);
  border-top: 1px solid color-mix(in oklch, var(--brand-050) 26%, transparent);
}

/* The line total, AUD leading and set at the top of the scale: the
   figure that matters most on this surface, showing its own arithmetic
   underneath so it reads as derived rather than typed. */
.sel-record__total-num {
  display: block;
  font-family: var(--font-mono);
  font-size: var(--step-3);
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  color: var(--accent2-400);
  line-height: 1;
}

.sel-record__total-num--unpriced {
  font-size: var(--step-1);
  font-weight: 500;
  font-style: italic;
  color: color-mix(in oklch, var(--brand-050) 60%, transparent);
}

.sel-record__total-sub {
  display: block;
  margin-top: 3px;
  font-family: var(--font-mono);
  font-size: var(--step--1);
  color: color-mix(in oklch, var(--brand-050) 64%, transparent);
}

.sel-record__actions {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
}

.sel-release,
.sel-book {
  font: inherit;
  font-size: var(--step--2);
  font-weight: 650;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  min-height: 44px;
  padding: 0 var(--sp-5);
  border: 1px solid var(--brand-050);
  border-radius: 0;
  background: var(--brand-050);
  color: var(--brand-900);
  cursor: pointer;
}

.sel-release {
  background: none;
  color: var(--brand-050);
  border-color: color-mix(in oklch, var(--brand-050) 42%, transparent);
}

.sel-book--booked {
  background: var(--accent2-400);
  border-color: var(--accent2-400);
  color: var(--brand-900);
}

.sel-status {
  font-size: var(--step--2);
  color: color-mix(in oklch, var(--brand-050) 60%, transparent);
}

.sel-status--saving {
  color: color-mix(in oklch, var(--brand-050) 80%, transparent);
}

.sel-status--failed {
  color: var(--accent2-400);
}

/* Saving to saved is a quiet, fast fade: never a flash. A failure carries
   more weight, since only that one needs you to act: a slower, larger
   entrance, still a plain ease-out with no bounce or elastic, matching the
   motion tokens' own rule. */
@media (prefers-reduced-motion: no-preference) {
  .sel-status {
    animation: sel-status-in var(--dur-fast) var(--ease-quart) both;
  }

  .sel-status--failed {
    animation: sel-status-in-failed var(--dur-mid) var(--ease-expo) both;
  }
}

@keyframes sel-status-in {
  from { opacity: 0; }
  to { opacity: 1; }
}

@keyframes sel-status-in-failed {
  from { opacity: 0; transform: scale(0.92); }
  to { opacity: 1; transform: scale(1); }
}

/* The same notice on a row that has no record: a write that failed on an
   option after it stopped being the winner. It sits on the page's light
   ground rather than the record's dark slab, so it takes --accent and the
   page focus ring instead of accent2-400, matching the rule stated below.
   Indented to the row body's text column, past the plate, so it reads as
   belonging to that option and not to the group. */
.sel-row > .sel-status {
  display: block;
  /* The vertical padding is hit-target clearance, not rhythm. This line is
     boxed in on both sides by other tap targets: the row's own toggle button
     ends exactly where this begins, and the next row's toggle begins just
     below. Retry needs to grow to a thumb-sized target without reaching into
     either, so the clearance it grows into is reserved here. */
  padding: var(--sp-4) 0 var(--sp-4) calc(7.5rem + var(--sp-4));
  color: var(--accent);
}

.sel-row > .sel-status .sel-status__retry {
  color: var(--accent);
}

.sel-status__retry:focus-visible {
  outline: 2px solid var(--accent2-400);
  outline-offset: 2px;
}

.sel-row > .sel-status .sel-status__retry:focus-visible {
  outline-color: var(--accent);
}

.sel-status__retry {
  position: relative;
  margin-left: var(--sp-2);
  background: none;
  border: none;
  padding: 0;
  color: var(--accent2-400);
  text-decoration: underline;
  cursor: pointer;
  font: inherit;
  font-size: inherit;
}

/* The word Retry sets at roughly 26 by 17 pixels, which is a fine link and a
   poor thumb target. It appears only when a write has failed, so it is the
   one control on the page you reach for while something is going wrong, and
   most often on a phone. The hit area is grown with a pseudo-element rather
   than padding so the target clears 44px without moving the text it sits
   beside.

   Every growth is capped at the clearance actually available, never assumed.
   A target that reaches past its own gap sits on top of the neighbouring
   control and quietly takes taps meant for it, which is a worse bug than a
   small button. In the record the neighbours are close, so the reach stays
   modest; on a row the clearance is reserved above, so it can grow to a
   thumb: 17px of text plus 14 either side clears the 44px minimum. */
.sel-status__retry::after {
  content: "";
  position: absolute;
  inset: -6px -12px;
}

.sel-row > .sel-status .sel-status__retry::after {
  inset: -14px -12px;
}

/* --- Focus: extends the pattern in base.css. The main job here is typing
   a rate and a booking reference into a form, so an inconsistent ring is a
   correctness bug, not decoration. The record sits on a permanently dark
   slab regardless of site theme, so its own controls ring in accent2-400
   rather than the page's --accent, which is tuned for the light ground. -- */
.sel-row__summary:focus-visible,
.sel-release:focus-visible,
.sel-book:focus-visible,
.sel-collapsed__button:focus-visible,
.sel-contents__link:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

.sel-row--winner .sel-row__summary:focus-visible {
  outline-color: var(--accent2-400);
}

.sel-record input:focus-visible,
.sel-record select:focus-visible,
.sel-record textarea:focus-visible {
  outline: 2px solid var(--accent2-400);
  outline-offset: 3px;
}

/* --- Loading skeleton: fixed height so nothing reflows ------------------ */
.sel-row--skeleton .sel-row__summary {
  cursor: default;
}

.sel-row--skeleton .sel-row__plate,
.sel-row--skeleton .sel-skel-line {
  background: var(--bg-sunken);
  border-color: transparent;
}

.sel-skel-line {
  display: block;
  height: 0.85em;
  border-radius: var(--radius-s);
  background: var(--bg-sunken);
}

.sel-skel-line + .sel-skel-line {
  margin-top: var(--sp-2);
  width: 60%;
}

@media (prefers-reduced-motion: no-preference) {
  .sel-row--skeleton .sel-row__plate,
  .sel-skel-line {
    animation: sel-pulse 1.4s ease-in-out infinite;
  }
}

@keyframes sel-pulse {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.55; }
}

/* --- Reopening the collapsed line: the returning rows unfold as a group
   rather than appearing as a block. selections.js sets animation-delay
   per row, about 25ms apart, only on the render that actually reopens a
   set (not on every unrelated re-render of an already-open group). ------- */
@media (prefers-reduced-motion: no-preference) {
  .sel-row--reveal {
    animation: sel-row-reveal var(--dur-mid) var(--ease-expo) both;
  }
}

@keyframes sel-row-reveal {
  from { opacity: 0; transform: translateY(-0.35rem); }
  to { opacity: 1; transform: translateY(0); }
}

/* --- Small screens -------------------------------------------------------
   29.99rem, not 30rem, matching style.css. At exactly 30rem a max-width: 30rem
   and a min-width: 30rem both match, so source order silently decides. Left at
   30rem here the header would take its desktop layout at exactly 480px while
   these rows took their mobile one, on the same page. */
@media (max-width: 29.99rem) {
  .sel-row__summary {
    /* Plate stays at its full width: a hotel suite photo is the one
       thing on the row a smaller thumbnail can't do the job of, so the
       text column gives up width instead. */
    grid-template-columns: 7.5rem 1fr;
    grid-template-areas: "plate body" "plate price";
    /* 44px minimum tap target, as a physical measurement rather than a
       typographic one: literal px, not a spacing token, so it does not
       shift if the type scale is retuned. */
    align-content: center;
    min-height: 44px;
  }

  .sel-row--winner .sel-row__summary {
    padding-inline: var(--sp-4);
  }

  .sel-row__plate {
    grid-area: plate;
  }

  .sel-row__body {
    grid-area: body;
  }

  .sel-row__price {
    grid-area: price;
    text-align: left;
    white-space: normal;
    min-width: 0;
  }

  .sel-record {
    padding-inline: var(--sp-4);
  }

  .sel-collapsed__button,
  .sel-release,
  .sel-book {
    min-height: 44px;
  }

  .sel-release,
  .sel-book {
    display: inline-flex;
    align-items: center;
    justify-content: center;
  }

  /* Single column, not a multi-up grid: the record's the form he fills in
     to actually book something, and at 44px tall each field a multi-up
     pairing gets tight. Full width per field is the same fix the login
     screen already uses. */
  .sel-record__grid {
    grid-template-columns: 1fr;
  }
}
