/*****************************************************************************
 *  Зерно на стёклах
 *
 *  Слой на каждой стеклянной плашке, не на всей странице. Фон и ореол остаются
 *  гладкими, зерно живёт только там, где есть стекло.
 *
 *  ПОЧЕМУ ::before, А НЕ ::after
 *
 *  Семь стеклянных классов – .panel, .step, .why, .doc, .rub, .post, .ecard –
 *  уже держат на ::after свои эффекты: затемнение у края таблицы, световое
 *  пятно под курсором, тонкие блики по кромке. Второй ::after тому же элементу
 *  не выдать. ::before свободен у всех, кроме .rub, поэтому зерно живёт там, а
 *  .rub получает его отдельной строкой в index.html, вписанной в свой ::before.
 *
 *  position:relative нужен, потому что не всякая плашка позиционирована, а без
 *  этого слой отсчитывался бы от ближайшего позиционированного предка и
 *  вылезал за края. Смещений не задаём, так что раскладку это не двигает.
 *
 *  БЕЗ РЕЖИМА НАЛОЖЕНИЯ, НАМЕРЕННО
 *
 *  Сначала стоял overlay, и зерна не было видно вообще. Overlay по построению
 *  сохраняет тёмное: на фоне яркостью около десяти из двухсот пятидесяти пяти
 *  он почти не меняет пиксель, сколько ни задирай плотность. На светлой теме
 *  сработало бы, на нашей нет. Обычное наложение светлого зерна поверх тёмного
 *  даёт ровно то, что нужно. Для справки: само зерно яркостью 187 и
 *  полупрозрачное, то есть до экрана доходит примерно половина плотности.
 *
 *  Шум рисует feTurbulence прямо здесь, картинки на диске нет. fractalNoise
 *  даёт ровную крупу без сгустков, stitchTiles сшивает края, иначе на стыках
 *  плиток проступала бы сетка. saturate 0 обесцвечивает: цветное зерно на
 *  синем ореоле отдавало бы в жёлтый.
 *****************************************************************************/
