/* ============================================================================
   arambolsu-ai — единый источник правды по дизайн-токенам.
   Правила и обоснования: docs/BRANDBOOK_ARAMBOLSU_RU.md
   План внедрения:        docs/TZ_DESIGN_IMPLEMENTATION_RU.md

   Этот файл подключается ПЕРВЫМ на каждом экране семьи — и на тех, что живут
   на style.css, и на «сиротских» шаблонах с собственной вёрсткой. Он не задаёт
   компонентов, только словарь: цвет, отступ, радиус, слой, движение — плюс
   слой взаимодействия (четыре состояния одним списком) и перекат разрядов.

   Тема по умолчанию светлая: публичный сайт, портал, travel и основной
   style.css светлые. Экраны, тёмные по замыслу (админка, терминал, монитор,
   студии, IDE), ставят <html data-theme="dark"> — палитра переворачивается,
   имена токенов не меняются.

   Что здесь запрещено: градиенты, свечение, transition:all, z-index вне шкалы,
   литеральный цвет вне :root.
   ========================================================================= */

:root {
  color-scheme: light dark;

  /* ── Нейтральная шкала ────────────────────────────────────────────────────
     Одна температура (холодный серый), без чистого чёрного и чистого белого:
     #000 на #fff читается как незаконченная вёрстка. Двенадцать ступеней —
     потолок, новая ступень не заводится, значение округляется к ближайшей. */
  --n-950: #0e1014;
  --n-900: #14171c;
  --n-850: #191d23;
  --n-800: #1e222a;
  --n-700: #272c36;
  --n-600: #343a46;
  --n-500: #4b525f;
  --n-400: #6b7382;
  --n-300: #8b93a2;
  --n-200: #b6bcc7;
  --n-100: #dcdfe6;
  --n-050: #f2f3f6;

  /* ── Поверхности: по «поднятости», а не по имени экрана ─────────────────── */
  --bg: #f3f6f8;
  --surface: #fbfcfd;
  --surface-2: #f1f3f6;
  --surface-3: #e8ebf0;
  --border: #d5dae3;
  --border-strong: #b2bac8;

  /* ── Текст ─────────────────────────────────────────────────────────────── */
  --text: #18212b;
  --text-soft: #3a4150;
  --muted: #5c6b7a;
  --text-faint: #828b9b;
  --on-accent: #ffffff;

  /* ── Акцент — один на всю семью ──────────────────────────────────────────
     Бирюза из логотипа и из meta theme-color. Производные: заливка, нажатая,
     подложка, контур. Новый акцент не заводится. */
  /* #2f8f82 — брендовая бирюза. Как ТЕКСТ на светлых поверхностях она даёт
     3.5–3.8:1, то есть ниже 4.5:1, поэтому --accent затемнён до читаемого
     оттенка той же бирюзы; заливка кнопки (--accent-2) и нажатая
     (--accent-press) остались светлее — на них текст белый. Значения
     подобраны расчётом контраста, включая собственные подложки. */
  --accent: #257066;
  --accent-2: #2a7f74;
  --accent-press: #236a61;
  --accent-fg: var(--on-accent);
  --accent-soft: rgba(37, 112, 102, 0.12);
  --accent-line: rgba(37, 112, 102, 0.34);

  /* Вторичный — только для связок «ссылка/иллюстрация», не как второй бренд */
  --accent-alt: #3a689f;

  /* ── Семантика: смысл, а не украшение ──────────────────────────────────── */
  --ok: #1d7350;
  --ok-soft: rgba(29, 115, 80, 0.12);
  --ok-line: rgba(29, 115, 80, 0.34);
  --warn: #8a5200;
  --warn-soft: rgba(138, 82, 0, 0.12);
  --warn-line: rgba(138, 82, 0, 0.3);
  --danger: #b3261e;
  --danger-soft: rgba(179, 38, 30, 0.1);
  --danger-line: rgba(179, 38, 30, 0.32);
  --info: var(--accent-alt);
  --info-soft: rgba(58, 104, 159, 0.12);
  --info-line: rgba(58, 104, 159, 0.32);

  /* Подложка под диалогом — одна на продукт */
  --scrim: rgba(14, 16, 20, 0.55);

  /* ── Биржевая свеча — единственное разрешённое исключение из акцента.
     «Рост/падение» — отраслевая конвенция, понятная трейдеру без подписи.
     Живёт токеном, а не литералом, и вне терминала не используется. */
  /* Зелёный биржи на СВЕТЛОМ фоне давал 1.96:1 — цифру было не прочесть.
     Конвенция «рост/падение» сохранена, оттенок доведён до различимого;
     в тёмной теме ниже возвращается привычный биржевой зелёный. */
  --mkt-up: #0ba267;
  --mkt-down: #d92c42;
  --mkt-up-soft: rgba(11, 162, 103, 0.12);
  --mkt-down-soft: rgba(217, 44, 66, 0.12);

  /* ── Шкала отступов, 4px ───────────────────────────────────────────────── */
  --s1: 4px;
  --s2: 8px;
  --s3: 12px;
  --s4: 16px;
  --s5: 20px;
  --s6: 24px;
  --s7: 32px;
  --s8: 40px;
  --s9: 56px;

  /* ── Пять радиусов. Новый не заводится — округляется к ближайшему. ─────── */
  --r-sm: 8px;
  --r-md: 10px;
  --r-lg: 14px;
  --r-xl: 18px;
  --r-full: 999px;

  /* ── Типографика: шесть размеров — потолок ─────────────────────────────── */
  --font: -apple-system, BlinkMacSystemFont, "Segoe UI", Inter, Roboto,
    "Helvetica Neue", sans-serif;
  --font-display: "Manrope", "Avenir Next", "Segoe UI", var(--font);
  --mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
  --t-xs: 11px;
  --t-sm: 13px;
  --t-md: 15px;
  --t-lg: 18px;
  --t-xl: 22px;
  --t-2xl: 28px;
  --lh-tight: 1.25;
  --lh-body: 1.55;
  --measure: 72ch; /* ширина текстовой колонки */

  /* ── Элевация: либо граница, либо тень, никогда одновременно.
     Структура (карточки, панели, таблицы) — волосяная граница.
     «Летающее» (меню, диалоги, тосты) — мягкая тень. */
  --e1: 0 1px 2px rgba(20, 24, 33, 0.07);
  --e2: 0 4px 12px rgba(20, 24, 33, 0.1), 0 1px 2px rgba(20, 24, 33, 0.06);
  --e3: 0 16px 40px rgba(20, 24, 33, 0.16), 0 2px 8px rgba(20, 24, 33, 0.08);

  /* ── Движение: «Отклик + Механика» ───────────────────────────────────────
     Появление не двигается. Двигается прикосновение и число, которое
     изменилось. Три длительности — потолок. */
  --dur-1: 120ms;
  --dur-2: 180ms;
  --dur-3: 220ms;
  --ease-out: cubic-bezier(0.22, 0.68, 0.42, 1);
  --ease-in: cubic-bezier(0.55, 0.06, 0.68, 0.19);

  --dur-tap: 150ms; /* наведение, фокус, нажатие */
  --ease-tap: cubic-bezier(0.34, 1.3, 0.64, 1); /* короткий перелёт */
  --lift: 2px; /* подъём карточки при наведении */
  --press: 0.97; /* сжатие при нажатии — одно на всю семью */
  --ring: 2px; /* толщина кольца фокуса */
  --ring-offset: 2px;
  --dur-roll: 420ms; /* «Механика»: перекат разряда */
  --ease-roll: cubic-bezier(0.2, 0.9, 0.3, 1);
  --roll-step: 60ms; /* сдвиг между соседними разрядами */

  --tap-min: 44px; /* минимальная цель нажатия */

  /* ── Слои — единственная шкала z-index в проекте ─────────────────────────
     Компонент, который слоится внутри себя, получает isolation:isolate
     и локальные 1, 2, 3 — а не новое значение здесь. */
  --z-sticky: 10;
  --z-drawer: 40;
  --z-popover: 60;
  --z-modal: 80;
  --z-toast: 100;

  --safe-top: env(safe-area-inset-top, 0px);
  --safe-bottom: env(safe-area-inset-bottom, 0px);
  --safe-left: env(safe-area-inset-left, 0px);
  --safe-right: env(safe-area-inset-right, 0px);

  /* ── Совместимость со старой разметкой ───────────────────────────────────
     Шаблоны и старые CSS ссылаются на эти имена. Они больше не самостоятельные
     значения, а синонимы шкалы: один источник правды сохраняется, разметку
     переписывать не нужно. Новый код берёт имена выше. */
  --panel: var(--surface);
  --panel-2: var(--surface-2);
  --card: var(--surface);
  --line: var(--border);
  --ink: var(--text);
  --mut: var(--muted);
  --text2: var(--text-soft);
  --surface2: var(--surface-2);
  --acc: var(--accent);
  --acc2: var(--accent-alt);
  --accent-hover: var(--accent-2);
  --success: var(--ok);
  --warning: var(--warn);
  --green: var(--ok);
  --red: var(--danger);
  --orange: var(--warn);
  --warn-bg: var(--warn-soft);
  --danger-bg: var(--danger-soft);
  --radius: var(--r-lg);
  --radius-sm: var(--r-sm);
  --shadow: var(--e2);
  --code-bg: var(--surface-2);
}

