/* ============================================================
   ECOTAB — hero swirl + floating products
   Palette drawn from the brand swirl artwork
   ============================================================ */

:root {
  --ink: #0a1045;
  --ink-soft: rgba(10, 16, 69, 0.68);
  --black: #0b0b0f;
  --yellow: #ffc700;
  --magenta: #e63888;
  --crimson: #e8384f;
  --cyan: #33bbef;
  --teal: #12b5ac;
  --white: #ffffff;

  --font-display: "Quicksand", system-ui, sans-serif;
  --font-body: "Poppins", system-ui, sans-serif;
}

* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
  /* kill iOS Safari's default dark tap-flash on links/buttons — the
     site provides its own press feedback (glider, card grow) */
  -webkit-tap-highlight-color: transparent;
}

/* also removes the legacy double-tap-to-zoom delay on taps */
button, a { touch-action: manipulation; }

html, body { scroll-behavior: smooth; }
html { overflow: hidden; }

/* The page scrolls INSIDE the fixed body, never the document itself.
   Browser bars (Safari's address bar, Instagram/Telegram's in-app
   chrome) only collapse/expand in response to DOCUMENT scrolling —
   with the document pinned, they hold still, so the viewport never
   resizes mid-scroll and the in-app jitter is gone. Same mechanism
   that already made the About and product-detail overlays stable. */
body {
  position: fixed;
  inset: 0;
  overflow-x: hidden;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  overscroll-behavior-y: contain;
  font-family: var(--font-body);
  font-weight: 400;
  color: var(--ink);
  background: var(--white);
}

/* boot gate: no scrolling until the intro has loaded & rasterized.
   (body is the element that actually scrolls the page.)
   The scroll hint stays hidden too — it fades in at the exact moment
   scrolling becomes possible. */
html.booting body { overflow-y: hidden; }
html.booting .scroll-hint { opacity: 0 !important; }

img { max-width: 100%; display: block; }

/* ============================================================
   Fixed visual layers
   ============================================================ */

/* --- Dispersed color field (the gradient the swirl becomes) --- */
.color-field {
  position: fixed;
  inset: 0;
  z-index: 1;
  opacity: 0;
  pointer-events: none;
}

/* the whole gradient field is ONE element: all five colours are
   stacked radial gradients painted into a single texture, so there
   are no separate blurred layers to blend every frame (that overdraw
   was the mid-scroll hitch). It drifts by translate only — free, even
   though it looks soft, because there's no filter to re-rasterize. */
.field-gradient {
  position: absolute;
  inset: -20%;
  background:
    radial-gradient(58% 60% at 16% 12%, var(--yellow), rgba(255, 199, 0, 0) 72%),
    radial-gradient(56% 58% at 82% 14%, var(--teal), rgba(18, 181, 172, 0) 70%),
    radial-gradient(62% 64% at 86% 52%, var(--magenta), rgba(230, 56, 136, 0) 72%),
    radial-gradient(64% 62% at 44% 88%, var(--crimson), rgba(232, 56, 79, 0) 74%),
    radial-gradient(64% 66% at 10% 66%, var(--cyan), rgba(51, 187, 239, 0) 72%),
    radial-gradient(50% 50% at 52% 46%, rgba(230, 56, 136, 0.35), rgba(230, 56, 136, 0) 70%);
  will-change: transform;
  animation: field-drift 15s ease-in-out infinite alternate;
}

/* calm mode: after the 5s intro the field freezes in place */
body.calm .field-gradient,
body.calm .swirl { animation-play-state: paused; }

@keyframes field-drift {
  from { transform: translate3d(-2.5%, -1.5%, 0) rotate(-1.5deg); }
  to   { transform: translate3d(3%, 2.5%, 0) rotate(1.5deg); }
}

/* --- Rainbow swirl ring --- */
.swirl-wrap {
  position: fixed;
  top: 50%;
  left: 50%;
  z-index: 2;
  width: 72vmin;
  height: 72vmin;
  margin: -36vmin 0 0 -36vmin;
  opacity: 0;
  pointer-events: none;
  /* the blur NEVER changes: the ring is rasterized once, and the
     scroll-driven scale (up to 7.6×) stretches that cached texture,
     which magnifies the blur with it — the melt for free. Animating
     the radius instead forced a full GPU re-raster per step, which
     was the last one-frame hitch on phones. */
  filter: blur(26px) saturate(1.15);
  will-change: transform, opacity;
}

