/* design-v2 listing TILE styles, scoped under .glv2 — the `.tile` rules and nothing
   else, lifted out of the catalog stylesheet for pages that print the tile without
   being the listing (the product card's rails). Same source, so the two cannot drift.
   Generated from design-v2/catalog.html by tools/build_catalog_css.py.
   Do not edit by hand — edit catalog.html and rebuild. */
.glv2 .num{ font-variant-numeric: tabular-nums; }
.glv2 .tile{ position: relative; display: flex; flex-direction: column; min-width: 0; border: var(--hairline-w) solid var(--hairline); background: var(--bg); transition: border-color .15s ease; }
.glv2 .tile:hover{ border-color: var(--hairline-strong); }
.glv2 .tile-thumb{ position: relative; width: 100%; aspect-ratio: 1/1; background: var(--surface-sub); display: flex; align-items: center; justify-content: center; color: var(--fg-muted); overflow: hidden; border-bottom: var(--hairline-w) solid var(--hairline); transition: background-color .3s ease; cursor: pointer; }
.glv2 .tile-thumb > .goods{ width: 44px; height: 44px; transition: transform .3s ease; }
.glv2 .tile-gallery{ position: absolute; inset: 0; z-index: 0; }
.glv2 .tile-img{ position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; opacity: 1; z-index: 0; transition: transform .5s ease; }
.glv2 .tile-img.is-active{ z-index: 1; }
.glv2 .tile:hover .tile-thumb .tile-img.is-active{ transform: scale(1.05); }
.glv2 .tile-thumb-link{ position: absolute; inset: 0; z-index: 2; display: block; }
.glv2 .tile-dots{ position: absolute; left: 0; right: 0; bottom: 8px; z-index: 3; display: flex; justify-content: center; gap: 5px; pointer-events: none; opacity: 0; transition: opacity .2s ease; }
.glv2 .tile:hover .tile-dots{ opacity: 1; }
.glv2 .tile-dots .dot{ width: 16px; height: 3px; background: rgba(255,255,255,.5); box-shadow: 0 0 2px rgba(0,0,0,.28); cursor: pointer; pointer-events: auto; transition: background .2s ease; }
.glv2 .tile-dots .dot:hover{ background: rgba(255,255,255,.85); }
.glv2 .tile-dots .dot.on{ background: #fff; }
@media (hover: none){
.glv2 .tile-dots{ opacity: 1; }
}
.glv2 .tile-badge{ position: absolute; top: var(--space-sm); left: var(--space-sm); z-index: 3; background: var(--accent); color: #fff; font-size: var(--fs-xs); font-weight: 600; padding: 3px 7px; }
.glv2 .tile-badge.neutral{ background: var(--fg); }
.glv2 .tile-fav{ -webkit-appearance: none; appearance: none; padding: 0; margin: 0; position: absolute; top: var(--space-sm); right: var(--space-sm); z-index: 4; width: 30px; height: 30px; border: var(--hairline-w) solid var(--hairline); background: var(--bg); cursor: pointer; display: inline-flex; align-items: center; justify-content: center; color: var(--fg-2); transition: color .15s ease, border-color .15s ease; }
.glv2 .tile-fav:hover{ color: var(--accent); border-color: var(--hairline-strong); }
.glv2 .tile-fav .fav-heart{ display: block; width: 16px; height: 16px; fill: none; stroke: #444444; stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round; }
.glv2 .tile-fav.faved{ color: var(--accent); }
.glv2 .tile-fav.faved .fav-heart{ fill: #58AA70; stroke: #58AA70; }
.glv2 .tile-body{ flex: 1; padding: 14px; display: flex; flex-direction: column; gap: 12px; }
.glv2 .tile-title{ font-size: var(--fs-base); font-weight: 500; color: var(--fg); margin: 0; line-height: 1.35; text-decoration: none; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; transition: color .3s ease; }
.glv2 .tile:hover .tile-title{ color: var(--accent); }
.glv2 .tile-rating{ display: inline-flex; align-items: center; gap: 5px; font-size: var(--fs-xs); color: var(--fg-muted); margin-top: -4px; }
.glv2 .tile-rating svg{ width: 12px; height: 12px; color: var(--warn); }
.glv2 .tile-colors{ position: relative; z-index: 2; display: flex; align-items: center; flex-wrap: wrap; gap: 8px; row-gap: 7px; }
.glv2 .tile-swatch{ position: relative; width: 22px; height: 22px; padding: 0; border: var(--hairline-w) solid var(--hairline-strong); background-clip: padding-box; cursor: pointer; transition: border-color .15s ease; }
.glv2 .tile-swatch:hover{ border-color: var(--fg); }
.glv2 .tile-swatch[aria-pressed="true"]{ border-color: var(--fg); box-shadow: inset 0 0 0 2px var(--bg); }
@media (hover: none){
.glv2 .tile-colors{ gap: 12px; row-gap: 10px; }

.glv2 .tile-swatch{ width: 30px; height: 30px; }

.glv2 .tile-swatch::before{ content: ''; position: absolute; inset: -7px; }
}
.glv2 .tile-swatch-more{ font-size: var(--fs-xs); color: var(--fg-muted); font-variant-numeric: tabular-nums; margin-left: 2px; }
.glv2 .tile-specs{ display: flex; flex-direction: column; gap: 4px; font-size: var(--fs-xs); color: var(--fg-2); }
.glv2 .tile-specs .srow{ display: flex; gap: 6px; }
.glv2 .tile-specs .sk{ color: var(--fg-muted); }
.glv2 .tile-foot{ border-top: var(--hairline-w) solid var(--hairline); padding: 14px; display: flex; flex-direction: column; gap: 12px; }
.glv2 .tile-price{ display: flex; flex-direction: column; align-items: flex-start; gap: 5px; min-height: 36px; }
.glv2 .tile-price .pricegroup{ display: inline-flex; align-items: baseline; gap: 3px; white-space: nowrap; }
.glv2 .tile-price .pmeta-row{ display: flex; flex-wrap: wrap; align-items: baseline; gap: 2px 8px; }
.glv2 .tile-price .from{ font-size: var(--fs-xs); font-weight: 500; color: var(--fg-muted); }
.glv2 .tile-price .now{ font-size: 20px; font-weight: 600; letter-spacing: -0.02em; line-height: 1; color: var(--fg); white-space: nowrap; font-variant-numeric: tabular-nums; }
.glv2 .tile-price .pmeta{ display: flex; flex-direction: column; gap: 3px; }
.glv2 .tile-price .old{ font-size: var(--fs-xs); color: var(--fg-muted); text-decoration: line-through; text-decoration-color: var(--hairline-strong); white-space: nowrap; font-variant-numeric: tabular-nums; }
.glv2 .tile-price .save{ font-size: 11px; font-weight: 600; color: var(--accent-hover); white-space: nowrap; font-variant-numeric: tabular-nums; }
.glv2 .add-btn{ position: relative; z-index: 2; width: 100%; height: 44px; border: 0; background: var(--accent); color: #fff; font-size: 14px; font-weight: 600; display: inline-flex; align-items: center; justify-content: center; gap: 8px; cursor: pointer; transition: background .15s ease; }
.glv2 .add-btn:hover:not(:disabled){ background: var(--accent-hover); }
.glv2 .add-btn.added{ background: var(--accent-soft); color: var(--accent-hover); cursor: default; }
.glv2 .add-btn svg{ width: 16px; height: 16px; }
.glv2 .tile-oos{ min-height: 44px; display: flex; align-items: center; justify-content: center; font-size: var(--fs-sm); color: var(--fg-muted); font-weight: 500; text-align: center; }
.glv2 .tile-body > .tile-title { min-height: calc(2 * 1.35em); }
.glv2 .tile-specs { min-height: calc(2 * 1.5em + 4px); }
.glv2 .tile-img { object-fit: contain; background: #fff; }

/* ── the listing tile inside a product-card rail ────────────────────────────────
   `.rail` is a horizontal flex track (product.html), so the tile needs an explicit column
   width the way `.recent-track` gives it one with grid-auto-columns on the catalog page.
   Same 262px, same snap, same mobile column.

   Mobile width, owner 2026-09-01 (third pass). Pass 1 on 2026-08-31 gave the rail the
   listing's own two-up, `(100% - gap) / 2`, and it read as two static tiles — with the
   arrows hidden under 560px nothing on screen said the row scrolls. Pass 2 the same day cut
   the divisor to 2.4 to buy a peek, which left the tile 142px wide on a 390px screen and the
   tile body stopped fitting: the product name wraps and the colour swatches break onto a
   second row. Pass 3 is divisor 1.6 — 214px on the same screen, one full tile plus 60% of
   the next one cut by the viewport edge, so the peek is still the scroll affordance.
   `100%` is the rail's content box, which the full-bleed margins + padding at <=640px make
   equal to the page's content width, so the first tile still lands on the left page gutter,
   flush with every grid above it. `.recent-track` on the catalog page carries the same
   divisor (catalog.html, <=640px); `.linktile` deliberately keeps 2.4, its cards are an
   image plus a caption and fit at that width. */
.glv2 .rail > .tile { flex: 0 0 262px; scroll-snap-align: start; }
@media (max-width: 640px){ .glv2 .rail > .tile { flex-basis: calc((100% - var(--space-md)) / 1.6); } }

/* The grid pins the spec rows to the bottom of the body so a one-line product name cannot
   lift the price above its neighbours' (`.tile-grid:not(.list) .tile-specs`, CSS_SECTION_SHELL
   — grid-scoped, so a rail tile never picked it up). A rail is a row of tiles too, and the
   owner reported exactly this on the card's rails once already: «цена съехана», 2026-08-03. */
.glv2 .rail > .tile .tile-specs { margin-top: auto; }

/* The site ships `a { text-decoration: underline }` (grland_main/css/style.css). The catalog
   page answers it once for the whole scope (`.glv2 a`, CSS_SECTION_SHELL), but this block is
   consumed by the product card, whose stylesheet has no such reset — so the tile's two links
   re-typed on the port, the «Купить» CTA (a tile links to the product page, it cannot pick one
   of N offers) and the tile title, arrived underlined in all four rails. Reported by the owner
   2026-08-21 on «Похожие товары». Every link a tile prints is one of those two plus the empty
   thumb overlay, so reset the tile once instead of naming classes. Scoped to the tile, not to
   `.glv2 a`: the card's prose and its doc list style their own links. Specificity (0,2,1)
   beats the site's (0,0,1) — no `!important` needed. */
.glv2 .tile a { text-decoration: none; }
