/* 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 80px above and below, and js/layouts.js (settle, which repeats the 160px)
   zooms the lead down to fit rather than let it scroll. The 80px below are the compare tray's
   (compare-tray.css, in the bottom right corner), kept whether or not it shows: made only while it
   showed, the room changed the zoom and the whole lead jumped with every pick (Patryk, 2026-11-02).
   --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 - 160px);
  cursor: auto;
}
@supports (height: 100dvh) {
  .results { max-height: calc(100dvh - 160px) }
}
/* 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 compare tray over the sheet (js/layouts.js, cmpTray) stands centred under it (Patryk,
   2026-11-02), rather than in the screen's corner as on a catalog. A phone keeps it across the foot. */
@media (min-width: 701px) {
  #details .cmp-tray { right: auto; left: 50%; translate: -50% 0 }
}

/* 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 }
.l-info { 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 }
/* "from" before the lowest of several shops' prices (js/layouts.js, lowOf), in the price's own colour
   (Patryk, 2026-11-02: greyed, it read as a separate note rather than part of the price). */
.l-head .l-fromw { margin-right: 6px }
/* The actions row at the column's foot (js/layouts.js, leadHTML): Amazon's search, the one dark
   button, and on a computer "N shops" beside it, which opens the other shops in a list over it. */
.l-links { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 8px; margin-top: auto }
/* Drawn as the site's Amazon button has always been (style.css, .buy-btn): the mark parked at the
   left edge, the words centred in the whole button (Patryk, 2026-11-02). */
.l-amz {
  position: relative; display: inline-flex; align-items: center; justify-content: center; height: 44px; padding: 0 40px; border-radius: 10px;
  background: var(--ink); color: var(--raised); font-size: 14px; font-weight: 600; text-decoration: none; white-space: nowrap;
}
.l-amz img { position: absolute; left: 16px; top: 50%; width: 16px; height: 16px; margin: -6px 0 0 }
.l-amz:hover { background: var(--ink-deep) }
.l-amz:focus-visible { outline: 2px solid var(--ink); outline-offset: 2px }
/* Compare (js/layouts.js, cmpHTML) in the render tile's bottom left corner (Patryk, 2026-11-02): the
   catalog's tick box and the word (catalog.css, .c-cmp) on a small white pill over the grey. The box
   is a hairline until pointed at, a shade darker then, and filled with the ink once picked. */
.l-cmp {
  position: absolute;
  left: 20px;
  bottom: 20px;
  z-index: 1;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  height: 34px;
  padding: 0 12px 0 10px;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--surface);
  color: var(--ink);
  font: inherit;
  font-size: 13px;
  font-weight: 500;
  line-height: 1.3;
  cursor: pointer;
  user-select: none;
  transition: border-color .15s;
}
.l-cmp .l-tick {
  flex: 0 0 16px;
  width: 16px;
  height: 16px;
  padding: 1px;
  border-radius: 4.5px;
  box-shadow: inset 0 0 0 1.5px var(--line);
  color: transparent;
  transition: background .15s, box-shadow .15s, color .15s;
}
.l-cmp:hover { border-color: var(--dim) }
.l-cmp:hover .l-tick { box-shadow: inset 0 0 0 1.5px var(--dim) }
.l-cmp[aria-pressed="true"] .l-tick { background: var(--ink); box-shadow: none; color: var(--raised) }
.l-cmp.is-full { color: var(--muted) }
.l-cmp:focus-visible { outline: 2px solid var(--ink); outline-offset: 2px }
/* 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 }
/* Where to buy (js/layouts.js, pricesHTML): the heading with the flag of the country it ships to
   beside it (a button that opens the bar's country picker); then one row per shop drawn as the list
   of shells beside the sheet draws its rows (Patryk, 2026-11-02): the bare logo, the name with its
   stock under it in grey, the price at the right with the old price under it, no rules between
   them, a grey ground under the pointer. Every row is one height, with or without a second line, so
   the list keeps one rhythm. Every shop is listed; the list scrolls in its own box, its scrollbar
   thin and shown only under the pointer. Amazon's row first, its white mark on a dark tile. */