.swirl {
  width: 100%;
  height: 100%;
  border-radius: 50%;
  background: conic-gradient(
    from 20deg,
    var(--yellow),
    var(--crimson),
    var(--magenta),
    var(--cyan),
    var(--teal),
    var(--cyan),
    var(--yellow)
  );
  -webkit-mask: radial-gradient(closest-side, transparent 38%, #000 62%, #000 92%, transparent 100%);
  mask: radial-gradient(closest-side, transparent 38%, #000 62%, #000 92%, transparent 100%);
  animation: swirl-spin 14s linear infinite;
  will-change: transform;
}

@keyframes swirl-spin {
  to { transform: rotate(360deg); }
}

/* --- Centered logo --- */
.logo-fix {
  position: fixed;
  top: 50%;
  left: 50%;
  z-index: 3;
  transform: translate(-50%, -50%);
  pointer-events: none;
  will-change: transform, opacity;
}

.logo-img {
  width: min(52vw, 560px);
  animation: logo-pop 0.9s cubic-bezier(0.22, 1.4, 0.36, 1) both;
  animation-delay: 0.15s;
}

@keyframes logo-pop {
  0%   { transform: scale(0); opacity: 0; }
  70%  { transform: scale(1.06); opacity: 1; }
  100% { transform: scale(1); opacity: 1; }
}

/* --- Scroll hint --- */
.scroll-hint {
  position: fixed;
  bottom: 28px;
  left: 50%;
  transform: translateX(-50%);
  z-index: 4;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  color: var(--ink);
  opacity: 0.55;
  font-size: 0.8rem;
  font-weight: 600;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  transition: opacity 0.4s ease;
  pointer-events: none;
}

.scroll-hint svg { animation: hint-bob 1.6s ease-in-out infinite; }

@keyframes hint-bob {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(5px); }
}

/* ============================================================
   Scroll stage — empty space that drives the hero timeline
   ============================================================ */

.scroll-stage {
  height: 380vh;
}

/* ============================================================
   Content
   ============================================================ */

.content {
  position: relative;
  z-index: 10;
}

.products {
  max-width: 1200px;
  margin: 0 auto;
  padding: 4vh 24px 22vh;
}

/* ============================================================
   Product showcase — an infinite marquee ribbon of every product,
   drifting rightward above the section title. Pure transform loop
   (no repaint), so it's compositor-cheap and can't heat the phone.
   ============================================================ */
.showcase {
  overflow: hidden;
  margin: 2vh 0 7vh;
  /* soft fade at both edges so products slide in/out, not cut off */
  -webkit-mask-image: linear-gradient(
    to right, transparent 0%, #000 9%, #000 91%, transparent 100%
  );
  mask-image: linear-gradient(
    to right, transparent 0%, #000 9%, #000 91%, transparent 100%
  );
}

.showcase-track {
  display: flex;
  width: max-content;
  align-items: center;
  /* --loop (exact px width of one product set) + --dur are set in JS
     so the wrap lands on an integer pixel — no half-pixel seam snap */
  animation: showcase-scroll var(--dur, 46s) linear infinite;
  will-change: transform;
}

/* each product hugs its own width (the width/height attrs reserve the
   box before load, so the row can't collapse), sized by a fixed height
   with tight margins so they sit close together. Two identical halves
   with equal per-item margins → -50% is exactly one set, seamless. */
.showcase-item {
  flex: none;
  height: clamp(120px, 21vh, 190px);
  margin: 0 clamp(3px, 1vw, 12px);
  display: flex;
  align-items: center;
}

.showcase-item img {
  height: 100%;
  width: auto;
  object-fit: contain;
}

/* rightward drift: from showing the 2nd set to the 1st, then repeat.
   Wraps by exactly one set width, so the two identical sets line up
   pixel-for-pixel and there's no jump. */
@keyframes showcase-scroll {
  from { transform: translateX(calc(var(--loop, 50%) * -1)); }
  to { transform: translateX(0); }
}

@media (prefers-reduced-motion: reduce) {
  .showcase-track { animation: none; }
}

.products-head {
  text-align: center;
  max-width: 640px;
  margin: 0 auto 11vh;
}

.eyebrow {
  font-size: 0.8rem;
  font-weight: 500;
  letter-spacing: 0.32em;
  text-transform: uppercase;
  color: var(--ink-soft);
  margin-bottom: 16px;
}

.products-head h1 {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(2.5rem, 6vw, 4.4rem);
  line-height: 1.06;
  letter-spacing: -0.015em;
  color: var(--ink);
}

.lede {
  margin-top: 20px;
  font-weight: 300;
  font-size: clamp(1rem, 1.6vw, 1.15rem);
  line-height: 1.6;
  color: var(--ink-soft);
}

/* --- Product list: frosted glass cards over the gradient --- */
.product-list {
  --row-gap: clamp(40px, 8vh, 90px);
  list-style: none;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  align-items: stretch;
  column-gap: clamp(20px, 3.5vw, 52px);
  row-gap: var(--row-gap);
}

/* the card: translucent pane + frost noise + glossy rim.
   No backdrop-filter — the frost dust + translucent white read as
   glass without the per-scroll-frame blur that was heating phones. */
.product {
  position: relative;
  display: flex;
  justify-content: center;
  align-items: center;
  cursor: pointer;
  padding: clamp(28px, 4.5vh, 48px) 20px;
  border-radius: 28px;
  isolation: isolate;
  overflow: hidden;
  background: rgba(255, 255, 255, 0.13);
  border: 1px solid rgba(255, 255, 255, 0.4);
  box-shadow:
    0 18px 40px rgba(10, 16, 69, 0.1),
    inset 0 1px 0 rgba(255, 255, 255, 0.55),
    inset 0 0 12px 4px rgba(255, 255, 255, 0.08);
}

/* traditional frosted-film dust: dense fine white speckle,
   generated procedurally, rasterized once */
.product::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  filter: url(#frost-dust);
  opacity: 0.2;
}

/* fixed height so every row sits on one clean horizontal line,
   whatever the source image's aspect ratio */
.product img {
  height: clamp(220px, 30vh, 300px);
  width: auto;
  max-width: 100%;
  object-fit: contain;
  transform: scale(var(--img-zoom, 1));
  transition: transform 0.35s cubic-bezier(0.22, 1, 0.36, 1);
}

/* photos whose product sits small in its frame get zoomed up to fill
   the pane — layout ignores transforms, so the block stays put */
.product img.img-boost {
  --img-zoom: 1.22;
}

.product img.img-boost-lg {
  --img-zoom: 1.5;
}

/* family shots (several bottles in one photo) live in one long pane
   that stretches across the whole row */
.product-wide {
  grid-column: 1 / -1;
  padding-left: clamp(24px, 4vw, 64px);
  padding-right: clamp(24px, 4vw, 64px);
}

/* family shots keep their natural shape: capped by height on wide
   screens, by the pane's width on phones — no fixed-height letterbox.
   (doubled class outweighs the responsive `.product img` heights) */
.product.product-wide img {
  height: auto;
  max-height: clamp(260px, 38vh, 380px);
}

/* each cell of the catalog: a slim title bar riding above its card */
.product-cell {
  display: flex;
  flex-direction: column;
  gap: 12px;
  min-width: 0;
}

.cell-wide {
  grid-column: 1 / -1;
}

/* the card grows to fill the cell so rows stay level */
.product-cell .product {
  flex: 1;
}

/* a slim glass bar naming the product beneath it — the same liquid
   glass as the dock (blue tint + backdrop blur + glossy rim),
   not the frosted pane the cards use */
.catalog-title {
  position: relative;
  z-index: 2;
  display: flex;
  justify-content: center;
  align-items: center;
  padding: clamp(9px, 1.6vh, 14px) 20px;
  border-radius: 20px;
  isolation: isolate;
  overflow: hidden;
  background: linear-gradient(140deg, var(--tint1), var(--tint2));
  backdrop-filter: blur(3px) saturate(1.6);
  -webkit-backdrop-filter: blur(3px) saturate(1.6);
}

/* glossy rim + inner light, same recipe as the dock's shine layer */
.catalog-title::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
  border-radius: 20px;
  pointer-events: none;
  box-shadow:
    0 2px 10px rgba(11, 11, 15, 0.12),
    inset 2.5px 2.5px 1px -2px rgba(255, 255, 255, 0.95),
    inset -2.5px -2.5px 1px -2px rgba(255, 255, 255, 0.85),
    inset 1px 1px 1px -0.5px rgba(255, 255, 255, 0.6),
    inset -1px -1px 1px -0.5px rgba(255, 255, 255, 0.6),
    inset 0 0 8px 6px rgba(255, 255, 255, 0.14),
    inset 0 0 3px 2px rgba(255, 255, 255, 0.08);
}

/* per-product glass tints: same translucency as the dock's blue, the
   hue borrowed from the bottle the bar sits above. Default is the
   white-blue of the bleach and salt lines. */
.catalog-title {
  --tint1: rgba(120, 200, 255, 0.28);
  --tint2: rgba(51, 187, 239, 0.16);
}

.catalog-title.flow-red {
  --tint1: rgba(255, 130, 140, 0.3);
  --tint2: rgba(232, 56, 79, 0.16);
}

.catalog-title.flow-navy {
  --tint1: rgba(130, 152, 232, 0.3);
  --tint2: rgba(46, 62, 158, 0.18);
}

.catalog-title.flow-lime {
  --tint1: rgba(255, 222, 92, 0.32);
  --tint2: rgba(255, 199, 0, 0.18);
}

.catalog-title.flow-purple {
  --tint1: rgba(172, 156, 255, 0.3);
  --tint2: rgba(126, 110, 224, 0.18);
}

.catalog-title.flow-mango {
  --tint1: rgba(255, 192, 112, 0.32);
  --tint2: rgba(255, 152, 48, 0.18);
}

.catalog-title.flow-ocean {
  --tint1: rgba(150, 210, 250, 0.3);
  --tint2: rgba(38, 148, 228, 0.18);
}

/* tracking is tighter than the original English tracking so the
   longer Russian names fit inside the slim bars without clipping */
