/* =========================================================================
   Univortex — стили сайта.

   Правило первое: никаких «магических» чисел в правилах ниже. Всё берётся
   из переменных этого блока. Нужно крупнее/просторнее/скруглённее —
   меняется одна переменная, а не двадцать мест.

   Правило второе: у всех интерактивных элементов одна геометрия. Высота,
   скругление, кегль и размер иконки заданы один раз в блоке «элементы
   управления»; дальше идут только различия в заливке и обводке.
   ========================================================================= */

:root {
  /* Общий масштаб. Единственная ручка размера на весь сайт.
     Проценты, а не пиксели: так уважается настройка шрифта в браузере. */
  font-size: 150%;

  /* --- шкала кеглей --- */
  --t-2xs:  .62rem;    /* мельче не бывает: только пометка о правке */
  --t-xs:   .72rem;
  --t-sm:   .82rem;
  --t-md:   .92rem;
  --t-base: 1rem;
  --t-lg:   1.08rem;
  --t-xl:   1.3rem;
  --t-2xl:  1.65rem;

  /* --- шкала отступов --- */
  --s-1: .2rem;
  --s-2: .35rem;
  --s-3: .55rem;
  --s-4: .8rem;
  --s-5: 1.2rem;
  --s-6: 1.8rem;
  --s-7: 2.6rem;

  /* --- скругления --- */
  --r-sm: .3rem;
  --r-md: .45rem;
  --r-lg: .7rem;
  --r-pill: 999px;

  /* --- размеры --- */
  --w-page: 44.1rem;   /* ширина колонки: блок выходит ровно 1020 точек */
  --card-h: 5.21rem;   /* высота блока в ленте — 125 точек */
  --card-pic: 5.6;     /* картинка в блоке: 700 на 125 */
  --ctl-h: 1.9rem;     /* высота любого элемента управления */
  --icon: 1.05rem;     /* сторона иконки внутри кнопки */
  --ava: 1.7rem;
  --ava-sm: 1.3rem;

  /* --- цвета, светлая тема ---
     Три уровня глубины. Шапка уходит назад и потому темнее страницы,
     блок поднят над ней и потому светлее. Тень довершает дело. */
  --chrome: #f6f7fb;       /* шапка — того же тона, что и блок */
  --bg: #eceef5;           /* страница — единственное, что темнее */
  --surface: #f6f7fb;      /* блок: статья, карточка, обсуждение */
  --raised: #eef0f7;       /* тот же блок под курсором */
  --border: #dfe3e9;
  --text: #15181d;
  --muted: #5d6673;
  --accent: #0a0f2f;   /* тёмно-синий из логотипа */
  --danger: #b3271c;

  /* Подсветка кликабельного. Сине-фиолетовый из логотипа: он же в мягком
     свечении под текстом — вместо подчёркивания. */
  --hl: #4733d0;
  --glow: rgba(71, 51, 208, .28);

  --dim: .55;          /* насколько приглушены второстепенные элементы */
  --dim-hover: 1;

  /* Вуаль поверх картинки под надписями. Одна на обе темы: она не
     подстраивается под тему, а задаёт тему тому, что под ней. */
  --veil: rgba(0, 0, 0, .2);
  --chip: rgba(16, 20, 40, .055);
  --chip-hi: rgba(16, 20, 40, .11);

  /* Тень у блока. Мягкая и в два слоя: ближний даёт край, дальний — объём. */
  --shade: 0 1px 2px rgba(16, 20, 40, .07), 0 3px 10px rgba(16, 20, 40, .05);
  --shade-hi: 0 2px 4px rgba(16, 20, 40, .1), 0 7px 20px rgba(16, 20, 40, .09);
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --chrome: #101216;
    --bg: #16181d;
    --surface: #1f232b;
    --raised: #272c35;
    --border: #2f343d;
    --chip: rgba(255, 255, 255, .07);
    --chip-hi: rgba(255, 255, 255, .14);
    --shade: 0 1px 2px rgba(0, 0, 0, .45), 0 3px 10px rgba(0, 0, 0, .3);
    --shade-hi: 0 2px 5px rgba(0, 0, 0, .55), 0 8px 22px rgba(0, 0, 0, .45);
    --text: #e8eaed;
    --muted: #a3aab6;
    --accent: #c6d2ff;
    --danger: #e8705f;
    --hl: #96a6ff;
    --glow: rgba(150, 166, 255, .35);
  }
}
:root[data-theme="dark"] {
  --chrome: #101216;
  --bg: #16181d;
  --surface: #1f232b;
  --raised: #272c35;
  --border: #2f343d;
  --chip: rgba(255, 255, 255, .07);
  --chip-hi: rgba(255, 255, 255, .14);
  --shade: 0 1px 2px rgba(0, 0, 0, .45), 0 3px 10px rgba(0, 0, 0, .3);
  --shade-hi: 0 2px 5px rgba(0, 0, 0, .55), 0 8px 22px rgba(0, 0, 0, .45);
  --text: #e8eaed;
  --muted: #a3aab6;
  --accent: #c6d2ff;
  --danger: #e8705f;
  --hl: #96a6ff;
  --glow: rgba(150, 166, 255, .35);
}

