/* ============================================================
   Красный флаг — дизайн-система, версия 2 (30.09.2026)

   Утверждённый владельцем концепт — тёмное фитнес-приложение как
   образец: светящиеся карточки-сквиркли, сетка точек, цифры точечной
   матрицей, «только более красное, более цепляющее». Токены, контраст
   и замеры — в scratchpad концепта (tokens.md); здесь — то, что из них
   дошло до кода, и почему.

   Три слоя, имена токенов одни на все:
     :root                        светлая тема (база)
     :root[data-theme="dark"]     тёмная
     [data-quiet]                 тихий режим поверх любой из них

   Атрибуты ставит js/theme-boot.js ДО первой отрисовки: сохранённый
   выбор или системная тема. Медиазапроса по prefers-color-scheme здесь
   больше нет — систему читает скрипт, и тема идёт за ней, пока выбора нет.

   Типографика: Onest — весь текст и заголовки, Doto — только числа от
   40px (кириллицы в нём нет). Моноширинного больше нет: метки набраны
   тем же Onest мелким кеглем без капслока.

   Тени, стекло и размытие не используются вовсе. Свечение карточек —
   только градиентами (.glow), без теней, картинок и filter, и оно
   неподвижно: пульс рядом с текстом, который надо прочитать, — метроном.
   ============================================================ */

:root{
  color-scheme:light;

  /* ----- основа ----- */
  --bg:#F5F1F0;
  --bg-dot:rgba(60,20,10,.09);
  --surface:#FFFFFF;
  --surface-2:#F0E8E6;
  --line:#E4DAD7;
  --line-strong:#CDBDB8;
  /* Рамка поля ввода и вариантов цены: граница поля обязана быть видна —
     3.41:1 к фону (1.4.11 требует 3). */
  --field-line:#8F7F7B;
  --ink:#1E1413;
  --ink-2:#4A3B38;
  --muted:#655651;        /* 6.23:1 на --bg, 5.22 на точке сетки */
  --ink-hi:#140B0A;       /* самое сильное: название приёма, цифры матрицей */

  /* ----- красный ----- */
  --red-600:#A82A1E;      /* фирменный: плитка, выделение текста */
  --red-500:#D12E1C;      /* заливки: главная кнопка, «Отправить», вкладка; белый на нём 5.10 */
  --accent:var(--red-500);
  --accent-ink:#A82A1E;   /* акцентный ТЕКСТ и каретка: 6.21 на --bg */
  --on-accent:#FFFFFF;
  --accent-contrast:var(--on-accent);

  /* «Стоп» — плоский, без свечения и движения, рамка 1px по контуру. */
  --alarm-bg:#FFFFFF;
  --alarm-rule:#D12E1C;
  --accent-soft:var(--alarm-bg);
  --accent-border:var(--line-strong);

  /* Её блок помощи (её собственные слова о кризисе) — не «стоп»: её
     холодный синий, плоско, без свечения. Кромка к фону 3.37:1. */
  --help-bg:#F4F5FF;
  --help-line:#6F79E6;

  --focus:#140B0A;        /* кольцо фокуса; к --red-500 3.81 */
  --selection-bg:#A82A1E; --selection-ink:#FFFFFF;

  /* Подложка круглых и вторичных кнопок — вместо белой пилюли с тенью. */
  --tint:rgba(60,20,10,.06);
  --tint-line:rgba(60,20,10,.16);
  --tint-hover:rgba(60,20,10,.1);
  /* «Как ответить» внутри карточки — нейтральная, не зелёная (решение владельца). */
  --fix-bg:rgba(255,255,255,.82);
  --fix-line:rgba(60,20,10,.12);
  /* Подложки [дата] в черновике: 10.49:1. */
  --fill-bg:#FBE1DA;
  --fill-ink:#5C1A10;
  --mark-bg:var(--fill-bg);
  --mark-fg:var(--fill-ink);
  --chart-dim:rgba(60,20,10,.32);
  --chart-hi:#140B0A;
  --chart-line:rgba(20,11,10,.7);
  --plan-on:#FFF0EC;
  --plan-on-line:#D12E1C;

  /* Её сторона — холодный синий: это не угроза, красным её не красим.
     Цвет — свечение .glow.cold (--gc*, ниже); прежней полосы слева нет. */

  --ok:#2E7D53;
  --ok-soft:#E4F0E9;
  --ok-ink:#1F5E3D;
  --warn-soft:#FBF2E3;
  --warn-ink:#7A5A1B;

  /* Маскот. Заливка своя, а не `--surface`: в тёмной теме карточка почти
     чёрная, и зверёк на ней сливался бы в пятно с обводкой. */
  --pet-fill:#FFFFFF;
  --pet-blush:#F6DDD8;

  /* Тумблеры: темы в шапке и тихого режима в настройках. Дорожка светлой
     темы к фону — 1.22:1, белый бегунок к дорожке — 1.37: положение тумблера
     было не видно (1.4.11 требует 3). Поэтому у дорожки кромка
     (--switch-line, 3.41 к фону), у бегунка — своя (--switch-thumb-line,
     5.10 к дорожке). В тёмных темах светлый бегунок на тёмной дорожке —
     13:1, кромка ему не нужна: она цвета самого бегунка. Меряет look-check. */
  --switch-track:#E4DAD7;
  --switch-thumb:#FFFFFF;
  --switch-line:#8F7F7B;
  --switch-thumb-line:#655651;
  --switch-icon:#655651;
  --switch-icon-on:#140B0A;

  /* ----- свечение: цвета по вариантам и сила слоёв ----- */
  --gh1:#E5341F; --gh2:#FF5A2A; --ghb:#FFF6F3;   /* тяжёлый приём */
  --gm1:#C2184A; --gm2:#E8436E; --gmb:#FFF4F7;   /* средний */
  --gl1:#B8402E; --gl2:#D9785F; --glb:#FCF5F3;   /* лёгкий */
  --gc1:#4A57E0; --gc2:#7F89F2; --gcb:#F4F5FF;   /* её сторона */
  --gp1:#E5341F; --gp2:#C2184A; --gpb:#FFF5F4;   /* Pro, «Повторяется» */
  --ga-top:48%; --ga-bottom:70%; --ga-side:40%; --ga-bloom:28%; --ga-corner:62%; --ga-border:45%;

  /* Теней нет: карточки держат рамка и поверхность. Имена оставлены, чтобы
     старое правило, забытое где-то, не рисовало тень. */
  --shadow-sm:none;
  --shadow:none;
  --shadow-lg:none;

  /* ----- радиусы ----- */
  --r-card:36px;          /* карточка со свечением */
  --r-card-sq:64px;       /* она же при corner-shape:squircle */
  --r-block:20px;         /* пузыри, записи, вердикт, цены */
  --r-flat:2px;           /* «стоп» — нарочно выпадает из системы */
  --r-xs:14px; --r-sm:12px; --r-md:var(--r-block); --r-lg:var(--r-block); --r-pill:999px;

  /* Шкала отступов. Радиусы и шрифты жили в токенах, а вертикальный ритм —
     нет: 26 разных значений margin на файл, в одном блоке «Тест» одиннадцать.
     Экран результата собран на этой шкале целиком; остальные блоки
     переводятся отдельным заходом — там смена значений двигает геометрию,
     которую сторожит layout-check. */
  --s-1:4px; --s-2:8px; --s-3:12px; --s-4:16px;
  --s-5:24px; --s-6:32px; --s-7:48px;

  /* ----- шрифты и шкала ----- */
  --f-body:"Onest",system-ui,-apple-system,"Segoe UI",sans-serif;
  --f-display:var(--f-body);
  /* Моноширинного нет: прежние моноширинные метки набраны Onest. */
  --f-mono:var(--f-body);
  --f-dot:"Doto",ui-monospace,monospace;
  /* 15 → 19 → 24 → 44 → 96. Заголовок экрана — от 32 до 44 по ширине:
     на телефоне 375 это 35px, и длинная строка главной держится в две. */
  --t-display:clamp(32px, 9.4vw, 44px);
  --t-section:24px;
  --t-small-head:19px;
  --t-micro:12.5px;

  --ease-out:cubic-bezier(.16,1,.3,1);
}

:root[data-theme="dark"]{
  color-scheme:dark;
  --bg:#0A0707;
  --bg-dot:rgba(255,236,230,.075);
  --surface:#151010;
  --surface-2:#1E1716;
  --line:#2E2523;
  --line-strong:#433633;
  --field-line:#74625E;
  --ink:#F5EFED;
  --ink-2:#D9CECB;
  --muted:#A89A96;
  --ink-hi:#FFFFFF;
  --accent-ink:#FF8A75;
  --alarm-bg:#1B1312;
  --help-bg:#10111F; --help-line:#4B57E0;   /* кромка к фону 3.57:1 */
  --focus:#FFFFFF;
  --tint:rgba(255,236,230,.08);
  --tint-line:rgba(255,236,230,.14);
  --tint-hover:rgba(255,236,230,.13);
  --fix-bg:rgb(10 7 7 / .72);
  --fix-line:rgba(255,236,230,.12);
  --fill-bg:#3A1C16;
  --fill-ink:#FFE3DC;
  --chart-dim:rgba(255,227,220,.28);
  --chart-hi:#FFFFFF;
  --chart-line:rgba(255,255,255,.75);
  --plan-on:#1E0D0B;
  --plan-on-line:#E5341F;
  --ok:#5FC98F; --ok-soft:#16302280; --ok-ink:#8FDCB0;
  --warn-soft:#332A18; --warn-ink:#E0C289;
  --pet-fill:#3A3330; --pet-blush:#6B3A31;
  --switch-track:#2E2523; --switch-thumb:#F5EFED; --switch-icon:#A89A96; --switch-icon-on:#0A0707;
  --switch-line:#74625E; --switch-thumb-line:#F5EFED;
  --gh1:#E5341F; --gh2:#FF4A1C; --ghb:#140A09;
  --gm1:#B3123B; --gm2:#D0204A; --gmb:#12080C;
  --gl1:#A82A1E; --gl2:#7A1B12; --glb:#110908;
  --gc1:#3A46D6; --gc2:#2B35B8; --gcb:#0B0B17;
  --gp1:#E5341F; --gp2:#B3123B; --gpb:#130909;
  --ga-top:55%; --ga-bottom:60%; --ga-side:40%; --ga-bloom:45%; --ga-corner:55%; --ga-border:40%;
}

/* ТИХИЙ РЕЖИМ: графит без красного и без свечения, в обеих темах. Имена
   токенов те же — режим только переопределяет значения. На экране не
   остаётся вывески: ни красного, ни плитки с флажком, ни названия. */
[data-quiet]{
  --bg:#F3F3F1;
  --bg-dot:rgba(0,0,0,.055);
  --surface:#FFFFFF;
  --surface-2:#EBEBE8;
  --line:#DDDDD9;
  --line-strong:#C6C6C1;
  --field-line:#8A8A90;
  --ink:#1B1B1D;
  --ink-2:#45454A;
  --muted:#5C5C62;
  --ink-hi:#111113;
  --red-600:#45454A;
  --red-500:#2A2A2E;
  --accent-ink:#45454A;
  --on-accent:#FFFFFF;
  --alarm-bg:#FFFFFF;
  --alarm-rule:#8E5A50;   /* приглушённая глина: 5.07:1 к фону */
  --help-bg:#EBEBE8; --help-line:#8A8A90;   /* графит; кромка 3.09:1 */
  --focus:#111113;
  --selection-bg:#45454A; --selection-ink:#FFFFFF;
  --tint:rgba(0,0,0,.05);
  --tint-line:rgba(0,0,0,.15);
  --tint-hover:rgba(0,0,0,.09);
  --fix-bg:#F5F5F3;
  --fix-line:#DDDDD9;
  --fill-bg:#E6E6E2;
  --fill-ink:#2A2A2E;
  --chart-dim:rgba(0,0,0,.3);
  --chart-hi:#111113;
  --chart-line:rgba(0,0,0,.6);
  --plan-on:#EFEFEC;
  --plan-on-line:#2A2A2E;
  --ok:#45454A; --ok-soft:#EBEBE8; --ok-ink:#2A2A2E;
  --warn-soft:#EBEBE8; --warn-ink:#2A2A2E;
  --pet-fill:#FFFFFF; --pet-blush:#E4E0DE;
  --switch-track:#DDDDD9; --switch-thumb:#FFFFFF; --switch-icon:#5C5C62; --switch-icon-on:#111113;
  --switch-line:#8A8A90; --switch-thumb-line:#5C5C62;
  --t-display:32px;
}
:root[data-theme="dark"][data-quiet]{
  --bg:#111113;
  --bg-dot:rgba(255,255,255,.045);
  --surface:#19191C;
  --surface-2:#222226;
  --line:#2C2C31;
  --line-strong:#3B3B41;
  --field-line:#6E6E75;
  --ink:#EDEDF0;
  --ink-2:#C9C9CF;
  --muted:#9A9AA2;
  --ink-hi:#FFFFFF;
  --red-600:#C9C9CF;
  --red-500:#E4E4E8;
  --accent-ink:#C9C9CF;
  --on-accent:#111113;
  --alarm-bg:#19191C;
  --alarm-rule:#A8766C;
  --help-bg:#222226; --help-line:#6E6E75;   /* кромка 3.73:1 */
  --focus:#FFFFFF;
  --selection-bg:#C9C9CF; --selection-ink:#111113;
  --tint:rgba(255,255,255,.07);
  --tint-line:rgba(255,255,255,.14);
  --tint-hover:rgba(255,255,255,.11);
  --fix-bg:#111113;
  --fix-line:#2C2C31;
  --fill-bg:#2C2C31;
  --fill-ink:#EDEDF0;
  --chart-dim:rgba(255,255,255,.28);
  --chart-hi:#FFFFFF;
  --chart-line:rgba(255,255,255,.7);
  --plan-on:#222226;
  --plan-on-line:#E4E4E8;
  --ok:#C9C9CF; --ok-soft:#222226; --ok-ink:#EDEDF0;
  --warn-soft:#222226; --warn-ink:#EDEDF0;
  --pet-fill:#3A3A3F; --pet-blush:#55484A;
  --switch-track:#2C2C31; --switch-thumb:#EDEDF0; --switch-icon:#9A9AA2; --switch-icon-on:#111113;
  --switch-line:#6E6E75; --switch-thumb-line:#EDEDF0;
}

*{box-sizing:border-box}
/* Сетка точек — на окне приложения, а не на каждой поверхности: `.shell`
   прозрачный и прокручивается поверх неё, сетка стоит. Непрозрачные полосы
   (шапка, панель, композер, липкий выход) рисуют ту же сетку у себя и
   СОВМЕЩЕНЫ с ней: иначе на шве растворения точки ехали бы рядами. Шаг 14,
   начало — левый верхний угол окна; на широком экране — угол колонки. */
body{
  margin:0; color:var(--ink);
  --grid-x:0px;
  background:
    radial-gradient(circle at 1px 1px, var(--bg-dot) 1px, transparent 1.5px) var(--grid-x) 0/14px 14px,
    var(--bg);
  font-family:var(--f-body); font-size:15px; line-height:1.5;
  -webkit-font-smoothing:antialiased;
}
@media (min-width:601px){ body{ --grid-x:calc(50vw - 300px) } }
html{background:var(--bg)}
a{color:inherit}
.sr{position:absolute; width:1px; height:1px; overflow:hidden; clip:rect(0 0 0 0); clip-path:inset(50%); white-space:nowrap}
/* Фокус — одно кольцо на всё приложение, по форме элемента. */
:focus-visible{outline:2px solid var(--focus); outline-offset:3px}
::selection{background:var(--selection-bg); color:var(--selection-ink)}
textarea, input{caret-color:var(--accent-ink)}
/* Подсказка в пустом поле — своим цветом, не браузерным: серый Chromium
   (#757575) в тёмной теме давал 4.09:1, в тихой тёмной 3.81 — а
   «Вставь переписку…» и есть инструкция к главному полю. Замер по
   пикселям, tools/contrast-check.mjs. opacity — против приглушения
   подсказки в Firefox. */
::placeholder{color:var(--muted); opacity:1}
/* Серую вспышку тапа гасим намеренно: у каждой кнопки своё нажатие
   (прозрачность и вжатие), и вспышка поверх него — второй, чужой отклик. */
button, a, summary, label{-webkit-tap-highlight-color:transparent}
/* Две строки на одно место: громкая — в обычном режиме, нейтральная — в
   тихом. display:none прячет и от читалки с экрана, и от выделения. */
.quiet-text{display:none}
[data-quiet] .loud-text{display:none}
[data-quiet] .quiet-text{display:inline}

/* Отступ снизу — от измеренной высоты композера (js/layout.js), не константа */
/* Прокручивается ОБОЛОЧКА, а не документ, и это не вкусовщина.
   На айфоне в Safari `position:fixed` считается от разметочного вьюпорта, и
   пока строка адреса то сворачивается, то разворачивается при прокрутке
   страницы, композер и нижняя панель едут по экрану — это и было видно
   живьём. Когда сам документ не прокручивается, строке адреса нечего
   сворачивать: панели стоят намертво, как в телеграме и в чате.
   `dvh` вместо `vh` — по той же причине: `vh` на телефоне считается по
   развёрнутой строке адреса и даёт лишние сто пикселей под экраном. */
html{height:100%}
/* touch-action:manipulation убирает зум по двойному тапу — тот самый
   непрошеный масштаб, который человек не просила. Заодно снимает задержку
   в 300 мс, которую браузер держит на каждом нажатии, ожидая второго тапа:
   все кнопки приложения начинают отзываться сразу. */
/* ОКНО ПРИЛОЖЕНИЯ, А НЕ СТРАНИЦА.

   body прижат к видимой области: js/layout.js ставит ему height и top по
   visualViewport, и при открытой клавиатуре окно просто становится ниже.
   Полосы внутри стоят на absolute и оказаться где-то ещё не могут —
   поэтому их больше не нужно догонять сдвигом, чем и занимались две
   предыдущие попытки. Подробности — в шапке js/layout.js.

   100dvh здесь — значение до первого замера и на случай, если
   visualViewport недоступен. */