.catalog-title h2 {
  position: relative;
  z-index: 2;
  max-width: 100%;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(0.95rem, 2vw, 1.3rem);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  text-indent: 0.12em; /* re-centers text that tracking pushes left */
  color: var(--ink);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* column-width bars carry shorter names in smaller type */
.product-cell:not(.cell-wide) .catalog-title h2 {
  font-size: clamp(0.72rem, 1.2vw, 0.95rem);
  letter-spacing: 0.1em;
  text-indent: 0.1em;
}

/* the product grows a little to acknowledge a finger / cursor on its card */
@media (hover: hover) {
  .product:hover img { transform: scale(calc(var(--img-zoom, 1) * 1.08)); }
}
.product.touched img { transform: scale(calc(var(--img-zoom, 1) * 1.08)); }

/* the frost-dust texture stays hidden while these cards float in —
   rasterizing the SVG noise mid-animation flashed as a rectangle.
   It fades in quietly once the card has settled. (Product cards are
   exempt: they idle pre-painted at near-zero opacity, so their frost
   is rasterized at load and can be part of the card from frame one —
   no late "lightening" step.) */
.reveal.about-story::after,
.reveal.review::after {
  opacity: 0;
  transition: opacity 0.6s ease 1.2s;
}

.reveal.visible.about-story::after,
.reveal.visible.review::after {
  opacity: 0.2;
}
/* --- Scroll-in reveal: elements blur into focus as they rise ---
   one-shot per element (not a per-frame animation), staggered, and
   fired only once the image is decoded, so the blur has little to
   re-rasterize while it animates. */
.reveal {
  opacity: 0;
  translate: 0 34px;
  filter: blur(10px);
  transition:
    opacity 0.7s cubic-bezier(0.16, 1, 0.3, 1),
    translate 0.7s cubic-bezier(0.16, 1, 0.3, 1),
    filter 0.7s cubic-bezier(0.16, 1, 0.3, 1);
}

.reveal.visible {
  opacity: 1;
  translate: 0 0;
  filter: blur(0);
}

/* product cards take a touch longer to drift into focus.
   opacity is near-zero instead of zero so the card (and its PNG) is
   painted and sitting in GPU memory long before the reveal runs —
   opacity:0 lets the browser skip that paint until mid-animation,
   which is where the dark flash behind each bottle came from. */
.product.reveal,
.catalog-title.reveal {
  opacity: 0.001;
  transition:
    opacity 1.1s cubic-bezier(0.16, 1, 0.3, 1),
    translate 1.1s cubic-bezier(0.16, 1, 0.3, 1),
    filter 1.1s cubic-bezier(0.16, 1, 0.3, 1);
}

.product.reveal.visible,
.catalog-title.reveal.visible {
  opacity: 1;
}

/* the bar carries a backdrop-filter; animating a blur filter on top
   of one is the iOS black-flash recipe — it fades and rises only */
.catalog-title.reveal {
  filter: none;
}

/* ============================================================
   Text effect — per-word blur-in stagger for the standalone
   headings (a vanilla take on the framer-motion "blur" preset:
   each word rises from opacity:0/blur(12px) to blur(0), one after
   another). Applied only to the free-floating page texts, not the
   copy that lives inside glass blocks.
   ============================================================ */
.te-word {
  display: inline-block;
  opacity: 0;
  filter: blur(12px);
  transition:
    opacity var(--te-dur, 0.5s) ease,
    filter var(--te-dur, 0.5s) ease;
  transition-delay: calc(var(--te-delay, 0s) + var(--i, 0) * var(--te-step, 0.045s));
}

/* the About heading reveals noticeably slower and more gracefully */
.about-head h2 .te-word {
  --te-dur: 1.1s;
  --te-step: 0.14s;
}

.te.in .te-word {
  opacity: 1;
  filter: blur(0);
}

/* cards whose inner text carries the word effect slide/fade in without
   their own blur, so the text isn't blurred by both the card and itself */
.reveal.no-blur,
.reveal.no-blur.visible {
  filter: none;
}

@media (prefers-reduced-motion: reduce) {
  .te-word {
    opacity: 1;
    filter: none;
    transition: none;
  }
}

/* language-switch blur-in (phones only — desktop swaps instantly). The
   freshly swapped text materialises out of a soft blur. Applied and
   removed by the lang toggle in JS. */
@keyframes lang-blur-in {
  from {
    opacity: 0;
    filter: blur(9px);
  }
  to {
    opacity: 1;
    filter: blur(0);
  }
}
.lang-in {
  animation: lang-blur-in 1s ease both;
}
@media (prefers-reduced-motion: reduce) {
  .lang-in {
    animation: none;
  }
}

/* ============================================================
   Liquid glass BUY button
   ============================================================ */

.buy-wrap {
  display: flex;
  justify-content: center;
  margin-top: clamp(48px, 9vh, 110px);
}

.buy-btn {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  white-space: nowrap;
  padding: 20px 72px;
  border: none;
  border-radius: 999px;
  cursor: pointer;
  text-decoration: none;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(1.1rem, 1.9vw, 1.4rem);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ink);
  background: linear-gradient(
    140deg,
    rgba(255, 221, 92, 0.44),
    rgba(255, 199, 0, 0.26)
  );
  backdrop-filter: blur(4px) saturate(1.6);
  -webkit-backdrop-filter: blur(4px) saturate(1.6);
  text-shadow: 0 1px 6px rgba(255, 255, 255, 0.55);
  transition: transform 0.25s ease, box-shadow 0.25s ease;
}

/* glossy liquid-glass rim, same treatment as the dock */
.buy-shine {
  position: absolute;
  inset: 0;
  z-index: 1;
  border-radius: 999px;
  pointer-events: none;
  box-shadow:
    0 10px 26px rgba(10, 16, 69, 0.16),
    inset 3px 3px 1px -2px rgba(255, 255, 255, 0.95),
    inset -3px -3px 1px -2px rgba(255, 255, 255, 0.8),
    inset 1px 1px 1px -0.5px rgba(255, 255, 255, 0.6),
    inset -1px -1px 1px -0.5px rgba(255, 255, 255, 0.6),
    inset 0 0 10px 6px rgba(255, 255, 255, 0.14);
}

.buy-label {
  position: relative;
  z-index: 2;
}

.buy-btn:hover {
  transform: translateY(-2px);
  box-shadow: 0 14px 30px rgba(255, 199, 0, 0.32);
}

.buy-btn:active { transform: translateY(0); }

.buy-btn:focus-visible {
  outline: 2px solid var(--ink);
  outline-offset: 3px;
}

/* ============================================================
   Detail-view action buttons — liquid-glass "Отзывы" + "Купить"
   pair sitting under each product description. Same glass recipe
   as the main BUY button, sized down to a paired row.
   ============================================================ */

/* "available in Korzinka" — a static foil award badge with a red
   holographic sheen (pre-rendered to a PNG, so it costs nothing to
   paint; it was ported from the Product Hunt AwardBadge). */
.korzinka-badge {
  display: block;
  width: min(290px, 100%);
  margin-top: clamp(20px, 3vh, 32px);
  border-radius: 11px;
  text-decoration: none;
  transition: transform 0.25s ease;
  /* let a finger-drag on the badge tilt it instead of scrolling */
  touch-action: none;
  transform-origin: center;
  backface-visibility: hidden;
  will-change: transform;
}

.korzinka-badge[hidden] { display: none; }
.korzinka-badge:hover { transform: translateY(-2px); }
.korzinka-badge:focus-visible { outline: 2px solid var(--ink); outline-offset: 4px; }

.korzinka-img {
  display: block;
  width: 100%;
  height: auto;
}

.detail-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 14px;
  margin-top: clamp(24px, 4vh, 40px);
}

.glass-btn {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  flex: 1 1 140px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  padding: 15px 20px;
  border: none;
  border-radius: 999px;
  cursor: pointer;
  text-decoration: none;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(0.95rem, 1.5vw, 1.15rem);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink);
  text-shadow: 0 1px 6px rgba(255, 255, 255, 0.55);
  backdrop-filter: blur(4px) saturate(1.6);
  -webkit-backdrop-filter: blur(4px) saturate(1.6);
  transition: transform 0.25s ease, box-shadow 0.25s ease;
}

/* reviews: fresh green glass */
.glass-btn-reviews {
  background: linear-gradient(
    140deg,
    rgba(74, 205, 96, 0.56),
    rgba(38, 170, 82, 0.4)
  );
}

