/**
 * The wall: grid, banner cells, demo banner styles, page chrome.
 *
 * Visual language is the owner-approved demo (~/blink-demo): white surface,
 * 1px hairlines, zero radius, one accent. Colours come from css/tokens.css —
 * the only literal colour here is the letterbox behind a banner image, and it
 * is explained where it stands.
 */

:root {
  /* Cell height is derived from --cw so CSS and js/wall.js agree to the pixel;
     wall.js overwrites both inline on every resize. */
  --ch: calc(var(--cw) * 31 / 88);

  /* A banner needs a darker hairline than the page chrome, or bright 88x31 art
     bleeds into its neighbour. */
  --cell-line: color-mix(in srgb, var(--ink) 45%, transparent);

  /* 88x31 art was authored on black; letterboxing must not be white. */
  --banner-bg: #000000;
}

/* The wall is always taller than the viewport, so reserve the scrollbar gutter
   from the first paint: otherwise the grid is measured, then shrinks by ~15px. */
html { scrollbar-gutter: stable; }

/* --- chrome: top bar ------------------------------------------------------- */
.lang {
  flex: 0 0 auto;
  width: auto;                 /* override the generic select{width:100%} in base.css */
  height: 15px;
  padding: 0 2px;
  border: 1px solid var(--line-2);
  background: var(--surface);
  color: var(--ink-2);
  font: var(--fs-xs)/1 var(--font);
  letter-spacing: .04em;
  border-radius: 0;
  cursor: pointer;
  appearance: none;
}
/* Chrome as thin as it goes: the wall is the product, not the bar. */
.topbar .btn.sm { padding: 0 6px; font-size: var(--fs-xs); }
.lang:hover { color: var(--ink); border-color: var(--ink); }

/* Not sticky on purpose: the top bar scrolls away with the wall - nothing is
   pinned while browsing. Scroll up (or the ▲ button) brings it back. */
.topbar {
  display: flex;
  align-items: center;
  gap: var(--s-2);
  padding: 0 var(--s-2);
  background: var(--surface);
  border-bottom: 1px solid var(--line);
  font-size: var(--fs-xs);
  line-height: 1;
  min-height: 0;
}
.brand {
  flex: 0 0 auto;
  font-size: var(--fs-lg);
  font-weight: 700;
  letter-spacing: .08em;
  color: var(--ink);
  text-decoration: none;
}
.brand:hover { color: var(--accent); }

.topbar-stats {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 0 var(--s-3);
  font-size: var(--fs-sm);
  color: var(--ink-2);
}
.stat { white-space: nowrap; }
.stat.dim { color: var(--ink-3); }

.topbar-actions {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: var(--s-1);
  margin-left: auto;
}

/* "Show price" checkbox: compact, sits with the top-bar actions. */
.price-toggle {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  white-space: nowrap;
  font-size: var(--fs-xs);
  color: var(--ink-2);
  cursor: pointer;
  user-select: none;
}
.price-toggle input { margin: 0; cursor: pointer; }
.price-toggle:hover { color: var(--ink); }

/* --- the wall ------------------------------------------------------------- */
#wall {
  position: relative;
  z-index: var(--z-wall);
  display: flex;
  flex-direction: column;
  gap: var(--gap);
  padding: var(--gap);
}

/* One batch = one API block. Its height is set inline by wall.js before the
   data arrives, so filling or emptying it never moves the scrollbar. */
.batch {
  flex: 0 0 auto;
  position: relative;
  display: grid;
  grid-template-columns: repeat(var(--cols), 1fr);
  grid-auto-rows: var(--ch);
  gap: var(--gap);
}
/* Off-screen batches (still in the DOM window) skip painting and GIF decode - this
   is what keeps scrolling smooth. The blank-band bug was NOT this; it was columns
   not dividing the block size (fixed by colsForWidth in js/wall.js), so it is safe. */
.batch.filled { content-visibility: auto; }

.batch.loading::before {
  content: "загрузка мест " attr(data-from) "-" attr(data-to);
  position: absolute;
  left: 50%;
  top: var(--s-2);
  transform: translateX(-50%);
  font-size: var(--fs-sm);
  color: var(--ink-3);
  letter-spacing: var(--track);
  opacity: 0;
  animation: gfx-fade .3s .45s forwards;   /* silence for fast blocks */
}
@keyframes gfx-fade { to { opacity: 1; } }

.batch.err {
  display: flex;
  align-items: center;
  justify-content: center;
}
.batch-error {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: var(--s-2);
  max-width: 460px;
  padding: var(--s-3);
  border: 1px dashed var(--danger);
  background: var(--surface-2);
  font-size: var(--fs-sm);
  color: var(--ink-2);
  text-align: center;
}