:root{
  /* Ключевая строка тут – feFuncA. Она делает прозрачность РОВНОЙ по всей
     плитке, slope 0 и intercept 1. Без неё прозрачность берётся из того же
     шума, и вместо плёнки выходит либо сплошной серый лист, если крупинки
     плотные, либо редкие яркие точки, то есть грязь, если разредить. Плёнка
     получается только когда крупинки покрывают всю поверхность, но каждая
     чуть-чуть.

     Раз слой сплошной, всю его силу задаёт прозрачность, и она мала. Выше 0.2
     стекло начинает светлеть заметнее, чем зернить. Прозрачность вшита прямо в
     картинку, атрибутом opacity у прямоугольника, а не задана слою: слой делит
     место с диагональю ниже, и общая opacity гасила бы заодно и её.

     feFuncR, G и B со slope 1.5 и intercept -0.4 растягивают шум по контрасту и
     опускают его середину. Растяжение даёт разброс, опускание держит среднюю
     яркость около тона самой плашки, иначе слой подсвечивал бы её целиком.

     baseFrequency 0.85 – размер крупинок, больше число даёт мельче.
     numOctaves 2 подмешивает вторую, более крупную волну: на одной волне крупа
     выходит однородной, как снег на телевизоре. Плитка 200 – шаг повтора. */
  --grain-size: 200px;
  --grain-img: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='200' height='200'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3CfeComponentTransfer%3E%3CfeFuncR type='linear' slope='1.5' intercept='-0.62'/%3E%3CfeFuncG type='linear' slope='1.5' intercept='-0.62'/%3E%3CfeFuncB type='linear' slope='1.5' intercept='-0.62'/%3E%3CfeFuncA type='linear' slope='0' intercept='1'/%3E%3C/feComponentTransfer%3E%3C/filter%3E%3Crect width='200' height='200' filter='url(%23n)' opacity='0.08'/%3E%3C/svg%3E");

  /* Та же плитка, но с прозрачностью, вшитой в саму картинку. Нужна там, где
     зерно лежит слоем фона внутри чужого ::before и потому берёт ЕГО
     прозрачность, а не --grain. Место одно, .rub на главной: его ::before стоит
     на 0.65, и обычная плитка выходила там впятеро сильнее нормы, плитка
     превращалась в серое полотно.
     0.12 подобрано так, чтобы 0.65 умноженные на него дали примерно 0.08.
     Меняете плотность зерна – пересчитайте и это число. */
  --grain-img-soft: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='200' height='200'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3CfeComponentTransfer%3E%3CfeFuncR type='linear' slope='1.5' intercept='-0.62'/%3E%3CfeFuncG type='linear' slope='1.5' intercept='-0.62'/%3E%3CfeFuncB type='linear' slope='1.5' intercept='-0.62'/%3E%3CfeFuncA type='linear' slope='0' intercept='1'/%3E%3C/feComponentTransfer%3E%3C/filter%3E%3Crect width='200' height='200' filter='url(%23n)' opacity='0.12'/%3E%3C/svg%3E");

  /* Подсветка правого нижнего угла. Левый верхний не трогаем вовсе: там своё
     свечение, его даёт базовый градиент стекла, linear-gradient(157deg, …), он
     начинается с самого светлого как раз в том углу. Получается два свечения
     навстречу друг другу, а середина плашки остаётся самой тёмной.

     Градиент радиальный, а не линейный: линейный делил плашку прямой полосой, и
     на широкой таблице это читалось швом поперёк.

     Круг небольшой нарочно. Считать удобно не в процентах круга, а в том, как
     далеко свет достаёт по плашке: это размер круга, умноженный на процент
     последней остановки. Сейчас 110 на 0.34, то есть около трети стороны, и
     свечение остаётся у угла. Стояло 300 на 0.22, это две трети, и свет
     расползался почти на всю плашку.

     Чёрного тут нет намеренно, пробовали и убрали. Чернение левого верхнего
     угла отнимало у него прозрачность, ореол сквозь плашку переставал
     просвечивать, и заодно оно спорило с базовым свечением.

     Наложение «экран» тоже пробовали и убрали. Экран прибавляет каждому каналу
     одинаково, а зерно под ним теряет тёмную половину крупинок и превращается в
     сплошную светлую вуаль. На тёмном фоне такая ровная прибавка съедает разницу
     между каналами, то есть саму синеву, и ореол переставал просвечивать сквозь
     стекло. При обычном наложении у зерна есть и тёмная половина, средняя
     прибавка около нуля, и цвет за стеклом остаётся виден. */
  --glass-diag: radial-gradient(110% 110% at 100% 100%,
      rgba(255,255,255,.16) 0%,
      rgba(255,255,255,0) 34%);
}

/* isolation нужен из-за z-index:-1 у слоя ниже. Отрицательный номер уводит слой
   под содержимое, но остаться над фоном самой плашки он может только внутри её
   собственного контекста наложения. На настольной машине его создаёт сам
   backdrop-filter, а на телефоне размытия нет вовсе, см. правило в конце файла,
   и там слой провалился бы за фон у всех плашек разом. isolate даёт контекст
   независимо от размытия, поэтому он и стоит без всяких условий.
   Всплывающие меню это не запирает: календарное и подсказки добавляются в body,
   то есть живут вне плашек. */
.glass{ position: relative; isolation: isolate; }

/* Зерно и диагональ живут на одном слое двумя фонами. Прозрачность слоя при
   этом единица, а сила зерна вшита в саму его картинку: иначе общая opacity
   гасила бы и диагональ, а поднять её обратно выше единицы уже нельзя.

   Наложения на слое нет намеренно. Оно действует на слой целиком, разделить
   его между зерном и диагональю нельзя, а «экран» на зерне обесцвечивает всё,
   что под стеклом. Подробности в комментарии к --glass-diag. */