/* buy: the warm gold glass, echoing the main BUY button */
.glass-btn-buy {
  background: linear-gradient(
    140deg,
    rgba(255, 221, 92, 0.44),
    rgba(255, 199, 0, 0.26)
  );
}

/* glossy liquid-glass rim, same treatment as the dock + BUY button */
.glass-btn-shine {
  position: absolute;
  inset: 0;
  z-index: 1;
  border-radius: 999px;
  pointer-events: none;
  box-shadow:
    0 8px 20px rgba(10, 16, 69, 0.14),
    inset 3px 3px 1px -2px rgba(255, 255, 255, 0.95),
    inset -3px -3px 1px -2px rgba(255, 255, 255, 0.8),
    inset 1px 1px 1px -0.5px rgba(255, 255, 255, 0.6),
    inset -1px -1px 1px -0.5px rgba(255, 255, 255, 0.6),
    inset 0 0 10px 6px rgba(255, 255, 255, 0.14);
}

.glass-btn-label {
  position: relative;
  z-index: 2;
}

.glass-btn:hover { transform: translateY(-2px); }
.glass-btn-reviews:hover { box-shadow: 0 12px 26px rgba(38, 170, 82, 0.36); }
.glass-btn-buy:hover { box-shadow: 0 12px 26px rgba(255, 199, 0, 0.3); }
.glass-btn:active { transform: translateY(0); }

.glass-btn:focus-visible {
  outline: 2px solid var(--ink);
  outline-offset: 3px;
}

/* reviews panel — unfolds under the buttons when "Отзывы" is pressed */
/* "more reviews" button under the About-section review list */
.more-reviews-wrap {
  display: flex;
  justify-content: center;
  margin-top: clamp(28px, 4vh, 44px);
}

/* stay auto-width here (don't inherit the paired-row flex-grow) */
.more-reviews-wrap .glass-btn {
  flex: 0 0 auto;
}

/* same frosted, green-tinted glass as the review cards themselves */
.more-reviews-btn {
  background: linear-gradient(
    140deg,
    rgba(178, 240, 210, 0.38),
    rgba(126, 228, 154, 0.18)
  );
  border: 1px solid rgba(255, 255, 255, 0.4);
  box-shadow:
    0 18px 40px rgba(10, 16, 69, 0.1),
    inset 0 1px 0 rgba(255, 255, 255, 0.55),
    inset 0 0 12px 4px rgba(255, 255, 255, 0.08);
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
}

/* the review cards' frost-dust grain */
.more-reviews-btn::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  border-radius: inherit;
  filter: url(#frost-dust);
  opacity: 0.2;
}

/* the heavy liquid-glass rim isn't part of the review material */
.more-reviews-btn .glass-btn-shine { display: none; }

.more-reviews-btn:hover {
  box-shadow:
    0 24px 50px rgba(10, 16, 69, 0.16),
    inset 0 1px 0 rgba(255, 255, 255, 0.55),
    inset 0 0 12px 4px rgba(255, 255, 255, 0.08);
}

.detail-reviews {
  display: grid;
  gap: 12px;
  margin-top: 20px;
}

/* class-based display would otherwise override the hidden attribute */
.detail-reviews[hidden] {
  display: none;
}

.detail-review {
  position: relative;
  padding: 16px 18px;
  border-radius: 16px;
  background: rgba(255, 255, 255, 0.6);
  box-shadow: inset 0 0 0 1px rgba(11, 11, 15, 0.06);
}

.detail-review-body {
  margin: 0 0 8px;
  line-height: 1.5;
  color: var(--ink);
}

.detail-review-name {
  font-weight: 600;
  font-size: 0.9rem;
  color: var(--ink);
  opacity: 0.75;
}

.detail-review-stars {
  color: #ffb800;
  letter-spacing: 2px;
  margin-bottom: 6px;
}

.detail-reviews-empty {
  padding: 14px 2px;
  color: var(--ink);
  opacity: 0.6;
  line-height: 1.5;
}

/* ============================================================
   About us — aurora light bands over a milky base, brand story,
   reviews and contact pills. Aurora drifts by transform only
   (compositor-cheap) and only while the section is on screen.
   ============================================================ */

.about-view {
  isolation: isolate;
  padding: 16vh 24px 14vh;
  min-height: 100vh;
  /* milky base fading in from the gradient field above */
  background: linear-gradient(
    180deg,
    rgba(250, 251, 255, 0) 0%,
    rgba(250, 251, 255, 0.88) 18%,
    rgba(250, 251, 255, 0.88) 100%
  );
}