/* ── Тёмная тема ────────────────────────────────────────────────────────────
   Два входа: системная настройка и явный data-theme="dark". Переопределяются
   только значения, имена те же. Токены, не перечисленные здесь, наследуются
   из :root намеренно — шкала отступов и радиусов от темы не зависит. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    color-scheme: dark;

    --bg: var(--n-950);
    --surface: var(--n-900);
    --surface-2: var(--n-850);
    --surface-3: var(--n-800);
    --border: var(--n-600);
    --border-strong: var(--n-500);

    --text: #e8eaf0;
    --text-soft: var(--n-200);
    --muted: var(--n-300);
    --text-faint: var(--n-400);

    --accent: #4db8a8;
    --accent-2: #3fa294;
    --accent-press: #3d968a;
    --accent-soft: rgba(77, 184, 168, 0.14);
    --accent-line: rgba(77, 184, 168, 0.34);
    --accent-alt: #7aa8d9;
    --on-accent: #08201d;

    --ok: #46c08b;
    --ok-soft: rgba(70, 192, 139, 0.14);
    --ok-line: rgba(70, 192, 139, 0.34);
    --warn: #e5a44c;
    --warn-soft: rgba(229, 164, 76, 0.14);
    --warn-line: rgba(229, 164, 76, 0.32);
    --danger: #e46a70;
    --danger-soft: rgba(228, 106, 112, 0.14);
    --danger-line: rgba(228, 106, 112, 0.38);
    --info-soft: rgba(122, 168, 217, 0.14);
    --info-line: rgba(122, 168, 217, 0.32);

    --e1: 0 1px 2px rgba(0, 0, 0, 0.28);
    --e2: 0 4px 12px rgba(0, 0, 0, 0.32), 0 1px 2px rgba(0, 0, 0, 0.24);
    --e3: 0 16px 40px rgba(0, 0, 0, 0.44), 0 2px 8px rgba(0, 0, 0, 0.28);

    --code-bg: #0a0c10;

  /* Свеча: на тёмном фоне читается привычный биржевой зелёный/красный */
  --mkt-up: #0ecb81;
  --mkt-down: #f6465d;
  --mkt-up-soft: rgba(14, 203, 129, 0.14);
  --mkt-down-soft: rgba(246, 70, 93, 0.14);
  }
}