@media (max-width: 900px) { :root { font-size: 125%; } }
@media (max-width: 560px) { :root { font-size: 110%; } }

/* ============================ основа ============================ */

* { box-sizing: border-box; }

/* Атрибут hidden обязан прятать элемент. Без этого любой класс с display
   его перебивает, и скрытая кнопка остаётся на виду. */
[hidden] { display: none !important; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: "Cambria Math", Cambria, Georgia, "Times New Roman", serif;
  font-size: var(--t-base);
  line-height: 1.6;
}

/* Ссылки выглядят как обычный текст. Под курсором не подчёркиваются,
   а загораются цветом логотипа с мягким свечением: подчёркивание рубит
   строку пополам и спорит с подчёркнутым текстом внутри статьи. */
a { color: inherit; text-decoration: none; transition: color .12s, text-shadow .12s; }
a:hover { color: var(--hl); text-shadow: 0 0 .7em var(--glow); }

h1 { font-size: var(--t-2xl); line-height: 1.2; margin: var(--s-1) 0 var(--s-2); }
h2 { font-size: var(--t-xl); margin: var(--s-6) 0 var(--s-3); }
h3 { font-size: var(--t-lg); margin: 0 0 var(--s-1); }

.muted { color: var(--muted); font-size: var(--t-sm); }
.empty { color: var(--muted); padding: var(--s-6) 0; }

/* Сверху зазор минимальный: блок подходит вплотную к шапке, и на его
   место потом встанет картинка потока. */
main { max-width: var(--w-page); margin: 0 auto; padding: var(--s-2) var(--s-4) var(--s-7); }

/* ==================================================================
   ЭЛЕМЕНТЫ УПРАВЛЕНИЯ

   Одна геометрия на все кнопки сайта: та же высота, то же скругление,
   тот же кегль, тот же размер иконки. Ниже — только различия в заливке.
   ================================================================== */

.btn,
.act,
.act-word,
.tabs a,
.kebab > summary,
.menu-row button,
.tb button,
.tb select {
  display: inline-flex; align-items: center; justify-content: center;
  gap: var(--s-2);
  height: var(--ctl-h); min-width: var(--ctl-h);
  margin: 0; padding: 0 var(--s-3);
  border: 1px solid transparent; border-radius: var(--r-md);
  background: none; color: var(--muted);
  font: inherit; font-size: var(--t-sm); line-height: 1;
  white-space: nowrap; cursor: pointer;
  appearance: none; -webkit-appearance: none;
  transition: color .12s, background .12s, border-color .12s;
}

.btn:hover,
.act:hover,
.act-word:hover,
.tabs a:hover,
.kebab > summary:hover,
.menu-row button:hover,
.tb button:hover,
.tb select:hover {
  color: var(--hl); background: var(--raised);
}

/* Кнопки без подписи — круг, иконка по центру. Заливка еле заметная,
   но она есть: кнопку должно быть видно до того, как на неё навели. */
.act,
.kebab > summary,
.tb button.only-icon {
  width: var(--ctl-h); padding: 0;
}
.act,
.kebab > summary {
  border-radius: 50%; background: var(--chip);
}
.act:hover,
.kebab > summary:hover,
.kebab[open] > summary {
  background: var(--chip-hi);
}

/* Иконки во всех кнопках одного размера и одного веса линии. */
.btn svg,
.act svg,
.act-word svg,
.kebab > summary svg,
.kebab-body a svg, .kebab-body button svg,
.menu > summary svg,
.menu-body a svg, .menu-body button svg,
.tb button svg,
.talk svg {
  width: var(--icon); height: var(--icon);
  display: block; flex-shrink: 0;
  fill: none; stroke: currentColor;
  stroke-width: 1.75; stroke-linecap: round; stroke-linejoin: round;
}

/* Обводка там, где элемент стоит сам по себе, а не в плотном ряду. */
.tabs a,
.menu-row button { border-color: var(--border); }

.tabs a { border-radius: var(--r-pill); padding: 0 var(--s-4); }

/* Главная кнопка страницы. */
.btn {
  background: var(--accent); color: var(--bg); border-color: var(--accent);
  padding: 0 var(--s-5); font-size: var(--t-md);
}
.btn:hover { background: var(--accent); color: var(--bg); opacity: .9; }

/* Включённое состояние — одно на вкладки, переключатели и панель редактора. */
.tabs a.active,
.menu-row .on,
.tb button.on {
  background: var(--accent); border-color: var(--accent);
  color: var(--bg); font-weight: 700;
}

/* Кнопка уже совершённого действия: «вы читаете». Та же геометрия,
   но без заливки — звать больше некуда. */
.btn-quiet {
  display: inline-flex; align-items: center; justify-content: center;
  height: var(--ctl-h); padding: 0 var(--s-5);
  border: 1px solid var(--border); border-radius: var(--r-md);
  background: none; color: var(--muted);
  font: inherit; font-size: var(--t-md); line-height: 1; cursor: pointer;
  transition: color .12s, border-color .12s;
}
.btn-quiet:hover { color: var(--hl); border-color: var(--hl); background: var(--raised); }

