/* F440 — базовые компоненты дизайн-системы.
   Источник: «Дизайн-система - F440.dc.html», §06, §09, §09а, §18, §21.
   Значения берутся только из tokens.css: литералов здесь быть не должно. */

/* ── Основа ──────────────────────────────────────────────────── */

.icon { display: block; flex-shrink: 0 }

/* Фокус — всегда обводкой, никогда только цветом фона. Одно кольцо
   на весь продукт: 2 px акцентом через 2 px зазора. */
.focus-ring:focus-visible,
.btn:focus-visible,
.icon-btn:focus-visible,
.chip:focus-visible,
.set-row:focus-visible,
.field:focus-visible {
  outline: var(--focus-w) solid var(--accent-hi);
  outline-offset: var(--focus-offset);
}
/* Switch и слайдер обводкой обойтись не могут: у них скруглённая
   форма и своя геометрия, кольцо рисуется тенью в два слоя. */
.switch:focus-visible,
.slider:focus-visible {
  outline: none;
  box-shadow: 0 0 0 2px var(--bg), 0 0 0 4px var(--accent-hi);
}

/* ── §06 Кнопка: 3 варианта × 5 состояний ────────────────────────
   Заливка зелёным зарезервирована за нажатием и за воспроизведением:
   в покое основная кнопка — контур с подложкой, иначе на экране
   тренажёра два зелёных пятна конкурируют за внимание с графиком. */

.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 9px;
  min-height: var(--tap-min);
  padding: 12px 20px;
  border-radius: var(--r);
  border: 1px solid var(--line);
  background: transparent;
  color: var(--text);
  font-family: inherit; font-size: 14px; font-weight: 500;
  cursor: pointer;
  transition: background var(--t-press) var(--ease),
              border-color var(--t-press) var(--ease),
              color var(--t-press) var(--ease);
}

.btn--primary { border-color: var(--accent-hi); background: var(--accent-wash); color: var(--accent-ink) }
.btn--ghost   { border-color: var(--line); background: transparent; color: var(--text) }
.btn--quiet   { border-color: var(--line); background: transparent; color: var(--muted) }
/* Заливка целиком — только там, где кнопка и есть подтверждение:
   «Повторить» в отказе размера XL, «Отдать в нарезку». */
.btn--solid   { border-color: var(--accent); background: var(--accent-deep); color: var(--on-accent); font-weight: 600 }

/* Наведение существует только на мыши; на тач-устройствах его роль
   берёт нажатие. Эмулировать hover на телефоне нельзя. */
@media (hover: hover) {
  .btn--primary:hover:not(:disabled) { border-color: var(--accent-hover); background: var(--accent-wash-2); color: var(--accent-hover) }
  .btn--ghost:hover:not(:disabled),
  .btn--quiet:hover:not(:disabled)   { border-color: var(--line-2); background: var(--panel-2); color: var(--text) }
  .btn--solid:hover:not(:disabled)   { border-color: var(--solid-hover-line); background: var(--solid-hover) }
}

.btn--primary:active:not(:disabled) { border-color: var(--accent-hi); background: var(--accent-deep); color: var(--on-accent) }
.btn--ghost:active:not(:disabled),
.btn--quiet:active:not(:disabled)   { border-color: var(--line-2); background: var(--panel-3); color: var(--text) }
/* У контурной primary нажатие заливку добавляет, у сплошной — темнит:
   вдавливание. Контраст текста держится 5.8 / 4.6 / 8.0:1 по состояниям. */
.btn--solid:active:not(:disabled)   { border-color: var(--accent); background: var(--solid-press) }
/* Обычное кольцо accent-hi на зелёной заливке не видно. */
.btn--solid:focus-visible { outline-color: var(--solid-focus) }

/* Выключенная кнопка не делается прозрачностью: opacity гасит и текст,
   и он перестаёт читаться. Тот же контур, подложка panel, подпись
   muted-3 — форма остаётся, зелёный уходит, контраст держится 4.8:1. */
.btn:disabled {
  cursor: default;
  border-color: var(--line);
  background: var(--panel);
  color: var(--muted-3);
}
/* У quiet в покое рамки нет, поэтому её выключенное состояние —
   пунктир: без него пропажа читалась бы как исчезновение элемента. */
.btn--quiet:disabled { background: transparent; border-style: dashed }