.glass::before{
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;   /* повторяет скругление плашки, иначе слой торчит углами */
  pointer-events: none;     /* обязательно: слой накрывает плашку целиком */
  z-index: -1;              /* под текст, но над фоном плашки: иначе тёмный угол ложится на буквы */
  background-image: var(--grain-img), var(--glass-diag);
  background-size: var(--grain-size) var(--grain-size), auto;
}

/* Печать: зерно ушло бы в тонер серой заливкой. */
@media print{
  .glass::before{ display: none; }
}

/* ── телефон: стекло без размытия фона ───────────────────────────────────
   Самое дорогое, что есть на сайте для телефона, это backdrop-filter. Он
   обязан заново снять фон под элементом и размыть его при каждом изменении
   того, что под ним, а под шапкой при прокрутке фон меняется каждый кадр.
   Шапка липкая, панель закреплена, карточек на экране бывает полтора десятка,
   и каждая размывает свой кусок фона отдельно.

   При этом отдавать за него почти нечего. Под плашками у нас лежит не текст и
   не картинка, а ровная аврора из aurora.css, а размытие ровного пятна даёт то
   же ровное пятно. Это уже проверено на карточках базы знаний и событий, где
   размытие сняли поимённо и разницы никто не заметил. Здесь то же самое,
   только разом и для всех.

   КАК ЭТО РАБОТАЕТ

   Размытия выписаны по страницам, в их собственных <style>, и перебить их
   отсюда нельзя: инлайновые стили идут после подключённых файлов и при равном
   весе выигрывают. Поэтому правила не перебиваются, а читают переменную:
   в каждом объявлении стоит var(--bdf, ...) со своим прежним значением
   в запасных. Пока переменной нет, всё как было, а объявить её достаточно
   один раз и в одном месте. Тот же приём применён к стопу градиента у пятен
   фона, --bstop в aurora.css.

   Новое размытие, если такое появится, тоже стоит писать через --bdf, иначе
   оно останется единственным на странице, которое на телефоне платит за себя.

   ПОЧЕМУ УСЛОВИЕ ТОЛЬКО ПРО ПАЛЕЦ

   Не про ширину. Причина запрета чисто скоростная, и суженное окно на
   настольной машине под неё не попадает: там стекло остаётся стеклом. Ровно
   это уже выяснили на плашках с темой в базе знаний, где условие по ширине
   гасило подсветку на узком окне.

   ЗАЛИВКА

   Без размытия плашка выглядит тоньше: вместе с blur уходит и saturate, а он
   приподнимал фон под стеклом. Возмещаем заливкой, с 0.06 до 0.08. Это одно
   число, и если на глаз выйдет слишком светло, править надо здесь. Выше 0.1
   заходить не стоит, дальше начинается молочная плашка вместо стекла.

   ТЕНЬ

   Тени плашек подбирались на почти чёрной странице, где их просто не было
   видно. На телефоне страница теперь тёмно-синяя, см. aurora.css, и всё, что
   пряталось в черноте, вышло наружу: под каждой плашкой появилось заметное
   чёрное пятно, особенно под плитками «С чего начать», у них тень самая
   тяжёлая.

   Дело не в самой тени, а в том, что её считали от другого фона. Возвращаем
   прежний вес по числам: у сплошной тени видимая сила в тени примерно
   шестьдесят процентов от заявленной, на старом фоне она отнимала около
   четырёх единиц яркости из 255, и при 0.3 на новом фоне отнимает столько же.
   Было 0.5 у стекла и 0.42 у плиток, на телефоне обе сходятся в одно значение.

   Правило то же, что у размытия: значение читается из --sh, а своё прежнее
   каждая тень держит в запасных. Внутренние блики не трогаем, они лежат поверх
   заливки и от цвета страницы не зависят. Всплывающие окна и наведение тоже:
   первые обязаны отрываться от страницы, вторых на пальце не бывает.

   Второе число, --sh-edge, это не тень. У карточек разборов, плиток рубрик и
   плашек «О проекте» под низом лежит торец, узкая полоса цвета страницы: она
   изображает просвет между сложенными листами, отсюда и стопка. Цвет у неё был
   подобран под прежний фон, rgba(9,12,18,.85), и на синей странице этот торец
   стал единственной по-настоящему чёрной полосой на экране. Значение здесь
   взято от нового фона и держит ту же разницу с ним, что держало со старым.

   ШАПКА ОТДЕЛЬНО

   Карточка стоит НА фоне, и сквозь неё просвечивает ровная аврора, там терять
   нечего. Шапка липкая, она едет ПОВЕРХ текста, и сквозь её семьдесят два
   процента при прокрутке лезли чужие строки. На большом экране их растирал
   blur, а здесь растирать нечем, и буквы оставались резкими. Тот же случай, что
   у выдвижного ящика в rail.css, только ящик непрозрачен на всём узком экране,
   а шапка только на пальце: на суженном окне ПК размытие работает и шапка
   остаётся стеклянной.

   Цвет тот же самый, из серебристой доводки в конце каждой страницы, где стоит
   .topbar{background:rgba(19,22,30,.72)}, просто без прозрачности. Поменяют тон
   там, менять надо и здесь.

   СВЕТ У НИЖНЕЙ КРОМКИ. ПОПРОБОВАЛИ ЧЕТЫРЬМЯ СПОСОБАМИ И ОТКАЗАЛИСЬ

   Задумка была такая: подсказка «внизу ещё есть страница». Белый свет у нижнего
   края ЭКРАНА, пока плашка через него проходит, и уходит вместе с ней. Ниже все
   четыре попытки и чем каждая кончилась, чтобы никто не пошёл по кругу заново.

   1. Слой во всю ширину экрана, на body::after. Его приходится класть поверх
   содержимого, иначе закрывает .app, а сверху он красит всё подряд, и пустой фон,
   и нижнюю строку текста.

   2. Обычным фоном у самой плашки. Фон рисуется от её коробки, а у высокой
   плашки нижняя кромка за краем экрана, и на экране нет ровно ничего.

   3. background-attachment:fixed у слоя фона. Выглядит правильно, кода мало, но
   на iPhone не поддерживается вовсе, а на остальных заставляет плашку
   перерисовываться на каждом кадре прокрутки. На телефоне прокрутка спотыкается,
   это видно глазом.

   4. Липкий элемент внутри плашки, <i class="glass-foot"> последним ребёнком.
   Работает везде, композитор считает его сам, прокрутка чистая. Ломается на
   другом: элемент стоит в потоке, то есть внутри набивки плашки, и когда конец
   плашки доходит до экрана, свет садится не на кромку плашки, а на край текста.
   Ниже остаётся тёмная полоса в набивку, и свет выглядит обрезанным по прямой.
   Ровный край тут стоил бы overflow:hidden на всех плашках, а у них свои слои
   поверх границ, вроде подсветки кромки у карточек разборов.

   Общий вывод. Свет у нижней кромки требует, чтобы у плашки совпали три вещи
   сразу: система координат экрана, отрисовка внутри плашки и край ровно по её
   границе. Пока это несовместимо без обрезки содержимого, оно того не стоит.
   Угловой свет и блик по верхней грани, которые у плашек есть, работают потому,
   что идут ПО краю формы, а не поперёк неё. */
@media (pointer: coarse){
  /* Двойной :root не описка. Страница объявляет свой --glass ниже по документу,
     и при равном весе выигрывает она. Второй :root добавляет вес, и правило
     перестаёт зависеть от порядка подключения. Так же сделано с .rail в
     rail.css, там причина та же. */
  :root:root{
    --bdf: none;
    --glass: rgba(205,215,233,.08);
    --sh: rgba(0,0,0,.3);
    --sh-edge: rgba(14,18,27,.85);
  }
  /* И по той же причине :root перед .topbar: своё правило страница объявляет
     ниже по документу. */
  :root .topbar{ background: rgb(19,22,30); }
}