/* Кнопка, после которой не отменишь: красная до нажатия, а не после. */
.btn-quiet.danger { color: var(--danger); border-color: var(--danger); }
.btn-quiet.danger:hover { color: var(--bg); background: var(--danger); border-color: var(--danger); }

.act-danger:hover { color: var(--danger); }

/* ============================ шапка ============================ */

header { border-bottom: 1px solid var(--border); background: var(--chrome); }

.bar {
  max-width: var(--w-page); margin: 0 auto;
  padding: var(--s-3) var(--s-4);
  display: flex; align-items: center; gap: var(--s-4);
}
.bar .spacer { flex: 1; }

.brand { display: inline-flex; align-items: center; flex-shrink: 0; }
.brand:hover { text-shadow: none; }
.brand img { display: block; height: var(--ava); width: auto; }
/* Логотип тёмно-синий и на тёмном фоне пропадает. brightness(0) делает его
   сплошным чёрным, invert(1) — белым; прозрачность сохраняется. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .brand img { filter: brightness(0) invert(1); }
}
:root[data-theme="dark"] .brand img { filter: brightness(0) invert(1); }

/* Поле поиска занимает всё свободное место между логотипом и меню. */
.search {
  flex: 1; min-width: 0; display: flex; align-items: center; gap: var(--s-1);
  height: var(--ctl-h); padding: 0 var(--s-1) 0 var(--s-3);
  border: 1px solid var(--border); border-radius: var(--r-pill);
  background: var(--bg);
}
.search input {
  flex: 1; min-width: 0;
  height: 100%; padding: 0; margin: 0;
  border: 0; background: none; color: var(--text);
  font: inherit; font-size: var(--t-sm);
}
.search input:focus { outline: none; }
.search input::placeholder { color: var(--muted); }
.search:focus-within { border-color: var(--muted); }
/* Кнопка внутри поля, а не поверх него: поле выше её на толщину
   обводки с обеих сторон. */
.search .act {
  flex-shrink: 0;
  height: calc(var(--ctl-h) - var(--s-2));
  width: calc(var(--ctl-h) - var(--s-2));
  border-radius: var(--r-pill);
}

@media (max-width: 560px) {
  /* На узком экране подпись пользователя важнее строки поиска. */
  .search { flex: 0 1 auto; }
  .search input { width: 4rem; }
}

.guest { display: flex; align-items: center; gap: var(--s-2); font-size: var(--t-md); }
.guest .sep { color: var(--muted); }

/* ======================= меню пользователя ======================= */

.menu { position: relative; }
.menu > summary {
  list-style: none; cursor: pointer; user-select: none;
  display: flex; align-items: center; gap: var(--s-2);
  height: var(--ctl-h); padding: 0 var(--s-2);
  border-radius: var(--r-pill); font-size: var(--t-md);
}
.menu > summary::-webkit-details-marker { display: none; }
.menu > summary:hover, .menu[open] > summary { background: var(--raised); color: var(--hl); }

.menu-body {
  position: absolute; right: 0; top: calc(100% + var(--s-2)); z-index: 20;
  min-width: 12rem; padding: var(--s-2);
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--r-lg); box-shadow: var(--shade-hi);
}
.menu-body a, .menu-body button {
  display: flex; align-items: center;
  width: 100%; height: var(--ctl-h); padding: 0 var(--s-3);
  gap: var(--s-3);
  border: 0; border-radius: var(--r-md);
  background: none; color: var(--text);
  font: inherit; font-size: var(--t-md); line-height: 1;
  cursor: pointer; white-space: nowrap;
}
.menu-body a:hover, .menu-body button:hover { background: var(--raised); color: var(--hl); text-shadow: none; }
.menu-body form { margin: 0; }

.menu-sep { height: 1px; background: var(--border); margin: var(--s-2) var(--s-1); }
.menu-label { padding: var(--s-1) var(--s-3); font-size: var(--t-xs); color: var(--muted); }
.menu-row { display: flex; gap: var(--s-1); padding: 0 var(--s-2) var(--s-1); }
.menu-row button { flex: 1; }

.ava { width: var(--ava); height: var(--ava); border-radius: 50%; object-fit: cover; display: block; flex-shrink: 0; }

/* ===================== меню на троеточии ===================== */

/* Жалоба и прочие редкие действия прячутся сюда, чтобы страница
   не пестрела восклицательными знаками. */
.kebab { position: relative; display: inline-flex; }
.kebab > summary { list-style: none; user-select: none; }
.kebab > summary::-webkit-details-marker { display: none; }
.kebab[open] > summary { color: var(--hl); background: var(--raised); }

.kebab-body {
  position: absolute; left: 0; top: calc(100% + var(--s-1)); z-index: 20;
  /* Ширина по содержимому: один пункт не должен растягивать панель. */
  width: max-content; max-width: 16rem; padding: var(--s-1);
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--r-md); box-shadow: var(--shade-hi);
}
.kebab-body a, .kebab-body button {
  display: flex; align-items: center;
  width: 100%; height: var(--ctl-h); padding: 0 var(--s-3);
  gap: var(--s-3);
  border: 0; border-radius: var(--r-sm);
  background: none; color: var(--text);
  font: inherit; font-size: var(--t-sm); line-height: 1;
  cursor: pointer; white-space: nowrap;
}
.kebab-body a:hover, .kebab-body button:hover { background: var(--raised); color: var(--hl); text-shadow: none; }
/* Корзина красная сразу, а не только под курсором: удаление
   не отменишь, и предупредить надо до нажатия. */
