/* ══════════════════════════════════════════════════════════════════════════
   IMPITO UI KIT — ТОКЕНЫ
   ══════════════════════════════════════════════════════════════════════════
   Кит снят с мини-аппы IMPITO: геометрия, стекло, пружины, сквиркл, таббар,
   листы, ползунок, переключатель — всё как в аппе. ПАЛИТРЫ ЗДЕСЬ НЕТ
   НАМЕРЕННО: цвета ниже — нейтральный графит, чтобы кит можно было положить
   в любой проект и покрасить своими токенами.

   КАК ПОКРАСИТЬ. Переопредели в своём css после kit.css:
     :root { --ui-accent: …; --ui-accent-strong: …; --ui-accent-rgb: r, g, b;
             --ui-bg: …; --ui-text: …; --ui-ink-rgb: r, g, b; }
     [data-theme="dark"] { …то же самое для тёмной… }
   Остальные токены считаются от этих (через rgba(var(--ui-ink-rgb), α) и
   color-mix), поэтому обычно хватает шести строк на тему.
     --ui-ink-rgb    — RGB цвета текста без альфы: из него собираются подсказки,
                       разделители, тени, обводки, «чернильные» плашки.
     --ui-accent-rgb — RGB акцента: мягкие подложки (--ui-accent-soft) и т. п.

   ТЕМА. Ставится атрибутом на <html>: data-theme="light" | "dark". Кто
   ставит — ImpitoKit.theme (kit.js): читает localStorage «ui:theme»
   (light | dark | system), при system берёт prefers-color-scheme или
   Telegram.WebApp.colorScheme.

   ПЛАТФОРМА. html[data-font-platform="apple" | "inter"] ставит kit.js до
   первого кадра: на apple стекло собрано из псевдослоёв (WebKit не умеет
   SVG-фильтры в backdrop-filter), на остальных — настоящая SVG-линза
   (html.ui-lg-refract). Половина стеклянных правил висит на этом атрибуте.
   ────────────────────────────────────────────────────────────────────────── */
:root {
  /* ── Палитра-заглушка (светлая): графит ─────────────────────────────── */
  --ui-ink-rgb: 28, 28, 30;
  --ui-accent-rgb: 28, 28, 30;
  --ui-bg: #f2f2f7;
  --ui-text: #1c1c1e;
  --ui-text-2: #2c2c2e;
  --ui-accent: #1c1c1e;
  --ui-accent-strong: #3a3a3c;
  --ui-accent-text: #ffffff;
  --ui-accent-soft: rgba(var(--ui-accent-rgb), 0.12);
  --ui-destructive: #ff3b30;
  --ui-confirm: #34c759;
  /* Две «тональные» подписи (в аппе — режимы модели: оранжевый и сиреневый).
     Здесь нейтральные, красятся вместе с палитрой. */
  --ui-tone-a: #636366;
  --ui-tone-b: #8e8e93;

  /* ── Производные: текст, подсказки, линии ───────────────────────────── */
  --ui-hint: rgba(var(--ui-ink-rgb), 0.58);
  --ui-section-header: rgba(var(--ui-ink-rgb), 0.52);
  --ui-separator: rgba(var(--ui-ink-rgb), 0.12);
  --ui-ink-soft: rgba(var(--ui-ink-rgb), 0.45);
  --ui-ink-faint: rgba(var(--ui-ink-rgb), 0.32);
  --ui-dash: rgba(var(--ui-ink-rgb), 0.22);
  --ui-dash-strong: rgba(var(--ui-ink-rgb), 0.25);
  --ui-veil-edge: rgba(var(--ui-ink-rgb), 0.1);
  --ui-expand-dot: rgba(var(--ui-ink-rgb), 0.16);
  --ui-wait-dot: rgba(var(--ui-ink-rgb), 0.22);

  /* ── Поверхности ────────────────────────────────────────────────────── */
  --ui-card: rgba(255, 255, 255, 0.62);
  --ui-card-raised: rgba(255, 255, 255, 0.78);
  --ui-card-selected: #fff;
  --ui-surface-highlight: 0 1px 0 rgba(255, 255, 255, 0.28) inset;
  --ui-count-bg: rgba(255, 255, 255, 0.6);
  --ui-fill: rgba(120, 120, 128, 0.1);
  --ui-fill-2: rgba(120, 120, 128, 0.16);
  --ui-fill-3: rgba(120, 120, 128, 0.22);
  --ui-hover: rgba(0, 0, 0, 0.035);
  --ui-press: rgba(0, 0, 0, 0.07);
  --ui-field-bg: #ffffff;
  --ui-white-veil: rgba(255, 255, 255, 0.5);
  --ui-white-veil-strong: rgba(255, 255, 255, 0.9);
  --ui-wait-bg: rgba(255, 255, 255, 0.5);
  --ui-seg-active: #ffffff;
  --ui-switch-on: var(--ui-accent);
  --ui-switch-thumb: #ffffff;
  /* Картинки до загрузки и их кромка. */
  --ui-media-bg: #ffffff;
  --ui-media-ring: rgba(255, 255, 255, 0.25);
  --ui-media-soft: rgba(255, 255, 255, 0.6);
  --ui-media-shot: linear-gradient(160deg, rgba(255, 255, 255, 0.72), var(--ui-accent-soft));
  /* Плашки на вуали (баланс, профиль). */
  --ui-pill-bg: rgba(var(--ui-ink-rgb), 0.13);
  --ui-pill-ink: rgba(var(--ui-ink-rgb), 0.55);
  --ui-pill-ink-soft: rgba(var(--ui-ink-rgb), 0.5);
  /* Боковое меню широкого экрана. */
  --ui-sidebar-bg: color-mix(in srgb, #fff 62%, var(--ui-bg));
  --ui-sidebar-border: rgba(var(--ui-ink-rgb), 0.06);
  --ui-rail-arrow: rgba(238, 238, 241, 0.92);
  --ui-sheet-cancel: rgba(238, 238, 241, 0.9);
  --ui-sheet-cancel-press: rgba(244, 244, 246, 0.95);
  --ui-tabbar-fallback: rgba(255, 255, 255, 0.6);

  /* ── Стекло нижних панелей (таббар, панель запуска, сегмент) ────────── */
  --ui-glass-panel: rgba(240, 240, 244, 0.9);
  --ui-glass-panel-soft: rgba(240, 240, 244, 0.82);
  --ui-glass-panel-hold: rgba(250, 250, 252, 0.92);
  --ui-glass-glow: #ffffff;
  --ui-glass-thumb: rgba(var(--ui-ink-rgb), 0.12);
  --ui-glass-thumb-hold: rgba(255, 255, 255, 0.13);
  --ui-glass-thumb-edge: rgba(255, 255, 255, 0.35);
  --ui-glass-thumb-edge-2: rgba(255, 255, 255, 0.2);
  --ui-glass-thumb-ring: rgba(255, 255, 255, 0.18);
  --ui-glass-btn: rgba(244, 244, 246, 0.62);
  --ui-shop-track: rgba(var(--ui-ink-rgb), 0.1);
  --ui-shop-thumb: var(--ui-glass-panel);
  --ui-pop-light: rgba(250, 250, 252, 0.6);
  --ui-pop-light-source: rgba(250, 250, 252, 0.5);
  --ui-sheet-bg: rgba(238, 238, 241, 0.9);

  /* ── Стекло листов (экшн-шит iOS 26): подложка, блик по краям, линия ── */
  --ui-sheet-glass-bg: rgba(255, 255, 255, 0.82);
  --ui-sheet-blur: 15px;
  --ui-sheet-glass-shadow:
    inset -1px -1px 0 -0.5px #fff,
    inset 1px 1px 0 -0.5px #fff,
    inset 3px 3px 10px -3px #ddd,
    inset -3px -3px 10px -3px #ddd,
    inset 0 0 5px 1px #fff,
    inset 0 0 0 0.5px rgba(0, 0, 0, 0.25),
    inset 0 0 24px rgba(0, 0, 0, 0.1),
    0 0 25px rgba(0, 0, 0, 0.2);
  --ui-sheet-divider: rgba(0, 0, 0, 0.2);

  /* ── Превью тем в пикере (мини-экраны): фон светлой и тёмной ─────────── */
  --ui-preview-light: #f2f2f7;
  --ui-preview-dark: #121214;

  /* ── Геометрия ──────────────────────────────────────────────────────── */
  --ui-radius-card: 22px;
  --ui-radius-field: 14px;
  --ui-radius-pill: 999px;

  /* ── Шрифт: system-ui на apple, Inter на остальных ──────────────────── */
  --ui-font-apple:
    system-ui, -apple-system, BlinkMacSystemFont, "Helvetica Neue", Arial,
    sans-serif;
  --ui-font-inter:
    "Inter Variable", "Inter", system-ui, -apple-system, BlinkMacSystemFont,
    "Roboto", "Helvetica Neue", "Segoe UI", Arial, sans-serif;
  --ui-font: var(--ui-font-apple);
  --ui-font-display: var(--ui-font);

  /* ── Движение: кривые и длительности ────────────────────────────────── */
  --ui-ease: cubic-bezier(0.25, 0.1, 0.25, 1);
  --ui-ease-out: cubic-bezier(0.16, 1, 0.3, 1);
  --ui-ease-nav: cubic-bezier(0.33, 1, 0.68, 1);
  /* «Пружинка» ползунков и сегментов: длинный хвост без перелёта. */
  --ui-spring: cubic-bezier(0.22, 1, 0.36, 1);
  /* Отскок с перелётом (bounce капсулы). */
  --ui-spring-bounce: cubic-bezier(0.34, 1.56, 0.5, 1);
  --ui-dur: 0.18s;
  --ui-dur-screen: 0.42s;

  /* ── Инсеты и служебные ─────────────────────────────────────────────── */
  --ui-safe-top: env(safe-area-inset-top, 0px);
  --ui-safe-bottom: env(safe-area-inset-bottom, 0px);
  --ui-fullscreen-top: 0px;
  --ui-keyboard: 0px;
  --ui-cta-bar-height: 84px;
  /* Высота верхней вуали (см. .ui-veil). */
  --ui-veil-height: calc(var(--ui-safe-top) + 52px);
}

html[data-font-platform="apple"] {
  --ui-font: var(--ui-font-apple);
  --ui-font-display: var(--ui-font);
}
html[data-font-platform="inter"] {
  --ui-font: var(--ui-font-inter);
  --ui-font-display: var(--ui-font);
}

[data-theme="dark"] {
  color-scheme: dark;
  /* ── Палитра-заглушка (тёмная): почти чёрный, светлый акцент ────────── */
  --ui-ink-rgb: 242, 242, 247;
  --ui-accent-rgb: 242, 242, 247;
  --ui-bg: #121214;
  --ui-text: #f2f2f7;
  --ui-text-2: #e5e5ea;
  --ui-accent: #f2f2f7;
  --ui-accent-strong: #d1d1d6;
  --ui-accent-text: #111114;
  --ui-accent-soft: rgba(var(--ui-accent-rgb), 0.16);
  --ui-destructive: #ff453a;
  --ui-tone-a: #aeaeb2;
  --ui-tone-b: #8e8e93;

  --ui-hint: rgba(var(--ui-ink-rgb), 0.55);
  --ui-section-header: rgba(var(--ui-ink-rgb), 0.5);
  --ui-separator: rgba(255, 255, 255, 0.1);
  --ui-ink-soft: rgba(var(--ui-ink-rgb), 0.5);
  --ui-ink-faint: rgba(var(--ui-ink-rgb), 0.35);
  --ui-dash: rgba(255, 255, 255, 0.22);
  --ui-dash-strong: rgba(255, 255, 255, 0.28);
  --ui-veil-edge: rgba(255, 255, 255, 0.12);
  --ui-expand-dot: rgba(255, 255, 255, 0.32);
  --ui-wait-dot: rgba(255, 255, 255, 0.22);

  --ui-card: rgba(255, 255, 255, 0.07);
  --ui-card-raised: rgba(255, 255, 255, 0.12);
  --ui-card-selected: var(--ui-accent-soft);
  --ui-surface-highlight: none;
  --ui-count-bg: rgba(255, 255, 255, 0.08);
  --ui-fill: rgba(255, 255, 255, 0.08);
  --ui-fill-2: rgba(255, 255, 255, 0.12);
  --ui-fill-3: rgba(255, 255, 255, 0.16);
  --ui-hover: rgba(255, 255, 255, 0.06);
  --ui-press: rgba(255, 255, 255, 0.1);
  --ui-field-bg: rgba(255, 255, 255, 0.08);
  --ui-white-veil: rgba(255, 255, 255, 0.08);
  --ui-white-veil-strong: rgba(255, 255, 255, 0.16);
  --ui-wait-bg: rgba(255, 255, 255, 0.06);
  --ui-seg-active: rgba(255, 255, 255, 0.16);
  /* Бегунок тумблера без белого «блика»: приглушённый светлый. */
  --ui-switch-thumb: #d1d1d6;
  --ui-media-bg: #1f1f23;
  --ui-media-ring: rgba(255, 255, 255, 0.05);
  --ui-media-soft: rgba(255, 255, 255, 0.08);
  --ui-media-shot: linear-gradient(160deg, rgba(255, 255, 255, 0.12), var(--ui-accent-soft));
  --ui-pill-bg: rgba(255, 255, 255, 0.14);
  --ui-pill-ink: #fff;
  --ui-pill-ink-soft: #fff;
  --ui-sidebar-bg: color-mix(in srgb, #fff 5%, var(--ui-bg));
  --ui-sidebar-border: rgba(255, 255, 255, 0.08);
  --ui-rail-arrow: rgba(44, 44, 48, 0.92);
  --ui-sheet-cancel: rgba(44, 44, 48, 0.92);
  --ui-sheet-cancel-press: rgba(56, 56, 60, 0.95);
  --ui-tabbar-fallback: rgba(34, 34, 38, 0.72);

  --ui-glass-panel: rgba(34, 34, 38, 0.88);
  --ui-glass-panel-soft: rgba(34, 34, 38, 0.8);
  --ui-glass-panel-hold: rgba(44, 44, 48, 0.94);
  --ui-glass-glow: #38383c;
  /* Ползунок таббара в покое БЕЗ обводки: только заливка. */
  --ui-glass-thumb: rgba(255, 255, 255, 0.06);
  --ui-glass-thumb-hold: rgba(255, 255, 255, 0.09);
  --ui-glass-thumb-edge: transparent;
  --ui-glass-thumb-edge-2: transparent;
  --ui-glass-thumb-ring: transparent;
  --ui-glass-btn: rgba(34, 34, 38, 0.62);
  --ui-shop-track: rgba(255, 255, 255, 0.04);
  --ui-shop-thumb: rgba(255, 255, 255, 0.1);
  --ui-pop-light: rgba(44, 44, 48, 0.72);
  --ui-pop-light-source: rgba(44, 44, 48, 0.62);
  --ui-sheet-bg: rgba(34, 34, 38, 0.92);

  --ui-sheet-glass-bg: rgba(50, 50, 50, 0.5);
  --ui-sheet-blur: 18.5px;
  --ui-sheet-glass-shadow:
    inset -2px -2px 0.5px -2.5px rgba(255, 255, 255, 0.4),
    inset 3px 3px 0.5px -3.5px rgba(255, 255, 255, 0.4),
    inset 2px 2px 0.5px -2px #262626,
    inset -2px -2px 0.5px -2px #262626,
    inset 0 0 5px 1px #141414,
    inset 0 0 0 1px rgba(255, 255, 255, 0.15),
    inset 0 0 10px rgba(255, 255, 255, 0.075),
    inset 0 0 24px rgba(255, 255, 255, 0.05),
    0 0 25px rgba(0, 0, 0, 0.15);
  --ui-sheet-divider: rgba(255, 255, 255, 0.15);
}

/* ══════════════════════════════════════════════════════════════════════════
   БАЗА: страница, секции, карточки, строки
   Снято с .ui-page/.ui-card/.ui-row аппы. Карточка без backdrop-filter
   намеренно (см. комментарий), сквиркл ей режет squircle-часть kit.js.
   ══════════════════════════════════════════════════════════════════════════ */

body {
  margin: 0;
  background: var(--ui-bg);
  color: var(--ui-text);
  font-family: var(--ui-font);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}
html {
  -webkit-tap-highlight-color: transparent;
  background: var(--ui-bg);
}
.ui-page {
  width: min(100%, 560px);
  margin: 0 auto;
  padding: calc(14px + var(--ui-safe-top)) 0 calc(32px + var(--ui-safe-bottom));
  font-family: var(--ui-font);
  color: var(--ui-text);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
}
.ui-page * {
  box-sizing: border-box;
}
.ui-page-head {
  padding: 18px 22px 14px;
}
.ui-page-title {
  margin: 0;
  font-size: 30px;
  font-weight: 700;
  letter-spacing: -0.02em;
  line-height: 1.1;
}
.ui-page-sub {
  margin: 5px 0 0;
  color: var(--ui-hint);
  font-size: 15px;
  font-weight: 400;
  line-height: 1.35;
}
.ui-section {
  margin-bottom: 24px;
}
.ui-section-header {
  display: block;
  margin: 0 0 9px;
  padding: 0 22px;
  color: var(--ui-section-header);
  font-size: 13px;
  font-weight: 510;
  letter-spacing: 0.02em;
  line-height: 1.2;
}
.ui-section-footer {
  display: block;
  margin: 9px 0 0;
  padding: 0 22px;
  color: var(--ui-hint);
  font-size: 13px;
  line-height: 1.35;
}
.ui-section--accent .ui-section-header {
  color: var(--ui-accent);
}
.ui-section--accent .ui-card {
  background: var(--ui-accent-soft);
}
.ui-card {
  margin: 0 12px;
  overflow: visible;
  border-radius: var(--ui-radius-card);
  /* No backdrop-filter here: iOS composites backdrop-filter elements over a
     blank (white) backdrop during page-load/route animations, flashing the
     cards white. Plain translucent paint over the page gradient looks the
     same and composites correctly in every frame. */
  background: var(--ui-card);
  box-shadow: var(--ui-surface-highlight);
}
.ui-row {
  position: relative;
  display: flex;
  width: 100%;
  align-items: center;
  gap: 14px;
  min-height: 54px;
  padding: 13px 18px;
  border: 0;
  background: none;
  color: inherit;
  font: inherit;
  text-align: left;
}
.ui-row + .ui-row:before {
  content: "";
  position: absolute;
  top: 0;
  left: 18px;
  right: 0;
  height: 1px;
  background: var(--ui-separator);
  transform: scaleY(0.5);
  transform-origin: top;
  transition: opacity var(--ui-dur) var(--ui-ease);
}
.ui-row--interactive {
  cursor: pointer;
}
.ui-row--interactive:after {
  content: "";
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  background: var(--ui-press);
  opacity: 0;
  transition: opacity var(--ui-dur) var(--ui-ease);
  pointer-events: none;
}
/* The card keeps overflow: visible, so round the press highlight on the
   edge rows — otherwise its square corners poke past the card radius. */
.ui-row--interactive:first-child:after {
  border-top-left-radius: var(--ui-radius-card);
  border-top-right-radius: var(--ui-radius-card);
}
.ui-row--interactive:last-child:after {
  border-bottom-left-radius: var(--ui-radius-card);
  border-bottom-right-radius: var(--ui-radius-card);
}
@media (hover: hover) {
  .ui-row--interactive:hover:after {
    background: var(--ui-hover);
    opacity: 1;
  }
}
.ui-row--interactive:active:after {
  background: var(--ui-press);
  opacity: 1;
}
.ui-row--interactive:active:before,
.ui-row--interactive:active + .ui-row:before {
  opacity: 0;
}
@media (hover: hover) {
  .ui-row--interactive:hover:before,
  .ui-row--interactive:hover + .ui-row:before {
    opacity: 0;
  }
}
.ui-row-before,
.ui-row-body,
.ui-row-after {
  position: relative;
  z-index: 1;
}
.ui-row-press {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  z-index: 0;
  width: 100%;
  margin: 0;
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
}
.ui-row--actionable > .ui-row-before,
.ui-row--actionable > .ui-row-body,
.ui-row--actionable > .ui-row-after {
  pointer-events: none;
}
.ui-row-before {
  display: inline-flex;
  flex: 0 0 auto;
  align-items: center;
  justify-content: center;
  color: var(--ui-accent);
}
.ui-row-body {
  display: flex;
  min-width: 0;
  flex: 1 1 auto;
  flex-direction: column;
  gap: 2px;
}
.ui-row-overline {
  color: var(--ui-hint);
  font-size: 13px;
  font-weight: 400;
  line-height: 1.2;
}
.ui-row-title {
  color: var(--ui-text);
  font-size: 17px;
  font-weight: 400;
  letter-spacing: -0.01em;
  line-height: 1.3;
}
.ui-row--accent .ui-row-title {
  color: var(--ui-accent);
}
.ui-row-subtitle {
  color: var(--ui-hint);
  font-size: 13.5px;
  font-weight: 400;
  line-height: 1.3;
}
.ui-row-after {
  display: inline-flex;
  flex: 0 0 auto;
  align-items: center;
  gap: 8px;
  color: var(--ui-hint);
  font-size: 17px;
  white-space: nowrap;
}
.ui-row-value {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  color: var(--ui-text);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}
.ui-modelpicker-head {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}
.ui-row--locked {
  opacity: 0.5;
}
.ui-amount svg,
.ui-row-value svg {
  color: var(--ui-accent);
  flex: 0 0 auto;
}
.ui-submit {
  padding: 8px 22px 0;
}

/* Вуаль сверху: матовая шапка под нативными кнопками/заголовком. В аппе это
   body:before; здесь — класс, чтобы не навязывать псевдоэлемент body. */
.ui-veil {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 40;
  height: var(--ui-veil-height);
  pointer-events: none;
  background: color-mix(in srgb, var(--ui-bg) 80%, transparent);
  -webkit-backdrop-filter: blur(6px) saturate(140%);
  backdrop-filter: blur(6px) saturate(140%);
  box-shadow: 0 0.5px 0 var(--ui-veil-edge);
  transition: height 150ms var(--ui-ease);
}
/* Подложка под весь вьюпорт: резиновый оверскролл остаётся цветом фона. */
.ui-underlay {
  position: fixed;
  inset: 0;
  z-index: -1;
  background: var(--ui-bg);
  pointer-events: none;
}
.ui-fade-bottom:before {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  top: -34px;
  bottom: 0;
  pointer-events: none;
  background: linear-gradient(
    180deg,
    transparent 0%,
    color-mix(in srgb, var(--ui-bg) 30%, transparent) 30%,
    color-mix(in srgb, var(--ui-bg) 78%, transparent) 56%,
    var(--ui-bg) 80%
  );
}
.ui-heading {
  position: fixed;
  top: calc(var(--ui-safe-top) + 11px);
  left: 72px;
  right: 72px;
  z-index: 60;
  overflow: hidden;
  color: var(--ui-text);
  /* Заголовок шапки: 19 → 15.2 → 16.4px (−20%, потом +8%), интерлиньяж следом. */
  font-size: 16.4px;
  font-weight: 700;
  letter-spacing: -0.01em;
  line-height: 23px;
  text-align: center;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* ══════════════════════════════════════════════════════════════════════════
   ПОЛЯ, КНОПКИ, ЧИПСЫ, СПИННЕР
   ══════════════════════════════════════════════════════════════════════════ */
.ui-field {
  display: block;
  width: 100%;
  min-height: 92px;
  padding: 15px 18px;
  border: 0;
  outline: none;
  background: none;
  color: var(--ui-text);
  font-family: var(--ui-font);
  font-size: 17px;
  line-height: 1.45;
  resize: none;
}
.ui-field--short {
  min-height: 66px;
}
.ui-field--input {
  min-height: 0;
}
.ui-field::placeholder {
  color: var(--ui-hint);
  opacity: 1;
}
/* КАРЕТКА — НАШИМ АКЦЕНТОМ, А НЕ СИСТЕМНОЙ (02.09.2026, просьба юзера).
   По умолчанию мигающая палочка берёт цвет текста (в iOS — системный синий),
   и на розовом фоне она читается как чужая деталь. Правило одно на все поля
   разом: промпт, поиск стилей, промокод, любое будущее — иначе про новое поле
   каждый раз придётся вспоминать отдельно.
   Именно caret-color, а не color: цвет самого текста не трогаем. */
input,
textarea,
[contenteditable] {
  caret-color: var(--ui-accent);
}
.ui-button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  height: 40px;
  padding: 0 20px;
  border: 0;
  border-radius: var(--ui-radius-pill);
  background: var(--ui-accent);
  color: var(--ui-accent-text);
  cursor: pointer;
  font-family: var(--ui-font);
  font-size: 15px;
  font-weight: 600;
  line-height: 1;
  white-space: nowrap;
  transition:
    background var(--ui-dur) var(--ui-ease),
    transform var(--ui-dur) var(--ui-ease),
    opacity var(--ui-dur) var(--ui-ease);
}
@media (hover: hover) {
  .ui-button:hover:not(:disabled) {
    background: var(--ui-accent-strong);
  }
}
.ui-button:active:not(:disabled) {
  transform: scale(0.97);
}
.ui-button:disabled {
  cursor: default;
  opacity: 0.5;
}
.ui-button--large {
  width: 100%;
  height: 52px;
  font-size: 17px;
}
.ui-button--tinted {
  background: var(--ui-accent-soft);
  color: var(--ui-accent);
}
@media (hover: hover) {
  .ui-button--tinted:hover:not(:disabled) {
    background: var(--ui-accent-soft);
    filter: brightness(0.96);
  }
}
.ui-chip {
  display: inline-flex;
  max-width: 100%;
  height: 36px;
  align-items: center;
  padding: 0 15px;
  border: 0;
  border-radius: var(--ui-radius-pill);
  background: var(--ui-fill);
  color: var(--ui-text);
  cursor: pointer;
  font-family: var(--ui-font);
  font-size: 15px;
  font-weight: 500;
  white-space: nowrap;
  transition:
    background var(--ui-dur) var(--ui-ease),
    color var(--ui-dur) var(--ui-ease),
    transform var(--ui-dur) var(--ui-ease);
}
@media (hover: hover) {
  .ui-chip:hover {
    background: var(--ui-fill-2);
  }
}
.ui-chip:active {
  transform: scale(0.95);
}
.ui-chip__label {
  overflow: hidden;
  max-width: 240px;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.ui-chip--active {
  background: var(--ui-accent);
  color: var(--ui-accent-text);
  font-weight: 600;
}
@media (hover: hover) {
  .ui-chip--active:hover {
    background: var(--ui-accent-strong);
  }
}
.ui-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 9px;
  padding: 14px 18px 16px;
}
.ui-spinner {
  display: inline-block;
  width: 20px;
  height: 20px;
  color: var(--ui-hint);
  animation: ui-spin 0.85s linear infinite;
}
.ui-spinner-track {
  opacity: 0.22;
}
.ui-button .ui-spinner {
  width: 18px;
  height: 18px;
  color: inherit;
}
@keyframes ui-spin {
  to {
    transform: rotate(360deg);
  }
}
@keyframes ui-pop {
  0% {
    opacity: 0;
    transform: scale(0.94);
  }
}

/* ══════════════════════════════════════════════════════════════════════════
   ПЕРЕКЛЮЧАТЕЛЬ (.ui-switch) И СЕГМЕНТЫ
   .ui-switch — как в аппе: кнопка, состояние классом ui-switch--on, бегунок на
   ::after (сквиркл через --sq-after). .ui-segmented — плоский, .ui-seg — с
   едущим стеклянным бегунком (переключатель магазина).
   ══════════════════════════════════════════════════════════════════════════ */
.ui-switch {
  position: relative;
  flex: 0 0 auto;
  width: 70px;
  height: 31px;
  padding: 0;
  border: 0;
  border-radius: var(--ui-radius-pill);
  background-color: var(--ui-fill-3);
  cursor: pointer;
  transition: background-color var(--ui-dur) var(--ui-ease);
}
/* Мгновенная установка состояния: ставится на один кадр, когда тумблер
   приводят в соответствие с ответом сервера, а не рукой пользователя.
   Гасим переход и у самого тумблера, и у бегунка — он живёт на :after. */
.ui-switch.is-instant,
.ui-switch.is-instant:after {
  transition: none;
}
.ui-switch:after {
  content: "";
  position: absolute;
  top: 2px;
  left: 2px;
  width: 43px;
  height: 27px;
  border-radius: var(--ui-radius-pill);
  background: var(--ui-switch-thumb);
  /* ТЕНИ ПОД БЕГУНКОМ НЕТ (2026-08-06, «убери тень за ползунком, везде с этим
     ползунком»). Была `0 1px 3px #0003`. Правило одно на все переключатели —
     и в шапке профиля, и на экране согласия, и в карточках генерации, так что
     точечных исключений заводить не надо. Не путать с бегунком КАЧЕСТВА
     (`.ui-slider__thumb`): у того своя тень, она подбиралась отдельно
     десятком правок и здесь ни при чём. */
  transform: translate3d(0, 0, 0);
  backface-visibility: hidden;
  will-change: transform;
  transition: transform var(--ui-dur) var(--ui-ease);
}
/* Сквиркл бегунка: путь считает squircle.js по размерам ::after. */
.ui-switch:after {
  clip-path: var(--sq-after, none);
}
.ui-switch--on {
  background-color: var(--ui-switch-on);
}
.ui-switch--on:after {
  transform: translate3d(23px, 0, 0);
}
.ui-switch:disabled,
.ui-switch[aria-disabled="true"] {
  cursor: default;
  opacity: 0.5;
}
/* МИНИ-ТУМБЛЕР для чипа под полем промпта (07.09.2026, просьба юзера
   «маленький ползуночек когда пишешь промпт»). Те же пропорции и цвета, что у
   большого, только 42×24: бегунок 24×20 и ход 14px. Обычный .ui-switch рядом с
   однострочным полем 44px выглядел бы как второй такой же ряд настроек. */
.ui-switch--mini {
  width: 42px;
  height: 24px;
}
.ui-switch--mini:after {
  width: 24px;
  height: 20px;
}
.ui-switch--mini.ui-switch--on:after {
  transform: translate3d(14px, 0, 0);
}
.ui-segmented {
  display: inline-flex;
  gap: 2px;
  padding: 2px;
  border-radius: var(--ui-radius-pill);
  background: var(--ui-fill);
}
.ui-segment {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  height: 32px;
  padding: 0 14px;
  border: 0;
  border-radius: var(--ui-radius-pill);
  background: none;
  color: var(--ui-hint);
  cursor: pointer;
  font-family: var(--ui-font);
  font-size: 14px;
  font-weight: 600;
  white-space: nowrap;
  transition:
    background var(--ui-dur) var(--ui-ease),
    color var(--ui-dur) var(--ui-ease);
}
.ui-segment--active {
  background: var(--ui-card);
  color: var(--ui-text);
  box-shadow: 0 1px 3px #0000001f;
}
/* ── Переключатель магазина ────────────────────────────────────────────────
   ПРОСТОЙ И САМОСТОЯТЕЛЬНЫЙ. Раньше он тянул стиль и физику из таббара —
   стекло, линзу, захват пальцем, отскок. По итогу это и выглядело чужеродно,
   и постоянно ловило чужую геометрию, поэтому 18.08.2026 всё это убрано, а
   правила переписаны с нуля: плоская дорожка, плоский ползунок, один переезд.
   Ничего отсюда не наследуется и никуда не наследует — трогать можно смело.

   Уже во всю ширину в полтора раза: во всю ширину переключатель читался как
   ещё одна панель, а он — выбор внутри экрана. Через min(), а не фиксированной
   шириной: на узких экранах поля по краям важнее точной доли. */
.ui-seg {
  position: relative;
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  box-sizing: border-box;
  width: min(calc((100% - 24px) / 1.5), 336px);
  margin: 0 auto 14px;
  padding: 4px;
  border-radius: var(--ui-radius-pill);
  /* ЦВЕТ ИЗ ТОЙ ЖЕ ГАММЫ, ЧТО У НИЖНЕЙ ПАНЕЛИ, а не серый (18.08.2026).
     Прежний rgba(120,120,128,…) — нейтральная серость, и поверх розовой
     страницы она читалась грязноватой.
     18.08.2026 дорожку сделали светлой, а ползунок плотнее; 28.08.2026 юзер
     попросил поменять обратно — теперь плотная дорожка и светлая выбранная
     доля. */
  background: var(--ui-shop-track);
}
.ui-shop-tabs {
  height: 46px;
}
.ui-subs-term {
  height: 38px;
  margin-bottom: 12px;
}
/* Ползунок ровно в половину дорожки и ровно по её высоте за вычетом полей.
   Все размеры от box-sizing дорожки, поэтому ни при какой ширине экрана он не
   вылезет за край — прежняя версия это делала регулярно. */
.ui-seg__thumb {
  position: absolute;
  top: 4px;
  left: 4px;
  z-index: 0;
  width: calc(50% - 4px);
  height: calc(100% - 8px);
  border-radius: var(--ui-radius-pill);
  /* Светлее дорожки — цвет нижней панели: выбранная доля выступает вперёд.
     Чистый белый пробовали 28.08.2026, юзер забраковал. */
  background: var(--ui-shop-thumb);
  transform: translate3d(0, 0, 0);
  /* Длиннее и мягче прежних 0.28с: короткий переезд с резким торможением
     читался как рывок. Кривая с длинным хвостом — та же, что у ползунка
     таббара, там она подбиралась под тот же жест. */
  transition: transform 0.42s cubic-bezier(0.22, 1, 0.36, 1);
  pointer-events: none;
}
/* Переезд — атрибутом на дорожке. Сдвиг на 100% собственной ширины: доли
   одинаковые, значит вторая позиция ровно в ширину ползунка. */
.ui-seg[data-index="1"] .ui-seg__thumb {
  transform: translate3d(100%, 0, 0);
}
@media (prefers-reduced-motion: reduce) {
  .ui-seg__thumb {
    transition: none;
  }
}
/* Подпись строго в одну строку и по центру доли. Раньше «−5%» уходило на
   вторую строку, кнопка становилась выше соседней, и текст переставал стоять
   по центру — со стороны это читалось как кривая вёрстка (18.08.2026). */
/* FLEX, А НЕ GRID, И ЭТО ГЛАВНОЕ В ЭТОМ ПРАВИЛЕ. У грида каждый ребёнок —
   отдельная ячейка, поэтому «−5%» лежал ОТДЕЛЬНОЙ СТРОКОЙ под «3 месяца»
   (18.08.2026, юзер жаловался дважды). `white-space: nowrap` тут бессилен: он
   запрещает перенос ВНУТРИ строки, а это были два разных элемента сетки.
   Заодно чинится центровка: у грида с двумя ячейками текст стоял по центру
   двухстрочного блока, то есть выше середины кнопки. */
.ui-seg__btn {
  position: relative;
  z-index: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 5px;
  white-space: nowrap;
  border: 0;
  padding: 0;
  background: none;
  color: var(--ui-text-2);
  font: inherit;
  font-size: 15.5px;
  font-weight: 590;
  line-height: 1;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: color var(--ui-dur) var(--ui-ease);
}
.ui-seg__btn.is-active {
  color: var(--ui-text);
  font-weight: 650;
}

/* ══════════════════════════════════════════════════════════════════════════
   ПЛИТКИ ПАРАМЕТРОВ (.ui-param) И СЕТКА ПЛИТОК (.ui-cells)
   .ui-param — «модель фото / формат» на экране генерации; .ui-cell — те же
   плитки в листе выбора 2×3; .ui-cell-pair — широкая плитка с капсулами.
   ══════════════════════════════════════════════════════════════════════════ */
/* ПЛИТКИ ПАРАМЕТРОВ: «модель фото» и «соотношение сторон» стоят в один ряд как
   две карточки (07.09.2026, просьба юзера со своим макетом). Слева большой
   логотип модели или рамка кадра, справа сверху выбранное значение жирным,
   ниже подпись, у правого края шеврон из прежних строк. Остальные параметры
   остаются строками в обычной .ui-card под сеткой.
   Сетка — auto-fit: одна плитка (видео без выбора формата) растягивается на
   всю ширину, две делят ряд поровну. Отступ 12px совпадает с полями .ui-card. */
.ui-params-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(0, 1fr));
  gap: 10px;
  margin: 0 12px;
}
.ui-params-grid + .ui-card {
  margin-top: 10px;
}
.ui-param {
  position: relative;
  display: flex;
  min-width: 0;
  min-height: 62px;
  align-items: center;
  gap: 8px;
  /* Поля ужаты до 11/9px, а не 18px как у строки: в плитке шириной ~178px
     иначе не помещаются «GPT-image 2» и шеврон в одну строку. */
  padding: 13px 9px 13px 11px;
  border: 0;
  border-radius: var(--ui-radius-card);
  background: var(--ui-card);
  box-shadow: var(--ui-surface-highlight);
  color: inherit;
  font: inherit;
  text-align: left;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition:
    transform 0.12s var(--ui-ease),
    background-color 0.12s var(--ui-ease);
}
.ui-param:active {
  background: var(--ui-card-raised);
  transform: scale(0.97);
}
.ui-param__logo {
  display: inline-flex;
  flex: 0 0 auto;
  width: 32px;
  height: 32px;
  align-items: center;
  justify-content: center;
  color: var(--ui-accent);
}
.ui-param__logo img {
  display: block;
  width: 32px;
  height: 32px;
}
.ui-param__logo svg {
  width: 30px;
  height: 30px;
}
.ui-param__body {
  display: flex;
  min-width: 0;
  flex: 1 1 auto;
  flex-direction: column;
  gap: 3px;
}
.ui-param__value {
  overflow: hidden;
  color: var(--ui-text);
  font-size: 15px;
  font-weight: 700;
  letter-spacing: -0.02em;
  line-height: 1.2;
  white-space: nowrap;
  text-overflow: ellipsis;
}
/* Подпись переносится: «соотношение сторон» в одну строку не влезает даже
   мелким кеглем, а обрезать её многоточием хуже, чем дать вторую строку. */