/* Loading сохраняет ширину и не выглядит выключенным: выключенная
   означала бы «нельзя», а не «уже идёт». Повторный тап игнорируется. */
.btn--loading { pointer-events: none }
.btn--loading .icon { animation: f440-spin 900ms linear infinite }
@keyframes f440-spin { to { transform: rotate(360deg) } }

/* ── §21 Icon-button: 32 на десктопе, 44 в TMA и всюду, где рядом
      нет другой цели. Всегда с aria-label — знак без подписи без него
      не существует. ── */
.icon-btn {
  display: grid; place-items: center;
  width: 32px; height: 32px;
  border-radius: var(--r-s);
  border: 1px solid var(--line);
  background: transparent;
  color: var(--muted-2);
  cursor: pointer;
  transition: background var(--t-press) var(--ease), color var(--t-press) var(--ease);
}
.icon-btn--lg { width: var(--tap-row); height: var(--tap-row); border-radius: var(--r-m) }
@media (hover: hover) {
  .icon-btn:hover:not(:disabled) { background: var(--panel-2); border-color: var(--line-2); color: var(--text) }
}
.icon-btn:active:not(:disabled) { background: var(--panel-3); color: var(--text) }
.icon-btn:disabled { cursor: default; color: var(--line-2) }
.icon-btn:focus-visible { outline: none; box-shadow: 0 0 0 2px var(--bg), 0 0 0 4px var(--accent-hi) }

/* ── §09 Чипсы материала ──────────────────────────────────────── */

.chip {
  display: inline-flex; align-items: center; gap: var(--sp-1);
  padding: 7px 12px;
  border-radius: var(--r-pill);
  border: 1px solid var(--line);
  background: var(--panel-2);
  color: var(--muted);
  font-family: inherit; font-size: 12px;
  white-space: nowrap;
  cursor: pointer;
  transition: background var(--t-press) var(--ease), border-color var(--t-press) var(--ease), color var(--t-press) var(--ease);
}
.chip[aria-pressed="true"], .chip.is-on {
  background: var(--accent-wash); border-color: var(--accent-edge); color: var(--accent-ink);
}
/* Грузится — прозрачность 50 %, но нажатие не блокируется. */
.chip.is-loading { opacity: .5 }
/* Не загрузился — терракотовая обводка, причина в подсказке. */
.chip.is-failed { border-color: var(--bad-edge); color: var(--bad-ink) }
/* Свой трек — пунктир, всегда последний в ленте. */
.chip--add { border-style: dashed; border-color: var(--line-2); color: var(--muted) }
@media (hover: hover) {
  .chip:hover { border-color: var(--line-2); color: var(--text) }
  .chip[aria-pressed="true"]:hover, .chip.is-on:hover { border-color: var(--accent-hover); color: var(--accent-hover) }
}

/* Лента на телефоне не обрезается, а скроллится по горизонтали.
   Маска-затухание 22 px у правого края и есть признак, что пункты
   продолжаются: полосы прокрутки в TMA не видно. */
