/* The list view of the results (js/layouts.js), in its own file next to style.css. Tokens, type and
 * radii are style.css's; the spec sheet, tabs and shop buttons inside the lead panel are style.css's
 * rules, reused.
 *
 * Sections: the sheet, the lead panel, the list, then the phone rules.
 */

/* ==== The sheet ============================================================================== */
/* One white sheet in the centred dialog, exactly as tall as the lead: the render tile and the
   lead's 32px padding, so the tile sits with the same margin above, below and to its left. The list
   beside it takes that height and scrolls (see .l-list). On a screen too short for that the sheet
   is the viewport less a margin all round (32px clear of the bottom edge), and js/layouts.js
   (settle, which repeats the 88px) zooms the lead down to fit rather than let it scroll. The extra
   24px on top once kept it under the Cards / List switch; the switch went on 2026-10-16 and the
   margin stayed, as the sheet's look. --shot-h is the tile's height (see
   .l-shot). */
.results {
  /* Only until js/layouts.js (settle) has measured the list and set the real height. */
  --shot-h: 754px;
  display: flex;
  flex-direction: column;
  width: min(1240px, 100vw - 48px);
  max-height: calc(100vh - 88px);
  margin-top: 24px;
  cursor: auto;
}
@supports (height: 100dvh) {
  .results { max-height: calc(100dvh - 88px) }
}
/* The lead and the list are two sheets side by side, 12px apart, so the list reads as its own thing
   (Patryk, 2026-10-02): over it the wheel scrolls the list, over the lead it steps the shells (see
   js/layouts.js, onWheel). Each clips its own corners, the lead's for the render tile bleeding to
   its edges. The outline is a shadow, not a border, so it takes no room from what settle measures. */
.l-pane, .l-side {
  background: var(--surface);
  border-radius: 18px;
  box-shadow: 0 0 0 1px var(--line);
  overflow: hidden;
}
.l-pane {
  position: relative;
  min-height: 0;
  display: grid;
}
.results-body {
  flex: 1 1 auto;
  min-height: 0;
  display: grid;
  grid-template-columns: minmax(0, 1fr) 280px;
  gap: 12px;
}
/* One shell, opened from the scene: the lead alone, the sheet narrower by the list it does not have. */
.results.is-single { width: min(960px, 100vw - 48px) }
.results.is-single .results-body { grid-template-columns: minmax(0, 1fr) }

/* The lead's scrollbar (it scrolls only where zoom is not supported) is the faint one Storefolio
   uses: a thin translucent thumb on no track. Chrome and Firefox read scrollbar-width/-color;
   Safari only the ::-webkit-scrollbar rules, where the transparent border narrows the thumb to
   about 4px. The list draws its own (see .l-bar). */
/* A lead that scrolls (a short window, js/layouts.js settle): the render's tile keeps the visible
   height and stays put while the specs scroll past it. */
.results.is-scroll .l-shot { align-self: start; height: var(--shot-h); position: sticky; top: -32px }
.l-lead { scrollbar-width: thin; scrollbar-color: oklch(0 0 0 / .22) transparent }
.l-lead::-webkit-scrollbar { width: 10px; background: transparent }
.l-lead::-webkit-scrollbar-track { background: transparent }
.l-lead::-webkit-scrollbar-thumb {
  background: oklch(0 0 0 / .18);
  background-clip: padding-box;
  border: 3px solid transparent;
  border-radius: 999px;
}
.l-lead::-webkit-scrollbar-thumb:hover { background: oklch(0 0 0 / .34); background-clip: padding-box }

/* ==== The lead panel ========================================================================= */
/* The render on a grey tile down the whole left side; beside it one column (.l-col): the name with
   the price, weight and size on grey tiles, the rest of the specs as a plain list, the shop
   stack, and Amazon's disclosure at the foot, level with the bottom of the tile. The tile takes
   the wider share: the render is never shown past its own pixels (js/layouts.js), so it is the
   grey frame, not a blown-up render, that fills the room and keeps a smaller mouse from reading as
   empty space. Chosen on 2026-10-02 from fourteen arrangements. */