.aurora {
  /* fixed to the viewport (not absolute inside the scroll container) so
     it always fills the whole screen edge-to-edge — an absolute box
     shrinks by the scrollbar width and stops covering once you scroll
     past the buttons, which left visible gaps on the sides/bottom */
  position: fixed;
  inset: 0;
  z-index: 0;
  overflow: hidden;
  /* bands melt away at the top (into the gradient field) and
     quiet down behind the contact pills at the bottom */
  -webkit-mask-image: linear-gradient(to bottom, transparent 0%, #000 24%, #000 72%, transparent 100%);
  mask-image: linear-gradient(to bottom, transparent 0%, #000 24%, #000 72%, transparent 100%);
}

/* diagonal aurora bands in the ECOTAB palette. Painted once and never
   moved — no animation, no compositor layer, no filter — so it's just
   a static picture that can't lag or heat the phone. */
.aurora-layer {
  position: absolute;
  top: -20%;
  bottom: -20%;
  left: -55%;
  width: 210%;
  background-image:
    repeating-linear-gradient(
      100deg,
      #fff 0%, #fff 6%,
      rgba(255, 255, 255, 0) 11%,
      rgba(255, 255, 255, 0) 15%,
      #fff 20%
    ),
    repeating-linear-gradient(
      100deg,
      rgba(51, 187, 239, 0.5) 8%,
      rgba(18, 181, 172, 0.4) 13%,
      rgba(159, 158, 255, 0.42) 18%,
      rgba(230, 56, 136, 0.3) 23%,
      rgba(255, 199, 0, 0.28) 27%,
      rgba(51, 187, 239, 0.5) 32%
    );
  background-size: 300% 200%, 200% 200%;
  background-position: 50% 50%;
  opacity: 0.55;
}

/* living glow behind the contact pills: colored light that shines up
   from the very bottom of the page, reaching about the buttons, and
   slowly moves around. An absolutely-positioned overlay — it adds no
   height, the page still ends right after the pills. The blobs drift
   by transform only (compositor-cheap, no filters, no repaints). */
.about-bottom-glow {
  position: absolute;
  z-index: -1;
  /* full-bleed: the .about-inner container is capped at 1100px, so
     anchoring to its edges left the glow cut off before the screen
     edges. Break out to the full viewport width, centred. */
  left: 50%;
  width: 100vw;
  transform: translateX(-50%);
  bottom: -14vh;
  height: 48vh;
  overflow: hidden;
  pointer-events: none;
  -webkit-mask-image: linear-gradient(to bottom, transparent 0%, #000 58%);
  mask-image: linear-gradient(to bottom, transparent 0%, #000 58%);
}

.glow-blob {
  position: absolute;
  bottom: -30%;
  width: 75vmin;
  height: 75vmin;
  border-radius: 50%;
  will-change: transform;
}

.glow-blob-cyan {
  left: -12%;
  background: radial-gradient(circle, rgba(51, 187, 239, 0.62) 0%, transparent 62%);
  animation: glow-drift-a 4.5s ease-in-out infinite alternate;
}

.glow-blob-magenta {
  right: -12%;
  background: radial-gradient(circle, rgba(230, 56, 136, 0.55) 0%, transparent 62%);
  animation: glow-drift-b 6s ease-in-out infinite alternate;
}

.glow-blob-yellow {
  left: 30%;
  bottom: -40%;
  background: radial-gradient(circle, rgba(255, 199, 0, 0.5) 0%, transparent 65%);
  animation: glow-drift-c 3.5s ease-in-out infinite alternate;
}

@keyframes glow-drift-a {
  from { transform: translate3d(-8%, 4%, 0) scale(0.9); }
  to   { transform: translate3d(42%, -18%, 0) scale(1.35); }
}
@keyframes glow-drift-b {
  from { transform: translate3d(6%, 10%, 0) scale(1.3); }
  to   { transform: translate3d(-40%, -16%, 0) scale(0.85); }
}
@keyframes glow-drift-c {
  from { transform: translate3d(-26%, 4%, 0) scale(0.85); }
  to   { transform: translate3d(28%, -20%, 0) scale(1.4); }
}

.about-inner {
  position: relative;
  z-index: 1;
  max-width: 1100px;
  margin: 0 auto;
}

.about-head {
  text-align: center;
  max-width: 640px;
  margin: 0 auto 7vh;
}

.about-head h2 {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(2.2rem, 5vw, 3.8rem);
  line-height: 1.08;
  letter-spacing: -0.015em;
  color: var(--ink);
}

/* --- brand story: one glass panel, same recipe as the cards --- */
/* the brand info block: a glass card that unfolds vertically from a
   thin line to full height when it scrolls in; its text animates in
   only once the card is fully open (sequenced from JS). */
.about-story {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  max-width: 720px;
  margin: 0 auto;
  padding: clamp(28px, 4vh, 44px) clamp(24px, 4vw, 48px);
  border-radius: 28px;
  background: rgba(255, 255, 255, 0.13);
  border: 1px solid rgba(255, 255, 255, 0.4);
  box-shadow:
    0 18px 40px rgba(10, 16, 69, 0.1),
    inset 0 1px 0 rgba(255, 255, 255, 0.55),
    inset 0 0 12px 4px rgba(255, 255, 255, 0.08);
}

/* the unfold: from a squished line to full height, slow enough to
   read as a deliberate reveal, plus a gentle fade */
.about-story.story-expand {
  opacity: 0;
  transform: scaleY(0.015);
  transform-origin: center;
  will-change: transform;
  transition:
    transform 1.3s cubic-bezier(0.22, 1, 0.36, 1),
    opacity 0.7s ease;
}

.about-story.story-expand.story-open {
  opacity: 1;
  transform: scaleY(1);
}

.about-story::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  filter: url(#frost-dust);
  opacity: 0.2;
}

/* keep the filtered frost out of the scaleY unfold — scaling a filtered
   layer re-rasterizes every frame on iOS. It stays hidden while the card
   grows, then fades in once the card has reached full height. */
.about-story.story-expand::after {
  opacity: 0;
  transition: opacity 0.4s ease;
}
.about-story.story-expand.story-open::after {
  opacity: 0.2;
  transition: opacity 0.5s ease 1.3s;
}

.about-story-inner { position: relative; z-index: 2; }

.about-text {
  font-weight: 300;
  font-size: clamp(0.98rem, 1.5vw, 1.1rem);
  line-height: 1.7;
  color: var(--ink-soft);
}

.about-text + .about-text { margin-top: 12px; }

/* key phrases lifted out of the body copy: a touch heavier and a
   shade darker than the surrounding text — no background, just weight */
.about-text .hl {
  color: var(--ink);
  font-weight: 500;
}

/* --- reviews --- */
.about-reviews { margin-top: 11vh; }

.reviews-title {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(1.5rem, 3.2vw, 2.2rem);
  color: var(--ink);
  text-align: center;
  margin-bottom: 5vh;
}

.review-list {
  list-style: none;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: clamp(16px, 2.5vw, 28px);
}

.review {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  padding: 26px 24px;
  border-radius: 24px;
  /* transform + box-shadow = the touch/hover grow; the rest keeps the
     blur-in reveal working (this rule's transition overrides .reveal's) */
  transition:
    opacity 0.7s cubic-bezier(0.16, 1, 0.3, 1),
    translate 0.7s cubic-bezier(0.16, 1, 0.3, 1),
    filter 0.7s cubic-bezier(0.16, 1, 0.3, 1),
    transform 0.3s cubic-bezier(0.22, 1, 0.36, 1),
    box-shadow 0.3s ease;
  /* light green tint over the glass */
  background: linear-gradient(
    140deg,
    rgba(178, 240, 210, 0.38),
    rgba(126, 228, 154, 0.18)
  );
  border: 1px solid rgba(255, 255, 255, 0.4);
  box-shadow:
    0 18px 40px rgba(10, 16, 69, 0.1),
    inset 0 1px 0 rgba(255, 255, 255, 0.55),
    inset 0 0 12px 4px rgba(255, 255, 255, 0.08);
}

.review::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  filter: url(#frost-dust);
  opacity: 0.2;
}

/* the block expands a touch and lifts while pressed / hovered */
@media (hover: hover) {
  .review:hover {
    transform: scale(1.04);
    box-shadow:
      0 26px 54px rgba(10, 16, 69, 0.16),
      inset 0 1px 0 rgba(255, 255, 255, 0.55),
      inset 0 0 12px 4px rgba(255, 255, 255, 0.08);
  }
}

.review.touched {
  transform: scale(1.04);
  box-shadow:
    0 26px 54px rgba(10, 16, 69, 0.16),
    inset 0 1px 0 rgba(255, 255, 255, 0.55),
    inset 0 0 12px 4px rgba(255, 255, 255, 0.08);
}

.review-stars {
  color: var(--yellow);
  font-size: 1.05rem;
  letter-spacing: 0.22em;
  text-shadow: 0 1px 4px rgba(255, 199, 0, 0.35);
  margin-bottom: 14px;
}

.review-text {
  font-weight: 300;
  font-size: 0.95rem;
  line-height: 1.65;
  color: var(--ink-soft);
}

.review-name {
  margin-top: auto;
  padding-top: 18px;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 0.9rem;
  color: var(--ink);
}

/* --- contact pills: blue liquid glass, like the dock --- */
.about-contacts {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 14px;
  margin-top: 9vh;
}

.contact-btn {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  display: inline-flex;
  align-items: center;
  gap: 10px;
  padding: 14px 26px;
  border-radius: 999px;
  text-decoration: none;
  font-family: var(--font-body);
  font-weight: 500;
  font-size: 0.82rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ink);
  background: linear-gradient(
    140deg,
    rgba(120, 200, 255, 0.32),
    rgba(51, 187, 239, 0.18)
  );
  text-shadow: 0 1px 6px rgba(255, 255, 255, 0.5);
  transition: transform 0.25s ease, box-shadow 0.25s ease;
}

.contact-shine {
  position: absolute;
  inset: 0;
  z-index: 1;
  border-radius: 999px;
  pointer-events: none;
  box-shadow:
    0 4px 14px rgba(10, 16, 69, 0.14),
    inset 2.5px 2.5px 1px -2px rgba(255, 255, 255, 0.95),
    inset -2.5px -2.5px 1px -2px rgba(255, 255, 255, 0.8),
    inset 0 0 8px 5px rgba(255, 255, 255, 0.14);
}

.contact-icon {
  position: relative;
  z-index: 2;
  width: 17px;
  height: 17px;
  flex: none;
}

.contact-label {
  position: relative;
  z-index: 2;
}

.contact-btn:hover {
  transform: translateY(-2px);
  box-shadow: 0 12px 26px rgba(51, 187, 239, 0.3);
}

.contact-btn:active { transform: translateY(0); }

.contact-btn:focus-visible {
  outline: 2px solid var(--ink);
  outline-offset: 3px;
}


/* --- per-platform brand tints (still translucent liquid glass) --- */
.contact-instagram {
  background: linear-gradient(140deg, rgba(255, 196, 54, 0.46), rgba(232, 62, 92, 0.32));
}
.contact-instagram:hover { box-shadow: 0 12px 26px rgba(232, 78, 92, 0.32); }

.contact-telegram {
  background: linear-gradient(140deg, rgba(146, 214, 255, 0.46), rgba(56, 168, 235, 0.26));
}
.contact-telegram:hover { box-shadow: 0 12px 26px rgba(56, 168, 235, 0.32); }

.contact-phone {
  background: linear-gradient(140deg, rgba(126, 228, 154, 0.46), rgba(28, 190, 110, 0.28));
}
.contact-phone:hover { box-shadow: 0 12px 26px rgba(36, 200, 120, 0.32); }

.contact-email {
  background: linear-gradient(140deg, rgba(255, 148, 128, 0.46), rgba(228, 52, 60, 0.3));
}
.contact-email:hover { box-shadow: 0 12px 26px rgba(228, 64, 66, 0.32); }

/* ============================================================
   Liquid glass top bar — the nav dock and language switch,
   centered together and sliding in as one.
   ============================================================ */

.top-bar {
  position: fixed;
  top: 26px;
  left: 50%;
  z-index: 50;
  display: flex;
  align-items: center;
  gap: 12px;
  transform: translateX(-50%) translateY(calc(-100% - 34px));
  transition:
    transform 0.7s cubic-bezier(0.22, 1.2, 0.36, 1),
    opacity 0.35s ease;
  pointer-events: none;
  user-select: none;
}

.top-bar.visible {
  transform: translateX(-50%) translateY(0);
  pointer-events: auto;
}

/* shared liquid-glass pill shell for the dock and the language switch */
.glass-pill {
  position: relative; /* keeps the sliding glow's offsetParent local */
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 12px 16px;
  border-radius: 999px;
  isolation: isolate;
  overflow: hidden;
  background: linear-gradient(
    140deg,
    rgba(120, 200, 255, 0.28),
    rgba(51, 187, 239, 0.16)
  );
  backdrop-filter: blur(3px) saturate(1.6);
  -webkit-backdrop-filter: blur(3px) saturate(1.6);
}

.lang-switch { flex: none; }

/* glossy rim + inner light, borrowed from the liquid-glass reference */
.dock-shine {
  position: absolute;
  inset: 0;
  z-index: 1;
  border-radius: 999px;
  box-shadow:
    0 2px 10px rgba(11, 11, 15, 0.12),
    inset 2.5px 2.5px 1px -2px rgba(255, 255, 255, 0.95),
    inset -2.5px -2.5px 1px -2px rgba(255, 255, 255, 0.85),
    inset 1px 1px 1px -0.5px rgba(255, 255, 255, 0.6),
    inset -1px -1px 1px -0.5px rgba(255, 255, 255, 0.6),
    inset 0 0 8px 6px rgba(255, 255, 255, 0.14),
    inset 0 0 3px 2px rgba(255, 255, 255, 0.08);
}

/* refraction layer: distorts whatever scrolls beneath the dock */
.dock-refraction {
  position: absolute;
  inset: 0;
  z-index: -1;
  border-radius: 999px;
  overflow: hidden;
  backdrop-filter: url("#glass-distort");
  -webkit-backdrop-filter: url("#glass-distort");
}

.dock-item {
  position: relative;
  z-index: 2;
  padding: 9px 22px;
  border-radius: 999px;
  font-family: var(--font-body);
  font-weight: 500;
  font-size: 0.82rem;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  white-space: nowrap;
  color: var(--black);
  text-decoration: none;
  text-shadow: 0 1px 6px rgba(255, 255, 255, 0.5);
  transition: background 0.25s ease;
}

.dock-item:hover { color: var(--ink); }

.dock-item:focus-visible {
  outline: 2px solid var(--ink);
  outline-offset: 2px;
}

/* the language items are <button>s — strip the browser's default
   button chrome so they match the dock links exactly */
.lang-item {
  appearance: none;
  -webkit-appearance: none;
  border: 0;
  margin: 0;
  background: transparent;
  cursor: pointer;
}

/* the highlight pill — a brighter glass tab that slides between the
   items to sit behind whichever section is active */
.dock-glow {
  position: absolute;
  left: 0;
  top: 0;
  z-index: 1; /* above the shine, behind the labels (z-index 2) */
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.4);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.8),
    0 2px 8px rgba(10, 16, 69, 0.1);
  pointer-events: none;
}

/* only animate the slide after the first placement */
.dock-glow.ready {
  transition:
    transform 0.5s cubic-bezier(0.34, 1.4, 0.5, 1),
    width 0.5s cubic-bezier(0.34, 1.4, 0.5, 1);
}

.glass-defs {
  position: absolute;
  width: 0;
  height: 0;
  overflow: hidden;
}

/* ============================================================
   Product detail — a full-screen glass sheet; its liquid glass
   rectangles bloom open in a clean staggered reveal.
   ============================================================ */

.detail {
  position: fixed;
  inset: 0;
  z-index: 60;
  isolation: isolate;
  overflow: hidden;
  background: rgba(255, 255, 255, 0.13);
  border: 1px solid rgba(255, 255, 255, 0.4);
  box-shadow:
    0 18px 40px rgba(10, 16, 69, 0.1),
    inset 0 1px 0 rgba(255, 255, 255, 0.55);
  opacity: 0;
  transition: opacity 0.4s ease;
}

.detail[hidden] { display: none; }

.detail.open {
  opacity: 1;
  overflow-y: auto;
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
}

/* a 2×2px crop in the page corner holding every gallery photo at a
   real layout size — imperceptible, but because the images are
   attached and painted, iOS keeps their decoded pixels resident and
   a first tap never pays image decode */
.img-pantry {
  position: fixed;
  left: 0;
  bottom: 0;
  width: 90px;
  height: 3px;
  overflow: hidden;
  opacity: 0.01;
  pointer-events: none;
  z-index: 1;
}

/* every image gets its own on-screen sliver: images fully clipped
   out of view are culled by Safari and never decoded at all, so they
   are staggered 3px apart — each one's corner is genuinely painted,
   which pins its full decode. Held at the same geometry the detail
   gallery displays so the cached decode is the right resolution. */
.img-pantry img {
  position: absolute;
  top: 0;
  left: calc(var(--i, 0) * 3px);
  height: min(38vh, 344px);
  width: auto;
}

/* idle dry-run: the sheet is painted once at imperceptible opacity so
   its glass layers are already rasterized when the first real open
   comes. Everything is forced to its final pose, no transitions. */
.detail.prewarm {
  opacity: 0.001;
  pointer-events: none;
  transition: none;
}

.detail.prewarm .detail-slide,
.detail.prewarm .detail-info,
.detail.prewarm .detail-howto {
  opacity: 0.001;
  transform: none;
  transition: none;
}

.detail-inner {
  max-width: 920px;
  margin: 0 auto;
  padding: 96px 22px 64px;
}

/* --- the liquid glass rectangles bloom from nothing, staggered,
       sliding outward as they scale up --- */
.detail-slide,
.detail-info,
.detail-howto {
  opacity: 0;
  transform: scale(0.55);
  transform-origin: center;
  transition:
    opacity 0.5s ease,
    transform 0.65s cubic-bezier(0.22, 1, 0.36, 1);
}

.detail.open .detail-slide,
.detail.open .detail-info,
.detail.open .detail-howto {
  opacity: 1;
  transform: scale(1);
}

.detail.open .detail-slide:nth-child(1) { transition-delay: 0.1s; }
.detail.open .detail-slide:nth-child(2) { transition-delay: 0.22s; }
.detail.open .detail-slide:nth-child(3) { transition-delay: 0.34s; }
.detail.open .detail-slide:nth-child(4) { transition-delay: 0.46s; }
.detail.open .detail-info { transition-delay: 0.4s; }
.detail.open .detail-howto { transition-delay: 0.5s; }

/* --- closing: the same bloom, played in reverse. The sheet stays lit
       while the rectangles collapse back to nothing (info leaves first,
       then the slides fold in from last to first), then the sheet fades. */
.detail.open.closing { opacity: 1; }

/* the sheet's final dissolve is slow enough to crossfade with the
   products page gliding back in underneath */
.detail.closing { transition: opacity 0.8s ease; }

.detail.open.closing .detail-slide,
.detail.open.closing .detail-info,
.detail.open.closing .detail-howto {
  opacity: 0;
  transform: scale(0.55);
}

.detail.open.closing .detail-howto { transition-delay: 0s; }
.detail.open.closing .detail-info { transition-delay: 0s; }
.detail.open.closing .detail-slide:nth-child(4) { transition-delay: 0.1s; }
.detail.open.closing .detail-slide:nth-child(3) { transition-delay: 0.2s; }
.detail.open.closing .detail-slide:nth-child(2) { transition-delay: 0.3s; }
.detail.open.closing .detail-slide:nth-child(1) { transition-delay: 0.4s; }

/* --- gallery: swipeable strip of glass slides --- */
.detail-gallery-wrap {
  position: relative;
}

.detail-gallery {
  display: flex;
  gap: 16px;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  padding: 6px 4px 20px;
}

/* single-photo products: centre the lone slide instead of pinning it left */
.detail-gallery.single {
  justify-content: center;
}

/* --- size bar: liquid-glass column of pack sizes, floating in the
       gutter to the right of the centred product photo --- */
.size-bar {
  position: absolute;
  top: 50%;
  right: clamp(2px, 2vw, 26px);
  z-index: 5;
  display: flex;
  flex-direction: column;
  gap: 5px;
  padding: 6px;
  border-radius: 22px;
  background: linear-gradient(
    150deg,
    rgba(255, 255, 255, 0.72),
    rgba(255, 255, 255, 0.42)
  );
  border: 1px solid rgba(255, 255, 255, 0.75);
  box-shadow:
    0 10px 28px rgba(10, 16, 69, 0.16),
    inset 0 1px 0 rgba(255, 255, 255, 0.9);
  /* blooms in after the slides, then rides the sheet's fade */
  opacity: 0;
  transform: translateY(-50%) scale(0.82);
  transition:
    opacity 0.5s ease 0.5s,
    transform 0.6s cubic-bezier(0.22, 1, 0.36, 1) 0.5s;
}

.detail.open .size-bar {
  opacity: 1;
  transform: translateY(-50%) scale(1);
}

.detail.open.closing .size-bar {
  opacity: 0;
  transform: translateY(-50%) scale(0.82);
  transition-delay: 0s;
}

.size-bar[hidden] { display: none; }

.size-chip {
  appearance: none;
  -webkit-appearance: none;
  border: 0;
  margin: 0;
  cursor: pointer;
  min-width: 46px;
  padding: 9px 8px;
  border-radius: 15px;
  background: transparent;
  color: var(--ink-soft);
  font-family: var(--font-body);
  font-weight: 600;
  font-size: 0.72rem;
  line-height: 1.05;
  letter-spacing: 0.01em;
  text-align: center;
  white-space: nowrap;
  transition:
    color 0.25s ease,
    background 0.25s ease,
    box-shadow 0.25s ease;
}

.size-chip.active {
  color: var(--ink);
  background: rgba(255, 255, 255, 0.92);
  box-shadow:
    0 3px 10px rgba(10, 16, 69, 0.12),
    inset 0 1px 0 rgba(255, 255, 255, 0.95);
}

@media (hover: hover) {
  .size-chip:hover { color: var(--ink); }
}

/* single-size products: the chip is a label, not a control */
.size-bar.single .size-chip { cursor: default; }

.detail-slide {
  flex: 0 0 min(78%, 460px);
  height: min(44vh, 400px);
  display: flex;
  align-items: center;
  justify-content: center;
  scroll-snap-align: center;
  border-radius: 24px;
  background: rgba(255, 255, 255, 0.16);
  border: 1px solid rgba(255, 255, 255, 0.45);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.55);
}