.l-col { align-self: stretch }
.l-shops { display: flex; flex-direction: column; gap: 10px; margin-top: 4px; min-height: 0 }
.l-prices-head { display: flex; align-items: center; justify-content: space-between; gap: 12px }
.l-prices-head h3 { margin: 0; font-size: 15px; font-weight: 600; letter-spacing: -.1px }
.l-country {
  display: inline-flex; align-items: center; gap: 4px; margin-right: -6px; padding: 5px 4px 5px 6px; border: 0; border-radius: 6px;
  background: none; color: var(--muted); font: inherit; cursor: pointer;
}
.l-country:hover { background: var(--tile-hover); color: var(--ink) }
.l-country:focus-visible { outline: 2px solid var(--ink); outline-offset: 1px }
.l-country svg { flex: 0 0 auto; width: 13px; height: 13px }
.l-flag { flex: 0 0 auto; display: inline-flex }
.l-country-name { display: none }
.l-flag img, .l-flag svg { width: 16px; height: 12px; border-radius: 2px; box-shadow: 0 0 0 1px oklch(0 0 0 / .08); object-fit: cover }
.l-offers {
  margin: 0 -10px; padding: 0; list-style: none;
  max-height: 248px; overflow-y: auto; overscroll-behavior: contain;
  scrollbar-width: thin; scrollbar-color: transparent transparent;
}
.l-offers:hover { scrollbar-color: oklch(0 0 0 / .22) transparent }
.l-offers::-webkit-scrollbar { width: 8px; background: transparent }
.l-offers::-webkit-scrollbar-thumb { background: transparent; background-clip: padding-box; border: 2px solid transparent; border-radius: 999px }
.l-offers:hover::-webkit-scrollbar-thumb { background: oklch(0 0 0 / .22); background-clip: padding-box }
.l-offer a {
  display: flex; align-items: center; gap: 12px; min-height: 52px; padding: 7px 10px; border-radius: 8px;
  color: var(--ink); text-decoration: none; transition: background .18s;
}
.l-offer a:hover { background: var(--tile) }
.l-offer a:focus-visible { outline: 2px solid var(--ink); outline-offset: -2px }
.l-offer-logo {
  flex: 0 0 22px; width: 22px; height: 22px; display: grid; place-items: center; border-radius: 5px; overflow: hidden;
  font-size: 12px; font-weight: 600; color: var(--muted-strong);
}
.l-offer-logo img { width: 20px; height: 20px; margin: 0; object-fit: contain }
.is-amazon .l-offer-logo { background: var(--ink) }
.is-amazon .l-offer-logo img { width: 13px; height: 13px }
.l-offer-name { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; font-size: 13px; font-weight: 600; line-height: 1.35 }
.l-offer-name > span { white-space: nowrap; overflow: hidden; text-overflow: ellipsis }
.l-offer-name small { font-size: 12px; font-weight: 400; color: var(--muted) }
.l-offer-price { flex: 0 0 auto; display: flex; flex-direction: column; align-items: flex-end; font-size: 13px; line-height: 1.35; white-space: nowrap }
.l-offer-price b { font-weight: 600 }
.l-offer-price s { font-size: 12px; color: var(--muted) }
.l-offer-price em { font-style: normal; font-size: 12px; color: var(--muted) }
/* A computer's card (Patryk, 2026-11-02): the shops are not a section of the column but a list that
   "N shops" opens above the actions row, over the specs, in a white card with a shadow; Amazon's
   search is the wide dark button beside it. The phone keeps them as its second tab (.l-shops, below
   in the phone rules) and has no such button. */