.l-lead {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 380px;
  grid-template-areas: "shot col";
  gap: 0 36px;
  padding: 32px;
  min-height: 0;
  overflow-y: auto;
  overflow-x: hidden;
}
/* Where zoom works, js/layouts.js (settle) fits the lead to the sheet, so it never needs to
   scroll; hidden rather than auto, so a rounding pixel can never bring a scrollbar in and narrow
   the tile. */
@supports (zoom: 1) {
  .l-lead { overflow-y: hidden }
}
/* `dialog img` sizes every image in the dialog to 200px with an auto margin: the sizes here and in
   the list are explicit, and the shop marks get their own rules under a .results scope (below). */
.results img.r-shot {
  flex: 0 0 auto;
  margin: 0;
  object-fit: contain;
  mix-blend-mode: multiply;
  pointer-events: none;
}
/* As tall as the tallest column in the list (js/layouts.js, settle, sets --shot-h), so the tile is
   one size for every shell. It bleeds through the lead's padding to the sheet's top, bottom and
   left edges (Patryk, 2026-10-02), and the sheet's own rounded clip gives it its outer corners. The
   negative margins leave its margin box shorter than the column, so the row is still the column's
   height and settle's measurement holds. */
.l-shot {
  grid-area: shot;
  position: relative;
  min-height: var(--shot-h);
  margin: -32px 0 -32px -32px;
  overflow: hidden;
  background: var(--tile);
}
/* Contained in the box until the script has measured the mouse and placed it, and held back until
   then, so the small render does not flash before the placed one. */
.l-shot img.r-shot { position: absolute; left: 0; top: 0; width: 100%; height: 100%; max-width: none; opacity: 0 }
.l-shot.is-fit img.r-shot { opacity: 1; transition: opacity .15s }
/* The old shell's copy while the lead slides to the next (js/layouts.js, slide): laid over the lead,
   in the same place, and moved out of the sheet with it. */
.l-ghost { position: absolute; inset: 0; pointer-events: none }
.l-col { grid-area: col; display: flex; flex-direction: column; gap: 18px; min-width: 0 }
/* The name, and the price under it, lighter than the name so the two do not compete. */
.l-head { display: flex; flex-direction: column; gap: 4px; min-width: 0 }
.l-head h2 {
  margin: 0;
  font-size: 24px;
  font-weight: 600;
  letter-spacing: -.4px;
  line-height: 1.3;
}
.l-head .price-row { flex: 0 0 auto; margin: 0; padding: 0 }
.l-head .price { font-size: 21px; font-weight: 400; letter-spacing: -.3px; color: inherit }
/* The two figures that say most about a shape, weight and size, on grey tiles. */
.l-figures { display: grid; grid-template-columns: 1fr 1fr; gap: 8px }
.l-figure { display: flex; flex-direction: column; gap: 3px; padding: 12px 14px; background: var(--tile); border-radius: 10px }
.l-figure span { font-size: 12px; color: var(--muted) }
.l-figure strong { font-size: 15px; font-weight: 600; line-height: 1.3 }
/* The rest of the specs: label left, value right, no rules between them — at a dozen rows the
   lines read as a grid of strokes rather than separating anything. */
.l-rows { margin: 0 }
.l-rows div { display: flex; justify-content: space-between; align-items: baseline; gap: 16px; padding: 6px 0 }
.l-rows dt { flex: 0 0 auto; font-size: 13px; color: var(--muted) }
.l-rows dd { margin: 0; font-size: 13.5px; text-align: right }
/* One full-width button per shop, drawn like Amazon's: the mark parked at the left edge, the
   name centred in the whole button. */