:root[data-theme="dark"] {
  color-scheme: dark;

  --bg: var(--n-950);
  --surface: var(--n-900);
  --surface-2: var(--n-850);
  --surface-3: var(--n-800);
  --border: var(--n-600);
  --border-strong: var(--n-500);

  --text: #e8eaf0;
  --text-soft: var(--n-200);
  --muted: var(--n-300);
  --text-faint: var(--n-400);

  --accent: #4db8a8;
  --accent-2: #3fa294;
  --accent-press: #3d968a;
  --accent-soft: rgba(77, 184, 168, 0.14);
  --accent-line: rgba(77, 184, 168, 0.34);
  --accent-alt: #7aa8d9;
  --on-accent: #08201d;

  --ok: #46c08b;
  --ok-soft: rgba(70, 192, 139, 0.14);
  --ok-line: rgba(70, 192, 139, 0.34);
  --warn: #e5a44c;
  --warn-soft: rgba(229, 164, 76, 0.14);
  --warn-line: rgba(229, 164, 76, 0.32);
  --danger: #e46a70;
  --danger-soft: rgba(228, 106, 112, 0.14);
  --danger-line: rgba(228, 106, 112, 0.38);
  --info-soft: rgba(122, 168, 217, 0.14);
  --info-line: rgba(122, 168, 217, 0.32);

  --e1: 0 1px 2px rgba(0, 0, 0, 0.28);
  --e2: 0 4px 12px rgba(0, 0, 0, 0.32), 0 1px 2px rgba(0, 0, 0, 0.24);
  --e3: 0 16px 40px rgba(0, 0, 0, 0.44), 0 2px 8px rgba(0, 0, 0, 0.28);

  --code-bg: #0a0c10;

  /* Свеча: на тёмном фоне читается привычный биржевой зелёный/красный */
  --mkt-up: #0ecb81;
  --mkt-down: #f6465d;
  --mkt-up-soft: rgba(14, 203, 129, 0.14);
  --mkt-down-soft: rgba(246, 70, 93, 0.14);
}