.l-buy { display: none }
@media (min-width: 701px) {
  .l-col > .l-shops { display: none }
  .l-links { flex-wrap: nowrap }
  .l-links .l-amz { flex: 1 1 auto }
  .l-buy { position: relative; display: block; flex: 0 0 auto }
  .l-shops-btn {
    display: flex; align-items: center; gap: 6px; height: 44px; padding: 0 14px; border: 1px solid var(--line); border-radius: 10px;
    background: var(--surface); color: var(--ink); font: inherit; font-size: 14px; font-weight: 500; white-space: nowrap; cursor: pointer;
    transition: background .15s;
  }
  /* Under the pointer, and while its list is open, the border darkens; the ground stays white. */
  .l-shops-btn:hover, .l-buy.is-open .l-shops-btn { border-color: var(--dim) }
  .l-shops-btn:focus-visible { outline: 2px solid var(--ink); outline-offset: 2px }
  .l-shops-btn svg { width: 14px; height: 14px; transition: transform .2s }
  .l-shops-btn svg { transform: rotate(180deg) }
  .l-buy.is-open .l-shops-btn svg { transform: none }
  .l-pop {
    position: absolute; z-index: 5; bottom: calc(100% + 8px); right: 0; width: 340px; max-height: 340px;
    display: none; flex-direction: column; gap: 10px; padding: 16px 16px 8px; border-radius: 14px; background: var(--surface); overflow: hidden;
    box-shadow: var(--shadow-pop);
  }
  /* In the card the rows' grey runs its whole width, as the list of shells beside the sheet does
     (Patryk, 2026-11-02: a grey box inside the card looked like a different list). */
  .l-pop .l-offers { margin: 0 -16px }
  .l-pop .l-offer a { padding: 7px 16px; border-radius: 0 }
  .l-buy.is-open .l-pop { display: flex }
  .l-pop .l-offers { flex: 1 1 auto; min-height: 0; max-height: none }
}
/* 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%; display: flex; flex-direction: column }
.l-list {
  flex: 1 1 auto;
  min-height: 0;
  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 }
/* The way to the catalog with the answers as filters (js/layouts.js, catalogHTML), at the list's foot
   under a hairline: the grey button the list's width, the one the finder's own "Browse the catalog
   with these answers" wears (style.css, .result-more), quieter than the dark Amazon one. */
.l-catalog {
  flex: 0 0 auto; display: flex; align-items: center; justify-content: center; height: 40px; margin: 10px 12px 12px;
  border-radius: 10px; background: var(--tile); color: var(--ink); font-size: 14px; font-weight: 600; text-decoration: none;
  transition: background .15s;
}
.l-catalog:hover { background: var(--tile-hover) }
.l-catalog:focus-visible { outline: 2px solid var(--ink); outline-offset: 2px }
.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 }
/* A row picked to compare (js/layouts.js, listHTML and syncCmp): a small tick in the ink on the
   thumbnail's lower corner, so the picks can be told apart while the list scrolls. */