.detail-slide img {
  height: 86%;
  width: auto;
  max-width: 88%;
  object-fit: contain;
}

/* --- info panel --- */
.detail-info {
  margin-top: 26px;
  padding: clamp(24px, 4vw, 40px);
  border-radius: 24px;
  background: rgba(255, 255, 255, 0.14);
  border: 1px solid rgba(255, 255, 255, 0.45);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.55);
}

/* --- desktop: photo and info sit side by side, vertically centred,
       instead of the mobile top-to-bottom stack --- */
@media (min-width: 1000px) {
  .detail-inner {
    display: grid;
    grid-template-columns: 1fr 1fr;
    align-items: center;
    gap: clamp(36px, 5vw, 84px);
    max-width: 1180px;
    min-height: 100vh;
    padding: 80px 56px;
  }
  .detail-info {
    margin-top: 0;
    align-self: center;
  }
  /* the how-to block spans the full width, under both columns */
  .detail-howto {
    grid-column: 1 / -1;
    max-width: 760px;
    margin: clamp(20px, 4vh, 48px) auto 0;
  }

  /* bigger, more prominent product marquee on desktop */
  .showcase-item {
    height: clamp(220px, 20vw, 300px);
    margin: 0 clamp(8px, 1.4vw, 20px);
  }
}