.kebab-body .danger svg { stroke: var(--danger); }
.kebab-body .danger:hover { color: var(--danger); }
.kebab-body form { margin: 0; }

/* ============================ вкладки ============================ */

.tabs { display: flex; gap: var(--s-2); margin: 0 0 var(--s-4); flex-wrap: wrap; }

/* ======================== карточка в ленте ======================== */

/* ============================= блок =============================

   Всё, что читается как отдельный предмет — статья, карточка в ленте,
   обсуждение, уведомление, — один и тот же блок: светлее страницы и
   с мягкой тенью. Разные правила на каждый случай развели бы винегрет.
   ================================================================= */

.block, .card, .notice {
  background: var(--surface);
  border-radius: var(--r-lg);
  box-shadow: var(--shade);
  margin-bottom: var(--s-3);
  transition: background .12s, box-shadow .12s;
}
.block { padding: var(--s-5); }

/* Высота блока задана жёстко, а не длиной заголовка: от неё считается
   форма картинки, и плавающая высота делала бы рамку в загрузчике
   обманом. Заголовок поэтому в одну строку, лишнее — многоточием. */
.card {
  display: flex; align-items: center; gap: var(--s-4);
  height: var(--card-h); padding: var(--s-4);
}
.card-main { min-width: 0; }

/* Картинка лежит под текстом в правой части блока и никогда его не
   закрывает. Размер её задан блоком, а не наоборот: высота блока целиком,
   ширина — отсюда и отношение сторон. Треть длины уходит наискосок в
   прозрачность, поэтому левого края у картинки не видно.

   Обрезка строгая: картинка с маской живёт отдельным слоем, и overflow
   такой слой не удерживает — блок рисовался шире соседних. */
.card.with-pic {
  position: relative; overflow: hidden;
  clip-path: inset(0 round var(--r-lg));
}
.card.with-pic .card-main {
  position: relative; z-index: 1;
  padding-right: calc(var(--card-h) * var(--card-pic) * .45);
}
.card-pic {
  position: absolute; right: 0; top: 0;
  height: 100%; width: auto; aspect-ratio: var(--card-pic);
  object-fit: cover;
  /* Угол посчитан по самой картинке, а не подобран: 144° — это линия от
     её нижнего левого угла к верхнему краю на четверти длины. Отсюда же
     и крайние доли: 20% — нижний левый угол, 80% — верхний правый. За
     первую черту растворение заходить не может, иначе левый край начнёт
     проступать; за вторую — иначе сквозь угол будет виден фон блока.
     Внутри этого окна прозрачность меняется с послаблением: ровное
     изменение глаз читает как резкую полосу.

     Числа держатся на том, что картинка 700 на 125. Поменяется --card-pic
     или --card-h — угол надо пересчитать. */
  --fade: linear-gradient(144deg,
    transparent 18%,
    rgba(0, 0, 0, .05) 32%,
    rgba(0, 0, 0, .22) 45%,
    rgba(0, 0, 0, .5) 58%,
    rgba(0, 0, 0, .8) 70%,
    #000 80%);
  -webkit-mask-image: var(--fade);
  mask-image: var(--fade);
  pointer-events: none;
}

/* Заголовок в одну строку: блок неизменной высоты, переносить некуда. */
.card-main h3 { overflow: hidden; }
.card-main h3 a {
  display: block; overflow: hidden;
  white-space: nowrap; text-overflow: ellipsis;
}

/* Блок, по которому можно щёлкнуть, под курсором всплывает. */
.card:hover, .notice:hover { background: var(--raised); box-shadow: var(--shade-hi); }

.talk {
  width: 3rem; flex-shrink: 0;
  display: flex; flex-direction: column; align-items: center; gap: var(--s-1);
  color: var(--muted);
}
.talk .n { font-size: var(--t-sm); font-variant-numeric: tabular-nums; }

/* ============================= статья ============================= */

article.body { margin: var(--s-5) 0 var(--s-4); font-size: var(--t-lg); }

/* Разметка статьи. Те же правила действуют и внутри редактора, чтобы
   написанное выглядело ровно так, как потом опубликуется. */
.rich p { margin: 0 0 .7em; }
.rich p:last-child { margin-bottom: 0; }
.rich ul, .rich ol { margin: 0 0 .7em; padding-left: 1.4em; }
.rich li { margin: 0 0 .25em; }
.rich a { color: var(--accent); text-decoration: underline; }
/* Картинка в тексте не вылезает за поля статьи и стоит по центру. */
.rich img {
  display: block; max-width: 100%; height: auto;
  margin: var(--s-5) auto; border-radius: var(--r-md);
}
.rich blockquote {
  margin: 0 0 .7em; padding-left: var(--s-4);
  border-left: 2px solid var(--border); color: var(--muted);
}

/* Классы, которые ставит панель редактора. Их же пропускает санитайзер. */
.ta-left { text-align: left; }
.ta-center { text-align: center; }
.ta-right { text-align: right; }

/* Размер текста — в rem, а не в em. В em вложенные куски перемножаются:
   «мелкий» внутри «крупного» давал бы обычный. В rem каждый кусок задаёт
   размер сам, независимо от того, во что он вложен. */
.txt-sm { font-size: .85rem; }
.txt-md { font-size: 1.08rem; }
.txt-lg { font-size: 1.4rem; }

/* Заголовок блока комментариев заведомо мельче заголовка статьи. */
.ctitle { font-size: var(--t-base); font-weight: 700; margin: 0; }

/* Заголовок обсуждений и выбор порядка в одной строке. */
.ctitle-row {
  display: flex; align-items: center; gap: var(--s-4);
  margin: var(--s-6) 0 var(--s-4);
}
.menu.sort > summary { color: var(--muted); font-size: var(--t-sm); }
/* Меню порядка стоит у левого края, поэтому и раскрывается вправо. */
.menu.sort .menu-body { right: auto; left: 0; }
.menu-body .on { color: var(--hl); font-weight: 700; }

/* Поле ответа с кружком слева — как и сам комментарий. Само поле —
   одна строка с чертой снизу: коробка во весь блок давила на глаза. */
.comment-write { display: flex; align-items: flex-start; gap: var(--s-3); }
.comment-write form { flex: 1; min-width: 0; }

#comment-box {
  padding: var(--s-2) 0; resize: none; overflow: hidden;
  border: 0; border-radius: 0; background: none;
  box-shadow: inset 0 -1px 0 var(--border);
}
#comment-box:focus { outline: none; box-shadow: inset 0 -2px 0 var(--hl); }