body{
  position:fixed; top:0; left:0; right:0; height:100dvh;
  overflow:hidden; overscroll-behavior:none; touch-action:manipulation;
}
.shell{
  max-width:600px; margin:0 auto; height:100%; overflow-y:auto;
  -webkit-overflow-scrolling:touch; overscroll-behavior:contain;
  padding:0 16px calc(var(--composer-h, 90px) + 16px);
}
/* Фокус с клавиатуры не прячется под липкой шапкой (и под липким выходом
   на длинных экранах без нижней панели): прокрутка к нему оставляет запас. */
.shell{scroll-padding-top:calc(var(--topbar-h, 71px) + 12px)}
body[data-pane="detail"] .shell, body[data-pane="settings"] .shell,
body[data-pane="archive"] .shell{scroll-padding-top:calc(var(--topbar-h, 71px) + 72px)}

/* ============================================================
   Шапка
   ============================================================ */
.topbar{
  position:sticky; top:0; z-index:40;
  /* Фон НЕПРОЗРАЧНЫЙ, и это не вкусовщина. Было 94% с blur(14px): на
     снимках в тёмной теме коралловый пузырь просвечивал через шапку ровным
     прямоугольником с видимой левой кромкой, а строка под её нижней
     границей была разрезана по середине букв. Это читается не как матовое
     стекло, а как сбой отрисовки. Растворение снизу делает ::after. */
  /* Во всю ширину колонки: от её кромки начинается сетка точек, и она
     совпадает с сеткой окна (начало шапки — угол окна или колонки). */
  background:
    radial-gradient(circle at 1px 1px, var(--bg-dot) 1px, transparent 1.5px) 0 0/14px 14px,
    var(--bg);
  margin-inline:-16px; padding-inline:16px;
  display:flex; align-items:center; gap:10px;
  /* Безопасная зона прибавляется к верхнему отступу, а не задаётся отдельным
     padding-top: сокращённое свойство ниже затёрло бы его. На домашнем экране
     статус-бар прозрачный и содержимое уходит под часы; в обычном Safari
     отступ равен нулю — там чёлку закрывает строка адреса.
     Переменная --safe-area-inset-* — от Capacitor 8 на Android: там
     приложение рисуется под системными полосами (edge-to-edge), а WebView
     старше 140 отдаёт env() нулём, и шапка уезжала бы под часы. Плагин
     SystemBars кладёт настоящие отступы в эти переменные; в браузере и на
     iOS их нет, и работает env(). */
  padding-block:calc(var(--safe-area-inset-top, env(safe-area-inset-top, 0px)) + 14px) 12px;
  margin-bottom:20px;
}
/* Полоса растворения живёт в margin-bottom шапки и ничего не двигает:
   текст должен уходить в туман, а не обрываться по кромке. */
.topbar::after{
  content:""; position:absolute; left:0; right:0; top:100%; height:18px;
  pointer-events:none;
  background:linear-gradient(to bottom, var(--bg), color-mix(in srgb, var(--bg) 0%, transparent));
}
.brand-tile{
  width:40px; height:40px; flex:none; border-radius:var(--r-sm);
  background:var(--red-600); color:#FFFFFF; display:grid; place-items:center;
}
.brand-tile svg{width:21px; height:21px}
.wordmark, .quiet-title{
  font-weight:600; font-size:18px; letter-spacing:-.02em; line-height:1.2; min-width:0;
}
/* Словесный знак — ЦЕЛИКОМ ИЛИ НИКАК, и не по точкам перелома, а по месту.
   С переключателем языка (88px) знак перестал помещаться на основных
   ширинах телефонов: «Красн…» на 375, «К…» на Pro при 390 (сверка 01.10),
   а старые точки перелома (339 и 379 на Pro) этого не знали — и не могли
   знать: «Красный флаг» — 120px, «Red Flag» — 71, а у «Закрыть» и «Close»
   своя ширина. Здесь знак — ряд с переносом высотой в одну строку: перед
   словами стоит пустой первый элемент, и слова, которым не хватает места,
   уходят на вторую строку, а она обрезана. Плитка остаётся всегда; читалка
   название слышит и тогда, когда его не видно. С 01.10 на телефонах знак
   мельче и от 375 виден на обоих языках, уже 375 — спрятан (ниже, у
   переключателя языка); этот ряд остался страховкой — на Pro и на случай
   чужого шрифта.
   Сторож — i18n-check, «ШАПКА: НАЗВАНИЕ ЦЕЛИКОМ» (ширины 320–430, оба
   языка, обычный и тихий режим, четыре экрана). */
.wordmark{
  flex:1 1 0; display:flex; flex-wrap:wrap; align-content:flex-start; height:1.2em; overflow:hidden;
}
/* Пустой первый элемент во всю высоту строки: не хватило места словам —
   они переносятся НИЖЕ него, за обрез. Высота нужна: у пустого элемента
   нулевой высоты вторая строка начиналась бы с той же нулевой отметки. */
.wordmark::before{content:""; width:0; height:100%}
.wordmark > span{flex:none; white-space:nowrap}
/* Тихий режим: вместо плитки с флажком и названия — название раздела. Его
   прятать нельзя — это единственная подпись экрана, — поэтому оно идёт в
   две строки (две строки по 18px ниже кнопок шапки в 44px — высота шапки
   та же), а на узких телефонах ещё и мельче: «Шпаргалка» и «Cheatsheet» —
   одно слово, 95px при 82 свободных на 320, «Pro» рядом с «Закрыть» —
   29 при 25. Обрезалось многоточием на 320–375 («Место и дан…»). */
.quiet-title{display:none; margin-right:auto; overflow:hidden}
[data-quiet] .brand-tile, [data-quiet] .wordmark{display:none}
[data-quiet] .quiet-title{
  display:-webkit-box; -webkit-box-orient:vertical; -webkit-line-clamp:2; line-clamp:2;
  line-height:1.15; white-space:normal;
}
@media (max-width:359px){ .quiet-title{font-size:15px} }

/* ---------- Тумблер темы: солнце и луна ----------
   Своей поверхности у кнопки нет (цель 56×44, дорожка 56×32 внутри), и
   под правило пилюли она не попадает; фокус — общее кольцо по пилюле.
   Положение бегунка задаёт css по data-theme, а не скрипт: при загрузке он
   не прыгает. Сама смена темы мгновенная, едет только бегунок. */
.theme-switch{
  flex:none; width:56px; height:44px; padding:0; border:0; background:none; cursor:pointer;
  border-radius:var(--r-pill); display:grid; place-items:center; color:var(--switch-icon);
}
.theme-switch .track{
  position:relative; display:block; width:56px; height:32px; border-radius:var(--r-pill); background:var(--switch-track);
  /* Кромка — внутрь, раскладку не трогает: бегунок стоит там же. */
  outline:1px solid var(--switch-line); outline-offset:-1px;
}
.theme-switch .thumb{
  position:absolute; top:3px; left:3px; width:26px; height:26px; border-radius:50%;
  background:var(--switch-thumb); border:1.5px solid var(--switch-thumb-line);
  transition:transform .18s var(--ease-out);
}
.theme-switch .ico{position:absolute; top:8px; width:16px; height:16px; z-index:1; color:var(--switch-icon)}
.theme-switch .sun{left:8px}
.theme-switch .moon{right:8px}
:root:not([data-theme="dark"]) .theme-switch .sun,
:root[data-theme="dark"] .theme-switch .moon{color:var(--switch-icon-on)}
:root[data-theme="dark"] .theme-switch .thumb{transform:translateX(24px)}
@media (hover:hover) and (pointer:fine){ .theme-switch:hover .track{background:var(--line-strong)} }

/* ---------- Язык интерфейса: RU | EN ----------
   Сегмент рядом с тумблером темы и тем же языком: дорожка 32px с кромкой
   (::before), выбранное — пилюлей-бегунком. Кнопки — цели 44×44 без своей
   поверхности (фон и рамка у внутреннего span), поэтому под правило
   пилюли и цели 44 они подходят так же, как тумблер темы. Нажатую
   кнопку (aria-pressed) ставит ранний скрипт — при загрузке ничего не
   прыгает. Цвета — токены тумблера: подписи 4.9–5.6:1 к дорожке во всех
   четырёх режимах. */
.lang-switch{flex:none; position:relative; display:flex; align-items:center; height:44px}
.lang-switch::before{
  content:""; position:absolute; left:4px; right:4px; top:6px; height:32px; border-radius:var(--r-pill);
  background:var(--switch-track); outline:1px solid var(--switch-line); outline-offset:-1px; pointer-events:none;
}
.lang-switch button{
  position:relative; width:44px; height:44px; padding:0; border:0; background:none; cursor:pointer;
  border-radius:var(--r-pill); display:grid; place-items:center;
  font-family:var(--f-body); font-size:12.5px; font-weight:600; line-height:1; letter-spacing:.02em; color:var(--switch-icon);
}
.lang-switch button span{
  display:grid; place-items:center; width:36px; height:26px; border-radius:var(--r-pill);
  border:1.5px solid transparent;
}
.lang-switch button[aria-pressed="true"]{color:var(--switch-icon-on)}
.lang-switch button[aria-pressed="true"] span{background:var(--switch-thumb); border-color:var(--switch-thumb-line)}
@media (hover:hover) and (pointer:fine){ .lang-switch button[aria-pressed="false"]:hover span{background:var(--line-strong)} }
/* Название в шапке — мельче на телефонах (решение владельца 01.10). Было:
   18px, и «Красный флаг» (120px) рядом с плиткой, RU | EN, тумблером и
   шестерёнкой (40 + 88 + 56 + 44) помещалось только от 430, на 360–414
   оставалась одна плитка; «Red Flag» (71px) — от 375. Теперь на телефонах
   (до 479) — 13px (87 и 52) и зазоры шапки 6 вместо 10: на 375 месту 91px,
   запас 4 по-русски. Уже 375 названия нет совсем (так и было: «на 320–374
   прятать целиком»), плитка остаётся и прижимает остальное вправо. Цели 44
   и цвета не тронуты. Механизм «целиком или никак» выше остаётся
   страховкой: на Pro «Закрыть» шире шестерёнки (101 по-русски, 79
   по-английски), и там «Red Flag» виден от 375, а «Красный флаг» — где
   поместится, от 428 (на 375 рядом с «Закрыть» ему остаётся 34px). Граница
   479, а не 429: с 430 при 18px русское название на Pro снова пряталось
   бы (73px места), то есть на 428 было бы видно, а на 430 — нет. С 480 —
   18px, и там помещается всё. Сторож — i18n-check, «ШАПКА: НАЗВАНИЕ ЦЕЛИКОМ». */
@media (max-width:479px){
  .topbar{gap:6px}
  .wordmark{font-size:13px}
}
@media (max-width:374px){
  .wordmark{display:none}
  .brand-tile{margin-right:auto}
}

/* Разметка приложения набрана по-русски. Пока таблица другого языка не
   приехала (js/i18n.js), помеченные узлы невидимы, но место держат —
   вспышки русского нет, и ничего не прыгает (метку ставит ранний скрипт). */
:root[data-i18n-wait] [data-i18n], :root[data-i18n-wait] .quiet-title{visibility:hidden}
/* Страницы вне приложения — двуязычные: блок каждого языка помечен
   data-only, виден тот, что в <html lang> (ставит ранний скрипт). */
:root:not([lang="en"]) [data-only="en"], :root[lang="en"] [data-only="ru"]{display:none !important}

.iconbtn{
  width:44px; height:44px; flex:none; padding:0; border-radius:var(--r-pill);
  border:1px solid var(--tint-line); background:var(--tint); color:var(--ink);
  display:grid; place-items:center; cursor:pointer;
  transition:opacity .15s, transform .15s var(--ease-out);
}
@media (hover:hover){.iconbtn:hover{background:var(--tint-hover)}}
.iconbtn svg{width:20px; height:20px}
.iconbtn.avatar{background:var(--accent); color:var(--accent-contrast); border-color:var(--accent)}
@media (hover:hover){.iconbtn.avatar:hover{background:var(--accent); opacity:.9}}

/* ============================================================
   Показатели — три карточки в ряд
   ============================================================ */
.stats{display:grid; grid-template-columns:repeat(3,1fr); gap:10px; margin-bottom:18px}
/* Пустое табло не должно занимать отступ: пока считать нечего, его нет */
.stats:empty{display:none}
.stat{
  background:var(--surface); border:1px solid var(--line); border-radius:var(--r-block);
  padding:14px 10px; text-align:center;
}
.stat-icon{
  width:38px; height:38px; margin:0 auto 10px; border-radius:var(--r-sm);
  background:var(--tint); color:var(--accent); display:grid; place-items:center;
}
.stat-icon svg{width:19px; height:19px}
.stat-num{
  font-weight:600; font-size:27px; line-height:1; letter-spacing:-.02em;
  font-variant-numeric:tabular-nums; margin-bottom:6px; color:var(--ink-hi);
}
/* Метки — тем же Onest, мелким кеглем без капслока (моноширинного больше
   нет). Замер кегля и строк у меток — в layout-check. */
.stat-label{font-size:12px; font-weight:500; color:var(--muted); line-height:1.3}

/* ============================================================
   Ряд действий
   ============================================================ */
.actions{display:flex; gap:10px; margin-bottom:22px}
.btn{
  font-family:var(--f-body); font-size:14.5px; font-weight:500; line-height:1.2; cursor:pointer;
  border-radius:var(--r-pill); border:1px solid var(--tint-line);
  background:var(--tint); color:var(--ink); text-decoration:none;
  padding:13px 20px; display:inline-flex; align-items:center; justify-content:center; gap:8px;
  /* Движется только прозрачность и масштаб: смена фона на наведении —
     мгновенная, переход по background перекрашивал бы каждый кадр. */
  transition:opacity .15s, transform .15s var(--ease-out);
}
@media (hover:hover){.btn:hover{background:var(--tint-hover)}}

/* ------------------------------------------------------------
   Отклик на нажатие.

   Его не было вовсе: во всём файле тринадцать правил `:hover` и ни
   одного `:active`. На телефоне наведения не существует как состояния,
   зато на айфоне `:hover` срабатывает по ПЕРВОМУ тапу и залипает до
   следующего тапа в стороне — то есть единственным следом нажатия была
   кнопка, которая осталась подсвеченной, хотя её уже отпустили. А самого
   нажатия не видно: подпись меняется («Скопировано», «Собираю…») только
   после того, как действие выполнилось.

   Поэтому наведение уведено под `@media (hover:hover)` — туда, где мышь
   есть, — а нажатие отвечает всем и сразу. `transition-duration:0s` —
   чтобы отклик был мгновенным на нажатие и плавным на отпускании: у
   `.btn` переход по opacity уже стоит.
   ------------------------------------------------------------ */
.btn:active, .iconbtn:active, .linkbtn:active, .chip:active,
.opts button:active, .q-next:not([disabled]):active,
.smart button:active,
.chat-plus:active, .chat-send:active, .kb-down:active,
.tab:active, .card:active, .back:active,
details.card-acc > summary:active, .find .more:active,
.theme-switch:active, .switch:active{
  opacity:.6; transition-duration:0s;
}
/* И чуть вжимается — кроме кнопки над клавиатурой: её место держит
   transform, и масштаб сорвал бы её с середины. */
.btn:active, .iconbtn:active, .chip:active, .opts button:active,
.q-next:not([disabled]):active, .smart button:active,
.chat-plus:active, .chat-send:active, .tab:active, .theme-switch:active, .switch:active{
  transform:scale(.97);
}
@media (prefers-reduced-motion:reduce){
  .btn:active, .iconbtn:active, .chip:active, .opts button:active,
  .q-next:not([disabled]):active, .smart button:active,
  .chat-plus:active, .chat-send:active, .tab:active, .theme-switch:active, .switch:active{
    transform:none;
  }
}
.btn svg{width:18px; height:18px; flex:none}
.btn-primary{background:var(--accent); border-color:var(--accent); color:var(--accent-contrast); flex:1}
@media (hover:hover){.btn-primary:hover{background:var(--accent); opacity:.9}}
.btn-ghost{flex:1}
/* Ряд действий главной делится НЕ поровну, и это замер, а не вкус. `.actions`
   раздавал обеим кнопкам по половине (`flex:1` у обеих), а подписи не равны:
   «Новый разбор» со значком просит 170px и получал 167 на 375 и 159 на 360.
   Замерено: подпись шла в два этажа, обе кнопки становились 62px вместо 47, и
   «Архив» рядом одной строкой висел посреди пустой пилюли — на первом экране,
   который видит вернувшаяся женщина. Свободного места в ряду при этом 343 при
   нужных 292.

   Правило стоит ЗДЕСЬ, ниже `.btn-primary`, а не в блоке `.actions` выше:
   специфичность у них одинаковая, и побеждает то, что ниже. Этот капкан в
   памяти проекта записан дважды — композером и медиазапросом по высоте. */
.actions .btn-primary{flex:1.35}
.btn-square{width:52px; padding:0; flex:none}
/* Высоты у класса просто не было заявлено, и кнопка выходила 34px — на всём
   экране теста это единственная цель меньше нормы. Тем же классом набраны
   «Удалить диалог», «Удалить всё безвозвратно» и «Сбросить всё и
   перезагрузить»: самые разрушительные действия были самыми мелкими целями.
   Отступы прежние, высоту держит min-height — .btn центрует подпись сам. */
.btn-sm{padding:var(--s-2) var(--s-4); font-size:13.5px; min-height:44px}
.btn[disabled]{opacity:.5; cursor:default}

/* ============================================================
   Карточка-сплитка: превью слева, содержимое справа
   ============================================================ */