/* The grey shops first, the Amazon search under them (js/layouts.js, amazonLast). */
.l-shops .shop-grid { grid-template-columns: 1fr; margin-top: 0 }
.l-shops .buy-btn.shop-search { margin-top: 8px }
.l-shops .shop-grid .buy-btn.is-shop { padding: 13px 16px }
/* The shop stack and Amazon's disclosure under it at the very foot of the column, the last line
   level with the bottom of the tile (the column is stretched to the tile's height and the stack
   pushed down; Patryk, 2026-10-16). */
.l-col { align-self: stretch }
.l-shops { margin-top: auto }
/* The phone card's tabs (js/layouts.js, leadHTML) are the phone's alone; on the desktop the spec
   sheet's wrapper steps aside, so the figures and rows stay children of the column. */
.l-tabs { display: none }
.l-specs { display: contents }
/* The shop's own favicon, on the button's padding line like Amazon's mark. A shop that publishes no
   icon simply has none, and its label centres like any other. */
.results img.shop-icon {
  position: absolute;
  left: 15px;
  top: 50%;
  transform: translateY(-50%);
  width: 18px;
  height: 18px;
  margin: 0;
  mix-blend-mode: normal;
  border-radius: 4px;
}
/* Amazon's "a", pinned to the left edge on the button's own padding line. Out of flow so the label
   stays centred on the button rather than on what is left beside the mark. */
.results img.amz {
  position: absolute;
  left: 16px;
  top: 50%;
  /* The 1px is optical: centring the boxes is not centring the mark, because four fifths of the
     icon's ink is the letter, which sits in the top half of its box with the smile trailing
     underneath — its centre of mass lands about a pixel above the text's. */
  transform: translateY(calc(-50% + 1px));
  /* Both axes given, at the file's own 251:260 ratio: left to size itself the button was one line
     tall until the image arrived and then jumped. */
  width: 16.4px;
  height: 17px;
  /* `dialog img` centres the mouse render with an auto margin, which in a flex row eats the free
     space; and a multiply blend on the black button would blend the white wordmark away. */
  margin: 0;
  mix-blend-mode: normal;
}

/* ==== The list =============================================================================== */
/* Height 0 and at least the row: the column then never sizes the row itself (it would, at 30
   shells tall), it only fills the height the lead sets, and the list scrolls inside it. Its rows
   run edge to edge, so the hover and the picked row fill the column's whole width — which a
   native scrollbar prevents: on Windows it takes a strip of its own, with arrows, that no row
   background reaches. So the native one is hidden and .l-bar, a thin thumb laid over the rows and
   driven by js/layouts.js, stands in for it. The foot fades out while the list is still at its top
   and nothing has been picked (js/layouts.js sets .no-fade after either, for good). */