/* Кнопки появляются, когда есть что отправлять, и прижаты вправо. */
.comment-buttons {
  display: flex; align-items: center; justify-content: flex-end;
  gap: var(--s-3); margin: var(--s-3) 0 0;
}

/* Обсуждение: сам комментарий, ответы под ним и место для формы.
   Вложенность одна — глубже уезжало бы за край экрана. */
.thread { padding: var(--s-4); }

/* Строка комментария: кружок, текст, троеточие прижато вправо. */
.comment-row { display: flex; align-items: flex-start; gap: var(--s-3); }
.comment-main { flex: 1; min-width: 0; }
.comment-row > .kebab { margin-left: auto; flex-shrink: 0; }

.comment-head {
  display: flex; align-items: baseline; flex-wrap: wrap;
  gap: 0 var(--s-2); font-size: var(--t-sm);
}
.comment-head .who { font-weight: 700; }

.comment .body { white-space: pre-wrap; margin-top: var(--s-1); }

/* Ответы с отбивкой и тонкой чертой: видно, к чему они относятся. */
.replies { margin-left: var(--s-6); padding-left: var(--s-4); border-left: 1px solid var(--border); }
.comment.reply { padding: var(--s-3) 0 0; }
.reply .ava { width: var(--ava-sm); height: var(--ava-sm); font-size: var(--t-2xs); }
.reply-slot:not(:empty) { margin: var(--s-3) 0 var(--s-3) var(--s-6); }

/* Свернуть ветку. */
.fold { margin-left: var(--s-6); margin-top: var(--s-2); }
.fold svg { transform: rotate(180deg); transition: transform .15s; }
.fold.shut svg { transform: rotate(0); }

.actions { display: flex; align-items: center; gap: var(--s-1); margin: var(--s-2) 0 0; }
.actions form { margin: 0; display: inline-flex; }

/* Отказ формы. Молча отказывать нельзя: человек жмёт «Сохранить»
   и не понимает, почему ничего не произошло. */
.errorlist {
  list-style: none; margin: 0 0 var(--s-2); padding: 0;
  color: var(--danger); font-size: var(--t-sm);
}

/* ======================= выбор картинки =======================

   Родное поле браузера спрятано: оно выглядит везде по-своему и тащит
   за собой «Файл не выбран» и галочку размером с точку. Наружу выведены
   две обычные кнопки сайта.
   ============================================================== */

.pick { margin-bottom: var(--s-4); }
.pick-label { display: block; margin-bottom: var(--s-1); font-size: var(--t-sm); }
.pick-row { display: flex; align-items: center; gap: var(--s-3); flex-wrap: wrap; }
.pick-shot {
  height: 3rem; width: auto; max-width: 12rem; object-fit: cover;
  border-radius: var(--r-md); background: var(--bg);
}
.pick-shot.round { width: 3rem; border-radius: 50%; }

/* Просмотр статьи перед публикацией: та же карточка, что и на самой
   странице, только в окне. */
.dialog.preview {
  width: min(46rem, 100%);
  max-height: 86vh; overflow: auto;
  background: var(--bg);
}
.dialog.preview .block { margin: 0; }
.dialog.preview h1 { margin-top: 0; }

/* ----------------------- окно обрезки ----------------------- */