.cards{display:flex; flex-direction:column; gap:12px}
.card{
  display:grid; grid-template-columns:112px 1fr;
  background:var(--surface); border:1px solid var(--line); border-radius:var(--r-block);
  overflow:hidden; text-decoration:none; color:inherit;
}
@media (hover:hover){.card:hover{border-color:var(--line-strong)}}
.card-preview{
  position:relative; background:var(--surface-2);
  display:grid; place-items:center; color:var(--muted); min-height:118px;
}
.card-preview svg{width:34px; height:34px; opacity:.55}
/* Дата на карточке диалога. Было 8.5px — самый мелкий кегль всего
   приложения, мельче тех 9px, которые уже поднимали до 12 у строки про
   приватность, — и при этом ЕДИНСТВЕННАЯ залитая поверхность строки:
   залитая форма читается громче текста равного контраста. То есть в
   списке, куда женщина приходит искать ленту по ИМЕНИ, первым в глаза
   бросалась дата, а имя шло третьим. Теперь дата — контурная метка,
   имя — самое заметное в строке. */
.card-tag{
  position:absolute; left:8px; bottom:8px;
  font-size:12px; font-weight:500; line-height:1.2;
  background:var(--surface); color:var(--muted); border:1px solid var(--line-strong);
  padding:3px 8px; border-radius:var(--r-pill);
}
.card-tag.accent{background:var(--accent); color:var(--accent-contrast)}
.card-body{padding:14px 15px; min-width:0}
.card-head{display:flex; align-items:flex-start; gap:8px; margin-bottom:8px}
.card-title{
  font-weight:600; font-size:18px; line-height:1.22; color:var(--ink-hi);
  letter-spacing:-.02em; margin:0; flex:1; min-width:0;
}
.chips{display:flex; flex-wrap:wrap; gap:6px; margin-bottom:10px}
.chip{
  display:inline-flex; align-items:center; gap:4px;
  font-size:12px; padding:4px 10px; border-radius:var(--r-pill);
  background:var(--surface-2); color:var(--muted); border:1px solid transparent;
  white-space:nowrap;
}
.chip-accent{background:var(--accent-soft); color:var(--accent-ink); border-color:var(--line)}
.chip-code{font-size:12px; background:none; padding:4px 0}
.badge{
  font-size:11px; font-weight:600; padding:4px 9px; border-radius:var(--r-pill);
  background:var(--accent); color:var(--accent-contrast); white-space:nowrap; flex:none;
}
.badge-quiet{background:var(--surface-2); color:var(--muted)}

/* сетка показателей внутри карточки */
.metrics{
  display:grid; grid-template-columns:1fr 1fr; gap:12px 14px;
  border-top:1px solid var(--line); padding-top:11px; margin-top:2px;
}
.metric-label{font-size:12px; font-weight:500; color:var(--muted); display:block; margin-bottom:2px; line-height:1.3}
.metric-value{font-size:14.5px; font-weight:500; font-variant-numeric:tabular-nums}
.metric-value.ok{color:var(--ok)}
.card-foot{
  display:flex; align-items:center; justify-content:flex-end; gap:8px;
  border-top:1px solid var(--line); margin-top:11px; padding-top:10px;
}
.card-foot .metric-label{margin:0}
.trend{font-weight:600; color:var(--ok); font-variant-numeric:tabular-nums}

/* ============================================================
   Нижняя панель
   ============================================================ */
.tabbar{
  position:absolute; left:0; right:0; bottom:0; z-index:50;
  /* Тоже непрозрачная, по той же причине: на 96% под подписями вкладок
     читались половинки слов — «Серый камень» разрезан верхней кромкой
     панели, его низ висел призраком прямо над «Главная/Архив». */
  /* Сетка точек совмещена с сеткой окна: начало плитки — верх окна. Верх
     панели в окне — это высота окна минус её собственная; обе меряет
     js/layout.js (--app-h, --tabbar-h). */
  background:
    radial-gradient(circle at 1px 1px, var(--bg-dot) 1px, transparent 1.5px)
      0 calc(var(--tabbar-h, 70px) - var(--app-h, 100dvh))/14px 14px,
    var(--bg);
  /* Начало плитки — от внешней кромки панели, а не от внутренней: у панели
     рамка сверху (и по бокам на широком экране), и от padding-box сетка
     уезжала на 1px против окна (замерено по снимку @2x: ряды окна на 28k,
     панели — на 28k+2). --tabbar-h — высота панели ВМЕСТЕ с рамкой. */
  background-origin:border-box;
  border-top:1px solid var(--line);
  padding-bottom:var(--safe-area-inset-bottom, env(safe-area-inset-bottom, 0px));
}
/* Растворение над панелью. В разборе его не рисуем: там эту роль уже
   играет градиент композера, а два тумана подряд дают полосу. */
/* На широком экране полосы держатся той же колонки, что и содержимое.
   Шапка живёт внутри `.shell` и колонкой ограничена сама; нижняя панель и
   композер стоят на absolute от окна и шли от кромки до кромки — заливка и
   линия во всю ширину под колонкой в 600. Верх и низ выглядели собранными
   из разных макетов. Двигать шапку наружу нельзя: она sticky внутри
   прокручиваемой оболочки, а прокрутка здесь выстрадана. */
@media (min-width:601px){
  /* Композера здесь нет намеренно: его базовое правило стоит НИЖЕ по
     файлу, специфичность у них одинаковая, и `left:0` оттуда перебивал
     этот `left:50%`, а `transform` оставался — композер уезжал ровно на
     полширины. Замерено на 1280: полоса на −300…300 при колонке
     340…940, то есть половина поля ввода за левой кромкой экрана, на
     любом экране шире 600. Его колонка задана рядом с ним самим. */
  .tabbar{ left:50%; right:auto; width:600px; transform:translateX(-50%) }
  .tabbar{ border-inline:1px solid var(--line) }
}

body:not([data-pane="chat"]) .tabbar::before{
  content:""; position:absolute; left:0; right:0; bottom:100%; height:22px;
  pointer-events:none;
  background:linear-gradient(to top, var(--bg), color-mix(in srgb, var(--bg) 0%, transparent));
}
.tabbar .inner{max-width:600px; margin:0 auto; display:grid; grid-template-columns:repeat(5,1fr)}
.tab{
  border:0; background:none; cursor:pointer; padding:9px 2px 10px;
  display:flex; flex-direction:column; align-items:center; gap:5px;
  /* Высота строки — целым числом пикселей: 11 × 1.2 давало панели 70.19px,
     её верхняя строка пикселей делилась с лентой, и снимок панели менялся
     при прокрутке (layout-check, «Сквозь полосы ничего не видно»). */
  font-family:var(--f-body); font-size:11px; line-height:13px; color:var(--muted);
  transition:opacity .15s, transform .15s var(--ease-out);
}
.tab-ico{
  width:40px; height:32px; border-radius:var(--r-pill);
  display:grid; place-items:center;
}
.tab-ico svg{width:20px; height:20px}
/* Подпись активной вкладки — цветом текста, а не красным: красный текст на
   фоне держит 4.55, а красной здесь и так залит кружок. */
.tab[aria-selected="true"]{color:var(--ink); font-weight:600}
.tab[aria-selected="true"] .tab-ico{background:var(--accent); color:var(--accent-contrast)}

/* ============================================================
   Общая типографика экранов
   ============================================================ */
/* Экраны меняются без появления: их открывают десятки раз в день, и
   движение на каждом переходе — задержка, а не отклик. */
.pane{display:none}
.pane.on{display:block}

/* По классу, а не по тегу. Заголовок главной — `<h2 class="screen">`
   (единственный h1 страницы уже занят), и правило его не находило: гротеск
   22.5px вместо Lora вместо 25–31. Единственный заголовок, который видит
   вернувшаяся женщина, был набран не так, как все остальные. */
/* Крупный кегль — нейтральным словам: «Архив», «Место и данные», имя
   диалога. От 32 до 44px по ширине, в тихом режиме 32. */
.screen{
  font-family:var(--f-display); font-weight:600; font-size:var(--t-display); color:var(--ink-hi);
  letter-spacing:-.035em; line-height:1.05; margin:6px 0 12px; text-wrap:balance;
  overflow-wrap:anywhere;
}
h2.sect{
  font-weight:600; font-size:18px; letter-spacing:-.015em; color:var(--ink-hi);
  margin:28px 0 12px; padding-bottom:9px; border-bottom:1px solid var(--line);
}
h3.sub{font-weight:600; font-size:17px; letter-spacing:-.01em; margin:22px 0 8px}
p.lede{color:var(--muted); margin:0 0 20px; max-width:58ch; font-size:14.5px}
/* Метка — мелкий кегль, без капслока и разрядки: моноширинного больше нет,
   а капслок кириллицей на 9px был самым медленным набором приложения. */
.kicker{font-size:var(--t-micro); font-weight:500; line-height:1.4; color:var(--muted); display:block; margin-bottom:6px}
/* Подпись над готовой формулировкой — это заголовок конечного продукта
   приложения. Замерено на 375: «Конфликт · Не защищаться и вернуть
   разговор к своей теме» — 55 знаков, 309×29, ДВЕ строки капслока самым
   мелким кеглем экрана. `.kicker` рассчитан на одно-два слова
   («ПОВТОРЯЕТСЯ», «ПОХОЖЕ, НО НЕ ОНО») и на предложении перестаёт быть
   меткой: капслок, разрядка, моноширинный и перенос разом. Там, где он
   метка, он таким и остаётся — правило узкое. */
.msg-report .verdict > .kicker{
  font-family:var(--f-body); font-size:var(--t-micro); font-weight:500;
  letter-spacing:0; text-transform:none;
}
.back{
  background:none; border:0; padding:8px 0; margin-bottom:4px;
  color:var(--ink-2); font-family:var(--f-body); font-size:14px; cursor:pointer;
}
@media (hover:hover){.back:hover{color:var(--ink)}}
.empty{
  color:var(--muted); font-size:14px; background:var(--surface-2);
  border:1px dashed var(--line-strong); border-radius:var(--r-block); padding:16px;
}
.rowbtns{display:flex; flex-wrap:wrap; gap:8px; margin:0}

/* ============================================================
   Разбор: переписка и находки
   ============================================================ */
/* ============================================================
   Лента сообщений
   ============================================================ */
/* Без min-height. Пустая лента раздувалась на полэкрана и выталкивала
   всё, что под ней, — предложение подключить модель при первом открытии
   лежало под композером на три четверти (замерено 458–557 при композере
   с 482). Пустого места на этом экране и так хватает: сверху приветствие,
   снизу композер, между ними лента ровно такая, сколько в ней есть. */
.thread{display:flex; flex-direction:column; gap:14px; padding:4px 0 8px}

.msg{max-width:88%; display:flex; flex-direction:column; gap:8px}
.msg-me{align-self:flex-end; align-items:flex-end}
.msg-app{align-self:flex-start; max-width:100%}

.msg-text{
  background:var(--surface); border:1px solid var(--line); border-radius:var(--r-block);
  padding:12px 15px; font-size:14.5px; white-space:pre-wrap;
}
/* Вставленная переписка — не сообщение собеседнику, а сырой ввод, и
   красить её акцентом нельзя. Замерено на 16 репликах (375×667): пузырь
   даёт 224 862 px² сплошного --accent при 9 472 у кнопки «Скопировать» —
   в двадцать четыре раза больше, и это 94% всего акцента на экране. А
   акцент в этом приложении значит «важно»: им покрашены карточки угрозы.
   Здесь важным оказывалось то, что человек просто скопировала, — вместе
   с ЕГО словами, напечатанными цветом тревоги.

   Вторая цена — перечитывание: белое по кирпичному на пятьсот пикселей
   текста, а перечитывать она будет, потому что находки на него ссылаются.

   «Это моё» держат правое выравнивание и срезанный угол — их достаточно,
   и от сообщений приложения пузырь отличается фоном и рамкой. */
.msg-me .msg-text{background:var(--surface-2); border-color:var(--line-strong); color:var(--ink)}
.msg-app .msg-text{border-bottom-left-radius:6px}
.msg-me  .msg-text{border-bottom-right-radius:6px}

.msg-imgs{display:flex; flex-wrap:wrap; gap:6px; justify-content:flex-end}
.msg-imgs img{
  max-width:190px; max-height:260px; border-radius:var(--r-sm);
  border:1px solid var(--line); object-fit:cover;
}
.msg-report{display:flex; flex-direction:column; gap:12px; width:100%}
/* Кнопка действия под ошибкой модели и сырой ответ сервиса — одной строкой */
.msg-actions{display:flex; flex-wrap:wrap; gap:8px}
/* Кнопки имён в блоке «Кто здесь ты?» — их столько, сколько людей в
   переписке, и в групповом чате это не два. Замерено на 375: четыре имени
   встают в один ряд до 426 пикселей, то есть четвёртое имя уезжает за
   кромку экрана и пальцем недостижимо, а остальные ужимаются и режут
   текст. Ряд обязан переноситься. Ровно та же оговорка стоит у выбора
   диалога (`.convpick`) и по той же причине. */
.unmarked .msg-actions{flex-wrap:wrap}
.msg-detail{font-size:12px; color:var(--muted); word-break:break-word; margin-top:-2px}

.typing{
  display:flex; gap:5px; padding:14px 16px; align-self:flex-start;
  background:var(--surface); border:1px solid var(--line); border-radius:var(--r-md);
}
.typing i{width:6px; height:6px; border-radius:50%; background:var(--muted); animation:blip 1.1s infinite}
.typing i:nth-child(2){animation-delay:.15s} .typing i:nth-child(3){animation-delay:.3s}
@keyframes blip{0%,60%,100%{opacity:.3; transform:translateY(0)} 30%{opacity:1; transform:translateY(-3px)}}

/* ============================================================
   Отчёт: его приёмы и её сторона — каруселями светящихся карточек

   Разделов два, и разница между ними — вся суть: «Что делает он» — его
   приёмы, «За что он может зацепиться» — механика её ответа. С 30.09
   (решение владельца) сторону видно цветом свечения: его карточки светятся
   красным по тяжести (sev-high → sev-low), её — холодным синим, в тихом
   режиме — тоном поверхности. Прежний признак стороны, полоса слева, ушёл
   вместе с плоскими карточками; «видна, но не громче его» теперь меряется
   насыщенностью свечения (layout-check, «Чья это половина отчёта»).

   Карточки листаются вбок (scroll-snap): пальцем, клавишами — карусель в
   фокусе — и точками под ней. Над каруселью заголовок и счёт матрицей. Если
   тревожный блок уже назвал угрозу, её карточки в карусели нет и в счёт
   она не входит (js/chat.js, reportHTML).
   ============================================================ */
.group{min-width:0}
.group-head{display:flex; align-items:flex-end; justify-content:space-between; gap:12px; margin:10px 2px 12px}
.group-head h3{
  margin:0; font-size:var(--t-section); font-weight:600; letter-spacing:-.02em;
  line-height:1.15; color:var(--ink-hi); text-wrap:balance;
}
.group-head .dot-num{font-size:44px; font-weight:900; flex:none}
[data-quiet] .group-head h3{font-size:var(--t-small-head)}

/* Во всю ширину колонки: карусель выходит за поля ленты (-16px), иначе
   соседняя карточка обрезалась бы по краю пузыря, а не экрана. */
.carousel{
  display:flex; gap:12px; overflow-x:auto; overscroll-behavior-x:contain;
  scroll-snap-type:x mandatory; scroll-padding-inline:16px; scrollbar-width:none;
  margin:0 -16px; padding:0 16px 4px;
}
.carousel::-webkit-scrollbar{display:none}
.carousel:focus-visible{outline-offset:-3px}
/* Соседняя карточка выглядывает на 28px: так видно, что листается. */
.carousel > .find{flex:0 0 calc(100% - 28px); scroll-snap-align:start; min-width:0}
.carousel > .find:only-child{flex-basis:100%}
/* Точки — кнопки без своей поверхности: цель 44×44, сама точка — ::before.
   Нетекущая точка — .5 цвета текста: 3.4:1 к фону в светлой, 4.8 в тёмной
   (1.4.11 требует 3; при .45 светлая давала 2.9). Текущую видно ещё и
   размером. */
.pager{display:flex; justify-content:center; margin:0 0 4px}
/* flex:none — точка не ужимается: без него ряд из одиннадцати точек на 320
   ужимал каждую до 26px. Больше шести точек не бывает (js/chat.js,
   ТОЧЕК_НЕ_БОЛЬШЕ) — там «3 из 11» со стрелками, ниже. */
.pager button{
  flex:none; width:44px; height:44px; padding:0; border:0; background:none; cursor:pointer;
  display:grid; place-items:center; border-radius:var(--r-pill);
}
.pager button::before{
  content:""; width:7px; height:7px; border-radius:50%; background:var(--ink);
  opacity:.5; transition:opacity .16s, transform .16s var(--ease-out);
}
.pager button[aria-current="true"]::before{opacity:1; transform:scale(1.4)}
@media (hover:hover) and (pointer:fine){ .pager button:hover::before{opacity:.75} }
/* Много карточек: место словами и две стрелки — круглые кнопки 44×44. */
.pager-steps{display:flex; justify-content:center; align-items:center; gap:14px; margin:0 0 4px}
.pager-steps .pos{min-width:72px; text-align:center; font-size:14.5px; font-weight:500; color:var(--ink); font-variant-numeric:tabular-nums}
.pager-steps .iconbtn span{font-size:18px; line-height:1}
.pager-steps [aria-disabled="true"]{opacity:.4; cursor:default}

/* Карточка находки. Поверхность и свечение даёт .glow с вариантом (его —
   .sev-*, её — .cold); сама карточка — только колонка текста. Текст не
   ближе 20px к кромке: самые насыщенные места свечения лежат у края. */