/* --- how-to: step-by-step usage block under the info panel.
       Tinted per product (--ht1/--ht2 set in JS from the slug). --- */
.detail-howto {
  margin-top: 22px;
  padding: clamp(24px, 4vw, 38px);
  border-radius: 24px;
  background: linear-gradient(
    140deg,
    var(--ht1, rgba(255, 255, 255, 0.16)),
    var(--ht2, rgba(255, 255, 255, 0.06))
  );
  border: 1px solid rgba(255, 255, 255, 0.5);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.55);
}

.detail-howto[hidden] { display: none; }

.detail-howto-title {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(1.3rem, 2.6vw, 1.7rem);
  color: var(--ink);
  margin-bottom: clamp(16px, 2.5vh, 24px);
}

.detail-howto-steps {
  list-style: none;
  counter-reset: howto;
  display: flex;
  flex-direction: column;
  gap: 14px;
}

.detail-howto-step {
  counter-increment: howto;
  position: relative;
  padding-left: 52px;
  min-height: 34px;
  display: flex;
  align-items: center;
  font-weight: 300;
  font-size: clamp(0.95rem, 1.5vw, 1.05rem);
  line-height: 1.55;
  color: var(--ink-soft);
}

/* the numbered badge — same product tint, a touch stronger */
.detail-howto-step::before {
  content: counter(howto);
  position: absolute;
  left: 0;
  top: 0;
  width: 34px;
  height: 34px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  background:
    linear-gradient(140deg, rgba(255, 255, 255, 0.5), rgba(255, 255, 255, 0.15)),
    linear-gradient(140deg, var(--ht1, rgba(120, 200, 255, 0.4)), var(--ht2, rgba(51, 187, 239, 0.22)));
  border: 1px solid rgba(255, 255, 255, 0.65);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.7);
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 0.95rem;
  color: var(--ink);
}