/* --- one cell ------------------------------------------------------------- */
.b {
  position: relative;
  display: block;
  overflow: hidden;
  aspect-ratio: 88 / 31;              /* used when a card renders .b standalone */
  background: var(--surface-3);
  border: 1px solid var(--cell-line);
  color: inherit;
  text-decoration: none;
  cursor: pointer;
  user-select: none;
  -webkit-tap-highlight-color: transparent;
}
.b:hover { outline: 1px solid var(--ink); }
.b:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; z-index: 3; }

.b.free {
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--free-fill);
  border: 1px dashed var(--free-line);
}
.b.free:hover { background: var(--surface); border-color: var(--accent); }
.fp {
  font-size: calc(var(--cw) * .11);
  font-weight: 700;
  color: var(--free);
  letter-spacing: .04em;
}
.b.free:hover .fp { color: var(--accent); }

/* Hidden by a moderation re-scan, or (legacy) waiting for review: shown, dimmed,
   never linked. No artwork - the API withholds it; the ribbon is the whole cell. */
.b.pending,
.b.hidden {
  background: var(--surface-2);
  border-style: dashed;
  border-color: var(--warn);
  display: flex; align-items: center; justify-content: center; cursor: pointer;
}
.rb {
  position: absolute;
  left: 0;
  bottom: 0;
  z-index: 2;
  max-width: 100%;
  padding: 1px 3px;
  background: var(--warn);
  color: var(--surface);
  font-size: calc(var(--cw) * .072);
  line-height: 1.25;
  letter-spacing: .02em;
  white-space: nowrap;
  overflow: hidden;
}

/* Landing from a deep link (#5000) or from the slot card. */
.b.hit { outline: 2px solid var(--accent); outline-offset: 1px; z-index: 3; }
@media (prefers-reduced-motion: no-preference) {
  .b.hit { animation: gfx-hit .45s steps(1) 3; }
}
@keyframes gfx-hit { 50% { outline-color: transparent; } }

/* --- banner bodies (see bannerHTML in js/ui.js) ---------------------------- */
.g {
  position: absolute;
  inset: 0;
  display: block;
  width: 100%;
  height: 100%;
  object-fit: contain;
  background: var(--banner-bg);
  image-rendering: pixelated;
  -webkit-user-drag: none;
}
/* A banner with no source must be loud, not quietly blank. */
.g:not([src]), .g[src=""] { background: var(--danger); }

.row {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: stretch;
}
.ic {
  flex: 0 0 32%;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--c3);
  color: var(--c4);
  font-weight: 700;
  font-size: calc(var(--cw) * var(--icf));
  line-height: 1;
  letter-spacing: -.03em;
}
.tx {
  flex: 1 1 auto;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  padding: 0 2%;
  background: var(--c1);
  color: var(--c2);
  font-weight: 700;
  font-size: calc(var(--cw) * var(--fs));
  line-height: 1;
  letter-spacing: .02em;
  white-space: nowrap;
  text-align: center;
}
.tx.grad { background: linear-gradient(90deg, var(--c1) 0%, var(--c5) 100%); }
.tx.stripe {
  background: repeating-linear-gradient(45deg,
    var(--c1) 0 6%,
    color-mix(in srgb, var(--c1) 74%, var(--c2) 26%) 6% 12%);
  text-shadow: 0 0 2px var(--c1), 0 0 3px var(--c1);
}
.tx.two { flex-direction: column; gap: .12em; }
.tx.two b { font-weight: 700; }
.tx.two i { font-style: normal; font-size: .78em; opacity: .85; }
.tx.frame { box-shadow: inset 0 0 0 1px var(--c2), inset 0 0 0 2px var(--c1); }
.tx.dot {
  background-image: radial-gradient(var(--c5) 26%, transparent 27%);
  background-size: 11% 30%;
}
.px {
  flex: 0 0 30%;
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  grid-template-rows: repeat(3, 1fr);
  gap: 0;
  padding: 9% 6%;
  background: var(--c3);
}
.px i { display: block; }
.bars {
  flex: 0 0 14%;
  display: flex;
  flex-direction: column;
}
.bars span { flex: 1; }

/* --- corner control cluster ----------------------------------------------- */
/* Top-right of every taken cell: the info dot 'i' (always) plus the price tag
   (only under #wall.show-price), laid out as one flush strip [price][i]. Both
   share box metrics so they read as a single control fused to the banner corner. */