/* ── Слой взаимодействия ────────────────────────────────────────────────────
   Четыре состояния заданы здесь один раз списком. Новый control достаточно
   вписать в список — и он получает поведение целиком, вместо того чтобы
   каждый раз дописывать :hover руками.

   Специфичность подобрана намеренно: :is() берёт вес самого «тяжёлого»
   аргумента (класс), поэтому кольцо фокуса весит (0,2,0) и переживает любое
   однокласcовое правило. :where() здесь весил бы ноль и не сработал.
   ───────────────────────────────────────────────────────────────────────── */

/* Единый список интерактивных элементов семьи.
   Порядок групп: примитивы → общий интерфейс → публичный сайт → студии,
   биржа, админка, монитор. */
:is(
    button, a, input, select, textarea, summary, [tabindex], [role="button"],
    [role="tab"], [role="link"],
    .btn, .button, .chip, .tab, .tab-btn, .seg-btn, .nav-item, .menu-btn,
    .icon-btn, .card-action, .pill, .toggle, .switch,
    .ps-cta, .ps-nav-link, .ps-nav-burger, .ps-teaser__cta, .ps-card,
    .rd-tab, .rd-subtab, .rd-btn,
    .studio-card, .asset-card, .model-card, .preset-card, .plan-card,
    .mkt-row, .mkt-tf, .sym-row, .hub-card, .doc-nav a, .adm-tab, .mon-card
  ):focus-visible {
  /* Кольцо фокуса одно на весь продукт. Радиус ему не задаём: outline сам
     повторяет border-radius элемента, жёсткое значение квадратило бы chip. */
  outline: var(--ring) solid var(--accent);
  outline-offset: var(--ring-offset);
}

/* Нажатие — единое сжатие вместо разнобоя из translateY и scale */
:is(
    button, [role="button"],
    .btn, .button, .chip, .tab, .tab-btn, .seg-btn, .nav-item, .menu-btn,
    .icon-btn, .card-action, .pill,
    .ps-cta, .rd-tab, .rd-subtab, .rd-btn,
    .studio-card, .asset-card, .model-card, .preset-card, .plan-card,
    .mkt-tf, .adm-tab
  ):not(:disabled, [aria-disabled="true"]):active {
  transform: scale(var(--press));
}

/* Наведение на «карточные» элементы — один подъём вместо четырёх */
:is(
    .studio-card, .asset-card, .model-card, .preset-card, .plan-card,
    .ps-card, .hub-card, .mon-card
  ):hover {
  transform: translateY(calc(-1 * var(--lift)));
}

/* Недоступно — одно правило на весь продукт, без движения */
:is(
    button, [role="button"], .btn, .button, .chip, .tab, .tab-btn, .seg-btn,
    .nav-item, .icon-btn, .ps-cta, .rd-btn, .studio-card, .model-card
  ):is(:disabled, [aria-disabled="true"]),
:is(input, select, textarea):disabled {
  opacity: 0.45;
  cursor: not-allowed;
  transform: none;
}
:is(button, [role="button"], .btn, .chip, .icon-btn, .ps-cta):is(
    :disabled,
    [aria-disabled="true"]
  ):hover {
  transform: none;
}

/* Общий переход. transform — с перелётом, цвет — без: цветовой отскок
   читается как дребезг. Свойства всегда перечисляются поимённо. */
:is(
    button, a, summary, [role="button"],
    .btn, .button, .chip, .tab, .tab-btn, .seg-btn, .nav-item, .menu-btn,
    .icon-btn, .card-action, .pill,
    .ps-cta, .ps-nav-link, .ps-teaser__cta, .ps-card,
    .rd-tab, .rd-subtab, .rd-btn,
    .studio-card, .asset-card, .model-card, .preset-card, .plan-card,
    .hub-card, .mon-card, .adm-tab,
    input, select, textarea
  ) {
  transition: background-color var(--dur-tap) var(--ease-out),
    border-color var(--dur-tap) var(--ease-out),
    color var(--dur-tap) var(--ease-out),
    box-shadow var(--dur-tap) var(--ease-out),
    transform var(--dur-tap) var(--ease-tap);
}

/* Цель нажатия на сенсорном экране */
@media (pointer: coarse) {
  :is(button, [role="button"], .btn, .icon-btn, .ps-cta, .tab, .nav-item) {
    min-height: var(--tap-min);
  }
}

/* ── Числа ──────────────────────────────────────────────────────────────────
   Любое число, которое пользователь читает как данные, набирается
   моноширинными цифрами: иначе колонка дёргается при каждом обновлении,
   а в таблице разряды не встают друг под друга. */