.ui-param__title {
  color: var(--ui-hint);
  font-size: 11.5px;
  letter-spacing: -0.01em;
  line-height: 1.2;
}
.ui-param__chevron {
  flex: 0 0 auto;
  width: 7px;
  height: 12px;
  margin-left: auto;
  color: var(--ui-hint);
  opacity: 0.55;
}
/* ── Плитки моделей в листе выбора (09.09.2026, макет юзера) ──────────────
   Вместо строк «значок · название · пояснение» — сетка 2×3 плоских плиток.
   Плитка носит `.ui-param` (та же, что кнопки «модель фото» и «формат»
   на экране): радиус, фон, сквиркл (squircle.js) и нажатие берутся оттуда,
   здесь только размеры под сетку. Разметка — model_cards.js, одна на три
   листа (генерация, стиль, настройки профиля).
   Ряды одной высоты: `align-items: stretch` + `height: 100%` у плитки, а
   высота ряда — по самой высокой плитке (пояснение в две строки). */
.ui-cells {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 8px;
  padding: 4px 12px 14px;
  align-items: stretch;
}
.ui-cell.ui-param {
  position: relative;
  width: 100%;
  height: 100%;
  min-height: 72px;
  align-items: center;
  gap: 8px;
  /* Плитка вдвое уже экранной кнопки — поля ужаты, иначе «Nano Banana Pro»
     переносится на две строки. */
  padding: 9px 8px 9px 11px;
}
.ui-cell .ui-param__logo {
  width: 28px;
  height: 28px;
}
.ui-cell .ui-param__logo img {
  width: 26px;
  height: 26px;
  object-fit: contain;
  pointer-events: none;
  -webkit-user-select: none;
  user-select: none;
}
/* Название и пояснение ПЕРЕНОСЯТСЯ, а не режутся многоточием: в плитке
   шириной ~170px «Nano Banana Pro» и «отличная для редактирования» иначе
   обрезались бы. */
.ui-cell .ui-param__value {
  white-space: normal;
  font-size: 13.5px;
  letter-spacing: -0.015em;
  line-height: 1.1;
}
.ui-cell .ui-param__title {
  margin-top: 2px;
  font-size: 11px;
  line-height: 1.2;
  white-space: normal;
}
/* ВЫДЕЛЕНИЯ ТЕКУЩЕЙ МОДЕЛИ НЕТ НАМЕРЕННО (юзер, 09.09.2026): класс
   `is-active` экраны ставят ради aria, но плитка его не рисует. */
/* Заглушка «список ещё не загрузился» — не кнопка, курсор обычный. */
.ui-sheet__option--static {
  cursor: default;
}

/* ТЁМНАЯ ТЕМА (09.09.2026, владелец: «кнопочки чуть сливаются»): плитки,
   широкая плитка и капсулы в листе моделей на 5% плотнее общего --ui-card
   (0.07 → 0.12) / --ui-fill (0.08 → 0.13), размытие листа на 7% сильнее
   (18.5 → 19.8px). Только лист моделей, остальные карточки прежние. */
[data-theme="dark"] .ui-cell.ui-param,
[data-theme="dark"] .ui-cell-pair {
  background: rgba(255, 255, 255, 0.12);
}
[data-theme="dark"] .ui-cap {
  background: rgba(255, 255, 255, 0.13);
}
/* ── Широкая плитка модели с двумя режимами (макет GPT-image 2.5,
   09.09.2026, вариант A). Оформление готово заранее: сама модель и её режимы
   Sunburst / Flare подключаются бэкендом отдельно, фронт ничего не
   подставляет. Разметка, под которую написаны правила:
     <div class="ui-cells">
       <div class="ui-cell-pair">
         <span class="ui-cell-pair__head">
           <span class="ui-param__logo"><img …></span>
           <span class="ui-param__body">
             <span class="ui-param__value">GPT-image 2.5</span>
             <span class="ui-param__title">самая лучшая модель</span>
           </span>
         </span>
         <button class="ui-cap ui-cap--sun" type="button">
           <span class="ui-cap__name">Sunburst</span><small>лучше</small>
         </button>
         <button class="ui-cap ui-cap--flare" type="button">
           <span class="ui-cap__name">Flare</span><small>быстрее</small>
         </button>
       </div>
       …обычные плитки…
     </div>
   Капсулы — две кнопки, а не переключатель: выделенного состояния нет,
   тап по капсуле выбирает модель с режимом, как тап по обычной плитке. */
.ui-cell-pair {
  display: grid;
  grid-column: 1 / -1;
  grid-template-columns: 1fr 1fr;
  gap: 8px;
  padding: 9px;
  border-radius: var(--ui-radius-card);
  background: var(--ui-card);
  box-shadow: var(--ui-surface-highlight);
}
.ui-cell-pair__head {
  display: flex;
  grid-column: 1 / -1;
  min-height: 28px;
  align-items: center;
  gap: 8px;
  padding-left: 2px;
}
.ui-cell-pair__head .ui-param__logo {
  width: 28px;
  height: 28px;
}
.ui-cell-pair__head .ui-param__logo img {
  width: 26px;
  height: 26px;
}
.ui-cell-pair__head .ui-param__value {
  white-space: normal;
  font-size: 13.5px;
  letter-spacing: -0.015em;
  line-height: 1.1;
}
.ui-cell-pair__head .ui-param__title {
  margin-top: 2px;
  font-size: 11px;
  line-height: 1.2;
  white-space: normal;
}
.ui-cap {
  display: flex;
  min-height: 36px;
  align-items: center;
  justify-content: center;
  gap: 5px;
  padding: 0 8px;
  border: 0;
  border-radius: var(--ui-radius-pill);
  background: var(--ui-fill);
  color: var(--ui-text);
  font: inherit;
  letter-spacing: -0.01em;
  line-height: 1;
}
.ui-cap__name {
  font-size: 13.5px;
  font-weight: 600;
  line-height: 1;
}
.ui-cap small {
  color: var(--ui-hint);
  font-size: 11.5px;
  font-weight: 400;
  line-height: 1;
}
/* Цвета режимов — токены ниже в :root и [data-theme="dark"]: Sunburst
   тёплый оранжевый, Flare сиреневый, подобраны под розовый акцент. */
.ui-cap--sun .ui-cap__name {
  color: var(--ui-mode-sun);
}
.ui-cap--flare .ui-cap__name {
  color: var(--ui-mode-flare);
}

/* ══════════════════════════════════════════════════════════════════════════
   ПРОФИЛЬ: шапка, плитки, карточки настроек, круглый сброс, пикер темы
   ══════════════════════════════════════════════════════════════════════════ */
