/* ПЕСОК v2 — CSS-кусок к bg2.js. Подключать ПОСЛЕ style.css.
   В основной странице заменяет правило .sand-gap (сам блок .sand-gap из разметки убрать). */

:root {
  --sand-lead: 5svh;      /* фронт идёт на столько впереди стыка секций — рваная кромка не режет заголовок следующей секции.
                             Должен быть меньше нижнего отступа секции, иначе фронт съест её последний текст.
                             15.09: 8svh → 5svh — хвост зерна укорочен до ~50 px, провалы между секциями сокращены */
  --sand-tile: 480px;     /* ширина плитки зернистой кромки текста */
}

/* hold (data-sand-text="hold"): bg2.js оборачивает секцию. Обёртка заходит на последний экран
   предыдущей секции, секция липнет к верху, распорка в экран держит её, пока фронт идёт снизу вверх. */
.sand-hold { position: relative; margin-top: calc(-100svh - var(--sand-lead)); pointer-events: none; }
.sand-hold > .sand-hold__sec { position: sticky; top: 0; pointer-events: none; }
.sand-hold .sand-part { pointer-events: auto; }        /* тапы — только по видимым кускам, остальное проходит к секции выше */
.sand-hold .sand-part--inert { pointer-events: none; } /* кусок ещё под песком */
.sand-hold__spacer { height: 100svh; }

/* Кромка текста приколотой секции — ОДНА статичная маска на обёртке. Фронт всегда на 100svh (+сдвиг) ниже
   верха обёртки, поэтому маску не надо двигать: её двигает сам скролл, перерисовки нет.
   (Первая версия двигала маску на каждом куске каждый кадр — 95% кадра 33–50 мс при CPU ×4.)
   Класс --live ставит bg2.js только пока кромка на экране: под маской стекло не размывает сцену. */