.detail-name {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(1.9rem, 4.5vw, 3rem);
  color: var(--ink);
  margin-bottom: 14px;
}

.detail-text {
  font-weight: 300;
  font-size: clamp(0.98rem, 1.5vw, 1.1rem);
  line-height: 1.7;
  color: var(--ink-soft);
  max-width: 620px;
}

.detail-text + .detail-text { margin-top: 12px; }

/* --- back button: liquid glass pill, blue like the dock --- */
.detail-back {
  position: fixed;
  top: 22px;
  left: 22px;
  z-index: 70;
  isolation: isolate;
  overflow: hidden;
  padding: 12px 26px;
  border: none;
  border-radius: 999px;
  cursor: pointer;
  font-family: var(--font-body);
  font-weight: 500;
  font-size: 0.82rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--black);
  background: linear-gradient(
    140deg,
    rgba(120, 200, 255, 0.32),
    rgba(51, 187, 239, 0.18)
  );
  text-shadow: 0 1px 6px rgba(255, 255, 255, 0.5);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.35s ease 0.25s;
}

.detail.open .detail-back {
  opacity: 1;
  pointer-events: auto;
}

.detail-back-shine {
  position: absolute;
  inset: 0;
  z-index: 1;
  border-radius: 999px;
  pointer-events: none;
  box-shadow:
    0 4px 14px rgba(10, 16, 69, 0.14),
    inset 2.5px 2.5px 1px -2px rgba(255, 255, 255, 0.95),
    inset -2.5px -2.5px 1px -2px rgba(255, 255, 255, 0.8),
    inset 0 0 8px 5px rgba(255, 255, 255, 0.14);
}

.detail-back-label { position: relative; z-index: 2; }

/* --- while the detail is open, the page recedes --- */
body.detail-open .content,
body.detail-open .top-bar {
  opacity: 0;
  pointer-events: none;
}

/* hero layers must not shine through the glass sheet
   (scroll-lock resets scrollY, which would revive them) */
body.detail-open .logo-fix,
body.detail-open .swirl-wrap,
body.detail-open .scroll-hint {
  opacity: 0 !important;
}

/* products page blurs out as about opens, blurs back in on return.
   Safe to keep as a CSS filter: the products content is static, so a
   resting blur(0) costs nothing per frame (unlike the animated about view).
   will-change promotes the page to its own layer at load — otherwise
   iOS performs that promotion mid-tap on the FIRST detail open, which
   was the one-time stutter (every later open reuses the layer). */
.content {
  filter: blur(0px);
  will-change: opacity;
  /* this is the RETURN transition (state classes coming off): after a
     detail/about view closes, the page glides back in long and soft */
  transition: opacity 1.2s cubic-bezier(0.22, 1, 0.36, 1), filter 0.4s ease;
}

/* while an overlay is OPENING the page steps aside briskly — the
   state-specific transition wins in that direction */
body.detail-open .content,
body.about-open .content {
  transition: opacity 0.4s ease, filter 0.4s ease;
}

/* scroll lock that keeps the page visually in place (shared by the
   product detail and the about view). On body — the element that
   scrolls — and geometry-neutral: no relayout, no scroll reset, no
   flash. The overlays contain their own overscroll so a rubber-band
   at their edge can't chain to the page behind. */
html.view-lock body { overflow-y: hidden; }

/* ============================================================
   About view — an in-page overlay that fades in over the
   products page; the dock stays on top and swaps the view.
   ============================================================ */

.about-view {
  position: fixed;
  inset: 0;
  z-index: 40; /* above the page, below the dock (50) */
  overflow: hidden;
  opacity: 0;
  pointer-events: none;
  /* the blur is driven from JS and cleared once open, so the animated
     glow inside doesn't get re-rasterized every frame */
  transition: opacity 0.4s ease, filter 0.4s ease;
}

.about-view[hidden] { display: none; }

.about-view.open {
  opacity: 1;
  pointer-events: auto;
  overflow-y: auto;
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
}

/* while about is open: the products page recedes, but the vivid
   gradient field shows through the transparent top of the view */
body.about-open .content,
body.about-open .logo-fix,
body.about-open .swirl-wrap,
body.about-open .scroll-hint {
  opacity: 0;
  pointer-events: none;
}

body.about-open .content { filter: blur(14px); }

/* ============================================================
   Responsive
   ============================================================ */

@media (max-width: 900px) {
  .product-list { grid-template-columns: repeat(2, 1fr); }
  .product img { height: clamp(200px, 28vh, 280px); }
  .review-list { grid-template-columns: 1fr; max-width: 520px; margin: 0 auto; }

  /* Two columns leave a blank beside Salt: the next cell (Tablets) is a
     full-width pane and wraps to its own row. Pull "5 в 1" up to sit
     next to Salt and re-sequence the rest so no gaps form. Scoped to
     the 2-col layout only — the 3-col desktop order is untouched. */
  .product-list > .product-cell:nth-child(8) { order: 1; } /* 5 в 1 → beside Salt */
  .product-list > .product-cell:nth-child(5) { order: 2; } /* Tablets (pane) */
  .product-list > .product-cell:nth-child(6) { order: 3; } /* Mango */
  .product-list > .product-cell:nth-child(7) { order: 4; } /* Ocean */
  .product-list > .product-cell:nth-child(9) { order: 5; } /* Bubble (pane) */
}

@media (max-width: 560px) {
  .logo-img { width: 74vw; }
  .swirl-wrap {
    width: 92vmin;
    height: 92vmin;
    margin: -46vmin 0 0 -46vmin;
  }
  .product-list {
    --row-gap: 5vh;
    grid-template-columns: repeat(2, 1fr);
    column-gap: 14px;
  }
  .product {
    padding: 22px 12px;
    border-radius: 20px;
  }
  .product img { height: clamp(150px, 24vh, 200px); }
  .scroll-stage { height: 320vh; }
  .top-bar { top: 16px; gap: 8px; }
  .glass-pill { padding: 10px 12px; }
  .dock-item { padding: 8px 14px; font-size: 0.72rem; }
  .lang-item { padding: 8px 12px; }
  .about-contacts { gap: 10px; }
  .contact-btn {
    flex: 1 1 42%;
    justify-content: center;
    padding: 13px 16px;
    font-size: 0.76rem;
  }
}

/* tighten the top bar so the dock + language switch fit narrow phones */
@media (max-width: 400px) {
  .top-bar { gap: 6px; }
  .glass-pill { padding: 9px 8px; }
  .dock-item {
    padding: 7px 10px;
    font-size: 0.68rem;
    letter-spacing: 0.1em;
  }
  .lang-item { padding: 7px 9px; letter-spacing: 0.06em; }
}

/* ============================================================
   Reduced motion
   ============================================================ */

@media (prefers-reduced-motion: reduce) {
  html, body { scroll-behavior: auto; }

  .logo-img,
  .swirl,
  .blob,
  .glow-blob,
  .product img,
  .scroll-hint svg {
    animation: none;
  }

  .reveal,
  .reveal::after,
  .top-bar,
  .dock-glow,
  .detail,
  .detail-slide,
  .detail-info,
  .detail-howto,
  .detail-back,
  .contact-btn,
  .content,
  .product img {
    transition: none;
  }

  /* no bloom under reduced motion — rectangles just appear */
  .detail-slide,
  .detail-info,
  .detail-howto {
    opacity: 1;
    transform: none;
  }
}