.ui-hero {
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: 4px 22px 24px;
  text-align: center;
}
.ui-avatar {
  position: relative;
  display: flex;
  width: 96px;
  height: 96px;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  border-radius: 50%;
  background: var(--ui-media-bg);
}
.ui-avatar__img {
  width: 100%;
  height: 100%;
  border-radius: 50%;
  object-fit: cover;
}
.ui-avatar__initials {
  color: var(--ui-ink-soft);
  font-size: 38px;
  font-weight: 600;
  letter-spacing: 0.01em;
  user-select: none;
}
.ui-avatar__person {
  display: flex;
  color: rgba(var(--ui-ink-rgb), 0.35);
}
.ui-avatar__person svg {
  width: 44px;
  height: 44px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.5;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.ui-hero__name {
  margin: 12px 0 0;
  color: var(--ui-text);
  font-size: 22px;
  font-weight: 600;
  letter-spacing: -0.01em;
  line-height: 1.2;
  overflow-wrap: anywhere;
}
.ui-hero__id {
  /* Раньше 1px — ID подпирал строку @юзернейма. Юзернейм убрали (2026-07-31),
     ID встал прямо под именем, поэтому отступ вернули к нормальному. */
  margin: 5px 0 0;
  padding: 3px 8px;
  border: 0;
  background: none;
  color: var(--ui-hint);
  cursor: pointer;
  font-family: var(--ui-font);
  font-size: 14px;
  font-weight: 400;
  line-height: 1.35;
  font-variant-numeric: tabular-nums;
  -webkit-tap-highlight-color: transparent;
  transition: opacity var(--ui-dur) var(--ui-ease);
}
.ui-hero__id:active {
  opacity: 0.55;
}
.ui-glyph {
  display: flex;
  width: 30px;
  height: 30px;
  align-items: center;
  justify-content: center;
  font-size: 23px;
  line-height: 1;
  user-select: none;
}
.ui-list-row .ui-row-after {
  color: var(--ui-ink-faint);
}
/* Строка с переключателем выше остальных: под заголовком идёт пояснение, и
   иконка обязана держаться по центру блока, а не прыгать к первой строке. */
.ui-list-row--switch {
  align-items: center;
}
.ui-list-row--switch .ui-row-body {
  padding-right: 6px;
}
/* Документ, прочитанный из профиля. Своей прокрутки у него нет — страница
   профиля скроллится целиком, поэтому это обычная карточка с текстом. */
.ui-legal-doc {
  padding: 16px;
}
.ui-legal-doc .ui-legal__h:first-of-type {
  margin-top: 0;
}
.ui-chevron {
  width: 8px;
  height: 14px;
  fill: none;
  stroke: currentColor;
  stroke-width: 2.1;
  stroke-linecap: round;
  stroke-linejoin: round;
}
/* Значение справа в строке профиля («оформление: тёмная»), перед шевроном. */
.ui-list-row__value {
  margin-right: 8px;
  color: var(--ui-hint);
  font-size: 15px;
}
.ui-list-row .ui-row-after {
  display: inline-flex;
  align-items: center;
}
/* ── КОРЕНЬ ПРОФИЛЯ: ШАПКА В СТРОКУ И ПЛИТКИ (08.09.2026, вариант «плитки» из
   ~/Desktop/ui_profile_mockup.html; юзер: без цветных квадратов и свечений,
   наш тумблер). Плитки — те же карточки, что .ui-card: подложка --ui-card,
   радиус карточки, без теней; значки контурные акцентом. ── */
.ui-hero--row {
  flex-direction: row;
  align-items: center;
  gap: 14px;
  /* Боковые поля как у карточек (.ui-card: margin 0 12px + внутренние 16px):
     шапка и плитки стояли впритык к краям экрана (08.09.2026, скриншот юзера). */
  margin: 0 12px;
  padding: 2px 6px 18px;
  text-align: left;
}
/* Мельче (08.09.2026, «с масштабом проебался»): аватар 56 → 46, имя 20 → 18,
   баланс 22 → 19. */
.ui-hero--row .ui-avatar {
  width: 46px;
  height: 46px;
  flex: 0 0 auto;
}
.ui-hero--row .ui-avatar__initials {
  font-size: 18px;
}
.ui-hero--row .ui-avatar__person svg {
  width: 24px;
  height: 24px;
}
.ui-hero__text {
  display: flex;
  min-width: 0;
  flex: 1 1 auto;
  flex-direction: column;
  align-items: flex-start;
}
.ui-hero--row .ui-hero__name {
  margin: 0;
  font-size: 18px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  max-width: 100%;
}
.ui-hero--row .ui-hero__id {
  margin: 1px 0 0;
  padding: 2px 0;
  font-size: 13px;
}
.ui-hero__balance {
  display: flex;
  flex: 0 0 auto;
  flex-direction: column;
  align-items: flex-end;
  padding: 4px 2px;
  border: 0;
  background: none;
  color: var(--ui-text);
  font-family: var(--ui-font);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
.ui-hero__balance strong {
  font-size: 19px;
  font-weight: 800;
  letter-spacing: -0.02em;
  line-height: 1.1;
  font-variant-numeric: tabular-nums;
}
.ui-hero__balance span {
  color: var(--ui-hint);
  font-size: 12px;
}
.ui-hero__balance:active {
  opacity: 0.6;
}
.ui-tiles {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 10px;
  margin: 0 12px 18px;
}
/* Плитки компактнее (08.09.2026): 112 → 88px высоты, поля 16 → 13px, значок
   26 → 22px, заголовок 16 → 15px. */
.ui-tile {
  display: flex;
  min-height: 88px;
  flex-direction: column;
  justify-content: space-between;
  align-items: flex-start;
  gap: 8px;
  padding: 13px 14px 12px;
  border: 0;
  border-radius: var(--ui-radius-card);
  background: var(--ui-card);
  box-shadow: var(--ui-surface-highlight);
  color: var(--ui-text);
  font-family: var(--ui-font);
  text-align: left;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition:
    transform 0.16s var(--ui-ease),
    background-color 0.16s var(--ui-ease);
}
.ui-tile:active {
  transform: scale(0.97);
  background: var(--ui-card-raised);
}
.ui-tile__glyph {
  display: flex;
  width: 24px;
  height: 24px;
  align-items: center;
  justify-content: center;
  color: var(--ui-accent-strong);
}
.ui-tile__glyph svg {
  width: 22px;
  height: 22px;
}
.ui-tile__text {
  display: flex;
  min-width: 0;
  max-width: 100%;
  flex-direction: column;
  gap: 2px;
}
.ui-tile__title {
  font-size: 15px;
  font-weight: 600;
  letter-spacing: -0.01em;
  line-height: 1.2;
}
.ui-tile__sub {
  overflow: hidden;
  color: var(--ui-hint);
  font-size: 12px;
  line-height: 1.3;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* Контурные значки в строках корня (тумблер, поддержка, правила, админка). */
.ui-glyph svg {
  width: 22px;
  height: 22px;
  color: var(--ui-accent-strong);
}
/* ── СТРАНИЦА «НАСТРОЙКИ» КАРТОЧКАМИ (08.09.2026): каждая карточка во всю
   ширину, как у темы; слева заголовок/значение/подпись, справа шеврон или
   тумблер; сброс — круглая кнопка в заголовке группы. ── */
.ui-set-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding-right: 16px;
}
.ui-set-head .ui-section-header {
  margin-bottom: 0;
}
.ui-set-head {
  margin-bottom: 9px;
}
.ui-set-reset {
  display: grid;
  width: 32px;
  height: 32px;
  place-items: center;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: var(--ui-card);
  color: var(--ui-accent-strong);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: transform 0.16s var(--ui-ease);
}
.ui-set-reset svg {
  width: 17px;
  height: 17px;
}
.ui-set-reset:active {
  transform: rotate(-40deg) scale(0.94);
}
.ui-set-tile {
  grid-column: 1 / -1;
  min-height: 0;
  flex-direction: row;
  align-items: center;
  gap: 12px;
  padding: 13px 16px 13px 16px;
}
.ui-set-tile__main {
  display: flex;
  min-width: 0;
  flex: 1 1 auto;
  flex-direction: column;
  gap: 3px;
}
.ui-set-tile__head {
  display: flex;
  align-items: center;
  gap: 8px;
}
.ui-set-tile__head .ui-tile__glyph {
  width: 22px;
  height: 22px;
}
.ui-set-tile__head .ui-tile__glyph svg {
  width: 20px;
  height: 20px;
}
.ui-set-tile__title {
  color: var(--ui-hint);
  font-size: 13px;
  font-weight: 500;
}
.ui-set-tile__value {
  display: block;
  overflow: hidden;
  color: var(--ui-text);
  font-size: 17px;
  font-weight: 700;
  letter-spacing: -0.01em;
  line-height: 1.2;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.ui-set-tile__aside {
  display: flex;
  flex: 0 0 auto;
  align-items: center;
  color: var(--ui-ink-faint);
}
.ui-set-tile__aside .ui-chevron {
  width: 10px;
  height: 17px;
}
div.ui-set-tile {
  cursor: default;
}
div.ui-set-tile:active {
  transform: none;
  background: var(--ui-card);
}

/* ── ШАПКА МАГАЗИНА В СТРОКУ (08.09.2026): баланс слева, премиум-стикер
   справа. ── */
.ui-topup-hero--row {
  flex-direction: row;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 2px 14px 2px 22px;
  text-align: left;
}
.ui-topup-hero__text {
  display: flex;
  min-width: 0;
  flex-direction: column;
  align-items: flex-start;
}
.ui-topup-hero__art {
  position: relative;
  display: grid;
  width: 96px;
  height: 96px;
  flex: 0 0 auto;
  place-items: center;
  pointer-events: none;
}
.ui-topup-hero__art img {
  display: block;
  width: 88px;
  height: 88px;
}
.ui-topup-hero__lottie {
  width: 96px;
  height: 96px;
}

/* ── ВЫБОР ТЕМЫ МИНИ-ЭКРАНАМИ (08.09.2026, как в Системных настройках macOS).
   Три превью 4:3: подложка темы, полоска шапки, две «карточки», розовая
   «кнопка». Выбранное — в акцентной рамке, подпись под ним жирнее. ── */
.ui-set-theme {
  display: flex;
  flex-direction: column;
  gap: 12px;
  padding: 13px 16px 14px;
}
.ui-theme-pick {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 10px;
}
.ui-theme-pick__item {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 7px;
  padding: 0;
  border: 0;
  background: none;
  color: var(--ui-hint);
  font-family: var(--ui-font);
  font-size: 12.5px;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
.ui-theme-pick__item.is-active {
  color: var(--ui-text);
  font-weight: 600;
}
.ui-theme-pick__preview {
  position: relative;
  display: block;
  width: 100%;
  aspect-ratio: 4 / 3;
  overflow: hidden;
  border-radius: 12px;
  box-shadow: inset 0 0 0 1px var(--ui-separator);
  transition:
    box-shadow 0.18s var(--ui-ease),
    transform 0.18s var(--ui-ease);
}
.ui-theme-pick__item.is-active .ui-theme-pick__preview {
  box-shadow:
    inset 0 0 0 2px var(--ui-accent),
    0 0 0 2px color-mix(in srgb, var(--ui-accent) 35%, transparent);
}
.ui-theme-pick__item:active .ui-theme-pick__preview {
  transform: scale(0.96);
}
.ui-theme-pick__preview--light {
  background: var(--ui-preview-light);
}
.ui-theme-pick__preview--dark {
  background: var(--ui-preview-dark);
}
.ui-theme-pick__preview--system {
  background: linear-gradient(105deg, var(--ui-preview-light) 0 50%, var(--ui-preview-dark) 50% 100%);
}
.ui-theme-pick__bar,
.ui-theme-pick__card,
.ui-theme-pick__btn {
  position: absolute;
  left: 12%;
  right: 12%;
  border-radius: 4px;
}
.ui-theme-pick__bar {
  top: 10%;
  height: 10%;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.62);
}
.ui-theme-pick__card {
  height: 17%;
  background: rgba(255, 255, 255, 0.62);
}
.ui-theme-pick__card:nth-of-type(2) {
  top: 28%;
}
.ui-theme-pick__card:nth-of-type(3) {
  top: 50%;
}
.ui-theme-pick__preview--dark .ui-theme-pick__bar,
.ui-theme-pick__preview--dark .ui-theme-pick__card {
  background: rgba(255, 255, 255, 0.1);
}
.ui-theme-pick__preview--system .ui-theme-pick__bar,
.ui-theme-pick__preview--system .ui-theme-pick__card {
  background: linear-gradient(105deg, rgba(255, 255, 255, 0.62) 0 50%, rgba(255, 255, 255, 0.1) 50% 100%);
}
.ui-theme-pick__btn {
  bottom: 10%;
  height: 12%;
  border-radius: 999px;
  background: var(--ui-accent);
}
.ui-theme-pick__label {
  line-height: 1.2;
  text-align: center;
}

/* ══════════════════════════════════════════════════════════════════════════
   ФОРМАТ КАДРА (.ui-ratio): карточки с рамкой пропорции
   ══════════════════════════════════════════════════════════════════════════ */
/* ── Формат внутри листа (14.08.2026) ──────────────────────────────────────
   Раньше лента форматов была отдельной секцией на странице и брала боковые
   поля от неё. В листе поля свои, а заголовок секции пропал вместе с секцией —
   поэтому он вернулся сюда, внутрь группы, иначе лист открывался без единой
   подписи и было непонятно, что вообще выбирают.
   Рейл внутри листа НЕ должен добавлять свои 12px по бокам: у группы уже есть
   собственные поля, и вместе они давали двойной отступ. */
.ui-sheet__ratio {
  padding: 14px 0 16px;
}
/* ВСЕ ФОРМАТЫ СРАЗУ, А НЕ ОДНА ПРОКРУЧИВАЕМАЯ СТРОКА (14.08.2026, просьба
   юзера). В листе горизонтальный рейл был вдвойне неудачен: лист и так
   выезжает снизу, и внутри него ещё одна прокрутка — человек видел четыре
   карточки из одиннадцати и не понимал, что есть остальные.
   Четыре колонки, а не три: при 375px это 74px на карточку, и все одиннадцать
   укладываются в три ряда без прокрутки. Три колонки дали бы четыре ряда, и
   лист занял бы пол-экрана. */
.ui-ratio-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 8px;
  padding: 0 18px;
}
.ui-ratio-grid .ui-ratio {
  width: auto;
}
/* Три формата у расширения — три колонки, а не четыре с пустой ячейкой
   (03.09.2026, просьба юзера). */
.ui-ratio-grid--three {
  grid-template-columns: repeat(3, minmax(0, 1fr));
}
.ui-ratio-rail {
  --ui-rail-gap: 8px;
  --ui-rail-peek: 18px;
  display: flex;
  gap: var(--ui-rail-gap);
  overflow-x: auto;
  padding: 0 12px;
  scrollbar-width: none;
  scroll-padding-right: 12px;
  scroll-padding-left: calc(var(--ui-rail-gap) + var(--ui-rail-peek));
  scroll-snap-type: x proximity;
  -webkit-overflow-scrolling: touch;
}
.ui-ratio-rail::-webkit-scrollbar {
  display: none;
}
.ui-ratio-rail .ui-ratio {
  width: 82px;
  flex: 0 0 auto;
  scroll-snap-align: start;
}
.ui-ratio {
  display: flex;
  aspect-ratio: 3 / 4;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 9px;
  padding: 10px 6px;
  border: 0;
  border-radius: var(--ui-radius-card);
  background: var(--ui-card);
  box-shadow: inset 0 0 0 0.5px rgba(var(--ui-ink-rgb), 0.08);
  color: var(--ui-text);
  cursor: pointer;
  font: inherit;
  -webkit-tap-highlight-color: transparent;
  transition:
    transform 0.15s var(--ui-ease),
    background-color 0.2s var(--ui-ease),
    color 0.2s var(--ui-ease);
}
.ui-ratio:active {
  transform: scale(0.96);
}
.ui-ratio__frame {
  display: block;
  max-width: 74%;
  /* Ограничения с обеих сторон: у 16:9 ширина упирается первой, у 9:16 —
     высота, и без пары max-* кадр вылезал бы за карточку. */
  max-height: 64%;
  border: 1.5px dashed rgba(var(--ui-ink-rgb), 0.38);
  border-radius: 5px;
  background: #fff;
}
.ui-ratio__label {
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 0.01em;
  line-height: 1;
}
.ui-ratio.is-active {
  background: var(--ui-accent);
  color: var(--ui-accent-text);
}
.ui-ratio.is-active .ui-ratio__frame {
  border-color: rgba(255, 255, 255, 0.9);
  background: rgba(255, 255, 255, 0.96);
}

/* «авто» в ленте форматов: пропорции у него нет, поэтому в кадре звёздочка —
   «какой получится». */
.ui-ratio__frame--auto {
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--ui-accent);
}
/* Звезда «авто». Размер 78% → 62% (−20%, 2026-07-31). Форма мягкая: лучи —
   вогнутые кубические кривые, а кончики скруглены обводкой того же цвета с
   round-соединениями — прежняя угловатая звезда юзеру не понравилась.
   Обводка здесь не контур, а инструмент скругления: цвет у неё тот же, что и
   заливка, поэтому фигура остаётся сплошной. */
.ui-ratio__frame--auto svg {
  width: 62%;
  height: 62%;
  fill: currentColor;
}
.ui-ratio.is-active .ui-ratio__frame--auto {
  color: var(--ui-accent-strong);
}

/* ══════════════════════════════════════════════════════════════════════════
   ПОЛЗУНОК (.ui-slider): дорожка, деления, капсула-бегунок, стекло на удержании
   Числа геометрии продублированы в kit.js (createSlider): менять вместе.
   ══════════════════════════════════════════════════════════════════════════ */
/* ── Качество ползунком (2026-07-31) ──
   Вместо трёх кнопок — шкала «меньше → больше». Дорожка, заливка и бегунок —
   СВОИ элементы, а нативный `input[type=range]` лежит поверх прозрачным: он
   по-прежнему ловит касания, тянется и работает с клавиатуры, но рисовать его
   псевдоэлементами нельзя — ни трансформировать бегунок, ни повесить на него
   слои стекла. Поэтому вид целиком на своих узлах, поведение — на нативном.
   Подложки-карточки под ползунком нет: он лежит прямо на фоне экрана. */
.ui-slider {
  display: flex;
  align-items: center;
  gap: 12px;
  margin: 0 22px;
}
.ui-slider__cap {
  flex: 0 0 auto;
  color: var(--ui-hint);
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 0.01em;
}
/* Высота с запасом снизу: там ряд делений, он ПОД дорожкой, а не на ней. */
.ui-slider__slider {
  position: relative;
  display: block;
  min-width: 0;
  height: 34px;
  flex: 1 1 auto;
}
/* WEBGL-СТЕКЛО КАПСУЛЫ (только apple, 04.09.2026): канвас во весь слайдер,
   над дорожкой и под DOM-капсулой; вне капсулы прозрачный. Рисует
   quality_slider.js, пока капсула в стекле. На остальных платформах —
   display: none, там работает SVG-преломление через backdrop-filter. */
.ui-slider__gl {
  position: absolute;
  inset: 0;
  z-index: 1;
  display: none;
  width: 100%;
  height: 100%;
  pointer-events: none;
}
html[data-font-platform="apple"] .ui-slider__gl {
  display: block;
}
/* Капсула над канвасом; пока стекло рисует канвас, её собственная подложка
   прозрачная (в `.is-holding` она и так transparent, `.is-glass` держит это
   и на спаде надувания после отпускания). */
.ui-slider__thumb {
  z-index: 2;
}
.ui-slider__thumb.is-glass {
  --thumb-fill: transparent;
}
.ui-slider__thumb::before {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  background: var(--thumb-fill);
  clip-path: var(--sq, none);
  transition: background-color 0.16s var(--ui-ease);
}
/* Дорожка тоньше на 20% (8 → 6.4px, 2026-08-05, просьба юзера «сделай палку
   тоньше примерно на 20 процентов»). `top` пересчитан так, чтобы ВЕРТИКАЛЬНЫЙ
   ЦЕНТР остался на 14px — на нём же стоит центр бегунка, и от него отмерены
   деления. Менять высоту, не трогая top, значит увести дорожку вверх.

   ПЕРЕХОДОВ ЗДЕСЬ НЕТ НАМЕРЕННО. `top`, `height`, `left` и `right` дорожки
   пишет покадрово js — это резинка на упорах (см. `QUALITY_OVER_*` в
   generate.js/restore.js). Любой transition на этих свойствах дрался бы с
   покадровой анимацией ровно так же, как дрался бы transform у бегунка.
   Числа 10.8/6.4 продублированы в js константами `QUALITY_TRACK_H` и
   `QUALITY_AXIS_Y` — меняешь тут, меняй и там. */
.ui-slider__track {
  position: absolute;
  top: 10.8px;
  right: 0;
  left: 0;
  overflow: hidden;
  height: 6.4px;
  border-radius: var(--ui-radius-pill);
  background: var(--ui-fill-2);
}
.ui-slider__fill {
  display: block;
  height: 100%;
  border-radius: var(--ui-radius-pill);
  background: var(--ui-accent);
}
/* Деления — ПОД дорожкой, отдельным рядом, как в системном слайдере. Боковые
   поля равны половине ширины бегунка (18.47px при ширине 36.94), иначе крайние
   точки не совпадают с его центром в крайних положениях. Меняешь ширину
   бегунка — обязательно меняй и это число, и `QUALITY_THUMB_W` в generate.js и
   restore.js: три места, одна величина. */
.ui-slider__ticks {
  position: absolute;
  top: 30px;
  /* 18.47 → 19.39 → 18.43: бегунок +5%, затем −5% со всех сторон
     (04.09.2026); поля — половина его ширины. */
  right: 18.43px;
  left: 18.43px;
  display: flex;
  justify-content: space-between;
  pointer-events: none;
}
.ui-slider__ticks i {
  width: 3px;
  height: 3px;
  border-radius: 50%;
  background: rgba(var(--ui-ink-rgb), 0.2);
}
/* Прозрачность КАЖДОЙ точки пишет js покадрово: гаснет ровно та, которую
   накрыла раздутая капсула, остальные остаются на месте (2026-08-05). Поэтому
   никакого transition здесь быть не должно — он дрался бы с покадровой
   записью, как и везде у этого ползунка. */
/* Бегунок — капсула той же формы, что кнопка переключателя (радиус пилюли, та
   же тень). Размер: 43x27 → 34x27 («менее длинным») → −20% = 27x22 → 40.5x23.1
   (2026-08-05: «по высоте на 5% выше, в полтора раза длиннее» — по системному
   слайдеру iOS со скриншота юзера) → 32.4x22.64 (в тот же день: «ебать он
   длинный», −20% по длине и −2% по высоте) → 38.88x27.17 (тогда же, крупный
   скриншот рядом с эпловским: «форму повторил идеально, но он маленький,
   процентов на 20 больше» — обе стороны ×1.2) → 36.94x25.81 (финальная подгонка
   того же дня: −5% по обеим сторонам).
   `top` пересчитан от прежнего центра 14px: 14 − 25.81/2 = 1.1. Так меняющийся
   бегунок растёт и убывает вверх-вниз симметрично, а дорожка и деления остаются
   на своих местах. Запас сверху невелик: замер — бегунок занимает 1.1…26.91
   при контейнере 34px и делениях на 30px. Ещё прибавка по высоте — и придётся
   растить `.ui-slider__slider`, иначе бегунок полезет на деления.
   Позицию и «желе» (растяжение по скорости, надувание при удержании) считает
   js и кладёт в transform, поэтому здесь никаких переходов на transform —
   иначе они дрались бы с покадровой анимацией. */
.ui-slider__thumb {
  position: absolute;
  /* 36.94×25.81 → 38.79×25.81 («длиннее на 5%») → 36.85×24.52 («уменьши на
     5% со всех сторон»), 04.09.2026. top держит центр на 14px. */
  top: 1.75px;
  left: 0;
  width: 36.85px;
  height: 24.52px;
  border-radius: var(--ui-radius-pill);
  /* ЗАЛИВКА ЖИВЁТ НА ::before (08.09.2026, сквиркл): форму режет clip-path, а
     он отрезал бы внешнюю тень; поэтому тень остаётся на самом бегунке, а
     заливка со сквирклом — на псевдослое. Цвет — через --thumb-fill. */
  --thumb-fill: var(--ui-switch-thumb);
  background: transparent;
  /* В покое — ТОЛЬКО внешняя тень, больше ничего. Волосяная обводка
     `inset 0 0 0 0.5px` убрана 2026-08-05: на крупном скриншоте рядом с
     эпловским бегунком юзер увидел её как лишний контур («убери мини-обводку,
     оставь онли тень»), и он прав — у системного слайдера капсула держится на
     одной тени. В состоянии `is-holding` обводка ОСТАЁТСЯ и трогать её там
     нельзя: подложка на удержании прозрачная, и без контура стеклянная пилюля
     просто исчезнет. Тень ВНУТРИ СВЕРХУ здесь тоже НЕ нужна: она часть стекла
     и появляется только на удержании (2026-07-31, просьба юзера — в покое она
     читалась как грязь на белой капсуле).

     Тень переделана 2026-08-05 «как у эпла»: не одна жёсткая полоска под
     кромкой, а два слоя — плотный контактный и широкий мягкий. Радиус размытия
     3 → 9px выбран по площади: юзер просил, чтобы тень занимала места втрое
     больше, а ореол вокруг капсулы растёт как (w+b)(h+b) − w·h, и при 40.5×23.1
     утроение даёт ровно b ≈ 8.4 ≈ 9. Цвет НЕ трогали — тот же чёрный, что был
     в `#0003`.

     Затем в тот же день: «эффект слабее в 2 раза, площадь оставь». Поэтому
     РАЗМЫТИЕ И СМЕЩЕНИЯ НЕ ТРОГАЛИ ВООБЩЕ (они и есть площадь), пополам делится
     только альфа: 0.22 → 0.11 и 0.1 → 0.05. Это единственная ручка силы тени:
     уменьшишь размытие — уедет площадь, за которую юзер держится отдельно.

     И финально: «тень ВОКРУГ ВСЕГО ползунка, площадь +20%». Смещение по Y
     обнулено — при `y = 3` и размытии 9 сверху оставалось 1.5px ореола, а снизу
     7.5px, и тень читалась как «под капсулой», а не «вокруг». Теперь ореол
     одинаков со всех сторон. Размытие 9 → 11px посчитано по той же формуле
     `(w+b)(h+b) − w·h`: при 36.94×25.81 это даёт +20% к прежнему ореолу.
     Альфы не трогали — просьба была про площадь, а не про силу.
     А вот следом («для афк ползунка сделай тень сильнее на 20 процентов»)
     трогали РОВНО альфы и ничего больше: 0.05 → 0.06 и 0.11 → 0.132. Площадь
     при этом обязана остаться прежней — она подбиралась отдельным требованием
     двумя правками раньше. */
  box-shadow:
    0 0 2.4px rgba(0, 0, 0, 0.06),
    0 0 11px rgba(0, 0, 0, 0.132);
  pointer-events: none;
  transform-origin: 50% 50%;
  transition:
    box-shadow 0.16s var(--ui-ease),
    background-color 0.16s var(--ui-ease);
  will-change: transform;
}
/* Стекло при удержании: чистая кромка системного слайдера — обводка, тень
   вдоль всей кромки и тень под верхней. РАЗМЫТИЯ НЕТ намеренно — юзер попросил
   без него, и backdrop-filter здесь не заводится вовсе: это самая дорогая часть
   эффекта, а бегунок ездит покадрово.

   ХРОМАТИЧЕСКОЙ АБЕРРАЦИИ БОЛЬШЕ НЕТ (2026-08-05). Четыре цветных слоя
   (`rgba(255,0,132)` слева, `rgba(0,168,255)` справа и пара сверху/снизу) были
   перенесены сюда с ползунка таббара, но на скриншоте рядом с эпловским
   слайдером юзер увидел их как толстый розово-голубой кант и забраковал:
   «смотри какую хуйню сделал ты, спизди 1 в 1 (кроме цвета)». У системного
   слайдера кант нейтральный. Слои удалены, остались только три тени в нашем
   тоне `rgba(43,16,32)` — «кроме цвета» относится именно к этому: рецепт
   эпловский, оттенок наш, серый оттуда не тащим. */
.ui-slider__thumb.is-holding {
  /* Подложка ПРОЗРАЧНАЯ. Пробовали дважды и оба раза откатили: ровную молочную
     `rgba(252,240,246,.44)` (31.07, «нужен чистый прозрачный кадр») и
     вертикальный градиент `rgba(255,255,255,.14 → .5)` (05.08, «ты че нахуй
     сделал? убери эту хуйню»). Не возвращать ни в каком виде — тело капсуле
     даёт тень под ней, а не заливка внутри.
     Размытия тоже нет намеренно — `backdrop-filter` не объявлен вовсе: это
     самая дорогая часть эффекта, а бегунок ездит покадрово. */
  --thumb-fill: transparent;
  /* ТЕНЬ ВНУТРИ — ПОЛУМЕСЯЦ ПОД ВЕРХНЕЙ КРОМКОЙ, А НЕ ЗАЛИВКА СИЛУЭТА.
     Этот слой переделывали трижды, и все три промаха стоит помнить:
     1. `inset 0 0 6px` без смещения — кольцо по ВСЕМУ периметру. Забраковано:
        «есть ебанная тень ползунка вокруг обводки внутри».
     2. Слоя нет вовсе — капсула превращается в голую дырку с контуром.
     3. `::before` с залитым силуэтом, сдвинутым вниз (попытка показать тень на
        дорожке сквозь стекло). Забраковано: «ты взял весь ползунок нахуярил,
        оно как пончик должно быть».
     Правильное — направленный inset со СМЕЩЕНИЕМ ВНИЗ и отрицательным spread:
     он рисует дугу вдоль верхней кромки и сходит на нет к середине. Именно так
     выглядит стекло на референсе, и именно это юзер называет «пончиком»:
     затемнение идёт по кромке, а середина остаётся чистой.
     Ключ — spread: без него (`inset 0 3px 6px`) тень расползается по всей
     капсуле и получается ровно тот самый залитый силуэт.

     КАК ЕГО КРУТИТЬ (2026-08-05, «более выраженным: площадь +10%, сила +10%»).
     Глубина полумесяца считается как `смещение + размытие/2 + spread`, где
     spread отрицательный и потому вычитается: было `3 + 6/2 − 2 = 4px`, стало
     `3 + 6.8/2 − 2 = 4.4px`, ровно +10%. То есть ПЛОЩАДЬ крутится размытием,
     а СИЛА — альфой (0.3 → 0.33). Смещение и spread не трогать: смещение
     задаёт, что дуга именно сверху, а spread — что она не расползается.

     ОБВОДКА ЗДЕСЬ 0.34px, А НЕ 0.5px КАК В ПОКОЕ, И ЭТО НЕ ОПЕЧАТКА. В захвате
     js раздувает бегунок до `scale(1.462)`, и вместе с ним масштабируется
     толщина линии: объявленные 0.5px рисуются как 0.73px — отсюда и жалоба
     «обводка жирнючая сука», хотя число то же, что в покое. 0.5 / 1.462 = 0.34
     возвращает ей на экране ровно ту же толщину, что у спокойного бегунка.
     Меняешь `QUALITY_GRAB` — пересчитывай и это число.
     Сила обводки — только альфа: 0.26 → 0.24 (2026-08-06, «совсем чуть чуть
     светлее»). Толщину 0.34px при этом не трогать — она привязана к
     `QUALITY_GRAB`, а не к тому, насколько контур тёмный.
     Тень под капсулой ослаблялась на 20% ДВАЖДЫ подряд: альфы 0.26 → 0.21 →
     0.168 и 0.12 → 0.096 → 0.077, затем ещё на 15% (2026-08-06): 0.168 → 0.143
     и 0.077 → 0.065. Геометрия ни разу не тронута — за форму «силуэта»
     отвечает соотношение смещения и размытия, а не сила. */
  /* 04.09.2026 (просьба юзера, по скрину рядом с iOS): обводка вдвое тоньше
     (0.34 → 0.17px), но темнее (0.24 → 0.62); плюс два белых блика ВНУТРИ у
     верхней и нижней стенки (`inset 0 ±1px`), как на эпловской капсуле.
     Полумесяц под верхней кромкой и внешние тени не тронуты. */
  box-shadow:
    0 5px 5px rgba(var(--ui-ink-rgb), 0.143),
    0 9px 14px rgba(var(--ui-ink-rgb), 0.065),
    inset 0 0 0 0.17px rgba(var(--ui-ink-rgb), 0.62),
    /* верхний блик −10% (0.8 → 0.72), нижний как был (04.09.2026) */
    inset 0 1px 0 -0.1px rgba(255, 255, 255, 0.72),
    inset 0 -1px 0 -0.1px rgba(255, 255, 255, 0.7),
    /* полумесяц: площадь +7% (размытие 6.8 → 7.4, по формуле 3 + b/2 − 2),
       сила −7% (0.33 → 0.307) — 04.09.2026 */
    inset 0 3px 7.4px -2px rgba(var(--ui-ink-rgb), 0.307);
}
/* СТЕКЛО С ИСКАЖЕНИЕМ — ТОЛЬКО ANDROID/WINDOWS (2026-08-05, просьба юзера).
   Настоящее преломление фона под капсулой, `backdrop-filter: url()` со своим
   SVG-фильтром (собирается в index.html, `#ui-lg-quality`).

   ГДЕ РАБОТАЕТ. Класс `ui-lg-refract` ставит скрипт линзы, а он сам
   запускается только при `Chrome/` в UA — то есть на iOS/WKWebView его нет в
   принципе (WebKit ссылку на SVG-фильтр в backdrop-filter не рисует, см.
   комментарий у таббара). `:not([data-font-platform="apple"])` добивает случай
   Chrome на маке. Итого остаются ровно Android и Windows.

   ТОЛЬКО НА УДЕРЖАНИИ. В покое фильтра нет вовсе — не «нулевой scale», а
   именно нет: цепочка (блюр + saturate + displacement + композиты) считается
   каждый кадр, пока капсула едет, и в покое это чистая трата. Та же грабля уже
   ловилась на ползунке таббара.

   АБЕРРАЦИИ НЕТ — фильтр собран с `aberrationChannels(0)`, один канал.
   ТЕНЬ ВЫШЕ ИСКАЖЕНИЯ и доделывать для этого ничего не пришлось:
   backdrop-filter обрезается по border-box капсулы, а тени рисуются поверх
   результата как часть элемента; внешняя тень вообще лежит за рамкой. */
html.ui-lg-refract:not([data-font-platform="apple"])
  .ui-slider__thumb.is-holding {
  -webkit-backdrop-filter: url(#ui-lg-quality);
  backdrop-filter: url(#ui-lg-quality);
}
/* ТЁМНАЯ ТЕМА, УДЕРЖАНИЕ: тот же прозрачный кадр с контуром и тенями, что и в
   светлой, только заливка белая на 12% (просьба юзера 08.09.2026: «просто
   прозрачность понизь до 88»). Геометрию и раздувание не трогаем. */
[data-theme="dark"] .ui-slider__thumb.is-holding {
  /* 0.12 → 0.07 («прозрачность 93», 08.09.2026). */
  --thumb-fill: rgba(255, 255, 255, 0.07);
  /* Контур в тёмной теме мягче: вместо тёмного кольца и белых бликов 0.7 —
     белое кольцо 30% и блики 22%, тени чёрные. Светлая тема не тронута. */
  box-shadow:
    0 5px 5px rgba(0, 0, 0, 0.2),
    0 9px 14px rgba(0, 0, 0, 0.1),
    inset 0 0 0 0.17px rgba(255, 255, 255, 0.3),
    inset 0 1px 0 -0.1px rgba(255, 255, 255, 0.22),
    inset 0 -1px 0 -0.1px rgba(255, 255, 255, 0.2),
    inset 0 3px 7.4px -2px rgba(0, 0, 0, 0.3);
}
/* Нативный input: прозрачный, но живой — он и есть область касания. */
.ui-slider__range {
  position: absolute;
  z-index: 2;
  top: 0;
  right: 0;
  left: 0;
  width: 100%;
  height: 28px;
  margin: 0;
  padding: 0;
  border: 0;
  appearance: none;
  -webkit-appearance: none;
  background: transparent;
  cursor: pointer;
}
.ui-slider__range::-webkit-slider-runnable-track {
  height: 8px;
  background: transparent;
}
.ui-slider__range::-moz-range-track {
  height: 8px;
  background: transparent;
}
.ui-slider__range::-webkit-slider-thumb {
  width: 27px;
  height: 22px;
  margin-top: -7px;
  border: 0;
  appearance: none;
  -webkit-appearance: none;
  background: transparent;
  opacity: 0;
}
.ui-slider__range::-moz-range-thumb {
  width: 27px;
  height: 22px;
  border: 0;
  background: transparent;
  opacity: 0;
}
@keyframes ui-thumb-bounce {
  0% {
    scale: 1 0.9;
  }
  35% {
    scale: 1 1.08;
  }
  68% {
    scale: 1 0.97;
  }
  100% {
    scale: 1 1;
  }
}

/* ══════════════════════════════════════════════════════════════════════════
   ПОЛЕ ЗАПРОСА (.ui-prompt): растёт под текст, плейсхолдер с акцентным словом
   ══════════════════════════════════════════════════════════════════════════ */
/* Отступ от промпта до референсов: 24 → 21.6 → 18 → 14px (28.08.2026). Только
   у этой секции — остальные интервалы на экране остаются прежними.
   С 07.09.2026 референсы стоят ВЫШЕ промпта (просьба юзера), и те же 12px
   теперь стоят между референсами и промптом, а прежние 12px промпта — между
   промптом и плитками параметров: три верхних блока держатся одним ритмом. */
.ui-prompt-section.ui-section {
  margin-bottom: 12px;
}
/* Поле промпта на экране генерации РАСТЁТ ПОД ТЕКСТ: начинается низким, тянется
   до потолка, дальше листается (просьба юзера 28.08.2026). Высоту ставит
   скрипт, здесь только границы. Отдельный класс, а не общее правило: на экране
   стилей то же поле фиксированной высоты и без скрипта — сняв там высоту, мы
   схлопнули бы его до двух строк навсегда. */
.ui-prompt.ui-prompt--grow.ui-field {
  height: auto;
  /* Одна строка и минимум воздуха вокруг: пустое поле не должно занимать
     экран (28.08.2026, дважды «сделай ещё меньше»). Ниже уже не опустить —
     упрёмся в саму строку текста. Вертикальные поля 16 → 11px, иначе высоту
     держали бы они, а не содержимое. */
  /* Высота одной строки — 44px: столько же, сколько у кнопок и строк списка,
     и ровно рекомендованный минимум для касания. По дороге пробовали 50, 40,
     34, 32, 28 и 26 — 26 оказалось «пизда какая-то» (28.08.2026), меньше 44
     смысла нет.
     ВЕРТИКАЛЬНОЕ ЦЕНТРИРОВАНИЕ ОДНОЙ СТРОКИ. У textarea нет ни flex, ни
     align-items, поэтому строке задана высота, равная внутренней: 44px минус
     поля по 10px. Как только строк становится больше, правило ниже (.is-tall)
     возвращает обычный множитель. */
  height: 44px;
  min-height: 44px;
  max-height: 220px;
  /* Рост под текст — переходом, а не скачком (просьба юзера 28.08.2026).
     Радиус едет вместе с высотой: он меняется ровно в тот момент, когда текст
     переходит на вторую строку. */
  transition:
    height 0.18s var(--ui-ease),
    border-radius 0.18s var(--ui-ease);
  padding: 10px 18px;
  font-size: 16px;
  line-height: 24px;
  /* Таблетка, пока строка одна. Радиус в 999px движок режет до половины
     высоты, поэтому торцы остаются полукруглыми сами собой. */
  border-radius: var(--ui-radius-pill);
}
/* ПЛЕЙСХОЛДЕР С АКЦЕНТНЫМ ПЕРВЫМ СЛОВОМ (02.09.2026, просьба юзера).
   Родной `::placeholder` — один текстовый узел, покрасить в нём отдельное
   слово нечем. Поэтому он прозрачный, но НА МЕСТЕ: по нему работает
   `:placeholder-shown` ниже и его читает скринридер, — а видимый текст рисует
   слой рядом с полем.

   Геометрия повторена вручную и обязана совпадать с полем: те же поля
   10px/18px, тот же кегль 16px и та же строка 24px, иначе подсказка поедет
   относительно курсора. Меняешь одно — правь и второе. */
.ui-prompt-card {
  position: relative;
}
.ui-prompt.ui-prompt--grow::placeholder {
  color: transparent;
}
.ui-prompt-ph {
  position: absolute;
  top: 10px;
  right: 18px;
  left: 18px;
  display: none;
  overflow: hidden;
  color: var(--ui-hint);
  font-size: 16px;
  line-height: 24px;
  /* Слой лежит поверх поля, но касания и выделение достаются полю. */
  pointer-events: none;
  -webkit-user-select: none;
  user-select: none;
  white-space: nowrap;
  text-overflow: ellipsis;
}
/* Показываем ровно тогда, когда поле пустое. Никакого js: `:placeholder-shown`
   гаснет на первом же введённом символе и возвращается, когда текст стёрли. */
.ui-prompt.ui-prompt--grow:placeholder-shown + .ui-prompt-ph {
  display: block;
}
.ui-prompt-ph b {
  color: var(--ui-accent);
  font-weight: inherit;
}
/* Текст перешёл на вторую строку — возвращаем карточный радиус: у высокого
   поля полукруглые торцы читаются как овал. Класс ставит скрипт вместе с
   высотой. */
.ui-prompt.ui-prompt--grow.ui-field.is-tall {
  border-radius: 22px;
  /* Многострочный текст — обычный интерлиньяж. Центрирование одной строки
     высотой строки (см. выше) здесь только растащило бы абзац. */
  line-height: 1.3;
}
.ui-prompt.ui-field {
  height: 220px;
  min-height: 220px;
  max-height: 220px;
  padding: 16px 18px;
  overflow-y: auto;
  font-size: 14.5px;
  line-height: 1.45;
  resize: none;
  -webkit-overflow-scrolling: touch;
  overscroll-behavior: contain;
}
.ui-section-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
}
.ui-section-head .ui-section-header:last-child {
  color: var(--ui-hint);
  font-weight: 400;
}
/* ЧИП «ИИ УЛУЧШЕНИЕ» — В ШАПКЕ СЕКЦИИ «ПРОМПТ», справа (07.09.2026, вариант 5
   из макета, выбор юзера; до этого был строкой под полем). Наследует поля и
   нижний отступ .ui-section-header, чтобы стоять вровень с заголовком слева;
   молния акцентом, подпись цветом подсказки, мини-тумблер. */
.ui-prompt-boost.ui-section-header {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  color: var(--ui-hint);
  font-weight: 400;
}
/* Перебор лимита под полем, у правого края («−94», красным через is-over);
   обычного счётчика нет с 07.09.2026 (просьба юзера). Отступ сверху 6px, нижнее
   поле заголовка снято, иначе промпт отъезжал бы от плиток на лишние 9px. */
.ui-prompt-foot {
  display: flex;
  justify-content: flex-end;
  margin-top: 6px;
}
.ui-prompt-foot .ui-section-header {
  margin-bottom: 0;
}
/* Строка есть только при переборе лимита («−94»); свой display: flex иначе
   перебил бы браузерное [hidden]. */
.ui-prompt-foot[hidden] {
  display: none;
}
.ui-prompt-boost__bolt {
  flex: 0 0 auto;
  width: 14px;
  height: 14px;
  color: var(--ui-accent);
}
.ui-prompt-boost__label {
  white-space: nowrap;
}
/* Вместо цветного эмодзи — монохромный знак в акценте: эмодзи выбивался из
   набора (системный глиф не перекрашивается и всегда ярче остального ряда),
   2026-07-31. */
.ui-row-icon {
  display: inline-flex;
  width: 26px;
  height: 26px;
  align-items: center;
  justify-content: center;
  color: var(--ui-accent);
}
.ui-row-icon svg {
  width: 100%;
  height: 100%;
}

/* ══════════════════════════════════════════════════════════════════════════
   ЛЕНТА РЕФЕРЕНСОВ (.ui-refs): плитки, крестик, пунктирный «плюс»
   ══════════════════════════════════════════════════════════════════════════ */
/* ЛЕНТА РЕФЕРЕНСОВ — ОДНА СТРОКА С ГОРИЗОНТАЛЬНЫМ ЛИСТАНИЕМ (10.08.2026,
   просьба юзера). Была сетка с переносом: пятый референс уезжал на второй ряд и
   двигал вниз всё, что под ним. Теперь строка одна и никогда не переносится —
   `flex` + `overflow-x: auto`, у плиток `flex: 0 0 <ширина>`, чтобы их не жало
   под ширину экрана.

   ПЛИТКИ ФИКСИРОВАННОЙ ШИРИНЫ, А НЕ `1fr` (та же дата, «сделай на 20% меньше»).
   Было `minmax(92px, 1fr)`: 92px — только минимум, а дальше колонки тянулись на
   всю строку, и на 375px выходило три плитки по 109px. Через минимум размер так
   не убавить — растяжка всё равно вернула бы 109px. Поэтому ширина задана
   прямо: 87px = 109 − 20%. Радиусы пересчитаны в той же пропорции (18 →
   14.5px), иначе на уменьшённом квадрате углы читаются заметно круглее.

   ХВОСТ СЛЕДУЮЩЕЙ ПЛИТКИ ПОЛУЧАЕТСЯ САМ, ПОДГОНЯТЬ НИЧЕГО НЕ НАДО. Считается
   так: 12px отступ + плюс 87 + 12 + «вставить» 43.5 + 12 + плитки по 87 через
   12. На экране 375px третья плитка начинается на 364.5 — то есть выглядывает
   ровно на 10.5px. Это и есть просьба «чтобы чуть-чуть торчала следующая».
   Пока лента помещается целиком, не торчит ничего — и правильно, листать
   нечего. `scroll-snap` СОЗНАТЕЛЬНО НЕ ВКЛЮЧЁН: ширины в ленте разные (плюс
   87, «вставить» 43.5, фото 87), и обязательная привязка дёргала бы ленту к
   разнокалиберным точкам.

   `padding-top: 9px` — не про воздух, а про крестик удаления: он торчит на 7px
   выше плитки, а у скролл-контейнера `overflow-y` перестаёт быть `visible` и
   срезал бы его. В padding контейнера крестик попадает и остаётся целым. */
.ui-refs {
  --ui-ref-tile: 87px;
  display: flex;
  gap: 12px;
  /* Справа НЕ padding, а отступ у последней плитки (ниже). Причина известная:
     часть вебвью на WebKit не учитывает правый padding у флексового
     скролл-контейнера, и в конце ленты последняя плитка липла бы к кромке
     экрана вместе со своим крестиком. Отступ у элемента считают все. */
  padding: 5px 0 0 12px;
  overflow-x: auto;
  overflow-y: hidden;
  scrollbar-width: none;
  -webkit-overflow-scrolling: touch;
  overscroll-behavior-x: contain;
}
.ui-refs::-webkit-scrollbar {
  display: none;
}
.ui-refs > * {
  flex: 0 0 var(--ui-ref-tile);
}
.ui-refs > :last-child {
  margin-right: 12px;
}
.ui-ref {
  position: relative;
  display: block;
}
.ui-ref img {
  display: block;
  width: 100%;
  aspect-ratio: 1;
  border-radius: 14.5px;
  object-fit: cover;
  box-shadow: inset 0 0 0 0.5px rgba(var(--ui-ink-rgb), 0.08);
}
.ui-ref__remove {
  position: absolute;
  top: -7px;
  right: -7px;
  display: grid;
  place-items: center;
  width: 26px;
  height: 26px;
  padding: 0;
  border: 2px solid var(--ui-bg);
  border-radius: 50%;
  background: rgba(var(--ui-ink-rgb), 0.78);
  color: #fff;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
.ui-ref__remove svg {
  width: 11px;
  height: 11px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.8;
  stroke-linecap: round;
}
.ui-ref-add {
  display: grid;
  place-items: center;
  aspect-ratio: 1;
  padding: 0;
  border: 1.5px dashed var(--ui-dash);
  border-radius: 14.5px;
  background: transparent;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
.ui-ref-add:active {
  background: var(--ui-press);
}
/* Файл тащат в окно — плюс подсвечивается, чтобы было видно, куда он упадёт.
   Класс вешает photo_picker.js на саму сетку, а не на плитку: плитки в ней
   перерисовываются при каждом добавлении. */
.ui-refs.is-drop-target .ui-ref-add {
  border-color: var(--ui-accent-strong);
  background: var(--ui-press);
}
/* Кружок с плюсом ужат в той же пропорции, что и плитка (40 → 32px, значок
   18 → 14.5px): оставить прежний — и он занял бы почти весь уменьшённый
   квадрат, вместо аккуратной цели по центру получилась бы кнопка в рамке. */
.ui-ref-add span {
  display: grid;
  place-items: center;
  width: 32px;
  height: 32px;
  border: 1px solid var(--ui-dash-strong);
  border-radius: 50%;
  color: var(--ui-accent-strong);
}
/* «ВСТАВИТЬ» — РОВНО ПОЛОВИНА ПЛИТКИ ПО ШИРИНЕ (10.08.2026, «представь, что
   кнопку референса поделили пополам по вертикали, вот она такого размера»).
   Высота остаётся полной: `align-items` у ленты по умолчанию `stretch`, а
   `aspect-ratio: 1` здесь снят — иначе квадрат пересилил бы половинную ширину и
   кнопка вышла бы вдвое ниже соседей. Пунктир, радиус и кружок со значком —
   те же, что у плюса, класс `.ui-ref-add` оставлен на кнопке
   намеренно: это одна и та же кнопка «добавить», просто другим способом. */
/* Селектор нарочно с родителем: правило выше (`.ui-refs > *`) имеет
   ту же вес-категорию, и без этого ширина держалась бы только на порядке строк
   в файле.
   Ширина: половина плитки + 15%, потом ещё +5% (11.08.2026, две просьбы
   подряд). 1.15 × 1.05 = 1.2075, то есть 52.5px при плитке 87. Записано
   формулой, а не числом, чтобы связь с размером плитки не терялась: поменяешь
   `--ui-ref-tile` — кнопка поедет следом. */
.ui-refs .ui-ref-paste {
  flex-basis: calc(var(--ui-ref-tile) / 2 * 1.2075);
  aspect-ratio: auto;
}
.ui-ref-add svg {
  width: 14.5px;
  height: 14.5px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.6;
  stroke-linecap: round;
  /* Для плюса безразлично — у него нет углов, — а планшетке «вставить» без
     этого острые стыки на скруглениях. */
  stroke-linejoin: round;
}
.ui-count-label.ui-section-header {
  color: var(--ui-hint);
  font-weight: 400;
  font-feature-settings: "tnum" 1;
  font-variant-numeric: tabular-nums;
}
/* Перебор длины промпта. Цвет тот же, что у «удалить» и прочих отказов, — по
   нему сразу понятно, что кнопка погасла именно из-за этого. */
.ui-count-label.is-over {
  color: var(--ui-destructive);
  font-weight: 590;
}
.ui-file-input {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
  pointer-events: none;
}
.ui-ref img {
  transition:
    opacity 0.32s var(--ui-ease),
    transform 0.32s var(--ui-ease);
}
.ui-ref.is-loading {
  border-radius: 18px;
  background: var(--ui-white-veil);
  box-shadow: inset 0 0 0 0.5px rgba(var(--ui-ink-rgb), 0.08);
}
.ui-ref.is-loading img {
  opacity: 0;
  transform: scale(1.05);
}
.ui-ref__spinner {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 22px;
  height: 22px;
  margin: -11px 0 0 -11px;
  border: 2.5px solid rgba(var(--ui-ink-rgb), 0.14);
  border-radius: 50%;
  border-top-color: var(--ui-accent-strong);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.2s var(--ui-ease);
}
.ui-ref.is-loading .ui-ref__spinner {
  opacity: 1;
  animation: ui-spin 0.8s linear infinite;
}
@keyframes ui-spin {
  to {
    transform: rotate(360deg);
  }
}
.ui-ref__remove {
  transition: opacity 0.2s var(--ui-ease);
}
.ui-ref.is-loading .ui-ref__remove {
  opacity: 0;
  pointer-events: none;
}
.ui-ref.is-repainting {
  animation: ui-photo-repaint 0.06s linear;
}
@keyframes ui-photo-repaint {
  from {
    opacity: 0.99;
    transform: translateZ(0);
  }
  to {
    opacity: 1;
    transform: translateZ(0);
  }
}
.ui-ref.is-removing {
  animation: ui-tile-out 0.18s var(--ui-ease) forwards;
  pointer-events: none;
}
@keyframes ui-tile-out {
  to {
    opacity: 0;
    transform: scale(0.82);
  }
}
.ui-ref,
.ui-ref-add {
  animation: ui-tile-in 0.24s var(--ui-ease-out);
}
@keyframes ui-tile-in {
  from {
    opacity: 0;
    transform: scale(0.94);
  }
}
/* Размеры задаёт сама плитка, а не ролик: у `<video>` без метаданных
   внутренний размер нулевой, и плитка схлопывалась вместе с крестиком. Здесь
   те же 1:1 и то же скругление, что у фото-превью. */
.ui-ref--video video {
  display: block;
  width: 100%;
  aspect-ratio: 1;
  border-radius: 18px;
  background: rgba(var(--ui-ink-rgb), 0.06);
  object-fit: cover;
  box-shadow: inset 0 0 0 0.5px rgba(var(--ui-ink-rgb), 0.08);
}
.ui-ref--video__badge {
  position: absolute;
  bottom: 6px;
  left: 6px;
  padding: 2px 7px;
  border-radius: 999px;
  background: rgba(0, 0, 0, 0.55);
  color: #fff;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.01em;
  pointer-events: none;
}

/* ══════════════════════════════════════════════════════════════════════════
   НИЖНЯЯ ПАНЕЛЬ ДЕЙСТВИЯ (.ui-bar): стекло как у таббара, цена, степпер, кнопка
   ══════════════════════════════════════════════════════════════════════════ */
.ui-bar.ui-submit {
  position: fixed;
  left: 0;
  right: 0;
  bottom: calc(82px + var(--ui-safe-bottom));
  z-index: 70;
  padding: 0;
  pointer-events: none;
}
/* Переключатель «токены / подписка» вписан В ТЕ ЖЕ ПРАВИЛА, что и нижняя
   панель (18.08.2026, просьба сделать «дотошную копию по спецэффектам»).
   Именно общий селектор, а не копия значений: стекло тут собрано из шести
   теней, тумана на :before и двух платформенных вариантов размытия — копия
   разъехалась бы при первой же правке панели. Размеры и раскладку переопределяю
   отдельным правилом ниже, всё остальное приезжает отсюда. */
/* Стекло нижней панели общее С БЕГУНКОМ переключателя, а не с его дорожкой
   (18.08.2026). Сам переключатель теперь плоский, как на референсе: светлая
   дорожка, а «стеклом» выглядит только та половина, что выбрана.
   Именно общий селектор, а не копия значений: эффект собран из шести теней,
   тумана на :before и двух платформенных вариантов размытия — копия
   разъехалась бы при первой же правке панели. Раскладку бегунка
   переопределяю ниже, всё остальное приезжает отсюда. */
.ui-bar__inner {
  position: relative;
  display: grid;
  grid-template-columns: max-content max-content minmax(0, 1fr);
  align-items: center;
  gap: 6px;
  width: min(calc(100% - 48px), 504px);
  height: 67px;
  margin: 0 auto;
  padding: 0 10px;
  border-radius: 34px;
  background: transparent;
  /* Внешней тени НЕТ (2026-07-30, просьба юзера) — как и у таббара, остались
     только внутренние блики стекла. Первая строка — та же волосяная тёмная
     обводка 0.5px, что у таббара: на 2x/3x это ровно 1 физический пиксель.
     Именно box-shadow, а не border — border с `box-sizing: border-box` съел бы
     внутреннюю высоту и сдвинул содержимое панели. */
  box-shadow:
    0 0 0 0.5px rgba(var(--ui-ink-rgb), 0.22),
    inset 0 1.2px 1px -0.5px rgba(255, 255, 255, 0.5),
    inset 0 -1px 1px -0.5px rgba(255, 255, 255, 0.22),
    inset 1px 0 1px -0.5px rgba(255, 255, 255, 0.3),
    inset -1px 0 1px -0.5px rgba(255, 255, 255, 0.3),
    inset 0 0 0 0.5px rgba(255, 255, 255, 0.15);
  pointer-events: auto;
}
/* Реставрация и улучшение качества: одно фото за запрос, счётчика количества
   на панели нет. Без этого третья колонка сетки осталась бы пустой, а кнопка
   встала бы в середину панели (02.08.2026). */
.ui-bar__inner--duo {
  grid-template-columns: max-content minmax(0, 1fr);
}
.ui-bar__inner:before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 0;
  border-radius: inherit;
  /* Same pink-tinted fog as the tabbar (anti white-flash on iOS reload). */
  background: var(--ui-glass-panel);
  -webkit-backdrop-filter: blur(1px) saturate(118%);
  backdrop-filter: blur(1px) saturate(118%);
  pointer-events: none;
}
html.ui-lg-refract .ui-bar__inner:before {
  -webkit-backdrop-filter: url(#ui-lg-refraction);
  backdrop-filter: url(#ui-lg-refraction);
}
.ui-bar__cost,
.ui-bar__qty,
.ui-bar__cta {
  position: relative;
  z-index: 1;
}
.ui-bar__cost {
  display: flex;
  width: 56px;
  min-width: 56px;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding-left: 4px;
}
.ui-bar__cost__value {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 3px;
  color: var(--ui-text);
  white-space: nowrap;
}
.ui-bar__cost__value strong {
  font-size: 19px;
  font-weight: 650;
  font-feature-settings: "tnum" 1;
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.02em;
  line-height: 1;
}
.ui-bar__cost__value span {
  color: var(--ui-hint);
  font-size: 11px;
  font-weight: 500;
  line-height: 1;
}
.ui-bar__qty {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}
.ui-bar__count {
  display: grid;
  place-items: center;
  min-width: 44px;
  height: 40px;
  border-radius: 11px;
  background: var(--ui-count-bg);
  box-shadow: inset 0 0 0 0.5px rgba(var(--ui-ink-rgb), 0.12);
  color: var(--ui-text);
  font-size: 16px;
  font-weight: 600;
  font-feature-settings: "tnum" 1;
  font-variant-numeric: tabular-nums;
}
.ui-stepper {
  display: inline-flex;
  align-items: center;
  height: 40px;
  border-radius: var(--ui-radius-pill);
  background: var(--ui-fill);
}
.ui-stepper__button {
  display: grid;
  place-items: center;
  width: 46px;
  height: 40px;
  padding: 0;
  border: 0;
  background: transparent;
  color: var(--ui-text);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
.ui-stepper__button:first-of-type {
  border-radius: 999px 0 0 999px;
}
.ui-stepper__button:last-of-type {
  border-radius: 0 999px 999px 0;
}
.ui-stepper__button:active {
  background: rgba(var(--ui-ink-rgb), 0.1);
}
.ui-stepper__button:disabled {
  cursor: default;
  opacity: 0.3;
}
.ui-stepper__button svg {
  display: block;
  width: 15px;
  height: 15px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.8;
  stroke-linecap: round;
}
.ui-stepper__divider {
  width: 1px;
  height: 18px;
  background: var(--ui-separator);
}
.ui-bar__cta {
  display: inline-flex;
  min-width: 0;
  height: 40px;
  align-items: center;
  justify-content: center;
  gap: 6px;
  padding: 0 12px;
  border: 0;
  border-radius: var(--ui-radius-pill);
  background: var(--ui-accent);
  color: var(--ui-accent-text);
  font: inherit;
  font-size: clamp(11.5px, 3.3vw, 14px);
  font-weight: 600;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  /* Цвет и текст переходят плавно, но быстро: кнопка загорается, как только
     в промпте появился текст, и это должно читаться как отклик, а не как
     перекраска (21.08.2026). Трансформация оставлена как была. */
  transition:
    transform 0.15s var(--ui-ease),
    background-color 0.18s var(--ui-ease),
    color 0.18s var(--ui-ease);
}
.ui-bar__cta:active {
  transform: scale(0.97);
}
/* Недоступная кнопка обязана ВЫГЛЯДЕТЬ недоступной. Экраны реставрации и
   улучшения качества открываются именно в этом состоянии — пока не добавлено
   фото, обрабатывать нечего, — и розовая кнопка, которая просто не нажимается,
   читалась бы как поломка. Тем же стилем гаснет кнопка генерации при переборе
   лимита промпта (02.08.2026). */
.ui-bar__cta:disabled {
  background: var(--ui-accent-soft);
  color: var(--ui-hint);
  cursor: default;
}
.ui-bar__cta:disabled:active {
  transform: none;
}
.ui-bar__cta span {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.ui-bar__cta svg {
  display: block;
  width: 18px;
  height: 18px;
  flex: 0 0 auto;
  fill: none;
  stroke: currentColor;
  stroke-width: 2.2;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.ui-bar__inner {
  animation: ui-submit-in 0.4s var(--ui-ease-out) 0.05s backwards;
}
@keyframes ui-submit-in {
  from {
    opacity: 0;
    transform: translateY(16px);
  }
}
.ui-bar__count.is-pop {
  animation: ui-count-pop 0.26s var(--ui-ease-out);
}
@keyframes ui-count-pop {
  35% {
    transform: scale(1.16);
  }
}
@media (max-width: 390px) {
    .ui-bar__cta svg {
      display: none;
    }
    .ui-bar__inner {
      width: min(calc(100% - 36px), 504px);
      height: 64px;
    }
}
@media (max-width: 380px) {
    .ui-bar__cta {
      padding: 0 8px;
    }
}
@media (max-width: 350px) {
    .ui-bar__inner {
      gap: 5px;
      padding: 0 8px;
    }
    .ui-bar__cost {
      width: 50px;
      min-width: 50px;
      padding-left: 2px;
    }
    .ui-bar__count {
      min-width: 40px;
    }
    .ui-stepper__button {
      width: 40px;
    }
    .ui-bar__cta {
      padding: 0 9px;
    }
}
/* ── ПАНЕЛЬ ЗАПУСКА В ТЁМНОЙ ТЕМЕ (08.09.2026, «выглядит грязно»): почти
   непрозрачная подложка и нормальное размытие вместо тумана 1px, сквозь
   который просвечивал контент; элементы контрастнее примерно на 7%
   («цвета чуть более выраженными, менее прозрачным»). :root[...] — выше
   платформенного правила apple с blur 1.15px. Светлая тема прежняя. ── */
:root[data-theme="dark"] .ui-bar__inner:before {
  background: rgba(38, 38, 42, 0.96);
  -webkit-backdrop-filter: blur(14px) saturate(1.3);
  backdrop-filter: blur(14px) saturate(1.3);
}
:root[data-theme="dark"] .ui-bar__inner .ui-bar__count {
  background: rgba(255, 255, 255, 0.15);
}
:root[data-theme="dark"] .ui-bar__inner .ui-stepper {
  background: rgba(255, 255, 255, 0.14);
}
:root[data-theme="dark"] .ui-bar__cta {
  background: var(--ui-accent-strong);
}
:root[data-theme="dark"] .ui-bar__cta:disabled {
  background: rgba(var(--ui-accent-rgb), 0.3);
  color: rgba(var(--ui-ink-rgb), 0.72);
}

/* ══════════════════════════════════════════════════════════════════════════
   СТРОКА СО СНИМКОМ (.ui-media-row): список как в Apple Music, скелет
   ══════════════════════════════════════════════════════════════════════════ */
/* Без панели-подложки: юзер попросил вместо карточек тонкие серые разделители,
   как в списках Apple Music. Строка — просто строка на фоне экрана. */
.ui-media-row {
  --ui-hist-thumb: 64px;
  --ui-hist-gap: 12px;
  position: relative;
  display: flex;
  width: 100%;
  align-items: center;
  padding: 7px 0;
  border: 0;
  background: transparent;
  cursor: pointer;
  gap: var(--ui-hist-gap);
  scroll-snap-align: start;
  text-align: left;
  -webkit-tap-highlight-color: transparent;
}
/* Линия идёт ТОЛЬКО под текстом, под превью её нет — как в списках Apple Music
   (2026-07-31, замечание юзера). Поэтому псевдоэлемент со сдвигом на ширину
   превью, а не border у всей строки. */
.ui-media-row::after {
  position: absolute;
  right: 0;
  bottom: 0;
  left: calc(var(--ui-hist-thumb) + var(--ui-hist-gap));
  height: 0.5px;
  background: rgba(var(--ui-ink-rgb), 0.12);
  content: "";
}
.ui-media-row:active {
  opacity: 0.55;
}
/* Последняя строка в колонке полки и в конце списка — без линии снизу.
   В полке поток по колонкам, поэтому «последняя» — каждая третья. */
.ui-media-rail .ui-media-row:nth-child(3n)::after,
.ui-media-list .ui-media-row:last-child::after {
  display: none;
}
/* Идущие и упавшие строки тоже открываются (03.09.2026) — курсор только у
   скелета остаётся обычным. */
.ui-media-row.is-skeleton {
  cursor: default;
}
.ui-media-row__thumb {
  position: relative;
  display: flex;
  overflow: hidden;
  width: var(--ui-hist-thumb);
  height: var(--ui-hist-thumb);
  flex: 0 0 auto;
  align-items: center;
  justify-content: center;
  border-radius: 13px;
  /* Белая с розоватым оттенком, а не серая (17.08.2026). Прежний серый налёт
     поверх розовой страницы выглядел грязным пятном — та же правка, что у
     карточек на главной. */
  background: var(--ui-media-bg);
}
.ui-media-row__thumb img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}
/* «Фотка тёмная размытая и кружочек-индикатор» — просьба юзера. */
/* Пока генерируется — та же белая с розоватым оттенком плитка, что и пустая.
   Раньше здесь лежал розовый градиент, придавленный `brightness(0.62)`, и
   выходил тёмно-фиолетовый квадрат (17.08.2026, юзер поймал скриншотом).
   ФИЛЬТР УБРАН НАСОВСЕМ, а не подкручен: `filter` красит элемент ЦЕЛИКОМ,
   вместе с крутилкой внутри — вернёшь его, и она погаснет вслед за фоном. */
.ui-media-row__thumb.is-running {
  background: var(--ui-media-bg);
}
/* Крутилка перекрашена вслед за плиткой: белая на белом просто не видна. */
.ui-media-row__spinner {
  width: 19px;
  height: 19px;
  border: 2.2px solid var(--ui-accent-soft);
  border-radius: 50%;
  border-top-color: var(--ui-accent);
  animation: ui-gen-spin 0.9s linear infinite;
}
@keyframes ui-gen-spin {
  to {
    transform: rotate(360deg);
  }
}
/* Розовый и по центру (03.09.2026): у знака была высота строки шрифта, и он
   висел чуть выше середины; с line-height 1 и явным центрированием стоит
   ровно. */
.ui-media-row__thumb.is-failed {
  display: grid;
  place-items: center;
  color: var(--ui-accent-strong);
  font-size: 22px;
  font-weight: 700;
  line-height: 1;
}
.ui-media-row__body {
  display: flex;
  min-width: 0;
  flex: 1 1 auto;
  flex-direction: column;
  gap: 3px;
}
/* Промпт — одной строкой с многоточием: юзер просил показывать только часть. */
.ui-media-row__title {
  overflow: hidden;
  color: var(--ui-text);
  font-size: 15px;
  font-weight: 600;
  letter-spacing: -0.01em;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.ui-media-row__meta {
  overflow: hidden;
  color: var(--ui-hint);
  font-size: 12.5px;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* Красная точка «ещё не смотрел» — то же, что число на вкладке, только в
   строке. Стоит вплотную к шеврону: отрицательное поле гасит общий `gap`
   строки (12px), иначе точка висела бы посреди пустоты. У строк с ошибкой
   шеврона нет, и точка встаёт на его место — так и задумано. */
.ui-media-row__dot {
  width: 5px;
  height: 5px;
  flex: 0 0 auto;
  border-radius: 50%;
  margin-right: calc(6px - var(--ui-hist-gap));
  background: var(--ui-destructive);
}
.ui-media-row__after {
  display: flex;
  width: 10px;
  height: 16px;
  flex: 0 0 auto;
  color: rgba(var(--ui-ink-rgb), 0.25);
}
.ui-media-row__after svg {
  width: 10px;
  height: 16px;
}
.ui-media-row.is-skeleton .ui-media-row__body {
  height: 32px;
  border-radius: 10px;
  background: rgba(var(--ui-ink-rgb), 0.1);
}

/* ══════════════════════════════════════════════════════════════════════════
   ЛИСТ СНИЗУ (.ui-sheet): стекло iOS 26, выезд 0.6с, шапка с крестиком
   Открытие/закрытие — ImpitoKit.sheet (kit.js): hidden → reflow → is-open,
   закрытие по transitionend. .ui-sheet-card — та же фактура одной панелью
   (промокод), .ui-sheet-note — заголовок/подпись для коротких листов.
   ══════════════════════════════════════════════════════════════════════════ */
.ui-sheet {
  position: fixed;
  inset: 0;
  z-index: 120;
  /* Открытый лист не должен прокручивать страницу под собой (09.09.2026,
     «почему я могу листать панель»): жесты по подложке гасим, панель
     прокручивается сама и не передаёт прокрутку документу. */
  touch-action: none;
  overscroll-behavior: contain;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  padding: 0 10px calc(10px + var(--ui-safe-bottom));
}
.ui-sheet[hidden] {
  display: none;
}
.ui-sheet__backdrop {
  position: absolute;
  inset: 0;
  background: rgba(var(--ui-ink-rgb), 0.28);
  opacity: 0;
  transition: opacity 0.2s var(--ui-ease);
}
.ui-sheet__panel {
  position: relative;
  display: flex;
  width: min(100%, 504px);
  max-height: calc(100% - 16px);
  flex-direction: column;
  gap: 8px;
  margin: 0 auto;
  /* ПАНЕЛЬ НЕ РЕЖЕТ СОДЕРЖИМОЕ. Прокрутка длинного листа живёт в группе
     (ниже), а не здесь: overflow на панели (09.09.2026, «лист под таббаром»)
     обрезал внешнюю тень группы (`0 0 25px` в --ui-sheet-glass-shadow) по
     прямоугольнику панели — в уголках за скруглением оставались тёмные
     «ушки» (скриншот владельца с iPhone, светлая тема). */
  opacity: 0;
  transform: translateY(24px);
  transition:
    transform 0.22s var(--ui-ease-out),
    opacity 0.18s var(--ui-ease);
}
.ui-sheet.is-open .ui-sheet__backdrop {
  opacity: 1;
}
.ui-sheet.is-open .ui-sheet__panel {
  opacity: 1;
  transform: translateY(0);
}
.ui-sheet__group {
  /* Скругление режет содержимое, по вертикали группа прокручивается сама,
     когда лист выше экрана (панель — flex-колонка с max-height, поэтому
     min-height: 0 обязателен, иначе группа не ужимается). Прокрутка внутри
     группы, а не на панели — чтобы не резать внешнюю тень (см. панель). */
  min-height: 0;
  overflow-x: hidden;
  overflow-y: auto;
  overscroll-behavior: contain;
  touch-action: pan-y;
  /* ФАКТУРА ЭКШН-ШИТА iOS 26 (08.09.2026, просьба юзера: «оставляем нашу
     менюшку 1 в 1 по анимациям и функционалу, меняем только фактуру»).
     Радиус 32, белое стекло 75% с размытием 16px и насыщенностью 1.8,
     стопка внутренних теней в токене — она и даёт блик по кромке. */
  border-radius: 32px;
  background: var(--ui-sheet-glass-bg);
  /* Размытие — токен: светлая 15px, тёмная 18.5px (08.09.2026). */
  -webkit-backdrop-filter: saturate(1.8) blur(var(--ui-sheet-blur));
  backdrop-filter: saturate(1.8) blur(var(--ui-sheet-blur));
  box-shadow: var(--ui-sheet-glass-shadow);
}
.ui-sheet__option {
  display: block;
  width: 100%;
  height: 54px;
  padding: 0;
  border: 0;
  background: transparent;
  color: var(--ui-accent-strong);
  font: inherit;
  font-size: 17px;
  font-weight: 500;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
.ui-sheet__option + .ui-sheet__option {
  border-top: 0.5px solid var(--ui-sheet-divider);
}
.ui-sheet__option:active {
  background: var(--ui-press);
}
.ui-sheet__cancel {
  display: block;
  width: 100%;
  height: 54px;
  border: 0;
  border-radius: var(--ui-radius-pill);
  background: var(--ui-sheet-cancel);
  -webkit-backdrop-filter: blur(2px) saturate(145%);
  backdrop-filter: blur(2px) saturate(145%);
  /* Тот же розовый, что у вариантов выше (2026-07-31, просьба юзера): чёрный
     жирный текст выбивался из листа. */
  color: var(--ui-accent-strong);
  font: inherit;
  font-size: 17px;
  font-weight: 640;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  box-shadow:
    0 18px 44px rgba(var(--ui-ink-rgb), 0.22),
    0 3px 10px rgba(var(--ui-ink-rgb), 0.09),
    inset 0 1.2px 1px -0.5px rgba(255, 255, 255, 0.5),
    inset 0 -1px 1px -0.5px rgba(255, 255, 255, 0.22),
    inset 0 0 0 0.5px rgba(255, 255, 255, 0.15);
}
.ui-sheet__cancel:active {
  background: var(--ui-sheet-cancel-press);
}
.ui-sheet .ui-sheet__panel,
.ui-sheet .ui-sheet__panel,
.ui-sheet .ui-sheet__panel,
.ui-sheet .ui-sheet__panel,
.ui-sheet .ui-sheet__panel {
  opacity: 1;
  /* СДВИГ БОЛЬШЕ 100%, И ЭТО НЕ ЗАПАС «НА ГЛАЗОК». У листа снизу отступ
     10px + безопасная зона, панель стоит НАД ним. Сдвинешь ровно на 100%
     собственной высоты — её верх встанет туда, где был низ, и полоса высотой
     с этот отступ ОСТАНЕТСЯ НА ЭКРАНЕ. Потом её сносит `hidden`, и это видно
     как «кусочек панели моргнул» (16.08.2026, жалоба юзера на концовку
     закрытия). Прибавляем сам отступ и ещё 4px на скругление. */
  transform: translateY(calc(100% + 14px + var(--ui-safe-bottom)));
  /* 0.42с и кривая с крутым стартом (0.32, 0.72) читались как «выстрел»
     (16.08.2026, «слишком резко вылетает»). Стало 0.6с, и старт заметно
     положе: наклон в начале 2.0 вместо 2.25, а конец такой же мягкий.
     Быстрее не делать — именно длинное торможение и создаёт ощущение веса. */
  transition: transform 0.6s cubic-bezier(0.3, 0.6, 0.1, 1);
}
.ui-sheet.is-open .ui-sheet__panel,
.ui-sheet.is-open .ui-sheet__panel,
.ui-sheet.is-open .ui-sheet__panel,
.ui-sheet.is-open .ui-sheet__panel,
.ui-sheet.is-open .ui-sheet__panel {
  transform: translateY(0);
}
/* Затемнение тянется почти столько же, сколько едет панель. По умолчанию у
   листов оно 0.2с — фон темнел рывком и был уже чёрным, когда панель ещё в
   пути, отчего движение и казалось резче, чем есть. */
.ui-sheet .ui-sheet__backdrop,
.ui-sheet .ui-sheet__backdrop,
.ui-sheet .ui-sheet__backdrop,
.ui-sheet .ui-sheet__backdrop,
.ui-sheet .ui-sheet__backdrop {
  /* Плотнее общих 0.28: панель тут светлая и во весь экран, при слабом
     затемнении граница с фоном терялась (17.08.2026). */
  background: rgba(var(--ui-ink-rgb), 0.34);
  /* КОРОЧЕ ВЫЕЗДА НАРОЧНО, И ЭТО НЕ НЕБРЕЖНОСТЬ. Стекло панели размывает то,
     что за ней, — то есть само затемнение. Пока затемнение меняется, источник
     размытия меняется тоже, и движку приходится пересчитывать его каждый кадр.
     Дав затемнению закончиться раньше, мы оставляем последнюю треть выезда с
     уже неподвижной картинкой под панелью: пересчитывать нечего, и «обрывчик»
     в конце ловить неоткуда. */
  transition: opacity 0.4s var(--ui-ease);
}
@media (prefers-reduced-motion: reduce) {
  .ui-sheet .ui-sheet__panel,
  .ui-sheet .ui-sheet__panel,
  .ui-sheet .ui-sheet__panel,
  .ui-sheet .ui-sheet__panel,
  .ui-sheet .ui-sheet__panel {
    transition: none;
  }
}
.ui-sheet-card {
  /* Нижнее поле 16 → 14: часть тех самых «минус 5% высоты» (17.08.2026).
     Высота набрана из четырёх мест, поджимать одно на 15px нельзя — либо
     эмодзи станет мелким, либо кнопка прилипнет к краю. */
  padding: 18px 18px 14px;
  /* СВОЙ СЛОЙ НА ВСЁ ВРЕМЯ ЖИЗНИ. Без этого браузер создаёт слой на старте
     перехода и выбрасывает в конце — на этой границе кадр и «щёлкает». */
  will-change: transform, backdrop-filter;
  backface-visibility: hidden;
  /* Радиус больше общего карточного (22px): на референсе углы заметно мягче, а
     панель тут крупная — на такой площади 22px читаются как почти прямой угол.
     30 → 32px по просьбе «ещё процентов на восемь» (16.08.2026). */
  border-radius: 32px;
  /* СТЕКЛО: полупрозрачная подложка и размытие того, что за панелью
     (17.08.2026 — то же, что вернули листу моделей).
     Здесь размытие сильнее, чем у листа моделей (6px против 2px), и это не
     разнобой: панель промокода почти во весь экран и почти пустая, сквозь
     слабое размытие под ней читался бы текст страницы и мешал бы коду.
     ПРО АНИМАЦИЮ. Размытие подложки и длинный выезд дружат плохо: пока панель
     едет, движок считает размытие приближённо, а на последнем кадре
     пересчитывает начисто — виден щелчок в конце. Именно из-за этого панель
     раньше и сделали непрозрачной. Чтобы стекло не вернуло рывок, слой
     закреплён через `will-change` выше — там и transform, и backdrop-filter:
     второе просит движок считать размытие живым на всём выезде, а не
     доводить его одним кадром в конце (17.08.2026, «небольшой обрывчик»).
     И НЕ ДОБАВЛЯЙ СЮДА `transform: translateZ(0)` ДЛЯ СЛОЯ, как это сделано у
     листа моделей. Там стекло на вложенной группе, а трансформ выезда — на
     панели, это разные элементы. Здесь панель и есть стекло: второй transform
     на ней либо перебьёт выезд, либо (как сейчас, по специфичности) молча не
     применится — и то и другое хуже, чем ничего. */
  /* Та же фактура, что у листов (стекло iOS 26, 08.09.2026, «примени на
     окошко промокод»). */
  background: var(--ui-sheet-glass-bg);
  -webkit-backdrop-filter: saturate(1.8) blur(var(--ui-sheet-blur));
  backdrop-filter: saturate(1.8) blur(var(--ui-sheet-blur));
  /* Блик по кромке: верхняя грань светлее нижней — стекло читается освещённым
     сверху, а не просто обведённым. Значения те же, что у листа моделей. */
  box-shadow: var(--ui-sheet-glass-shadow);
  text-align: center;
}
/* Шапка и крестик общие с листом выбора модели (17.08.2026): юзер просил
   «1 в 1 как в промокоде». Именно общий селектор, а не копия значений —
   копия разъедется при первой же правке одной из панелей. */
.ui-sheet-card__head,
.ui-sheet__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
}
.ui-sheet-card__title,
.ui-sheet__title {
  color: var(--ui-text);
  font-size: 19px;
  font-weight: 700;
  letter-spacing: -0.01em;
}
/* Крестик — круг с заливкой, как у референса, но на нашей подложке. */
.ui-sheet-card__close,
.ui-sheet__close {
  display: grid;
  width: 34px;
  height: 34px;
  flex: 0 0 auto;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: var(--ui-fill-2);
  color: var(--ui-text-2);
  cursor: pointer;
  place-items: center;
  -webkit-tap-highlight-color: transparent;
}
.ui-sheet-card__close svg,
.ui-sheet__close svg {
  width: 15px;
  height: 15px;
}
.ui-sheet-card__close:active,
.ui-sheet__close:active {
  background: var(--ui-fill-3);
}
/* Выбранная модель в листе — акцентом, чтобы было видно, что уже стоит. */
.ui-sheet__option.is-active {
  color: var(--ui-accent-strong);
  font-weight: 600;
}
/* ── Строка модели: имя слева, пояснение справа (11.08.2026, просьба юзера) ──
   Модификатор, а НЕ правка базового `.ui-sheet__option`: тот же класс
   носят пункты листа выбора источника фото («сделать фото», «из галереи»,
   «файлы»), и им нужна прежняя строка по центру.
   Высота уходит в `min-height`: пояснение на узком экране переносится на две
   строки, и жёсткие 54px обрезали бы вторую. */
.ui-sheet__option--model {
  display: flex;
  min-height: 54px;
  height: auto;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  padding: 11px 18px;
  text-align: left;
}
.ui-sheet__option-name {
  flex: 0 0 auto;
}
/* Значок модели — тот же премиум-эмодзи, что на кнопке в боте (картинкой,
   см. model_emoji.js). Пара «значок + название» живёт в своей обёртке, иначе
   `space-between` строки растащила бы их по разным краям. */
.ui-sheet__option-lead {
  display: flex;
  flex: 0 1 auto;
  min-width: 0;
  align-items: center;
  gap: 9px;
}
.ui-sheet__option-emoji {
  flex: 0 0 auto;
  width: 21px;
  height: 21px;
  object-fit: contain;
  /* Значок не должен ловить долгий тап «сохранить изображение»: он часть
     кнопки, а не картинка, которую тут кто-то собирался разглядывать. */
  pointer-events: none;
  -webkit-user-select: none;
  user-select: none;
}
.ui-sheet__option--static {
  cursor: default;
}
/* ── Стекло листов модели и формата ───────────────────────────────────────
   Время выезда у них общее с промокодом и задано выше — здесь только вид.
   Scope нужен: классы `.ui-sheet*` общие, на них живут и другие листы
   (выбор в разделе «стили»), у которых прежний короткий выезд на 24px. */
.ui-sheet .ui-sheet__group,
.ui-sheet .ui-sheet__group {
  /* Радиус как у промокода. */
  border-radius: 32px;
  /* СТЕКЛО ОСТАЁТСЯ: полупрозрачный фон и размытие подложки — как на прежней
     панели (17.08.2026, юзер прислал скриншот старой и попросил вернуть).
     Значения не свои, а унаследованные от базового `.ui-sheet__group`,
     тут они не переопределяются вовсе — переписывать их копией значило бы
     развести две панели при первой же правке базовой.
     ВАЖНО ПРО АНИМАЦИЮ. Размытие подложки и длинный выезд дружат плохо: пока
     панель едет, движок считает размытие приближённо, а на последнем кадре
     пересчитывает начисто — и это видно как щелчок в конце. На промокоде мы
     от этого ушли, сделав панель непрозрачной, но здесь стекло важнее. Чтобы
     щелчка не было, слой у панели закреплён заранее (`will-change` ниже), и
     сама группа тоже вынесена в свой слой — тогда движок не заводит и не
     выбрасывает его на границах перехода.
     Если рывок всё же вернётся — виновато именно размытие, и выбор будет
     между ним и гладкой концовкой. */
  transform: translateZ(0);
  /* Просим движок считать размытие живым на всё время, а не «как-нибудь, а в
     конце начисто»: именно тот доводочный кадр и читается как обрывчик. */
  will-change: backdrop-filter;
  /* Тени и блик — из базового `.ui-sheet__group` (фактура iOS 26, 08.09.2026). */
}
.ui-sheet .ui-sheet__panel,
.ui-sheet .ui-sheet__panel {
  /* Свой слой на всё время жизни: иначе браузер заводит его на старте
     перехода и выбрасывает в конце, и на этой границе кадр щёлкает. */
  will-change: transform;
  backface-visibility: hidden;
}
/* Верхний отступ теперь даёт шапка, а не сама группа — иначе они сложатся и
   заголовок уедет от края вдвое дальше, чем у остальных панелей. */
.ui-sheet .ui-sheet__ratio {
  padding: 0 0 16px;
}
/* Шапка листа. Отступ слева тот же 18px, что у строк с моделями, — заголовок
   встаёт ровно над их текстом. */
.ui-sheet__head {
  padding: 14px 18px 10px;
}
/* Первая строка модели идёт сразу под шапкой, и разделитель между ними нужен
   такой же, как между самими строками: без него шапка сливается со списком. */
.ui-sheet__head + .ui-sheet__option {
  border-top: 0.5px solid var(--ui-separator);
}
.ui-sheet__option-note {
  min-width: 0;
  max-width: 175px;
  color: var(--ui-hint);
  font-size: 13px;
  font-weight: 400;
  line-height: 1.25;
  text-align: right;
}
/* Лист «не хватает токенов» и ошибки генерации — на той же основе, что лист
   скачивания в истории. */
.ui-sheet-note__title {
  margin: 0;
  padding: 16px 16px 4px;
  color: var(--ui-text);
  font-size: 17px;
  font-weight: 700;
  letter-spacing: -0.01em;
  text-align: center;
}
.ui-sheet-note__sub {
  margin: 0;
  padding: 0 16px 16px;
  color: var(--ui-hint);
  font-size: 14px;
  line-height: 1.35;
  text-align: center;
}
[data-theme="dark"] .ui-sheet__cancel,
[data-theme="dark"] .ui-style-search {
  box-shadow: 0 0 0 0.5px rgba(0, 0, 0, 0.25);
}
/* Чёрный логотип OpenAI на тёмном фоне не виден — инвертируем только его;
   остальные значки моделей цветные. */
[data-theme="dark"] .ui-param__logo img[src*="gpt15"],
[data-theme="dark"] .ui-sheet__option-emoji[src*="gpt15"],
[data-theme="dark"] .ui-param__logo img[src*="grok"],
[data-theme="dark"] .ui-sheet__option-emoji[src*="grok"] {
  filter: invert(1);
}

/* ══════════════════════════════════════════════════════════════════════════
   ПРУЖИНКА (.ui-pop): меню, вырастающее из кнопки с перелётом
   Позицию и transform-origin ставит ImpitoKit.pop (kit.js).
   ══════════════════════════════════════════════════════════════════════════ */
[data-theme="dark"] .ui-pop--light .ui-pop__menu {
  box-shadow: 0 18px 44px rgba(0, 0, 0, 0.35);
}
/* ВСПЛЫВАЮЩЕЕ МЕНЮ «ИЗМЕНИТЬ РАЗМЕР» (07.09.2026, видео юзера из галереи
   iOS): тёмное стекло вырастает из кнопки с пружинкой. Точку роста ставит
   скрипт (transform-origin в центр кнопки), здесь — вид и переход. */
.ui-pop {
  position: absolute;
  inset: 0;
  z-index: 3;
}
.ui-pop[hidden] {
  display: none;
}
.ui-pop__backdrop {
  position: absolute;
  inset: 0;
}
.ui-pop__menu {
  position: absolute;
  right: 12px;
  bottom: 120px;
  min-width: 232px;
  padding: 6px 0;
  border-radius: 22px;
  background: rgba(44, 44, 46, 0.72);
  -webkit-backdrop-filter: blur(24px) saturate(1.6);
  backdrop-filter: blur(24px) saturate(1.6);
  box-shadow:
    0 18px 44px rgba(0, 0, 0, 0.45),
    inset 0 0 0 0.5px rgba(255, 255, 255, 0.14);
  color: #fff;
  opacity: 0;
  transform: scale(0.25);
  transform-origin: 100% 100%;
  transition:
    transform 0.34s cubic-bezier(0.34, 1.45, 0.64, 1),
    opacity 0.16s var(--ui-ease);
  will-change: transform, opacity;
}
.ui-pop.is-open .ui-pop__menu {
  opacity: 1;
  transform: scale(1);
}
.ui-pop__item {
  display: flex;
  width: 100%;
  min-height: 46px;
  align-items: center;
  gap: 14px;
  padding: 0 18px;
  border: 0;
  background: none;
  color: #fff;
  font: inherit;
  font-size: 16px;
  text-align: left;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
.ui-pop__item + .ui-pop__item {
  border-top: 0.5px solid rgba(255, 255, 255, 0.14);
}
.ui-pop__item:active {
  background: rgba(255, 255, 255, 0.12);
}
.ui-pop__item.is-active {
  color: rgba(255, 255, 255, 0.55);
}
.ui-pop__frame {
  display: inline-flex;
  width: 22px;
  height: 22px;
  flex: 0 0 auto;
  align-items: center;
  justify-content: center;
}
.ui-pop__box {
  display: block;
  border: 1.6px solid currentColor;
  border-radius: 4px;
}
.ui-pop__label {
  white-space: nowrap;
}
/* Двухстрочный пункт (сохранить): подпись и пояснение, как в листе истории. */
.ui-pop__item--two {
  min-height: 56px;
  padding-top: 8px;
  padding-bottom: 8px;
}
.ui-pop__text {
  display: flex;
  min-width: 0;
  flex-direction: column;
  gap: 2px;
}
.ui-pop__hint {
  color: rgba(255, 255, 255, 0.58);
  font-size: 12.5px;
  white-space: nowrap;
}
.ui-pop__frame svg {
  width: 20px;
  height: 20px;
}
/* Верхнее меню растёт вниз из кнопки «сохранить»/«инфо». */
.ui-pop--top .ui-pop__menu {
  top: 120px;
  bottom: auto;
  transform-origin: 100% 0%;
}
/* В истории меню живёт на обычной странице: контейнер фиксированный на весь
   экран, чтобы тап мимо закрывал, а меню считалось от viewport. */
.ui-pop--fixed {
  position: fixed;
  z-index: 110;
}
/* «Инфо»: пары ключ–значение на тёмном стекле, без промпта. */
.ui-pop__menu--info {
  min-width: 248px;
  padding: 4px 0;
}
.ui-pop__row {
  display: flex;
  justify-content: space-between;
  gap: 16px;
  padding: 10px 18px;
  font-size: 15px;
}
.ui-pop__row + .ui-pop__row {
  border-top: 0.5px solid rgba(255, 255, 255, 0.14);
}
.ui-pop__key {
  flex: 0 0 auto;
  color: rgba(255, 255, 255, 0.6);
}
.ui-pop__val {
  min-width: 0;
  color: #fff;
  font-weight: 600;
  text-align: right;
  white-space: nowrap;
}
/* СВЕТЛОЕ МЕНЮ — для истории (07.09.2026, просьба юзера «в истории белую
   менюшку»): то же стекло, что у панелей аппы, цвета из токенов. В просмотре
   результата на чёрном фоне остаётся тёмное. */
/* Прозрачнее, чем панели (0.86 → 0.6), и размытие сильнее: на розовом фоне
   с мелким текстом плотное стекло выглядело просто плашкой (07.09, «где
   размытие»). */
.ui-pop--light .ui-pop__menu {
  background: var(--ui-pop-light);
  -webkit-backdrop-filter: blur(28px) saturate(1.8);
  backdrop-filter: blur(28px) saturate(1.8);
  box-shadow:
    0 18px 44px rgba(var(--ui-ink-rgb), 0.22),
    inset 0 0 0 0.5px rgba(255, 255, 255, 0.7);
  color: var(--ui-text);
}
.ui-pop--light .ui-pop__row + .ui-pop__row,
.ui-pop--light .ui-pop__item + .ui-pop__item {
  border-top-color: var(--ui-separator);
}
.ui-pop--light .ui-pop__key {
  color: var(--ui-hint);
}
.ui-pop--light .ui-pop__val,
.ui-pop--light .ui-pop__item {
  color: var(--ui-text);
}
.ui-pop--light .ui-pop__item:active {
  background: var(--ui-press);
}
.ui-pop__empty {
  margin: 0;
  padding: 12px 18px;
  color: rgba(255, 255, 255, 0.7);
  font-size: 15px;
}
/* «Пружинка» сортировки в каталоге: растёт из строки слева, поэтому левый
   край по кнопке (координаты ставит скрипт), пункт с галочкой. */
.ui-pop--start .ui-pop__menu {
  min-width: 232px;
}
.ui-pop__check {
  width: 16px;
  height: 16px;
  flex: 0 0 auto;
  margin-left: auto;
  opacity: 0;
}
.ui-pop__item.is-active .ui-pop__check {
  opacity: 1;
}
/* В светлом меню активный пункт не гасится, его отмечает галочка. */
.ui-pop--light .ui-pop__item.is-active {
  color: var(--ui-text);
}
.ui-pop--light .ui-pop__check {
  color: var(--ui-accent-strong);
}
/* ═══ МЕНЮ «ДОБАВИТЬ ФОТО» — светлая пружинка из кнопки (Android), как
   меню «инфо» в истории: текстовые строки без иконок. ═══ */
.ui-pop--source .ui-pop__menu {
  min-width: 232px;
  /* Размытие мягче, чем у «инфо» в истории (07.09, просьба юзера «послабее
     для фото»); история и сортировка каталога остаются на 28px. */
  -webkit-backdrop-filter: blur(14px) saturate(1.5);
  backdrop-filter: blur(14px) saturate(1.5);
  /* Прозрачнее на 20% (07.09, просьба юзера): 0.7 → 0.5. */
  background: var(--ui-pop-light-source);
}

/* ══════════════════════════════════════════════════════════════════════════
   ОКНО СВЕРХУ (.ui-toast): стекло, выезд с перелётом, смахивание
   API: ImpitoKit.toast.show({title, subtitle, spinner, tone, thumb, onClick}) / hide().
   ══════════════════════════════════════════════════════════════════════════ */
/* ── Окно «генерируется», выезжающее сверху (22.08.2026) ──────────────────
   Форма и эффекты — ровно те же, что у листа выбора модели
   (.ui-sheet__group): подложка, размытие, радиус, тень. Второго языка
   всплывающих окон в аппе быть не должно.
   Отличие одно: приезжает сверху и не перекрывает работу — под ним можно
   продолжать набирать промпт. Поэтому ни фона-затемнения, ни перехвата
   нажатий у него нет. */
.ui-toast {
  position: fixed;
  /* 6 → 12px: «чуть-чуть ниже» (03.09.2026, просьба юзера). */
  top: calc(var(--ui-veil-height) + 12px);
  left: 0;
  right: 0;
  z-index: 130;
  display: flex;
  justify-content: center;
  padding: 0 10px;
  pointer-events: none;
}
.ui-toast__panel {
  display: flex;
  /* BORDER-BOX ОБЯЗАТЕЛЕН. Правило `.ui-page *` действует только внутри
     страницы, а окно живёт прямо в body — значит по умолчанию content-box, и
     `width: 100%` складывалось с полями 16px, вылезая за края экрана
     (28.08.2026, скриншот юзера с окном «изображение готово»). */
  box-sizing: border-box;
  width: min(100%, 504px);
  align-items: center;
  gap: 12px;
  padding: 13px 16px;
  border-radius: var(--ui-radius-card);
  /* Стекло, а не плотная подложка (просьба юзера 22.08.2026): сквозь окно
     видно экран, поэтому оно читается как всплывшее поверх, а не как кусок
     интерфейса. Тон розовый — тот же, что у таббара. */
  background: var(--ui-glass-panel-soft);
  -webkit-backdrop-filter: blur(14px) saturate(150%);
  backdrop-filter: blur(14px) saturate(150%);
  /* ТЕНИ НЕТ. Вместо неё волосяная тёмная обводка 0.5px — ровно та же, что у
     таббара и панели генерации (на экранах 2x/3x это один физический пиксель,
     тоньше не бывает). Блики внутрь — оттуда же, они и дают ощущение стекла. */
  box-shadow:
    0 0 0 0.5px rgba(var(--ui-ink-rgb), 0.22),
    inset 0 1.2px 1px -0.5px rgba(255, 255, 255, 0.5),
    inset 0 -1px 1px -0.5px rgba(255, 255, 255, 0.22),
    inset 0 0 0 0.5px rgba(255, 255, 255, 0.15);
  opacity: 0;
  /* Живее прежнего: окно не просто съезжает, а слегка проскакивает вниз и
     возвращается — кривая с выбросом (y > 1). Плюс еле заметное «раздутие»
     по масштабу, от него движение читается упругим, а не линейным. */
  transform: translateY(-26px) scale(0.94);
  transition:
    transform 0.44s cubic-bezier(0.22, 1.42, 0.36, 1),
    opacity 0.22s var(--ui-ease);
  /* Нажатия ловит только сама панель — чтобы её можно было смахнуть. */
  pointer-events: auto;
  touch-action: none;
}
.ui-toast.is-open .ui-toast__panel {
  opacity: 1;
  transform: translateY(0) scale(1);
}
.ui-toast__body {
  display: flex;
  min-width: 0;
  flex-direction: column;
  gap: 2px;
}
.ui-toast__title {
  color: var(--ui-text);
  font-family: var(--ui-font);
  font-size: 15px;
  font-weight: 600;
  letter-spacing: -0.01em;
  line-height: 1.2;
}
.ui-toast__sub {
  color: var(--ui-hint);
  font-family: var(--ui-font);
  font-size: 13px;
  line-height: 1.25;
}
/* Кружок-крутилка: тот же приём, что у спиннера в истории — кольцо с
   прозрачным сектором. */
.ui-toast__spinner {
  flex: 0 0 auto;
  width: 20px;
  height: 20px;
  border: 2px solid var(--ui-accent-soft);
  border-top-color: var(--ui-accent);
  border-radius: 50%;
  animation: ui-toast-spin 0.8s linear infinite;
}
/* Ошибка — то же окно, другой знак. Кружок один в один как у неудавшейся
   строки в истории (`.ui-media-row__thumb.is-failed`): человек уже видел
   его там, и второй раз объяснять не нужно. */
.ui-toast__mark {
  display: flex;
  width: 20px;
  height: 20px;
  flex: 0 0 auto;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  background: var(--ui-destructive);
  color: #ffffff;
  font-family: var(--ui-font);
  font-size: 13px;
  font-weight: 600;
  line-height: 1;
}
.ui-toast.is-error .ui-toast__title {
  color: var(--ui-destructive);
}
/* Окно «изображение готово»: слева превью, справа заголовок и промпт. */
.ui-toast__thumb {
  display: block;
  overflow: hidden;
  width: 40px;
  height: 40px;
  flex: 0 0 auto;
  border-radius: 10px;
  background: rgba(var(--ui-ink-rgb), 0.06);
}
.ui-toast__thumb img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
/* Промпт — РОВНО одна строка с многоточием (просьба юзера 23.08.2026). Без
   этого длинный запрос растягивал окно на пол-экрана. Работает только вместе
   с `min-width: 0` у __body: без него флекс-ребёнок не даёт себя сжать и
   многоточие не появляется вовсе. */
.ui-toast.has-thumb .ui-toast__title,
.ui-toast.has-thumb .ui-toast__sub {
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}
.ui-toast.is-tappable .ui-toast__panel {
  cursor: pointer;
}
.ui-toast.is-tappable .ui-toast__panel:active {
  opacity: 0.75;
}
/* Стекло листов в тёмной теме задаётся токенами --ui-sheet-glass-* выше. */
/* БЕЛЫХ INSET-КРОМОК В ТЁМНОЙ ТЕМЕ НЕТ (07.09.2026, «инсет кромки убирай»).
   На светлом стекле они рисуют блик по краю панели, на тёмном — светлый
   ободок. Оставлены только внешние тени, перекрашенные в чёрный. */
[data-theme="dark"] .ui-bar__inner,
[data-theme="dark"] .ui-toast__panel,
html[data-theme="dark"][data-font-platform="apple"] .ui-tabbar {
  box-shadow: 0 0 0 0.5px rgba(0, 0, 0, 0.35);
}
@media (prefers-reduced-motion: reduce) {
    .ui-toast__panel {
      transition: opacity 0.2s var(--ui-ease);
      transform: none;
    }
    .ui-toast__spinner {
      animation-duration: 2.4s;
    }
}

/* ══════════════════════════════════════════════════════════════════════════
   ОВЕРЛЕЙ И МОДАЛКА (.ui-overlay, .ui-modal) — простой слой поверх
   ══════════════════════════════════════════════════════════════════════════ */
.ui-overlay {
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  z-index: 100;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 20px;
  background: #0006;
  animation: ui-fade 0.2s var(--ui-ease);
  font-family: var(--ui-font);
  color: var(--ui-text);
}
.ui-overlay,
.ui-overlay * {
  box-sizing: border-box;
}
.ui-overlay--bottom {
  align-items: flex-end;
  padding: 0;
}
@keyframes ui-fade {
  0% {
    opacity: 0;
  }
}
.ui-modal {
  width: min(100%, 360px);
  padding: 22px;
  border-radius: var(--ui-radius-card);
  background: var(--ui-card);
  -webkit-backdrop-filter: saturate(180%) blur(18px);
  backdrop-filter: saturate(180%) blur(18px);
  box-shadow: var(--ui-surface-highlight);
  animation: ui-pop 0.24s var(--ui-ease-out);
}
.ui-modal-title {
  margin: 0 0 12px;
  color: var(--ui-text);
  font-size: 19px;
  font-weight: 700;
  text-align: center;
}
.ui-modal-actions {
  display: flex;
  gap: 10px;
  margin-top: 18px;
}
.ui-modal-actions > * {
  flex: 1 1 0;
}

/* ══════════════════════════════════════════════════════════════════════════
   ДВИЖЕНИЕ: смена кадров, проявление карточек, скелет, hero
   Кадры: .ui-page-leave (гаснет 110мс) → .ui-page-enter (проявление 200мс,
   без fill-mode, см. комментарий). data-anim: fade | push | pop на <main>.
   ══════════════════════════════════════════════════════════════════════════ */
/* ── СМЕНА КАДРОВ ПРОФИЛЯ (08.09.2026): старый гаснет, новый проявляется. ── */
.ui-page-leave {
  opacity: 0;
  transition: opacity 0.11s var(--ui-ease);
  pointer-events: none;
}
.ui-page-enter {
  /* БЕЗ fill-mode (09.09.2026, скриншоты юзера с Android: лист настроек
     уезжал ПОД таббар). Заполненная анимация оставляла на <main> контекст
     наложения с z-index auto, и листы внутри него (z 120) рисовались ниже
     таббара (z 80). Без заливки после 200мс контекста нет. Стартовый кадр
     задан явно, вспышки не будет. */
  animation: ui-page-in 0.2s var(--ui-ease-out);
}
@keyframes ui-page-in {
  from {
    opacity: 0;
    transform: translateY(6px);
  }
  to {
    opacity: 1;
    transform: none;
  }
}
@media (prefers-reduced-motion: reduce) {
  .ui-page-enter {
    animation: none;
  }
}

main[data-anim="fade"] { animation: ui-page-in 0.3s var(--ui-ease-out); }
main[data-anim="push"] { animation: ui-push-in 0.34s var(--ui-ease-nav); }
main[data-anim="pop"] { animation: ui-pop-in 0.3s var(--ui-ease-nav); }
@keyframes ui-push-in {
  from {
    opacity: 0.15;
    transform: translateX(64px);
  }
}
@keyframes ui-pop-in {
  from {
    opacity: 0.15;
    transform: translateX(-48px);
  }
}
.ui-screen--fwd {
  animation-name: ui-screen-in-fwd;
}
.ui-screen--back {
  animation-name: ui-screen-in-back;
}
@keyframes ui-screen-in-fwd {
  0% {
    opacity: 0;
    transform: translate(26px);
  }
}
@keyframes ui-screen-in-back {
  0% {
    opacity: 0;
    transform: translate(-26px);
  }
}
@keyframes ui-card-in {
  from {
    opacity: 0;
    transform: translateY(16px) scale(0.96);
  }
}

/* Проявление карточки при монтировании (сетка стилей в аппе). */
.ui-card-in { animation: ui-card-in 0.5s var(--ui-ease-out) backwards; }
/* Скелет: та же серая заливка, что у строк истории. */
.ui-skeleton { border-radius: 10px; background: rgba(var(--ui-ink-rgb), 0.08); }
.ui-hero-emoji {
  display: flex;
  width: 144px;
  height: 144px;
  align-items: center;
  justify-content: center;
  font-size: 116px;
  line-height: 1;
  animation: ui-hero-emoji-in 0.5s var(--ui-ease-out) both;
}
.ui-hero-emoji > * {
  animation: ui-hero-float 4s ease-in-out 0.5s infinite;
}
.ui-hero-emoji canvas,
.ui-hero-emoji svg,
.ui-hero-emoji img {
  width: 100%;
  height: 100%;
  object-fit: contain;
}
.ui-emoji-img {
  display: block;
  object-fit: contain;
  -webkit-user-drag: none;
  -webkit-user-select: none;
  user-select: none;
  pointer-events: none;
}
.ui-hero-title {
  margin: 16px 0 0;
  color: var(--ui-text);
  font-family: var(--ui-font-display);
  font-size: 36px;
  font-weight: var(--ui-weight-bold);
  letter-spacing: var(--ui-tracking-title);
  line-height: var(--ui-leading-tight);
  animation: ui-hero-rise 0.42s var(--ui-ease-out) 0.06s both;
}
.ui-hero-sub {
  margin: 10px 0 0;
  max-width: 32ch;
  color: var(--ui-hint);
  font-size: var(--ui-size-row);
  line-height: var(--ui-leading-normal);
  animation: ui-hero-rise 0.42s var(--ui-ease-out) 0.12s both;
}
@keyframes ui-hero-emoji-in {
  0% {
    opacity: 0;
    transform: scale(0.5) translateY(10px);
  }
}
@keyframes ui-hero-float {
  0%,
  to {
    transform: translateY(0);
  }
  50% {
    transform: translateY(-7px);
  }
}
@keyframes ui-hero-rise {
  0% {
    opacity: 0;
    transform: translateY(10px);
  }
}
.ui-hero-title {
  margin: 14px 0 0;
  color: var(--ui-text);
  font-size: 24px;
  font-weight: 700;
  letter-spacing: -0.01em;
  line-height: 1.2;
  text-wrap: balance;
}
.ui-hero-sub {
  margin: 8px 0 0;
  max-width: 40ch;
  color: var(--ui-hint);
  font-size: 15px;
  line-height: 1.4;
  text-align: center;
  text-wrap: pretty;
}
@media (prefers-reduced-motion: reduce) {
  .ui-cta,
  .ui-overlay,
  .ui-modal,
  .ui-sheet {
    animation: none;
  }
  .ui-hero-emoji,
  .ui-hero-emoji > *,
  .ui-hero-title,
  .ui-hero-sub,
  .ui-screen {
    animation: none !important;
  }
  .ui-cta-bar {
    transition: none;
  }
}

/* ══════════════════════════════════════════════════════════════════════════
   ТАББАР (.ui-tabbar): стекло, ползунок-пилюля, желе, линза, значок
   CSS из автономной сборки ui_tabbar_standalone.html + правила тёмной
   темы из аппы. Контроллер — kit.js (UiTabbar): тап, удержание, перетаскивание,
   отскок; линза (SVG-преломление) только в Chromium, на apple — псевдослои.
   ══════════════════════════════════════════════════════════════════════════ */
/* ================================================================
   3. САМА ПАНЕЛЬ
   ================================================================ */
.ui-tabbar {
  position: fixed;
  left: 50%;
  bottom: calc(4px + var(--ui-safe-bottom));
  z-index: 80;
  display: flex;
  align-items: stretch;
  width: min(calc(100% - 48px), 504px);
  height: 67px;
  /* Боковые поля больше вертикальных: ползунок шире слота на 10%
     (THUMB_SLOT_K в js), и этот перехлёст должен помещаться у крайних
     вкладок. */
  padding: 5px 9px;
  border: 0;
  border-radius: 34px;
  overflow: visible;
  background: transparent;
  /* Внешней тени НЕТ — только внутренние блики стекла.
     Первая строка — волосяная тёмная обводка 0.5px (на 2x/3x это ровно
     один физический пиксель); сделана box-shadow, а не border, чтобы не
     влезать в геометрию панели. */
  box-shadow:
    0 0 0 0.5px rgba(var(--ui-ink-rgb), 0.22),
    inset 0 1.2px 1px -0.5px rgba(255, 255, 255, 0.5),
    inset 0 -1px 1px -0.5px rgba(255, 255, 255, 0.22),
    inset 1px 0 1px -0.5px rgba(255, 255, 255, 0.3),
    inset -1px 0 1px -0.5px rgba(255, 255, 255, 0.3),
    inset 0 0 0 0.5px rgba(255, 255, 255, 0.15);
  font-family: var(--ui-font);
  transform: translateX(-50%);
  transition: transform 0.08s var(--ui-ease);
  touch-action: none;
  -webkit-user-select: none;
  user-select: none;
}
/* Туман. ВАЖНО: цвет подложки уже совпадает с итоговым цветом стекла —
   WebKit докомпоновывает backdrop-filter на несколько кадров позже
   перезагрузки, и без этого панель на iOS вспыхивает белым. */
.ui-tabbar:before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 0;
  border-radius: inherit;
  background: var(--ui-glass-panel);
  -webkit-backdrop-filter: blur(1px) saturate(118%);
  backdrop-filter: blur(1px) saturate(118%);
  pointer-events: none;
}
/* Свечение панели при захвате — гонится из js через --ui-panel-glow. */
.ui-tabbar:after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 0;
  border-radius: inherit;
  background: var(--ui-glass-glow);
  opacity: var(--ui-panel-glow, 0);
  pointer-events: none;
}
.ui-tabbar,
.ui-tabbar * {
  box-sizing: border-box;
}

/* ── Ползунок ─────────────────────────────────────────────────── */
.ui-tabbar__thumb {
  position: absolute;
  top: 0;
  left: 0;
  z-index: 3;
  --ui-thumb-scale: 1;
  width: 76px;
  height: 57px;
  border-radius: 999px;
  overflow: hidden;
  /* В покое — нейтрально-серая пилюля (как в таббаре Telegram). Серость
     даётся ПОДЛОЖКОЙ, а не десатурацией фона: ползунок лежит НАД
     иконками (z 3 > 2), сильный saturate() убил бы розовый цвет
     активной иконки. */
  background: var(--ui-glass-thumb);
  -webkit-backdrop-filter: saturate(92%) brightness(0.99);
  backdrop-filter: saturate(92%) brightness(0.99);
  box-shadow:
    inset 0 1px 1px -0.5px rgba(255, 255, 255, 0.35),
    inset 0 -1px 1px -0.5px rgba(255, 255, 255, 0.2),
    inset 0 0 0 0.5px rgba(255, 255, 255, 0.18);
  opacity: 0;
  transform: translate3d(5px, 5px, 0) scale(var(--ui-thumb-scale, 1));
  transition:
    transform 0.48s cubic-bezier(0.22, 1, 0.36, 1),
    width 0.48s cubic-bezier(0.22, 1, 0.36, 1),
    height 0.48s cubic-bezier(0.3, 1.25, 0.4, 1),
    opacity 0.12s var(--ui-ease),
    background-color 0.16s var(--ui-ease),
    box-shadow 0.16s var(--ui-ease);
  will-change: transform;
  pointer-events: none;
}
/* Внутренняя тень/обводка пилюли — появляется только на удержании. */
.ui-tabbar__thumb:after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
  border-radius: inherit;
  box-shadow:
    inset 0 0 10px -6px rgba(var(--ui-ink-rgb), 0.33),
    inset 0 1px 2px rgba(var(--ui-ink-rgb), 0.12);
  opacity: 0;
  transition: opacity 0.25s var(--ui-ease);
  pointer-events: none;
}
html.ui-lg-active .ui-tabbar__thumb:after,
.ui-tabbar.is-dragging .ui-tabbar__thumb:after {
  opacity: 1;
}
.ui-tabbar__thumb.is-bounce {
  animation: ui-thumb-bounce 0.6s cubic-bezier(0.34, 1.56, 0.5, 1);
}
@keyframes ui-thumb-bounce {
  0% {
    scale: 1 0.9;
  }
  35% {
    scale: 1 1.08;
  }
  68% {
    scale: 1 0.97;
  }
  100% {
    scale: 1 1;
  }
}
/* До первого замера ползунок спрятан — иначе на загрузке он видимо
   въезжает от левого края. */
.ui-tabbar:not(.is-ready) .ui-tabbar__thumb {
  visibility: hidden;
  opacity: 0;
  transition: none;
}
.ui-tabbar.is-ready .ui-tabbar__thumb {
  visibility: visible;
  opacity: 1;
}

/* ── Захват ───────────────────────────────────────────────────── */
.ui-tabbar.is-dragging {
  transform: translateX(-50%) scale(1.045);
}
.ui-tabbar.is-dragging:before {
  background: var(--ui-glass-panel-hold);
  -webkit-backdrop-filter: blur(1px) saturate(130%) brightness(1.03);
  backdrop-filter: blur(1px) saturate(130%) brightness(1.03);
}
.ui-tabbar.is-dragging .ui-tabbar__thumb {
  --ui-thumb-scale: 1;
  background: var(--ui-glass-thumb-hold);
  -webkit-backdrop-filter: saturate(200%);
  backdrop-filter: saturate(200%);
  box-shadow:
    0 17px 36px rgba(var(--ui-ink-rgb), 0.19),
    0 2px 7px rgba(var(--ui-ink-rgb), 0.075),
    inset 0 1px 1px -0.5px rgba(255, 255, 255, 0.55),
    inset 0 -1px 1px -0.5px rgba(255, 255, 255, 0.3),
    inset 0 0 0 0.5px rgba(255, 255, 255, 0.3);
  /* Никаких width/height-транзишенов в захвате: карта преломления
     печётся под размер БОКСА, поэтому анимация бокса оставляла стекло на
     старом размере и потом резко перещёлкивала. Бокс встаёт мгновенно,
     рост даёт transform (sizeSx/sizeSy в jellyTick). */
  transition:
    background-color 0.12s var(--ui-ease),
    box-shadow 0.12s var(--ui-ease),
    opacity 0.12s var(--ui-ease);
}

/* ── Вкладка ──────────────────────────────────────────────────── */
.ui-tabbar__item {
  position: relative;
  z-index: 2;
  display: inline-flex;
  flex: 1 1 0;
  min-width: 0;
  height: 100%;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0;
  padding: 5px 1px 4px;
  border: 0;
  border-radius: 29px;
  background: transparent;
  color: rgba(var(--ui-ink-rgb), 0.9);
  cursor: pointer;
  font: inherit;
  -webkit-tap-highlight-color: transparent;
  transition:
    color 0.2s var(--ui-ease),
    transform 0.2s var(--ui-ease),
    filter 0.18s var(--ui-ease);
}
.ui-tabbar.is-dragging .ui-tabbar__item {
  filter: brightness(calc(1.55 + var(--ui-panel-glow, 0) * 1.4));
}
.ui-tabbar.is-dragging .ui-tabbar__item.is-hot {
  color: var(--ui-accent-strong);
}
.ui-tabbar.is-dragging .ui-tabbar__item.is-active:not(.is-hot) {
  color: rgba(var(--ui-ink-rgb), 0.9);
}
.ui-tabbar.is-dragging .ui-tabbar__icon,
.ui-tabbar.is-dragging .ui-tabbar__label {
  text-shadow: 0 0 8px rgba(255, 255, 255, 0.55);
}
.ui-tabbar__item.is-active {
  background: transparent;
  color: var(--ui-accent-strong);
  box-shadow: none;
}
.ui-tabbar:not(.is-dragging) .ui-tabbar__item:active {
  transform: scale(0.98);
}

.ui-tabbar__icon {
  display: block;
  height: 26.4px;
  font-size: 25.3px;
  font-weight: 760;
  letter-spacing: 0;
  line-height: 0.96;
  transform: translateY(0);
}
.ui-tabbar__icon svg {
  /* Иконки Lucide/Tabler несут свои presentation-атрибуты внутри —
     css только задаёт размер. */
  display: block;
  width: 26.4px;
  height: 26.4px;
  margin: 0 auto;
}

/* ── Значок непросмотренного ──────────────────────────────────── */
.ui-tabbar__badge {
  position: absolute;
  top: 3px;
  left: calc(50% + 1px);
  z-index: 3;
  display: block;
  min-width: 18px;
  height: 18px;
  padding: 0 5px;
  border-radius: var(--ui-radius-pill);
  background: var(--ui-destructive);
  color: #ffffff;
  font-family: var(--ui-font);
  font-size: 13px;
  font-weight: 400;
  letter-spacing: 0;
  line-height: 18px;
  text-align: center;
  pointer-events: none;
}
.ui-tabbar__badge[hidden] {
  display: none;
}

.ui-tabbar__label {
  display: block;
  max-width: 100%;
  overflow: hidden;
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0;
  line-height: 1;
  text-overflow: ellipsis;
  transform: translateY(3px);
  white-space: nowrap;
}

/* ── Узкие экраны ─────────────────────────────────────────────── */
@media (max-width: 390px) {
  .ui-tabbar {
    width: min(calc(100% - 36px), 504px);
    height: 64px;
    padding: 4px 8px;
    border-radius: 32px;
  }
  .ui-tabbar__item {
    border-radius: 28px;
  }
  .ui-tabbar__icon {
    height: 25.3px;
    font-size: 24.2px;
  }
  .ui-tabbar__icon svg {
    width: 25.3px;
    height: 25.3px;
  }
}
/* ── Планшет/десктоп: панель не растягиваем ───────────────────── */
@media (min-width: 700px) {
  .ui-tabbar {
    width: min(calc(100% - 48px), 420px);
  }
}

/* ── Нет backdrop-filter вообще (старый WebView) ──────────────── */
@supports not (
  (-webkit-backdrop-filter: blur(1px)) or (backdrop-filter: blur(1px))
) {
  .ui-tabbar {
    background: rgba(255, 255, 255, 0.6);
  }
  .ui-tabbar:before {
    background: transparent;
  }
  .ui-tabbar__thumb {
    background: rgba(var(--ui-ink-rgb), 0.3);
  }
}

/* ================================================================
   4. ANDROID / CHROMIUM — НАСТОЯЩАЯ ЛИНЗА (SVG-преломление)
      Классы ui-lg-refract / ui-lg-active ставит скрипт линзы.
   ================================================================ */
html.ui-lg-refract .ui-tabbar:before {
  -webkit-backdrop-filter: url(#ui-lg-refraction);
  backdrop-filter: url(#ui-lg-refraction);
}
/* В ПОКОЕ url()-фильтра у ползунка НЕТ. Он висел всегда, а нулевой scale
   смещения гасил только результат — сама цепочка (блюр + saturate + три
   feDisplacementMap + композиты) всё равно считалась каждый кадр, пока
   ползунок едет 0.48s. Отсюда были рывки при обычном нажатии. */
html.ui-lg-refract .ui-tabbar .ui-tabbar__thumb {
  -webkit-backdrop-filter: saturate(92%) brightness(0.99);
  backdrop-filter: saturate(92%) brightness(0.99);
}
/* :not(apple) обязателен: иначе это правило перебило бы сброс фильтра у
   ползунка на apple (там своё стекло на псевдослоях). */
html.ui-lg-refract.ui-lg-active:not([data-font-platform="apple"])
  .ui-tabbar
  .ui-tabbar__thumb,
html.ui-lg-refract .ui-tabbar.is-dragging .ui-tabbar__thumb {
  -webkit-backdrop-filter: url(#ui-lg-thumb);
  backdrop-filter: url(#ui-lg-thumb);
}

/* ================================================================
   5. APPLE (iOS / macOS) — СТЕКЛО БЕЗ SVG
      WebKit не умеет SVG-фильтры в backdrop-filter, поэтому здесь
      стекло собрано из двух псевдослоёв: размытие с кольцевой маской
      (:before) и обводка с поддельной хроматикой (:after).
   ================================================================ */
html[data-font-platform="apple"] .ui-tabbar:before {
  -webkit-backdrop-filter: blur(1.15px) saturate(120%);
  backdrop-filter: blur(1.15px) saturate(120%);
}
/* Класс ползунка ПОВТОРЁН намеренно: правилу нужно перебить и
   drag-вариант refract (`.is-dragging` даёт ту же специфичность), иначе
   на apple в захвате тихо возвращается url()-фильтр — в WebKit он не
   рисуется, но стоит денег.
   `isolation: isolate` — не косметика: элемент с backdrop-filter в
   WebKit уезжает в свой композиторский слой и начинает игнорировать
   z-index, из-за чего обводка и хроматика оказывались то над размытием,
   то под ним. */
html[data-font-platform="apple"]
  .ui-tabbar
  .ui-tabbar__thumb.ui-tabbar__thumb {
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
  isolation: isolate;
}
/* Размытие живёт в отдельном слое с кольцевой маской: в центре пилюли
   она прозрачна (иконка остаётся резкой), к краю набирает силу. */
html[data-font-platform="apple"] .ui-tabbar__thumb:before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 0;
  border-radius: inherit;
  transform: translateZ(0);
  /* В покое слоя нет ВООБЩЕ (не просто без фильтра): маскированный слой
     внутри едущей пилюли — отдельная композиция с маской на каждый кадр
     переезда, на iOS это дороже самого переезда. */
  display: none;
  -webkit-mask-image: radial-gradient(
    ellipse closest-side at 50% 50%,
    transparent 0 42%,
    rgba(0, 0, 0, 0.5) 72%,
    #000 100%
  );
  mask-image: radial-gradient(
    ellipse closest-side at 50% 50%,
    transparent 0 42%,
    rgba(0, 0, 0, 0.5) 72%,
    #000 100%
  );
  pointer-events: none;
}
html[data-font-platform="apple"].ui-lg-active
  .ui-tabbar__thumb:before,
html[data-font-platform="apple"]
  .ui-tabbar.is-dragging
  .ui-tabbar__thumb:before {
  display: block;
  -webkit-backdrop-filter: blur(7px) saturate(92%);
  backdrop-filter: blur(7px) saturate(92%);
}
/* Обводка пилюли на удержании — СВОЯ и постоянная. Кромка размывающего
   слоя подхватывала то границу панели, то чистый фон за её краем, и
   «обводка» появлялась только когда под ней было что размывать. Своя
   линия лежит выше размытия и ни от чего не зависит. Тут же хроматика:
   тёплая кайма слева, холодная справа — имитация дисперсии, которую на
   Android даёт настоящая SVG-линза. */
html[data-font-platform="apple"] .ui-tabbar__thumb:after {
  z-index: 2;
  transform: translateZ(0);
}
html[data-font-platform="apple"].ui-lg-active
  .ui-tabbar__thumb:after,
html[data-font-platform="apple"]
  .ui-tabbar.is-dragging
  .ui-tabbar__thumb:after {
  box-shadow:
    inset 0 0 0 0.5px rgba(var(--ui-ink-rgb), 0.16),
    inset 0 0 10px -6px rgba(var(--ui-ink-rgb), 0.33),
    inset 0 1px 2px rgba(var(--ui-ink-rgb), 0.12),
    inset 2px 0 2.5px -1.5px rgba(255, 0, 132, 0.34),
    inset -2px 0 2.5px -1.5px rgba(0, 168, 255, 0.3),
    inset 0 2px 2.5px -1.5px rgba(255, 64, 160, 0.22),
    inset 0 -2px 2.5px -1.5px rgba(0, 190, 255, 0.2);
}
/* Тот же захват без стекла читался как неоновая подсветка букв: яркость
   1.55 плюс белый text-shadow на светло-розовом фоне. На apple глушим —
   на Android яркая версия остаётся, там это читается как свет сквозь
   стекло. */
html[data-font-platform="apple"]
  .ui-tabbar.is-dragging
  .ui-tabbar__item {
  filter: brightness(calc(1.12 + var(--ui-panel-glow, 0) * 0.5));
}
html[data-font-platform="apple"]
  .ui-tabbar.is-dragging
  .ui-tabbar__icon,
html[data-font-platform="apple"]
  .ui-tabbar.is-dragging
  .ui-tabbar__label {
  text-shadow: none;
}

@media (prefers-reduced-motion: reduce) {
  .ui-tabbar,
  .ui-tabbar__thumb,
  .ui-tabbar__item {
    transition: none;
  }
}

/* Стекло листов в тёмной теме задаётся токенами --ui-sheet-glass-* выше. */
/* БЕЛЫХ INSET-КРОМОК В ТЁМНОЙ ТЕМЕ НЕТ (07.09.2026, «инсет кромки убирай»).
   На светлом стекле они рисуют блик по краю панели, на тёмном — светлый
   ободок. Оставлены только внешние тени, перекрашенные в чёрный. */
[data-theme="dark"] .ui-bar__inner,
[data-theme="dark"] .ui-toast__panel,
html[data-theme="dark"][data-font-platform="apple"] .ui-tabbar {
  box-shadow: 0 0 0 0.5px rgba(0, 0, 0, 0.35);
}
/* ТАББАР В ТЁМНОЙ ТЕМЕ — СТЕКЛО КАК У ТАББАРА TELEGRAM iOS 26 (08.09.2026,
   скриншот юзера: «эффект этого стекла, обводочка беленькая»). Тёмно-серая
   полупрозрачная подложка с сильным размытием (контент за панелью читается
   размытым), белая волосяная обводка по периметру и блик сверху. */
/* ТОЛЬКО ANDROID/ПРОЧИЕ (08.09.2026, «на айфоне и макбуке верни панель с
   0a6e2b4»): на apple таббар в тёмной теме остаётся прежним — подложка
   --ui-glass-panel, лёгкий туман 1.15px и тёмная обводка (правило выше).
   Снаружи — только тень. Обводка и блики лежат на :before ниже: inset-тени
   самого nav закрывались его же :before со стеклом («блики нихуя не видно»). */
:root[data-theme="dark"]:not([data-font-platform="apple"]) .ui-tabbar {
  /* Ровно как на 89373cd (08.09.2026, «верни как было»): обводка и блики на
     самом nav, внешняя тень. */
  box-shadow:
    inset 0 0 0 0.5px rgba(255, 255, 255, 0.24),
    inset 0 1px 0 -0.5px rgba(255, 255, 255, 0.55),
    inset 0 -1px 0 -0.5px rgba(255, 255, 255, 0.32),
    0 10px 28px rgba(0, 0, 0, 0.35);
}
/* ЗАХВАТ В ТЁМНОЙ ТЕМЕ БЕЗ «НЕОНА» (08.09.2026, скриншот юзера: фиолетовые
   цвета при удержании). В светлой захват подсвечивает пункты brightness(1.55),
   кладёт белую тень под текст, насыщает подложку ползунка saturate(200%), а на
   apple ещё рисует хроматические кромки (розовая/синяя) на ползунке — на
   тёмном всё это складывалось в фиолетовое свечение. Здесь всё выключено,
   ползунок получает только белую волосяную обводку. Специфичность через
   :root[...] выше платформенных правил apple. */
:root[data-theme="dark"] .ui-tabbar.is-dragging .ui-tabbar__item {
  filter: none;
}
:root[data-theme="dark"] .ui-tabbar.is-dragging .ui-tabbar__icon,
:root[data-theme="dark"] .ui-tabbar.is-dragging .ui-tabbar__label {
  text-shadow: none;
}
:root[data-theme="dark"]:not(.ui-lg-refract)
  .ui-tabbar.is-dragging
  .ui-tabbar__thumb {
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
}
:root[data-theme="dark"].ui-lg-active .ui-tabbar__thumb:after,
:root[data-theme="dark"] .ui-tabbar.is-dragging .ui-tabbar__thumb:after {
  box-shadow: inset 0 0 0 0.5px rgba(255, 255, 255, 0.14);
}
/* iPhone/Mac: радужная кромка ползунка в захвате, как в светлой теме, но
   контрастнее (08.09.2026, «обводку радужную как на светлой, цвет на тёмной
   чуть контрастнее»). Те же четыре цветные inset-тени, что у apple-правила в
   светлой, альфы подняты примерно в полтора раза, плюс белое кольцо. */
:root[data-theme="dark"][data-font-platform="apple"].ui-lg-active
  .ui-tabbar__thumb:after,
:root[data-theme="dark"][data-font-platform="apple"]
  .ui-tabbar.is-dragging
  .ui-tabbar__thumb:after {
  box-shadow:
    inset 0 0 0 0.5px rgba(255, 255, 255, 0.22),
    inset 0 0 10px -6px rgba(0, 0, 0, 0.4),
    inset 2px 0 2.5px -1.5px rgba(255, 0, 132, 0.52),
    inset -2px 0 2.5px -1.5px rgba(0, 168, 255, 0.46),
    inset 0 2px 2.5px -1.5px rgba(255, 64, 160, 0.34),
    inset 0 -2px 2.5px -1.5px rgba(0, 190, 255, 0.3);
}
/* Как на 89373cd: стекло только там, где нет преломления ui-lg-refract
   (на Android с преломлением панель остаётся базовой), и не на apple. */
:root[data-theme="dark"]:not([data-font-platform="apple"]):not(.ui-lg-refract)
  .ui-tabbar:before {
  background: rgba(40, 40, 44, 0.62);
  -webkit-backdrop-filter: blur(22px) saturate(1.5);
  backdrop-filter: blur(22px) saturate(1.5);
}

[data-theme="dark"] .ui-tabbar.is-dragging .ui-tabbar__thumb {
  box-shadow:
    0 17px 36px rgba(0, 0, 0, 0.3),
    0 2px 7px rgba(0, 0, 0, 0.15);
}
[data-theme="dark"] .ui-sheet__cancel,
[data-theme="dark"] .ui-style-search {
  box-shadow: 0 0 0 0.5px rgba(0, 0, 0, 0.25);
}
[data-theme="dark"] .ui-expand-badge,
[data-theme="dark"] .ui-rail-arrow {
  box-shadow: 0 6px 18px rgba(0, 0, 0, 0.3);
}

/* Иконка маской (белый силуэт → currentColor), если вместо svg хочется
   картинку: <span class="ui-tabbar__glyph" style="--tab-glyph:url(…)"> */
.ui-tabbar__glyph {
  display: block;
  width: 34.3px;
  height: 34.3px;
  margin: -3.95px auto;
  background: currentColor;
  -webkit-mask: var(--tab-glyph) center / contain no-repeat;
  mask: var(--tab-glyph) center / contain no-repeat;
}
@media (min-width: 700px) {
    .ui-tabbar,
    .ui-bar__inner {
      width: min(calc(100% - 48px), 420px);
    }
}

/* ══════════════════════════════════════════════════════════════════════════
   УГАСАНИЕ ПОД ТАББАРОМ (.ui-bottom-fade)
   ══════════════════════════════════════════════════════════════════════════ */
/* ── УГАСАНИЕ ПОД ТАББАРОМ (08.09.2026, по образцу нижней панели Framework7 v9) ──
   Два слоя в фиксированной полосе внизу экрана, под плавающей пилюлей таббара:
   ::before — лёгкое размытие 3px с маской-градиентом (внизу полное, кверху
   сходит на нет — «прогрессивный блюр»), ::after — градиент от цвета фона к
   прозрачному. Тапы пропускает. На широком экране таббара нет — полосы тоже. */
.ui-bottom-fade {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 79;
  /* 103 → 69px и вдвое слабее (08.09.2026, «по площади в 1.5 раза меньше и
     в 2 раза слабее»): размытие 3 → 1.5px, градиент на половинной плотности. */
  height: calc(69px + var(--ui-safe-bottom));
  pointer-events: none;
}
.ui-bottom-fade::before,
.ui-bottom-fade::after {
  content: "";
  position: absolute;
  inset: 0;
}
.ui-bottom-fade::before {
  -webkit-backdrop-filter: blur(1.5px);
  backdrop-filter: blur(1.5px);
  -webkit-mask-image: linear-gradient(to top, #000 50%, transparent 100%);
  mask-image: linear-gradient(to top, #000 50%, transparent 100%);
}
.ui-bottom-fade::after {
  opacity: 0.5;
  background: linear-gradient(
    to top,
    var(--ui-bg) 0%,
    color-mix(in srgb, var(--ui-bg) 72%, transparent) 42%,
    transparent 100%
  );
}

/* ══════════════════════════════════════════════════════════════════════════
   БОКОВОЕ МЕНЮ (.ui-sidebar): широкий экран вместо таббара
   ══════════════════════════════════════════════════════════════════════════ */
/* САМО МЕНЮ. По умолчанию скрыто — показывает его только медиа-запрос выше,
   поэтому на телефоне разметка просто лежит мёртвым грузом и ни на что не
   влияет. */
.ui-sidebar {
  position: fixed;
  top: 0;
  left: 0;
  bottom: 0;
  z-index: 90;
  display: none;
  width: var(--ui-sidebar-w, 244px);
  flex-direction: column;
  box-sizing: border-box;
  /* ВЕРХНИЙ ОТСТУП ЗАВИСИТ ОТ КЛИЕНТА, И ЭТО ВАЖНО.
     На макбуке кнопки Telegram (закрыть, ⌄, ⋯) живут в хроме окна, ВНЕ вебвью,
     и меню спокойно начинается от самого верха. На айпаде аппа открыта на весь
     экран, те же кнопки лежат ПОВЕРХ страницы — и накрывали логотип
     (31.08.2026, скриншот юзера). Отступ берём от `--ui-fullscreen-top`: это и
     есть высота полосы, которую занимают нативные кнопки. На десктопе она
     ноль, поэтому там ничего не съедет. */
  padding: calc(6px + var(--ui-fullscreen-top, 0px)) 12px 18px;
  overflow-y: auto;
  /* По той же причине, что и у экранов: иначе меню тоже елозит вбок. */
  overflow-x: hidden;
  /* ПРОКРУТКА ТОЛЬКО ВНУТРИ ПАНЕЛИ. Без этого жест в зоне меню, дойдя до края
     списка, подхватывал документ и тащил всю страницу. */
  overscroll-behavior: contain;
  border-right: 1px solid var(--ui-sidebar-border);
  /* ФОН СПЛОШНОЙ, БЕЗ ПРОЗРАЧНОСТИ И РАЗМЫТИЯ — намеренно. Полупрозрачная
     подложка на оттяжке просвечивала уезжающий контент, и в панели мелькало
     содержимое страницы. Заодно это и есть «другой цвет»: панель светлее
     полотна. */
  background: var(--ui-sidebar-bg);
}

/* ЗАПАС ФОНА ЗА КРАЯМИ ЭКРАНА. Резиновая оттяжка WebKit двигает весь слой
   вместе с `position: fixed` — панель уезжает, и в освободившейся полосе
   проглядывает полотно страницы. Лечим подложкой, которая на 240px больше
   панели сверху и снизу: тянуть по-прежнему можно, а показаться из-под неё
   уже нечему. Это `::before`, а не padding, чтобы не трогать прокрутку
   списка. */
.ui-sidebar:before {
  content: "";
  /* Именно fixed, а не absolute: абсолютная подложка своими -240px снизу
     увеличивала прокручиваемую высоту САМОЙ панели, и под меню появлялась
     пустая полоса, которую можно было листать в никуда. Fixed в прокрутке
     не участвует вовсе, а при резиновой оттяжке едет вместе со слоем — то
     есть по-прежнему прикрывает просвет. */
  position: fixed;
  z-index: -1;
  top: -240px;
  bottom: -240px;
  left: 0;
  width: var(--ui-sidebar-w, 244px);
  background: inherit;
}

/* Логотип кликабельный — уводит на главную. Именно кнопка, а не обработчик на
   картинке: так работают и клавиатура, и озвучка экрана. */
.ui-sidebar__logo-btn {
  display: block;
  width: 100%;
  padding: 0;
  border: 0;
  background: transparent;
  text-align: left;
  cursor: pointer;
}

.ui-sidebar__logo-btn:active {
  opacity: 0.75;
}

.ui-sidebar__logo {
  display: block;
  width: 152px;
  max-width: calc(100% - 16px);
  height: auto;
  margin: 2px 0 2px 10px;
}

.ui-sidebar__inner {
  display: flex;
  flex: 1 0 auto;
  flex-direction: column;
  gap: 20px;
  /* Ровно на пиксель выше панели — этого хватает, чтобы у меню появилась своя
     резиновая оттяжка, отдельная от оттяжки основного полотна. Вместе с
     `overscroll-behavior: contain` на панели получается то, что просил юзер:
     тянешь меню — едет меню, тянешь контент — едет контент. */
  min-height: calc(100% + 1px);
}

.ui-sidebar__group {
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.ui-sidebar__caption {
  margin: 0 0 6px;
  padding: 0 10px;
  color: var(--ui-hint);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.ui-sidebar__item {
  display: flex;
  align-items: center;
  gap: 12px;
  box-sizing: border-box;
  width: 100%;
  padding: 10px 12px;
  border: 0;
  /* Максимальный радиус — просьба юзера: пункт читается как пилюля. */
  border-radius: 999px;
  background: transparent;
  color: var(--ui-text);
  font-family: inherit;
  font-size: 15px;
  /* Тоньше, чем было (600): просьба юзера. */
  font-weight: 500;
  text-align: left;
  cursor: pointer;
  transition:
    background 150ms var(--ui-ease),
    color 150ms var(--ui-ease);
}

.ui-sidebar__item:hover {
  background: var(--ui-hover);
}

.ui-sidebar__item.is-active {
  background: var(--ui-accent);
  color: #fff;
}

.ui-sidebar__item:active {
  transform: scale(0.985);
}

/* Значок непросмотренных — РОВНО ТОТ ЖЕ, что на вкладке истории в таббаре.
   Размеры, цвет и начертание скопированы оттуда один в один, своих чисел
   здесь быть не должно: `--ui-destructive` — тот самый красный, 18×18 — тот
   самый системный размер, а вес 400 стоит не случайно. В таббаре про него
   написано прямым текстом: вес 500 пробовали и юзер его отбраковал, на
   красном жирные цифры выглядят тяжело. Крутить размер, вес не трогать.
   Отличие одно: здесь значок не абсолютный, а прижат к правому краю пункта. */
.ui-sidebar__badge {
  margin-left: auto;
  display: block;
  /* КРУГ ДЕРЖИТСЯ И НА ДВУХ ЦИФРАХ. В таббаре значок 18px с полями по 5px:
     одна цифра даёт круг, а две растягивают его в овал — на телефоне это не
     мешает, значок там маленький и висит на иконке. Здесь он стоит в строке
     меню, и юзер попросил круг (31.08.2026: «на айпаде круглый, а на маке вот
     такая хуйня» — на маке было двузначное число). Поэтому 20px в обе стороны
     и поля всего 2px: «16» при шрифте 13px занимает ~15px и спокойно влезает
     внутрь круга. Растянуться значок может только на «99+», и это правильно —
     обрезать число хуже, чем потерять форму на трёхзначном.
     Цвет, шрифт и вес — те же, что в таббаре, их не трогаем. */
  min-width: 20px;
  height: 20px;
  padding: 0 2px;
  box-sizing: border-box;
  border-radius: var(--ui-radius-pill);
  background: var(--ui-destructive);
  color: #ffffff;
  font-family: var(--ui-font);
  font-size: 13px;
  font-weight: 400;
  /* Моноширинные цифры: иначе ширина значка гуляет от числа к числу, а на
     разных платформах ещё и по-разному. */
  font-variant-numeric: tabular-nums;
  letter-spacing: 0;
  line-height: 20px;
  text-align: center;
  pointer-events: none;
}

.ui-sidebar__badge[hidden] {
  display: none;
}

.ui-sidebar__icon {
  display: flex;
  flex: 0 0 auto;
  width: 20px;
  height: 20px;
}

.ui-sidebar__icon svg {
  width: 100%;
  height: 100%;
}
@media (prefers-reduced-motion: reduce) {
    .ui-sidebar__item {
      transition: none;
    }
}
@media (min-aspect-ratio: 1/1) and (min-width: 1000px) {
  :root { --ui-sidebar-w: 244px; }
  .ui-sidebar { display: flex; }
  .ui-tabbar, .ui-bottom-fade { display: none; }
  .ui-veil { left: var(--ui-sidebar-w); }
  .ui-heading { left: calc(var(--ui-sidebar-w) + 72px); }
}

/* ══════════════════════════════════════════════════════════════════════════
   ПОЛОСА ПРОКРУТКИ СПРЯТАНА (как в аппе)
   ══════════════════════════════════════════════════════════════════════════ */
/* ПОЛОСА ПРОКРУТКИ СПРЯТАНА ВО ВСЕЙ АППЕ (03.09, просьба юзера: «справа
   палочка, которая показывает, где листаешь»). На телефоне скроллится документ,
   на широком экране — узел экрана (см. блок «ШИРОКИЙ ЭКРАН»), поэтому правило
   и на html/body, и на самих экранах. Прокрутка при этом остаётся, пропадает
   только индикатор. Вернуть — удалить этот блок. */
html,
body,
.ui-scroll,
.ui-sidebar {
  scrollbar-width: none;
  -ms-overflow-style: none;
}
html::-webkit-scrollbar,
body::-webkit-scrollbar,
.ui-scroll::-webkit-scrollbar,
.ui-sidebar::-webkit-scrollbar {
  display: none;
  width: 0;
  height: 0;
}