.find{position:relative; display:flex; flex-direction:column}
.find .name{
  margin:0 0 12px; font-size:var(--t-section); font-weight:600; letter-spacing:-.02em;
  line-height:1.15; color:var(--ink-hi); text-wrap:balance;
}
[data-quiet] .find .name{font-size:var(--t-small-head)}
/* Цитата — то единственное на карточке, что человек может сверить со
   своей перепиской: «он говорит именно так». Не самая мелкая и не самая
   бледная строка карточки — это сторожит layout-check («Цитата на
   карточке»). С 30.09 она Onest 500, 16px, самым сильным цветом текста
   (решение владельца: моноширинного нет). Крупнее названия приёма не
   делается: название — 24px. */
.find .hit{margin:0 0 12px; font-size:16px; line-height:1.4; font-weight:500; color:var(--ink-hi)}
.find .why{margin:0 0 14px; font-size:14.5px; color:var(--ink)}
/* «Как ответить» — нейтральная вставка, не зелёная: зелёный здесь читался
   как «правильный ответ», а это совет (решение владельца). Прижата к низу
   карточки — в карусели карточки одной высоты, и советы стоят в ряд. */
.find .fix{
  margin:auto 0 0; font-size:14.5px; color:var(--ink); background:var(--fix-bg);
  border:1px solid var(--fix-line); border-radius:18px; padding:11px 13px;
}
.find .more{
  align-self:flex-start; display:inline-flex; align-items:center; min-height:44px;
  margin-top:4px; font-size:14px; color:var(--ink);
  text-decoration:underline; text-underline-offset:3px;
}
@media (hover:hover) and (pointer:fine){
  .find .more:hover, .alarm .more:hover{color:var(--ink-hi); text-decoration-thickness:2px}
}
/* Сообщения отчёта без находок — «Кто здесь ты?» и «Ничего не нашлось» —
   плоские: свечение значит «приём», а здесь приёма нет. */
.group.none{background:var(--surface); border:1px solid var(--line); border-radius:var(--r-block); padding:16px}
.group.unmarked .name, .group.none .name{font-size:var(--t-small-head); margin-bottom:8px}
.group.unmarked .why, .group.none .why{margin-bottom:0}

/* Карточки отчёта не анимируются (решение владельца 09.10: «Новый разбор»
   спокойнее, ничего не летает). Раньше они вставали по очереди с анимацией
   `rise`; сторожит look-check («Карусель»): у карточки `animation-name`
   равен `none` и без «уменьшить движение». Тревожный блок не анимировался
   и раньше. */

/* «Стоп» нарочно выпадает из системы: плоский, прямые углы (2px), рамка по
   всему контуру, без свечения и без появления — решение владельца. Всё
   остальное в приложении скруглено и светится; этот блок — нет, и потому
   его не спутать ни с чем. Рамка к фону блока 5.10:1 в светлой, 3.59 в
   тёмной; заголовок — самым сильным цветом текста. */
.alarm{
  background:var(--alarm-bg); border:1px solid var(--alarm-rule);
  border-radius:var(--r-flat); padding:16px 17px;
}
.alarm h3{margin:0 0 8px; font-size:var(--t-small-head); font-weight:600; letter-spacing:-.01em; line-height:1.25; color:var(--ink-hi)}
.alarm p{margin:0 0 8px; font-size:14px} .alarm p:last-child{margin:0}
.alarm ol{margin:0; padding-left:19px; font-size:14px}
/* Абзац после списка — оговорка шпаргалки про угрозу его жизни. */
.alarm ol + p{margin-top:8px}

/* Её блок помощи — когда о кризисе пишет она сама (js/chat.js, `еёБлокHTML`,
   решение владельца 01.10). Нарочно НЕ похож на «стоп»: скруглён, как всё
   спокойное в приложении, её холодным цветом и без красного; и не похож на
   карточку приёма — без свечения (свечение значит «приём», а здесь приёма
   нет). В тихом режиме — графит (`--help-*` в обоих тихих слоях: тёмная
   тема сильнее [data-quiet], капкан записан выше). Без движения, как и
   «стоп». Сторожит look-check («её блок помощи»), контраст — contrast-check. */
.help-her{
  background:var(--help-bg); border:1px solid var(--help-line);
  border-radius:var(--r-block); padding:16px 17px;
}
.help-her h3{margin:0 0 8px; font-size:var(--t-small-head); font-weight:600; letter-spacing:-.01em; line-height:1.25; color:var(--ink-hi); text-wrap:balance}
/* `pretty` — без висячего слова: на 375 «Ты не одна.» рвалось так, что
   «одна.» оставалось одно на строке (снимок 01.10). */
.help-her p{margin:0 0 8px; font-size:14.5px; color:var(--ink); text-wrap:pretty}
.help-her p:last-child{margin:0}
.help-her ul{margin:0 0 8px; padding-left:19px; font-size:14.5px; color:var(--ink); text-wrap:pretty}
.help-her ul:last-child{margin:0}
.help-her li + li{margin-top:4px}
/* Фокус приходит на блок после её ответа на вопрос (кнопка исчезла). */
.help-her:focus{outline:none}
.help-her:focus-visible{outline:2px solid var(--focus); outline-offset:3px}

/* Вопрос в блоке «b» — отделён тонкой линией её же цвета; ответы — обычные
   пилюли 44px, «Да, сейчас» не громче остальных: ответ необязателен. */
.her-ask{margin-top:12px; padding-top:12px; border-top:1px solid var(--help-line)}
.her-ask .her-ask-q{margin:0 0 4px; font-weight:600; color:var(--ink-hi)}
.her-ask .her-ask-note{margin:0 0 10px; font-size:13.5px; color:var(--ink)}

/* Поддержка под её блоком (решение владельца 02.10) — без поверхности:
   это продолжение блока, а не вторая карточка. Кегль тот же, цвет текста. */
.her-next{padding:0 4px}
.her-next h4{margin:0 0 6px; font-size:15px; font-weight:600; line-height:1.3; color:var(--ink-hi)}
.her-next ul{margin:0 0 6px; padding-left:19px; font-size:14.5px; color:var(--ink); text-wrap:pretty}
.her-next li + li{margin-top:4px}
.her-next p{margin:0; font-size:14.5px; color:var(--ink)}

/* Короткий план — свёрнут, подпись-раскрывашка ростом в палец (44px).
   Поля — 16px общим правилом полей ниже (Safari иначе увеличивает
   страницу при фокусе); сторожит look-check. */
.her-plan{padding:0 4px}
.her-plan > summary{
  list-style:none; cursor:pointer; display:flex; align-items:center; gap:7px;
  min-height:44px; font-size:14.5px; font-weight:500; color:var(--ink);
  text-decoration:underline; text-underline-offset:3px;
}
.her-plan > summary::-webkit-details-marker{display:none}
.her-plan > summary::after{content:"+"; font-size:15px; line-height:1; text-decoration:none}
.her-plan[open] > summary::after{content:"–"}
.her-plan-body{display:flex; flex-direction:column; gap:10px; padding:4px 0 2px}
.her-plan-body p{margin:0; font-size:13.5px; color:var(--ink)}
.her-plan-field{display:flex; flex-direction:column; gap:5px; font-size:14px; color:var(--ink)}
.her-plan-field input{
  min-width:0; min-height:44px; padding:0 var(--s-3);
  border:1px solid var(--field-line); border-radius:var(--r-pill);
  background:var(--surface); color:var(--ink); font-family:inherit;
}
.her-plan-field input:focus-visible{outline:2px solid var(--focus); outline-offset:2px}
.her-plan-status:empty{display:none}
/* `.btn` ставит display:inline-flex и перебивает [hidden]: «Удалить план»
   стоял на экране, когда удалять было нечего (снимок 02.10). */
.her-plan [hidden]{display:none}

/* Её строки об опасности от него — спокойный блок её цвета, как блок
   помощи: не «стоп» (без красного, скруглён) и не приём (без свечения). */
.her-safety{
  background:var(--help-bg); border:1px solid var(--help-line);
  border-radius:var(--r-block); padding:16px 17px;
}
.her-safety h3{margin:0 0 8px; font-size:var(--t-small-head); font-weight:600; letter-spacing:-.01em; line-height:1.25; color:var(--ink-hi); text-wrap:balance}
.her-safety p{margin:0 0 8px; font-size:14.5px; color:var(--ink); text-wrap:pretty}
.her-safety ul{margin:0; padding-left:19px; font-size:14.5px; color:var(--ink); text-wrap:pretty}
.her-safety li + li{margin-top:4px}

/* Вымотана (уровень «c»): одна строка признания над обычным разбором —
   легче блока помощи: без поверхности, тонкая линия её цвета слева. */
.her-tired{border-left:2px solid var(--help-line); padding:2px 0 2px 12px}
.her-tired p{margin:0; font-size:14.5px; color:var(--ink); text-wrap:pretty}
.her-tired p + p{margin-top:6px}

/* Вопрос о тоне (решение владельца 02.10): четыре равных ответа сеткой
   2×2 — «Не знаю» не тише «Всерьёз», ни один не главный; цель 44, текст
   переносится внутри пилюли (по-английски «In the heat of the moment» на
   320 — в две строки). Отделён линией цвета своего блока. */
.tone-ask{margin-top:12px; padding-top:12px; border-top:1px solid var(--help-line)}
.alarm .tone-ask{border-top-color:var(--field-line)}
.tone-ask .tone-q{margin:0 0 4px; font-size:14.5px; font-weight:600; color:var(--ink-hi)}
.tone-ask .tone-note{margin:0 0 10px; font-size:13.5px; color:var(--ink)}
.tone-ask .tone-note:last-child{margin:10px 0 0}
.tone-opts{display:grid; grid-template-columns:repeat(2, minmax(0, 1fr)); gap:8px}
.tone-opts .btn{width:100%; white-space:normal; text-align:center}

/* Его неоднозначная угроза до ответа — тот же плоский «стоп» по форме, но
   без цвета тревоги: рамка цвета полей. Это не «всё в порядке», а «по
   отрывку не понять» — сигнал без крика. */
.alarm-soft{border-color:var(--field-line)}
.alarm:focus, .her-tone:focus{outline:none}
.alarm:focus-visible, .her-tone:focus-visible{outline:2px solid var(--focus); outline-offset:3px}

/* «В шутку» на её словах — одна тихая строка, как «выматывает». */
.her-tone{border-left:2px solid var(--help-line); padding:2px 0 2px 12px}
.her-tone p{margin:0; font-size:14.5px; color:var(--ink); text-wrap:pretty}

/* Его угрозы повторяются — спокойный блок её цвета, как карточка об
   опасности от него: это о её ощущении, а не «стоп». */
.his-pattern{
  background:var(--help-bg); border:1px solid var(--help-line);
  border-radius:var(--r-block); padding:16px 17px;
}
.his-pattern h3{margin:0 0 8px; font-size:var(--t-small-head); font-weight:600; letter-spacing:-.01em; line-height:1.25; color:var(--ink-hi); text-wrap:balance}
.his-pattern p{margin:0 0 8px; font-size:14.5px; color:var(--ink); text-wrap:pretty}
.his-pattern ul{margin:0; padding-left:19px; font-size:14.5px; color:var(--ink); text-wrap:pretty}

/* Разбор под её словами о кризисе — под тихой ссылкой. Раскрыт — те же
   карточки, шаблон и кнопки, что всегда, с тем же шагом 12px. */
.her-later > summary{
  list-style:none; cursor:pointer; display:inline-flex; align-items:center; min-height:44px;
  padding:0 4px; font-size:14px; color:var(--ink); text-decoration:underline; text-underline-offset:3px;
}
.her-later > summary::-webkit-details-marker{display:none}
.her-later > summary .when-open, .her-later[open] > summary .when-closed{display:none}
.her-later[open] > summary .when-open{display:inline}
.her-later-body{display:flex; flex-direction:column; gap:12px; margin-top:8px}
@media (hover:hover) and (pointer:fine){
  .her-later > summary:hover, .her-plan > summary:hover{color:var(--ink-hi); text-decoration-thickness:2px}
}

.verdict{
  background:var(--surface); border:1px solid var(--line);
  border-radius:var(--r-block); padding:15px 16px;
}
.draft{
  font-family:var(--f-body); white-space:pre-wrap; background:var(--surface-2);
  border:1px solid var(--line-strong); border-radius:var(--r-xs);
  padding:13px 14px; margin:0 0 11px; font-size:14.5px;
}
.draft b{background:var(--fill-bg); color:var(--fill-ink); font-weight:500; border-radius:4px; padding:0 3px}
.note{font-size:13.5px; color:var(--muted); margin:11px 0 0}

/* Запрос в свой чат — запасной путь, а не главное действие: отделён
   от отчёта, подпись мелкая, кнопки контурные. Цели касания те же
   44px, что и у остальных: кнопка под пальцем не знает, что она
   второстепенная. Ссылка выглядит кнопкой, но остаётся ссылкой —
   на телефоне это единственный способ попасть в приложение чата. */
.handover{margin:12px 0 0; padding:11px 2px 0; border-top:1px solid var(--line)}
.handover > summary{
  list-style:none; cursor:pointer; display:flex; align-items:center; gap:7px;
  min-height:44px; font-size:13px; font-weight:500; color:var(--muted);
}
.handover > summary::-webkit-details-marker{display:none}
.handover > summary::after{content:"+"; font-size:15px; line-height:1}
.handover[open] > summary::after{content:"–"}
.handover .sign{margin:0 0 10px; display:block; line-height:1.5}
.handover .rowbtns a.btn{text-decoration:none}

/* ============================================================
   Уровень доказательности
   ============================================================ */
.ev{
  display:inline-flex; align-items:center; gap:6px;
  font-size:12px; font-weight:500; line-height:1.2;
  border:1px solid var(--line-strong); border-radius:var(--r-pill);
  padding:4px 10px; color:var(--muted);
}
.ev::before{content:""; width:6px; height:6px; border-radius:50%; background:var(--line-strong)}
.ev[data-ev="исследования"]::before{background:var(--ok)}
.ev[data-ev="практика специалистов"]::before{background:var(--muted)}
.ev[data-ev="опыт сообщества"]::before{background:var(--line-strong)}

.warnbox{
  background:var(--warn-soft); color:var(--warn-ink); border-radius:var(--r-xs);
  padding:12px 14px; font-size:13.5px; margin:12px 0;
}

/* «Похоже, но не оно» — где похожее поведение приёмом не является.
   Намеренно спокойный, не тревожный блок: это уточнение, а не сигнал. */
.notbox{
  background:var(--surface-2); border-left:3px solid var(--line-strong);
  border-radius:var(--r-xs); padding:12px 14px; margin:14px 0;
}
.notbox p{margin:0; font-size:13.5px; color:var(--ink-2)}
.notbox .kicker{margin-bottom:6px}

/* ============================================================
   Композер
   ============================================================ */
/* Только строка ввода и прикреплённые снимки. Всё остальное — чипы целей,
   предложение подключить модель, умный разбор, обещание про приватность —
   уехало в ленту: вместе они занимали 274px из 352, то есть обвес был втрое
   больше самого поля. */
.composer{
  position:absolute; left:0; right:0; bottom:var(--tabbar-h, 0px); z-index:45;
  /* Подложка НЕПРОЗРАЧНА, как у шапки и нижней панели. Был градиент от
     прозрачного к фону с полной непрозрачностью только к 55% высоты — а
     белая пилюля поля начинается на 12-м пикселе: вокруг неё просвечивало
     то, что под ней, и карточка разбора читалась обрезанной по кромке, с
     красной полоской важности сбоку от пилюли. Растворение делает ::before
     НАД композером, не меняя его высоты: её меряет js/layout.js.
     Сетка точек совмещена с сеткой окна: верх композера в окне — высота
     окна минус --composer-h (он сам плюс панель под ним). */
  background:
    radial-gradient(circle at 1px 1px, var(--bg-dot) 1px, transparent 1.5px)
      0 calc(var(--composer-h, 160px) - var(--app-h, 100dvh))/14px 14px,
    var(--bg);
  padding:12px 16px 8px;  /* безопасную зону снизу держит таббар под композером */
}
/* Та же колонка, что у содержимого и нижней панели. Стоит ЗДЕСЬ, а не в
   общем медиазапросе выше: там правило перебивалось базовым `left:0` из
   блока над ним, и композер уезжал на полширины влево. */
@media (min-width:601px){
  .composer{ left:50%; right:auto; width:600px; transform:translateX(-50%) }
}
.composer::before{
  content:""; position:absolute; left:0; right:0; bottom:100%; height:24px;
  pointer-events:none;
  background:linear-gradient(to top, var(--bg), color-mix(in srgb, var(--bg) 0%, transparent));
}
.composer .inner{max-width:600px; margin:0 auto}
.goals{display:flex; gap:7px; overflow-x:auto; padding-bottom:9px; scrollbar-width:none}
.goals::-webkit-scrollbar{display:none}
.goals .chip{cursor:pointer; border:1px solid var(--tint-line); background:var(--tint); color:var(--ink-2)}
.goals .chip[aria-pressed="true"]{background:var(--accent); border-color:var(--accent); color:var(--accent-contrast); font-weight:500}
/* Строка чата: плюс слева, поле, отправка справа */
/* Рамка поля — --field-line: граница того, куда печатать, обязана быть
   видна (3.41:1 к фону), а не угадываться по тени, как было. */
.chatbar{
  display:flex; gap:6px; align-items:flex-end; background:var(--surface);
  border:1px solid var(--field-line); border-radius:var(--r-pill);
  padding:5px;
}
.chatbar:has(textarea:focus-visible){outline:2px solid var(--focus); outline-offset:3px}
/* Пока текст в одну строку — скруглять пилюлей; как только поле выросло,
   углы смягчаются, иначе многострочный ввод выглядит стадионом. */