.l-side { position: relative; height: 0; min-height: 100% }
.l-list {
  height: 100%;
  list-style: none;
  margin: 0;
  padding: 0;
  overflow-y: auto;
  scrollbar-width: none;
  -webkit-mask-image: linear-gradient(to bottom, #000 calc(100% - 64px), transparent);
  mask-image: linear-gradient(to bottom, #000 calc(100% - 64px), transparent);
}
.l-list.no-fade { -webkit-mask-image: none; mask-image: none }
.l-list::-webkit-scrollbar { display: none }
.l-bar {
  position: absolute;
  top: 0;
  right: 3px;
  width: 4px;
  border-radius: 999px;
  background: oklch(0 0 0 / .22);
  cursor: grab;
  touch-action: none;
  /* Out of sight until the pointer is over the list (or the thumb is being dragged). */
  opacity: 0;
  transition: opacity .2s, background .15s, width .15s;
}
.l-side:hover .l-bar, .l-bar.is-drag { opacity: 1 }
/* The phone's drawer button (see the phone rules); the desktop list has no drawer. */
.l-drawer { display: none }
/* The phone card's X (see the phone rules); the desktop closes by its backdrop and Escape. */
.l-close { display: none }
/* The phone's strip of cards (see the phone rules): on the desktop the track steps aside, so the
   pane is still the sheet's grid item, and the neighbours are not drawn. */
.l-track { display: contents }
.l-peek { display: none }
.l-bar:hover, .l-bar.is-drag { width: 6px; background: oklch(0 0 0 / .34) }
.l-bar.is-drag { cursor: grabbing }
.l-item {
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  min-width: 0;
  padding: 11px 20px;
  text-align: left;
  transition: background .18s;
}
.l-item:hover { background: var(--tile) }
/* The lead: the hover grey, a step darker, and nothing else. */
.l-item[aria-current="true"] { background: var(--tile-hover) }
/* The thumbnail is cropped to the mouse (js/layouts.js, fitShot) in a narrow box: a square one
   carried the render's white margins and made every row mostly air. */
.l-thumb { position: relative; flex: 0 0 26px; width: 26px; height: 40px; overflow: hidden }
/* Shown contained until it is placed: a thumbnail that is never measured must still be seen. */
.l-thumb img.r-shot { position: absolute; left: 0; top: 0; width: 100%; height: 100%; max-width: none }
.l-text { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column }
.l-name { font-size: 13px; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis }
.l-price { font-size: 12px; color: var(--muted) }

/* The list's labels: short and grey, at the right of the row. */
.l-tag { flex: 0 0 auto; margin-left: auto; padding: 3px 7px; border-radius: 6px; background: var(--tile); font-size: 11px; font-weight: 500; color: var(--muted-strong) }
.l-item[aria-current="true"] .l-tag, .l-item:hover .l-tag { background: var(--surface) }

/* ==== Narrow desktop ========================================================================= */
/* Under 1100px the tile and the list narrow. */
@media (max-width: 1100px) {
  .results-body { grid-template-columns: minmax(0, 1fr) 260px }
  .l-lead { grid-template-columns: minmax(0, 1fr) 320px; column-gap: 28px }
}

/* ==== Phone ================================================================================== */
@keyframes l-specs-fade {
  0%, 90% { --fade: 40px }
  100% { --fade: 0px }
}
@media (max-width: 700px) {
  /* The whole result on one screen (Patryk, 2026-10-16): the card, and under it, apart from it, a
     dropdown naming the shell on the card. The card is laid out compact enough that its render,
     figures, specs and shop buttons fit the space above the dropdown on an ordinary phone; a
     longer one scrolls inside the card. A tap on the dropdown slides the whole list up over the
     card as a drawer, the card dims, and a tap on it shuts the drawer (js/layouts.js, drawer). The
     sheet is 36px shorter than the viewport, and the dialog centres its margin box, so 12px of top
     margin puts its top edge 24px down, level with the card's 24px from either side, and its foot
     12px clear of the bottom (Patryk, 2026-10-16: the 36px it first kept on top read as empty
     space; the strips either side still close it, as does Escape). The 44px it once gave up left
     the dropdown 4px from the screen's edge, under a phone's home bar, hence the bar's inset as
     well, where the browser reports one. A single shell opened from the scene keeps this full width: the
     desktop's narrower single sheet (.results.is-single, above) outranks the plain rule here. A
     list's sheet is narrower, for the neighbours either side (below). */
  .results, .results.is-single {
    width: calc(100vw - 16px);
    height: calc(100vh - 36px - env(safe-area-inset-bottom, 0px));
    max-height: none;
    margin-top: 12px;
    background: none;
    overflow: visible;
  }
  .results-body { position: relative; display: flex; flex-direction: column; gap: 8px; overflow: visible }
  /* No outline on a phone (Patryk, 2026-10-16): white on the dimmed page is edge enough. */
  .l-pane, .l-side { border-radius: 14px; box-shadow: none }
  .l-pane { flex: 1 1 auto; display: grid; min-height: 0 }
  /* The card between its neighbours (js/layouts.js, peeks): each as wide as the card, 8px from it
     (PEEK_GAP), so the 24px the sheet leaves either side of the screen shows 16px of each, cut off
     by the edge, and the strip reads as one to swipe. The track is what the swipe moves. A single
     shell from the scene has no neighbours and keeps the full width. */
  .results:not(.is-single) { width: calc(100vw - 48px) }
  .l-track { position: relative; flex: 1 1 auto; min-height: 0; display: grid }
  .l-peek { position: absolute; top: 0; bottom: 0; width: 100%; display: grid; pointer-events: none }
  .l-peek[hidden] { display: none }
  .l-peek[data-side="-1"] { right: calc(100% + 8px) }
  .l-peek[data-side="1"] { left: calc(100% + 8px) }
  /* The card the site had before the list view (Patryk, 2026-10-16, "the card looks awful"): white
     all through, the render small on top, the name and price, two tabs (the spec sheet, and the
     shops besides Amazon), and the Amazon search held at the card's foot under either tab. */
  .l-lead {
    grid-template-columns: 1fr;
    grid-template-areas: "shot" "col";
    grid-template-rows: auto minmax(0, 1fr);
    gap: 6px 0;
    padding: 16px 18px 14px;
    overflow: hidden;
  }
  /* The render takes the top of the card at a good size (Patryk, 2026-10-16: the top read empty);
     the spec sheet below scrolls on a short phone rather than shrinking it. */
  .l-shot { min-height: 0; height: clamp(140px, 23vh, 240px); margin: 0; background: none }
  /* A sideways swipe is the card's own (js/layouts.js, bindSwipe); vertical pans stay the browser's. */
  .l-pane { touch-action: pan-y }
  /* The X in the card's top-right corner, drawn as the old card strip drew its own: 40px round,
     the icon muted. On the pane, so it travels with the card in a swipe. */
  .l-close {
    position: absolute;
    top: 8px;
    right: 8px;
    width: 40px;
    height: 40px;
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--muted);
    border-radius: 50%;
  }
  .l-close svg { width: 20px; height: 20px }
  .l-close:active { color: var(--ink); background: var(--tile) }
  /* The card never scrolls as a whole: a long spec sheet scrolls in its own box, so the Amazon
     search and its disclosure always stand at the foot. */
  .l-col { gap: 12px; min-height: 0; overflow: hidden }
  .l-head { gap: 2px }
  .l-head h2 { font-size: 20px; letter-spacing: -.3px }
  .l-head .price { font-size: 19px }
  /* The tabs are the card's segmented switch (style.css, .tabs, which js/layouts.js gives them);
     the column's gap spaces them, so the switch's own top margin is dropped. */
  .l-tabs { display: flex; margin-top: 0 }
  /* The spec sheet one to a row (Patryk, 2026-10-16), label left and value right as on the desktop,
     weight and size first among the rest rather than on grey tiles of their own. Two to a row,
     label over value, a value as long as a sensor's name broke onto a second line. */
  .l-specs {
    flex: 0 1 auto;
    min-height: 0;
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    align-content: start;
    gap: 9px;
    overflow-y: auto;
    overscroll-behavior: contain;
    /* The sheet scrolls, so a touch on it answers to its own touch-action, not the pane's: left at
       auto, the browser took a sideways drag here for itself and cancelled the card's swipe
       (Patryk, 2026-10-16). Vertical pans stay the browser's, sideways ones the swipe's. */
    touch-action: pan-y;
    scrollbar-width: none;
  }
  .l-specs::-webkit-scrollbar { display: none }
  /* A sheet that scrolls fades out at its foot until it reaches the end, so a row cut by the edge
     reads as "more below" (the --fade length is registered in style.css). A sheet that fits has no
     scroll timeline, so no fade. */
  @supports (animation-timeline: scroll()) {
    .l-specs {
      -webkit-mask-image: linear-gradient(to bottom, #000 calc(100% - var(--fade)), transparent);
      mask-image: linear-gradient(to bottom, #000 calc(100% - var(--fade)), transparent);
      animation: l-specs-fade linear both;
      animation-timeline: scroll(self block);
    }
  }
  .l-figures, .l-rows { display: contents }
  .l-figure, .l-rows div { display: flex; flex-direction: row; align-items: baseline; justify-content: space-between; gap: 16px; min-width: 0; padding: 0; background: none; border-radius: 0 }
  .l-figure span, .l-rows dt { flex: 0 0 auto; font-size: 13px; color: var(--muted) }
  .l-figure strong, .l-rows dd { margin: 0; font-size: 14px; font-weight: 400; line-height: 1.35; text-align: right; overflow-wrap: anywhere }
  /* Where to buy: the shop buttons one under another, under the tabs; Amazon stays at the foot. The
     spec tab hides them, and this tab the spec sheet, only where the card has the tabs at all. */
  .l-shops .shop-grid { grid-template-columns: 1fr; gap: 8px }
  .l-shops .shop-grid .buy-btn.is-shop { padding: 13px 16px }
  .l-pane:not([data-tab="shops"]) .l-shops:not(.no-tabs) .shop-grid { display: none }
  .l-pane[data-tab="shops"] .l-specs:has(+ .l-shops:not(.no-tabs)) { display: none }
  .l-pane[data-tab="shops"] .l-shops:not(.no-tabs) { flex: 1 1 auto; display: flex; flex-direction: column; margin-top: 0 }
  .l-pane[data-tab="shops"] .l-shops:not(.no-tabs) .shop-search { margin-top: auto }
  .l-shops .buy-btn.shop-search { padding-top: 14px; padding-bottom: 14px }
  .l-bar { display: none }

  /* The dropdown, shut: the shell on the card, and a chevron. */
  .l-side { flex: 0 0 auto; display: flex; flex-direction: column; height: auto; min-height: 0; z-index: 2 }
  .l-drawer { display: flex; align-items: center; gap: 10px; width: 100%; padding: 9px 14px; text-align: left; color: var(--ink) }
  .l-current { flex: 1 1 auto; min-width: 0; display: flex; align-items: center; gap: 12px }
  .l-drawer svg { flex: 0 0 auto; width: 18px; height: 18px; color: var(--muted-strong); transition: transform .2s }
  .l-list { display: none; height: auto; -webkit-mask-image: none; mask-image: none }
  .l-item { padding: 11px 14px }

  /* The drawer, open: three quarters of the screen's results, the list under the dropdown's row. */
  .results.is-drawer .l-side {
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    height: 78%;
    box-shadow: 0 0 0 1px var(--line), 0 -8px 24px oklch(0 0 0 / .14);
  }
  .results.is-drawer .l-drawer { border-bottom: 1px solid var(--line) }
  .results.is-drawer .l-drawer svg { transform: rotate(180deg) }
  .results.is-drawer .l-list { display: block; flex: 1 1 auto; min-height: 0; overflow-y: auto; overscroll-behavior: contain; padding-bottom: 8px }
  /* The card under the open drawer, dimmed; a tap here shuts the drawer and reaches nothing under it. */
  /* Blurred as well as dimmed (Patryk, 2026-10-16), so the open list reads as the one thing on screen. */
  .results.is-drawer .l-pane::after {
    content: ""; position: absolute; inset: 0; z-index: 1; background: oklch(0 0 0 / .28);
    -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px);
  }
}
@supports (height: 100dvh) {
  @media (max-width: 700px) {
    .results, .results.is-single { height: calc(100dvh - 36px - env(safe-area-inset-bottom, 0px)) }
    /* The dialog the sheet is centred in, as tall as what is on screen too: at 100vh (style.css,
       #details.wide) a phone counts the address bar it can hide, so the dialog ran under the
       browser's toolbar and centred the sheet half that bar lower, which on a real phone left a
       gap on top well over the 12px meant (Patryk, 2026-10-16). */
    #details.wide.layouts { height: 100dvh }
  }
}