.shade {
  position: fixed; inset: 0; z-index: 60;
  display: flex; align-items: center; justify-content: center;
  padding: var(--s-5);
  background: rgba(8, 10, 18, .72);
}
.dialog {
  display: flex; flex-direction: column; gap: var(--s-4);
  max-width: min(44rem, 100%);
  padding: var(--s-4);
  background: var(--surface); border-radius: var(--r-lg);
  box-shadow: var(--shade-hi);
}
.dialog-row { display: flex; justify-content: flex-end; gap: var(--s-3); }
/* Окно, которое просто говорит фразу. Поля абзацев убираем: вместе с
   отступом самого окна они давали провал в две строки. Правило нарочно
   с отдельным классом — в окне просмотра статьи абзацы нужны как есть. */
.dialog.says p { margin: 0; }

.shot {
  position: relative; line-height: 0;
  touch-action: none; user-select: none;
}
.shot-img {
  display: block; max-width: 100%; max-height: 60vh;
  width: auto; height: auto;
  -webkit-user-drag: none;
}

/* Всё, что вне рамки, притушено. Одна тень наружу вместо четырёх
   накладок по сторонам. */
.frame {
  position: absolute; box-sizing: border-box;
  border: 1px solid rgba(255, 255, 255, .9);
  box-shadow: 0 0 0 9999px rgba(0, 0, 0, .55);
  cursor: move;
  /* Трети: по ним ровняют кадр. */
  background-image:
    linear-gradient(rgba(255, 255, 255, .35) 1px, transparent 1px),
    linear-gradient(90deg, rgba(255, 255, 255, .35) 1px, transparent 1px);
  background-size: 100% 33.333%, 33.333% 100%;
  background-position: 0 33.333%, 33.333% 0;
  background-repeat: repeat-y, repeat-x;
}

/* Кружок: ровно то, что потом увидят на месте аватара. Захваты по углам
   остаются — тянуть за дугу неудобно. */
.frame.round { border-radius: 50%; }

.grab {
  position: absolute; width: 1rem; height: 1rem;
  border: 3px solid #fff;
}
.grab.tl { left: -3px; top: -3px; border-right: 0; border-bottom: 0; cursor: nwse-resize; }
.grab.tr { right: -3px; top: -3px; border-left: 0; border-bottom: 0; cursor: nesw-resize; }
.grab.bl { left: -3px; bottom: -3px; border-right: 0; border-top: 0; cursor: nesw-resize; }
.grab.br { right: -3px; bottom: -3px; border-left: 0; border-top: 0; cursor: nwse-resize; }

/* Застава ушедшего: одна карточка посреди пустого экрана. */
.gate {
  min-height: 100vh;
  display: flex; align-items: center; justify-content: center;
}
.gate .block { margin: 0; text-align: center; }
.gate .publish-row { justify-content: center; margin-top: var(--s-5); }

/* Картинка статьи вверху страницы. Как и у потока: вплотную к шапке,
   сверху не скруглена. Обрезка та же, что и в ленте, — 3:1, поэтому
   показывается ровно выбранный кусок. */
/* Блок, у которого картинка во весь размер: поток и шапка статьи.
   Подходит вплотную к шапке сайта и сверху не скруглён. Отношение сторон
   у каждого своё — ровно то, что человек выбрал рамкой.

   Поверх картинки лежит затемняющая вуаль. Без неё задача неразрешима:
   белый текст пропадает на светлой картинке, тёмный — на тёмной, а какую
   картинку поставят, мы не знаем. Вуаль делает фон предсказуемым при
   любой, после чего текст всегда белый. */
.on-cover {
  margin-top: calc(var(--s-2) * -1);
  border-radius: 0 0 var(--r-lg) var(--r-lg);
  display: flex; flex-direction: column; justify-content: center;
  background-size: cover; background-position: center;
  color: #fff;
}
.flow-block.on-cover { aspect-ratio: 4; }
.head-block.on-cover { aspect-ratio: var(--card-pic); }

/* Тень по контуру, а не обводка: буквы остаются буквами. */
.on-cover h1,
.on-cover .muted,
.on-cover .flow-about {
  color: #fff;
  text-shadow: 0 1px 2px rgba(0, 0, 0, .75), 0 0 .8rem rgba(0, 0, 0, .55);
}
.flow-about { margin: var(--s-4) 0 0; }

/* Название потока слева, «Написать статью» — напротив него справа. */
.flow-head { display: flex; align-items: flex-start; gap: var(--s-4); }
.flow-id { min-width: 0; }
.flow-head h1 { margin: 0; }
.flow-head .muted { margin: var(--s-1) 0 0; }
.flow-head .actions { margin: 0 0 0 auto; flex-shrink: 0; }

/* Порядок разделов настроек задаётся здесь, а не разметкой: вид и
   уведомления сохраняются сами и потому лежат в своих формах, внутрь
   главной их не положить. display: contents распускает главную форму
   по столбцу, не трогая саму отправку. */
.settings { display: flex; flex-direction: column; }
.settings > .settings-main { display: contents; }
.s-profile { order: 1; }
.s-flow    { order: 2; }
.s-notify  { order: 3; }
.s-look    { order: 4; }
.s-login   { order: 5; }
.s-account { order: 6; }