.chatbar:has(textarea:not(:placeholder-shown)){border-radius:var(--r-lg)}
.chat-plus, .chat-send{
  flex:none; width:44px; height:44px; padding:0; border-radius:50%;
  display:grid; place-items:center; cursor:pointer; border:1px solid transparent;
  transition:opacity .15s, transform .15s var(--ease-out);
}
.chat-plus{background:var(--tint); border-color:var(--tint-line); color:var(--ink)}
@media (hover:hover){.chat-plus:hover{background:var(--tint-hover)}}
.chat-send{background:var(--accent); border-color:var(--accent); color:var(--accent-contrast)}
@media (hover:hover){.chat-send:hover{opacity:.9}}
.chat-plus svg, .chat-send svg{width:19px; height:19px}
/* ШЕСТНАДЦАТЬ ПИКСЕЛЕЙ — НЕ ВКУСОВЩИНА.

   Safari на айфоне увеличивает всю страницу при нажатии на любое поле,
   где шрифт меньше 16px. Порог жёсткий, обойти его нельзя, а масштаб
   обратно Safari не возвращает — страница так и остаётся увеличенной.

   Дальше это ломало раскладку: при масштабе больше единицы visualViewport
   отдаёт схлопнутую высоту, подъём полосы считается от неё, и композер
   уезжал за верхнюю кромку. То есть «поле мельче 16px» и «композер улетает
   при нажатии» — одна поломка, и начинается она здесь. Было 15px.

   Любое новое поле ввода в приложении обязано быть не мельче; это сторожит
   проверка в layout-check. */
textarea, input:not([type=file]):not([type=hidden]):not([type=checkbox]):not([type=radio]){
  font-size:16px;
}
textarea{
  flex:1; border:0; resize:none; background:transparent; color:var(--ink);
  font-family:inherit; padding:11px 2px; max-height:140px; min-height:44px;
  line-height:1.45; box-sizing:border-box;
}
textarea:focus{outline:none}

/* ============================================================
   Клавиатура открыта.

   Экран ужимается примерно втрое: из 667 остаётся около 336. Всё, что
   не строка ввода и не лента, в этом состоянии только мешает — человек
   печатает, а не выбирает раздел и не читает обещания. Панель уходит,
   обвес под лентой уходит, композер встаёт вплотную над клавиатурой.
   ============================================================ */
:root.kb-open .tabbar{display:none}
:root.kb-open .belowthread{display:none}
:root.kb-open .composer{bottom:0; padding-top:8px}
/* Экран ужат втрое, а обещание к этому моменту уже прочитано: держать под
   полем 34px ради контрола, который переопределяет то, что и так
   определяется само, — плохая сделка. Окно чтения 153px против 193. */
:root.kb-open .composer .slot{display:none}

/* Убрать клавиатуру, не отправляя написанное. Появляется только когда
   клавиатура открыта: иначе это кнопка, которая ничего не делает.

   Прицеплена к композеру абсолютом, а не стоит в своей системе координат:
   композер уже считается по визуальному вьюпорту, и отстать от него кнопка
   не может. Отсчитанная отдельно, через --composer-h, она уезжала на
   top −123 — за верхнюю кромку экрана, невидимая и ненажимаемая. */
.kb-down{
  display:none; position:absolute; z-index:46;
  left:50%; top:-52px; transform:translateX(-50%);
  width:44px; height:44px; padding:0; border-radius:50%;
  border:1px solid var(--field-line); background:var(--surface); color:var(--ink);
  cursor:pointer; place-items:center;
}
/* Кнопка поднята над композером на 52px и лежит поверх страницы, а низ
   ленты рассчитан только на композер: замерено при клавиатуре на 375×667
   — кнопка занимает 242–286, а лента кончается на 313, то есть кнопка
   садится прямо на последние строки разбора. Это единственное состояние,
   где экран ужат втрое и каждая строка на счету. 60 = подъём 52 + зазор. */
:root.kb-open .shell{padding-bottom:calc(var(--composer-h, 90px) + 60px)}
:root.kb-open .kb-down{display:grid}
.kb-down svg{width:21px; height:21px}
@media (hover:hover){.kb-down:hover{background:var(--surface-2); color:var(--ink)}}

/* Обвес под лентой: то, что раньше висело в композере. Прокручивается вместе
   с разбором, поэтому не претендует на экран, пока человек читает. */
.belowthread{display:flex; flex-direction:column; gap:var(--s-3); margin-top:var(--s-5)}
.belowthread:empty{display:none}
.belowthread .goals{margin:0}

/* Пустой блок вложений съедал 8px в каждом состоянии: [hidden] — стиль
   браузера, он слабее класса .attachments{display:flex}, и атрибут ничего
   не прятал. */
.attachments[hidden]{display:none}

/* ------------------------------------------------------------
   Подпись под полем: одна строка на две работы.
   Поле пустое — обещание, ради которого человек решается вставить
   переписку. Появился текст — чипы целей: цель выбирают перед
   отправкой, а пока пусто, выбирать нечего. Обмен идёт на :has(),
   тем же приёмом, каким рядом скругляется .chatbar.
   ------------------------------------------------------------ */