.chip-row {
  display: flex; align-items: center; gap: var(--sp-2);
  overflow-x: auto; scrollbar-width: none;
  -webkit-overflow-scrolling: touch;
}
.chip-row::-webkit-scrollbar { display: none }
@media (max-width: 640px) {
  .chip-row { -webkit-mask-image: linear-gradient(90deg, #000 calc(100% - 22px), transparent);
                      mask-image: linear-gradient(90deg, #000 calc(100% - 22px), transparent) }
  .chip { min-height: var(--tap-row) }
}

/* ── §18 Switch. Один размер на все платформы и все места: 46×26,
      шарик 20, отступ 3, ход 20. 26 px — визуальный размер; зона
      нажатия 44 px даёт строка настройки, в которой он живёт. ── */

.switch {
  position: relative; flex-shrink: 0;
  width: 46px; height: 26px;
  border-radius: var(--r-pill);
  border: 1px solid var(--line-2);
  background: var(--panel-2);
  padding: 0; cursor: pointer;
  transition: background var(--t-press) var(--ease), border-color var(--t-press) var(--ease);
}
.switch::after {
  content: ""; position: absolute; top: 3px; left: 3px;
  width: 20px; height: 20px; border-radius: 50%;
  background: var(--knob-off);
  box-shadow: var(--knob-shadow);
  transition: transform var(--t-press) var(--ease), background var(--t-press) var(--ease);
}
.switch[aria-checked="true"] {
  background: var(--switch-on); border-color: transparent;
}
.switch[aria-checked="true"]::after { background: var(--on-accent); transform: translateX(20px) }
/* Шарик уезжает на 2 px за трек — единственная анимация компонента. */
.switch[aria-checked="true"]:active::after { transform: translateX(22px) }
.switch[aria-checked="false"]:active::after { transform: translateX(-2px) }
@media (hover: hover) {
  .switch[aria-checked="true"]:hover:not(:disabled) { background: #2C9A2C }
}
/* Без заливки и без opacity: причина пишется строкой рядом. */
.switch:disabled { cursor: default; background: var(--panel); border-color: var(--line) }
.switch:disabled::after { background: var(--line-2); transform: none }

/* ── §21 Слайдер. Ручка 22 px, под нажатием 26 — единственный
      компонент, который растёт под пальцем. Значение всегда над
      шкалой справа и никогда в тултипе на ручке: под пальцем его
      не видно. ── */

.slider-head { display: flex; justify-content: space-between; align-items: baseline; margin-bottom: 9px }
.slider-head .val { font-family: var(--font-mono); font-size: 13px; color: var(--accent-ink); font-variant-numeric: tabular-nums }
.slider-scale { display: flex; justify-content: space-between; margin-top: 6px;
  font-family: var(--font-mono); font-size: 10px; color: var(--muted-3); font-variant-numeric: tabular-nums }

.slider {
  -webkit-appearance: none; appearance: none;
  width: 100%; height: 22px; margin: 0;
  background: transparent; cursor: pointer;
}
.slider::-webkit-slider-runnable-track {
  height: 6px; border-radius: var(--r-pill);
  background: linear-gradient(90deg, var(--accent) 0 var(--fill, 0%), var(--panel-3) var(--fill, 0%) 100%);
}
.slider::-moz-range-track {
  height: 6px; border-radius: var(--r-pill);
  background: linear-gradient(90deg, var(--accent) 0 var(--fill, 0%), var(--panel-3) var(--fill, 0%) 100%);
}
.slider::-webkit-slider-thumb {
  -webkit-appearance: none; appearance: none;
  width: 22px; height: 22px; margin-top: -8px;
  border-radius: 50%; background: var(--on-accent);
  border: 3px solid var(--bg); box-shadow: 0 0 0 1px var(--line-2);
  transition: width var(--t-press) var(--ease), height var(--t-press) var(--ease);
}
.slider::-moz-range-thumb {
  width: 16px; height: 16px;
  border-radius: 50%; background: var(--on-accent);
  border: 3px solid var(--bg); box-shadow: 0 0 0 1px var(--line-2);
}
.slider:active::-webkit-slider-thumb {
  width: 26px; height: 26px; margin-top: -10px;
  background: #FFFFFF; box-shadow: 0 0 0 1px var(--accent-hi);
}
.slider:active::-moz-range-thumb { background: #FFFFFF; box-shadow: 0 0 0 1px var(--accent-hi) }
.slider:disabled { cursor: default; opacity: .45 }
.slider:disabled::-webkit-slider-runnable-track {
  background: linear-gradient(90deg, var(--line-2) 0 var(--fill, 0%), var(--panel-3) var(--fill, 0%) 100%);
}
.slider:disabled::-webkit-slider-thumb { background: var(--line-2); box-shadow: none }

/* ── §21 Строка настройки. 44 px минимум, вся строка кликабельна,
      управляющий элемент справа. Одна строка — один смысл: шеврон
      ведёт вглубь, тумблер применяет сразу. ── */

.set-list { display: grid; gap: 1px; background: var(--line); border-radius: var(--r-card); overflow: hidden }
.set-row {
  display: flex; align-items: center; gap: var(--sp-3);
  min-height: var(--tap-row); padding: 13px 14px;
  background: var(--stage); border: 0; width: 100%;
  color: var(--text); font-family: inherit; font-size: 14px; text-align: left;
}
.set-row[role="button"], button.set-row, a.set-row { cursor: pointer }
@media (hover: hover) { .set-row[role="button"]:hover, button.set-row:hover, a.set-row:hover { background: var(--panel-response) } }
.set-row-main { flex: 1; min-width: 0 }
.set-row-title { font-size: 14px; font-weight: 600 }
.set-row-sub { font-size: 12px; color: var(--muted) }
.set-row-value { font-size: 13px; color: var(--muted); flex-shrink: 0 }
.set-row-chev { color: var(--muted-3); display: grid; place-items: center; flex-shrink: 0 }
.set-row--danger .set-row-title { color: var(--bad-ink); font-weight: 400 }

/* ── §21 Поле ввода ───────────────────────────────────────────── */

.field {
  width: 100%;
  padding: 11px 13px;
  border-radius: var(--r);
  background: var(--stage);
  border: 1px solid var(--line);
  color: var(--text);
  font-family: inherit; font-size: 14px;
  transition: border-color var(--t-press) var(--ease), box-shadow var(--t-press) var(--ease);
}
.field::placeholder { color: var(--muted-3) }
.field:focus-visible {
  outline: none;
  border-color: var(--accent-hi);
  box-shadow: 0 0 0 2px rgba(79, 168, 90, .28);
}
.field[aria-invalid="true"] { border-color: var(--bad) }
.field-error { font-size: 12px; color: var(--bad-ink); margin-top: 6px }

/* ── §09а Не загрузилось — один компонент на весь продукт.
      Скелетон отвечает только на вопрос «сейчас грузится». На вопрос
      «не загрузилось» отвечает этот. Скелетон живёт не дольше десяти
      секунд, дальше на его месте появляется он: бесконечный скелетон
      считается дефектом. ── */

.err {
  background: var(--stage); border: 1px solid var(--line); border-radius: var(--r-card);
  padding: 22px var(--sp-4);
  display: grid; justify-items: center; gap: 10px; text-align: center;
}
.err-mark {
  width: 44px; height: 44px; border-radius: var(--r-card);
  background: var(--panel-2); border: 1px solid var(--line-2);
  display: grid; place-items: center; color: var(--brass);
}
/* Иконка кодирует тип: перечёркнутая антенна и латунь — сеть,
   сервер и терракота — отказ на нашей стороне. */
.err--server .err-mark { background: var(--bad-wash); border-color: var(--bad-edge); color: var(--bad-ink) }
.err-title { font-size: 14px; font-weight: 600; margin-bottom: 3px }
.err-reason { font-size: 13px; color: var(--muted) }

/* Размер S — вместо строки: причина и «повторить» в одну линию. */
.err--s { display: flex; align-items: center; gap: 10px; text-align: left; padding: 11px 13px; background: var(--panel); border: 0; border-radius: 0 }
.err--s .err-mark { width: auto; height: auto; border: 0; background: none; border-radius: 0 }
.err--s .err-reason { flex: 1 }

/* Размер XL — вместо экрана. Единственный случай, где показываем код:
   он нужен поддержке, а не человеку, и только для 5xx. */
.err--xl { padding: var(--sp-6) var(--sp-4); gap: 11px }
.err--xl .err-mark { width: 52px; height: 52px; border-radius: 15px }
.err--xl .err-title { font-size: 15px }
.err--xl .err-reason { max-width: 230px }
.err-code { font-family: var(--font-mono); font-size: 10px; color: var(--muted-3) }

/* ── Утилиты типографики ─────────────────────────────────────── */

.t-display { font-size: var(--fs-display); line-height: var(--lh-display); letter-spacing: var(--ls-display); font-weight: 600 }
.t-h1 { font-size: var(--fs-h1); line-height: var(--lh-h1); letter-spacing: var(--ls-h1); font-weight: 600 }
.t-h2 { font-size: var(--fs-h2); line-height: var(--lh-h2); font-weight: 600 }
.t-h3 { font-size: var(--fs-h3); line-height: var(--lh-h3); font-weight: 600 }
.t-body { font-size: var(--fs-body); line-height: var(--lh-body) }
.t-small { font-size: var(--fs-small); line-height: var(--lh-small); color: var(--muted) }
.t-label {
  font-family: var(--font-mono); font-size: var(--fs-label);
  letter-spacing: var(--ls-label); text-transform: uppercase; color: var(--muted-2);
}
/* Табличные цифры обязательны там, где число меняется на месте:
   значения порога обновляются, и цифры не должны прыгать. */
.t-num { font-family: var(--font-mono); font-variant-numeric: tabular-nums }
