/* ============================================================================
   Основание мини-аппа: палитра, фон, типографика, заставка.

   Общий файл для всех трёх экранов — «Коммуникации», «Мотивация», «Админка».
   Раньше у каждого экрана была своя палитра: доска жила на камне под холодным
   светом, пульт — на плоском тёмном сером, дашборд по банкам — на зелёном. Три
   разных приложения в одном окне, и переход между ними читался как переход в
   другой продукт.

   Значения светлоты выверены по пикселям отрендеренной страницы доски. OKLCH L
   не совпадает со шкалой sRGB: L 0.18 — почти чёрный, а не тёмно-серый.

   Токены объявлены на body, а не на :root: applyTheme() в app.js пишет палитру
   Telegram инлайном на <html>, а инлайновое свойство сильнее любого правила для
   того же элемента. Объявление уровнем ниже выигрывает для всего в <body>.
   ========================================================================== */

body {
  color-scheme: dark;

  --page:  oklch(0.150 0.009 248);
  --sheet: oklch(0.230 0.012 248);
  --raise: oklch(0.300 0.013 248);
  --line:  oklch(0.370 0.014 248);

  --tg-theme-bg-color: var(--sheet);
  --tg-theme-secondary-bg-color: oklch(0.130 0.008 248);
  --tg-theme-text-color: oklch(0.970 0.003 240);
  --tg-theme-hint-color: oklch(0.808 0.012 240);

  /* Акцент — холодный ледниковый голубой, только на главном действии,
     выделении и фокусе. Тёмная подпись на нём вместо белой: белый текст на
     светлом акценте даёт 3:1 и проваливает AA. */
  --accent: oklch(0.790 0.108 228);
  --on-accent: oklch(0.165 0.030 235);
  --tg-theme-button-color: var(--accent);
  --tg-theme-button-text-color: var(--on-accent);
  --tg-theme-link-color: oklch(0.830 0.095 230);

  /* Стеклянная плёнка. Светлая, потому что стекло не затемняет камень, а ловит
     на себя свет; тёмная заливка выглядела бы вырезанным отверстием. */
  --film-top: oklch(1 0 0 / .105);
  --film-bottom: oklch(1 0 0 / .030);
  --film-edge: oklch(1 0 0 / .155);
  --hair: oklch(1 0 0 / .062);
  --wash: oklch(1 0 0 / .045);
  --spec: radial-gradient(120% 88% at 0% 0%, oklch(1 0 0 / .075), transparent 58%);

  --glass: saturate(150%) blur(22px);
  --ease: cubic-bezier(.22, 1, .36, 1);

  /* Статусы приглушены: восемь пикселей насыщенного цвета на тёмном камне
     выглядят индикатором аппаратуры, а не рабочим состоянием.

     Цвет привязан к порядковому номеру статуса, поэтому палитра выстроена под
     фактический порядок ленты: 0 Новое, 1 В работе, 2 Согласование,
     3 Подготовка коммуникаций, 4 Опубликовано, 5 Завершено, 6 Отложено,
     7 Отменено. Два конечных состояния рядом и оба зелёные — «завершено»
     спокойнее «опубликовано»; отложенное обесцвечено, чтобы не спорить за
     внимание с работой в процессе; красный остаётся только за отменой. */
  --s0: oklch(0.760 0.085 245);
  --s1: oklch(0.805 0.095 78);
  --s2: oklch(0.755 0.085 310);
  --s3: oklch(0.785 0.075 198);
  --s4: oklch(0.800 0.095 152);
  --s5: oklch(0.755 0.070 170);
  --s6: oklch(0.715 0.014 250);
  --s7: oklch(0.715 0.105 25);

  --a0: oklch(0.790 0.085 245);
  --a1: oklch(0.775 0.095 25);
  --a2: oklch(0.800 0.085 152);
  --a3: oklch(0.820 0.085 78);
  --a4: oklch(0.785 0.085 310);
  --a5: oklch(0.800 0.070 198);

  /* Смысловая шкала слоёв — никаких случайных 999. */
  --z-sticky: 20;
  --z-fab: 30;
  --z-backdrop: 40;
  --z-modal: 50;
  --z-pop: 55;
  --z-toast: 60;
  --z-gate: 70;
}