/* Чей поток — слева, что сделать со статьёй — справа. */
.byline {
  display: flex; align-items: center; gap: var(--s-4);
  flex-wrap: wrap; margin-top: var(--s-5);
}
.byline-who { display: flex; align-items: center; gap: var(--s-3); min-width: 0; }
.byline-text { display: flex; flex-direction: column; min-width: 0; }
.byline-name { font-weight: 700; }
.byline-text .muted { font-size: var(--t-xs); }
.byline .actions { margin: 0; margin-left: auto; gap: var(--s-2); }

/* Нажатое состояние иконки: закладка поставлена, статья закреплена. */
.share .when-done svg { stroke: var(--hl); }

.act.on { color: var(--hl); }
.act.on svg { fill: currentColor; }

/* ========================= редактор статьи ========================= */

/* Панель: кнопки той же геометрии, что и везде, но без обводки —
   в плотном ряду рамки превратились бы в рябь. */
/* Панель пришита к верху: в длинной статье она уезжала вместе с текстом,
   и чтобы поставить картинку в конце, приходилось гонять страницу вверх
   за кнопкой и обратно вниз за местом. Ездит текст, инструмент стоит. */
.tb {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--s-1);
  padding: var(--s-1);
  border: 1px solid var(--border); border-bottom: 0;
  border-radius: var(--r-md) var(--r-md) 0 0;
  background: var(--surface);
  position: sticky; top: 0; z-index: 20;
}
.tb .sep {
  width: 1px; height: calc(var(--ctl-h) - var(--s-3));
  background: var(--border); margin: 0 var(--s-1);
}
.tb select {
  width: auto; border-color: var(--border); color: var(--text);
  padding: 0 var(--s-2);
}
.tb button.b { font-weight: 700; }
.tb button.i { font-style: italic; }
.tb button.u { text-decoration: underline; }
.tb button.strike { text-decoration: line-through; }

.editor {
  min-height: 16rem; padding: var(--s-3) var(--s-4);
  border: 1px solid var(--border); border-radius: 0 0 var(--r-md) var(--r-md);
  background: var(--bg); color: var(--text);
  /* Тот же кегль, что у опубликованной статьи: написанное должно выглядеть
     ровно так, как его потом увидят. */
  font-size: var(--t-lg); line-height: 1.6;
  overflow-wrap: break-word;
}
.editor:focus { outline: 2px solid var(--accent); outline-offset: -2px; }
/* Подсказка показывается, пока ничего не написано. :empty тут не годится:
   внутри всегда лежит хотя бы пустой абзац — на нём стоит курсор. */
.editor { position: relative; }
.editor.empty::before {
  content: attr(data-placeholder); color: var(--muted); pointer-events: none;
  position: absolute; top: var(--s-3); left: var(--s-4);
}
/* Картинка, выбранная щелчком. Браузер подсвечивает выделение сам, но на
   картинке это почти не видно — обводим. */
.editor img::selection { background: transparent; }

/* Строка ввода ссылки или картинки. Всплывает у курсора: картинка
   появится там же, и смотреть в два места не приходится. */
.tb-row {
  display: none; position: fixed; z-index: 30;
  gap: var(--s-2); padding: var(--s-2); align-items: center; flex-wrap: wrap;
  width: min(26rem, 90vw);
  border: 1px solid var(--border); border-radius: var(--r-md);
  background: var(--surface); box-shadow: var(--shadow-lg, 0 8px 24px rgba(0,0,0,.25));
}
.tb-row.open { display: flex; }
.tb-row input { flex: 1; height: var(--ctl-h); padding: 0 var(--s-3); font-size: var(--t-sm); }
/* Пока картинку проверяют, кнопка крутит колечко. Надпись не подменяем:
   «проверяю» — это объяснение, а колечко просто видно. */
.tb-row button.busy { color: transparent; position: relative; }
.tb-row button.busy::after {
  content: ''; position: absolute; inset: 0; margin: auto;
  width: 1em; height: 1em;
  /* Основа — цветом той надписи, которую колечко заменило: заметно
     ровно настолько же, насколько было видно слово. */
  border: 2px solid var(--muted); border-top-color: var(--accent);
  opacity: .7;
  border-radius: 50%;
  animation: spin .7s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }
/* Кому движение на экране мешает — колечко остаётся, но еле поворачивается. */
@media (prefers-reduced-motion: reduce) {
  .tb-row button.busy::after { animation-duration: 3s; }
}

/* Ошибка — второй строкой под полем. Пока её нет, места не занимает:
   без этого она съедала всю ширину и поле ввода сжималось в точку. */
.tb-row .tb-err { flex-basis: 100%; }
.tb-row .tb-err:empty { display: none; }
.publish-row { display: flex; align-items: center; gap: var(--s-4); }
/* Строка с галочкой: подпись справа от квадратика, а не над ним, — иначе
   непонятно, к чему галочка относится. */
.tick { display: flex; align-items: center; gap: var(--s-2); }
.tick label { margin: 0; font-size: var(--t-md); cursor: pointer; }
.draft-state { font-size: var(--t-xs); }

.tb-err { color: var(--danger); font-size: var(--t-xs); padding: 0 var(--s-2) var(--s-1); }

