/* THE RESULTS PAGE
 *
 * Two columns that scroll differently: a list that runs as long as the
 * fleet does, and a chart of the bay that stays where it is. That is the
 * whole layout, and it is the layout because the two halves answer
 * different questions about the same six boats — what does it cost, and
 * where is it — and the answer to the second is only useful while you can
 * still see the first.
 *
 * The chart is not decoration. Half of what "which boat" means in
 * Cartagena is which water it is already in: a hull lying at Manga and a
 * hull lying at Cholón are an hour apart before anybody has boarded.
 */

/* ---- the bar at the top --------------------------------------------
   Shallow on purpose. The home page's hero is a field of water with the
   search floating on it, because up there the search IS the page. Here
   it is a control at the top of a list, so it gets the least water it
   can be legible on, and then the list starts. */
.search-top{position:relative; padding-block:clamp(18px,3vw,30px) clamp(20px,3vw,32px)}
.search-water{
  position:absolute; z-index:0; pointer-events:none;
  inset:calc(-1 * var(--header-h, 76px)) 0 0 0;
  -webkit-mask-image:linear-gradient(#000 62%, transparent 100%);
          mask-image:linear-gradient(#000 62%, transparent 100%);
}
.search-water canvas{width:100%; height:100%; display:block}
/* 50, over the filter rail's 40. The search bar's panels — the month
   calendar, the party stepper, the list of destinations — open downward
   out of this section and across the rail underneath it, and a panel
   cannot win that on its own: z-index inside a stacking context is only
   compared with its siblings, so the panel's own 40 was being measured
   against the other things in THIS wrap, while the wrap's 2 was what
   actually met the rail's 40. The rail won, and its chips came out on
   top of an open calendar. What has to outrank the rail is the box the
   panels are sealed inside, which is this one. */
.search-top .wrap{position:relative; z-index:50}

/* ---- the filter rail ------------------------------------------------
   It follows the header down the page. A list this long is scrolled far
   past the point where the controls that shaped it are off screen, and a
   sort you cannot see is a sort you have forgotten you set. */
/* OPAQUE, and that is the whole point of this change. At 88% with a blur
   behind it the rail was a translucent band that had to cross something
   to be seen — and the something it crosses on this page is the chart.
   The map is sticky too and sticks 2px lower, so on the way down the
   scroll the rail slid across the bay as a smeared grey stripe: a bug on
   a map of a city, which is a bad place to have one. Sand is the page's
   own ground, so an opaque rail over the list is invisible, and over the
   map it is a shelf. */
.search-chips{
  position:sticky; top:var(--header-now, var(--header-h, 76px)); z-index:40;
  background:var(--bg);
  border-bottom:1px solid color-mix(in srgb, var(--ink) 9%, transparent);
}
/* AND IT PAINTS UPWARDS. --header-now is measured by a ResizeObserver, so
   for the frame or two the header spends animating its padding the rail's
   own top edge is behind the number by a few pixels — and a few pixels of
   boat photograph sliding through the seam between two sticky bars is
   exactly the thing this rail was made opaque to stop. The ground is the
   page's own, so painting more of it costs nothing and can never show. */
.search-chips::before{
  content:""; position:absolute; left:0; right:0; bottom:100%;
  height:28px; background:var(--bg);
}
.chips-inner{padding:12px var(--gut); overflow-x:auto; scrollbar-width:none}
.chips-inner::-webkit-scrollbar{display:none}
/* ONE ROW THAT SCROLLS, ALL THE WAY DOWN.
   `.chips-inner` is a horizontal scroller and `.filters` was told not to
   wrap, but a `.filter-set` is a flex row of its own and it kept the
   `flex-wrap:wrap` it has everywhere else on the site. So inside a rail
   built to scroll sideways, each of the two sets folded downwards
   instead: on a phone the eight chips came out as a 119px block of three
   ragged rows, with SORT and ONLY stranded at the head of columns they
   no longer led. Neither set wraps in here. */
.search-chips .filters{margin-bottom:0; flex-wrap:nowrap; white-space:nowrap}
.search-chips .filter-set{flex-wrap:nowrap}

/* ---- the two columns -----------------------------------------------
   Full width rather than inside the site's 1180px column: a map that
   stops short of the edge of the window is a picture of a map. */
.search-split{
  display:grid; grid-template-columns:minmax(0,1fr) minmax(0,40%);
  gap:clamp(20px,2.5vw,34px);
  padding:clamp(18px,2.5vw,28px) var(--gut) clamp(40px,6vw,80px);
  align-items:start;
}
.search-list{min-width:0}
.results-head{margin:0 0 clamp(16px,2vw,22px)}
.results-head h1{font-size:clamp(19px,2.1vw,24px); line-height:1.25; margin:0}
.results-head p{margin:6px 0 0; font-size:14.5px; color:var(--muted)}

/* Two up beside the map, which is what the column is wide enough for
   and what keeps the photograph big enough to choose from. */
.search-list .b-grid{grid-template-columns:repeat(auto-fill, minmax(248px,1fr))}
.search-list .b-shot{aspect-ratio:4/3}

.search-empty{
  padding:44px 30px; text-align:center; border-radius:var(--r-card);
  background:color-mix(in srgb, var(--ink) 4%, transparent);
}
.search-empty h3{font-size:19px; margin:0 0 8px}
.search-empty p{margin:0; color:var(--muted); font-size:15px}

/* ---- the chart ------------------------------------------------------
   Sticky and as tall as what is left of the window under the header and
   the filter rail. */
.search-map-col{position:sticky; top:calc(var(--header-h, 76px) + 62px)}
.search-map{
  position:relative; overflow:hidden;
  height:calc(100vh - var(--header-h, 76px) - 84px);
  min-height:420px;
  border-radius:var(--r-card);
  border:1px solid color-mix(in srgb, var(--ink) 10%, transparent);
  box-shadow:var(--elev);
  background:var(--surface);
  cursor:grab;
  /* Narrow, the map is the first thing on the page and the page is
     scrolled THROUGH it. `none` there would trap the scroll: a reader
     dragging up to reach the list would pan the bay instead. Vertical
     belongs to the page until the column is wide enough for the map to
     be beside the list rather than on top of it. */
  touch-action:pan-y;
}
@media (min-width:1081px){ .search-map{touch-action:none} }
.search-map.dragging{cursor:grabbing}

/* What is drawn while the tiles are still coming, and what is left if
   they never do: water, and a note saying so. A blank white rectangle
   would read as a broken map; this reads as a chart with no coastline
   on it yet, which is what it is. */
.map-plate{
  position:absolute; inset:0;
  background:linear-gradient(180deg,
    color-mix(in srgb, var(--ac) 13%, var(--surface)),
    color-mix(in srgb, var(--su) 17%, var(--surface)));
}
.map-tiles{position:absolute; inset:0}
.map-tiles img{position:absolute; display:block; user-select:none; -webkit-user-drag:none}
.map-pins{position:absolute; inset:0}

/* The price, standing where the boat is. Airbnb's pin, and it is the
   right one: the thing being compared across a map of six boats is the
   number, so the number is the marker rather than a dot you have to
   hover to price. */
.map-pin{
  position:absolute; transform:translate(-50%,-50%);
  display:inline-flex; align-items:center; gap:5px;
  padding:6px 11px; border-radius:999px; border:1px solid transparent;
  background:var(--surface); color:var(--ink);
  font-family:"Lexend",sans-serif; font-size:13px; font-weight:600;
  font-variant-numeric:tabular-nums; white-space:nowrap; cursor:pointer;
  box-shadow:0 1px 3px -1px rgba(var(--sh),.3), 0 8px 18px -10px rgba(var(--sh),.8);
  transition:transform .18s cubic-bezier(.34,1.5,.5,1), background .16s, color .16s;
}
.map-pin:hover{transform:translate(-50%,-50%) scale(1.07)}
.map-pin:focus-visible{outline:2.5px solid var(--ac); outline-offset:2px}
/* Lit from either side: the pointer on the pin, or the pointer on the
   card the pin belongs to. */
.map-pin.lit{background:var(--ink); color:var(--surface); z-index:5;
  transform:translate(-50%,-50%) scale(1.07)}

/* A pier several boats board from. One pin, the cheapest of them, and
   the count — because zooming in does not separate two boats tied to the
   same pontoon, so overlapping labels there can only ever be untangled
   by folding them. Pressing it fans them out. */
.map-pin.group{padding-right:7px}
.map-pin.group .n{
  display:inline-grid; place-items:center; min-width:19px; height:19px;
  padding:0 5px; margin-left:2px; border-radius:999px;
  background:var(--su); color:var(--onacc); font-size:11.5px; font-weight:700;
}
.map-pin.group.lit .n{background:var(--wa); color:var(--ink)}

/* The pier itself, under a fan. Without it the stack of prices floats
   beside the coast with nothing saying which quay it belongs to. */
.map-anchor{
  position:absolute; transform:translate(-50%,-50%);
  width:11px; height:11px; border-radius:50%;
  background:var(--ink); border:2.5px solid var(--surface);
  box-shadow:0 1px 4px -1px rgba(var(--sh),.5);
}

.map-zoom{
  position:absolute; right:12px; top:12px; z-index:6;
  display:grid; gap:1px; border-radius:12px; overflow:hidden;
  box-shadow:0 1px 3px -1px rgba(var(--sh),.3), 0 10px 22px -12px rgba(var(--sh),.8);
}
.map-btn{
  width:34px; height:34px; border:none; cursor:pointer; padding:0;
  background:var(--surface); color:var(--ink);
  font-size:19px; font-weight:500; line-height:1;
  display:grid; place-items:center;
  transition:background .16s;
}
.map-btn:hover{background:#fff}
.map-btn:disabled{color:color-mix(in srgb, var(--ink) 30%, transparent); cursor:default}
.map-btn:focus-visible{outline:2.5px solid var(--ac); outline-offset:-2px}

.map-note{
  position:absolute; left:0; right:0; bottom:0; margin:0; z-index:6;
  display:flex; flex-wrap:wrap; gap:4px 12px; align-items:baseline;
  padding:7px 12px; font-size:11px; line-height:1.4;
  color:var(--muted);
  background:color-mix(in srgb, var(--surface) 88%, transparent);
  backdrop-filter:blur(8px); -webkit-backdrop-filter:blur(8px);
}
.map-note .map-live{color:var(--ink)}
.map-note .map-credit{margin-left:auto}
.map-note a{color:inherit}

/* ---- narrow ---------------------------------------------------------
   One column under the other. The chart stops being sticky, because
   sticking it would mean scrolling the list under a panel that is
   already taking most of the screen. */
@media (max-width:1080px){
  .search-split{grid-template-columns:1fr}
  .search-map-col{position:static; order:-1}
  .search-map{height:min(52vh, 420px); min-height:0}
  .search-list .b-grid{grid-template-columns:repeat(auto-fill, minmax(240px,1fr))}
}
@media (max-width:640px){
  .search-map{height:min(46vh, 340px)}
}

/* =====================================================================
   THE CARD A PIN OPENS

   Pressing a price used to scroll the list to the matching card, which
   meant the answer to "what is that one" appeared somewhere else on the
   screen and you had to look away from the map to read it. The boat
   comes to the pin instead.

   It is the list card's content in a plate: the photograph, the score,
   one line about her, the three facts that decide a charter, and the
   price for the day being searched. The heart is the same `data-fav`
   the list uses, so saving from the map and saving from the list are one
   act — app.js wires that against the document and both copies light.
   ===================================================================== */
.map-card{
  position:absolute; z-index:8; width:264px; max-width:calc(100% - 16px);
  /* the whole card is the boat, so the whole card is pressable */
  cursor:pointer;
  border-radius:16px; overflow:hidden;
  background:var(--surface);
  border:1px solid color-mix(in srgb, var(--ink) 10%, transparent);
  box-shadow:0 4px 12px -4px rgba(var(--sh),.4), 0 26px 50px -22px rgba(var(--sh),.9);
  animation:map-card-in .22s cubic-bezier(.2,.9,.3,1) both;
}
.map-card[hidden]{display:none}
@keyframes map-card-in{from{opacity:0; transform:translateY(6px) scale(.97)} to{opacity:1; transform:none}}

.map-card .mc-shot{display:block; aspect-ratio:16/10; overflow:hidden; background:color-mix(in srgb, var(--ink) 7%, transparent)}
.map-card .mc-shot img{width:100%; height:100%; object-fit:cover; display:block}

/* The two controls that sit on the photograph. The close is on the left
   because the heart has been top-right on every card on this site since
   the fleet grid was built, and moving it here would make the one card
   that opens over a map the one card where saving is somewhere else. */
.mc-x,.mc-fav{
  position:absolute; top:9px; width:30px; height:30px; z-index:2;
  display:grid; place-items:center; border:none; padding:0; cursor:pointer;
  background:none;
}
.mc-x{
  left:9px; border-radius:50%;
  background:color-mix(in srgb, var(--surface) 92%, transparent);
  color:var(--ink);
  box-shadow:0 2px 8px -3px rgba(var(--sh),.5);
}
.mc-x:hover{background:#fff}
.mc-x .ic{width:16px; height:16px}
.mc-fav{right:9px}
.mc-x:focus-visible,.mc-fav:focus-visible{outline:2.5px solid var(--ac); outline-offset:2px}

.mc-body{padding:12px 14px 14px; display:grid; gap:5px}
.mc-line{display:flex; align-items:baseline; gap:10px; color:inherit}
.mc-line h3{
  font-family:"Lexend",sans-serif; font-size:15.5px; font-weight:600; margin:0;
  line-height:1.3; min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
}
.mc-rate{
  margin-left:auto; flex:none; display:inline-flex; align-items:center; gap:4px;
  font-size:13.5px; color:var(--ink); font-variant-numeric:tabular-nums;
}
.mc-rate .ic{width:13px; height:13px}
.mc-rate em{font-style:normal; color:var(--muted)}
.mc-rate.none{color:var(--muted); font-size:12.5px}

.mc-blurb{
  margin:0; font-size:13px; color:var(--muted); line-height:1.45;
  display:-webkit-box; -webkit-line-clamp:2; -webkit-box-orient:vertical; overflow:hidden;
}
.mc-facts{
  margin:2px 0 0; display:flex; flex-wrap:wrap; gap:4px 12px;
  font-size:12.5px; color:var(--muted);
}
.mc-facts span{display:inline-flex; align-items:center; gap:5px; min-width:0}
.mc-facts .ic{width:14px; height:14px; color:var(--ac); flex:none}

.mc-foot{
  display:flex; align-items:center; justify-content:space-between; gap:12px;
  margin-top:8px; padding-top:10px;
  border-top:1px solid color-mix(in srgb, var(--ink) 8%, transparent);
}
.mc-price{display:grid; gap:0}
.mc-price b{font-size:16px; font-weight:700; font-variant-numeric:tabular-nums; line-height:1.2}
.mc-price i{font-style:normal; font-size:11px; color:var(--muted)}

/* The pin whose card is open holds the lit state so the two read as one
   object even while the pointer is somewhere else entirely. */
.map-pin.open{background:var(--ink); color:var(--surface); z-index:6}

/* ---- the tools ------------------------------------------------------ */
.map-tools{
  position:absolute; right:12px; top:12px; z-index:6;
  display:grid; gap:8px; justify-items:end;
}
.map-tools .map-zoom{
  /* BACK INTO THE GRID. `.map-zoom` carries position:absolute with
     right:12/top:12 from when it was hung on the map itself; inside
     .map-tools -- which is absolute, and therefore its containing block
     -- that puts it twelve pixels down from the tools' own top corner,
     which is where the expand button already is. The two have been
     printed on top of each other the whole time; at 34px it read as a
     shadow behind the plus, and at a size a thumb can hit it is half a
     button sticking out from behind another one. The grid above already
     says how they stack and how far apart. */
  position:static;
  display:grid; gap:1px; border-radius:12px; overflow:hidden;
  box-shadow:0 1px 3px -1px rgba(var(--sh),.3), 0 10px 22px -12px rgba(var(--sh),.8);
}
.map-tools > .map-btn{
  border-radius:12px;
  box-shadow:0 1px 3px -1px rgba(var(--sh),.3), 0 10px 22px -12px rgba(var(--sh),.8);
}
.map-btn .ic{width:17px; height:17px}

/* ---- expanded -------------------------------------------------------
   The map beside the list is 40% of a column: enough to choose between
   five boats, not enough to look at the bay. This takes it to the whole
   window and back. */
.search-map.expanded{
  position:fixed; inset:0; z-index:200;
  width:auto; height:auto; min-height:0;
  border-radius:0; border:0;
  box-shadow:none;
}
.search-map.expanded .map-card{width:300px}
/* the page underneath must not scroll behind a full-window map */
html.map-expanded,html.map-expanded body{overflow:hidden}
/* and the sticky header must not float over it */
html.map-expanded .site-header,
html.map-expanded .search-chips{z-index:1}
/* THE COLUMN HAS TO BE RAISED WITH IT. `position:sticky` makes an element
   a stacking context whatever its z-index is, so the expanded map's 200
   was only ever being compared with the other things inside this column —
   and the column itself sat at `auto`, which is level 0, which is where
   the footer is. A full-window map with the site's footer printed across
   it is the result, and it is the sort of thing that looks like a z-index
   race when it is really a context boundary. */
html.map-expanded .search-map-col{z-index:200}

@media (max-width:640px){
  .map-card{width:232px}
}


/* See WHAT A FINGER CAN ACTUALLY HIT at the foot of magik.css. Same
   Leaflet zoom as the live board, and the same reason for the `.search-map`
   prefix: Leaflet's sheet is injected at runtime and lands after this one. */
@media (hover:none) and (pointer:coarse){
  .search-map.leaflet-touch .leaflet-bar a{width:44px; height:44px; line-height:44px}
  /* The chart's own zoom and recentre, which are 34 wide. */
  .map-btn{min-width:44px; min-height:44px}
  /* A price pin IS the boat: tapping one is how you get from the chart
     to a listing, and a group pin stands for several. 30px tall, over a
     moving map, with other pins beside it. The hit area is invisible and
     the pin keeps its drawn size -- a 44px price tag is a label, and a
     chart of them is a chart of labels rather than of boats. */
  .map-pin{position:relative}
  .map-pin::after{
    content:""; position:absolute; left:0; right:0; top:50%;
    height:44px; transform:translateY(-50%);
  }
}

/* =====================================================================
   THE RESULTS PAGE ON A PHONE: A CHART WITH THE LIST ON A SHEET OVER IT

   Stacked, this page was a chart 340px tall with a column of boats under
   it, and the two never met: the chart was too short to tell you
   anything about the bay and it scrolled away the moment you started
   reading the list, so by the time you were choosing you could no longer
   see where any of them were. Two halves of one question, shown one at a
   time, and neither of them big enough.

   So on a phone the page stops being a column and becomes a screen. The
   chart takes all of it, edge to edge under the filter rail, and the
   list rides over it on a sheet you drag: at the foot of the screen it
   is a count and the first boat, pulled up it is the whole list, and
   the chart is still underneath the whole time. That is the same
   arrangement every map-and-list app has arrived at, and for the same
   reason -- it is the only one where moving between the two costs
   nothing.

   Everything here is phone-only. On a wider window the list is a column
   beside the chart, which is the better shape when there is width for
   it, and none of this applies.
   ===================================================================== */
@media (max-width:760px){
  /* The screen: what is left of the window under the header and the
     filter rail. `dvh` so it grows into the space the browser's own
     chrome gives up as you scroll, with `vh` behind it for anything that
     has not got dynamic units. --chips-h is measured in searchmap.js
     because the rail's height depends on the filter chips inside it,
     which depend on the pointer -- a coarse one gets 44px rows. */
  /* ---- THE HERO GOES, AND THAT IS WHAT MAKES THIS A SCREEN ----
     The chart is sized to the window, so it only actually FILLS the
     window when it is AT the top of it -- and it was not, because four
     hundred and sixty pixels of hero sat above it. You landed on the
     results looking at the search you had just run, scrolled, and passed
     through a band where the chart was half on screen with the sheet cut
     off at the seam. A screen you have to scroll into position is not a
     screen.

     So on a phone this page does not have a hero. It does not need one:
     the criteria are in the header, in the summary pill, and the pill
     opens the whole bar as a sheet -- which is a better version of what
     the hero was for and is on screen the whole time rather than only at
     the top of the page.

     AND HIDING IT IS WHAT DOCKS THE BAR. site.js docks when the scroll
     passes a sentinel sitting just under the bar; inside a hidden
     subtree that sentinel measures zero, the threshold comes out
     negative, and the page is already past it at rest. So the bar moves
     into the header at load, which is exactly where this layout needs
     it, and it undocks again by the same measurement the moment the
     window is wide enough for the hero to come back. Nothing had to be
     added to site.js to arrange that. */
  .search-top{display:none}

  /* ---- AND THE SCREEN CLICKS INTO PLACE ----
     The chart is sized to the window but it is still a block in a
     scrolling document, so it only actually FILLS the window at one
     scroll position: a few pixels either side and you are looking at the
     bottom of the hero above it or the top of the footer below, with the
     sheet cut off at the seam. A screen you can stop halfway into is not
     a screen.
     `scroll-snap-stop:always` is the part that matters. Proximity
     snapping alone would tidy up a gesture that ended nearby and let a
     hard flick sail past the whole thing; `always` makes the scroll come
     to rest here whatever the gesture was going to do, so arriving at
     the results always means arriving squarely at them. A second gesture
     carries on to the footer, which is how you get past it.
     `scroll-margin-top` is the header and the filter rail: both are
     sticky, both are over this, and without it "the top of the region"
     means the part of it hidden behind them.
     This file is loaded by search.html and nothing else, so the rule on
     `html` is this page's alone. */
  html{scroll-snap-type:y proximity}
  .search-split{
    scroll-snap-align:start; scroll-snap-stop:always;
    scroll-margin-top:calc(var(--header-now, 76px) + var(--chips-h, 62px));
    display:block; position:relative; padding:0; gap:0;
    height:calc(100vh - var(--header-now, 76px) - var(--chips-h, 62px));
    height:calc(100dvh - var(--header-now, 76px) - var(--chips-h, 62px));
    /* the sheet is taller than the screen and slides within it */
    overflow:hidden;
  }

  /* ---- the chart, behind everything ---- */
  .search-map-col{position:absolute; inset:0; order:0}
  .search-map{
    height:100%; min-height:0; border-radius:0; border:none; box-shadow:none;
    /* THE CHART TAKES THE GESTURE NOW.
       `touch-action` was left alone below 1081 on purpose, and the note
       on the rule above says why: the map was a 340px box halfway down a
       page, and a box that eats a vertical drag is a box you cannot
       scroll past. That is no longer what this is. It is the screen, the
       page behind it does not go anywhere, and a drag on a chart means
       pan -- which on a phone it has never done. */
    touch-action:none;
  }
  /* Expand is what you pressed when the chart was a 340px box. It fills
     the screen now, and what covers it is the sheet, so the button would
     be offering to do the thing that is already done. */
  .search-map [data-expand]{display:none}
  /* and the tools come in off the edge, since there is no longer a
     rounded corner for them to sit inside */
  .map-tools{right:14px; top:14px}

  /* THE CREDIT MOVES TO THE TOP, because the bottom is the sheet now.
     It is a strip across the foot of the chart, which is precisely where
     the list sits at every stop -- so it was being painted over, and the
     one line on this page that is not ours to hide was the line hidden.
     The tile licence requires it to be legible, so it goes where nothing
     covers it. The sentence beside it goes: "5 boats board from 3 piers"
     is a gloss on the pins, and the sheet directly underneath already
     opens with the count. */
  .map-note{
    top:0; bottom:auto; left:auto; right:auto;
    width:max-content; max-width:100%;
    padding:5px 11px; border-radius:0 0 12px 0;
    font-size:11px;
  }
  .map-note .map-live{display:none}
  .map-note .map-credit{margin-left:0}

  /* ---- the sheet ----
     Full height of the screen and translated down to sit at whichever of
     the three stops it is on, rather than resized to them: a transform
     is composited, and a sheet that re-lays a list of boat cards on
     every frame of a drag is a sheet that judders. searchmap.js writes
     `--sheet-y` in pixels; the 100% here is only what it looks like
     before the script has measured anything, which is closed. */
  .search-list{
    /* above the chart and everything drawn on it -- the pins, the tools
       and the credit are all z-index 6 inside the map, and a sheet that
       shares their number is a sheet with map furniture printed through
       it */
    position:absolute; left:0; right:0; top:0; bottom:0; z-index:7;
    display:flex; flex-direction:column; min-width:0;
    background:var(--surface);
    border-radius:22px 22px 0 0;
    border-top:1px solid color-mix(in srgb, var(--ink) 9%, transparent);
    box-shadow:0 -2px 10px -5px rgba(var(--sh),.2), 0 -26px 52px -30px rgba(var(--sh),.8);
    transform:translateY(var(--sheet-y, 100%));
    transition:transform .34s cubic-bezier(.2,.9,.3,1);
    will-change:transform;
  }
  /* Under the finger there is no animation: the sheet is where the
     finger is, and a transition would make it lag behind it. */
  .search-list.is-dragging{transition:none; will-change:transform}

  /* The handle. A wide invisible press target with a small bar drawn in
     the middle of it -- the bar is the affordance and 4px of it is not
     something anybody can grab. */
  .list-grab{
    flex:none; display:grid; place-items:center;
    width:100%; height:30px; padding:0; margin:0;
    border:0; background:none; cursor:grab; touch-action:none;
  }
  .list-grab:active{cursor:grabbing}
  .list-grab-bar{
    display:block; width:38px; height:4px; border-radius:99px;
    background:color-mix(in srgb, var(--ink) 22%, transparent);
    transition:background .18s ease;
  }
  .list-grab:hover .list-grab-bar{background:color-mix(in srgb, var(--ink) 34%, transparent)}
  .list-grab:focus-visible{outline:2.5px solid var(--ac); outline-offset:-4px; border-radius:22px 22px 0 0}

  /* The count stays put while the boats scroll under it, so the sheet
     says what it is holding even when it is closed down to a strip. It
     is the whole of the peek state, and it is centred there the way a
     title on a sheet is rather than ranged left the way a heading on a
     page is. */
  .results-head{
    flex:none; margin:0; padding:0 var(--gut) 12px; text-align:center;
    /* it is also the second thing you can drag the sheet by: the strip
       at the foot of the screen is mostly this, and a handle you have to
       hit exactly is a handle you miss */
    touch-action:none; cursor:grab;
  }
  .results-head h1{font-size:17px}
  .results-head p{margin-top:3px; font-size:13px}

  /* and the boats scroll inside the sheet rather than the page.
     `overscroll-behavior:contain` so running out of list does not hand
     the scroll to the document underneath and carry the whole screen
     away mid-gesture. */
  .search-list .b-grid{
    flex:1 1 auto; min-height:0; overflow-y:auto; overscroll-behavior:contain;
    -webkit-overflow-scrolling:touch;
    grid-template-columns:1fr;
    padding:2px var(--gut) calc(24px + env(safe-area-inset-bottom));
  }

  /* ---- the way back to the chart ----
     Only drawn while the sheet is actually covering it. Centred at the
     foot of the screen, over the sheet, because that is where a thumb
     is and because it belongs to the screen rather than to the list. */
  .to-map{
    position:absolute; z-index:8; left:50%; translate:-50% 0;
    bottom:calc(18px + env(safe-area-inset-bottom));
    display:inline-flex; align-items:center; gap:7px;
    min-height:44px; padding:0 20px; border:0; border-radius:999px;
    background:var(--ink); color:var(--surface); cursor:pointer;
    font-family:"Lexend",sans-serif; font-size:14.5px; font-weight:600;
    box-shadow:0 3px 10px -3px rgba(var(--sh),.4), 0 16px 34px -18px rgba(var(--sh),.9);
    animation:to-map-in .24s cubic-bezier(.2,.9,.3,1) both;
  }
  .to-map[hidden]{display:none}
  .to-map .ic{width:16px; height:16px}
  @keyframes to-map-in{from{opacity:0; transform:translateY(10px)} to{opacity:1; transform:none}}
}

/* The sheet is a phone shape. Anything wider keeps the column beside the
   chart, so the handle and the Map button are not drawn at all. */
@media (min-width:761px){
  .list-grab,.to-map{display:none}
}