.composer .slot{min-height:34px; margin-top:6px; display:flex; align-items:center}
.composer .slot > *{margin:0; width:100%; min-width:0}
.composer .slot .goals{
  display:none; padding:0; gap:6px;
  /* Пять чипов не влезают: 524px при 343 доступных. Видно три из пяти на
     375 и 360. Обрез должен быть виден, иначе последние чипы для человека
     не существуют вовсе. */
  -webkit-mask-image:linear-gradient(to right, #000 calc(100% - 28px), transparent);
          mask-image:linear-gradient(to right, #000 calc(100% - 28px), transparent);
}
/* 44px — то же правило, что у всех кнопок приложения: у чипа есть своя
   поверхность (фон и рамка), значит он под правило попадает. Было 34, и не
   мерил их никто: чипы показываются только при непустом поле, а обход целей
   пальца ходил по экрану с очищенным — целый ряд кнопок мимо прибора.
   Цена замерена и мала: композер в этом состоянии и так прыгает с 77 на 117,
   когда она набирает первый знак после отчёта; здесь прибавляется 10. */
.composer .slot .goals .chip{min-height:44px; padding:6px 13px; font-size:12.5px}
.composer .privacy{font-size:12.5px; line-height:1.25; margin:0; text-align:center}
.composer .inner:has(#chat-input:not(:placeholder-shown)) .slot .goals{display:flex}
.composer .inner:has(#chat-input:not(:placeholder-shown)) .slot .privacy{display:none}
/* …кроме того случая, когда менять обещание не на что. До первого отчёта
   чипы целей спрятаны (applyOffers), и правило выше оставляло под полем
   тридцать четыре пикселя пустоты ровно тогда, когда женщина вставила
   переписку и решает, отправлять ли. Метку ставит applyOffers. */
.composer.no-goals .inner:has(#chat-input:not(:placeholder-shown)) .slot .privacy{display:block}

/* Обещание приватности живёт под полем ровно до первого разбора.

   Дальше оно прочитано, а полоса под композером продолжает занимать сорок
   пикселей — на телефоне это две строки самого сообщения, которых из-за неё
   не видно. Прячется весь слот, а не только текст: пустой слот держит
   min-height и отступ, то есть занимает место, ничего не показывая.

   Чипы целей это не задевает: они появляются, когда в поле есть текст, и
   тогда слот снова нужен. */
:root.thread-filled .composer .inner:has(#chat-input:placeholder-shown) .slot{display:none}

/* Выбор диалога в ленте вместо серого системного окна. */
.convpick p{margin:0 0 var(--s-2); font-size:14px}
.convpick .msg-actions{flex-wrap:wrap}
.convnew{display:flex; gap:var(--s-2); margin-top:var(--s-2)}
.convnew input{
  flex:1; min-width:0; min-height:44px; padding:0 var(--s-3);
  border:1px solid var(--field-line); border-radius:var(--r-pill);
  background:var(--surface); color:var(--ink); font-family:inherit;
}
.convnew input:focus-visible{outline:2px solid var(--focus); outline-offset:2px}

/* Поле для ключа модели — в самом блоке способа, а не в системном окне.

   Кегль 16px обязателен и не наследуется случайно: Safari на айфоне
   увеличивает страницу при фокусе на поле мельче 16px и масштаб обратно
   НЕ возвращает, а увеличенная страница ломает раскладку — у неё
   `visualViewport.height` схлопывается пропорционально масштабу. */
.keyform{display:flex; flex-wrap:wrap; gap:var(--s-2); margin-top:var(--s-3)}
.keyform input{
  flex:1; min-width:0; min-height:44px; padding:0 var(--s-3); font-size:16px;
  border:1px solid var(--field-line); border-radius:var(--r-pill);
  background:var(--surface); color:var(--ink); font-family:inherit;
}
.keyform input:focus-visible{outline:2px solid var(--focus); outline-offset:2px}

/* Поле имени диалога в архиве — там же, где кнопка, а не в системном окне.
   Кегль 16px по той же причине, что и у поля ключа. */
.nameform{display:flex; flex-wrap:wrap; gap:var(--s-2); margin-top:var(--s-2)}
.nameform input{
  flex:1 1 100%; min-width:0; min-height:44px; padding:0 var(--s-3); font-size:16px;
  border:1px solid var(--field-line); border-radius:var(--r-pill);
  background:var(--surface); color:var(--ink); font-family:inherit;
}
.nameform input:focus-visible{outline:2px solid var(--focus); outline-offset:2px}

/* Подложка в шаблоне — настоящее поле, и выглядеть должна как поле.

   Прежде это были просто жёлтые буквы: человек тапала, ничего не
   происходило, и в буфер уходил текст с квадратными скобками. Пунктирный
   низ говорит «сюда писать», а не «тут выделено». */
.draft .fillme{
  background:var(--mark-bg); color:var(--mark-fg);
  border-bottom:1.5px dashed currentColor; border-radius:3px;
  padding:0 3px; font-weight:500; cursor:text;
  /* Заполненная подложка перестаёт звать: дело сделано. */
  &:focus{outline:2px solid var(--focus); outline-offset:1px}
}

/* Разбор без подписей: сказано, чего приложение НЕ сделало.

   Приглушённая рамка, а не тревожная: это не беда, а ограничение, и
   пугать им человека, которая только что вставила свою переписку, нельзя.
   Но и потеряться среди находок оно не должно — отсюда своя рамка. */
.group.unmarked{
  border:1px dashed var(--line-strong); border-radius:var(--r-md);
  padding:var(--s-3); background:var(--surface-2);
}
.group.unmarked .name{color:var(--ink-2)}
.group.unmarked .why{margin-top:var(--s-1)}

/* Прикреплённые скриншоты до отправки */
.attachments{display:flex; gap:7px; flex-wrap:wrap; padding-bottom:8px}
.att{position:relative; width:58px; height:58px; border-radius:var(--r-sm); overflow:hidden;
  border:1px solid var(--line); background:var(--surface-2)}
.att img{width:100%; height:100%; object-fit:cover; display:block}
.att-x{
  position:absolute; top:2px; right:2px; width:26px; height:26px; padding:0;
  border:0; border-radius:50%; background:rgba(0,0,0,.62); color:#fff;
  font-size:15px; line-height:1; cursor:pointer; display:grid; place-items:center;
}
#chat.dropping{outline:2px dashed var(--accent); outline-offset:8px; border-radius:var(--r-md)}
/* Единственная строка, отвечающая на «безопасно ли по ней нажимать», а
   набрана была самым мелким кеглем на экране — мельче дисклеймера (12px).
   Экран часто смотрят с общего телефона; обещание должно быть читаемым. */
.privacy{
  font-size:12.5px; color:var(--muted); text-align:center;
  margin:var(--s-3) 0 0; text-wrap:balance;
}

.local-slot .bar{height:4px; border-radius:2px; background:var(--surface-2); margin:22px 0 6px; position:relative}
/* Без перехода по ширине: ширину ставит каждое событие загрузки, и переход
   раскладывал бы полосу заново в каждом кадре. Движется только зверёк. */
.local-slot .bar i{display:block; height:100%; background:var(--accent); border-radius:2px; position:relative}
.local-slot .status{font-size:12px; color:var(--muted)}

/* Включение смыслового разбора и его прогресс */
.smart{margin-top:9px; text-align:center}
.smart button{
  font-family:var(--f-body); font-size:13px; font-weight:500; cursor:pointer;
  border:1px solid var(--tint-line); background:var(--tint); color:var(--ink);
  border-radius:var(--r-pill); min-height:44px; padding:0 18px;
  transition:opacity .15s, transform .15s var(--ease-out);
}
@media (hover:hover){.smart button:hover{background:var(--tint-hover)}}
.smart .bar{height:4px; border-radius:2px; background:var(--surface-2); margin:22px 0 5px; position:relative}
.smart .bar i{display:block; height:100%; background:var(--accent); border-radius:2px; position:relative}

/* ------------------------------------------------------------
   Маскот на полосе загрузки

   Он сидит ВНУТРИ заливки, на её переднем крае, — и едет сам, без второго
   счётчика процентов: заливка уже знает, сколько скачано. Отсюда и
   `overflow` у полосы снят, а скругление осталось на самой заливке: иначе
   зверёк обрезался бы по четырём пикселям высоты.

   Бежит он там, где бег что-то значит. Слой смысла — это 112 мегабайт и
   минуты ожидания, про которые в памяти проекта записано, что человек
   смотрит на неподвижную полосу и решает, что всё зависло. Ни на разборе,
   ни в тесте, ни на экране восстановления его нет и быть не должно.
   ------------------------------------------------------------ */
.pet{
  position:absolute; right:-10px; bottom:1px; width:20px; height:20px;
  color:var(--ink-2); pointer-events:none;
}
.pet svg{display:block; width:100%; height:100%}
.bar i .pet{animation:pet-hop .62s ease-in-out infinite}
@keyframes pet-hop{
  0%,100%{transform:translateY(0) rotate(-4deg)}
  50%{transform:translateY(-3px) rotate(4deg)}
}
/* Уставшему от движения экран не дёргается: зверёк просто едет с полосой. */
@media (prefers-reduced-motion:reduce){
  .bar i .pet{animation:none}
}
/* Вне полосы он стоит в строке, а не висит: `position:absolute` там
   вырвало бы его из потока и посадило в угол коробки.

   Селектор `.smart .on`, а НЕ голый `.on`: `on` — это класс активной
   ПАНЕЛИ (`.pane.on`), и правило по нему ловило каждого зверька на
   экране, в том числе того, что едет на полосе. Поймано на снимке: он
   висел под полосой вместо того, чтобы стоять на ней. */
.smart .on .pet, .empty .pet, .q-nav .pet{
  position:static; display:inline-block; vertical-align:-5px; margin-right:6px;
}
.empty .pet{width:26px; height:26px; vertical-align:-7px}

/* ---------- Зверёк у композера: убран 09.10 ----------
   Решение владельца: «Новый разбор» спокойнее — на экране разбора зверька
   нет вовсе (ни до отчёта, ни после), как нет и анимации `rise` у карточек
   находок. Разметка `#pet-chat` из index.html удалена; сторожит layout-check
   («МАСКОТ»). Метки `report-shown` и `pet-busy` на корне остаются (js/chat.js
   `draw`): их читают проверки, а стили для них больше не нужны. Зверёк
   остался там, где ждут и нечего делать: полоса загрузки, пустой архив,
   тест. */
.chatbar{position:relative; z-index:1}

@keyframes pet-tap{
  0%{transform:scaleX(1.12) scaleY(.88)}
  40%{transform:translateY(-6px)}
  100%{transform:translateY(0)}
}

/* ---------- Зверёк в тесте ----------
   Флекс-элементом ряда, а не абсолютом: замерено, ряд остаётся 52px, а
   на 375×568 до нижней панели от него всего 21px — всё, что добавит
   высоту, ляжет под панель. `margin-left:auto` переезжает с кнопки на
   зверька, иначе они оба уедут вправо и слипнутся. */
.q-nav .pet{
  display:block; width:30px; height:30px; flex:none; margin:0 0 0 auto;
  vertical-align:0; pointer-events:auto; touch-action:manipulation;
  transform-origin:50% 100%;
}
.q-nav:has(.pet) .q-next{margin-left:0}
.pet-in{animation:pet-in .26s ease-out, pet-hop .62s ease-in-out .26s 1}
.pet-nod{animation:pet-nod .36s ease-in-out}
.pet-quiz.pet-tap{animation:pet-tap .48s cubic-bezier(.34,1.3,.64,1)}
@keyframes pet-in{
  from{transform:translateY(6px); opacity:0}
  to{transform:translateY(0); opacity:1}
}
@keyframes pet-nod{
  0%,100%{transform:rotate(0)}
  30%{transform:rotate(-6deg)}
  70%{transform:rotate(6deg)}
}

/* Уставшему от движения зверёк остаётся рисунком: движение ему гасит общее
   правило `*{animation:none !important}` ниже, своего у зверька для этого
   нет и не надо. */
.smart .status{font-size:11px; color:var(--muted)}
.smart .on{color:var(--ok); font-size:11.5px}

/* Находка по смыслу: помечаем, что это похожесть, а не точная фраза */
.bymeaning{font-size:12px; font-weight:500; color:var(--muted); margin:0 0 7px}

/* ============================================================
   Архив
   ============================================================ */
.convlist{display:flex; flex-direction:column; gap:10px}
.linkbtn{
  margin-left:auto; border:0; background:none; padding:6px 0; min-height:24px;
  font-family:var(--f-body); font-size:11.5px; color:var(--muted);
  text-decoration:underline; text-underline-offset:3px; cursor:pointer;
}
/* У `.linkbtn` две роли. Три из четырёх — слово внутри строки («Тест уже
   пройден. Пройти заново»), и палец там целится в строку, а не в кнопку.
   Четвёртая, «Удалить» в шапке записи архива, стоит одна и справа: это
   самостоятельная кнопка, и мимо 26px палец промахивается ровно так же,
   как мимо пилюли той же высоты. Цель растится до 44, вид остаётся
   ссылочным — поверхности у неё по-прежнему нет. Запись от этого не
   становится выше: в шапке уже было 49px при кнопке в 26, отступы
   ужимаются на ту же величину (замерено: 49 до, 51 после). */
.entry > header .linkbtn{min-height:44px; padding:0 8px; margin-left:auto; font-size:13.5px}
@media (hover:hover){.linkbtn:hover{color:var(--ink)}}
/* Вход в тест с главной — цель пальца, а не строчка текста. Был 26px при
   44 у всего остального в приложении, и рядом с ним «Новый разбор» во всю
   ширину: самый дешёвый первый шаг выглядел самым мелким. Правило узкое —
   `.linkbtn` в ленте разбора и в архиве остаётся строчной ссылкой. */
#home-quiz .linkbtn{min-height:44px; display:inline-flex; align-items:center}

/* ============================================================
   Тест — один вопрос на экран

   Кнопка «Дальше» стоит на одном месте и не прыгает вслед за длиной
   отклика: под стрессом переезжающая кнопка читается как сбой. Цели
   касания — 48 и 52 px вместо прежних 38: промах по варианту ответа
   на телефоне стоит дороже, чем лишние десять пикселей.
   ============================================================ */
/* Заголовок раздела и лид — во весь рост только на входе. Внутри воронки они
   не меняются двенадцать экранов подряд, а вопрос при этом на 40% мельче:
   взгляд под стрессом идёт на самое крупное, то есть каждый раз на подпись.
   Замер на 375×667: шапка занимала 224px из 667, вопрос начинался на 285-м. */
#quiz:has(.q-txt) h1.screen,
#quiz:has(.q-h) h1.screen{
  font-size:15px; font-weight:600; letter-spacing:0; line-height:1.3;
  color:var(--muted); margin:0 0 var(--s-3);
}
#quiz:has(.q-txt) .lede,
#quiz:has(.q-h) .lede{display:none}
/* …кроме самого первого экрана. Правило выше прячет лид при наличии вопроса,
   а вопрос на экране есть ВСЕГДА — то есть лид не видел никто и никогда, и
   вместе с ним пропало единственное место, где названа длина теста и сказано,
   что ответы остаются на устройстве. Заявленная длина — самый сильный
   измеренный рычаг на входе в опрос. */
/* Отступ сверху, а не снизу: лид переехал под вопрос (см. index.html).
   Отступ и длина текста считаны: на 360×640 весь входной экран вместе с
   лидом обязан уложиться до нижней панели, иначе обещание, ради которого
   он тут стоит, кончается под ней. */
#quiz[data-step="start"] .lede{display:block; margin:var(--s-3) 0 0}
/* Оговорка «не заменяет врача, психолога или юриста» — под лидом, тем же
   правилом: видна на первом экране, уходит с первым ответом. Прячет её
   атрибут hidden из js/app.js; стиль здесь только ставит на место. Одна
   строка намеренно: на 360×640 под лидом запаса почти нет, и то, что не
   влезет, уйдёт под нижнюю панель — оболочка прокручивается, но первый
   взгляд её не увидит. */
#quiz .q-foot{margin:var(--s-1) 0 0; font-size:12.5px; line-height:1.35}
#quiz .q-foot[hidden]{display:none}

/* Полоса прогресса: разница между «отвечено» и «нет» была 1.27:1 при норме
   3:1 — в тёмной теме двенадцать сегментов сливались в одну линию. */
/* Одна линия, без делений: делений двенадцать — это и есть «сколько
   вопросов», а полоса не должна их называть. Ход нелинейный, считается в
   js/app.js. Перехода по ширине нет: полоса рисуется заново с каждым
   вопросом, и прежний `transition:width` не срабатывал ни разу, а сработай
   он — раскладывал бы экран в каждом кадре. Движется в приложении только
   прозрачность и масштаб (сторожит look-check). */
.qbar{
  height:5px; border-radius:2.5px; background:var(--line-strong);
  margin:0 0 var(--s-3); overflow:hidden;
}
.qbar i{
  display:block; height:100%; width:0; border-radius:2.5px;
  background:var(--accent);
}
/* Номер вопроса — единственный буквальный ответ на «где я», а был самой
   мелкой типографикой экрана (11px --muted). Полоса выше теперь набрана
   --ink-2; номер берёт тот же цвет, и пара «полоса + номер» читается одним
   узлом навигации, а не подписью к нему. */
.qnum{font-size:12.5px; font-weight:500; color:var(--ink-2); margin:0 0 var(--s-3)}
.q-resume{font-size:12.5px; color:var(--muted); margin:0 0 var(--s-2)}
.q-resume .linkbtn{margin-left:0}
.q-txt{
  font-size:22px; font-weight:500; letter-spacing:-.015em; line-height:1.3; color:var(--ink-hi);
  margin:0 0 var(--s-4); outline:none;
}
.q-txt:focus-visible{outline:2px solid var(--focus); outline-offset:4px}
.opts{display:grid; grid-template-columns:repeat(3,1fr); gap:var(--s-2)}
/* Пилюля, как у всех кнопочных поверхностей приложения (.btn, .iconbtn,
   .chip, .badge, вкладки, композер). Кнопки теста были
   единственным исключением на весь файл — а первый экран приложения это
   первый вопрос теста, то есть знакомство шло по форме, которой больше
   нигде нет. Геометрия не меняется: 109×48 остаётся 109×48. */
.opts button{
  font-family:var(--f-body); font-size:14px; min-height:48px; padding:9px 4px;
  cursor:pointer; border:1px solid var(--line-strong); border-radius:var(--r-pill);
  background:var(--surface); color:var(--ink);
}
.opts button[aria-pressed="true"]{
  background:var(--accent); border-color:var(--accent);
  color:var(--accent-contrast); font-weight:600;
}
.q-feedback{min-height:76px; margin:var(--s-3) 0 0}
.q-feedback p{margin:0 0 6px; font-size:14px} .q-feedback p:last-child{margin:0}
.q-dim{color:var(--muted); font-size:13px}
/* Подпись про частоту объясняет варианты ответа, а стояла от них на тех же
   13px, что и до отклика, — то есть висела третьим элементом сама по себе.
   Прижата к вариантам: это подпись к ним, а не строка экрана. */
.q-scale{margin:var(--s-2) 0 0; line-height:1.4}
.q-nav{display:flex; align-items:center; gap:10px; margin:var(--s-4) 0 0}
/* Низкий экран — это не старый телефон, это ОБЫЧНЫЙ телефон в браузере.
   С домашнего экрана 375×667 отдаёт все 667, а в Safari строка адреса
   забирает 70–100: живая высота там 560–600. Замерено на первом экране
   теста: лид кончается на 547, а нижняя панель при высоте 600 начинается
   с 531 и при 568 — с 499. То есть обещание «двенадцать утверждений,
   минуты две» — единственное место, где названа длина теста, и, по
   замеру, самый сильный рычаг на входе в опрос — лежало под панелью у
   всякого, кто открыл приложение ссылкой, а не установил. А ссылкой его
   открывают все и всегда в первый раз.

   Съедается это отступами, а не кеглем: вопрос и варианты не трогаются.
   На 320×568 сверх того прячется подпись раздела — она видна двенадцать
   экранов подряд и там дороже места, которое занимает; прячется в `.sr`,
   а не `display:none`, чтобы остаться для читалки с экрана. */
@media (max-height:620px){
  #quiz .qbar{margin-bottom:var(--s-2)}
  #quiz .q-txt{margin-bottom:var(--s-3)}
  #quiz .q-feedback{margin-top:var(--s-2)}
  #quiz .q-nav{margin-top:var(--s-3)}
  #quiz[data-step="start"] .lede{margin-top:var(--s-2)}
  #quiz:has(.q-txt) h1.screen,
  #quiz:has(.q-h) h1.screen{margin-bottom:var(--s-2)}
}
@media (max-height:580px){
  #quiz .q-txt{margin-bottom:var(--s-2)}
  #quiz[data-step="start"] .lede{margin-top:var(--s-1)}
  #quiz:has(.q-txt) h1.screen,
  #quiz:has(.q-h) h1.screen{
    position:absolute; width:1px; height:1px; margin:-1px; padding:0;
    overflow:hidden; clip:rect(0 0 0 0); white-space:nowrap; border:0;
  }
}
.back{
  border:0; background:none; padding:8px 0; min-height:44px; cursor:pointer;
  font-family:var(--f-body); font-size:14px; color:var(--ink-2);
}
/* Выход липнет под шапкой на экранах, где нижней панели нет.

   Замерено на 375×667: карточка приёма — 2797px прокрутки, экран «Место и
   данные» — 2821, и на обоих единственный выход уезжал на −2039 и −2063.
   В приложении, поставленном на домашний экран, ни строки адреса, ни
   кнопки «назад» у браузера нет — выйти было нечем, кроме прокрутки на
   две тысячи пикселей вверх.

   Проверка на «выход есть» при этом была зелёной: она спрашивала, есть ли
   кнопка, а не достанет ли до неё палец. Это ровно тот способ обмануться,
   который записан в памяти проекта первым.

   Правило узкое: в тесте `.back` стоит в ряду с «Дальше» и липнуть не
   должен, поэтому только прямые дети трёх панелей. */
#detail > .back, #settings > .back, #archive > .back{
  position:sticky; top:var(--topbar-h, 71px); z-index:39;
  /* Сетка совмещена с сеткой окна: полоса стоит на высоте шапки. */
  background:
    radial-gradient(circle at 1px 1px, var(--bg-dot) 1px, transparent 1.5px)
      0 calc(-1 * var(--topbar-h, 71px))/14px 14px,
    var(--bg);
  margin:0 -16px 4px; padding:8px 16px;
  width:calc(100% + 32px); text-align:left;
}
/* Растворение под липким выходом — тем же способом, что у шапки и по той
   же причине: без него текст и кромки карточек режутся по нижней границе
   полосы, и на снимках это читается не как слой, а как сбой отрисовки. */
#detail > .back::after, #settings > .back::after, #archive > .back::after{
  content:""; position:absolute; left:0; right:0; top:100%; height:14px;
  pointer-events:none;
  background:linear-gradient(to bottom, var(--bg), color-mix(in srgb, var(--bg) 0%, transparent));
}
@media (hover:hover){.back:hover{color:var(--ink)}}
.q-next{
  margin-left:auto; min-height:52px; min-width:132px; padding:0 22px; cursor:pointer;
  font-family:var(--f-body); font-size:15px; font-weight:600;
  border:1px solid var(--accent); border-radius:var(--r-pill);
  background:var(--accent); color:var(--accent-contrast);
}
.q-next[disabled]{
  background:transparent; border:1px solid var(--line-strong);
  color:var(--muted); cursor:default; font-weight:500;
}

/* Результат: балл вторым планом, действие первым. */
.q-h{font-size:21px; font-weight:600; letter-spacing:-.015em; line-height:1.3; margin:0 0 var(--s-3)}
.score{
  background:var(--surface); border:1px solid var(--line);
  border-radius:var(--r-block); padding:18px; margin:16px 0;
}
.score .big{
  font-weight:600; font-size:38px; line-height:1; letter-spacing:-.02em;
  font-variant-numeric:tabular-nums; color:var(--ink-hi);
}
.score .big small{font-size:16px; font-weight:500; color:var(--muted)}
.score-sm{padding:13px 15px; margin:0 0 var(--s-4)}
.score-sm .big{font-size:22px; color:var(--muted)}
.score-sm .big small{font-size:13px}
.score h3{font-family:var(--f-display); margin:12px 0 7px; font-size:17px}
.score p{margin:0 0 8px; font-size:14px} .score p:last-child{margin:0}
.meter{height:6px; border-radius:3px; background:var(--surface-2); overflow:hidden; margin:13px 0 0}
.meter i{display:block; height:100%; background:var(--accent); border-radius:3px}
/* Линия цитаты была --line-strong: 1.36:1 в светлой, 1.74 в тёмной — блок
   читался абзацем со случайным отступом, причина отступа не видна. Цвет линии
   не акцентный намеренно: акцент на этом экране оставлен блоку безопасности. */
.q-effects{
  font-size:14px; border-left:2px solid var(--muted);
  padding-left:13px; margin:var(--s-4) 0; color:var(--ink);
}
.q-cta{
  background:var(--surface); border:1px solid var(--line-strong);
  border-radius:var(--r-md); padding:var(--s-4); margin:var(--s-6) 0;
}
.q-cta p:first-child{margin:0 0 var(--s-3); font-size:14.5px}
.q-cta .btn{width:100%; margin-bottom:var(--s-2)}
.q-cta .privacy{margin:var(--s-1) 0 0}
#quiz h3{font-family:var(--f-display); font-size:16px; margin:20px 0 9px}
#quiz-stage .alarm{
  margin:var(--s-5) 0; padding:17px 18px;
  font-size:15px; line-height:1.5;
}
#quiz .alarm h3{margin:0 0 7px; font-size:16px}
/* Тот же низкий экран, но экран РЕЗУЛЬТАТА. Главная кнопка там —
   конверсия всей воронки, и на верхнем уровне её отодвигает блок
   безопасности: он стоит выше кнопки и это правильно. Замерено на
   375×568: кнопка вставала на 513…558 при панели с 499, то есть под
   ней целиком, и нажать её было нельзя. Съедается отступами вокруг
   блоков, а не их содержимым: на этом экране нет ни одного лишнего
   слова, и сокращать надо воздух.

   Блок стоит ЗДЕСЬ, ниже базовых правил, а не рядом с остальными
   медиазапросами теста. Первая попытка была выше `.q-cta` и `.alarm`, и
   не делала ровно ничего: специфичность одинаковая, медиазапрос её не
   добавляет, побеждает то правило, что ниже. Этот капкан в памяти
   проекта уже записан — композером, который на широком экране уезжал
   наполовину за кромку. Поймано замером: числа не сдвинулись ни на
   пиксель. */
@media (max-height:620px){
  .q-h{margin-bottom:var(--s-2)}
  #quiz-stage .alarm{margin:var(--s-4) 0; padding:13px 14px}
  .q-cta{margin:var(--s-4) 0; padding:var(--s-3)}
  .q-cta p:first-child{margin-bottom:var(--s-2)}
  #quiz-stage > h3{margin-top:var(--s-5)}
}


/* ------------------------------------------------------------
   Результат: главы

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

   Приём взят существующий в приложении — h2.sect с подчёркивающей линией,
   которой размечена вся шпаргалка. Ритм: 32 между главами, 16 между блоками
   внутри главы, 12 от заголовка до его содержимого.

   `>` вместо потомка не случайно: внутри сцены есть h3 у блока безопасности
   и у карточки балла, и они не главы.
   ------------------------------------------------------------ */
#quiz-stage > h3{
  font-family:var(--f-display); font-weight:600; font-size:17px;
  letter-spacing:-.01em; margin:var(--s-6) 0 var(--s-3);
  padding-bottom:var(--s-2); border-bottom:1px solid var(--line);
}
#quiz-stage > p:not([class]){margin:0 0 var(--s-4)}
#quiz-stage > .chips{margin:0 0 var(--s-4)}
/* «Вся шпаргалка» закрывает главу, а не продолжает стопку аккордеонов:
   при отступе карточки в 8px кнопка читалась приклеенной к последней. */
#quiz-stage > p:not([class]):has(.btn){margin:var(--s-4) 0 0}

/* «24 из 24» с залитой во всю ширину акцентной шкалой — это визуальная
   грамматика счёта в игре, показанная человеку, который только что узнал,
   что у него не характер, а система. Число приглушено намеренно; шкала
   приводится к нему и перестаёт перебивать блок безопасности под собой. */
#quiz-stage .score-sm .meter i{background:var(--muted)}

/* Девять акцентных плашек в четыре ряда под «Что ты узнала» — не список
   узнанного, а табло. Вместе со шкалой, плиткой логотипа, точкой на
   шестерёнке, линией .alarm, кнопкой CTA и активной вкладкой на экране
   набиралось семь акцентных поверхностей — при том, что комментарий над
   .alarm обещает цвет как сигнал. Заливку снимаем, цвет остаётся в тексте:
   смысл сохраняется, масса уходит, и сигнальным на экране остаётся
   блок безопасности с действием под ним. */
#quiz-stage .chips .chip-accent{
  background:var(--surface-2); color:var(--accent-ink);
  border-color:var(--accent-border);
}

/* ------------------------------------------------------------
   Результат: подвал

   Концовка шла так: дисклеймер → «Пройти заново» → «остаётся на устройстве»
   → при повторном прохождении ещё «в прошлый раз». Три-четыре почти
   одинаковые серые моно-строки, между которыми зажата кнопка: экран не
   завершался, а иссякал. Линия сверху собирает их в один закрытый блок —
   тот же приём, что у .foot.

   Дисклеймер опознаётся по тому, что он единственный .sign до кнопки:
   строки после неё дописываются условно, а эта есть всегда.
   ------------------------------------------------------------ */
#quiz-stage .sign{margin:var(--s-3) 0 0}
#quiz-stage .rowbtns{margin:var(--s-4) 0 0}
#quiz-stage .sign:has(~ .rowbtns){
  margin-top:var(--s-6); padding-top:var(--s-4); border-top:1px solid var(--line);
}

/* ============================================================
   Шпаргалка
   ============================================================ */
details.card-acc{
  background:var(--surface); border:1px solid var(--line);
  border-radius:var(--r-block); margin-bottom:var(--s-2);
}
/* Вес, а не кегль: заголовок раздела (h2.sect, Lora 18/600) и заголовок
   карточки под ним были одной гарнитуры, одного начертания и одного
   цвета, с разницей в 2.5px. На экране из 34 карточек в пяти разделах
   раздел не читался как уровень выше карточки — одиннадцать строк подряд
   выглядели одиннадцатью заголовками. Поднимать кегль раздела нельзя:
   на 19px «Приёмы, которые применяют к тебе» переносится на две строки. */