.num,
.price,
.qty,
.quota,
.balance,
.pct,
.money,
.metric,
.count,
.stat-value,
.odo,
[data-num],
td.num,
th.num,
table.data td,
table.numeric td,
/* Дашборды: карточки метрик, бейджи ёмкости, строки телеметрии */
.stat-card .value,
.stats-grid .value,
.stat,
.stats,
.badge-gpu,
.badge-cpu,
.mt-stat-row strong,
.res-row b,
.rd-num,
code,
kbd,
samp {
  font-variant-numeric: tabular-nums;
}

/* ── «Механика»: перекат разрядов ───────────────────────────────────────────
   Единственное место, где движение обслуживает данные, а не жест. Катится
   ТОЛЬКО при реальной смене значения — static/js/odometer.js следит за этим
   сам, на первую отрисовку перекат не запускается. Не обходите это. */
.odo {
  display: inline-flex;
  font-variant-numeric: tabular-nums;
  line-height: inherit;
}
.odo .odo-sep {
  width: 0.28em;
  flex: 0 0 auto;
}
.odo .odo-d {
  display: inline-block;
  height: 1.15em;
  overflow: hidden;
  vertical-align: bottom;
}
.odo .odo-d i {
  display: block;
  font-style: normal;
  transform: translateY(0);
}
.odo.rolling .odo-d i {
  transition: transform var(--dur-roll) var(--ease-roll);
}
.odo .odo-d b {
  display: block;
  height: 1.15em;
  line-height: 1.15;
  font-weight: inherit;
}

/* ── Загрузка / пустота / ошибка ────────────────────────────────────────────
   Скелет структуры вместо надписи «Загружаем…»: человек должен видеть, что
   появится. Пустота объясняет, почему пусто и что сделать. Ошибка — простым
   языком, с выходом; техническая подробность прячется под «Подробности». */
.skeleton {
  position: relative;
  overflow: hidden;
  background: var(--surface-2);
  border-radius: var(--r-sm);
  color: transparent;
  user-select: none;
}
.skeleton::after {
  content: "";
  position: absolute;
  inset: 0;
  background: var(--surface-3);
  opacity: 0;
  animation: skeleton-pulse 1.4s var(--ease-out) infinite;
}
@keyframes skeleton-pulse {
  0%,
  100% {
    opacity: 0;
  }
  50% {
    opacity: 1;
  }
}
.skeleton-line {
  height: 1em;
  margin-bottom: var(--s2);
}
.skeleton-line:last-child {
  width: 60%;
  margin-bottom: 0;
}

.state-empty,
.state-error,
.state-loading {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--s2);
  padding: var(--s7) var(--s4);
  text-align: center;
  color: var(--muted);
  font-size: var(--t-sm);
  line-height: var(--lh-body);
}
.state-empty__title,
.state-error__title {
  color: var(--text);
  font-size: var(--t-md);
  font-weight: 600;
}
.state-error {
  color: var(--danger);
}
.state-error__title {
  color: var(--danger);
}
.state-error details {
  margin-top: var(--s2);
  color: var(--muted);
  text-align: left;
  max-width: var(--measure);
}
.state-error details summary {
  cursor: pointer;
  color: var(--muted);
  font-size: var(--t-xs);
}
.state-error details pre {
  margin-top: var(--s1);
  padding: var(--s2);
  background: var(--code-bg);
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  font-family: var(--mono);
  font-size: var(--t-xs);
  white-space: pre-wrap;
  word-break: break-word;
  overflow-x: auto;
}

/* Ссылка «пропустить к содержимому» — первая цель таба на любой странице */
.skip-link {
  position: absolute;
  left: var(--s2);
  top: calc(-1 * var(--s9));
  z-index: var(--z-toast);
  padding: var(--s2) var(--s3);
  border-radius: var(--r-sm);
  background: var(--surface);
  border: 1px solid var(--border-strong);
  color: var(--text);
  font-size: var(--t-sm);
  transition: top var(--dur-tap) var(--ease-out);
}
.skip-link:focus-visible {
  top: var(--s2);
}

/* Видно только программе чтения с экрана */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* ── Сокращённое движение ───────────────────────────────────────────────────
   Сокращённый режим даёт РАБОЧИЙ экран, а не сломанный: конечные состояния на
   месте, перекат не запускается, бесконечные анимации остановлены. Для части
   людей непрерывное движение на экране физически некомфортно. */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
  .odo.rolling .odo-d i {
    transition: none !important;
  }
  .skeleton::after {
    animation: none !important;
    opacity: 0.5;
  }
  :is(button, .btn, .chip, .studio-card, .model-card, .ps-card):hover,
  :is(button, .btn, .chip):active {
    transform: none !important;
  }
}