.ctl {
  position: absolute;
  top: 0;
  right: 0;
  z-index: 2;
  display: flex;
  align-items: flex-start;
}
.i,
.bid {
  padding: 1px 3px;
  border: 1px solid;
  border-top: 0;                        /* top edge fuses with the banner's top edge */
  border-right: 0;
  /* line-height 1 hugs the glyph so the chip height tracks the text, not a line box */
  font: 700 calc(var(--cw) * .1)/1 var(--font);
  /* Slightly translucent white so the control reads as part of the banner. */
  background: color-mix(in srgb, #fff 82%, transparent);
  cursor: pointer;
}
.i {
  position: relative;
  min-width: 12px;
  text-align: center;
  border-color: var(--line-2);
  color: var(--ink);
}
.i:hover { background: var(--surface-3); }
.i:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
/* Thumb-sized hit area without a thumb-sized button. */
.i::after { content: ""; position: absolute; inset: -9px -6px -9px -9px; }

/* Buyout price tag: green digit, sits just left of the info dot. Hidden until the
   wall is switched to "show price" mode by the top-bar checkbox. */
.bid {
  display: none;
  background: #1f9d3f;                   /* solid green so the white digits read clearly over any banner */
  border-color: #1f9d3f;
  color: #fff;
  letter-spacing: .01em;
  white-space: nowrap;
}
#wall.show-price .bid { display: block; }
.bid:hover { background: #178235; }

/* --- motion off ----------------------------------------------------------- */
/* Stops every CSS-driven banner. A GIF cannot be frozen in the browser, so an
   animated cell is marked instead of pretending — see setAnimation() in wall.js. */
.no-anim #wall *,
.batch.off * { animation-play-state: paused !important; }
.no-anim .b.anim::after {
  content: "gif";
  position: absolute;
  right: 0;
  bottom: 0;
  z-index: 2;
  padding: 0 2px;
  background: var(--ink);
  color: var(--surface);
  font-size: calc(var(--cw) * .07);
  line-height: 1.4;
  letter-spacing: .04em;
}

/* --- horizon -------------------------------------------------------------- */
.horizon {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: var(--s-2);
  padding: var(--s-6) var(--s-3) var(--s-4);
}
.horizon-rule {
  flex: 1 1 40px;
  max-width: 140px;
  height: 1px;
  background: var(--line-2);
}
.horizon-label {
  font-size: var(--fs-sm);
  letter-spacing: var(--track);
  text-transform: uppercase;
  color: var(--ink-2);
}
.horizon-note {
  flex: 1 0 100%;
  margin: var(--s-2) 0 0;
  font-size: var(--fs-sm);
  color: var(--ink-3);
  text-align: center;
}

#sentinel { height: 1px; }

/* --- chrome: floating bits ------------------------------------------------ */
#to-top {
  position: fixed;
  right: 10px;
  bottom: calc(10px + env(safe-area-inset-bottom, 0px));
  z-index: var(--z-chrome);
  width: 34px;
  height: 34px;
  display: none;
  align-items: center;
  justify-content: center;
  border: 1px solid var(--ink);
  background: color-mix(in srgb, var(--surface) 92%, transparent);
  color: var(--ink);
  font: 700 14px/1 var(--font);
  cursor: pointer;
}
#to-top.on { display: flex; }
#to-top:hover { background: var(--surface); }

#hint {
  position: fixed;
  left: 50%;
  bottom: calc(12px + env(safe-area-inset-bottom, 0px));
  transform: translateX(-50%);
  z-index: calc(var(--z-chrome) + 1);
  max-width: min(88vw, calc(100vw - 70px));
  padding: 8px 12px;
  background: color-mix(in srgb, var(--ink) 92%, transparent);
  color: var(--surface);
  font-size: var(--fs-sm);
  letter-spacing: .02em;
  text-align: center;
  transition: opacity .4s;
}
#hint.off { opacity: 0; pointer-events: none; }

.mock-flag {
  padding: 2px 6px;
  border: 1px dashed var(--line-2);
  color: var(--ink-3);
  letter-spacing: .04em;
}

/* --- narrow screens ------------------------------------------------------- */
@media (max-width: 560px) {
  .topbar { gap: var(--s-1); padding: 1px var(--gap); }
  .topbar-stats { font-size: var(--fs-xs); }
}

/* Always-visible honesty badge: the footer sits after ~28 000 slots and nobody
   scrolls there. A visitor must know this is a mock before picking a slot. */
.mock-badge {
  flex: 0 0 auto;
  padding: 2px 6px;
  border: 1px dashed var(--ink-3);
  color: var(--ink-2);
  font-size: var(--fs-xs);
  letter-spacing: var(--track);
  text-transform: uppercase;
  white-space: nowrap;
}