details.card-acc>summary{
  padding:14px 15px; cursor:pointer; font-family:var(--f-display);
  font-weight:500; font-size:15.5px; list-style:none; display:flex; align-items:center; gap:10px;
}
details.card-acc>summary::-webkit-details-marker{display:none}
details.card-acc>summary::after{content:"+"; margin-left:auto; color:var(--muted); font-size:18px; line-height:1}
details.card-acc[open]>summary::after{content:"−"}
details.card-acc .body{padding:0 15px 15px; font-size:14px}
details.card-acc .body p{margin:0 0 9px} details.card-acc .body p:last-child{margin:0}
/* «Подробно и источники» — строчная цель в 19px, и на результате это
   единственный выход в карточку. Правило узкое намеренно: тем же классом
   в «Рядом» набран ряд ссылок через «·», и там inline-block с высотой
   разорвал бы строку. */
/* Единственный путь из шпаргалки в полную карточку приёма — и
   единственная ссылка приложения, набранная не акцентным цветом: она
   наследовала --ink, то есть цвет абзаца над ней. Все остальные
   («Подробно» в разборе, шаги, источники) — --accent-ink. */
details.card-acc .body .more{
  display:inline-block; padding:var(--s-2) 0; min-height:36px;
  font-size:13px; color:var(--accent-ink);
}
/* `.sign` стоит в десяти местах, и меткой из них является одно —
   «Модель: <имя>». Остальные девять — связные предложения: объяснение,
   куда уйдёт текст в чужом чате (восемь строк подряд), его фразы в
   карточке шпаргалки, оговорка про бесплатный тариф, дисклеймер на
   результате теста. Моноширинный кириллицей на 12px — самый медленный
   набор в приложении, и им была набрана ровно та строка, которая
   отвечает на «безопасно ли по этому нажимать».

   Правило: моноширинный остаётся за однострочными метками (заголовки
   групп, .ev, .metric-label, .card-tag, цитата находки). Всё, что
   переносится, набирается интерфейсным. */
.sign{font-family:var(--f-body); font-size:13px; color:var(--muted)}
.foot{font-size:12.5px; color:var(--muted); margin:26px 0 0; padding-top:14px; border-top:1px solid var(--line)}

/* ============================================================
   Карточка приёма
   ============================================================ */
/* Карточка приёма — самый длинный экран приложения: замерено 2797px,
   больше четырёх экранов связного текста. Единственным, чем человек
   могла по нему ориентироваться, была строка КРУПНЕЕ АБЗАЦА НА ПОЛТОРА
   ПИКСЕЛЯ: 16px против 14.5. Приём, который это решает, в приложении уже
   есть — заголовки глав на экране результата теста (`#quiz-stage > h3`):
   кегль, линия и ритм. Сюда он не доехал. */
.detail h3{
  font-family:var(--f-display); font-weight:600; font-size:17px;
  letter-spacing:-.01em; margin:var(--s-6) 0 var(--s-3);
  padding-bottom:var(--s-2); border-bottom:1px solid var(--line);
}
.detail p{margin:0 0 10px; font-size:14.5px}
.srclist{list-style:none; padding:0; margin:10px 0 0; font-size:13px; color:var(--muted)}
.srclist li{padding:9px 0; border-top:1px solid var(--line)}
.srclist a{color:var(--accent-ink)}

/* ============================================================
   Что видно на каком экране
   ============================================================ */
body:not([data-pane="chat"]) .composer{display:none}

/* Экран восстановления — два действия и ничего больше. Полосы живут
   снаружи `.shell`, и стирание её содержимого их не трогало: под
   «приложение не смогло запуститься» оставался рабочий композер с
   приглашением вставить переписку, а вкладки вели на экраны, которых
   уже нет. */
:root.recovering .composer,
:root.recovering .tabbar{display:none}
:root.recovering .shell{padding-bottom:24px}
body:not([data-pane="chat"]) .shell{padding-bottom:calc(var(--tabbar-h, 70px) + 30px)}
body[data-pane="detail"] .tabbar,
body[data-pane="settings"] .tabbar{display:none}
body[data-pane="detail"] .shell,
body[data-pane="settings"] .shell{padding-bottom:40px}

/* Подсказка в поле была на 330px при доступных 212 — она переносилась на
   вторую строку, и ради второй строки поле держали в 60px. Платили высотой
   за текст, который и так стоит в приветствии первым сообщением ленты
   («вставь текст или прикрепи скриншот через плюс слева»), причём там его
   видно целиком. Подсказка укорочена до 147px, поле вернулось к 44. */

@media (max-width:560px){
  .stat-num{font-size:24px}
  .card{grid-template-columns:92px 1fr}
}

/* И псевдоэлементы тоже: `*` их не берёт, а точки карусели и растворения
   живут в ::before — точка плавно росла бы и при «уменьшить движение»
   (look-check, «Карусель»). */
@media (prefers-reduced-motion:reduce){
  *, *::before, *::after{animation:none !important; transition:none !important}
}

/* Экран восстановления вместо белого экрана */
.recover{padding:32px 0}
.recover .warnbox{font-size:12.5px; word-break:break-word}

/* ============================================================
   Скриншоты в архиве
   ============================================================ */
.item-imgs{display:flex; flex-wrap:wrap; gap:6px; margin:0 0 9px}
.item-imgs img{
  width:64px; height:64px; object-fit:cover; cursor:zoom-in;
  border-radius:var(--r-xs); border:1px solid var(--line); background:var(--surface-2);
}
.shotview{
  border:0; padding:0; background:none; max-width:100vw; max-height:100vh;
}
.shotview::backdrop{background:rgba(0,0,0,.86)}
.shotview img{max-width:96vw; max-height:92vh; display:block; border-radius:var(--r-sm)}

/* Ответ модели, сохранённый вместе с разбором */
.answer{margin-top:8px}
.answer summary{font-size:12.5px; font-weight:500; color:var(--muted); cursor:pointer}
.answer p{margin:7px 0 0; font-size:13.5px; color:var(--ink-2); white-space:pre-wrap}

/* ============================================================
   Тихий режим: настройка и разовое предложение
   ============================================================ */
/* Переключатель в «Месте и данных». Своей поверхности у кнопки нет —
   дорожка внутри, цель 56×44; фокус — общее кольцо. Включённое состояние
   видно не только цветом: бегунок уезжает вправо. */
.setting{
  background:var(--surface); border:1px solid var(--line); border-radius:var(--r-block);
  padding:14px 12px 16px 16px; margin:22px 0 0;
}
.setting .row-line{display:flex; align-items:center; justify-content:space-between; gap:12px}
.setting h3{margin:0; font-size:17px; font-weight:600; letter-spacing:-.01em}
.setting p{margin:8px 4px 0 0; font-size:14px; color:var(--ink-2)}
.switch{
  flex:none; width:56px; height:44px; padding:0; border:0; background:none; cursor:pointer;
  border-radius:var(--r-pill); display:grid; place-items:center;
  transition:opacity .15s, transform .15s var(--ease-out);
}
.switch .track{position:relative; display:block; width:52px; height:32px; border-radius:var(--r-pill); background:var(--field-line)}
.switch .thumb{
  position:absolute; top:3px; left:3px; width:26px; height:26px; border-radius:50%;
  background:var(--surface); transition:transform .18s var(--ease-out);
}
.switch[aria-checked="true"] .track{background:var(--ink)}
.switch[aria-checked="true"] .thumb{transform:translateX(20px); background:var(--bg)}
@media (hover:hover) and (pointer:fine){ .switch:hover .track{opacity:.85} }

/* Разовое предложение: одна фраза и два строчных ответа. Не громче экрана
   под ним — без поверхности, без пилюль; цель ответа — 44 по высоте. */
.quiet-offer{display:flex; flex-wrap:wrap; align-items:center; column-gap:18px; margin:0 0 10px}
.quiet-offer p{flex:1 1 100%; margin:0; font-size:14px; line-height:1.4; color:var(--ink)}
.quiet-offer .linkbtn{
  margin:0; min-height:44px; padding:0; display:inline-flex; align-items:center;
  font-size:14px; font-weight:500; color:var(--ink);
}
#quiz-quiet .quiet-offer{margin:var(--s-4) 0 0}
/* С первым ответом экран теста перестаёт быть входным — строка уходит
   вместе с лидом и подвалом. */
#quiz:not([data-step="start"]) #quiz-quiet{display:none}

/* ============================================================
   Свечение карточек и цифры точечной матрицей

   Заведены здесь, как основа; карточки находок, счётчик и Pro получают
   их отдельными проходами. Свечение — только градиенты: восемь слоёв
   (выдох сверху, два угла снизу, четыре кромки, основа), вариант задаёт
   три цвета, тема — силу слоёв. Текст начинается не ближе 20px от края:
   самые насыщенные места лежат у кромки, где текста нет.
   ============================================================ */
.glow{
  --g1:var(--gh1); --g2:var(--gh2); --base:var(--ghb);
  position:relative; border-radius:var(--r-card); padding:22px 22px 20px;
  border:1px solid color-mix(in oklab, var(--g1) var(--ga-border), transparent);
  background:
    linear-gradient(to bottom, color-mix(in oklab, var(--g1) var(--ga-top), transparent), transparent 46px) top/100% 46px no-repeat,
    linear-gradient(to top, color-mix(in oklab, var(--g2) var(--ga-bottom), transparent), transparent 40px) bottom/100% 40px no-repeat,
    linear-gradient(to right, color-mix(in oklab, var(--g1) var(--ga-side), transparent), transparent 26px) left/26px 100% no-repeat,
    linear-gradient(to left, color-mix(in oklab, var(--g1) var(--ga-side), transparent), transparent 26px) right/26px 100% no-repeat,
    radial-gradient(120% 60% at 50% 0%, color-mix(in oklab, var(--g1) var(--ga-bloom), transparent), transparent 70%),
    radial-gradient(65% 45% at 0% 100%, color-mix(in oklab, var(--g2) var(--ga-corner), transparent), transparent 72%),
    radial-gradient(65% 45% at 100% 100%, color-mix(in oklab, var(--g2) var(--ga-corner), transparent), transparent 72%),
    var(--base);
}
@supports (corner-shape:squircle){ .glow{corner-shape:squircle; border-radius:var(--r-card-sq)} }
.glow.sev-high{--g1:var(--gh1); --g2:var(--gh2); --base:var(--ghb)}
.glow.sev-mid {--g1:var(--gm1); --g2:var(--gm2); --base:var(--gmb)}
.glow.sev-low {--g1:var(--gl1); --g2:var(--gl2); --base:var(--glb)}
.glow.cold    {--g1:var(--gc1); --g2:var(--gc2); --base:var(--gcb)}
.glow.pro     {--g1:var(--gp1); --g2:var(--gp2); --base:var(--gpb)}
/* В тихом режиме свечения нет: плоская поверхность и тонкая рамка. */
[data-quiet] .glow{background:var(--surface); border:1px solid var(--line-strong)}
[data-quiet] .glow.cold{background:var(--surface-2)}

/* Цифры матрицей — только число и только от 40px; кириллицы в Doto нет.
   Если рядом нужен падеж, матрица aria-hidden, а фраза — .sr. */
.dot-num{
  font-family:var(--f-dot); font-weight:800; font-variant-numeric:tabular-nums;
  line-height:.9; letter-spacing:.02em; color:var(--ink-hi);
}

/* ============================================================
   Концепт v2: компоненты (30.09)

   Всё ниже — по утверждённому концепту: счётчик бесплатного чтения,
   «Повторяется» точечным графиком, записи архива, экран Pro, лист входа,
   блоки подписки и аккаунта. Стоит В КОНЦЕ файла намеренно: у части
   правил та же специфичность, что у общих (.btn, .lede), и побеждает то,
   что ниже, — капкан, записанный в CLAUDE.md трижды.
   ============================================================ */

/* ---------- «Стоп»: ссылка на карточку ----------
   Карточки угрозы в карусели больше нет (её назвал этот блок), и путь к
   подробностям ведёт отсюда — строчной ссылкой, без поверхности. */
.alarm .more{
  display:inline-flex; align-items:center; min-height:44px; margin-top:2px;
  font-size:14px; color:var(--ink); text-decoration:underline; text-underline-offset:3px;
}

/* ---------- Тихая строка про Pro в ленте ---------- */
.pro-line{margin:0; font-size:13.5px; color:var(--ink-2)}
.pro-line a, .note a{color:var(--ink); text-underline-offset:3px}

/* ---------- Счётчик бесплатного чтения ----------
   Только у бесплатной и только при включённой оплате (js/pro.js). Число,
   а не отсчёт: таймера нет нигде. Пять точек — пять слотов скользящих
   суток; прочитанный гаснет. Живёт до первой отправки: рядом с находками
   закрытое не предлагается. */
#ocr-counter:empty{display:none}
:root.thread-filled #ocr-counter{display:none}
.counter{display:flex; flex-direction:column; margin:0 0 16px; overflow:hidden; min-height:280px}
.counter > *{position:relative; z-index:1}
.counter .top{margin:0; font-size:15px; font-weight:500; color:var(--ink-hi)}
.counter .num{margin:14px 0 4px; font-size:132px; text-align:center}
.counter .unit{margin:0; text-align:center; font-size:16px; color:var(--ink)}
.counter .next{margin:12px 0 0; text-align:center; font-size:13.5px; color:var(--ink)}
.slots{display:flex; justify-content:center; gap:14px; margin:18px 0 0; padding:0; list-style:none}
.slots li{width:10px; height:10px; border-radius:50%; background:var(--ink-hi)}
.slots li.used{opacity:.25}
.counter .arcs{
  position:absolute; left:0; right:0; bottom:0; z-index:0; width:100%; height:120px;
  pointer-events:none; opacity:.55; stroke:var(--chart-dim);
}
[data-quiet] .counter{min-height:0}
[data-quiet] .counter .num{font-size:96px}
[data-quiet] .counter .arcs{display:none}

/* ---------- Архив: записи диалога ---------- */
.lede.chrono{color:var(--ink-2); font-size:15px}
.entries{display:flex; flex-direction:column; gap:10px; margin:16px 0 0}
.entry{background:var(--surface); border:1px solid var(--line); border-radius:var(--r-block); overflow:hidden}
.entry > header{
  display:flex; align-items:center; gap:8px; padding:0 8px 0 15px; min-height:48px;
  border-bottom:1px solid var(--line); font-size:13.5px; color:var(--ink-2);
  font-variant-numeric:tabular-nums;
}
.entry .body{padding:12px 15px 14px}
/* Переносы сохранённой переписки доживают до экрана: абзац их съедает, и
   «Он: …» склеивается с «Я: …» — в том самом датированном доказательстве
   (layout-check, «Архив: переносы»). */
.entry .text{white-space:pre-wrap; overflow-wrap:anywhere; font-size:14.5px; margin:0 0 8px; color:var(--ink)}
.entry .names{margin:0; font-size:14px; font-weight:500; color:var(--ink)}
.entry .names.none{color:var(--ink-2); font-weight:400}

/* ---------- «Повторяется»: точечный график ----------
   Одна тусклая точка — один день от первой записи диалога до последней,
   яркая — день, когда приём нашёлся, пунктирные дуги связывают повторы.
   Строится по датам записей в масштабе (js/archive.js), не по порядку.
   Точки загораются один раз; при «уменьшить движение» — сразу. */
.repeats{margin:0 0 6px}
.repeats .head{display:flex; justify-content:space-between; align-items:baseline; gap:12px; margin:0 0 16px}
.repeats h2{margin:0; font-size:var(--t-section); font-weight:600; letter-spacing:-.02em; color:var(--ink-hi); text-wrap:balance}
[data-quiet] .repeats h2{font-size:var(--t-small-head)}
.repeats .tag{font-size:13px; font-weight:500; color:var(--ink)}
.rep-row{margin:0 0 14px}
.rep-row .lbl{display:flex; justify-content:space-between; align-items:flex-end; gap:10px; margin:0 0 4px}
.rep-row .nm{font-size:15px; font-weight:500; min-width:0; color:var(--ink-hi)}
.rep-row .cnt{display:inline-flex; align-items:baseline; gap:6px; flex:none; font-size:14px; color:var(--ink)}
.rep-row .cnt .dot-num{font-size:40px; font-weight:900}
.timeline{display:block; width:100%; height:auto; overflow:visible}
.timeline .bg{fill:var(--chart-dim)}
.timeline .lit{fill:var(--chart-hi)}
.timeline .arc{fill:none; stroke:var(--chart-line); stroke-width:1.2; stroke-dasharray:2 4; stroke-linecap:round}
.axis{display:flex; justify-content:space-between; gap:12px; margin:2px 0 14px; font-size:12.5px; color:var(--ink-2)}
.repeats .note{margin:0; font-size:13.5px; color:var(--ink)}
@media (prefers-reduced-motion:no-preference){
  .timeline .lit{transform-box:fill-box; transform-origin:center; animation:pop .24s var(--ease-out) both}
  .timeline .arc{animation:fade-in .24s ease-out .12s both}
}
@keyframes pop{from{opacity:0; transform:scale(.6)}}
@keyframes fade-in{from{opacity:0}}

/* ---------- Экран Pro ----------
   Крупно — только нейтральное слово «Pro» (96px, в тихом 32). Выход —
   «Закрыть» в правом верхнем углу шапки вместо шестерёнки: закрыть экран
   покупки можно одним нажатием всегда. Без таймеров, перечёркнутых цен и
   бейджей «выгоднее». */
.topbar-close{display:none}
body[data-pane="pro"] .topbar-close{display:inline-flex}
body[data-pane="pro"] #go-settings{display:none}
/* Экран покупки — целиком, без нижней панели (как карточка приёма и
   «Место и данные»): выход один и на виду — «Закрыть». */
body[data-pane="pro"] .tabbar{display:none}
body[data-pane="pro"] .shell{padding-bottom:40px}
/* Pro на узком: «Закрыть» шире шестерёнки. Уже 375 знака нет на всех
   экранах (общее правило у шапки выше: пустой знак съел бы ещё один зазор, и
   на 320 «Закрыть» уезжал за кромку); от 375 — целиком или никак, по месту:
   «Red Flag» рядом с «Close» помещается от 375, «Красный флаг» рядом с
   «Закрыть» — от 428. */