.l-item.is-cmp .l-thumb::after {
  content: '';
  position: absolute;
  right: 0;
  bottom: 0;
  width: 14px;
  height: 14px;
  border-radius: 4px;
  background: var(--ink) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fafaf9' stroke-width='3.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m5 12.5 4.5 4.5L19 7.5'/%3E%3C/svg%3E") center / 10px no-repeat;
}
/* 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). */
  /* Pulled up (Patryk, 2026-11-02: room was left on top): 20px shorter than the screen with 4px of
     top margin, so the card's top edge is 12px down and its foot 8px clear. */
  /* As wide as a list's card for one product too (Patryk, 2026-11-02: the catalog's sheet read wider). */
  .results, .results.is-single {
    width: calc(100vw - 48px);
    height: calc(100vh - 20px - env(safe-area-inset-bottom, 0px));
    max-height: none;
    margin-top: 4px;
    background: none;
    overflow: visible;
  }
  /* While the compare tray shows (js/layouts.js, cmpTray), the card ends 64px higher; its top stays. */
  #details.has-tray .results { height: calc(100vh - 20px - 64px - env(safe-area-inset-bottom, 0px)); margin-bottom: 64px }
  .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. */
  .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: 8px 18px 14px;
    overflow: hidden;
  }
  /* The render at the top of the card, smaller since 2026-11-02 (Patryk: too little room was left for
     the spec sheet and the shops). It runs 10px past the card's padding either side, so Compare in
     its top-left corner stands as far from the card's edge as the X from the other. */
  .l-shot { min-height: 0; height: clamp(110px, 17vh, 170px); margin: 0 -10px; 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%;
    background: var(--tile);
  }
  .l-close svg { width: 18px; height: 18px }
  .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-info { display: contents }
  .l-head { gap: 2px }
  /* A step smaller than they were (Patryk, 2026-11-02), for room for the spec sheet and the shops. */
  .l-head h2 { font-size: 17px; letter-spacing: -.2px }
  .l-head .price { font-size: 16px }
  /* 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 is the second tab: the spec tab hides the list, and this tab the spec sheet. The
     list scrolls in its own box, as the spec sheet does. */
  .l-links { margin-top: auto; padding-top: 4px }
  .l-amz { flex: 1 1 auto; justify-content: center; height: 40px; font-size: 13.5px }
  .l-amz img { width: 15px; height: 15px }
  /* One product alone (a catalog's card, a shell tapped in the scene) has no dropdown under it, so it
     keeps the larger render and type (Patryk, 2026-11-02): the list's card is the one short of room. */
  .results.is-single .l-shot { height: clamp(140px, 22vh, 230px) }
  .results.is-single .l-head h2 { font-size: 19px; letter-spacing: -.3px }
  .results.is-single .l-head .price { font-size: 18px }
  .results.is-single .l-amz { height: 44px; font-size: 14px }
  .l-pane:not([data-tab="shops"]) .l-shops { display: none }
  .l-pane[data-tab="shops"] .l-specs { display: none }
  .l-pane[data-tab="shops"] .l-shops { flex: 0 1 auto; min-height: 0; margin-top: 0; overflow-y: auto; overscroll-behavior: contain; touch-action: pan-y; scrollbar-width: none }
  .l-shops::-webkit-scrollbar { display: none }
  .l-prices-head h3 { display: none }
  /* The shops closer together, a hairline between each two, the rows level with the country field
     above them (Patryk, 2026-11-02). */
  .l-offers { max-height: none; margin: 0; overflow: visible }
  .l-offer + .l-offer { border-top: 1px solid var(--line) }
  .l-offer a { min-height: 44px; padding: 5px 2px; border-radius: 0 }
  /* Compare in the card's top-left corner, level with the X in the other, with no ring round it
     (Patryk, 2026-11-02). */
  .l-cmp { top: 3px; left: 0; bottom: auto; border-color: transparent }
  .l-cmp:hover { border-color: transparent }
  /* The country as a full-width field over the shops, its name in it (Patryk, 2026-11-02: the flag
     alone was too small a target). */
  .l-prices-head { display: block }
  .l-country {
    width: 100%; height: 44px; margin: 0 0 8px; padding: 0 12px; gap: 10px; border: 1px solid var(--line); border-radius: 10px;
    color: var(--ink); font-size: 14px;
  }
  .l-country-name { display: block; flex: 1 1 auto; text-align: left }
  .l-country svg { width: 16px; height: 16px; color: var(--muted) }
  .l-flag img, .l-flag svg { width: 20px; height: 15px }
  .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) }
  /* Only in the open drawer, under the list. */
  .results:not(.is-drawer) .l-catalog { display: none }
  .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 - 20px - env(safe-area-inset-bottom, 0px)) }
    /* And with the compare tray under it: the 100vh rule above outranks the line before (an id), so
       on a real phone the card ran the address bar's height down under the tray (Patryk,
       2026-11-02: "the compare covers the card"). */
    #details.has-tray .results { height: calc(100dvh - 20px - 64px - 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 }
  }
}
