/* ШАПКА САЙТУ — ОДНА НА ВСІ ТРИ СТОРІНКИ.

   Її не було: кожна сторінка везла свою копію правил і свій набір посилань, і
   вони, звісно, розійшлися. На головній марка була 23 пікселі, посилання троє
   й залита кнопка; на `about` — 19 пікселів і одне посилання `privacy`; на
   `privacy` — 19 і одне `about`. Тобто з підсторінок не було як ані
   повернутися до другої підсторінки, ані завантажити застосунок.

   Це та сама пастка, якою закінчується `CLAUDE.md`: одне значення збирається в
   одному місці. Тут воно вперше з'явилося на вебі — і одразу з трьома
   розбіжностями. Тому файл спільний, а не «однакові стилі, тільки скопіювати
   уважніше»: копії розходяться завжди, питання лише коли.

   Змінні (`--paper`, `--ink`, `--hair`) лишаються в самих сторінках: вони там
   і так однакові до символу, а тягнути сюди ще й тему означало б забрати в
   `index.html` можливість жити без цього файла. */

#top {
  position: sticky;
  top: 0;
  z-index: 4;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 18px 22px;
  padding-top: max(18px, env(safe-area-inset-top));
}

/* ВІД'ЄМНИЙ ВІДСТУП ТІЛЬКИ НА ГОЛОВНІЙ. Він віднімає власну висоту шапки з
   потоку — без цього герой поїхав би вниз на її висоту й перестав бути на весь
   екран. На текстових сторінках героя немає, і такий відступ підсунув би
   заголовок під марку. */
#land #top {
  margin-bottom: -72px;
}

#top a {
  color: var(--ink);
  text-decoration: none;
  font-size: 14px;
}

#top .logo {
  font-weight: 800;
  /* Більший за 19: марка мусить важити стільки ж, скільки залита кнопка на
     тому самому рядку, інакше вона читається як підпис до неї. Раніше 23 було
     лише на головній, а на текстових сторінках 19 — тобто та сама марка мала
     дві ваги. */
  font-size: 23px;
  letter-spacing: 0.10em;
  text-transform: uppercase;
}

#top .nav {
  display: flex;
  align-items: center;
  gap: 18px;
}

#top a.link {
  padding-bottom: 3px;
  border-bottom: 1px solid var(--hair);
}

/* АДРЕСИ БЕЗ `.html`, І ЦЕ НЕ СМАК.

   Cloudflare Workers Assets віддає на `/about.html` перенаправлення 307 на
   `/about` — тобто кожен клік по навігації коштував зайвий похід у мережу, і
   так на всіх трьох сторінках. Перевірено на живому сервері вже після
   розгортання: `/about.html` → HTTP 307, `/about` → 200.

   Канонічна адреса тут та, яку віддає сервер, а не та, як зветься файл. */

/* ПОСИЛАННЯ НА СЕБЕ САМЕ не підкреслюємо: воно нікуди не веде, і волосінь під
   ним обіцяла б дію. Ставиться атрибутом `aria-current` — тим самим, який
   читач з екрана й так оголошує. */
#top a.link[aria-current='page'] {
  border-bottom-color: transparent;
  color: var(--soft);
}

#top a.get {
  background: var(--ink);
  color: var(--paper);
  border: 1px solid var(--ink);
  padding: 9px 16px;
  font-size: 13px;
}

/* ШАПКА ПРОЗОРА, БЕЗ РОЗМИТТЯ.

   Тут стояв `backdrop-filter: blur(7px)` із маскою й переливом паперу —
   те саме, що `TopBlur` у застосунку. Рішення власника: прибрати, лишити
   просто прозору.

   Цікаво, що запасний шлях це вже й описував: нижче був `@supports not
   (mask-image: ...)` з коментарем «там краще лишити шапку просто прозорою».
   Тепер це не запасний шлях, а єдиний, тож і сам `@supports` пішов —
   ховати більше нічого. */


@media (max-width: 420px) {
  #top {
    padding-left: 18px;
    padding-right: 18px;
    gap: 10px;
  }
  #top .nav {
    gap: 14px;
  }
  #top .logo {
    font-size: 20px;
  }
}

/* ЗЕРНО ПАПЕРУ — НА ВЕСЬ САЙТ, І ТЕ САМЕ, ЩО В ЗАСТОСУНКУ.

   Плитка `grain.png` зроблена тими самими числами, що `grainTile` у
   `grain.dart`: 160 пікселів, сіре, з тим самим зерном (`Random(7)`). Різниць
   дві, і обидві навмисні.

   ПЕРША: альфа винесена в CSS. У Flutter вона запечена в пікселі (11 із 255,
   канали премножені), і тайл важив 39.8 КБ. Тут альфа стала, тож її можна
   тримати властивістю, а картинку лишити сірою на чотирьох бітах — 13.0 КБ
   замість 39.8. Шістнадцять рівнів сірого при 4.3% непрозорості око не
   відрізняє від 256, а вага в цьому проєкті вже була приводом для догани
   (favicon на 391 КБ).

   ДРУГА: зерно тут НЕРУХОМЕ. У застосунку матриця зсувається 12 разів на
   секунду — це плівка, і воно того варте на живій сцені. Сайт же читають, а не
   дивляться; рухоме зерно під текстом заважає, і його довелося б вимикати за
   `prefers-reduced-motion`. Нерухоме не потребує ні того, ні JS.

   ПІД ГЕРОЄМ ЗЕРНО МАЛЮЄ САМЕ ЦЕЙ ШАР, а не Flutter: `ViewApp` свій вимикає
   (`GrainOverlay(grain: false)`), інакше папір під деревом був би вдвічі
   зернистіший за папір під текстом поруч. */
#grain {
  position: fixed;
  inset: 0;
  z-index: 9;
  pointer-events: none;
  background-image: url('/grain.png');
  background-repeat: repeat;
  /* 4.3% — та сама альфа 11/255, що в застосунку. */
  opacity: 0.043;
}

/* ПОВНИЙ ЗАСТОСУНОК У БРАУЗЕРІ малює своє зерно сам, і в нього є перемикач у
   налаштуваннях. Якби ми клали своє поверх, той перемикач перестав би щось
   означати: людина його гасить, а зерно лишається. */
body.running #grain {
  display: none;
}

/* У темній темі зерно мусить бути СВІТЛІШИМ за тло, а не темнішим: чорні
   крапки на майже чорному папері не видно взагалі, і шар просто з'їдав би
   контраст. Те саме робить застосунок, малюючи зерно поверх перевернутої
   палітри. */
@media (prefers-color-scheme: dark) {
  #grain {
    filter: invert(1);
    opacity: 0.055;
  }
}