.pro-title{margin:0 0 10px}
.pro-title .screen{font-size:96px; letter-spacing:-.045em; line-height:.95; margin:0}
[data-quiet] .pro-title .screen{font-size:32px; letter-spacing:-.03em}
.status-line{margin:0 0 6px; font-size:14px; color:var(--ink-2)}
#pro .lede{color:var(--ink-2); font-size:15px; margin:0 0 20px}
.feat{list-style:none; margin:0; padding:0}
.feat li{display:grid; grid-template-columns:14px 1fr; gap:10px; margin:0 0 12px; font-size:15px; color:var(--ink-hi)}
.feat li:last-child{margin:0}
.feat li::before{content:""; width:7px; height:7px; border-radius:50%; background:var(--ink-hi); margin-top:8px}
.free-note{margin:16px 0 22px; font-size:14px; color:var(--ink-2)}
.plans{border:0; margin:0 0 16px; padding:0; min-width:0; display:grid; gap:10px}
.plan{
  position:relative; display:flex; flex-wrap:wrap; align-items:center; gap:4px 12px;
  min-height:72px; padding:14px 18px; border-radius:var(--r-block); cursor:pointer;
  background:var(--surface); border:1px solid var(--field-line);
}
.plan input{position:absolute; inset:0; width:100%; height:100%; margin:0; opacity:0; cursor:pointer}
.plan .price{display:inline-flex; align-items:baseline; gap:4px; font-size:18px; font-weight:600; color:var(--ink-hi)}
.plan .price .dot-num{font-size:40px; letter-spacing:-.06em}
.plan .per{font-size:15px; color:var(--ink)}
.plan .radio{
  margin-left:auto; width:22px; height:22px; flex:none; border-radius:50%;
  border:2px solid var(--ink-2); display:grid; place-items:center;
}
.plan .plan-note{flex-basis:100%; font-size:13.5px; color:var(--ink-2)}
.plan:has(input:checked){border-color:var(--plan-on-line); background:var(--plan-on)}
.plan:has(input:checked) .radio{border-color:var(--ink-hi)}
.plan:has(input:checked) .radio::after{content:""; width:10px; height:10px; border-radius:50%; background:var(--ink-hi)}
.plan:has(input:focus-visible){outline:2px solid var(--focus); outline-offset:3px}
@media (hover:hover) and (pointer:fine){ .plan:hover{border-color:var(--ink-2)} }
.buyrow{margin:0 0 20px}
.buyrow .btn{width:100%}
.renew{margin:0 0 10px; font-size:13.5px; color:var(--ink-2)}
.legal{margin:0 0 12px; display:flex; flex-wrap:wrap; gap:0 6px; align-items:center; font-size:14px; color:var(--muted)}
.legal a{display:inline-flex; align-items:center; min-height:44px; color:var(--ink); text-underline-offset:3px}
@media (hover:hover) and (pointer:fine){ .legal a:hover{color:var(--ink-hi); text-decoration-thickness:2px} }

/* ---------- Галочка ----------
   Своя: рамка --ink-2, отмечено — заливка кнопки. Цель пальца — вся строка
   (не меньше 44), а не квадрат в 22px. */
.consent{
  display:grid; grid-template-columns:24px 1fr; gap:12px; align-items:start;
  min-height:44px; margin:0 0 18px; font-size:14.5px; color:var(--ink); cursor:pointer;
}
.consent input{
  appearance:none; -webkit-appearance:none; width:22px; height:22px; margin:1px 0 0;
  cursor:pointer; border:2px solid var(--ink-2); border-radius:6px; background:transparent;
  display:grid; place-items:center;
}
.consent input:checked{background:var(--red-500); border-color:var(--red-500)}
.consent input:checked::after{
  content:""; width:6px; height:11px; border:solid var(--on-accent); border-width:0 2.5px 2.5px 0;
  transform:translateY(-1px) rotate(45deg);
}
.consent input:focus-visible{outline:2px solid var(--focus); outline-offset:3px}

/* ---------- Вход ----------
   Три способа одного веса: контрастные пилюли во всю ширину, ни один не
   выделен цветом. */
.signin{border-top:1px solid var(--line); padding:20px 0 0; margin:0 0 20px}
.signin h3{margin:0 0 8px; font-size:var(--t-small-head); font-weight:600; letter-spacing:-.01em; color:var(--ink-hi)}
.signin p{margin:0 0 14px; font-size:14.5px; color:var(--ink-2)}
.signin .stack{display:flex; flex-direction:column; gap:8px; margin:0 0 12px}
.signin .stack .btn{width:100%}
.signin .keyform{margin:0 0 12px}
.signin .note{font-size:13.5px; color:var(--ink-2)}
.btn-contrast{background:var(--ink); border-color:var(--ink); color:var(--bg)}
@media (hover:hover){ .btn-contrast:hover{background:var(--ink); opacity:.9} }

/* ---------- Блоки в «Месте и данных» ----------
   Подписка и аккаунт — карточкой, как переключатель тихого режима: это
   состояние, а не абзац справки. */
.panel{background:var(--surface); border:1px solid var(--line); border-radius:var(--r-block); padding:16px; margin:22px 0 0}
.panel > h3{margin:0 0 8px; font-size:var(--t-small-head); font-weight:600; letter-spacing:-.01em; color:var(--ink-hi)}
.panel p{margin:0 0 10px; font-size:14.5px}
.panel .note{margin:0 0 10px}
.panel .rowbtns{margin:0 0 4px}
.panel [data-account]:not(:empty){border-top:1px solid var(--line); margin-top:14px; padding-top:14px}
.panel [data-account] > h3{margin:0 0 8px; font-size:16px; font-weight:600}

/* ---------- Страницы вне приложения ----------
   Реквизиты, условия, политика: та же шапка с тумблером темы, что в
   приложении, и тот же тихий режим. */
.page-top .back{display:inline-flex; align-items:center; min-height:44px; margin:0 auto 0 0; padding:0; text-decoration:none}
.page main{padding-bottom:40px}

/* Название приёма на его карточке — 24px, в тихом 19: крупный кегль
   достаётся только нейтральным словам. */
.screen.tactic-title{font-size:var(--t-section); letter-spacing:-.02em; line-height:1.15; margin:6px 0 10px}
[data-quiet] .screen.tactic-title{font-size:var(--t-small-head)}

/* ---------- Собеседница (ИИ): экран #/talk (js/companion.js) ----------
   Есть только при включённой собеседнице: без неё ни одного из этих узлов
   на экране нет. Вид — тот же концепт: карточка на главной светится её
   холодным синим (в тихом режиме — плоская), ворота — спокойные панели,
   выбор модели — пилюли, ответ ИИ — пузырь приложения, композер — та же
   полоса, что у разбора. Маскота здесь нет. */
.talk-title{margin:6px 0 12px}
.talk-gate{background:var(--surface); border:1px solid var(--line); border-radius:var(--r-block); padding:16px; margin:0 0 16px}
.talk-gate-h{margin:0 0 8px; font-size:var(--t-small-head); font-weight:600; letter-spacing:-.01em; line-height:1.25; color:var(--ink-hi); text-wrap:balance}
.talk-gate p{margin:0 0 10px; font-size:14.5px; color:var(--ink); text-wrap:pretty}
.talk-gate .note{font-size:13.5px; color:var(--ink-2)}
.talk-gate .note:empty{display:none}
.talk-gate .rowbtns{margin:12px 0 0}
.talk-gate .signin{margin:12px 0 0}
.talk-gate [hidden]{display:none}
/* Возраст — нейтральный вопрос (ревью 02.10): год рождения, по году ровно
   18 — ещё месяц. Поле — как поля плана (.her-plan-field): пилюля, цель 44,
   шрифт 16px — иначе iOS увеличивает страницу при фокусе. */
.talk-age-form{display:flex; flex-direction:column; gap:10px; margin-top:4px}
.talk-field{display:flex; flex-direction:column; gap:5px; font-size:14px; color:var(--ink)}
.talk-field input, .talk-field select{
  min-width:0; min-height:44px; padding:0 var(--s-3); font-size:16px;
  border:1px solid var(--field-line); border-radius:var(--r-pill);
  background:var(--surface); color:var(--ink); font-family:inherit;
}
.talk-field input{max-width:10em; letter-spacing:.04em}
.talk-field input:focus-visible, .talk-field select:focus-visible{outline:2px solid var(--focus); outline-offset:2px}
.talk-age-form .rowbtns{margin:4px 0 0}
.talk-more{margin:0}
.talk-more a{display:inline-flex; align-items:center; min-height:44px; color:var(--ink); text-underline-offset:3px}
/* Шапка разговора: выбор модели и «Разговоры» / «Новый разговор» в одном
   ряду (решение 09.10: обычный чат, ничего лишнего). Выбор — слева, кнопки
   следом; не помещаются — переносятся. */
.talk-tools{display:flex; align-items:center; gap:8px; flex-wrap:wrap; margin:0 0 12px}
.talk-tools .talk-pick{margin:0 auto 0 0}
/* Выбор модели — радио-пилюли: выбранная залита (в тихом — графитом),
   остаток сообщений рядом с именем. Цель 44. */
.talk-pick{display:flex; gap:8px; flex-wrap:wrap; margin:0 0 6px}
.talk-model{
  font-family:var(--f-body); font-size:14px; font-weight:500; line-height:1.2; cursor:pointer;
  min-height:44px; padding:8px 16px; border-radius:var(--r-pill);
  border:1px solid var(--tint-line); background:var(--tint); color:var(--ink);
  display:inline-flex; align-items:center; gap:8px;
  transition:opacity .15s, transform .15s var(--ease-out);
}
.talk-model[aria-checked="true"]{background:var(--accent); border-color:var(--accent); color:var(--accent-contrast)}
.talk-left{font-weight:400; font-variant-numeric:tabular-nums}
/* Одна «Пробная» — метка, а не выбор: без заливки и без цели пальца. */
.talk-model-one{cursor:default; min-height:0; padding:6px 14px; background:var(--surface-2); border-color:var(--line)}
.talk-model:active, .talk-open:active{opacity:.6; transition-duration:0s}
.talk-model:active{transform:scale(.97)}
@media (prefers-reduced-motion:reduce){ .talk-model:active{transform:none} }
.talk-note{margin:0 0 14px; font-size:13.5px; color:var(--ink-2)}
.talk-note a{color:var(--ink); text-underline-offset:3px}
/* Тихая ссылка на обычный разбор: под воротами и под «пробные кончились».
   Не кнопка и не плашка — возможность, а не следующий шаг. */
.talk-plain{margin:0 0 16px}
/* Скриншоты в разговоре (решение 09.10): в её сообщении — миниатюры (общий
   .msg-imgs), под ними, пока идёт тихое чтение на устройстве, строка статуса. */
.msg-me .talk-reading{margin:6px 0 0; font-size:13.5px; color:var(--ink-2); text-align:right}
.talk-composer .attachments{padding:0 4px 8px}
.talk-plain .linkbtn{margin-left:0; min-height:44px; padding:0; font-size:13.5px; color:var(--ink-2)}
/* Окошко после ответа (решение 09.10): под последним завершённым ответом, не
   модальное, закрывается. Плоское — без свечения и без появления: чат тихий. */
.talk-after{background:var(--surface); border:1px solid var(--line); border-radius:var(--r-block); padding:12px 15px}
.talk-after p{margin:0 0 8px; font-size:14px; color:var(--ink); text-wrap:pretty}
.talk-after .talk-after-h{margin:4px 0 4px; font-size:13px; color:var(--ink-2)}
.talk-after-links{list-style:none; margin:0 0 8px; padding:0}
.talk-after-links a{display:inline-flex; align-items:center; min-height:44px; color:var(--ink); text-underline-offset:3px}
.talk-after .rowbtns{margin:0; align-items:center}
.talk-after-close{margin-left:auto; min-height:44px; padding:0 4px; font-size:13.5px; color:var(--ink-2)}
.talk-thread{display:flex; flex-direction:column; gap:14px; padding:4px 0 8px}
/* «Ты говоришь с ИИ, не с человеком» — заметно, но не тревогой: своя
   рамка, первая строка жирным. Знаки прошлых встреч — одной тихой
   строкой. */
.ai-notice{background:var(--surface); border:1px solid var(--line-strong); border-radius:var(--r-block); padding:12px 15px}
.ai-notice-h{margin:0 0 4px; font-size:15px; font-weight:600; line-height:1.35; color:var(--ink-hi)}
.ai-notice p:not(.ai-notice-h){margin:0; font-size:14px; color:var(--ink-2); text-wrap:pretty}
p.ai-notice.past{background:none; border:0; padding:0; margin:0; text-align:center; font-size:12.5px; color:var(--muted)}
.talk-meta{display:flex; align-items:center; gap:0 12px; flex-wrap:wrap}
.talk-who{font-size:12.5px; color:var(--muted)}
.talk-meta .linkbtn{margin-left:0; min-height:44px; padding:0 4px; font-size:13px; color:var(--ink-2)}
.talk-reported{font-size:13px; color:var(--ink-2)}
.talk-fail{margin:0; font-size:13.5px; color:var(--ink-2); text-wrap:pretty}
.msg-me .talk-fail{text-align:right}
.msg-me .rowbtns{justify-content:flex-end}
.talk-help{display:flex; flex-direction:column; gap:12px}
.talk-ctx{background:var(--surface-2); border:1px solid var(--line); border-radius:var(--r-block); padding:0 15px}
.talk-ctx summary{min-height:44px; display:flex; align-items:center; font-size:14px; font-weight:500; color:var(--ink); cursor:pointer}
.talk-ctx .note{margin:0 0 8px; color:var(--ink-2)}
.talk-ctx-text{margin:0 0 12px; white-space:pre-wrap; font-size:13.5px; color:var(--ink-2)}
.talk-report-sheet{border-top:1px solid var(--line); padding:12px 0 0; margin:4px 0 0}
.talk-report-sheet h3{margin:0 0 10px; font-size:15px; font-weight:600; color:var(--ink-hi)}
.talk-reasons{display:flex; flex-wrap:wrap; gap:8px; margin:0 0 12px}
.talk-reasons [aria-checked="true"]{background:var(--ink); border-color:var(--ink); color:var(--bg)}
.talk-report-sheet .note{margin:0 0 10px; font-size:13.5px; color:var(--ink-2)}
.talk-report-sheet .note:empty{display:none}
.talk-report-sheet .consent{margin:0 0 8px}
.talk-convs{list-style:none; margin:0 0 16px; padding:0; display:flex; flex-direction:column; gap:8px}
.talk-conv{display:flex; align-items:center; gap:4px; background:var(--surface); border:1px solid var(--line); border-radius:var(--r-block); padding:2px 6px 2px 2px}
.talk-open{
  flex:1; min-width:0; text-align:left; font-family:var(--f-body); font-size:14.5px; line-height:1.35; color:var(--ink);
  background:none; border:0; min-height:44px; padding:8px 12px; cursor:pointer;
  display:flex; flex-direction:column; align-items:flex-start; gap:2px; border-radius:var(--r-block);
}
.talk-open[aria-current="true"]{font-weight:600}
.talk-kind{font-size:12.5px; font-weight:400; color:var(--muted)}
.talk-conv .linkbtn{margin-left:0; min-height:44px; padding:0 8px; font-size:13.5px}
.talk-list .note{margin:0 0 10px; font-size:13.5px; color:var(--ink-2)}
.talk-list .note:empty{display:none}
.talk-list .rowbtns{margin:0 0 12px}
.talk-withdraw{margin-left:0; min-height:44px; font-size:13.5px}
.talk-from-report{margin:0}
/* Композер разговора — своя полоса с видом композера разбора (класс
   `.composer`), видна только в самом разговоре; высоту меряет
   js/layout.js. Кнопка «Остановить» — на месте «Отправить». */
.talk-composer{display:none}
body[data-pane="talk"][data-talk="chat"] .talk-composer{display:block}
body[data-pane="talk"][data-talk="chat"] .shell{padding-bottom:calc(var(--composer-h, 90px) + 16px)}
body[data-pane="talk"][data-talk="chat"] .tabbar::before{display:none}
.talk-composer [hidden]{display:none}
.talk-composer textarea:disabled{opacity:.6}
.talk-composer .chat-send:disabled{opacity:.5; cursor:default}
.talk-stop svg{width:16px; height:16px}
.talk-under{margin:6px 0 0; font-size:12.5px; line-height:1.3; text-align:center; color:var(--ink-2)}
.talk-under:empty{display:none}

/* ---------- Принудительные цвета (высокий контраст Windows) ----------
   Система перекрашивает фоны в Canvas, а всё, что нарисовано ТОЛЬКО
   фоном, пропадает: точки карусели (::before), дорожки и бегунки обоих
   тумблеров, кружок активной вкладки, слоты счётчика. Кнопки-точки при
   этом оставались в порядке фокуса невидимыми. Здесь эти знаки рисуются
   системными цветами. Рамки и кольца система красит сама (CanvasText),
   поэтому кромки тумблеров из обычных правил видны и так. Сторожит
   look-check («принудительные цвета»). */
@media (forced-colors:active){
  .pager button::before, .slots li{forced-color-adjust:none; background:CanvasText}
  .pager button[aria-current="true"]::before{background:Highlight}
  .theme-switch .thumb, .switch .thumb, .switch[aria-checked="true"] .thumb{forced-color-adjust:none; background:Highlight; border:1.5px solid CanvasText}
  .lang-switch::before{outline:1px solid CanvasText; outline-offset:-1px}
  .lang-switch button[aria-pressed="true"] span{forced-color-adjust:none; background:Highlight; color:HighlightText; border:1.5px solid CanvasText}
  .switch .track{outline:1px solid CanvasText; outline-offset:-1px}
  .tab[aria-selected="true"] .tab-ico{outline:2px solid CanvasText; outline-offset:-2px}
  .talk-model[aria-checked="true"], .talk-reasons [aria-checked="true"]{forced-color-adjust:none; background:Highlight; color:HighlightText; border-color:CanvasText}
}
