/* ============================================================================
   ДИЗАЙН-СИСТЕМА
   ----------------------------------------------------------------------------
   Один слой токенов на весь сайт: поверхности, текст, акценты, отступы,
   радиусы, тени, типографика. Всё ниже ссылается ТОЛЬКО на эти переменные —
   поэтому цвет или ритм отступов меняется в одном месте, а не в 900 строках.

   Правила, которых держимся (проверяются `design_review` из плагина
   dsh-ui-ux-pro-max и тестом контраста):
   • семантические имена (`--surface-2`), а не «какой-то синий»;
   • три тона текста: основной ≥ 12:1, вторичный ≥ 9:1, приглушённый ≥ 4.5:1
     на панели `--surface-1` (посчитано для #8b94a7 → 6.0:1);
   • ОДИН акцент для действий (`--accent`). Остальные цвета — только смысл:
     левая/правая рука, стена, ошибка/успех/предупреждение;
   • радиусы и отступы из шкалы 4/8, без произвольных значений;
   • фокус виден всегда (`:focus-visible`), «меньше движения» уважается.
   ========================================================================== */

/* ---------- шрифты: свои файлы, без запросов наружу ----------
   Inter — интерфейс, JetBrains Mono — цифры (таймкоды, BPM, номера такта):
   они не «прыгают» при смене значения, потому что моноширинные.
   Оба шрифта нарезаны на подмножества (latin / latin-ext / cyrillic), в
   сумме ~215 КБ; браузер берёт только нужные и кладёт их в кеш навсегда
   (имена файлов стабильные). `build.mjs` копирует `src/fonts/` в `dist/fonts/`. */