@media (prefers-color-scheme: light) {
  body {
    color-scheme: light;

    --page:  oklch(0.972 0.006 248);
    --sheet: oklch(1 0 0);
    --raise: oklch(0.956 0.007 248);
    --line:  oklch(0.893 0.009 248);

    --tg-theme-secondary-bg-color: oklch(0.960 0.006 248);
    --tg-theme-text-color: oklch(0.210 0.013 248);
    /* Замерено по пикселям на подсвеченных участках камня, а не на чистом
       листе: описание задачи лежит на градиенте, и 0.470 давало там 4.19. */
    --tg-theme-hint-color: oklch(0.448 0.017 248);

    --accent: oklch(0.520 0.140 235);
    --on-accent: oklch(1 0 0);
    --tg-theme-link-color: oklch(0.500 0.135 235);

    --film-top: oklch(1 0 0 / .88);
    --film-bottom: oklch(1 0 0 / .66);
    --film-edge: oklch(1 0 0 / .95);
    --hair: oklch(0.45 0.02 248 / .13);
    --wash: oklch(0.45 0.02 248 / .045);
    --spec: radial-gradient(120% 88% at 0% 0%, oklch(1 0 0 / .5), transparent 58%);

    --s0: oklch(0.545 0.135 245);
    --s1: oklch(0.620 0.125 68);
    --s2: oklch(0.540 0.145 310);
    --s3: oklch(0.565 0.090 198);
    --s4: oklch(0.575 0.120 152);
    --s5: oklch(0.540 0.085 170);
    --s6: oklch(0.600 0.016 250);
    --s7: oklch(0.555 0.150 25);

    /* Темнее статусов: подпись в аватаре — текст 9.5px на собственной
       тонированной плашке, ему нужны 4.5:1, а не 3:1 как точке. */
    --a0: oklch(0.435 0.145 245);
    --a1: oklch(0.440 0.155 25);
    --a2: oklch(0.430 0.120 152);
    --a3: oklch(0.445 0.115 68);
    --a4: oklch(0.425 0.155 310);
    --a5: oklch(0.430 0.095 198);
  }
}

/* ==================================================================== база */

* { box-sizing: border-box; }

/* Класс с display (как .gate) перебивает UA-правило атрибута hidden, и
   переключение hidden из JS молча перестало бы работать. */
[hidden] { display: none !important; }

html, body {
  margin: 0;
  padding: 0;
  min-height: 100%;
  color: var(--tg-theme-text-color);
  font: 14.5px/1.5 -apple-system, BlinkMacSystemFont, "Segoe UI Variable Text",
    "Segoe UI", Roboto, sans-serif;
  overscroll-behavior-y: contain;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

button, input, textarea { font: inherit; color: inherit; }

/* Полоса прокрутки документа берёт схему с корня, а не с body. */
html { background: var(--page); color-scheme: dark; background-color: transparent; }
@media (prefers-color-scheme: light) { html { color-scheme: light; } }
body { background-color: transparent; }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: .01ms !important; transition: none !important; }
}

/* Фон под открытой карточкой не должен ездить: прокрутка колесом уводила доску,
   пока модалка стояла на месте, и было непонятно, что вообще двигается.
   Позиция запоминается в JS и возвращается при закрытии. */
html.is-locked, html.is-locked body { overflow: hidden; }
html.is-locked body { position: fixed; width: 100%; }

/* ================================================================== камень */

/* Свет на фиксированном псевдоэлементе, а не на body с
   background-attachment: fixed — тот перерисовывается на каждом кадре
   прокрутки. Центры вынесены за правый край: текст стоит слева, и подсветка
   под ним уронила бы приглушённые подписи ниже 4.5:1. */
body::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: -2;
  pointer-events: none;
  background:
    radial-gradient(86% 68% at 102% -10%, oklch(0.515 0.088 228 / .74), transparent 66%),
    radial-gradient(74% 60% at 104% 104%, oklch(0.425 0.092 288 / .72), transparent 68%),
    radial-gradient(62% 46% at -10% 94%,  oklch(0.330 0.050 262 / .55), transparent 70%),
    linear-gradient(172deg, oklch(0.268 0.017 244), oklch(0.152 0.009 250) 80%);
}

@media (prefers-color-scheme: light) {
  body::before {
    background:
      radial-gradient(86% 68% at 102% -10%, oklch(0.870 0.062 228 / .85), transparent 66%),
      radial-gradient(74% 60% at 104% 104%, oklch(0.895 0.050 288 / .75), transparent 68%),
      radial-gradient(62% 46% at -10% 94%,  oklch(0.962 0.020 262 / .55), transparent 70%),
      linear-gradient(172deg, oklch(1 0 0), oklch(0.948 0.010 246) 78%);
  }
}

/* Зерно против полос на градиенте. Статично, после первой отрисовки не стоит
   ни кадра; его задача — быть незаметным. */
body::after {
  content: "";
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  opacity: .14;
  mix-blend-mode: overlay;
  background-image: 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='.9' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='200' height='200' filter='url(%23n)' opacity='.42'/%3E%3C/svg%3E");
  background-size: 200px 200px;
}

@media (prefers-color-scheme: light) {
  body::after { opacity: .10; mix-blend-mode: multiply; }
}

/* ================================================================ заставка */

.gate {
  position: fixed;
  inset: 0;
  display: grid;
  place-content: center;
  justify-items: center;
  gap: 16px;
  z-index: var(--z-gate);
}

.gate__spinner {
  width: 26px; height: 26px;
  border: 2.5px solid var(--hair);
  border-top-color: var(--accent);
  border-radius: 50%;
  animation: spin .8s linear infinite;
}

.gate--error .gate__spinner { display: none; }
.gate__text { margin: 0; padding: 0 32px; color: var(--tg-theme-hint-color); text-align: center; }

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

/* Высоту сообщает клиент Telegram: 100vh в его вебвью больше видимой области —
   сверху полоса клиента, снизу область жеста. JS кладёт реальное значение в
   --app-height, запасной вариант нужен до первого ответа клиента. */
.app { min-height: var(--app-height, 100vh); }