/* ============================= формы ============================= */

form.stacked p { margin: 0 0 var(--s-4); }
form.stacked label { display: block; margin-bottom: var(--s-1); font-size: var(--t-sm); }

/* Перечислять типы по одному — верный способ однажды забыть новый.
   Берём все текстовые поля разом и вычитаем те, у которых своя геометрия:
   переключатели, кнопки и строку поиска в шапке. */
input:not([type=checkbox]):not([type=radio]):not([type=submit]):not([type=button]):not([type=search]),
select, textarea {
  width: 100%; padding: var(--s-2) var(--s-3);
  font: inherit; font-size: var(--t-md);
  color: var(--text); background: var(--bg);
  border: 1px solid var(--border); border-radius: var(--r-md);
}
textarea { resize: vertical; }

/* Кнопка выбора файла — та же геометрия, что у остальных кнопок. */
input[type=file] { padding: var(--s-1) var(--s-2); }
input[type=file]::file-selector-button {
  height: calc(var(--ctl-h) - .2rem); margin-right: var(--s-3);
  padding: 0 var(--s-4); border: 1px solid var(--border);
  border-radius: var(--r-md); background: var(--surface); color: var(--text);
  font: inherit; font-size: var(--t-sm); cursor: pointer;
}
input[type=file]::file-selector-button:hover { border-color: var(--muted); }

/* Переключатели не должны растягиваться во всю строку. */
input[type=checkbox], input[type=radio] { width: auto; margin: 0; }

.errorlist { color: var(--danger); padding-left: var(--s-5); margin: var(--s-1) 0; font-size: var(--t-sm); }
.helptext { color: var(--muted); font-size: var(--t-xs); display: block; margin-top: var(--s-1); }

/* ========================= уведомления ========================= */

.bell { position: relative; flex-shrink: 0; }
.badge {
  position: absolute; top: -.1rem; right: -.2rem;
  min-width: .95rem; height: .95rem; padding: 0 .2rem;
  display: flex; align-items: center; justify-content: center;
  border-radius: var(--r-pill);
  background: var(--danger); color: #fff;
  font-size: .55rem; line-height: 1; font-variant-numeric: tabular-nums;
}

.notice {
  display: flex; gap: var(--s-3); align-items: flex-start;
  padding: var(--s-3) var(--s-4);
}
/* Непрочитанное помечено полосой сбоку: заливка уже занята самим блоком. */
.notice.fresh { box-shadow: inset .18rem 0 0 var(--hl); }
.notice .ava { width: var(--ava-sm); height: var(--ava-sm); margin-top: .15rem; }
.notice-text { min-width: 0; }
.notice-what { font-size: var(--t-sm); }

/* Пометка «изменено». Нарочно мельче всего остального: это сноска,
   а не часть текста. */
.edited { font-size: var(--t-2xs); opacity: var(--dim); }
.edited-line { margin: 0; }
.edited-line:empty { display: none; }

/* =========================== подписки =========================== */

/* Список потоков: круглая иконка, название, точка у тех, где с прошлого
   захода появились статьи. Потоки без картинки показывают первую букву
   названия — пустых кружков в списке быть не должно. */
.sub {
  display: flex; align-items: center; gap: var(--s-3);
  padding: var(--s-2) var(--s-3); margin: 0 calc(var(--s-3) * -1);
  border-radius: var(--r-md); color: inherit;
  transition: background .12s, color .12s;
}
.sub:hover { background: var(--raised); color: var(--hl); text-shadow: none; }
.ava-letter {
  display: grid; place-items: center;
  /* Цвет страницы, а не блока: на блоке кружок должен быть виден. */
  background: var(--bg); border: 1px solid var(--border);
  font-size: var(--t-sm); text-transform: uppercase; line-height: 1;
}
.sub-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.dot { width: .35rem; height: .35rem; border-radius: 50%; background: var(--accent); flex-shrink: 0; }

/* ========================== настройки ========================== */

.ava-big { width: 5rem; height: 5rem; }

/* Картинка потока — широкой полосой над названием, как шапка журнала. */
.cover {
  display: block; width: 100%; aspect-ratio: 6 / 1;
  object-fit: cover; border-radius: var(--r-md);
  margin-bottom: var(--s-4);
}

.cover-preview {
  display: block; width: 100%; max-height: 9rem;
  object-fit: cover; border-radius: var(--r-md);
}

.saved { margin-left: var(--s-3); font-size: var(--t-xs); }

.notify { border-collapse: collapse; width: 100%; margin-bottom: var(--s-4); }
.notify th, .notify td {
  padding: var(--s-2) var(--s-3); text-align: left;
  border-bottom: 1px solid var(--border); font-size: var(--t-sm);
}
.notify th { color: var(--muted); font-weight: 400; }
.notify th:not(:first-child), .notify td:not(:first-child) { width: 6rem; text-align: center; }
.notify input { width: auto; }

.btn-danger-solid { background: var(--danger); border-color: var(--danger); color: #fff; }
.btn-danger-solid:hover { background: var(--danger); color: #fff; }

.note {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--r-md); padding: var(--s-3) var(--s-4); margin: var(--s-4) 0;
}