@font-face {
  font-family: "Inter"; font-style: normal; font-weight: 400 700; font-display: swap;
  src: url("./fonts/inter-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Inter"; font-style: normal; font-weight: 400 700; font-display: swap;
  src: url("./fonts/inter-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: "Inter"; font-style: normal; font-weight: 400 700; font-display: swap;
  src: url("./fonts/inter-cyrillic.woff2") format("woff2");
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@font-face {
  font-family: "JetBrains Mono"; font-style: normal; font-weight: 400 600; font-display: swap;
  src: url("./fonts/jetbrains-mono-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "JetBrains Mono"; font-style: normal; font-weight: 400 600; font-display: swap;
  src: url("./fonts/jetbrains-mono-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: "JetBrains Mono"; font-style: normal; font-weight: 400 600; font-display: swap;
  src: url("./fonts/jetbrains-mono-cyrillic.woff2") format("woff2");
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}

:root {
  color-scheme: dark;

  /* --- типографика --- */
  --font-sans: "Inter", "Segoe UI", system-ui, -apple-system, "Helvetica Neue", Arial, sans-serif;
  --font-mono: "JetBrains Mono", ui-monospace, "SF Mono", "Cascadia Mono", Consolas, monospace;
  --fs-micro: 10.5px;   /* надзаголовки-капсы, счётчики */
  --fs-xs: 11.5px;      /* подписи полей, подсказки */
  --fs-sm: 12.5px;      /* плотный интерфейсный текст */
  --fs-md: 13.5px;      /* основной текст */
  --fs-lg: 15px;        /* заголовки панелей, значения */
  --fs-xl: 17px;        /* бренд, крупные числа */
  --fs-2xl: 22px;       /* только в диалогах/пустых состояниях */
  --lh-tight: 1.25;
  --lh-normal: 1.5;
  --tracking-caps: .09em;

  /* --- поверхности: от «глубже страницы» до «под курсором» --- */
  --bg: #0a0c11;            /* страница */
  --bg-2: #0d1017;          /* полоса вкладок, шапка */
  --bg-inset: #07090d;      /* полотна: 3D-поле, таймлайн, код */
  --surface-1: #12151d;     /* панели, карточки */
  --surface-2: #171b25;     /* кнопки, поля ввода, вложенные блоки */
  --surface-3: #1f2431;     /* наведение, активное состояние */
  --surface-4: #28303f;     /* нажатие, выбранный чип */

  /* --- текст --- */
  --text: #e7ecf5;          /* 15:1 на панели */
  --text-2: #b3bccd;        /* 9.5:1 */
  --muted: #8b94a7;         /* 6.0:1 — минимум для второстепенного текста */
  --faint: #6b7486;         /* 3.9:1 — только декор и подсказки-точки */

  /* --- линии: полупрозрачные, чтобы лежать на любой поверхности --- */
  --line: rgba(255, 255, 255, .16);        /* граница интерактивных элементов */
  --line-soft: rgba(255, 255, 255, .085);  /* разделители внутри панелей */
  --line-strong: rgba(255, 255, 255, .28); /* наведение на границу */

  /* --- акценты --- */
  --accent: #35c6e0;        /* единственный акцент действий (9:1 на панели) */
  --accent-hi: #5fdcf2;     /* наведение/свечение */
  --accent-dim: #1d8ba1;    /* нажатие */
  --accent-ink: #04161c;    /* текст на акценте */
  --accent-soft: rgba(53, 198, 224, .13);
  --accent-line: rgba(53, 198, 224, .42);
  --violet: #8b7dff;        /* вторичный смысл: 3D, «вариативность» */
  --green: #3ddc97;         /* успех, «зелёные» ноты */
  --amber: #ffb648;         /* предупреждение, стены */
  --red: #ff5d6c;           /* ошибка, удаление */

  /* --- цвета нот и рук (смысловые, не брендовые) --- */
  --hand-left: #4aa8ff;
  --hand-right: #ff5fa8;
  --hand-both: #ffce6a;

  /* --- алиасы прежних имён: старые правила продолжают работать --- */
  --bg2: var(--bg-2);
  --panel: var(--surface-1);
  --panel-solid: var(--surface-1);
  --cyan: var(--accent);
  --magenta: var(--hand-right);

  /* --- отступы: шкала 4/8 --- */
  --s-1: 4px; --s-2: 8px; --s-3: 12px; --s-4: 16px; --s-5: 24px; --s-6: 32px;
  /* --- радиусы --- */
  --r-xs: 6px; --r-sm: 8px; --r-md: 10px; --r-lg: 14px; --r-xl: 18px; --r-pill: 999px;
  --radius: var(--r-md);
  /* --- тени: слоистые, с тонкой светлой кромкой сверху (объём без «грязи») --- */
  --shadow-1: 0 1px 2px rgba(0, 0, 0, .4);
  --shadow-2: 0 8px 24px -8px rgba(0, 0, 0, .7), 0 1px 0 rgba(255, 255, 255, .04) inset;
  --shadow-3: 0 24px 60px -20px rgba(0, 0, 0, .85), 0 1px 0 rgba(255, 255, 255, .05) inset;
  --shadow: var(--shadow-2);
  --shadow-focus: 0 0 0 2px var(--bg), 0 0 0 4px var(--accent-line);
  /* --- движение --- */
  --t-fast: 110ms;
  --t-base: 170ms;
  --ease: cubic-bezier(.2, .6, .2, 1);
  /* --- слои --- */
  --z-sticky: 20; --z-topbar: 40; --z-menu: 60; --z-toast: 80; --z-dialog: 100;

  font-synthesis-weight: none;
  -webkit-tap-highlight-color: transparent;
}

* { box-sizing: border-box; }
/* The `hidden` attribute must win over any layout rule below (e.g.
   `label.field { display: block }`), otherwise a field marked hidden in the
   markup keeps showing up — that is how the login form ended up asking for the
   password twice. */
[hidden] { display: none !important; }
html, body { height: 100%; }
/* Фон — не «космос с туманностями», а спокойная нейтральная подложка с одним
   холодным свечением сверху: панели и полотно 3D должны читаться как слои на
   ней, а цветные блики конкурировали с цветами нот (красный/синий/золотой) и
   сбивали с толку — на графике карты их принимали за элементы карты. */
body {
  margin: 0;
  background:
    radial-gradient(1200px 620px at 50% -220px, rgba(53, 198, 224, .10) 0%, transparent 70%),
    var(--bg);
  background-attachment: fixed;
  color: var(--text);
  font: var(--fs-md)/var(--lh-normal) var(--font-sans);
  letter-spacing: -.005em;
  font-feature-settings: "cv05" 1, "ss01" 1;
  overflow: hidden;
}
button, input, select, textarea { font: inherit; color: inherit; letter-spacing: inherit; }
a { color: var(--accent); text-decoration-color: var(--accent-line); text-underline-offset: 2px; }
a:hover { color: var(--accent-hi); }
::selection { background: var(--accent-line); color: #fff; }

/* Полосы прокрутки — часть интерфейса: тонкие, чтобы не съедать ширину панели,
   и видимые только при наведении на контейнер (иначе они «шумят» на скриншотах
   и в тёмной теме выглядят как ещё одна рамка). */
* { scrollbar-width: thin; scrollbar-color: rgba(255, 255, 255, .16) transparent; }
*::-webkit-scrollbar { width: 10px; height: 10px; }
*::-webkit-scrollbar-track { background: transparent; }
*::-webkit-scrollbar-thumb {
  background: rgba(255, 255, 255, .13); border: 3px solid transparent; border-radius: 999px;
  background-clip: padding-box;
}
*:hover::-webkit-scrollbar-thumb { background: rgba(255, 255, 255, .22); background-clip: padding-box; }

/* Фокус: ЕДИНОЕ кольцо по всему сайту. `:focus-visible` — чтобы мышью кольцо не
   мигало, а с клавиатуры было видно всегда (в тёмной теме системный outline
   почти не читался). */
:focus-visible { outline: none; box-shadow: var(--shadow-focus); border-radius: var(--r-sm); }

/* «Меньше движения»: выключаем переходы и анимации, кроме индикаторов работы
   (спиннер несёт смысл «идёт работа», его только замедляем — см. ниже). */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { transition-duration: 1ms !important; animation-duration: 1ms !important; }
}

/* ---------- мелкая типографика-утилита ---------- */
.mono { font-family: var(--font-mono); font-variant-numeric: tabular-nums; letter-spacing: -.02em; }
.caps {
  font-size: var(--fs-micro); font-weight: 600; letter-spacing: var(--tracking-caps);
  text-transform: uppercase; color: var(--muted);
}
.small { font-size: var(--fs-xs); }
.muted { color: var(--muted); }

/* ---------- иконки ----------
   Спрайт: `<svg class="sprite">` в разметке (внутри — `<symbol>`), на каждый
   значок ссылаются `<svg class="ic"><use href="#ic-save"/></svg>`. Размеры — три
   токена, толщина штриха одна на весь сайт, цвет наследуется от текста
   (`currentColor`), поэтому иконка в кнопке всегда одного цвета с подписью. */
.sprite { position: absolute; width: 0; height: 0; overflow: hidden; }
.ic {
  width: 16px; height: 16px; flex: none;
  fill: none; stroke: currentColor; stroke-width: 1.75;
  stroke-linecap: round; stroke-linejoin: round;
  /* Оптическая компенсация: у линейных иконок «центр массы» чуть выше базовой
     линии, поэтому значок в строке текста поднимаем на 1–2 px. */
  vertical-align: -2px;
}
.ic-sm { width: 14px; height: 14px; }
.ic-lg { width: 22px; height: 22px; }
button.icon > .ic { margin: 0; }
/* Заголовки диалогов: крестик без «рамки» — это закрытие, а не действие. */
.dlg-head button.icon { width: 28px; height: 28px; border-color: transparent; background: transparent; }
.dlg-head button.icon:hover:not(:disabled) { background: rgba(255, 255, 255, .07); border-color: transparent; }

/* ---------- top bar ----------
   Шапка = бренд слева, состояние движка по центру, действия справа. Действия
   разделены на смысловые группы тонкими разделителями (проект · аккаунт ·
   справка): раньше двенадцать кнопок одного вида стояли подряд, и «Сохранить»
   не отличалось от «ЧАВО». */
.topbar {
  height: 56px; display: flex; align-items: center; justify-content: space-between; gap: var(--s-3);
  padding: 0 var(--s-4); border-bottom: 1px solid var(--line-soft);
  background: color-mix(in srgb, var(--bg-2) 92%, transparent);
  backdrop-filter: blur(10px) saturate(1.2);
  /* Шапка обязана стоять НАД полем просмотра: её выпадающие меню (⋯ и история
     уведомлений) выходят за её границы, а `.view` — позиционированный элемент
     ниже по документу. Без своего контекста наложения панель уведомлений
     рисовалась ПОД 3D-полем: заголовок видно, строк с сообщениями нет —
     «уведомления не видно» (владелец, 2026-10-20). */
  position: relative;
  z-index: var(--z-topbar);
}
.brand {
  display: flex; align-items: center; gap: var(--s-2); font-size: var(--fs-lg);
  letter-spacing: -.01em; min-width: 0; white-space: nowrap;
}
/* На ноутбуке шапка дорогая: подзаголовок «для Synth Riders» первым уходит под
   нож, иначе бренд ломается на две строки и шапка становится выше. */
@media (max-width: 1560px) {
  .brand .sub { display: none; }
  .brand .ver { display: none; }
}
@media (max-width: 1460px) {
  /* Справка о возможностях браузера — не действие: без неё шапка спокойно
     укладывается в одну строку. Значения видны в консоли и на больших экранах. */
  #engine-badge { display: none; }
}
.brand b { color: var(--text); font-weight: 650; }
/* Логотип — не светящийся ромб, а знак на акцентной плашке: читается и в 16 px,
   и на ретине, и не «мигает неоном» рядом с заголовком. */
.brand .logo {
  width: 26px; height: 26px; flex: none; display: inline-flex; align-items: center; justify-content: center;
  border-radius: var(--r-sm); background: linear-gradient(160deg, var(--accent), var(--accent-dim));
  color: var(--accent-ink); font-size: 15px; line-height: 1;
  box-shadow: 0 1px 0 rgba(255, 255, 255, .25) inset, 0 4px 14px -6px var(--accent);
}
.brand .sub { color: var(--muted); font-weight: 400; font-size: var(--fs-sm); }
.ver {
  color: var(--faint); font-family: var(--font-mono); font-size: var(--fs-micro);
  border: 1px solid var(--line-soft); border-radius: var(--r-pill); padding: 1px 6px;
}
.topbar-actions { display: flex; gap: var(--s-2); align-items: center; min-width: 0; }
/* разделитель между группами действий: 1 px высотой 20 px, не «полоса в полшапки» */
.topbar-actions > .sep { width: 1px; height: 20px; background: var(--line-soft); margin: 0 2px; flex: none; }

/* меню «⋯» в шапке: сюда убирается то, что не нужно каждый день
   («Мои проекты», «Как установить в игру») — но и не спрятано глубоко */
.menu { position: relative; }
.menu > summary {
  list-style: none; cursor: pointer; display: inline-flex; align-items: center; justify-content: center;
  min-width: 34px; height: 32px; padding: 0 9px; border: 1px solid var(--line-soft); border-radius: var(--r-sm);
  background: var(--surface-2); font-size: 15px; line-height: 1; transition: background var(--t-fast), border-color var(--t-fast);
}
.menu > summary::-webkit-details-marker { display: none; }
.menu > summary:hover { border-color: var(--line-strong); background: var(--surface-3); }
.menu[open] > summary { border-color: var(--accent-line); background: var(--surface-3); }
.menu-body {
  position: absolute; right: 0; top: calc(100% + 8px); z-index: var(--z-menu);
  display: flex; flex-direction: column; gap: 2px; min-width: 220px; padding: 6px;
  border: 1px solid var(--line); border-radius: var(--r-lg);
  background: color-mix(in srgb, var(--surface-1) 97%, transparent);
  box-shadow: var(--shadow-3);
  animation: menu-in var(--t-base) var(--ease);
}
@keyframes menu-in { from { opacity: 0; transform: translateY(-4px); } to { opacity: 1; transform: none; } }
.menu-body button { justify-content: flex-start; text-align: left; padding: 8px 10px; border-color: transparent; background: transparent; }
.menu-body button:hover:not(:disabled) { background: var(--surface-3); border-color: transparent; box-shadow: none; }

/* полоса вкладок: на десктопе её заменяют вкладки .tabs, поэтому скрыта */
.mtabs { display: none; }

/* ---------- generic controls ----------
   Одна высота (32 px), один радиус, три вида: обычная (surface-2), главная
   (акцентная заливка) и «тональная» (акцентная подложка для действия-экспорта).
   Раньше главных было две — голубая и розовая, — и на экране не было понятно,
   какое действие «то самое». */
button {
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  height: 32px; padding: 0 11px;
  border: 1px solid var(--line-soft); background: var(--surface-2); color: var(--text);
  border-radius: var(--r-sm); cursor: pointer; white-space: nowrap;
  font-size: var(--fs-sm); font-weight: 500;
  transition: background var(--t-fast) var(--ease), border-color var(--t-fast) var(--ease),
              color var(--t-fast) var(--ease), transform var(--t-fast) var(--ease);
}
button:hover:not(:disabled) { background: var(--surface-3); border-color: var(--line-strong); }
button:active:not(:disabled) { background: var(--surface-4); transform: translateY(.5px); }
button:disabled { opacity: .45; cursor: not-allowed; }
button.primary {
  background: var(--accent); color: var(--accent-ink); border-color: transparent;
  font-weight: 620; box-shadow: 0 1px 0 rgba(255, 255, 255, .22) inset;
}
button.primary:hover:not(:disabled) { background: var(--accent-hi); border-color: transparent; }
button.primary:active:not(:disabled) { background: var(--accent-dim); }
/* Тональная — для «скачать/экспортировать»: то же семейство акцента, но не
   спорит с главной кнопкой текущего шага. */
button.accent { background: var(--accent-soft); color: var(--accent-hi); border-color: var(--accent-line); font-weight: 600; }
button.accent:hover:not(:disabled) { background: rgba(53, 198, 224, .2); border-color: var(--accent); }
button.ghost { background: transparent; border-color: var(--line-soft); }
button.ghost:hover:not(:disabled) { background: var(--surface-2); border-color: var(--line-strong); }
button.tiny { height: 26px; padding: 0 8px; font-size: var(--fs-xs); border-radius: var(--r-xs); }
button.icon { width: 32px; padding: 0; }
button.wide { width: 100%; justify-content: flex-start; }

/* Поля ввода — ОДИН вид на весь сайт, независимо от типа. Раньше в правиле были
   только `text`/`number`, поэтому `url` (ссылка на Яндекс Музыку) и `password`
   (токен, вход) оставались системными: другой фон, другая рамка, другой кегль и
   высота — на одной панели соседствовали два непохожих поля. Ширину по-прежнему
   задаёт контекст (`.grow`, компактные ячейки инспектора), а всё остальное —
   общее: рамка, фон, радиус, кегль, отступы, кольцо фокуса. */
input[type="text"], input[type="number"], input[type="url"], input[type="password"],
input[type="search"], input[type="email"], input[type="tel"], input[type="date"],
select, textarea {
  width: 100%; min-height: 32px; padding: 6px 9px;
  background: var(--bg-inset); border: 1px solid var(--line-soft); border-radius: var(--r-sm);
  color: var(--text); font: inherit; font-size: var(--fs-sm); line-height: 1.35;
  transition: border-color var(--t-fast) var(--ease), background var(--t-fast) var(--ease), box-shadow var(--t-fast) var(--ease);
}
input:not([type="range"]):not([type="checkbox"]):not([type="radio"]):not([type="file"]):hover:not(:disabled),
select:hover:not(:disabled), textarea:hover:not(:disabled) { border-color: var(--line-strong); }
input:focus, select:focus, textarea:focus { outline: none; border-color: var(--accent-line); box-shadow: 0 0 0 3px var(--accent-soft); }
input:disabled, select:disabled, textarea:disabled { opacity: .45; cursor: not-allowed; }
input::placeholder, textarea::placeholder { color: var(--faint); opacity: 1; }
/* Числовые поля и таймкоды — моноширинными: цифры не «прыгают» при вводе. */
input[type="number"], input[type="date"] { font-family: var(--font-mono); font-size: var(--fs-sm); font-variant-numeric: tabular-nums; }
select {
  appearance: none; padding-right: 26px; cursor: pointer;
  /* своя стрелка: нативная в тёмной теме рисуется светлой и разной в каждом браузере */
  background-image: linear-gradient(45deg, transparent 50%, var(--muted) 50%), linear-gradient(135deg, var(--muted) 50%, transparent 50%);
  background-position: calc(100% - 14px) 13px, calc(100% - 9px) 13px;
  background-size: 5px 5px, 5px 5px; background-repeat: no-repeat;
}
input[type="range"] { width: 100%; height: 18px; accent-color: var(--accent); cursor: pointer; }
input[type="checkbox"], input[type="radio"] { accent-color: var(--accent); width: 16px; height: 16px; margin: 0; flex: none; cursor: pointer; }
label.check { display: flex; align-items: center; gap: var(--s-2); font-size: var(--fs-xs); color: var(--text-2); cursor: pointer; user-select: none; }
label.check span { color: var(--text); }
label.field { display: block; margin-bottom: var(--s-2); }
label.field > span {
  display: block; color: var(--muted); font-size: var(--fs-micro); font-weight: 600;
  text-transform: uppercase; letter-spacing: var(--tracking-caps); margin-bottom: 5px;
}

/* ---------- крестик очистки поля и «стандартное значение» ползунка ----------
   Обёртки навешивает decorateFields() в main.js на готовую разметку: `${input}`
   остаётся тем же элементом (его держат ссылки `el.*` и обработчики), меняется
   только родитель. Поэтому обёртка обязана вести себя как поле в раскладке —
   забрать `grow` у поля и растянуться, а не схлопнуться в строчный `<span>`. */
.input-wrap { position: relative; display: block; width: 100%; min-width: 0; }
.input-wrap.grow { flex: 1 1 auto; }
.input-wrap > input { width: 100%; padding-right: 32px; }
/* Обёртка — не подпись поля: `label.field > span` ставит капитель, кегль подписи
   и цвет, а внутри обёртки живёт само поле, и оно наследует от неё шрифт. */
label.field > span.input-wrap, label.field > span.range-wrap {
  margin: 0; font: inherit; font-size: 13px; letter-spacing: normal;
  text-transform: none; color: var(--text);
}
.input-clear {
  position: absolute; top: 50%; right: 5px; transform: translateY(-50%);
  width: 20px; height: 20px; padding: 0; display: grid; place-items: center;
  border: 0; border-radius: 50%; background: rgba(255, 255, 255, .1); color: var(--text-2);
  font-size: 11px; line-height: 1; cursor: pointer;
  opacity: 0; visibility: hidden; transition: opacity var(--t-fast), background var(--t-fast), color var(--t-fast);
}
.input-wrap.has-value .input-clear { opacity: 1; visibility: visible; }
.input-clear:hover:not(:disabled) { background: rgba(255, 93, 108, .22); color: #ffc2c8; box-shadow: none; }
.input-clear:focus-visible { opacity: 1; visibility: visible; }
.input-clear:disabled { opacity: 0; visibility: hidden; }

.range-wrap { display: flex; align-items: center; gap: 6px; min-width: 0; }
.range-wrap > input[type="range"] { flex: 1 1 auto; width: auto; min-width: 0; }
.range-reset {
  flex: none; width: 20px; height: 20px; padding: 0; display: grid; place-items: center;
  border: 1px solid transparent; border-radius: 50%; background: rgba(255, 255, 255, .07);
  color: var(--muted); font-size: 13px; line-height: 1; cursor: pointer; transition: all var(--t-fast);
}
.range-reset:hover:not(:disabled) { background: var(--accent-soft); border-color: var(--accent-line); color: var(--accent-hi); }
.range-reset:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; box-shadow: none; }
/* Ползунок уже стоит на стандартном значении — возвращать нечего, гасим; при
   наведении на строку стрелка проявляется, чтобы её было видно и понятно. */
.range-wrap.at-default .range-reset { opacity: .5; }
.slider-row:hover .range-wrap.at-default .range-reset,
.range-wrap.at-default .range-reset:hover:not(:disabled) { opacity: .95; }
.row { display: flex; gap: var(--s-2); align-items: center; }
.row.wrap { flex-wrap: wrap; }
.grow { flex: 1; }
.hint { color: var(--muted); font-size: var(--fs-xs); line-height: 1.45; }
hr.sep { border: 0; border-top: 1px solid var(--line-soft); margin: var(--s-3) 0; }
.badge {
  display: inline-flex; align-items: center; gap: 5px; border: 1px solid var(--line-soft);
  border-radius: var(--r-pill); padding: 2px 8px; font-size: var(--fs-micro);
  color: var(--text-2); background: rgba(255, 255, 255, .03);
}
/* Значок возможностей движка в шапке: это техническая справка («что умеет этот
   браузер»), а не действие и не статус проекта. Поэтому он самый тихий элемент
   шапки: моноширинный микротекст, без заливки, цветная только точка-индикатор. */
#engine-badge {
  border-color: transparent; background: transparent; padding: 2px 4px; white-space: nowrap;
  font-family: var(--font-mono); font-size: var(--fs-micro); color: var(--faint);
  letter-spacing: -.01em;
}
#engine-badge::before {
  content: ''; width: 6px; height: 6px; border-radius: 50%; flex: none;
  background: var(--muted);
}
#engine-badge.ok::before { background: var(--green); }
#engine-badge.warn::before { background: var(--amber); }
#engine-badge:hover { color: var(--text-2); }

.badge.ok { color: var(--green); border-color: rgba(61, 220, 151, .34); background: rgba(61, 220, 151, .09); }
.badge.warn { color: var(--amber); border-color: rgba(255, 182, 72, .34); background: rgba(255, 182, 72, .09); }
.badge.bad { color: var(--red); border-color: rgba(255, 93, 108, .34); background: rgba(255, 93, 108, .09); }

/* ---------- layout ---------- */
.layout { display: grid; grid-template-columns: 368px 1fr; height: calc(100% - 56px); }
.sidebar {
  overflow-y: auto; overscroll-behavior: contain;
  padding: var(--s-3) var(--s-3) var(--s-6);
  border-right: 1px solid var(--line-soft); background: var(--bg-2);
}
.main { display: flex; flex-direction: column; min-width: 0; }

/* Панель — карточка со своим заголовком: номер шага, название. Заголовок больше
   не «капс голубым» — он нейтральный, а цветом выделен только номер шага, чтобы
   взгляд шёл по порядку ① → ② → ③, а не спотыкался о четыре одинаковых
   акцентных строки. */
.panel {
  background: var(--surface-1); border: 1px solid var(--line-soft); border-radius: var(--r-lg);
  padding: var(--s-3); margin-bottom: var(--s-3);
  box-shadow: var(--shadow-1);
}
.panel > h2 {
  margin: 0 0 var(--s-3); padding-bottom: var(--s-2); border-bottom: 1px solid var(--line-soft);
  font-size: var(--fs-lg); font-weight: 620; letter-spacing: -.01em; color: var(--text);
  display: flex; align-items: center; gap: var(--s-2); text-transform: none;
}
/* Номер шага. Правило самостоятельное, а не «.panel > h2 .num»: в Full Auto
   такой h2 лежит внутри строки-обёртки, и номер оставался простой цифрой,
   приклеенной к заголовку («2Очередь треков»). */
.num {
  width: 20px; height: 20px; border-radius: 50%; flex: none;
  background: var(--accent-soft); border: 1px solid var(--accent-line);
  display: inline-flex; align-items: center; justify-content: center;
  font-family: var(--font-mono); font-size: var(--fs-micro); font-weight: 600; color: var(--accent);
  line-height: 1;
}
.panel > h2 .num { margin-right: 0; }
/* Подзаголовок внутри объединённых панелей: «Проект» начинается с аудио, а
   «Ритм и карта» держит темп и параметры раскладки в одной панели — разделитель
   между частями нужен, отдельный заголовок панели им уже не поставить. */
.panel > h3 {
  margin: var(--s-3) 0 var(--s-2); font-size: var(--fs-micro); letter-spacing: var(--tracking-caps);
  text-transform: uppercase; color: var(--muted); font-weight: 600;
}
.panel > h3:first-child { margin-top: 0; }
.panel.disabled { opacity: .45; pointer-events: none; filter: saturate(.4); }

/* Поле, недоступное в текущем состоянии проекта (см. refreshAvailability в
   main.js): у input/button/select это native `disabled`, у чипов, полосок и
   таблицы — этот класс. Так панель остаётся читаемой, а недоступное — видно. */
.off { opacity: .45; pointer-events: none; filter: saturate(.4); }
/* То же затемнение, но БЕЗ запрета кликов: так помечают группу, которая ждёт
   настройки от самого пользователя. На группе фрагмента стоял `.off`, и кнопки
   «⇤ A» / «B ⇥» оказывались некликабельными ровно до того момента, как фрагмент
   задан, — задать его мышью было нельзя, только из консоли (нашёл editor.test). */
.dim { opacity: .55; filter: saturate(.45); }

/* Кольцо-спиннер на кнопке, пока идёт сохранение (класс `.busy` ставит
   setSaveBusy в main.js). Крутится `transform`, то есть на композиторе: анимация
   продолжает идти и пока главный поток занят кодированием OGG. */
.spin {
  display: inline-block; width: 11px; height: 11px; margin-right: 7px; vertical-align: -1px;
  border: 2px solid currentColor; border-right-color: transparent; border-radius: 50%;
  animation: spin 0.7s linear infinite;
}
button.busy { cursor: progress; }
@keyframes spin { to { transform: rotate(1turn); } }

/* Отметка «Сохранено» на 3 секунды (класс `.saved` ставит flashSaved в main.js):
   подпись становится серой на нейтральной подложке — и на розовой кнопке в
   панели, и на «призрачной» в шапке. Наведение в этом состоянии ничего не
   подсвечивает: делать на кнопке больше нечего. */
button.saved,
button.accent.saved,
button.ghost.saved {
  color: var(--muted);
  background: color-mix(in srgb, #ffffff 6%, transparent);
  border-color: color-mix(in srgb, #ffffff 14%, transparent);
  box-shadow: none;
}
button.saved:hover { border-color: color-mix(in srgb, #ffffff 14%, transparent); box-shadow: none; }
/* Уважаем «меньше движения»: спиннер не выключаем совсем (он несёт смысл
   «идёт работа»), но замедляем. */
@media (prefers-reduced-motion: reduce) { .spin { animation-duration: 2.4s; } }

/* Режим «Бокс» — спойлер, у которого ЗАГОЛОВОК — сама галочка «только с точкой»,
   а тело — вложенный режим. Каретка своя (нативный маркер у flex не работает):
   клик по тексту раскрывает спойлер, клик по чекбоксу только ставит галочку —
   так `<summary>` с голым `input` и ведёт себя в браузере. */
details.box-mode { margin-top: 8px; }
details.box-mode > summary {
  display: flex; align-items: center; gap: 6px;
  cursor: pointer; user-select: none; font-size: 12px;
}
details.box-mode > summary::before {
  content: '▸'; color: var(--muted); font-size: 10px; width: 9px; flex: none;
}
details.box-mode[open] > summary::before { content: '▾'; color: var(--cyan); }
details.box-mode > summary:hover::before { color: var(--cyan); }
details.box-mode.on > summary { color: var(--green); }
details.box-mode.on > summary::after { content: ' ✓'; }
details.box-mode > .check,
details.box-mode > .hint { padding-left: 15px; }
details.box-mode > .check { display: flex; margin-top: 7px; }
details.box-mode > .hint { margin-top: 6px; }

/* ---------- drop zone ----------
   Первый экран нового проекта: не пунктирная рамка на весь блок, а «полка» с
   иконкой, строкой-приглашением и строкой форматов. Иконка — SVG из спрайта
   (`.ic`), не эмодзи: на системах без эмодзи-шрифта такие значки превращаются
   в «квадратики» (именно это и было видно в шапке). */
.drop {
  border: 1px dashed var(--line); border-radius: var(--r-lg); padding: var(--s-5) var(--s-3);
  text-align: center; cursor: pointer; background: var(--bg-inset);
  transition: border-color var(--t-base) var(--ease), background var(--t-base) var(--ease);
}
.drop:hover, .drop.over { border-color: var(--accent); background: rgba(53, 198, 224, .06); }
.drop .big { display: flex; justify-content: center; margin-bottom: var(--s-2); color: var(--muted); }
.drop:hover .big, .drop.over .big { color: var(--accent); }
.drop .big .ic { width: 30px; height: 30px; }
.drop .hint { margin-top: var(--s-1); }
/* Трек уже загружен: зона перетаскивания становится компактной строкой-заменой,
   а не занимает четверть панели (там теперь живут название, обложка и экспорт). */
body.has-audio .drop { padding: var(--s-2) var(--s-3); }
body.has-audio .drop .big,
body.has-audio .drop .hint,
body.has-audio .drop br { display: none; }
body.has-audio .drop b { font-size: var(--fs-sm); font-weight: 500; color: var(--muted); }
/* Компактная подпись «Заменить файл» вместо приглашения на два строки. */
.drop-compact { display: none; color: var(--text-2); font-size: var(--fs-sm); }
body.has-audio .drop-compact { display: inline; }
body.has-audio .drop-full { display: none; }

.filecard { display: flex; gap: var(--s-2); align-items: center; margin-top: var(--s-2); }
.filecard .name { font-weight: 600; word-break: break-all; font-size: var(--fs-sm); }
.meter { height: 4px; background: rgba(255, 255, 255, .07); border-radius: var(--r-pill); overflow: hidden; }
.meter > i { display: block; height: 100%; width: 0; background: var(--accent); transition: width var(--t-base) var(--ease); }

/* ---------- chips / sliders ----------
   Чип — выбор из набора (сложность, инструмент, рука). В покое нейтральный,
   выбранный — тональная подложка акцента с акцентной рамкой. */
.chips { display: flex; flex-wrap: wrap; gap: 5px; }
.chip {
  border: 1px solid var(--line-soft); background: var(--surface-2); border-radius: var(--r-pill);
  height: 28px; padding: 0 11px; cursor: pointer; font-size: var(--fs-sm); user-select: none;
  display: inline-flex; align-items: center; gap: 6px; color: var(--text-2);
  transition: background var(--t-fast) var(--ease), border-color var(--t-fast) var(--ease), color var(--t-fast) var(--ease);
}
.chip:hover { background: var(--surface-3); border-color: var(--line-strong); color: var(--text); }
.chip.on { border-color: var(--accent-line); background: var(--accent-soft); color: var(--accent-hi); font-weight: 550; }
.chip .dot { width: 7px; height: 7px; border-radius: 50%; background: var(--muted); flex: none; }
.chip.on .dot { background: var(--accent); }
/* Строка ползунка: подпись · ползунок · значение. Значение моноширинное и
   фиксированной ширины — иначе строка «дёргается», когда число меняет разряд. */
.slider-row {
  display: grid; grid-template-columns: 88px 1fr 52px; gap: var(--s-2); align-items: center;
  margin-bottom: 7px;
}
.slider-row > span:first-child { color: var(--muted); font-size: var(--fs-xs); }
.slider-row output {
  text-align: right; color: var(--text); font-family: var(--font-mono);
  font-variant-numeric: tabular-nums; font-size: var(--fs-xs);
}

/* ---------- tabs / viewer ----------
   Виды («Предпросмотр 3D» / «Таймлайн и редактор») — сегментированный
   переключатель над полотном, а не «папки»: выбранный вид поднят фоном,
   невыбранный — просто текст, который светлеет при наведении. */
.tabs { display: flex; gap: 4px; padding: var(--s-2) var(--s-3) 0; }
.tab {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 7px 12px; cursor: pointer; color: var(--muted);
  font-size: var(--fs-sm); font-weight: 500; border-radius: var(--r-sm);
  border: 1px solid transparent;
  transition: color var(--t-fast) var(--ease), background var(--t-fast) var(--ease);
}
.tab:hover { color: var(--text); background: var(--surface-2); }
.tab.on { color: var(--text); background: var(--surface-1); border-color: var(--line-soft); }
.viewwrap {
  flex: 1; margin: 0 var(--s-3) var(--s-3); border: 1px solid var(--line-soft); border-radius: var(--r-lg);
  background: var(--bg-inset); overflow: hidden; position: relative; min-height: 0;
}
.view { position: absolute; inset: 0; display: none; }
.view.on { display: block; }
.view.timeline-view { overflow: auto; padding: var(--s-3) var(--s-3) 84px; }
.tl-toolbar-row { display: flex; align-items: center; flex-wrap: wrap; gap: var(--s-2); margin-bottom: var(--s-2); }
.tl-row-label { flex: 0 0 auto; font-size: var(--fs-xs); color: var(--muted); }
/* Гнёзда в строке инструментов таймлайна: отмена/сетка/масштаб — разные смыслы,
   между ними вертикальная черта, а не просто «пустое место». */
.tl-group {
  display: inline-flex; align-items: center; gap: 4px;
  padding-right: var(--s-2); border-right: 1px solid var(--line-soft);
}
.tl-group:last-of-type { border-right: 0; }
.tl-window, .tl-pos { font-size: var(--fs-xs); color: var(--text-2); }
.tl-pos { color: var(--muted); }
.chip { cursor: pointer; }
.chip#btn-snap { font-family: var(--font-mono); font-weight: 550; min-width: 46px; justify-content: center; }

/* transport
   Панель воспроизведения: слева главное действие (плей) и время, дальше шкала,
   справа — параметры показа (скорость, руки, звук). Раньше всё стояло в один
   ряд одинаковым весом, и «Play» терялся среди чекбоксов. */
.transport {
  display: flex; align-items: center; gap: var(--s-2); padding: 7px 10px;
  border-top: 1px solid var(--line-soft);
  background: color-mix(in srgb, var(--bg-2) 94%, transparent);
  position: absolute; left: 0; right: 0; bottom: 0; backdrop-filter: blur(10px);
  /* Панель никогда не вылезает за поле: на узком ноутбуке (1440) она переносила
     «синхр.» за правый край. Лучше вторая строка, чем обрезанные элементы. */
  flex-wrap: wrap; row-gap: 6px;
}
.transport .time {
  font-family: var(--font-mono); font-variant-numeric: tabular-nums;
  color: var(--text); font-size: var(--fs-sm); min-width: 112px;
}
.transport .time .k { color: var(--muted); }
/* ползунок и полоска выбранного фрагмента под ним */
.transport .scrub-wrap { flex: 1; display: flex; align-items: center; position: relative; min-width: 80px; }
.scrub-wrap .frag-band {
  position: absolute; bottom: -1px; height: 3px; border-radius: 2px; background: var(--accent);
  pointer-events: none;
}
/* фрагмент: границы A/B, включение, подпись */
.transport .frag { display: flex; align-items: center; gap: 5px; flex: none; }
.transport .frag .small { white-space: nowrap; }
#frag-label { color: var(--muted); font-family: var(--font-mono); font-variant-numeric: tabular-nums; font-size: var(--fs-xs); }
#frag-label.on { color: var(--accent); }
/* Кнопка «Играть» — крупнее прочих: это главное действие панели. */
#btn-play, .transport .play {
  height: 36px; min-width: 88px; font-size: var(--fs-md); font-weight: 620; border-radius: var(--r-md);
}

/* Группы транспорта: каждое смысловое гнездо отделено тонкой чертой, чтобы
   «перемотка / фрагмент / показ» не сливались в одну серую строку. */
.transport .tr-group { display: inline-flex; align-items: center; gap: var(--s-2); flex: none; }
.transport .tr-group + .tr-group { padding-left: var(--s-2); border-left: 1px solid var(--line-soft); }
.transport .tr-opts { gap: var(--s-3); flex-wrap: wrap; row-gap: 4px; }
@media (max-width: 1560px) {
  /* «весь трек» — подпись длительности фрагмента; без неё панель влезает в одну
     строку на ноутбуке. Сам фрагмент включается галочкой рядом. */
  #frag-label { display: none; }
}
@media (max-width: 1320px) {
  /* На нешироком экране шкала перемотки уходит отдельной строкой, а не сжимается
     до нерабочих 40 px. */
  .transport .scrub-wrap { order: 9; flex-basis: 100%; }
}

/* Подсказка-спойлер в панели: длинное пояснение не занимает пол-панели, но и не
   спрятано — заголовок виден всегда, текст раскрывается по клику. */
details.hint-more { margin-top: var(--s-2); }
details.hint-more > summary {
  cursor: pointer; list-style: none; display: flex; align-items: center; gap: 5px;
  font-size: var(--fs-xs); color: var(--text-2); user-select: none;
  padding: 3px 0;
}
details.hint-more > summary::-webkit-details-marker { display: none; }
details.hint-more > summary::before { content: '▸'; color: var(--muted); font-size: 10px; transition: transform var(--t-fast); }
details.hint-more[open] > summary::before { content: '▾'; color: var(--accent); }
details.hint-more > summary:hover { color: var(--text); }
details.hint-more > .hint { margin-top: 5px; padding-left: 14px; }

/* Пустое состояние 3D-поля: спокойная плашка по центру, гаснет с первой картой. */
.view-empty {
  position: absolute; inset: 0; z-index: 2;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: var(--s-2); text-align: center; padding: var(--s-5);
  color: var(--muted); pointer-events: none;
}
.view-empty .ic { width: 34px; height: 34px; color: var(--surface-4); stroke-width: 1.4; }
.view-empty b { color: var(--text-2); font-size: var(--fs-lg); font-weight: 600; }
.view-empty span { font-size: var(--fs-sm); line-height: 1.55; max-width: 34ch; }
body.has-chart .view-empty { display: none; }

canvas { display: block; }
/* Поле 3D — тоже «полотно», а не страница: палец по нему крутит камеру, а не
   прокручивает документ. Без touch-action: none браузер забирает жест себе и
   присылает pointercancel — поворот получается рывками, а «щипок» уходит в
   масштабирование страницы. user-select гасит выделение при перетаскивании. */
#preview-canvas {
  width: 100%; height: 100%; cursor: grab;
  touch-action: none; user-select: none; -webkit-user-select: none; -webkit-touch-callout: none;
}
#preview-canvas:active { cursor: grabbing; }
/* touch-action: палец по полотну — это перетаскивание нот и перемотка, а не прокрутка
   страницы. Без этого браузер забирает жест себе и присылает pointercancel: движение
   получалось рывками (замер: 12 touchmove → 2 pointermove → pointercancel). */
#timeline-canvas { width: 100%; height: 200px; cursor: crosshair; background: var(--bg-inset); border-radius: var(--r-sm); touch-action: none; }
/* полоска обзора всего трека: где мы и какой кусок видим */
#overview-canvas { width: 100%; height: 28px; background: var(--bg-inset); border-radius: var(--r-sm); margin-bottom: 6px; cursor: grab; touch-action: none; }
#overview-canvas:active { cursor: grabbing; }
#waveform-canvas { width: 100%; height: 96px; background: var(--bg-inset); border-radius: var(--r-sm); }

/* ---------- stats / note lists ----------
   Таблица сложностей: числа выровнены по правому краю и набраны моноширинными,
   заголовки не переносятся по буквам (в узкой панели «НОТ/С» рвалось на две
   строки и колонки съезжали). */
table.stats { width: 100%; border-collapse: collapse; font-size: var(--fs-sm); table-layout: auto; }
table.stats th, table.stats td { text-align: left; padding: 6px; border-bottom: 1px solid var(--line-soft); vertical-align: middle; }
table.stats th {
  color: var(--muted); font-weight: 600; font-size: var(--fs-micro);
  text-transform: uppercase; letter-spacing: var(--tracking-caps); white-space: nowrap;
}
table.stats td.num, table.stats th.num {
  text-align: right; font-family: var(--font-mono); font-variant-numeric: tabular-nums; white-space: nowrap;
}
table.stats tbody tr { cursor: pointer; }
table.stats tbody tr:hover { background: rgba(255, 255, 255, .04); }
/* Активная сложность: та же строка, что играет в 3D. Раньше был класс `.on` без
   правил — строка выглядела как остальные, и непонятно было, что показывается. */
table.stats tbody tr.on { background: var(--accent-soft); }
table.stats tbody tr.on td:first-child { color: var(--text); font-weight: 600; }
table.stats .dot { display: inline-block; width: 7px; height: 7px; border-radius: 50%; margin-right: 5px; vertical-align: 1px; }
table.stats .dot.bad { background: var(--red); }
table.stats .dot.warn { background: var(--amber); }
table.stats .dot.ok { background: transparent; border: 1.5px solid rgba(61, 220, 151, .55); }
table.stats .dot.stale { background: transparent; border: 1.5px dashed var(--muted); }
/* Значок статуса в первой колонке стоит после подписи и не сдвигает числа */
table.stats td:first-child .dot:last-child { margin: 0 0 0 5px; }
table.stats .good { color: var(--green); }
table.stats .bad { color: var(--red); }
table.stats .warn { color: var(--amber); }
/* Числовые заголовки выровнены так же, как числа под ними (по правому краю) —
   иначе «Н/с» стоит слева, а «0.0 / 4» справа, и столбец читается как два. */
table.stats th.num { text-align: right; }
table.stats th:first-child, table.stats td:first-child { padding-left: 2px; }
table.stats th:last-child, table.stats td:last-child { padding-right: 2px; }
.diffname { display: inline-flex; align-items: center; gap: 6px; white-space: nowrap; }
.diffname .swatch { width: 8px; height: 8px; border-radius: 2px; flex: none; }

/* ---------- 3D overlay ---------- */
/* Шапка поля — одна строка на десктопе (показания слева, сложность и камера
   справа) и колонка на телефоне. Позиционируется контейнер, а не два
   независимых absolute-блока: иначе на узком экране они наезжали друг на друга
   (HUD «Время» уходил под выбор сложности). */
.overlay-top {
  position: absolute; top: 10px; left: var(--s-3); right: var(--s-3);
  display: flex; align-items: flex-start; justify-content: space-between; gap: 10px;
  pointer-events: none;
}
/* Показания — «стеклянная» плашка, а не текст поверх сцены: цифры читаются и на
   светлом небе, и на тёмном полу. */
.overlay-hud {
  display: flex; flex-direction: column; gap: 2px;
  padding: 7px 10px; border-radius: var(--r-md);
  background: rgba(10, 12, 17, .62); border: 1px solid var(--line-soft);
  backdrop-filter: blur(10px);
  font-size: var(--fs-xs); color: var(--text-2); pointer-events: none;
}
.overlay-hud .k { color: var(--muted); }
.overlay-hud b {
  color: var(--text); font-family: var(--font-mono); font-variant-numeric: tabular-nums;
  font-weight: 550;
}
/* строки HUD не переносим: подписи короткие, а перенос ломает сетку чтения */
.overlay-hud > div { white-space: nowrap; }
.overlay-right { display: flex; gap: 6px; align-items: center; }
/* кнопки шапки живые, сама строка — прозрачная для пальца: жест по пустому
   месту строки должен доставаться полю и крутить камеру */
.overlay-right > * { pointer-events: auto; }
/* Кнопка «Игрок» — быстрый переход к третьему лицу; в этом ракурсе подсвечена. */
#btn-player.on { color: var(--accent-hi); border-color: var(--accent-line); background: var(--accent-soft); }
/* выбор сложности: в 3D — на самом поле, в таймлайне — в строке инструментов */
.overlay-pick, .inline-pick {
  display: inline-flex; align-items: center; gap: 6px; padding: 3px 4px 3px 9px; border-radius: var(--r-md);
  background: rgba(10, 12, 17, .62); border: 1px solid var(--line-soft); backdrop-filter: blur(10px);
}
.overlay-pick > span, .inline-pick > span { font-size: var(--fs-xs); color: var(--muted); white-space: nowrap; }
.overlay-pick select, .inline-pick select {
  width: auto; min-width: 88px; min-height: 26px; padding: 2px 22px 2px 6px; font-size: var(--fs-xs);
  border-radius: var(--r-xs); background-color: var(--surface-2); border: 1px solid var(--line-soft);
  color: var(--text); background-position: calc(100% - 12px) 11px, calc(100% - 7px) 11px;
}
.legend {
  position: absolute; bottom: calc(var(--transport-h, 58px) + 8px); left: var(--s-3);
  display: flex; flex-wrap: wrap; gap: 10px; align-items: center;
  padding: 5px 10px; border-radius: var(--r-pill);
  background: rgba(10, 12, 17, .55); border: 1px solid var(--line-soft);
  backdrop-filter: blur(8px);
  font-size: var(--fs-xs); color: var(--text-2); pointer-events: none;
}
.legend i { display: inline-flex; align-items: center; gap: 5px; font-style: normal; white-space: nowrap; }
.legend .sw { width: 8px; height: 8px; border-radius: 50%; flex: none; }

/* Подсказка управления жестами (только тач-экран, гаснет после первого жеста).
   Стоит у нижнего края поля — над легендой, а не поверх нот в центре. */
.touch-hint {
  position: absolute; left: 10px; right: 10px; bottom: 10px; z-index: 3;
  display: flex; justify-content: center; pointer-events: none;
}
.touch-hint > span {
  padding: 7px 13px; border-radius: var(--r-pill);
  background: rgba(10, 12, 17, .9); border: 1px solid var(--line-soft);
  font-size: var(--fs-xs); color: var(--text-2); box-shadow: var(--shadow-2); text-align: center;
}

/* ---------- timeline hint accordion ---------- */
.timeline-hint-accordion { margin: 6px 0; border: 1px solid transparent; }
.timeline-hint-accordion summary {
  cursor: pointer; padding: 4px 0; font-size: var(--fs-xs); color: var(--accent); user-select: none;
}
@media (min-width: 901px) {
  .timeline-hint-accordion > summary { display: none; }
  .timeline-hint-accordion > .hint { display: block !important; }
}

/* ---------- files view ---------- */
pre.code {
  background: var(--bg-inset); border: 1px solid var(--line-soft); border-radius: var(--r-sm); padding: var(--s-3);
  overflow: auto; max-height: 320px; font: var(--fs-xs)/1.6 var(--font-mono); color: var(--text-2);
}

/* ---------- уведомления ---------- */
/* Всплывающая плашка — СВЕРХУ и по центру: сообщение об ошибке должно попадаться
   на глаза там, где оно случилось (раньше плашка стояла внизу и её было не
   видно вовсе — стили ждали класс `on`, а код ставил `show`). Элемент объявлен
   как `popover`, поэтому его не закрывает открытый диалог. Гаснет сам. */
.toast {
  position: fixed; top: 14px; left: 50%; right: auto; bottom: auto; margin: 0;
  transform: translateX(-50%) translateY(-16px);
  background: color-mix(in srgb, var(--surface-2) 97%, transparent); border: 1px solid var(--line); border-radius: 10px; padding: 10px 16px;
  box-shadow: var(--shadow); opacity: 0; transition: .25s; z-index: 60;
  max-width: min(560px, 92vw); font-size: 13px; line-height: 1.45;
  /* Цвет текста задаём ЯВНО. Элемент объявлен `popover`, а встроенный стиль
     браузера для popover ставит `color: CanvasText` — в светлой теме это ЧЁРНЫЙ
     текст, и на тёмной плашке его не видно (владелец: «на чёрном фоне чёрные
     буквы»). Наследование от body здесь не помогает, поэтому пишем цвет сами и
     просим тёмную схему для внутренностей браузера. */
  color: var(--text); color-scheme: dark;
  /* Полоса слева — вид сообщения: её видно и боковым зрением, не читая текст. */
  border-left-width: 4px;
  /* Сообщение — это только сообщение: клики сквозь него уходят туда, куда
     целился человек (иначе плашка сверху перехватывала бы нажатия по шапке). */
  pointer-events: none;
}
.toast.on { opacity: 1; transform: translateX(-50%) translateY(0); }
/* Классы видов названы с префиксом `kind-`: голые `err`/`ok` в этом файле уже
   заняты блоками ошибок (`.err` — розовая плашка, `.ok` — зелёная рамка), и
   плашка ловила их фон вместо своего. */
.toast.kind-err { border-color: color-mix(in srgb, var(--red) 67%, transparent); border-left-color: var(--red); background: rgba(42, 21, 34, 0.97); box-shadow: 0 12px 34px color-mix(in srgb, var(--red) 25%, transparent); }
.toast.kind-warn { border-color: color-mix(in srgb, var(--amber) 67%, transparent); border-left-color: var(--amber); background: rgba(39, 32, 15, 0.97); box-shadow: 0 12px 34px color-mix(in srgb, var(--amber) 20%, transparent); }
.toast.kind-ok { border-color: color-mix(in srgb, var(--green) 67%, transparent); border-left-color: var(--green); background: rgba(18, 35, 28, 0.97); }
.toast.kind-info { border-left-color: var(--cyan); }

/* Колокольчик: счётчик непрочитанных поверх иконки */
#notif-menu > summary { position: relative; }
.notif-count {
  position: absolute; top: -5px; right: -5px; min-width: 16px; height: 16px; padding: 0 4px;
  display: inline-flex; align-items: center; justify-content: center; border-radius: var(--r-pill);
  /* Счётчик — не «розовый акцент бренда», а сигнал внимания: красный кружок с
     белёсым текстом читается на любой шапке и не спорит с акцентом действий. */
  background: var(--red); color: #fff; font-size: var(--fs-micro); font-weight: 700;
  box-shadow: 0 0 0 2px var(--bg-2);
  font-family: var(--font-mono);
}
/* Цвет текста и здесь задаём явно: панель не должна зависеть от того, что
   унаследовалось от шапки, — на тёмном фоне нужны светлые буквы. */
.notif-body { width: min(380px, 92vw); gap: var(--s-2); color: var(--text); }
.notif-list { color: var(--text); }
.notif-head { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.notif-head b { font-size: 13px; }
.notif-list { display: flex; flex-direction: column; gap: var(--s-2); max-height: 56vh; overflow: auto; }
.notif-group h4 {
  margin: 0 0 5px; font-size: 10.5px; text-transform: uppercase; letter-spacing: .06em; color: var(--muted);
}
.notif-item {
  display: flex; align-items: baseline; gap: var(--s-2); padding: 8px 10px; margin-bottom: 6px;
  border-radius: var(--r-sm); background: rgba(255, 255, 255, .035);
  border-left: 2px solid var(--line); font-size: var(--fs-sm); line-height: 1.45;
}
.notif-item:last-child { margin-bottom: 0; }
.notif-item.err { border-left-color: var(--red); background: rgba(255, 93, 108, .1); }
.notif-item.warn { border-left-color: var(--amber); background: rgba(255, 182, 72, .1); }
.notif-item.info { border-left-color: var(--green); }
.notif-item .when { color: var(--muted); font-size: var(--fs-micro); white-space: nowrap; font-family: var(--font-mono); }
.notif-item .text { flex: 1; min-width: 0; word-break: break-word; }
.notif-item .times { color: var(--muted); font-size: 11px; }
/* Диалог — карточка поверх затемнения: заголовок отделён линией, тело
   прокручивается, кнопки закрытия — иконка-крестик в правом верхнем углу. */
dialog {
  border: 1px solid var(--line); background: var(--surface-1); color: var(--text);
  border-radius: var(--r-xl);
  max-width: 780px; width: 92vw; max-height: 84vh; padding: 0;
  box-shadow: var(--shadow-3);
}
dialog::backdrop { background: rgba(5, 7, 11, .72); backdrop-filter: blur(4px); }
dialog .dlg-head {
  display: flex; justify-content: space-between; align-items: center; gap: var(--s-3);
  padding: var(--s-3) var(--s-4); border-bottom: 1px solid var(--line-soft);
}
dialog .dlg-head > b { font-size: var(--fs-lg); font-weight: 620; letter-spacing: -.01em; }
dialog .dlg-body { padding: var(--s-4); overflow: auto; max-height: 66vh; }
dialog h3 {
  margin: var(--s-4) 0 var(--s-2); font-size: var(--fs-md); font-weight: 600;
  letter-spacing: var(--tracking-caps); text-transform: uppercase; color: var(--muted);
}
dialog h3:first-child { margin-top: 0; }
dialog code {
  background: rgba(255, 255, 255, .07); padding: 1px 5px; border-radius: var(--r-xs);
  font-family: var(--font-mono); font-size: var(--fs-xs);
}
dialog .dlg-foot {
  display: flex; justify-content: flex-end; gap: var(--s-2);
  padding: var(--s-3) var(--s-4); border-top: 1px solid var(--line-soft);
}
.spin { display: inline-block; width: 13px; height: 13px; border: 2px solid rgba(255, 255, 255, .2); border-top-color: var(--accent); border-radius: 50%; animation: spin .7s linear infinite; }
@keyframes spin { to { transform: rotate(360deg); } }
.progress-line { display: flex; align-items: center; gap: 9px; margin-top: 8px; }

/* inspector */
.inspector { border-top: 1px solid var(--line-soft); padding: 10px 12px; display: flex; gap: 12px; align-items: flex-end; background: color-mix(in srgb, var(--bg-2) 50%, transparent); flex-wrap: wrap; }
.inspector .field { margin: 0; }
.inspector label.field > span { margin-bottom: 2px; }
/* Ширина — своя (инспектор узкий), остальное оформление — общее, как у всех полей */
.inspector .field input, .inspector .field select { width: 78px; }
.pad {
  display: grid; grid-template-columns: repeat(3, 26px); grid-template-rows: repeat(3, 26px); gap: 3px;
}
.pad button { padding: 0; border-radius: 6px; font-size: 11px; background: var(--surface-2); }
.pad button.on { background: color-mix(in srgb, var(--accent) 20%, transparent); border-color: var(--cyan); }
/* выбор направления реза у Beat Saber: 3×3 — восемь стрелок и точка «любой» */
.cut-pad { display: grid; grid-template-columns: repeat(3, 24px); grid-template-rows: repeat(3, 24px); gap: 2px; }
.cut-pad button { padding: 0; border-radius: 5px; font-size: 12px; line-height: 1; background: var(--surface-2); }
.cut-pad button.on { background: color-mix(in srgb, var(--accent) 20%, transparent); border-color: var(--accent); }
.cut-pad button span { pointer-events: none; }

@media (max-width: 1100px) {
  .layout { grid-template-columns: 320px 1fr; }
}

/* ============================ mobile ============================
   Телефон и планшет: одна колонка, и ВСЁ — вкладками (полоса .mtabs в шапке):
   четыре панели параметров и три вида. Сворачиваемого меню нет, показывается
   ровно одна секция за раз, страница прокручивается. Размеры элементов
   рассчитаны на палец (не меньше 40 px по высоте).
   =============================================================== */
.only-mobile { display: none; }

@media (max-width: 900px) {
  html, body { height: auto; min-height: 100%; overflow: visible; -webkit-text-size-adjust: 100%; }

  .only-mobile { display: inline-flex; }

  /* Шапка телефона — ДВА ряда: «бренд · сохранение · уведомления · ⋯» и под ним
     вкладки. Раньше сюда падали в четыре ряда (бренд, формат+Full Auto+язык,
     сохранить+последний проект, аккаунт+ЧАВО+колокольчик+⋯) и съедали 340 px из
     844 — почти половину экрана. Всё, что не поместилось, живёт в меню «⋯»
     (пункты-прокси нажимают те же кнопки шапки), поэтому действий не убавилось. */
  /* Сетка, а не flex-wrap: бренд ужимается с многоточием, действия всегда
     прижаты к правому краю и не могут уехать за экран (при широком системном
     шрифте и переносе строки кнопка «⋯» раньше уходила за границу). */
  .topbar {
    position: sticky; top: 0; z-index: var(--z-sticky); height: auto; min-height: 0;
    display: grid; grid-template-columns: minmax(0, 1fr) auto;
    column-gap: 8px; row-gap: 4px; align-items: center;
    padding: 8px 12px 6px; padding-top: max(8px, env(safe-area-inset-top));
  }
  .topbar-actions { grid-column: 2; justify-self: end; justify-content: flex-end; flex-wrap: nowrap; gap: 6px; }
  .brand { min-width: 0; overflow: hidden; }
  .brand > span:not(.logo) { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .brand .sub, .brand .ver { display: none; }
  .brand { font-size: var(--fs-md); }
  .brand .logo { width: 24px; height: 24px; }

  /* «⋯» и колокольчик: панель отсчитывается от ШАПКИ, а не от кнопки — кнопка
     стоит у самого края, и панель с `right: 0` от неё уезжала за экран. */
  .topbar .menu { position: static; }
  .topbar .menu-body {
    left: auto; right: 8px; top: calc(100% + 4px);
    min-width: 0; width: min(280px, calc(100vw - 16px)); max-width: none;
  }

  /* Только то, что нужно каждый день: генератор статуса, формат карты, Full Auto,
     флаги, сохранение словом, аккаунт, ЧАВО, админка — в меню «⋯». */
  .topbar-actions > .badge,
  .topbar-actions > .mode-toggle,
  .topbar-actions > #btn-fullauto,
  .topbar-actions > .lang-toggle,
  .topbar-actions > #btn-close-top,
  .topbar-actions > #btn-resume-top,
  .topbar-actions > #btn-admin-top,
  .topbar-actions > #btn-account,
  .topbar-actions > #btn-faq { display: none; }
  /* «Сохранить» остаётся, но без слова: значок + подпись для скринридера. */
  #btn-save-top { width: 38px; padding: 0; font-size: 0; gap: 0; }
  #btn-save-top .ic { width: 18px; height: 18px; }

  /* вкладки: одна строка, прокручивается по горизонтали, если не влезла.
     Тач-цель 44 px по высоте. */
  .mtabs {
    grid-column: 1 / -1;
    display: flex; flex-wrap: nowrap; gap: 6px;
    margin: 0 -4px; padding: 2px 4px; overflow-x: auto; scrollbar-width: none;
    scroll-snap-type: x proximity;
  }
  .mtabs::-webkit-scrollbar { display: none; }
  .mtabs button {
    flex: 0 0 auto; height: 40px; padding: 0 14px; font-size: var(--fs-sm);
    border-radius: var(--r-sm); scroll-snap-align: start;
    background: transparent; border-color: transparent; color: var(--text-2);
  }
  .mtabs button.on {
    color: var(--text); background: var(--surface-2);
    border-color: var(--line-soft); font-weight: 600;
  }
  .mtabs button:disabled {
    opacity: .35; color: var(--muted); cursor: not-allowed;
    border-color: transparent; pointer-events: none;
  }

  /* «⋯» на телефоне: панель меню отсчитывается от ШАПКИ, а не от самой кнопки.
     Кнопка — последний элемент строки .topbar-actions; когда строка уже
     заполнена (широкий системный шрифт + «Сохранить · Админка · аккаунт ·
     ЧАВО»), она переносится на новую строку к ЛЕВОМУ краю. Панель с `right: 0`
     от кнопки шириной 36 px разворачивалась влево и уезжала за экран: на
     телефоне владельца от неё оставалась полоска ~50 px поверх вкладок, а сами
     вкладки и заголовки панели были перекрыты (2026-10-20). `position: static`
     у .menu делает точкой отсчёта шапку (она sticky, то есть уже
     позиционирована), и панель ложится под шапку с полями 12 px — справа на
     ширину до 260 px, куда бы кнопка ни перенеслась. */
  .topbar .menu { position: static; }
  .topbar .menu-body {
    left: auto; right: 12px; top: calc(100% + 4px);
    min-width: 0; width: min(260px, calc(100vw - 24px)); max-width: none;
  }
  .menu-body button { min-height: 42px; }
  /* меню «⋯» на телефоне — ещё и единственное место для формата карты и языка */
  .menu-label {
    font-size: var(--fs-micro); font-weight: 600; letter-spacing: var(--tracking-caps);
    text-transform: uppercase; color: var(--muted); padding: 8px 10px 2px;
  }
  .menu-modes { display: flex; gap: 6px; padding: 2px 6px 6px; flex-wrap: wrap; }
  .menu-modes .chip { height: 34px; }
  .menu-sep { height: 1px; background: var(--line-soft); margin: 4px 2px; }
  /* на 3D и таймлайне шапка — «плеер»: остаются уведомления и меню */
  body[data-mtab="preview"] .topbar-actions > :not(#notif-menu):not(#menu-more),
  body[data-mtab="timeline"] .topbar-actions > :not(#notif-menu):not(#menu-more):not(#btn-save-top) { display: none; }

  .layout { display: block; height: auto; }
  .sidebar {
    border-right: none; border-bottom: 1px solid var(--line-soft);
    max-height: none; overflow: visible; padding: 12px 12px 132px;
  }
  /* десктопные вкладки видов заменены общими вкладками */
  .tabs { display: none; }

  /* ровно одна секция за раз: либо панель параметров, либо вид */
  .sidebar { display: none; }
  .sidebar > .panel { display: none; }
  .main { display: none; flex-direction: column; min-height: calc(100svh - 52px); }
  body[data-mtab="project"] #panel-project,
  body[data-mtab="rhythm"] #panel-rhythm,
  body[data-mtab="project"] .sidebar,
  body[data-mtab="rhythm"] .sidebar { display: block; }
  body[data-mtab="preview"] .main,
  body[data-mtab="timeline"] .main { display: flex; }

  /* легенда относится к полю: на вкладках параметров она мешает */
  body.mtab-params .legend { display: none; }

  .viewwrap { margin: 10px; border-radius: 0 10px 10px 10px; height: auto; flex: 1; min-height: 320px; }

  /* 3D — отдельный экран телефона: поле занимает ровно место между шапкой и
     панелью воспроизведения, страница не прокручивается. Высоты шапки, панели
     и легенды меряет main.js (--topbar-h/--transport-h/--legend-h): они
     переносятся по строкам и зависят от языка, поэтому «на глаз» не годятся.
     Легенда стоит отдельной строкой под полем, а не поверх нот. */
  body[data-mtab="preview"] .main {
    height: calc(100vh - var(--topbar-h, 52px));
    height: calc(100svh - var(--topbar-h, 52px));
    min-height: 0;
    overflow: hidden;
  }
  body[data-mtab="preview"] .viewwrap {
    flex: 1 1 auto;
    min-height: 120px;
    margin: 8px 10px calc(var(--transport-h, 128px) + var(--legend-h, 0px) + 8px);
  }
  /* На вкладках 3D и таймлайна шапка — компактный «плеер»: только бренд и вкладки.
     Сохранение, аккаунт, справка и выбор игры остаются на вкладке «Проект» — иначе на телефоне шапка
     занимает 225 из 844 px и у рабочей зоны остаётся меньше половины экрана. */
  body[data-mtab="preview"] .topbar,
  body[data-mtab="timeline"] .topbar { padding: 6px 10px; gap: 6px; }
  /* На этих вкладках в шапке остаётся только колокольчик уведомлений: ошибка
     выгрузки или генерации должна быть видна там, где работают, а не только на
     вкладке «Проект». Остальные кнопки шапки прячем по одной. */
  body[data-mtab="preview"] .topbar-actions > :not(#notif-menu),
  body[data-mtab="timeline"] .topbar-actions > :not(#notif-menu) { display: none; }
  body[data-mtab="preview"] .mtabs,
  body[data-mtab="timeline"] .mtabs { margin: 0; padding: 0; }

  /* Полоса воспроизведения на телефоне: два ряда (действия и шкала), вторичное —
     в раскрывающейся панели. Тач-цели не меньше 44 px. */
  .transport {
    flex-wrap: wrap; row-gap: 6px; gap: 8px;
    padding: 8px 10px calc(8px + env(safe-area-inset-bottom));
  }
  .transport .tr-group { flex-wrap: nowrap; }
  .transport .frag, .transport .tr-opts { display: none; }
  .transport .scrub-wrap { order: 9; flex-basis: 100%; }
  #btn-play { height: 44px; min-width: 104px; }
  #btn-play, #btn-stop, #tr-more { flex: none; }
  #tr-more { width: 40px; height: 40px; }
  .transport .time { min-width: 0; font-size: var(--fs-xs); }
  /* Раскрытая панель «ещё» висит НАД полосой: не сдвигает поле 3D и не
     перекрывает шкалу. */
  .transport.more-open .frag,
  .transport.more-open .tr-opts {
    display: flex; position: absolute; left: 8px; right: 8px; bottom: calc(100% + 6px);
    flex-direction: column; align-items: stretch; gap: 10px;
    padding: 12px; border: 1px solid var(--line); border-radius: var(--r-md);
    background: var(--surface-1); box-shadow: var(--shadow-3);
  }
  .transport.more-open .frag { flex-wrap: wrap; flex-direction: row; align-items: center; }
  .transport.more-open .tr-opts { padding-top: 10px; border-top: 1px solid var(--line-soft); }
  .transport .frag .tiny, .transport .tr-opts .row { min-height: 36px; }
  .transport input[type="range"] { height: 28px; }
  .transport label.check, .transport label.small { font-size: var(--fs-xs); }

  /* Легенда — одна прокручиваемая строка: двумя рядами она отнимала у поля 3D
     ещё 40 px. */
  .legend {
    flex-wrap: nowrap; overflow-x: auto; scrollbar-width: none; gap: 12px;
    max-width: calc(100vw - 20px); padding: 6px 10px;
  }
  .legend::-webkit-scrollbar { display: none; }

  /* На таймлайне контролы, специфичные только для 3D (руки игрока, калибровка задержки мс), скрыты */
  body[data-mtab="timeline"] .transport .preview-only { display: none !important; }

  /* шапка поля: на телефоне кнопки сверху отдельной строкой, показания — под
     ними. Раньше оба блока были absolute и на узком экране наезжали друг на
     друга (HUD «Время» прятался под выбором сложности). */
  .overlay-top { top: 8px; left: 8px; right: 8px; flex-direction: column; gap: 6px; }
  .overlay-right { order: -1; width: 100%; justify-content: space-between; flex-wrap: nowrap; gap: 4px; }
  .overlay-hud { font-size: 11px; }
  .overlay-right button { min-height: 36px; padding: 6px 8px; }
  .overlay-pick, .inline-pick { padding: 4px 8px; }
  .overlay-pick select, .inline-pick select { min-height: 34px; font-size: 13px; }
  /* «Камера: свободно» — самая длинная подпись; на телефоне она ужимается с
     многоточием, чтобы кнопка ⤾ не уезжала на вторую строку и не съедала поле */
  .overlay-right #btn-cam { flex: 0 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .overlay-right #btn-recenter { flex: 0 0 auto; }

  #timeline-canvas { height: clamp(180px, 30vh, 250px); border: 1px solid var(--line-soft); }
  #overview-canvas { height: 34px; margin-bottom: 4px; border: 1px solid var(--line-soft); }
  #waveform-canvas { height: 48px; margin-top: 4px; border: 1px solid var(--line-soft); }

  /* на телефоне панель воспроизведения закреплена внизу: она всегда под рукой,
     а поле может занимать всю оставшуюся высоту */
  .transport {
    position: fixed; left: 0; right: 0; bottom: 0; z-index: 15;
    flex-wrap: wrap; gap: 8px; row-gap: 6px; padding: 8px 10px;
    box-shadow: 0 -10px 26px rgba(0, 0, 0, 0.67);
  }
  /* высоту панели воспроизведения считает main.js: она переносится по строкам
     (в неё добавились фрагмент и его границы), поэтому место под неё — из переменной */
  .view.timeline-view {
    padding: 8px 8px calc(var(--transport-h, 110px) + 16px);
    overflow-x: hidden;
  }
  .timeline-view .tl-row-label { display: none; }
  .timeline-view .tl-help-text { display: none; }
  .timeline-view .tl-toolbar-row {
    gap: 5px;
    margin-bottom: 5px;
    flex-wrap: nowrap;
    align-items: center;
    width: 100%;
  }
  .timeline-view #tl-bar {
    flex-wrap: wrap;
    gap: 4px;
    margin-bottom: 6px;
  }
  /* Горизонтально прокручиваемые ряды инструментов и рук на мобильном */
  .timeline-view #tool-chips,
  .timeline-view #hand-chips,
  .timeline-view #wall-chips {
    display: flex;
    flex-wrap: nowrap;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
    gap: 5px;
    padding: 2px 1px;
    max-width: 100%;
    flex: 1 1 auto;
    min-width: 0;
  }
  .timeline-view #tool-chips::-webkit-scrollbar,
  .timeline-view #hand-chips::-webkit-scrollbar,
  .timeline-view #wall-chips::-webkit-scrollbar {
    display: none;
  }
  .timeline-view .chip {
    flex: 0 0 auto;
    padding: 6px 11px;
    font-size: 12px;
    min-height: 32px;
  }
  .timeline-view .inline-pick {
    padding: 2px 6px;
    min-height: 32px;
    flex: 0 0 auto;
  }
  .timeline-view .inline-pick select {
    min-height: 28px;
    font-size: 12px;
    padding: 2px 4px;
  }
  .timeline-view button.tiny {
    min-height: 32px;
    padding: 4px 7px;
    font-size: 11.5px;
  }
  .timeline-hint-accordion {
    margin: 6px 0;
    border: 1px solid var(--line-soft);
    border-radius: 8px;
    background: color-mix(in srgb, var(--bg-2) 40%, transparent);
    padding: 2px 8px;
  }
  .timeline-hint-accordion summary {
    padding: 6px 0;
    font-size: 11.5px;
    font-weight: 500;
  }
  .timeline-hint-accordion[open] summary {
    border-bottom: 1px solid var(--line-soft);
    margin-bottom: 6px;
  }
  .timeline-hint-accordion .hint {
    padding: 4px 0;
    font-size: 11px;
    line-height: 1.45;
  }
  #btn-delete-note {
    background: color-mix(in srgb, var(--red) 13%, transparent);
    border-color: color-mix(in srgb, var(--red) 47%, transparent);
    color: #ffc2c8;
    min-height: 34px;
    padding: 6px 12px;
    font-weight: 500;
  }
  #btn-delete-note:active {
    background: color-mix(in srgb, var(--red) 33%, transparent);
  }
  .transport .time { min-width: auto; font-size: 12px; }
  .transport .scrub-wrap { flex: 1 1 100%; order: 3; }
  .transport .frag { flex: 1 1 100%; order: 4; justify-content: space-between; }
  .transport button, .transport .ghost, .transport .primary { min-height: 40px; padding: 8px 14px; }
  /* Круглая стрелка «стандартное значение» стоит в панели воспроизведения (у
     ползунка скорости). Отступы кнопок плеера ей не нужны, но палец должен
     попадать — поэтому остаётся 34 px в круге, а не 20 px, как на десктопе. */
  .transport .range-reset { width: 34px; height: 34px; min-height: 34px; padding: 0; }
  /* Крестик и стрелка в панелях — тоже под палец: на телефоне они крупнее
     (в поле высотой 32 px крестик на 22 px ещё влезает), на десктопе — мелкие. */
  .input-clear { width: 22px; height: 22px; right: 4px; }
  .range-reset { width: 24px; height: 24px; }
  .transport label { font-size: 12px; }
  /* легенда тоже закреплена: поле на телефоне выше экрана, и «низ вида» уезжает
     за край — absolute-легенда оказалась бы под панелью воспроизведения */
  .legend {
    position: fixed; left: 10px; right: 10px; bottom: calc(var(--transport-h, 146px) + 8px); z-index: 14;
    /* одна строка с горизонтальной прокруткой: в две строки легенда отнимала у
       поля 3D ещё ~22 px на телефоне */
    flex-wrap: nowrap; overflow-x: auto; scrollbar-width: none; gap: 10px; font-size: 10.5px;
    padding: 5px 9px;
  }
  .legend::-webkit-scrollbar { display: none; }
  button, .chip, .tab, select, input[type="range"], .drop { touch-action: manipulation; }
  .chip { padding: 8px 12px; }
  .slider-row { grid-template-columns: 72px 1fr 40px; }
  .inspector { gap: 10px; padding: 10px; }
  .inspector .field { min-width: 92px; }
  .inspector .field input, .inspector .field select { width: 100%; min-width: 92px; }
  .pad { grid-template-columns: repeat(3, 30px); grid-template-rows: repeat(3, 30px); }
  pre.code { max-height: 240px; white-space: pre-wrap; word-break: break-word; }
  dialog { width: 96vw; max-height: 90vh; }
  dialog .dlg-body { max-height: 74vh; padding: 14px; }
  .toast { max-width: 88vw; }
}

@media (max-width: 560px) {
  .brand { font-size: 14px; }
  #engine-badge { display: none; }          /* место в шапке дороже: движок виден в панели «Ритм и карта» */
  .legend i { font-size: 10px; }
  .transport .time { font-size: 11.5px; }
  .topbar-actions .ghost { padding: 8px 10px; font-size: 12.5px; }
  /* На узком поле слово «Сложность» перед селектом дороже места, чем помогает:
     значение («Expert») и так читается, а подпись выдавливала кнопку камеры. */
  .overlay-pick > span { display: none; }
}

/* телефон в ландшафте: экран низкий, каждый пиксель по вертикали на счету */
@media (max-width: 900px) and (max-height: 520px) {
  .topbar { min-height: 44px; padding: 5px 10px; }
  .brand { font-size: 13.5px; }
  .mtabs { margin-top: 0; }
  .mtabs button { padding: 7px 12px; font-size: 12.5px; }
  .main { min-height: calc(100svh - 44px); }
  .viewwrap { min-height: 200px; margin: 8px; }
  .sidebar { padding-bottom: 112px; }
  .legend { bottom: calc(var(--transport-h, 104px) + 6px); font-size: 10px; }
  .overlay-hud { font-size: 10.5px; }
  .transport { padding: 6px 8px; }
  .transport button, .transport .ghost, .transport .primary { min-height: 34px; padding: 5px 12px; }
}

/* (Напоминания «поверните телефон» больше нет: поле подстраивается под портрет
   само — угол обзора считается от формы полотна, а камера крутится пальцем.) */

/* ── аккаунт и проекты ─────────────────────────────────────────────────── */
.proj-list { display: flex; flex-direction: column; gap: 6px; margin-top: 12px; min-width: min(560px, 78vw); max-height: 52vh; overflow: auto; }
.proj-row { display: flex; align-items: center; gap: 10px; padding: 9px 11px; border: 1px solid var(--line); border-radius: 10px; background: rgba(255,255,255,.02); }
.proj-row .grow { flex: 1; min-width: 0; }
.proj-row b { display: block; font-size: 13.5px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.proj-row .hint { margin: 0; }
.proj-row .empty { opacity: .6; }
.err { margin-top: 10px; padding: 8px 10px; border-radius: 8px; background: rgba(255,80,120,.12); border: 1px solid rgba(255,80,120,.35); color: #ffc2c8; font-size: 12.5px; }
button.danger { color: #ffc2c8; border-color: rgba(255,80,120,.35); }
dialog .chip { font-size: 12.5px; }
@media (max-width: 560px) {
  .proj-list { min-width: 0; width: 82vw; }
  .proj-row { flex-wrap: wrap; }
}

/* ─────────────────────────────── FAQ ───────────────────────────────
   Кнопка FAQ в шапке открывает #faq-dialog: как пользоваться сайтом, что он
   умеет и примеры. Разметка — обычные списки, поэтому кегль, маркеры и отступы
   задаются здесь, а не инлайном в шаблоне. */
dialog .faq { font-size: 13px; line-height: 1.55; }
dialog .faq p { margin: 0 0 10px; }
dialog .faq h3 { margin: 20px 0 8px; }
dialog .faq h3:first-of-type { margin-top: 12px; }
dialog .faq ol, dialog .faq ul { margin: 0 0 12px; padding-left: 22px; }
dialog .faq li { margin: 5px 0; }
/* Длинные пути и имена файлов в <code> не должны тянуть диалог вбок: переносим
   их, только когда иначе не влезает (на телефоне это заметно) */
dialog .faq code { overflow-wrap: anywhere; }
dialog .faq li > b:first-child { color: var(--text); }

/* «Первый раз: пять шагов» — вместо цифр списка кружки с номером */
.faq-steps { counter-reset: faq; list-style: none; padding-left: 0; }
.faq-steps > li { position: relative; padding-left: 30px; margin: 9px 0; }
.faq-steps > li::before {
  counter-increment: faq; content: counter(faq);
  position: absolute; left: 0; top: 1px; width: 20px; height: 20px; border-radius: 50%;
  display: grid; place-items: center; font-size: 11.5px; font-weight: 650;
  color: var(--accent-ink); background: var(--cyan);
}

/* Пример — цитата-условие над списком действий */
.faq-ex {
  margin: 0 0 8px; padding: 8px 11px; border-left: 3px solid var(--violet);
  background: color-mix(in srgb, var(--violet) 8%, transparent); border-radius: 0 8px 8px 0; color: var(--text);
}

/* «Что умеет» и «Частые вопросы» — маркер-точка вместо вложенных кружков */
.faq-list { list-style: none; padding-left: 0; }
.faq-list > li { position: relative; padding-left: 16px; }
.faq-list > li::before { content: '•'; position: absolute; left: 2px; color: var(--cyan); }

@media (max-width: 560px) {
  dialog .faq { font-size: 12.5px; }
  .faq-steps > li { padding-left: 26px; }
  .faq-steps > li::before { width: 18px; height: 18px; font-size: 11px; }
}

/* ─────────────────────── тумблер языка в шапке ───────────────────────
   Флаги — инлайновый SVG (эмодзи-флаги на Windows рисуются буквами), активный
   подсвечен, неактивный приглушён. Русский — по умолчанию. */
/* Режим (Synth Riders / Beat Saber): текстовые кнопки в той же капсуле, что флаги */
.mode-toggle {
  display: inline-flex; align-items: center; gap: 2px; padding: 3px;
  border: 1px solid var(--line); border-radius: 999px; background: var(--bg-2);
}
.mode-toggle button {
  padding: 4px 10px; border: 0; border-radius: 999px; background: none; cursor: pointer;
  font: inherit; font-size: 12px; color: var(--text-2); opacity: .5; transition: .14s;
}
.mode-toggle button[aria-pressed="true"] {
  opacity: 1; color: var(--text); background: color-mix(in srgb, var(--accent) 11%, transparent); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--accent) 33%, transparent);
}
.mode-toggle button:hover:not([aria-pressed="true"]) { opacity: .8; }
/* На телефоне шапка и так тесная: режим переключается вкладкой «Проект» */
@media (max-width: 760px) { .mode-toggle button { padding: 4px 7px; font-size: 11px; } }

.lang-toggle {
  display: inline-flex; align-items: center; gap: 2px; padding: 3px;
  border: 1px solid var(--line); border-radius: 999px; background: var(--bg-2);
}
.lang-toggle button {
  display: grid; place-items: center; padding: 3px 6px; border: 0; border-radius: 999px;
  background: none; cursor: pointer; opacity: .45; filter: saturate(.3); transition: .14s;
}
.lang-toggle button[aria-pressed="true"] {
  opacity: 1; filter: none; background: color-mix(in srgb, var(--accent) 11%, transparent); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--accent) 33%, transparent);
}
.lang-toggle button:hover { box-shadow: none; box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--accent) 33%, transparent); }
.lang-toggle button:hover:not([aria-pressed="true"]) { opacity: .8; filter: saturate(.7); box-shadow: none; }
.lang-toggle .flag { display: block; width: 21px; height: 14px; border-radius: 2.5px; box-shadow: 0 0 0 1px color-mix(in srgb, #ffffff 18%, transparent); }

/* ─────────────────── загрузка проекта на весь экран ───────────────────
   #loader (разметка — в src/index.template.html) закрывает сайт, пока проект
   открывается: «Мои проекты» или файл проекта. Выше тостов и меню, но НИЖЕ
   нативных <dialog> — они в top layer, поэтому вопрос пароля и окно входа
   остаются видны поверх загрузки. Кольцо, ядро и полоска анимируются только
   transform/opacity: CSS-анимации продолжают идти, даже когда главный поток
   занят декодированием звука (та же причина, что у .spin на кнопке сохранения). */
.loader {
  position: fixed; inset: 0; z-index: 90;
  display: grid; place-items: center; padding: 20px;
  background: radial-gradient(760px 520px at 50% 42%, color-mix(in srgb, var(--surface-1) 90%, transparent) 0%, color-mix(in srgb, var(--bg-inset) 98%, transparent) 68%), color-mix(in srgb, var(--bg-inset) 97%, transparent);
  backdrop-filter: blur(4px);
  animation: loader-fade .16s ease-out;
}
@keyframes loader-fade { from { opacity: 0 } }
.loader-box { display: grid; justify-items: center; gap: 16px; text-align: center; }

/* Внешняя дуга — циан, внутренняя — магента, крутятся в разные стороны,
   в центре пульсирует точка. */
.loader-ring { position: relative; width: 64px; height: 64px; animation: spin 1.1s linear infinite; }
.loader-ring::before, .loader-ring::after { content: ''; position: absolute; border-radius: 50%; }
.loader-ring::before { inset: 0; border: 3px solid color-mix(in srgb, #ffffff 7%, transparent); border-top-color: var(--cyan); border-right-color: color-mix(in srgb, var(--accent) 50%, transparent); }
.loader-ring::after { inset: 13px; border: 2.5px solid color-mix(in srgb, #ffffff 6%, transparent); border-bottom-color: var(--magenta); animation: spin 1.7s linear infinite reverse; }
.loader-core {
  position: absolute; inset: 25px; border-radius: 50%;
  background: var(--cyan); box-shadow: 0 0 16px color-mix(in srgb, var(--accent) 80%, transparent);
  animation: loader-pulse 1.5s ease-in-out infinite;
}
@keyframes loader-pulse { 0%, 100% { transform: scale(.62); opacity: .45 } 50% { transform: scale(1); opacity: 1 } }

.loader-title { font-size: 15.5px; font-weight: 600; letter-spacing: .2px; }
/* min-height — чтобы подпись этапа не дёргала кольцо, пока её нет */
.loader-stage { font-size: 12.5px; color: var(--muted); min-height: 18px; font-variant-numeric: tabular-nums; }

/* Полоска: без класса `.on` — «бегунок» (сколько ждать, неизвестно), с ним —
   заполнение по доле (сколько звука уже скачано), ширину ставит main.js. */
.loader-meter { width: min(240px, 62vw); height: 4px; border-radius: 999px; background: color-mix(in srgb, #ffffff 8%, transparent); overflow: hidden; }
.loader-meter > i {
  display: block; height: 100%; width: 34%; border-radius: 999px;
  background: linear-gradient(90deg, var(--cyan), var(--magenta));
  animation: loader-slide 1.15s ease-in-out infinite;
}
.loader-meter.on > i { animation: none; width: 0; transition: width .18s linear; }
@keyframes loader-slide { 0% { transform: translateX(-105%) } 100% { transform: translateX(300%) } }

@media (prefers-reduced-motion: reduce) {
  .loader-ring, .loader-ring::after { animation-duration: 2.6s; }
  .loader-core { animation: none; opacity: .9; }
  .loader-meter > i { animation-duration: 2.8s; }
}

/* Сид генерации: обычное текстовое поле рядом с «Другой вариант». Оформление —
   общее (как у всех полей), здесь только ширина и цифровая гарнитура: сид
   читают как число, а не как текст. */
.seed-row { display: inline-flex; align-items: center; gap: 8px; }
.seed-row > span { color: var(--muted); font-size: 11.5px; text-transform: uppercase; letter-spacing: .05em; }
.seed-row .input-wrap { width: 120px; flex: none; }
.seed-row input { width: 100%; font-variant-numeric: tabular-nums; }

/* ---------- Full Auto Mode ---------- */
.fa-topbar-btn {
  font-weight: 600;
  border-color: color-mix(in srgb, var(--accent) 27%, transparent);
  color: var(--cyan);
}
.fa-topbar-btn:disabled {
  opacity: .35;
  color: var(--muted);
  border-color: var(--line-soft);
  cursor: not-allowed;
  box-shadow: none;
}
.fa-topbar-btn.on {
  background: linear-gradient(135deg, color-mix(in srgb, var(--accent) 13%, transparent), color-mix(in srgb, var(--hand-right) 13%, transparent));
  border-color: var(--cyan);
  color: #fff;
  box-shadow: 0 0 10px color-mix(in srgb, var(--accent) 20%, transparent);
}

body.fullauto-active .layout {
  display: block;
  height: calc(100% - 56px);
  overflow-y: auto;
}
body.fullauto-active .sidebar,
body.fullauto-active .main {
  display: none !important;
}
body.fullauto-active #view-fullauto {
  display: block !important;
}

.fullauto-view {
  min-height: 100%;
  padding: 16px;
  background: var(--bg-inset);
}
.fa-container {
  max-width: 1240px;
  margin: 0 auto;
}
.fa-header-card {
  background: linear-gradient(135deg, var(--surface-1), var(--surface-2));
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 16px 20px;
  margin-bottom: 16px;
  box-shadow: 0 4px 20px rgba(0, 0, 0, 0.25);
}
.fa-title {
  margin: 0 0 var(--s-1);
  display: flex; align-items: center; gap: var(--s-2);
  font-size: var(--fs-2xl); font-weight: 650; line-height: var(--lh-tight);
  color: var(--text); letter-spacing: -.02em;
}
.fa-subtitle {
  margin: 0;
  color: var(--text-2);
  font-size: var(--fs-sm);
  line-height: 1.55;
  max-width: 76ch;
}
.fa-grid {
  display: grid;
  grid-template-columns: 1fr 380px;
  gap: 16px;
  align-items: start;
}
.fa-track-list {
  max-height: 520px;
  overflow-y: auto;
  border: 1px solid var(--line-soft);
  border-radius: 8px;
  background: color-mix(in srgb, var(--bg-2) 38%, transparent);
}
.fa-track-item {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 12px;
  border-bottom: 1px solid color-mix(in srgb, #ffffff 4%, transparent);
  transition: background .12s;
}
.fa-track-item:hover {
  background: color-mix(in srgb, #ffffff 3%, transparent);
}
.fa-track-item:last-child {
  border-bottom: 0;
}
.fa-track-cover {
  width: 40px;
  height: 40px;
  border-radius: 6px;
  background: var(--surface-2);
  object-fit: cover;
  flex: none;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 18px;
}
.fa-track-info {
  flex: 1;
  min-width: 0;
}
.fa-track-title {
  font-size: 13px;
  font-weight: 600;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  color: var(--fg);
}
.fa-track-artist {
  font-size: 11.5px;
  color: var(--muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.fa-track-status {
  font-size: 11px;
  border-radius: 999px;
  padding: 2px 8px;
  white-space: nowrap;
}
.fa-track-status.pending { color: var(--muted); background: color-mix(in srgb, #ffffff 5%, transparent); }
.fa-track-status.downloading { color: var(--cyan); background: color-mix(in srgb, var(--accent) 9%, transparent); }
.fa-track-status.analyzing { color: var(--amber); background: color-mix(in srgb, var(--amber) 9%, transparent); }
.fa-track-status.generating { color: var(--magenta); background: color-mix(in srgb, var(--hand-right) 9%, transparent); }
.fa-track-status.packaging { color: var(--cyan); background: color-mix(in srgb, var(--accent) 14%, transparent); }
.fa-track-status.done { color: var(--green); background: color-mix(in srgb, var(--green) 9%, transparent); font-weight: 600; }
.fa-track-status.error { color: var(--red); background: color-mix(in srgb, var(--red) 9%, transparent); }
.fa-track-delete {
  padding: 2px 7px;
  font-size: 11px;
  opacity: .5;
  border-radius: 6px;
  margin-left: 4px;
}
.fa-track-delete:hover {
  opacity: 1;
}
.fa-track-retry {
  padding: 2px 7px;
  font-size: 11px;
  border-radius: 6px;
  color: var(--amber);
  border-color: color-mix(in srgb, var(--amber) 27%, transparent);
  margin-left: 4px;
}
.fa-track-retry:hover {
  background: color-mix(in srgb, var(--amber) 13%, transparent);
  border-color: var(--amber);
  color: #fff;
}
.fa-track-play {
  padding: 3px 8px;
  font-size: 11px;
  border-radius: 6px;
  color: var(--cyan);
  border-color: color-mix(in srgb, var(--accent) 20%, transparent);
  flex: none;
  min-width: 28px;
  text-align: center;
}
.fa-track-play:hover, .fa-track-play.active {
  background: color-mix(in srgb, var(--accent) 13%, transparent);
  border-color: var(--cyan);
  color: #fff;
}

@media (max-width: 900px) {
  .fa-grid {
    grid-template-columns: 1fr;
  }
}

/* ====================== регистрация по почте, подарок, гость ======================
   Три блока, добавленные вместе с регистрацией по e-mail (2026-10-20):
   плашка-оффер гостю, замок на вкладке «Ритм и карта» и поля почты/капчи в
   диалоге входа. Все цвета — из токенов, чтобы не завести второй акцент. */

/* Оффер вверху страницы. Живёт НАД контентом, но ниже шапки: у шапки свои
   выпадающие меню (колокольчик, «⋯»), и перекрывать их нельзя. */
.trial-banner {
  /* Низкий слой: плашка — часть страницы, а не всплывающий слой. С z-index
     шапки (40) она перекрывала выпадающее меню колокольчика. */
  position: relative;
  z-index: 1;
  display: flex;
  align-items: center;
  gap: var(--s-3);
  margin: 8px 12px 0;
  padding: 9px 14px;
  border: 1px solid var(--accent-line);
  border-radius: var(--r-md);
  background:
    linear-gradient(90deg, color-mix(in srgb, var(--accent) 12%, var(--surface-2)), var(--surface-1) 65%);
  color: var(--text);
  font-size: var(--fs-sm);
  line-height: 1.4;
}
.trial-banner[hidden] { display: none; }
.trial-banner > .ic { color: var(--accent); width: 20px; height: 20px; }
.trial-banner-text { flex: 1 1 auto; min-width: 0; }
.trial-banner-text b { color: var(--text); font-weight: 650; }
.trial-banner-actions { display: flex; align-items: center; gap: 6px; flex: 0 0 auto; }
.trial-banner-actions .icon { width: 28px; height: 28px; border-color: transparent; background: transparent; color: var(--muted); }
.trial-banner-actions .icon:hover:not(:disabled) { background: rgba(255, 255, 255, .07); border-color: transparent; color: var(--text); }

/* Замок на «Ритме и карте» для гостя. Это не disabled-панель: кнопка входа
   обязана быть кликабельной, поэтому панель у гостя НЕ получает `.disabled`. */
.rhythm-auth-lock {
  margin-top: var(--s-3);
  padding: 22px 12px 18px;
  text-align: center;
  border: 1px dashed var(--line);
  border-radius: var(--r-md);
  background: color-mix(in srgb, var(--surface-2) 55%, transparent);
}
.rhythm-auth-lock[hidden] { display: none; }
.rhythm-auth-lock-icon {
  width: 52px; height: 52px; margin: 0 auto 10px;
  display: flex; align-items: center; justify-content: center;
  border-radius: 50%;
  background: var(--accent-soft);
  color: var(--accent);
  border: 1px solid var(--accent-line);
}
.rhythm-auth-lock-icon .ic { width: 24px; height: 24px; }
.rhythm-auth-lock h3 {
  margin: 0 0 8px;
  padding: 0;
  border: 0;
  font-size: var(--fs-md);
  letter-spacing: 0;
  text-transform: none;
  color: var(--text);
}
.rhythm-auth-lock p {
  margin: 0 0 14px;
  color: var(--text-2);
  font-size: var(--fs-sm);
  line-height: 1.55;
}
.rhythm-auth-lock p.hint { margin: 12px 0 0; color: var(--muted); font-size: var(--fs-xs); }
.rhythm-auth-lock .primary.wide { width: 100%; justify-content: center; }

/* Поля регистрации */
.field-label {
  display: block;
  font-size: var(--fs-xs);
  color: var(--muted);
  margin-bottom: 5px;
}
.auth-captcha-row { display: flex; align-items: center; gap: var(--s-2); }
.auth-captcha-img {
  width: 200px; height: 64px;
  border-radius: var(--r-sm);
  border: 1px solid var(--line-soft);
  background: var(--bg-inset);
  object-fit: cover;
  flex: 0 0 auto;
}
.auth-captcha-row .icon { width: 32px; height: 32px; }
.auth-captcha-input {
  width: 100%;
  margin-top: 6px;
  padding: 9px 11px;
  border-radius: var(--r-sm);
  border: 1px solid var(--line);
  background: var(--surface-2);
  color: var(--text);
  font-family: var(--font-mono);
  font-size: var(--fs-md);
  letter-spacing: .18em;
  text-transform: uppercase;
}
.auth-captcha-input:focus-visible { border-color: var(--accent); outline: none; box-shadow: 0 0 0 3px var(--accent-soft); }

/* «Проверьте почту» вместо формы */
.auth-pending { padding: 6px 0 2px; text-align: center; }
.auth-pending[hidden] { display: none; }
.auth-pending-icon {
  width: 44px; height: 44px; margin: 0 auto 8px;
  display: flex; align-items: center; justify-content: center;
  border-radius: 50%;
  background: var(--accent-soft);
  color: var(--accent);
  border: 1px solid var(--accent-line);
}
.auth-pending-icon .ic { width: 21px; height: 21px; }
.auth-pending b { font-size: var(--fs-md); }
.auth-pending p { margin: 8px 0 12px; color: var(--text-2); font-size: var(--fs-sm); line-height: 1.55; }
.auth-pending p b { color: var(--text); }

/* Диалог подарка после подтверждения */
.trial-dialog-icon {
  width: 64px; height: 64px; margin: 6px auto 12px;
  display: flex; align-items: center; justify-content: center;
  border-radius: 50%;
  background: radial-gradient(circle at 35% 30%, color-mix(in srgb, var(--accent) 30%, transparent), var(--surface-2));
  color: var(--accent);
  border: 1px solid var(--accent-line);
  box-shadow: 0 8px 30px -12px var(--accent);
}
.trial-dialog-icon .ic { width: 30px; height: 30px; }
.trial-dialog-title { margin: 0 0 6px; font-size: var(--fs-2xl); letter-spacing: -.01em; }
.trial-dialog-text { margin: 12px 0 18px; color: var(--text-2); font-size: var(--fs-sm); line-height: 1.55; }
#trial-dialog, #auth-dialog { max-height: calc(100vh - 28px); overflow: auto; }

@media (max-width: 900px) {
  .trial-banner {
    margin: 6px 8px 0;
    padding: 8px 10px;
    gap: 8px;
    flex-wrap: wrap;
    font-size: var(--fs-xs);
  }
  .trial-banner > .ic { order: 1; width: 18px; height: 18px; }
  .trial-banner-text { order: 2; flex: 1 1 calc(100% - 30px); }
  .trial-banner-actions { order: 3; flex: 1 1 100%; justify-content: flex-end; }
  .trial-banner-actions .icon { margin-left: auto; }
  .auth-captcha-img { width: 168px; height: 54px; }
  .rhythm-auth-lock { padding: 18px 8px 14px; }
}

/* «Подтвердите почту» — не реклама, а напоминание: та же плашка, но янтарная. */
.verify-banner {
  border-color: color-mix(in srgb, var(--amber) 45%, transparent);
  background: linear-gradient(90deg, color-mix(in srgb, var(--amber) 13%, var(--surface-2)), var(--surface-1) 65%);
}
.verify-banner > .ic { color: var(--amber); }