.sand-hold--live {
  /* + зазор: текст приколотой секции открывается ниже рваной кромки и падающих зёрен (контроль 15.09: заголовок «съеден зерном») */
  --sand-edge: calc(100svh + var(--sand-shift, 0px) + var(--sand-hold-gap, 0px));
  -webkit-mask-image: linear-gradient(transparent calc(var(--sand-edge) + var(--sand-bh) - 2px), #000 0), var(--sand-band-in);
          mask-image: linear-gradient(transparent calc(var(--sand-edge) + var(--sand-bh) - 2px), #000 0), var(--sand-band-in);
  -webkit-mask-size: 100% 100%, var(--sand-tile) calc(var(--sand-bh) * 2);
          mask-size: 100% 100%, var(--sand-tile) calc(var(--sand-bh) * 2);
  -webkit-mask-repeat: no-repeat, repeat-x;           mask-repeat: no-repeat, repeat-x;
  -webkit-mask-position: 0 0, 0 calc(var(--sand-edge) - var(--sand-bh));
          mask-position: 0 0, 0 calc(var(--sand-edge) - var(--sand-bh));
  -webkit-mask-composite: source-over;                 mask-composite: add;
}
/* data-sand-text-edge="clip": текст не рассыпается, а ровно закрывается кромкой с мягкими 8 px */
.sand-hold--live.sand-hold--clip {
  -webkit-mask-image: linear-gradient(transparent calc(var(--sand-edge) - var(--sand-soft)), #000 calc(var(--sand-edge) + var(--sand-soft)));
          mask-image: linear-gradient(transparent calc(var(--sand-edge) - var(--sand-soft)), #000 calc(var(--sand-edge) + var(--sand-soft)));
  -webkit-mask-size: 100% 100%; mask-size: 100% 100%;
  -webkit-mask-repeat: no-repeat; mask-repeat: no-repeat;
  -webkit-mask-position: 0 0; mask-position: 0 0;
}
:root { --sand-soft: 4px; }
.sand-part--in-clip {
  -webkit-mask-image: linear-gradient(transparent calc(var(--sand-o) - var(--sand-soft)), #000 calc(var(--sand-o) + var(--sand-soft)));
          mask-image: linear-gradient(transparent calc(var(--sand-o) - var(--sand-soft)), #000 calc(var(--sand-o) + var(--sand-soft)));
}
.sand-part--out-clip {
  -webkit-mask-image: linear-gradient(#000 calc(var(--sand-o) - var(--sand-soft)), transparent calc(var(--sand-o) + var(--sand-soft)));
          mask-image: linear-gradient(#000 calc(var(--sand-o) - var(--sand-soft)), transparent calc(var(--sand-o) + var(--sand-soft)));
}

/* flow: верхний отступ секции складывается с --sand-lead в пустую полосу фона под фронтом.
   16vh + 12svh давали ~30% экрана без текста — Nick просил без зазоров. 8vh + 8svh ≈ 18%, из них видна полоса падающих зёрен. */
.sand-on .chapter[data-sand]:not([data-sand-text="hold"]) { padding-top: 8vh; }

/* текст, через который идёт фронт: видимая часть + зернистая полоса высотой 2×--sand-bh */
.sand-part--in, .sand-part--out {
  -webkit-mask-repeat: no-repeat, repeat-x;           mask-repeat: no-repeat, repeat-x;
  -webkit-mask-size: 100% 100%, var(--sand-tile) calc(var(--sand-bh) * 2);
          mask-size: 100% 100%, var(--sand-tile) calc(var(--sand-bh) * 2);
  -webkit-mask-composite: source-over;                 mask-composite: add;
}
/* in — кусок следующей секции: виден НИЖЕ фронта */
/* сплошная часть заходит на полосу на 2 px — иначе на стыке слоёв маски от округления остаётся просвет-линия */
.sand-part--in {
  -webkit-mask-image: linear-gradient(transparent calc(var(--sand-o) + var(--sand-bh) - 2px), #000 0), var(--sand-band-in);
          mask-image: linear-gradient(transparent calc(var(--sand-o) + var(--sand-bh) - 2px), #000 0), var(--sand-band-in);
  -webkit-mask-position: 0 0, var(--sand-x) calc(var(--sand-o) - var(--sand-bh));
          mask-position: 0 0, var(--sand-x) calc(var(--sand-o) - var(--sand-bh));
}
/* out — кусок осыпающейся секции: виден ВЫШЕ фронта */
.sand-part--out {
  -webkit-mask-image: linear-gradient(#000 calc(var(--sand-o) - var(--sand-bh) + 2px), transparent 0), var(--sand-band-out);
          mask-image: linear-gradient(#000 calc(var(--sand-o) - var(--sand-bh) + 2px), transparent 0), var(--sand-band-out);
  -webkit-mask-position: 0 0, var(--sand-x) calc(var(--sand-o) - var(--sand-bh));
          mask-position: 0 0, var(--sand-x) calc(var(--sand-o) - var(--sand-bh));
}
.sand-part--hidden { visibility: hidden; }
/* короткий кусок приколотой секции ждёт, пока его верх откроется, и проявляется ЦЕЛИКОМ за .2 с.
   filter, а не opacity: opacity у .reveal пишет GSAP инлайном */
.sand-part { transition: filter .2s ease-out; }
.sand-part--wait { filter: opacity(0); pointer-events: none; transition: none; }

/* Провалы на стыках Б (контроль 15.09): нижний отступ уходящей секции + верхний у следующей давали 200–280 px пустого фона.
   Нижний отступ уходящей секции ≥ --sand-lead + мягкий край (42 + 4) — панель режется по самому фронту (bg2.js), иначе срежет её низ.
   Верхний у следующей: заголовок ≥ ~75 px ниже фронта (рваная кромка 34 + хвост зерна 40) */
.sand-on #pain { padding-bottom: 48px; }
.sand-on #price { padding-bottom: 48px; }
.sand-on #faq { padding-top: 48px; }

/* фон любой секции с data-bg рисует сцена. Свой фон у секции закрывает холст — песок ниже стыка
   обрезается ровной линией (поймано 14.09: style.css дал #why сплошной --c-deep по id, обычное правило
   его не перебивало). Поэтому !important — это не стиль, а условие работы сцены.
   Страница: не только при песке (.sand-on), но при любом WebGL — с «меньше движения» сцена тоже рисует фон
   (ровными стыками), а кадры первого экрана и «Хто веде» есть только в сцене. Без WebGL — свои заливки секций. */
html:not(.no-webgl) [data-bg] { background: none !important; }
